{"id":13608365,"url":"https://github.com/llxiaoyuan/oxorany","last_synced_at":"2025-04-05T19:12:21.035Z","repository":{"id":37253651,"uuid":"404358867","full_name":"llxiaoyuan/oxorany","owner":"llxiaoyuan","description":"obfuscated any constant encryption in compile time on any platform","archived":false,"fork":false,"pushed_at":"2023-04-25T09:07:52.000Z","size":164,"stargazers_count":441,"open_issues_count":8,"forks_count":85,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-03-29T18:08:04.221Z","etag":null,"topics":["compile-time","cpp14","encryption","obfuscated","template","xor"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/llxiaoyuan.png","metadata":{"files":{"readme":"README.en.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-09-08T13:30:42.000Z","updated_at":"2025-03-28T12:29:01.000Z","dependencies_parsed_at":"2024-01-14T06:55:49.615Z","dependency_job_id":null,"html_url":"https://github.com/llxiaoyuan/oxorany","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llxiaoyuan%2Foxorany","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llxiaoyuan%2Foxorany/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llxiaoyuan%2Foxorany/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llxiaoyuan%2Foxorany/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/llxiaoyuan","download_url":"https://codeload.github.com/llxiaoyuan/oxorany/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247386265,"owners_count":20930619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compile-time","cpp14","encryption","obfuscated","template","xor"],"created_at":"2024-08-01T19:01:26.711Z","updated_at":"2025-04-05T19:12:21.009Z","avatar_url":"https://github.com/llxiaoyuan.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"# oxorany\n## A heavily obfuscated c++14 compile time any constant encryption.\n\n[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![](https://img.shields.io/badge/C%2B%2B-14-brightgreen)]()\n[![](https://img.shields.io/badge/OS-any-brightgreen)]()\n[![](https://img.shields.io/badge/compiler-any-brightgreen)]()\n[![](https://img.shields.io/badge/arch-any-brightgreen)]()\n\n* [简体中文](README.md)\n\n### Description\n\n\u003e We integrated some implementation ideas from open source projects `ollvm` and `xorstr`, as well as the new `constexpr` keyword in the `c++14` standard and some template knowledge, to complete the compile-time obfuscation encryption of arbitrary constants.\n\n\u003e Before C++14, if we want to protect the constants in the program, we first encrypt the constants, here we take the string `\"some_data_or_string\"` byte by byte `-1` as an example, and then write the encrypted data \"rnld^c\\`s\\`^nq^rsqhmf\" to the code, while doing byte by byte `+1` decryption.\n\n\u003e Code show as below\n\n```C++\nchar encrypted[] = {\"rnld^c`s`^nq^rsqhmf\"};\nchar key = 0x1;\nfor (size_t i = 0; i \u003c strlen(encrypted); i++) {\n\tencrypted[i] += key;\n}\n//output: some_data_or_string\nprintf(\"%s\\n\", encrypted);\n```\n\n\u003e The above method can only be used when the amount of data to be protected is relatively small, and when the amount of data increases, the time taken by the tedious encryption process will also rise, and it makes the readability and maintainability of the code greatly reduced. And it is not possible to design a separate decryption algorithm and key for each data, which makes a general decryption tool easier to write.\n\n\u003e **With the advent of `oxorany`, the above process will be changed**\n\n### 🎨 Features\n* **Support any platform(`C++14`)**\n* **Higher operability, using `__asm` `_emit` can further increase the difficulty of reverse**\n* Obfuscated encryption of any constants at compile time\n* All the decryption process is done inside the stack, and the decrypted data cannot be obtained through runtime `dump`，unlike [Armariris](https://github.com/GoSSIP-SJTU/Armariris)、[flounder](https://github.com/isrc-cas/flounder)\n* Decryption algorithm with `Bogus Control Flow` like `ollvm`\n* Generate a unique control flow for each encryption algorithm through `compile optimization`\n* Generate a unique `key` for each encryption algorithm with the `__COUNTER__` macro\n* Dynamically generate `key` via the `__TIME__` macro\n* **The code has been crafted** so that can Destroying the stack to anti `IDA` `F5`\n* Stack variable based `Opaque Predicate`\n* Fuzzy data length\n* Since most of the code for the decryption algorithm is not executed, the impact on efficiency is not particularly significant\n* **The complexity of the decryption algorithm can be improve**\n* Because of the `implicit conversion` feature of constants in `C++`, some constants may require forced type conversion\n* Easy to use, tested in `msvc`, `clang`, `gcc`\n* **There is no guarantee that the data will be embedded directly into code**，[Want embedded](https://github.com/llxiaoyuan/xorstr)\n\n### Data types supported\n\n- [x] String(`char*` `wchar_t*`)\n- [x] Macro\n- [x] Enume\n- [x] Integer(`int8_t` `int16_t` `int32_t` `int64_t` `uint8_t` `uint16_t` `uint32_t` `uint64_t`)\n- [x] Floating point(`float` `double`)\n\n### Compilers Supported\n\n- [x] `msvc`\n- [x] `clang`(`llvm`)\n- [x] `gcc`\n- [x] `android ndk`\n- [x] `leetcode gcc`\n- [x] `...`\n\n\u003cbr /\u003e\n\n### 🚀 Usage\n```C++\n#include \u003ciostream\u003e\n//#define OXORANY_DISABLE_OBFUSCATION\n#include \"oxorany.h\"\n\nenum class MyEnum : int {\n\tfirst = 1,\n\tsecond = 2,\n};\n\n#define NUM_1 1\n\nint main() {\n        // output:\n        // 1 1 2 12 1234 12345678 1234567887654321 1.000000 2.000000\n        // string wstring raw string raw wstring\n\tprintf(oxorany(\"%d %d %d %hhx %hx %x %llx %f %lf\\n%s %S %s %S\\n\")  //string\n            , oxorany(NUM_1)                                               //macro\n            , oxorany(MyEnum::first), oxorany(MyEnum::second)              //enum\n            , oxorany((uint8_t)0x12)                                       //uint8_t\n            , oxorany((uint16_t)0x1234)                                    //uint16_t\n            , oxorany((uint32_t)0x12345678)                                //uint32_t\n            , oxorany((uint64_t)0x1234567887654321)                        //uint64_t\n            , oxorany(1.0f)                                                //float\n            , oxorany(2.0)                                                 //double\n            , oxorany(\"string\")                                            //string\n            , oxorany(L\"wstring\")                                          //wstring\n            , oxorany(R\"(raw string)\")                                     //raw string\n            , oxorany(LR\"(raw wstring)\")                                   //raw wstring\n\t);\n\treturn oxorany(0);\n}\n```\n\n\u003cbr /\u003e\n\n### ⚙️ Need Cast\n\n\u003e 0 error 0 warning\n\n```C++\nMessageBoxA(0, 0, 0, 0);\n```\n\n\u003cbr /\u003e\n\n\u003e error(active)\tE0167 Real parameters of type \"int\" are incompatible with formal parameters of type \"HWND\"\n\n```C++\nMessageBoxA(oxorany(0), 0, 0, 0);\n```\n\n\u003cbr /\u003e\n\n\u003e The reason for the above problem is due to the peculiarity of `0` in `C/C++`, because it can be implicitly converted to a pointer of any type, and is also related to the definition of `NULL`\n\n```C++\n#ifndef NULL\n    #ifdef __cplusplus\n        #define NULL 0\n    #else\n        #define NULL ((void *)0)\n    #endif\n#endif\n```\n\n\u003cbr /\u003e\n\n\u003e So we add a forced type conversion to `HWND` to solve the problem\n```C++\nMessageBoxA(oxorany((HWND)0), 0, 0, 0);\n```\n\n\u003cbr /\u003e\n\n### `Control Flow Graph` in `IDA`\n\n![image](https://user-images.githubusercontent.com/36320938/132527280-34c443b8-40b5-4b76-a35b-2629a1df087c.png)\n\n\u003cbr /\u003e\n\n### `Compilation Optimization` test\n\n```C++\n#include \"oxorany.h\"\nint main() {\n\treturn oxorany(0);\n}\n```\n\n\u003cbr /\u003e\n\n### ✅ `Control Flow Graph` in `IDA` after multiple compilation using `msvc`\n\n![image](https://user-images.githubusercontent.com/36320938/132721095-7ef48f99-37ef-407e-bf14-0ba3e72f1e25.png)\n\n\u003cbr /\u003e\n\n### ✅ `Control Flow Graph` in `IDA` after multiple compilation using `clang`\n\n![image](https://user-images.githubusercontent.com/36320938/132723406-dcf26a9e-9a12-4fa4-a0b7-4889861d7478.png)\n\n\u003cbr /\u003e\n\n### ✅ `Control Flow Graph` in `IDA` after multiple compilation using `gcc`\n\n![image](https://user-images.githubusercontent.com/36320938/132799274-d816cc02-e913-43ab-b183-3a1c75fee5ce.png)\n\n\u003cbr /\u003e\n\n### ✅ `Control Flow Graph` in `IDA` after compilation using `android ndk`\n\n![image](https://user-images.githubusercontent.com/36320938/133132325-d70fe632-5e7e-407a-a42c-7594b788507a.png)\n\n\u003cbr /\u003e\n\n### ✅ Testing with `leetcode gcc` ([Sword Pointing Offer 05. replace space](https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/comments/))\n\n![S5(LFNXH~_KM6UH@L}U(CY6](https://user-images.githubusercontent.com/36320938/133314352-50d434a3-d5ae-4e0d-8504-1e1215be19e6.png)\n\n\u003cbr /\u003e\n\n### ✅ `Control Flow Graph` in `IDA` after multiple compilation using `wdk`\n\n![image](https://user-images.githubusercontent.com/36320938/133409709-7e176557-439c-4988-91ee-219b35ab80e0.png)\n\n\u003cbr /\u003e\n\n### ✅ `Control Flow Graph` in `IDA` after compilation using `ollvm`\n\n![image](https://user-images.githubusercontent.com/36320938/133938052-cdccca0f-6bdf-4fc7-811f-f470bbea7663.png)\n\n\u003cbr /\u003e\n\n### Opaque predicate\n\n\u003e The `opaque predicate` can be understood as `\"the judgment of the result cannot be determined\"`，The words themselves do not contain the meaning that the result must be true or must be false, but only the condition that the result must be true is used here for obfuscation\n\n\u003e The `rand() % 2 == 0` in the code is actually an opaque predicate, because we can't determine its result, so we can't be sure whether the program is outputting `hello` or `world`\n\n```C++\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003ctime.h\u003e\nint main() {\n\tsrand((unsigned int)time(NULL));\n\tif (rand() % 2 == 0) {\n\t\tprintf(\"hello\\n\");\n\t}\n\telse {\n\t\tprintf(\"world\\n\");\n\t}\n\treturn 0;\n}\n```\n\n\u003cbr /\u003e\n\n\u003e But in another case, here we create a global variable `zeor` and assign an initial value of `0`, without modifying the value of `zeor` or making reasonable modifications to ensure that the result of the predicate is constant, then the predicate `zeor \u003c 1` is constant, and at the same time the compiler will not optimize due to the natural opacity of global variables, so we add a forged to the control flow. We can add `any code` inside an unreachable basic block, and here we add a `99 multiplication table` as an example.。\n\n```C++\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003ctime.h\u003e\nint zeor = 0;\nint main() {\n\tif (zeor \u003c 1) {\n\t\tprintf(\"hello\\n\");\n\t}\n\telse {\n\t\t//unreachable\n\t\tfor (int i = 1; i \u003c= 9; i++) {\n\t\t\tfor (int j = 1; j \u003c= 9; j++) {\n\t\t\t\tprintf(\"%d*%d=%2d\\t\", i, j, i * j);\n\t\t\t}\n\t\t    \tprintf(\"\\n\");\n\t\t}\n\t}\n\treturn 0;\n}\n```\n\n\u003cbr /\u003e\n\n\u003e Here `copy` the code from `ollvm`，`ASCII Picasso`\n\n```C++\n// Before :\n// \t         \t     entry\n//      \t\t       |\n//  \t    \t  \t ______v______\n//   \t    \t\t|   Original  |\n//   \t    \t\t|_____________|\n//             \t\t       |\n// \t\t       \t       v\n//\t\t             return\n//\n// After :\n//           \t\t     entry\n//             \t\t       |\n//            \t\t   ____v_____\n//      \t\t  |condition*| (false)\n//           \t\t  |__________|----+\n//           \t\t (true)|          |\n//             \t\t       |          |\n//           \t\t ______v______    |\n// \t            +--\u003e|   Original* |   |\n// \t            |   |_____________| (true)\n// \t            |   (false)|    !-----------\u003e return\n// \t            |    ______v______    |\n// \t            |   |   Altered   |\u003c--!\n// \t            |   |_____________|\n// \t            |__________|\n//\n//  * The results of these terminator's branch's conditions are always true, but these predicates are\n//    opacificated. For this, we declare two global values: x and y, and replace the FCMP_TRUE\n//    predicate with (y \u003c 10 || x * (x + 1) % 2 == 0) (this could be improved, as the global\n//    values give a hint on where are the opaque predicates)\n```\n\n\u003cbr /\u003e\n\n\u003e Definition of global `x`, `y` in ollvm`\n\n```C++\n      GlobalVariable \t* x = new GlobalVariable(M, Type::getInt32Ty(M.getContext()), false,\n          GlobalValue::CommonLinkage, (Constant * )x1,\n          *varX);\n      GlobalVariable \t* y = new GlobalVariable(M, Type::getInt32Ty(M.getContext()), false,\n          GlobalValue::CommonLinkage, (Constant * )y1,\n          *varY);\n```\n\n\u003cbr /\u003e\n\n\u003e The implementation of the opaque predicate `y \u003c 10 || x * (x + 1) % 2 == 0` in `ollvm` is shown by `Instruction::Sub`, which, although annotated with `x + 1`, actually uses `x - 1`\n\n```C++\n        //if y \u003c 10 || x*(x+1) % 2 == 0\n        opX = new LoadInst ((Value *)x, \"\", (*i));\n        opY = new LoadInst ((Value *)y, \"\", (*i));\n\n        op = BinaryOperator::Create(Instruction::Sub, (Value *)opX,\n            ConstantInt::get(Type::getInt32Ty(M.getContext()), 1,\n              false), \"\", (*i));\n        op1 = BinaryOperator::Create(Instruction::Mul, (Value *)opX, op, \"\", (*i));\n        op = BinaryOperator::Create(Instruction::URem, op1,\n            ConstantInt::get(Type::getInt32Ty(M.getContext()), 2,\n              false), \"\", (*i));\n        condition = new ICmpInst((*i), ICmpInst::ICMP_EQ, op,\n            ConstantInt::get(Type::getInt32Ty(M.getContext()), 0,\n              false));\n        condition2 = new ICmpInst((*i), ICmpInst::ICMP_SLT, opY,\n            ConstantInt::get(Type::getInt32Ty(M.getContext()), 10,\n              false));\n        op1 = BinaryOperator::Create(Instruction::Or, (Value *)condition,\n            (Value *)condition2, \"\", (*i));\n\n```\n\n\n\u003cbr /\u003e\n\n\u003e Adjusting our code above slightly to show the implementation of `ollvm`, here `x * (x + 1) % 2 == 0`, thinking that `x` and `x + 1`, must be an odd number and an even number, according to the operation of parity we can learn that the result of `x * (x + 1)` must be even, so the judgment of `% 2 == 0` will necessarily hold\n\n```C++\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003ctime.h\u003e\nint x = 0;\nint y = 0;\nint main() {\n\tif (y \u003c 10 || x * (x + 1) % 2 == 0) {\n\t\tprintf(\"hello\\n\");\n\t}\n\telse {\n\t\t//unreachable\n        \tfor (int i = 1; i \u003c= 9; i++) {\n\t\t\tfor (int j = 1; j \u003c= 9; j++) {\n                \t\tprintf(\"%d*%d=%2d\\t\", i, j, i * j);\n\t\t\t}\n            \t\tprintf(\"\\n\");\n        \t}\n\t}\n\treturn 0;\n}\n```\n\n\u003cbr /\u003e\n\n### Implemention\n\u003e Inspired by the `Bogus Control Flow` function in `ollvm`, we created two global variables `x` and `y` and assigned initial values of `0` as the basis for implementing opaque predicates\n\n![image](https://user-images.githubusercontent.com/36320938/132540802-06b63425-acc8-4da8-b9d7-de5886587f42.png)\n\n\u003cbr /\u003e\n\n\u003e Due to the complexity of the stack environment, we assign the global variables `x` and `y` to two local variables `stack_x` and `stack_y` respectively to make the inverse more difficult\n\n![image](https://user-images.githubusercontent.com/36320938/132541176-02f4f8a7-0b80-4b2a-b584-7658f954a003.png)\n\n\u003cbr /\u003e\n\n\u003e We created `label` in many positions of the function, used `stack_x`, `stack_y` to judge the constant to be true for confusion, and added `goto label` in the basic block that could not be reached to remove the basic block as much as possible point. We use the wrong key to decrypt the decrypted data `decrypted` in many places, so that the real key is difficult to identify among the many wrong keys.\n\n![image](https://user-images.githubusercontent.com/36320938/132542465-c9495bde-c34f-468b-ae0f-b9ab79959bba.png)\n\n\u003cbr /\u003e\n\n\u003e Generate random numbers with range limition, since the same values can occur here, while duplicate conditions are removed by compilation optimization because of the existence of compilation optimization, which makes us have a different control flow diagram for each compilation\n\n![image](https://user-images.githubusercontent.com/36320938/132543102-c7c59806-6f34-4f60-b5cf-59abdfa79048.png)\n\n\u003cbr /\u003e\n\n\u003e We add illegal stack operations within the unreachable basic fast to make `IDA`'s stack frame analysis fail against `F5`\n\n![image](https://user-images.githubusercontent.com/36320938/132544334-27a63575-35b0-4b52-ac12-9079a984c2bf.png)\n\n\u003cbr /\u003e\n\n\u003e We are aligning the data by `16` bytes and adding a certain random value to obscure the data length, which may waste a little space\n\n![image](https://user-images.githubusercontent.com/36320938/132553464-d8ef7b64-c4a7-4a36-9250-51062751a8d1.png)\n\n\u003cbr /\u003e\n\n\u003e We are replacing `xor` with a more complex implementation to make the inversion more difficult\n\n![image](https://user-images.githubusercontent.com/36320938/132621379-81796348-23d1-4549-99b7-55e4aa87f0eb.png)\n\n\u003cbr /\u003e\n\n\u003e Use the `__TIME__` macro to implement a different `key` for each compilation\n\n![image](https://user-images.githubusercontent.com/36320938/132704045-7510c6df-f2db-4e9b-99b0-ca80aa871aed.png)\n\n\u003cbr /\u003e\n\n\u003e Random number generator with range restrictions, making `opaque predicates` similar to normal `predicates`\n\n![image](https://user-images.githubusercontent.com/36320938/132704535-10761dda-61e7-47b3-95a4-e2439d483532.png)\n\n\u003cbr /\u003e\n\n\u003e To sum up, with the help of `oxorany`, the security of the software will be further improved\n\n### Reference\n+ [Armariris -- LLVM obfuscation framework maintained by the Laboratory of Cryptography and Computer Security, Shanghai Jiao Tong University](https://github.com/GoSSIP-SJTU/Armariris)\n+ [PLCT labs maintain the collvm branch](https://github.com/isrc-cas/flounder)\n+ [heavily vectorized c++17 compile time string encryption](https://github.com/JustasMasiulis/xorstr)\n\n### Github\nhttps://github.com/llxiaoyuan/oxorany\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllxiaoyuan%2Foxorany","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fllxiaoyuan%2Foxorany","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllxiaoyuan%2Foxorany/lists"}