From 680aa95c48ffff0a6efe8a8388d46e03c234f0d6 Mon Sep 17 00:00:00 2001 From: Nicholas Lum Date: Tue, 8 Nov 2016 21:55:32 +0800 Subject: [PATCH 1/5] add mul obfuscation but the obfuscation will overflow so cannot be used --- lib/Transforms/Obfuscation/Substitution.cpp | 65 ++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/lib/Transforms/Obfuscation/Substitution.cpp b/lib/Transforms/Obfuscation/Substitution.cpp index c47d67e28e19..e441fb21b5df 100644 --- a/lib/Transforms/Obfuscation/Substitution.cpp +++ b/lib/Transforms/Obfuscation/Substitution.cpp @@ -18,6 +18,9 @@ #include "llvm/Transforms/Obfuscation/Utils.h" #include "llvm/IR/Intrinsics.h" +#include +#include + #define DEBUG_TYPE "substitution" #define NUMBER_ADD_SUBST 4 @@ -26,6 +29,8 @@ #define NUMBER_OR_SUBST 2 #define NUMBER_XOR_SUBST 2 +#define NUMBER_MUL_SUBST 1 + static cl::opt ObfTimes("sub-loop", cl::desc("Choose how many time the -sub pass loops on a function"), @@ -48,7 +53,7 @@ Percentage("perSUB", cl::init(100), // Stats STATISTIC(Add, "Add substitued"); STATISTIC(Sub, "Sub substitued"); -// STATISTIC(Mul, "Mul substitued"); +STATISTIC(Mul, "Mul substitued"); // STATISTIC(Div, "Div substitued"); // STATISTIC(Rem, "Rem substitued"); // STATISTIC(Shi, "Shift substitued"); @@ -65,6 +70,8 @@ struct Substitution : public FunctionPass { void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo); void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo); void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo); + + void (Substitution::*funcMul[NUMBER_MUL_SUBST])(BinaryOperator *bo); bool flag; Substitution() : FunctionPass(ID) {} @@ -95,6 +102,8 @@ struct Substitution : public FunctionPass { funcXor[0] = &Substitution::xorSubstitution; funcXor[1] = &Substitution::xorSubstitutionRand; + + funcMul[0] = &Substitution::mulSubstitution; } bool runOnFunction(Function &F); @@ -117,6 +126,8 @@ struct Substitution : public FunctionPass { void xorSubstitution(BinaryOperator *bo); void xorSubstitutionRand(BinaryOperator *bo); + + void mulSubstitution(BinaryOperator *bo); }; } @@ -161,7 +172,10 @@ bool Substitution::substitute(Function *f) { break; case BinaryOperator::Mul: case BinaryOperator::FMul: - //++Mul; + // substitute with mul + (this->*funcMul[llvm::cryptoutils->get_range(NUMBER_MUL_SUBST)])( + cast(inst)); + ++Mul; break; case BinaryOperator::UDiv: case BinaryOperator::SDiv: @@ -589,3 +603,50 @@ void Substitution::xorSubstitutionRand(BinaryOperator *bo) { bo->replaceAllUsesWith(op); } +// multiplication substitution +// a = b * c becomes: +// x = rand(); +// y = rand(); +// z = x * y; -> overflow +// a = b * x; +// a = a * c; +// a = a * y; +// a = a / z; +void Substitution::mulSubstitution(BinaryOperator *bo) { + BinaryOperator *a, *z = NULL; + + std::random_device rd; + std::mt19937 rng(rd()); + std::uniform_int_distribution uni(1, 2); + auto x_val = uni(rng); + auto y_val = uni(rng); + + Type *ty = bo->getType(); + + Value *b = bo->getOperand(0); + Value *c = bo->getOperand(1); + ConstantInt *x = (ConstantInt *)ConstantInt::get(ty, x_val); + ConstantInt *y = (ConstantInt *)ConstantInt::get(ty, y_val); + + // z = x * y + z = BinaryOperator::Create(Instruction::Mul, x, y, "", bo); + + // a = b * x + a = BinaryOperator::Create(Instruction::Mul, b, x, "", bo); + + // a = a * c + a = BinaryOperator::Create(Instruction::Mul, a, c, "", bo); + + // a = a * y + a = BinaryOperator::Create(Instruction::Mul, a, y, "", bo); + + // a = a / z + a = BinaryOperator::Create(Instruction::SDiv, a, z, "", bo); + + // Check signed wrap + a->setHasNoSignedWrap(bo->hasNoSignedWrap()); + a->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); + + bo->replaceAllUsesWith(a); +} + From 76420534051c81545236f72050957cb4bef5d9ab Mon Sep 17 00:00:00 2001 From: Nicholas Lum Date: Tue, 8 Nov 2016 22:59:08 +0800 Subject: [PATCH 2/5] add aha transform for xor --- .gitignore | 1 + lib/Transforms/Obfuscation/Substitution.cpp | 83 ++++++++------------- 2 files changed, 32 insertions(+), 52 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..b25c15b81fae --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/lib/Transforms/Obfuscation/Substitution.cpp b/lib/Transforms/Obfuscation/Substitution.cpp index e441fb21b5df..ae27ad423c4b 100644 --- a/lib/Transforms/Obfuscation/Substitution.cpp +++ b/lib/Transforms/Obfuscation/Substitution.cpp @@ -27,9 +27,7 @@ #define NUMBER_SUB_SUBST 3 #define NUMBER_AND_SUBST 2 #define NUMBER_OR_SUBST 2 -#define NUMBER_XOR_SUBST 2 - -#define NUMBER_MUL_SUBST 1 +#define NUMBER_XOR_SUBST 3 static cl::opt ObfTimes("sub-loop", @@ -53,7 +51,7 @@ Percentage("perSUB", cl::init(100), // Stats STATISTIC(Add, "Add substitued"); STATISTIC(Sub, "Sub substitued"); -STATISTIC(Mul, "Mul substitued"); +// STATISTIC(Mul, "Mul substitued"); // STATISTIC(Div, "Div substitued"); // STATISTIC(Rem, "Rem substitued"); // STATISTIC(Shi, "Shift substitued"); @@ -70,8 +68,6 @@ struct Substitution : public FunctionPass { void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo); void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo); void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo); - - void (Substitution::*funcMul[NUMBER_MUL_SUBST])(BinaryOperator *bo); bool flag; Substitution() : FunctionPass(ID) {} @@ -102,8 +98,7 @@ struct Substitution : public FunctionPass { funcXor[0] = &Substitution::xorSubstitution; funcXor[1] = &Substitution::xorSubstitutionRand; - - funcMul[0] = &Substitution::mulSubstitution; + funcXor[2] = &Substitution::xorSubstitutionAha; } bool runOnFunction(Function &F); @@ -126,8 +121,7 @@ struct Substitution : public FunctionPass { void xorSubstitution(BinaryOperator *bo); void xorSubstitutionRand(BinaryOperator *bo); - - void mulSubstitution(BinaryOperator *bo); + void xorSubstitutionAha(BinaryOperator *bo); }; } @@ -172,10 +166,7 @@ bool Substitution::substitute(Function *f) { break; case BinaryOperator::Mul: case BinaryOperator::FMul: - // substitute with mul - (this->*funcMul[llvm::cryptoutils->get_range(NUMBER_MUL_SUBST)])( - cast(inst)); - ++Mul; + //++Mul; break; case BinaryOperator::UDiv: case BinaryOperator::SDiv: @@ -198,17 +189,17 @@ bool Substitution::substitute(Function *f) { break; case Instruction::And: (this->* - funcAnd[llvm::cryptoutils->get_range(2)])(cast(inst)); + funcAnd[llvm::cryptoutils->get_range(NUMBER_AND_SUBST)])(cast(inst)); ++And; break; case Instruction::Or: (this->* - funcOr[llvm::cryptoutils->get_range(2)])(cast(inst)); + funcOr[llvm::cryptoutils->get_range(NUMBER_OR_SUBST)])(cast(inst)); ++Or; break; case Instruction::Xor: (this->* - funcXor[llvm::cryptoutils->get_range(2)])(cast(inst)); + funcXor[llvm::cryptoutils->get_range(NUMBER_XOR_SUBST)])(cast(inst)); ++Xor; break; default: @@ -603,45 +594,33 @@ void Substitution::xorSubstitutionRand(BinaryOperator *bo) { bo->replaceAllUsesWith(op); } -// multiplication substitution -// a = b * c becomes: -// x = rand(); -// y = rand(); -// z = x * y; -> overflow -// a = b * x; -// a = a * c; -// a = a * y; -// a = a / z; -void Substitution::mulSubstitution(BinaryOperator *bo) { - BinaryOperator *a, *z = NULL; - - std::random_device rd; - std::mt19937 rng(rd()); - std::uniform_int_distribution uni(1, 2); - auto x_val = uni(rng); - auto y_val = uni(rng); - +// XOR substitution using the method found in the Aha! superoptimizer +// https://yurichev.com/blog/llvm/ +// +// a = b XOR c = ((b AND c) * -2) + b + c +// a = b AND c; +// a = a * -2; +// a = a + b; +// a = a + c; +void Substitution::xorSubstitutionAha(BinaryOperator *bo) { + BinaryOperator *a = NULL; Type *ty = bo->getType(); + ConstantInt *negTwo = (ConstantInt *)ConstantInt::get(ty, -2, true); Value *b = bo->getOperand(0); Value *c = bo->getOperand(1); - ConstantInt *x = (ConstantInt *)ConstantInt::get(ty, x_val); - ConstantInt *y = (ConstantInt *)ConstantInt::get(ty, y_val); - - // z = x * y - z = BinaryOperator::Create(Instruction::Mul, x, y, "", bo); - - // a = b * x - a = BinaryOperator::Create(Instruction::Mul, b, x, "", bo); - - // a = a * c - a = BinaryOperator::Create(Instruction::Mul, a, c, "", bo); - - // a = a * y - a = BinaryOperator::Create(Instruction::Mul, a, y, "", bo); - - // a = a / z - a = BinaryOperator::Create(Instruction::SDiv, a, z, "", bo); + + // a = b AND c; + a = BinaryOperator::Create(Instruction::And, b, c, "", bo); + + // a = a * -2 + a = BinaryOperator::Create(Instruction::Mul, a, negTwo, "", bo); + + // a = a + b + a = BinaryOperator::Create(Instruction::Add, a, b, "", bo); + + // a = a + c + a = BinaryOperator::Create(Instruction::Add, a, c, "", bo); // Check signed wrap a->setHasNoSignedWrap(bo->hasNoSignedWrap()); From acb4a5d41a87ebe60c0d1a3e927b67144b766b59 Mon Sep 17 00:00:00 2001 From: Nicholas Lum Date: Wed, 9 Nov 2016 00:49:34 +0800 Subject: [PATCH 3/5] add aha method for add works --- lib/Transforms/Obfuscation/Substitution.cpp | 39 +++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/Transforms/Obfuscation/Substitution.cpp b/lib/Transforms/Obfuscation/Substitution.cpp index ae27ad423c4b..1c61c9be77d5 100644 --- a/lib/Transforms/Obfuscation/Substitution.cpp +++ b/lib/Transforms/Obfuscation/Substitution.cpp @@ -23,7 +23,7 @@ #define DEBUG_TYPE "substitution" -#define NUMBER_ADD_SUBST 4 +#define NUMBER_ADD_SUBST 5 #define NUMBER_SUB_SUBST 3 #define NUMBER_AND_SUBST 2 #define NUMBER_OR_SUBST 2 @@ -85,6 +85,7 @@ struct Substitution : public FunctionPass { funcAdd[1] = &Substitution::addDoubleNeg; funcAdd[2] = &Substitution::addRand; funcAdd[3] = &Substitution::addRand2; + funcAdd[4] = &Substitution::addAha; funcSub[0] = &Substitution::subNeg; funcSub[1] = &Substitution::subRand; @@ -108,6 +109,7 @@ struct Substitution : public FunctionPass { void addDoubleNeg(BinaryOperator *bo); void addRand(BinaryOperator *bo); void addRand2(BinaryOperator *bo); + void addAha(BinaryOperator *bo); void subNeg(BinaryOperator *bo); void subRand(BinaryOperator *bo); @@ -153,7 +155,7 @@ bool Substitution::substitute(Function *f) { case BinaryOperator::Add: // case BinaryOperator::FAdd: // Substitute with random add operation - (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])( + (this->*funcAdd[/*llvm::cryptoutils->get_range(*/NUMBER_ADD_SUBST-1/*)*/])( cast(inst)); ++Add; break; @@ -317,6 +319,37 @@ void Substitution::addRand2(BinaryOperator *bo) { } */ } +// using the aha! method to do add +// since we get b XOR c = ((b AND c) * -2) + (b + c) +// we convert to a = b + c = (b XOR c) - ((b AND c) * -2) +// +// a = b XOR c +// x = b AND c +// x = x * -2 +// a = a - x +void Substitution::addAha(BinaryOperator *bo) { + BinaryOperator *a, *x = NULL; + + if (bo->getOpcode() == Instruction::Add) { + Type *ty = bo->getType(); + + ConstantInt *negTwo = (ConstantInt *)ConstantInt::get(ty, -2, true); + Value *b = bo->getOperand(0); + Value *c = bo->getOperand(1); + + a = BinaryOperator::Create(Instruction::Xor, b, c, "", bo); + x = BinaryOperator::Create(Instruction::And, b, c, "", bo); + x = BinaryOperator::Create(Instruction::Mul, x, negTwo, "", bo); + a = BinaryOperator::Create(Instruction::Sub, a, x, "", bo); + + // Check signed wrap + a->setHasNoSignedWrap(bo->hasNoSignedWrap()); + a->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); + } + + bo->replaceAllUsesWith(a); +} + // Implementation of a = b + (-c) void Substitution::subNeg(BinaryOperator *bo) { BinaryOperator *op = NULL; @@ -596,8 +629,8 @@ void Substitution::xorSubstitutionRand(BinaryOperator *bo) { // XOR substitution using the method found in the Aha! superoptimizer // https://yurichev.com/blog/llvm/ -// // a = b XOR c = ((b AND c) * -2) + b + c +// // a = b AND c; // a = a * -2; // a = a + b; From 63f4775d669f595c20c03a926c19f811101b2975 Mon Sep 17 00:00:00 2001 From: Nicholas Lum Date: Wed, 9 Nov 2016 01:21:35 +0800 Subject: [PATCH 4/5] add aha substitution for minus also --- lib/Transforms/Obfuscation/Substitution.cpp | 38 +++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/Transforms/Obfuscation/Substitution.cpp b/lib/Transforms/Obfuscation/Substitution.cpp index 1c61c9be77d5..048bce8ec886 100644 --- a/lib/Transforms/Obfuscation/Substitution.cpp +++ b/lib/Transforms/Obfuscation/Substitution.cpp @@ -24,7 +24,7 @@ #define DEBUG_TYPE "substitution" #define NUMBER_ADD_SUBST 5 -#define NUMBER_SUB_SUBST 3 +#define NUMBER_SUB_SUBST 4 #define NUMBER_AND_SUBST 2 #define NUMBER_OR_SUBST 2 #define NUMBER_XOR_SUBST 3 @@ -90,6 +90,7 @@ struct Substitution : public FunctionPass { funcSub[0] = &Substitution::subNeg; funcSub[1] = &Substitution::subRand; funcSub[2] = &Substitution::subRand2; + funcSub[3] = &Substitution::subAha; funcAnd[0] = &Substitution::andSubstitution; funcAnd[1] = &Substitution::andSubstitutionRand; @@ -114,6 +115,7 @@ struct Substitution : public FunctionPass { void subNeg(BinaryOperator *bo); void subRand(BinaryOperator *bo); void subRand2(BinaryOperator *bo); + void subAha(BinaryOperator *bo); void andSubstitution(BinaryOperator *bo); void andSubstitutionRand(BinaryOperator *bo); @@ -155,7 +157,7 @@ bool Substitution::substitute(Function *f) { case BinaryOperator::Add: // case BinaryOperator::FAdd: // Substitute with random add operation - (this->*funcAdd[/*llvm::cryptoutils->get_range(*/NUMBER_ADD_SUBST-1/*)*/])( + (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])( cast(inst)); ++Add; break; @@ -350,6 +352,38 @@ void Substitution::addAha(BinaryOperator *bo) { bo->replaceAllUsesWith(a); } +// using the aha! method to do sub +// since we get b XOR c = ((b AND c) * -2) + (b + c) +// we convert to a = b + -c = (b XOR -c) - ((b AND -c) * -2) +// +// a = b XOR -c +// x = b AND -c +// x = x * -2 +// a = a - x +void Substitution::subAha(BinaryOperator *bo) { + BinaryOperator *a, *x, *c = NULL; + + if (bo->getOpcode() == Instruction::Sub) { + Type *ty = bo->getType(); + + ConstantInt *negTwo = (ConstantInt *)ConstantInt::get(ty, -2, true); + Value *b = bo->getOperand(0); + c = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); + + + a = BinaryOperator::Create(Instruction::Xor, b, c, "", bo); + x = BinaryOperator::Create(Instruction::And, b, c, "", bo); + x = BinaryOperator::Create(Instruction::Mul, x, negTwo, "", bo); + a = BinaryOperator::Create(Instruction::Sub, a, x, "", bo); + + // Check signed wrap + a->setHasNoSignedWrap(bo->hasNoSignedWrap()); + a->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); + } + + bo->replaceAllUsesWith(a); +} + // Implementation of a = b + (-c) void Substitution::subNeg(BinaryOperator *bo) { BinaryOperator *op = NULL; From da4ec6b0691fcf05168086142f5befd938e2db9e Mon Sep 17 00:00:00 2001 From: Nicholas Lum Date: Mon, 14 Nov 2016 04:07:22 +0800 Subject: [PATCH 5/5] update add, sub. add and. add and sub updated to not use mul and substitution added force to use newly implemented substitutions instead of previously implemented --- lib/Transforms/Obfuscation/Substitution.cpp | 127 +++++++++++++++++--- 1 file changed, 107 insertions(+), 20 deletions(-) diff --git a/lib/Transforms/Obfuscation/Substitution.cpp b/lib/Transforms/Obfuscation/Substitution.cpp index 048bce8ec886..cd9419e041cb 100644 --- a/lib/Transforms/Obfuscation/Substitution.cpp +++ b/lib/Transforms/Obfuscation/Substitution.cpp @@ -25,9 +25,9 @@ #define NUMBER_ADD_SUBST 5 #define NUMBER_SUB_SUBST 4 -#define NUMBER_AND_SUBST 2 +#define NUMBER_AND_SUBST 3 #define NUMBER_OR_SUBST 2 -#define NUMBER_XOR_SUBST 3 +#define NUMBER_XOR_SUBST 4 static cl::opt ObfTimes("sub-loop", @@ -94,6 +94,7 @@ struct Substitution : public FunctionPass { funcAnd[0] = &Substitution::andSubstitution; funcAnd[1] = &Substitution::andSubstitutionRand; + funcAnd[2] = &Substitution::andSubstitutionRandExp; funcOr[0] = &Substitution::orSubstitution; funcOr[1] = &Substitution::orSubstitutionRand; @@ -101,6 +102,7 @@ struct Substitution : public FunctionPass { funcXor[0] = &Substitution::xorSubstitution; funcXor[1] = &Substitution::xorSubstitutionRand; funcXor[2] = &Substitution::xorSubstitutionAha; + funcXor[3] = &Substitution::xorSubstitutionAhaOpt; } bool runOnFunction(Function &F); @@ -119,6 +121,7 @@ struct Substitution : public FunctionPass { void andSubstitution(BinaryOperator *bo); void andSubstitutionRand(BinaryOperator *bo); + void andSubstitutionRandExp(BinaryOperator *bo); void orSubstitution(BinaryOperator *bo); void orSubstitutionRand(BinaryOperator *bo); @@ -126,6 +129,7 @@ struct Substitution : public FunctionPass { void xorSubstitution(BinaryOperator *bo); void xorSubstitutionRand(BinaryOperator *bo); void xorSubstitutionAha(BinaryOperator *bo); + void xorSubstitutionAhaOpt(BinaryOperator *bo); }; } @@ -157,14 +161,14 @@ bool Substitution::substitute(Function *f) { case BinaryOperator::Add: // case BinaryOperator::FAdd: // Substitute with random add operation - (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])( + (this->*funcAdd[/*llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)*/4])( cast(inst)); ++Add; break; case BinaryOperator::Sub: // case BinaryOperator::FSub: // Substitute with random sub operation - (this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])( + (this->*funcSub[/*llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)*/3])( cast(inst)); ++Sub; break; @@ -193,7 +197,7 @@ bool Substitution::substitute(Function *f) { break; case Instruction::And: (this->* - funcAnd[llvm::cryptoutils->get_range(NUMBER_AND_SUBST)])(cast(inst)); + funcAnd[/*llvm::cryptoutils->get_range(NUMBER_AND_SUBST)*/2])(cast(inst)); ++And; break; case Instruction::Or: @@ -203,7 +207,7 @@ bool Substitution::substitute(Function *f) { break; case Instruction::Xor: (this->* - funcXor[llvm::cryptoutils->get_range(NUMBER_XOR_SUBST)])(cast(inst)); + funcXor[/*llvm::cryptoutils->get_range(NUMBER_XOR_SUBST)*/3])(cast(inst)); ++Xor; break; default: @@ -327,22 +331,19 @@ void Substitution::addRand2(BinaryOperator *bo) { // // a = b XOR c // x = b AND c -// x = x * -2 -// a = a - x +// x = x + x +// a = a + x void Substitution::addAha(BinaryOperator *bo) { BinaryOperator *a, *x = NULL; if (bo->getOpcode() == Instruction::Add) { - Type *ty = bo->getType(); - - ConstantInt *negTwo = (ConstantInt *)ConstantInt::get(ty, -2, true); Value *b = bo->getOperand(0); Value *c = bo->getOperand(1); a = BinaryOperator::Create(Instruction::Xor, b, c, "", bo); x = BinaryOperator::Create(Instruction::And, b, c, "", bo); - x = BinaryOperator::Create(Instruction::Mul, x, negTwo, "", bo); - a = BinaryOperator::Create(Instruction::Sub, a, x, "", bo); + x = BinaryOperator::Create(Instruction::Add, x, x, "", bo); + a = BinaryOperator::Create(Instruction::Add, a, x, "", bo); // Check signed wrap a->setHasNoSignedWrap(bo->hasNoSignedWrap()); @@ -356,10 +357,11 @@ void Substitution::addAha(BinaryOperator *bo) { // since we get b XOR c = ((b AND c) * -2) + (b + c) // we convert to a = b + -c = (b XOR -c) - ((b AND -c) * -2) // -// a = b XOR -c -// x = b AND -c -// x = x * -2 -// a = a - x +// c = -c +// a = b XOR c +// x = b AND c +// x = x + x +// a = a + x void Substitution::subAha(BinaryOperator *bo) { BinaryOperator *a, *x, *c = NULL; @@ -373,8 +375,8 @@ void Substitution::subAha(BinaryOperator *bo) { a = BinaryOperator::Create(Instruction::Xor, b, c, "", bo); x = BinaryOperator::Create(Instruction::And, b, c, "", bo); - x = BinaryOperator::Create(Instruction::Mul, x, negTwo, "", bo); - a = BinaryOperator::Create(Instruction::Sub, a, x, "", bo); + x = BinaryOperator::Create(Instruction::Add, x, x, "", bo); + a = BinaryOperator::Create(Instruction::Add, a, x, "", bo); // Check signed wrap a->setHasNoSignedWrap(bo->hasNoSignedWrap()); @@ -517,6 +519,56 @@ void Substitution::andSubstitutionRand(BinaryOperator *bo) { bo->replaceAllUsesWith(op); } +// b AND c = (b AND c) OR (r AND !r) +// = (b OR r) AND (c OR r) AND (b OR !r) AND (c or !r) + +// r = rand() +// s = !r +// w = b OR r +// x = c OR r +// y = b OR s +// z = c OR s +// a = w AND x +// a = a AND y +// a = a AND z +void Substitution::andSubstitutionRandExp(BinaryOperator *bo) { + BinaryOperator *a, *s, *w, *x, *y, *z = NULL; + + Type *ty = bo->getType(); + auto r_val = llvm::cryptoutils->get_uint64_t(); + ConstantInt *r = (ConstantInt *)ConstantInt::get(ty, r_val); + s = BinaryOperator::CreateNot(r, "", bo); + Value *b = bo->getOperand(0); + Value *c = bo->getOperand(1); + + // w = b OR r + w = BinaryOperator::Create(Instruction::Or, b, r, "", bo); + + // x = c OR r + x = BinaryOperator::Create(Instruction::Or, c, r, "", bo); + + // y = b OR s + y = BinaryOperator::Create(Instruction::Or, b, s, "", bo); + + // z = c OR s + z = BinaryOperator::Create(Instruction::Or, c, s, "", bo); + + // a = w AND x + a = BinaryOperator::Create(Instruction::And, w, x, "", bo); + + // a = a AND y + a = BinaryOperator::Create(Instruction::And, a, y, "", bo); + + // a = a AND z + a = BinaryOperator::Create(Instruction::And, a, z, "", bo); + + // Check signed wrap + a->setHasNoSignedWrap(bo->hasNoSignedWrap()); + a->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); + + bo->replaceAllUsesWith(a); +} + // Implementation of a = b | c => a = (b & c) | (b ^ c) void Substitution::orSubstitutionRand(BinaryOperator *bo) { @@ -662,7 +714,7 @@ void Substitution::xorSubstitutionRand(BinaryOperator *bo) { } // XOR substitution using the method found in the Aha! superoptimizer -// https://yurichev.com/blog/llvm/ +// https://yurichev.com/blog/llvm/ // a = b XOR c = ((b AND c) * -2) + b + c // // a = b AND c; @@ -696,3 +748,38 @@ void Substitution::xorSubstitutionAha(BinaryOperator *bo) { bo->replaceAllUsesWith(a); } +// Optimised aha! substitution. +// Does not use expensive multiply operation +// a = b XOR c = b + c - 2 * (b AND c) = b + c - ((b AND c) + (b AND c)) +// However we still keep the non-opt version as the mul might be effective at +// obfuscating as well +// +// x = b AND c +// x = x + x +// a = b + c +// a = a - x +void Substitution::xorSubstitutionAhaOpt(BinaryOperator *bo) { + BinaryOperator *a, *x = NULL; + + Value *b = bo->getOperand(0); + Value *c = bo->getOperand(1); + + // x = b AND c; + x = BinaryOperator::Create(Instruction::And, b, c, "", bo); + + // x = x + x + x = BinaryOperator::Create(Instruction::Add, x, x, "", bo); + + // a = b + c + a = BinaryOperator::Create(Instruction::Add, b, c, "", bo); + + // a = a - x + a = BinaryOperator::Create(Instruction::Sub, a, x, "", bo); + + // Check signed wrap + a->setHasNoSignedWrap(bo->hasNoSignedWrap()); + a->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); + + bo->replaceAllUsesWith(a); +} +