{"id":17914420,"url":"https://github.com/dtcxzyw/fsubfuscator","last_synced_at":"2025-07-25T02:13:42.568Z","repository":{"id":199782831,"uuid":"701993381","full_name":"dtcxzyw/fsubfuscator","owner":"dtcxzyw","description":"Do integer arithmetic with fsub.","archived":false,"fork":false,"pushed_at":"2025-04-01T07:42:23.000Z","size":193,"stargazers_count":27,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-01T08:38:25.447Z","etag":null,"topics":["anti-debug","compiler","fuscator","llvm","llvm-pass","llvm-project","obfu","obfuscation","obfuscator"],"latest_commit_sha":null,"homepage":"https://github.com/dtcxzyw/fsubfuscator","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dtcxzyw.png","metadata":{"files":{"readme":"README.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-08T07:18:27.000Z","updated_at":"2025-04-01T07:42:26.000Z","dependencies_parsed_at":"2023-10-12T11:27:43.341Z","dependency_job_id":"9210fa5f-fb5b-4847-a5ed-6dd8374a7ab9","html_url":"https://github.com/dtcxzyw/fsubfuscator","commit_stats":null,"previous_names":["dtcxzyw/fsubfuscator"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dtcxzyw/fsubfuscator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcxzyw%2Ffsubfuscator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcxzyw%2Ffsubfuscator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcxzyw%2Ffsubfuscator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcxzyw%2Ffsubfuscator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dtcxzyw","download_url":"https://codeload.github.com/dtcxzyw/fsubfuscator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcxzyw%2Ffsubfuscator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266944047,"owners_count":24010481,"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","status":"online","status_checked_at":"2025-07-25T02:00:09.625Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["anti-debug","compiler","fuscator","llvm","llvm-pass","llvm-project","obfu","obfuscation","obfuscator"],"created_at":"2024-10-28T19:58:16.031Z","updated_at":"2025-07-25T02:13:42.544Z","avatar_url":"https://github.com/dtcxzyw.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FSubfuscator\n\n[![Build](https://github.com/dtcxzyw/fsubfuscator/actions/workflows/build.yml/badge.svg)](https://github.com/dtcxzyw/fsubfuscator/actions/workflows/build.yml)\n\nAn obfuscator inspired by [Subtraction Is Functionally Complete](https://orlp.net/blog/subtraction-is-functionally-complete/).\n\n## Overview\n\nThe FSubfuscator rewrites most of integer arithmetic operations into a bunch of `fsub`s. It is implemented as a LLVM pass and can be used as a standalone tool or a compiler wrapper.\n\nIt supports C/C++/Rust and other programming languages that use LLVM as the backend.\n\n## CTF Challenge\nTo confuse some automatic exploit generation tools, I added a new bit representation called `Mod3`. I also designed a CTF challenge to demonstrate the effectiveness of this obfuscator. Here is the source code of the challenge (magic numbers are omitted):\n```\n# Compiled with:\n# FSUBFUSCATOR_BITREP_OVERRIDE=Mod3 ./fsubcc -O3 test.c\n#include \u003cstdio.h\u003e\nint main() {\n  int a, b, c;\n  printf(\"Please input a, b, c:\\n\");\n  scanf(\"%d%d%d\", \u0026a, \u0026b, \u0026c);\n  if (((b + ?) \u0026 (c + ?)) == (a ^ ?)) {\n    if (a + c == ?) {\n      printf(\"%d %d %d\\n\", a, b, c);\n      puts(\"Win!\");\n    }\n  }\n  return 0;\n}\n```\n\nHere is [x86-64 Executable](https://github.com/dtcxzyw/fsubfuscator/files/12885861/a.out.tar.gz). Please file an issue to describe your approach if you get a solution.\n```\necho \"bbde02bd001bb27c4175347851b8a953c918de88d8a59f5115f2ec687f2bdb3e a.out.tar.gz\" | sha256sum -c\n```\n\nGood luck and have fun :)\n\n## Building\n### Prerequisites\n\n+ Linux\n+ Compiler with C++17 support\n+ CMake 3.20 or higher\n+ Ninja\n+ Recent versions of LLVM\n+ alive2 (optional for test)\n+ gtest (optional for test)\n+ csmith (optional for fuzzing)\n  \n```\n# Install dependencies with apt\nwget -O- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -\nsudo add-apt-repository \"deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main\"\nsudo apt-get update\nsudo apt-get install csmith cmake z3 re2c ninja-build clang-18 llvm-18-dev libgtest-dev\n```\n\n### Build and Test\n```\ngit clone https://github.com/dtcxzyw/fsubfuscator.git\ncd fsubfuscator\nmkdir build\ncd build\n\ncmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DFSUBFUSCATOR_ENABLE_TESTS=ON ..\ncmake --build . -j\nctest # optional\n```\n## Usage\n```\n# Standalone\n./fsubfuscator test.ll -S -o out.ll\n# With wrapper\n# Note: O0 pipeline is not supported yet.\n./fsubcc -O3 test.c\n./fsub++ -O3 test.cpp\n./opt-fsub.sh -O3 test.ll -S -o out.ll\n# Use wrapper in your project with Make\nexport CC=\u003cpath to build\u003e/fsubcc\nexport CXX=\u003cpath to build\u003e/fsub++\nconfigure \u0026\u0026 make ...\n# Use wrapper in your project with CMake\ncmake -DCMAKE_C_COMPILER=\u003cpath to build\u003e/fsubcc -DCMAKE_CXX_COMPILER=\u003cpath to build\u003e/fsub++ ...\n# To use other bit representation instead of fsub\n./fsubfuscator -bitrep=\u003cFSub|Int1|InvInt1|Mod3\u003e test.ll -S -o out.ll\n# or use the environment variable (highest priority) to pass the parameter to clang\nexport FSUBFUSCATOR_BITREP_OVERRIDE=\u003cFSub|Int1|InvInt1|Mod3\u003e\n./fsubcc ...\n```\n\n## Extending fsubfuscator\n### Add a new bit representation\n+ Implement the new bit representation in `BitRep.cpp`. It should implement `BitRepBase` interface.\n+ Add a enum value to `BitRepMethod` in `BitRep.hpp`\n+ Add a switch case to `BitRepBase::createBitRep` in `BitRep.cpp`\n+ Add a unittest in `BitRepTest.cpp`\n+ Add a test in `CMakeLists.txt`\n\n### Handle new instructions\n+ Implement the rewriting logic in `FSubFuscatorPass.cpp`\n+ If it creates new blocks, make sure that the DomTree is updated correctly before calling `convertFromBit`\n+ Add some tests to `test.ll` and `test.cpp`\n\n## Example\n\n\nX86-64 Assembly for int4 a + b:\n\nBefore:\n```\nadd:                                    # @add\n        lea     eax, [rdi + rsi]\n        ret\n```\n\nAfter (with `-mcpu=skylake`):\n```\n.LCPI0_0:\n        .long   1                               # 0x1\n        .long   2                               # 0x2\n        .long   4                               # 0x4\n        .long   8                               # 0x8\n.LCPI0_1:\n        .long   0x80000000                      # float -0\nadd:                                    # @add\n        vmovd   xmm0, edi\n        vpbroadcastd    xmm0, xmm0\n        vmovdqa xmm1, xmmword ptr [rip + .LCPI0_0] # xmm1 = [1,2,4,8]\n        vpand   xmm0, xmm0, xmm1\n        vpxor   xmm2, xmm2, xmm2\n        vpcmpeqd        xmm3, xmm0, xmm2\n        vpbroadcastd    xmm0, dword ptr [rip + .LCPI0_1] # xmm0 = [-0.0E+0,-0.0E+0,-0.0E+0,-0.0E+0]\n        vpand   xmm3, xmm3, xmm0\n        vmovd   xmm4, esi\n        vpbroadcastd    xmm4, xmm4\n        vpand   xmm1, xmm4, xmm1\n        vpcmpeqd        xmm1, xmm1, xmm2\n        vpand   xmm2, xmm1, xmm0\n        vpxor   xmm1, xmm3, xmm0\n        vsubss  xmm4, xmm2, xmm3\n        vsubss  xmm5, xmm3, xmm2\n        vxorps  xmm5, xmm5, xmm0\n        vsubss  xmm6, xmm1, xmm2\n        vshufps xmm1, xmm3, xmm3, 245           # xmm1 = xmm3[1,1,3,3]\n        vshufps xmm7, xmm2, xmm2, 245           # xmm7 = xmm2[1,1,3,3]\n        vxorps  xmm8, xmm1, xmm0\n        vsubss  xmm9, xmm7, xmm1\n        vsubss  xmm1, xmm1, xmm7\n        vxorps  xmm1, xmm1, xmm0\n        vsubss  xmm9, xmm1, xmm9\n        vbroadcastss    xmm1, xmm9\n        vxorps  xmm10, xmm1, xmm0\n        vsubss  xmm7, xmm8, xmm7\n        vshufps xmm8, xmm3, xmm3, 78            # xmm8 = xmm3[2,3,0,1]\n        vshufps xmm11, xmm2, xmm2, 78           # xmm11 = xmm2[2,3,0,1]\n        vxorps  xmm12, xmm8, xmm0\n        vsubss  xmm13, xmm11, xmm8\n        vsubss  xmm8, xmm8, xmm11\n        vxorps  xmm8, xmm8, xmm0\n        vsubss  xmm8, xmm8, xmm13\n        vxorps  xmm13, xmm8, xmm0\n        vsubss  xmm11, xmm12, xmm11\n        vshufps xmm3, xmm3, xmm3, 255           # xmm3 = xmm3[3,3,3,3]\n        vshufps xmm2, xmm2, xmm2, 255           # xmm2 = xmm2[3,3,3,3]\n        vsubss  xmm12, xmm2, xmm3\n        vsubss  xmm2, xmm3, xmm2\n        vxorps  xmm2, xmm2, xmm0\n        vsubss  xmm2, xmm2, xmm12\n        vsubss  xmm3, xmm5, xmm4\n        vxorps  xmm4, xmm4, xmm4\n        vsubss  xmm5, xmm4, xmm3\n        vxorps  xmm5, xmm5, xmm0\n        vsubss  xmm5, xmm5, xmm6\n        vsubss  xmm6, xmm9, xmm5\n        vxorps  xmm6, xmm6, xmm0\n        vsubss  xmm9, xmm10, xmm5\n        vxorps  xmm9, xmm9, xmm0\n        vsubss  xmm7, xmm9, xmm7\n        vsubss  xmm9, xmm8, xmm7\n        vxorps  xmm9, xmm9, xmm0\n        vsubss  xmm10, xmm13, xmm7\n        vxorps  xmm10, xmm10, xmm0\n        vsubss  xmm10, xmm10, xmm11\n        vshufps xmm5, xmm5, xmm7, 0             # xmm5 = xmm5[0,0],xmm7[0,0]\n        vinsertps       xmm5, xmm5, xmm10, 48   # xmm5 = xmm5[0,1,2],xmm10[0]\n        vinsertps       xmm1, xmm1, xmm8, 32    # xmm1 = xmm1[0,1],xmm8[0],xmm1[3]\n        vinsertps       xmm1, xmm1, xmm2, 48    # xmm1 = xmm1[0,1,2],xmm2[0]\n        vsubps  xmm1, xmm5, xmm1\n        vaddss  xmm4, xmm3, xmm4\n        vblendps        xmm1, xmm1, xmm4, 1             # xmm1 = xmm4[0],xmm1[1,2,3]\n        vsubss  xmm2, xmm2, xmm10\n        vxorps  xmm0, xmm2, xmm0\n        vunpcklps       xmm2, xmm3, xmm6        # xmm2 = xmm3[0],xmm6[0],xmm3[1],xmm6[1]\n        vmovlhps        xmm2, xmm2, xmm9                # xmm2 = xmm2[0],xmm9[0]\n        vinsertps       xmm0, xmm2, xmm0, 48    # xmm0 = xmm2[0,1,2],xmm0[0]\n        vsubps  xmm0, xmm0, xmm1\n        vmovmskps       eax, xmm0\n        xor     eax, 15\n        ret\n```\n\n## Limitations\n\n+ It doesn't support bitfield since some integer operations with uncommon bitwidths are not supported by CodeGen.\n\n+ It doesn't support vectorized code yet. Currently it rewrites IR before vectorization.\n\n+ It doesn't work with `-ffast-math` since clang will ignore the sign of floating point zeros. See also https://clang.llvm.org/docs/UsersManual.html#controlling-floating-point-behavior.\n\n## License\nThis repository is licensed under the Apache License 2.0. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdtcxzyw%2Ffsubfuscator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdtcxzyw%2Ffsubfuscator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdtcxzyw%2Ffsubfuscator/lists"}