From 7f42d309dcd586963dc05616de52bc8e3a9b103c Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 12 Oct 2023 23:45:11 +0800 Subject: [PATCH] feat: add Mod3 bitrep --- BitRep.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ BitRep.hpp | 1 + BitRepTest.cpp | 2 ++ CMakeLists.txt | 1 + FSubFuscatorPass.cpp | 4 +++- README.md | 4 ++-- 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/BitRep.cpp b/BitRep.cpp index ee92759..fd0d4a8 100644 --- a/BitRep.cpp +++ b/BitRep.cpp @@ -106,6 +106,48 @@ struct InvInt1BitRep final : public BitRepBase { } }; +struct Mod3BitRep final : public BitRepBase { + explicit Mod3BitRep(IRBuilder<> &Builder) : BitRepBase(Builder) {} + + Type *getBitTy() override { return Builder.getInt32Ty(); } + Constant *getBit0() override { return Builder.getInt32(1); } + Constant *getBit1() override { return Builder.getInt32(2); } + + // handle vector of i1 + Value *convertToBit(Value *V) override { + auto *VT = V->getType()->getWithNewType(getBitTy()); + return Builder.CreateSelect(V, ConstantInt::get(VT, 2), + ConstantInt::get(VT, 1)); + } + // handle vector of bitTy + Value *convertFromBit(Value *V) override { + return Builder.CreateICmpSGT(V, ConstantInt::get(V->getType(), 1)); + } + + Value *bitNot(Value *V) override { + return Builder.CreateURem(Builder.CreateShl(V, 1), + ConstantInt::get(V->getType(), 3)); + } + Value *bitXor(Value *V1, Value *V2) override { + return Builder.CreateURem(Builder.CreateMul(V1, V2), + ConstantInt::get(V1->getType(), 3)); + } + Value *bitOr(Value *V1, Value *V2) override { + auto *One = ConstantInt::get(V1->getType(), 1); + return Builder.CreateSub( + ConstantInt::get(V1->getType(), 2), + Builder.CreateURem(Builder.CreateMul(Builder.CreateAdd(V1, One), + Builder.CreateAdd(V2, One)), + ConstantInt::get(V1->getType(), 3))); + } + Value *bitAnd(Value *V1, Value *V2) override { + auto *One = ConstantInt::get(V1->getType(), 1); + return Builder.CreateAdd(Builder.CreateMul(Builder.CreateSub(V1, One), + Builder.CreateSub(V2, One)), + One); + } +}; + std::unique_ptr BitRepBase::createBitRep(IRBuilder<> &Builder, BitRepMethod Method) { switch (Method) { @@ -115,6 +157,8 @@ std::unique_ptr BitRepBase::createBitRep(IRBuilder<> &Builder, return std::make_unique(Builder); case InvInt1: return std::make_unique(Builder); + case Mod3: + return std::make_unique(Builder); default: llvm_unreachable("Unexpected bit representation method"); } diff --git a/BitRep.hpp b/BitRep.hpp index 4d190a9..e9efab6 100644 --- a/BitRep.hpp +++ b/BitRep.hpp @@ -21,6 +21,7 @@ enum BitRepMethod { FSub, Int1, InvInt1, + Mod3, DefaultBitRep = FSub, }; diff --git a/BitRepTest.cpp b/BitRepTest.cpp index 9547ead..2a1e8bb 100644 --- a/BitRepTest.cpp +++ b/BitRepTest.cpp @@ -98,6 +98,8 @@ TEST_F(BinRepTest, MethodInvInt1) { TEST_F(BinRepTest, MethodFSub) { testBitRep(Builder, BitRepMethod::FSub); } +TEST_F(BinRepTest, MethodMod3) { testBitRep(Builder, BitRepMethod::Mod3); } + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); InitLLVM Init{argc, argv}; diff --git a/CMakeLists.txt b/CMakeLists.txt index 14dc47c..e60f0e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ if (${FSUBFUSCATOR_ENABLE_TESTS}) add_test(NAME test_standalone_int1 COMMAND sh -c "${FSUBFUSCATOR_EXECUTABLE} -S -bitrep=Int1 test.ll -o ${CMAKE_BINARY_DIR}/test_int1.ll && ${ALIVE2} test.ll ${CMAKE_BINARY_DIR}/test_int1.ll" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME test_standalone_invint1 COMMAND sh -c "${FSUBFUSCATOR_EXECUTABLE} -S -bitrep=InvInt1 test.ll -o ${CMAKE_BINARY_DIR}/test_invint1.ll && ${ALIVE2} test.ll ${CMAKE_BINARY_DIR}/test_invint1.ll" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_test(NAME test_standalone_mod3 COMMAND sh -c "${FSUBFUSCATOR_EXECUTABLE} -S -bitrep=Mod3 test.ll -o ${CMAKE_BINARY_DIR}/test_mod3.ll" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME test_standalone_fsub COMMAND ${FSUBFUSCATOR_EXECUTABLE} -S -bitrep=FSub test.ll -o ${CMAKE_BINARY_DIR}/test_fsub.ll WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME test_opt COMMAND ${OPT} -O3 -S -load-pass-plugin ${FSUBFUSCATOR_PLUGIN} test.ll -o ${CMAKE_BINARY_DIR}/test_opt.ll WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME test_clang COMMAND ${CLANG} -O3 -c -emit-llvm -S -fpass-plugin=${FSUBFUSCATOR_PLUGIN} test.c -o ${CMAKE_BINARY_DIR}/test_clang.ll WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/FSubFuscatorPass.cpp b/FSubFuscatorPass.cpp index 354c6b5..124628d 100644 --- a/FSubFuscatorPass.cpp +++ b/FSubFuscatorPass.cpp @@ -54,7 +54,8 @@ static cl::opt RepMethod( "bitrep", cl::desc("Bit representation to use"), cl::values(clEnumVal(FSub, "Default: Use fsub and f32. (T=0.0, F=-0.0)"), clEnumVal(Int1, "Use bitwise and i1. (T=true, F=false)"), - clEnumVal(InvInt1, "Use bitwise and i1. (T=false, F=true)")), + clEnumVal(InvInt1, "Use bitwise and i1. (T=false, F=true)"), + clEnumVal(Mod3, "Use mod and i32. (T=2, F=1)")), cl::init(DefaultBitRep), cl::cat(FsubFuscatorCategory)); class BitFuscatorImpl final : public InstVisitor { @@ -765,6 +766,7 @@ class BitFuscatorImpl final : public InstVisitor { .Case("Int1", BitRepMethod::Int1) .Case("InvInt1", BitRepMethod::InvInt1) .Case("FSub", BitRepMethod::FSub) + .Case("Mod3", BitRepMethod::Mod3) .Default(BitRepMethod::DefaultBitRep); } return RepMethod; diff --git a/README.md b/README.md index 229b94b..b18ffb4 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,9 @@ configure && make ... # Use wrapper in your project with CMake cmake -DCMAKE_C_COMPILER=/fsubcc -DCMAKE_CXX_COMPILER=/fsub++ ... # To use other bit representation instead of fsub -./fsubfuscator -bitrep= test.ll -S -o out.ll +./fsubfuscator -bitrep= test.ll -S -o out.ll # or use the environment variable (highest priority) to pass the parameter to clang -export FSUBFUSCATOR_BITREP_OVERRIDE= +export FSUBFUSCATOR_BITREP_OVERRIDE= ./fsubcc ... ```