Kotoamatsukami is an obfuscator based on LLVM-17, utilizing LLVM's new pass to implement plug-in features, for obfuscating multiple languages and platforms.
The name "Kotoamatsukami" is derived from my favorite anime, Naruto, which features the best genjutsu in my heart.
I will provide a complete set of related documentation in the future,now you can find the dynamically link files-Kotoamatsukami.so in /bin/build,and the /bin/test contains the different files obsfucated by different methods.
PS:This project is written by myself out of interest, it may not be complete, if you have any questions about this project, please feel free to contact me.
Now u can taste it through my ugly site http://39.102.210.108:8080/
Welcome~!
The following test file is rc4 encryption algorithm(source file in the end of this readme),the ida view of the original file is as follows:
Currently open obfuscation functions include:
A method to obfuscate control flow of the program
The performance of using Loopen only:
Transform the br to call some function in assembly level,curently only supported X86 and X64.
The performance of using branch2call only:
Add for loop for combating dynamic execution projects such as angr.
The performance of using ForObs only:
My bogus-control-flow is based on the version of rimao (source code: https://github.com/za233/Polaris-Obfuscator/blob/main/src/llvm/lib/Transforms/Obfuscation/BogusControlFlow2.cpp) What i have done is to modify the judging conditions from certain to possible , but it's probability of occurrence is so liitle that it can't happen when the actual program running .And I add a local viriables to reinforces the illusion that it can be run.
But what I want to do is that make the false block can be real excute on a very low probability.And if the false block have excuted ,the program will find it and re-execute the true block.But the fake variable in my false block is un-alloced so that it will corrupt.Hope I will have time to finish this in the future.
The performance of using BogusControlFlow only:
This obfuscation method can turn the branch jump to an indirect jump through the register,and each block has a unique key to increase the difficulty crackers' attacks.
The performance of using Indirect_branch only:
As the indirect_branch method,this method will turn partial func call to indirect call through register with different keys.
The performance of using Indirect_call only:
This is an easy method to split a basic block to multiple.Its purpose is to strengthen other obfuscation algorithms.
For example , the performance of using it and the Loopen:
Add assembly level junk code , currently only support X86 and X64. The performance of using AddJunkCode only:
This code is adapted from the Pluto project (https://github.com/DreamSoule/ollvm17) Thanks to the contributions of our predecessors! The performance of using Flatten only:
This code is adapted from the Pluto project (https://github.com/bluesadi/Pluto) source file: https://github.com/bluesadi/Pluto/blob/kanxue/Transforms/src/Substitution.cpp I just adapted it to the LLVM-17 and the LLVM New Pass Thanks to the contributions of our predecessors! The performance of using Substitution only:
The method will encrypt partial global virable or global constant with inserting the func-relative dec func in the head of the func,and guard the dec func only excute once through a global virable.May I will add the relative func in the end of the func to enhance secrecy.
The performance of using GVEncrypt only:
The method will insert some anti-debugging functions into the program's constructor list to be called when the program starts running:
And I try to make the anti-debugging functions configurable,see code for details.
Now the method wiil randomly insert some anti-debug functions into the each functions of the program to guard the program in runtime.
You can compile LLVM-17 project in by youself in your computer,then modify the CMakeLists.txt of this project to compile it.
The following are the commands I use for your reference:
git clone --depth 1 -b release/17.x https://github.com/llvm/llvm-project.git
mkdir build
cmake -G Ninja -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TARGETS_TO_BUILD="X86;ARM;AArch64" -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_RTTI=ON -DLLVM_OBFUSCATION_LINK_INTO_TOOLS=
ON -DCMAKE_INSTALL_PREFIX=./build/ ../llvm-project/llvm
ninja -j8
ninja install
These commands will install compiled products to /build,then your need modify the CMakeLists.txt of this project.
cd Kotoamatsukami
mkdir build
cd build
cmake ..
make -j
finish ~~
Now you can use this obfucator easily,you just need install the clang-17 first,then modify the Kotoamatsukami_so
in the compiler/clang_wrapper.sh
,then you can use it in compiler
directory, and i will supply compiled so in the /bin
.
The compile options to use as shown below:
./clang_wrapper.sh -kotoamatsukami {obfuscation_options} <input_file> -o <output_file>
- <input_file>: Path to the source code file you want to obfuscate (e.g., my_program.c).
- -o <output_file>: Path to the output executable file (e.g., my_program).
- {obfuscation_options}: This is a space-separated list of obfuscation passes you wish to apply. Here are the available options (matching the internal pass names in the provided code snippet):
- split-basic-block: Splits basic blocks within the code.
- anti-debug: Inserts anti-debugging techniques.
- gv-encrypt: Encrypts global variables.
- bogus-control-flow: Inserts bogus control flow to confuse analysis.
- add-junk-code: Adds junk code to increase code size and complexity.
- loopen: Applies loop-based obfuscation.
- for-obs: Applies for loop based obfuscation
- branch2call-32: Converts branches to calls (32-bit version).
- branch2call: Converts branches to calls.
- indirect-call: Inserts indirect function calls.
- indirect-branch: Inserts indirect branches.
- flatten: Flattens the control flow of the program.
- substitution: Replaces instructions with equivalent sequences.
Example:
To apply global variable encryption and bogus control flow to a file named rc4.c, and generate an executable named rc4, you would use:
./clang_wrapper.sh -kotoamatsukami { gv-encrypt bogus-control-flow } ./tests/rc4.c -o ./tests/rc4
To apply global variable encryption only:
./clang_wrapper.sh -kotoamatsukami { gv-encrypt } ./tests/rc4.c -o ./tests/rc4
You need set the configuration file in /tmp/Kotoamatsukami/Kotoamatsukami.config
,which format is as follows.
0
: All functions are turned off (everything is disabled).
1
: All functions are turned on (everything is enabled).
2
: Enable only the functions that are already enabled (keep the enabled functions on, others unchanged).
3
: Enable all functions except those that are explicitly disabled (enable all functions that are not disabled).
Then you can use the Kotoamatsukami.so as follows:
<your-clang-17> -fpass-plugin=<your-Kotoamatsukami_so>
Kotoamatsukami.config
{
"target": "X86_64",
"loopen": {
"model": 0,
"enable function": [
""
],
"disable function": [],
"loopen_x_list": [
2,
3,
5,
8,
11,
12,
13,
14,
18,
20,
21,
27,
30,
31,
32,
34,
35,
37,
38,
41,
43,
44,
45,
46,
48,
50,
51,
52,
56,
57,
66,
69,
71,
72,
73,
75,
77,
78,
80,
84,
85,
89,
91,
94,
95,
97,
98,
99,
103,
106,
108,
110,
113,
115,
116,
120,
124,
125,
126,
128,
130,
134,
136,
137,
140,
141,
147,
148,
152,
157,
158,
159,
162,
163,
164,
165,
167,
172,
173,
174,
176,
180,
184,
187,
189,
192,
195,
197,
199,
200,
201,
202,
204,
209,
210,
214,
217,
218,
221,
222,
224,
227,
228,
233,
235,
236,
237,
238,
239,
241,
242,
243,
244,
245,
246,
247,
249,
253,
254,
257,
258,
259,
261,
262,
263,
264,
266,
270,
275,
276,
278,
279,
284,
286,
287,
288,
290,
292,
293,
298,
299,
300,
301,
303,
306,
307,
308,
310,
311,
312,
315,
320,
322,
325,
327,
333,
335,
336,
337,
338,
340,
342,
347,
350,
353,
354,
356,
357,
363,
364,
366,
369,
370,
373,
376,
379,
380,
382,
386,
387,
388,
392,
393,
395,
396,
397,
399,
405,
410,
412,
414,
415,
417,
421,
422,
424,
426,
429,
430,
432,
433,
435,
438,
440,
443,
446,
447,
450,
453,
458,
459,
460,
462,
464,
465,
467,
468,
479,
480,
483,
493,
496,
497,
499,
500,
502,
504,
505,
507,
509,
510,
511,
512
],
"module_name": "/home/zzzccc/cxzz/Kotoamatsukami/config/quick_pow.ll"
},
"ForObs": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"SplitBasicBlocks": {
"model": 0,
"enable function": [
""
],
"disable function": [],
"split number": 3
},
"branch2call": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
],
"split number": 3
},
"branch2call_32": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
],
"split number": 3
},
"Junkcode": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"Antihook": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"Antidebug": {
"model": 1,
"enable function": [
""
],
"disable function": [
""
]
},
"indirect_branch": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"indirect_call": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"bogus_control_flow": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"substitution": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"flatten": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
},
"gv_encrypt": {
"model": 0,
"enable function": [
""
],
"disable function": [
""
]
}
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define MAX_KEY_LENGTH 256
void confuse_key(unsigned char *key, unsigned long key_len) {
for (unsigned long i = 0; i < key_len; i++) {
key[i] = key[i] ^(unsigned char)(i % 256);
}
}
void rc4_ksa(unsigned char *s, unsigned char *key, unsigned long key_len) {
unsigned char temp;
unsigned long i, j = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + key[i % key_len]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
void rc4_prga(unsigned char *s, unsigned char *data, unsigned long data_len) {
unsigned char temp;
unsigned long i = 0, j = 0, t;
for (unsigned long k = 0; k < data_len; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
t = (s[i] + s[j]) % 256;
data[k] ^= s[t];
}
}
void rc4_encrypt_decrypt(unsigned char *data, unsigned long data_len, unsigned char *key, unsigned long key_len) {
unsigned char s[256];
rc4_ksa(s, key, key_len);
rc4_prga(s, data, data_len);
}
unsigned char data[512];
int main() {
unsigned char key[MAX_KEY_LENGTH];
char input[512];
unsigned long key_len, data_len;
printf("请输入密钥(最多 256 个字符):");
fgets(input, sizeof(input), stdin);
key_len = strlen(input) - 1;
memcpy(key, input, key_len);
confuse_key(key, key_len);
printf("请输入需要加密的数据:");
fgets(input, sizeof(input), stdin);
data_len = strlen(input) - 1;
memcpy(data, input, data_len);
printf("\n加密前的数据:%s\n", data);
rc4_encrypt_decrypt(data, data_len, key, key_len);
printf("加密后的数据:");
for (unsigned long i = 0; i < data_len; i++) {
printf("%02x ", data[i]);
}
printf("\n");
rc4_encrypt_decrypt(data, data_len, key, key_len);
printf("解密后的数据:%s\n", data);
return 0;
}