指令替换(Instruction Substitution)是一种代码混淆技术,用于将程序中的原始指令替换为等效但更难理解和还原的指令序列。通过指令替换,可以增加程序的复杂性和抵抗逆向工程的能力。
指令替换可以采用不同的方式进行,下面是一些常见的替换方式:
常量展开(Constant Unfold):将原始指令中的常量操作替换为等效的指令序列,增加了代码的复杂性和可读性。例如,将乘法操作替换为逐位移位和加法操作:
算术替换(Arithmetic Substitution):将原始指令中的算术操作替换为等效的其他算术操作,使得代码更难理解。例如,在加法和减法之间进行替换:
逻辑替换(Logical Substitution):将原始指令中的逻辑操作替换为其他等效的逻辑操作,增加代码的混淆性。例如,将逻辑与替换为逻辑或:
//===- Substitution.cpp - Substitution Obfuscation
// pass-------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements operators substitution's pass
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Obfuscation/Substitution.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Obfuscation/Utils.h"
#include "llvm/IR/Intrinsics.h"
#define DEBUG_TYPE "substitution"
#define NUMBER_ADD_SUBST 4
#define NUMBER_SUB_SUBST 3
#define NUMBER_AND_SUBST 2
#define NUMBER_OR_SUBST 2
#define NUMBER_XOR_SUBST 2
static cl::opt
ObfTimes("sub_loop",
cl::desc("Choose how many time the -sub pass loops on a function"),
cl::value_desc("number of times"), cl::init(1), cl::Optional);
// Stats
STATISTIC(Add, "Add substitued");
STATISTIC(Sub, "Sub substitued");
// STATISTIC(Mul, "Mul substitued");
// STATISTIC(Div, "Div substitued");
// STATISTIC(Rem, "Rem substitued");
// STATISTIC(Shi, "Shift substitued");
STATISTIC(And, "And substitued");
STATISTIC(Or, "Or substitued");
STATISTIC(Xor, "Xor substitued");
namespace {
struct Substitution : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
void (Substitution::*funcAdd[NUMBER_ADD_SUBST])(BinaryOperator *bo);
void (Substitution::*funcSub[NUMBER_SUB_SUBST])(BinaryOperator *bo);
void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo);
void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo);
void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo);
bool flag;
Substitution() : FunctionPass(ID) {}
Substitution(bool flag) : FunctionPass(ID) {
this->flag = flag;
funcAdd[0] = &Substitution::addNeg;
funcAdd[1] = &Substitution::addDoubleNeg;
funcAdd[2] = &Substitution::addRand;
funcAdd[3] = &Substitution::addRand2;
funcSub[0] = &Substitution::subNeg;
funcSub[1] = &Substitution::subRand;
funcSub[2] = &Substitution::subRand2;
funcAnd[0] = &Substitution::andSubstitution;
funcAnd[1] = &Substitution::andSubstitutionRand;
funcOr[0] = &Substitution::orSubstitution;
funcOr[1] = &Substitution::orSubstitutionRand;
funcXor[0] = &Substitution::xorSubstitution;
funcXor[1] = &Substitution::xorSubstitutionRand;
}
bool runOnFunction(Function &F);
bool substitute(Function *f);
void addNeg(BinaryOperator *bo);
void addDoubleNeg(BinaryOperator *bo);
void addRand(BinaryOperator *bo);
void addRand2(BinaryOperator *bo);
void subNeg(BinaryOperator *bo);
void subRand(BinaryOperator *bo);
void subRand2(BinaryOperator *bo);
void andSubstitution(BinaryOperator *bo);
void andSubstitutionRand(BinaryOperator *bo);
void orSubstitution(BinaryOperator *bo);
void orSubstitutionRand(BinaryOperator *bo);
void xorSubstitution(BinaryOperator *bo);
void xorSubstitutionRand(BinaryOperator *bo);
};
}
char Substitution::ID = 0;
static RegisterPass X("substitution", "operators substitution");
Pass *llvm::createSubstitution(bool flag) { return new Substitution(flag); }
bool Substitution::runOnFunction(Function &F) {
// Check if the percentage is correct
if (ObfTimes <= 0) {
errs()<<"Substitution application number -sub_loop=x must be x > 0";
return false;
}
Function *tmp = &F;
// Do we obfuscate
if (toObfuscate(flag, tmp, "sub")) {
substitute(tmp);
return true;
}
return false;
}
bool Substitution::substitute(Function *f) {
Function *tmp = f;
// Loop for the number of time we run the pass on the function
int times = ObfTimes;
do {
for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) {
for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) {
if (inst->isBinaryOp()) {
switch (inst->getOpcode()) {
case BinaryOperator::Add:
// case BinaryOperator::FAdd:
// Substitute with random add operation
(this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])(
cast(inst));
++Add;
break;
case BinaryOperator::Sub:
// case BinaryOperator::FSub:
// Substitute with random sub operation
(this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])(
cast(inst));
++Sub;
break;
case BinaryOperator::Mul:
case BinaryOperator::FMul:
//++Mul;
break;
case BinaryOperator::UDiv:
case BinaryOperator::SDiv:
case BinaryOperator::FDiv:
//++Div;
break;
case BinaryOperator::URem:
case BinaryOperator::SRem:
case BinaryOperator::FRem:
//++Rem;
break;
case Instruction::Shl:
//++Shi;
break;
case Instruction::LShr:
//++Shi;
break;
case Instruction::AShr:
//++Shi;
break;
case Instruction::And:
(this->*
funcAnd[llvm::cryptoutils->get_range(2)])(cast(inst));
++And;
break;
case Instruction::Or:
(this->*
funcOr[llvm::cryptoutils->get_range(2)])(cast(inst));
++Or;
break;
case Instruction::Xor:
(this->*
funcXor[llvm::cryptoutils->get_range(2)])(cast(inst));
++Xor;
break;
default:
break;
} // End switch
} // End isBinaryOp
} // End for basickblock
} // End for Function
} while (--times > 0); // for times
return false;
}
// Implementation of a = b - (-c)
void Substitution::addNeg(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create sub
if (bo->getOpcode() == Instruction::Add) {
op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op =
BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}/* else {
op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FSub, bo->getOperand(0), op, "",
bo);
}*/
}
// Implementation of a = -(-b + (-c))
void Substitution::addDoubleNeg(BinaryOperator *bo) {
BinaryOperator *op, *op2 = NULL;
if (bo->getOpcode() == Instruction::Add) {
op = BinaryOperator::CreateNeg(bo->getOperand(0), "", bo);
op2 = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, op2, "", bo);
op = BinaryOperator::CreateNeg(op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
} else {
op = BinaryOperator::CreateFNeg(bo->getOperand(0), "", bo);
op2 = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FAdd, op, op2, "", bo);
op = BinaryOperator::CreateFNeg(op, "", bo);
}
bo->replaceAllUsesWith(op);
}
// Implementation of r = rand (); a = b + r; a = a + c; a = a - r
void Substitution::addRand(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Add) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo);
} */
}
// Implementation of r = rand (); a = b - r; a = a + b; a = a + r
void Substitution::addRand2(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Add) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo);
} */
}
// Implementation of a = b + (-c)
void Substitution::subNeg(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Sub) {
op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op =
BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
} else {
op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FAdd, bo->getOperand(0), op, "",
bo);
}
bo->replaceAllUsesWith(op);
}
// Implementation of r = rand (); a = b + r; a = a - c; a = a - r
void Substitution::subRand(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Sub) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo);
} */
}
// Implementation of r = rand (); a = b - r; a = a - c; a = a + r
void Substitution::subRand2(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Sub) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FSub,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FAdd,op,co,"",bo);
} */
}
// Implementation of a = b & c => a = (b^~c)& b
void Substitution::andSubstitution(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create NOT on second operand => ~c
op = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// Create XOR => (b^~c)
BinaryOperator *op1 =
BinaryOperator::Create(Instruction::Xor, bo->getOperand(0), op, "", bo);
// Create AND => (b^~c) & b
op = BinaryOperator::Create(Instruction::And, op1, bo->getOperand(0), "", bo);
bo->replaceAllUsesWith(op);
}
// Implementation of a = a && b <=> !(!a | !b) && (r | !r)
void Substitution::andSubstitutionRand(BinaryOperator *bo) {
// Copy of the BinaryOperator type to create the random number with the
// same type of the operands
Type *ty = bo->getType();
// r (Random number)
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
// !a
BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo);
// !b
BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// !r
BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo);
// (!a | !b)
BinaryOperator *opa =
BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
// (r | !r)
opr = BinaryOperator::Create(Instruction::Or, co, opr, "", bo);
// !(!a | !b)
op = BinaryOperator::CreateNot(opa, "", bo);
// !(!a | !b) && (r | !r)
op = BinaryOperator::Create(Instruction::And, op, opr, "", bo);
// We replace all the old AND operators with the new one transformed
bo->replaceAllUsesWith(op);
}
// Implementation of a = b | c => a = (b & c) | (b ^ c)
void Substitution::orSubstitutionRand(BinaryOperator *bo) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
// !a
BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo);
// !b
BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// !r
BinaryOperator *op2 = BinaryOperator::CreateNot(co, "", bo);
// !a && r
BinaryOperator *op3 =
BinaryOperator::Create(Instruction::And, op, co, "", bo);
// a && !r
BinaryOperator *op4 =
BinaryOperator::Create(Instruction::And, bo->getOperand(0), op2, "", bo);
// !b && r
BinaryOperator *op5 =
BinaryOperator::Create(Instruction::And, op1, co, "", bo);
// b && !r
BinaryOperator *op6 =
BinaryOperator::Create(Instruction::And, bo->getOperand(1), op2, "", bo);
// (!a && r) || (a && !r)
op3 = BinaryOperator::Create(Instruction::Or, op3, op4, "", bo);
// (!b && r) ||(b && !r)
op4 = BinaryOperator::Create(Instruction::Or, op5, op6, "", bo);
// (!a && r) || (a && !r) ^ (!b && r) ||(b && !r)
op5 = BinaryOperator::Create(Instruction::Xor, op3, op4, "", bo);
// !a || !b
op3 = BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
// !(!a || !b)
op3 = BinaryOperator::CreateNot(op3, "", bo);
// r || !r
op4 = BinaryOperator::Create(Instruction::Or, co, op2, "", bo);
// !(!a || !b) && (r || !r)
op4 = BinaryOperator::Create(Instruction::And, op3, op4, "", bo);
// [(!a && r) || (a && !r) ^ (!b && r) ||(b && !r) ] || [!(!a || !b) && (r ||
// !r)]
op = BinaryOperator::Create(Instruction::Or, op5, op4, "", bo);
bo->replaceAllUsesWith(op);
}
void Substitution::orSubstitution(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Creating first operand (b & c)
op = BinaryOperator::Create(Instruction::And, bo->getOperand(0),
bo->getOperand(1), "", bo);
// Creating second operand (b ^ c)
BinaryOperator *op1 = BinaryOperator::Create(
Instruction::Xor, bo->getOperand(0), bo->getOperand(1), "", bo);
// final op
op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
bo->replaceAllUsesWith(op);
}
// Implementation of a = a ~ b => a = (!a && b) || (a && !b)
void Substitution::xorSubstitution(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create NOT on first operand
op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); // !a
// Create AND
op = BinaryOperator::Create(Instruction::And, bo->getOperand(1), op, "",
bo); // !a && b
// Create NOT on second operand
BinaryOperator *op1 =
BinaryOperator::CreateNot(bo->getOperand(1), "", bo); // !b
// Create AND
op1 = BinaryOperator::Create(Instruction::And, bo->getOperand(0), op1, "",
bo); // a && !b
// Create OR
op = BinaryOperator::Create(Instruction::Or, op, op1, "",
bo); // (!a && b) || (a && !b)
bo->replaceAllUsesWith(op);
}
// implementation of a = a ^ b <=> (a ^ r) ^ (b ^ r) <=> (!a && r || a && !r) ^
// (!b && r || b && !r)
// note : r is a random number
void Substitution::xorSubstitutionRand(BinaryOperator *bo) {
BinaryOperator *op = NULL;
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
// !a
op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo);
// !a && r
op = BinaryOperator::Create(Instruction::And, co, op, "", bo);
// !r
BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo);
// a && !r
BinaryOperator *op1 =
BinaryOperator::Create(Instruction::And, bo->getOperand(0), opr, "", bo);
// !b
BinaryOperator *op2 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// !b && r
op2 = BinaryOperator::Create(Instruction::And, op2, co, "", bo);
// b && !r
BinaryOperator *op3 =
BinaryOperator::Create(Instruction::And, bo->getOperand(1), opr, "", bo);
// (!a && r) || (a && !r)
op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
// (!b && r) || (b && !r)
op1 = BinaryOperator::Create(Instruction::Or, op2, op3, "", bo);
// (!a && r) || (a && !r) ^ (!b && r) || (b && !r)
op = BinaryOperator::Create(Instruction::Xor, op, op1, "", bo);
bo->replaceAllUsesWith(op);
}
(x + y) - 2 * (x & y) -> x ^ y
,因此可以通过IDA MicroCode来进行模式匹配,比如匹配到(x + y) - 2 * (x & y)
则将其转换为 x ^ y
暂无