Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
61bcdefg committed Jan 2, 2023
1 parent 07cd153 commit faf2037
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 144 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ AntiDebugging PreCompiled IR文件的路径

在虚假块中花指令的最大数量。默认为3

-bcf_createfunc

使用函数封装不透明谓词。默认关闭

#### Flattening (修改过)

经过修改,支持混淆存在C++异常处理的函数
Expand Down
26 changes: 12 additions & 14 deletions llvm/include/llvm/Transforms/Obfuscation/CryptoUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,45 +24,43 @@
#include <random>
#include <map>
namespace llvm {

class CryptoUtils;
extern ManagedStatic<CryptoUtils> cryptoutils;
class CryptoUtils {
public:
CryptoUtils();
~CryptoUtils();
void prng_seed(std::uint_fast64_t seed);
void prng_seed();
template <typename T>
T get(){
std::uint_fast64_t num=get_raw();
T get() {
std::uint_fast64_t num = get_raw();
return static_cast<T>(num);
};
//Return a value in [0,max)
uint32_t get_range(uint32_t max){
return get_range(0,max);
// Return a value in [0,max)
uint32_t get_range(uint32_t max) {
return get_range(0, max);
}
uint32_t get_range(uint32_t min,uint32_t max);
uint32_t get_uint32_t(){
uint32_t get_uint32_t() {
return get<uint32_t>();
};
uint64_t get_uint64_t(){
uint64_t get_uint64_t() {
return get<uint64_t>();
};
uint32_t get_uint8_t(){
uint32_t get_uint8_t() {
return get<uint8_t>();
};
uint32_t get_uint16_t(){
uint32_t get_uint16_t() {
return get<uint16_t>();
};
// Scramble32 originally uses AES to generates the mapping relationship between a BB and its switchvar
// Hikari updates this by doing this using mt19937_64 in C++ STLs which is a faster but less cryprographically secured
// This method try to find the corresponding value from the VMap first, if not then use RNG to generate,fill and return the value
uint32_t scramble32(uint32_t in,std::map<uint32_t/*IDX*/,uint32_t/*VAL*/>& VMap);
uint32_t scramble32(uint32_t in, std::map<uint32_t/*IDX*/,uint32_t/*VAL*/>& VMap);
private:
std::mt19937_64* eng=nullptr;
std::mt19937_64 *eng = nullptr;
std::uint_fast64_t get_raw();
};
extern ManagedStatic<CryptoUtils> cryptoutils;
}

#endif // LLVM_CryptoUtils_H
47 changes: 14 additions & 33 deletions llvm/lib/Transforms/Obfuscation/AntiHooking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ struct AntiHook : public ModulePass {
}
return true;
} // End runOnFunction

void HandleInlineHookAArch64(Function *F, vector<Function *> &FunctionsToDetect) {
// First we locate an insert point to check ourself
// The following is equivalent to
Expand Down Expand Up @@ -258,30 +259,7 @@ struct AntiHook : public ModulePass {
SI->addCase(ConstantInt::get(IntegerType::get(F->getContext(), 32), sig), B);
SI2->addCase(ConstantInt::get(IntegerType::get(F->getContext(), 32), sig), B);
}

Function *AHCallBack = F->getParent()->getFunction("AHCallBack");
if (AHCallBack) {
IRBB.CreateCall(AHCallBack);
} else {
if (triple.isOSDarwin() &&
triple.getArch() == Triple::ArchType::aarch64) {
string exitsvcasm = "mov w16, #1\n";
exitsvcasm += "svc #" + to_string(cryptoutils->get_range(65536)) + "\n";
InlineAsm *IA = InlineAsm::get(FunctionType::get(IRBB.getVoidTy(), false),
exitsvcasm, "", true, false);
IRBB.CreateCall(IA);
}
else {
// First. Build up declaration for abort();
FunctionType *ABFT =
FunctionType::get(Type::getVoidTy(A->getContext()), false);
Function *abort_declare = cast<Function>(
F->getParent()->getOrInsertFunction("abort", ABFT).getCallee());
abort_declare->addFnAttr(Attribute::AttrKind::NoReturn);
IRBB.CreateCall(abort_declare);
}
}
IRBB.CreateBr(C); // Insert a new br into the end of B to jump back to C
CreateCallbackAndJumpBack(&IRBB, C);
}
}

Expand Down Expand Up @@ -318,28 +296,31 @@ struct AntiHook : public ModulePass {
IRBA.CreateICmpEQ(IRBA.CreateBitCast(GetMethodImp, Int8PtrTy),
ConstantExpr::getBitCast(ObjcMethodImp, Int8PtrTy));
IRBA.CreateCondBr(IcmpEq, C, B);

CreateCallbackAndJumpBack(&IRBB, C);
}
void CreateCallbackAndJumpBack(IRBuilder<> *IRBB, BasicBlock *C) {
Module *M = C->getModule();
Function *AHCallBack = M->getFunction("AHCallBack");
if (AHCallBack) {
IRBB.CreateCall(AHCallBack);
IRBB->CreateCall(AHCallBack);
} else {
if (triple.isOSDarwin() && triple.isAArch64()) {
string exitsvcasm = "mov w16, #1\n";
exitsvcasm += "svc #" + to_string(cryptoutils->get_range(65536)) + "\n";
InlineAsm *IA =
InlineAsm::get(FunctionType::get(IRBB.getVoidTy(), false),
InlineAsm::get(FunctionType::get(IRBB->getVoidTy(), false),
exitsvcasm, "", true, false);
IRBB.CreateCall(IA);
IRBB->CreateCall(IA);
} else {
// First. Build up declaration for abort();
FunctionType *ABFT =
FunctionType::get(Type::getVoidTy(A->getContext()), false);
Function *abort_declare = cast<Function>(M->getOrInsertFunction("abort", ABFT).getCallee());
FunctionType::get(Type::getVoidTy(M->getContext()), false);
Function *abort_declare =
cast<Function>(M->getOrInsertFunction("abort", ABFT).getCallee());
abort_declare->addFnAttr(Attribute::AttrKind::NoReturn);
IRBB.CreateCall(abort_declare);
IRBB->CreateCall(abort_declare);
}
}
IRBB.CreateBr(C); // Insert a new br into the end of B to jump back to C
IRBB->CreateBr(C);
}
};
} // namespace llvm
Expand Down
156 changes: 81 additions & 75 deletions llvm/lib/Transforms/Obfuscation/BogusControlFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,15 @@ static cl::opt<int> MinNumberOfJunkAssembly(
"bcf_junkasm_minnum",
cl::desc("The minimum number of junk assembliy per altered basic block"),
cl::value_desc("min number of junk assembly"), cl::init(1), cl::Optional);
static cl::opt<bool> CreateFunctionForOpaquePredicate(
"bcf_createfunc",
cl::desc("Create function for each opaque predicate"),
cl::value_desc("create function"), cl::init(false), cl::Optional);

static Instruction::BinaryOps ops[] = {Instruction::Add, Instruction::Sub,
Instruction::And, Instruction::Or,
Instruction::Xor};
Instruction::Xor, Instruction::Mul,
Instruction::UDiv};
static CmpInst::Predicate preds[] = {CmpInst::ICMP_EQ, CmpInst::ICMP_NE,
CmpInst::ICMP_UGT, CmpInst::ICMP_UGE,
CmpInst::ICMP_ULT, CmpInst::ICMP_ULE};
Expand Down Expand Up @@ -204,9 +209,11 @@ struct BogusControlFlow : public FunctionPass {
if (toObfuscate(flag, &F, "bcf")) {
if (F.isPresplitCoroutine())
return false;
if (F.getName().startswith("HikariBCFOpaquePredicateFunction"))
return false;
errs() << "Running BogusControlFlow On " << F.getName() << "\n";
bogus(F);
doF(*F.getParent());
doF(F);
}

return true;
Expand Down Expand Up @@ -332,7 +339,7 @@ struct BogusControlFlow : public FunctionPass {
needtoedit.emplace_back(condition2);
// Do random behavior to avoid pattern recognition.
// This is achieved by jumping to a random BB
switch (llvm::cryptoutils->get_uint16_t() % 2) {
switch (llvm::cryptoutils->get_range(2)) {
case 0: {
BranchInst::Create(originalBBpart2, originalBB, condition2, originalBB);
break;
Expand Down Expand Up @@ -586,131 +593,130 @@ struct BogusControlFlow : public FunctionPass {
if (JunkAssembly) {
string junk = "";
for (uint32_t i = cryptoutils->get_range(MinNumberOfJunkAssembly, MaxNumberOfJunkAssembly); i > 0; i--)
junk += ".long " + to_string(cryptoutils->get_range((uint32_t)1145141919810)) + "\n";
junk += ".long " + to_string(cryptoutils->get_uint32_t()) + "\n";
InlineAsm *IA = InlineAsm::get(
FunctionType::get(Type::getVoidTy(alteredBB->getContext()), false), junk, "", true, false);
CallInst::Create(IA, None, "", &*alteredBB->getFirstInsertionPt());
}
return alteredBB;
} // end of createAlteredBasicBlock()

/* doFinalization
/* doF
*
* Overwrite FunctionPass method to apply the transformations to the whole
* module. This part obfuscate all the always true predicates of the module.
* More precisely, the condition which predicate is FCMP_TRUE.
* It also remove all the functions' basic blocks' and instructions' names.
* This part obfuscate the always true predicates generated in addBogusFlow() of the function.
*/
bool doF(Module &M) {
// In this part we extract all always-true predicate and replace them with
// opaque predicate: For this, we declare two global values: x and y, and
// replace the FCMP_TRUE predicate with (y < 10 || x * (x + 1) % 2 == 0) A
// better way to obfuscate the predicates would be welcome. In the meantime
// we will erase the name of the basic blocks, the instructions and the
// functions.
bool doF(Function &F) {
vector<Instruction *> toEdit, toDelete;
// Looking for the conditions and branches to transform
for (Module::iterator mi = M.begin(), me = M.end(); mi != me; ++mi) {
for (Function::iterator fi = mi->begin(), fe = mi->end(); fi != fe;
++fi) {
Instruction *tbb = fi->getTerminator();
if (tbb->getOpcode() == Instruction::Br) {
BranchInst *br = (BranchInst *)tbb;
if (br->isConditional()) {
ICmpInst *cond = (ICmpInst *)br->getCondition();
if (std::find(needtoedit.begin(), needtoedit.end(), cond) !=
needtoedit.end()) {
toDelete.emplace_back(cond); // The condition
toEdit.emplace_back(tbb); // The branch using the condition
}
for (BasicBlock &BB : F) {
Instruction *tbb = BB.getTerminator();
if (BranchInst *br = dyn_cast<BranchInst>(tbb)) {
if (br->isConditional()) {
ICmpInst *cond = dyn_cast<ICmpInst>(br->getCondition());
if (cond && std::find(needtoedit.begin(), needtoedit.end(), cond) !=
needtoedit.end()) {
toDelete.emplace_back(cond); // The condition
toEdit.emplace_back(tbb); // The branch using the condition
}
}
}
}
Module &M = *F.getParent();
Type *I1Ty = Type::getInt1Ty(M.getContext());
Type *I32Ty = Type::getInt32Ty(M.getContext());
// Replacing all the branches we found
for (std::vector<Instruction *>::iterator i = toEdit.begin();
i != toEdit.end(); ++i) {
for (Instruction *i : toEdit) {
// Previously We Use LLVM EE To Calculate LHS and RHS
// Since IRBuilder<> uses ConstantFolding to fold constants.
// The return instruction is already returning constants
// The variable names below are the artifact from the Emulation Era
Type *I32Ty = Type::getInt32Ty(M.getContext());
Module emuModule("HikariBCFEmulator", M.getContext());
emuModule.setDataLayout(M.getDataLayout());
emuModule.setTargetTriple(M.getTargetTriple());
Function *emuFunction =
Function::Create(FunctionType::get(I32Ty, false),
GlobalValue::LinkageTypes::PrivateLinkage,
"BeginExecution", &emuModule);
BasicBlock *EntryBlock =
BasicBlock::Create(M.getContext(), "", emuFunction);

Instruction *tmp = &*((*i)->getParent()->getFirstInsertionPt());
IRBuilder<> IRBReal(tmp);
IRBuilder<> IRBEmu(EntryBlock);
"HikariBCFEmuFunction", M);
BasicBlock *emuEntryBlock =
BasicBlock::Create(emuFunction->getContext(), "", emuFunction);

Function *opFunction = nullptr;
IRBuilder<> *IRBOp = nullptr;
if (CreateFunctionForOpaquePredicate) {
opFunction = Function::Create(FunctionType::get(I1Ty, false),
GlobalValue::LinkageTypes::PrivateLinkage,
"HikariBCFOpaquePredicateFunction", M);
BasicBlock *opTrampBlock =
BasicBlock::Create(opFunction->getContext(), "", opFunction);
BasicBlock *opEntryBlock =
BasicBlock::Create(opFunction->getContext(), "", opFunction);
// Insert a br to make it can be obfuscated by IndirectBranch
BranchInst::Create(opEntryBlock, opTrampBlock);
IRBOp = new IRBuilder<>(opEntryBlock);
}
Instruction *tmp = &*(i->getParent()->getFirstNonPHIOrDbgOrLifetime());
IRBuilder<> *IRBReal = new IRBuilder<>(tmp);
IRBuilder<> IRBEmu(emuEntryBlock);
// First,Construct a real RHS that will be used in the actual condition
Constant *RealRHS = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t());
// Prepare Initial LHS and RHS to bootstrap the emulator
Constant *LHSC = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t());
Constant *RHSC = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t());
Constant *LHSC = ConstantInt::get(I32Ty, cryptoutils->get_range(1, UINT32_MAX));
Constant *RHSC = ConstantInt::get(I32Ty, cryptoutils->get_range(1, UINT32_MAX));
GlobalVariable *LHSGV =
new GlobalVariable(M, Type::getInt32Ty(M.getContext()), false,
GlobalValue::PrivateLinkage, LHSC, "LHSGV");
GlobalVariable *RHSGV =
new GlobalVariable(M, Type::getInt32Ty(M.getContext()), false,
GlobalValue::PrivateLinkage, RHSC, "RHSGV");
LoadInst *LHS = IRBReal.CreateLoad(LHSGV->getValueType(), LHSGV, "Initial LHS");
LoadInst *RHS = IRBReal.CreateLoad(RHSGV->getValueType(), RHSGV, "Initial LHS");
LoadInst *LHS =
(CreateFunctionForOpaquePredicate ? IRBOp : IRBReal)
->CreateLoad(LHSGV->getValueType(), LHSGV, "Initial LHS");
LoadInst *RHS =
(CreateFunctionForOpaquePredicate ? IRBOp : IRBReal)
->CreateLoad(RHSGV->getValueType(), RHSGV, "Initial LHS");

// To Speed-Up Evaluation
Value *emuLHS = LHSC;
Value *emuRHS = RHSC;
Instruction::BinaryOps initialOp = ops[llvm::cryptoutils->get_uint32_t() %
(sizeof(ops) / sizeof(ops[0]))];
Instruction::BinaryOps initialOp = ops[llvm::cryptoutils->get_range(sizeof(ops) / sizeof(ops[0]))];
Value *emuLast =
IRBEmu.CreateBinOp(initialOp, emuLHS, emuRHS, "EmuInitialCondition");
Value *Last =
IRBReal.CreateBinOp(initialOp, LHS, RHS, "InitialCondition");
Value *Last = (CreateFunctionForOpaquePredicate ? IRBOp : IRBReal)
->CreateBinOp(initialOp, LHS, RHS, "InitialCondition");
for (int i = 0; i < ConditionExpressionComplexity; i++) {
Constant *newTmp = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t());
Instruction::BinaryOps initialOp =
ops[llvm::cryptoutils->get_uint32_t() %
(sizeof(ops) / sizeof(ops[0]))];
emuLast = IRBEmu.CreateBinOp(initialOp, emuLast, newTmp,
Constant *newTmp = ConstantInt::get(I32Ty, cryptoutils->get_range(1, UINT32_MAX));
Instruction::BinaryOps initialOp2 =
ops[llvm::cryptoutils->get_range(sizeof(ops) / sizeof(ops[0]))];
emuLast = IRBEmu.CreateBinOp(initialOp2, emuLast, newTmp,
"EmuInitialCondition");
Last = IRBReal.CreateBinOp(initialOp, Last, newTmp, "InitialCondition");
Last = (CreateFunctionForOpaquePredicate ? IRBOp : IRBReal)->CreateBinOp(initialOp2, Last, newTmp, "InitialCondition");
}
// Randomly Generate Predicate
CmpInst::Predicate pred = preds[llvm::cryptoutils->get_uint32_t() %
(sizeof(preds) / sizeof(preds[0]))];
Last = IRBReal.CreateICmp(pred, Last, RealRHS);
CmpInst::Predicate pred = preds[llvm::cryptoutils->get_range(sizeof(preds) / sizeof(preds[0]))];
if (CreateFunctionForOpaquePredicate) {
IRBOp->CreateRet(IRBOp->CreateICmp(pred, Last, RealRHS));
Last = IRBReal->CreateCall(opFunction);
}
else
Last = IRBReal->CreateICmp(pred, Last, RealRHS);
emuLast = IRBEmu.CreateICmp(pred, emuLast, RealRHS);
ReturnInst *RI = IRBEmu.CreateRet(emuLast);
ConstantInt *emuCI = cast<ConstantInt>(RI->getReturnValue());
uint64_t emulateResult = emuCI->getZExtValue();
vector<BasicBlock *> BBs; // Start To Prepare IndirectBranching
APInt emulateResult = emuCI->getValue();
if (emulateResult == 1) {
// Our ConstantExpr evaluates to true;

BranchInst::Create(((BranchInst *)*i)->getSuccessor(0),
((BranchInst *)*i)->getSuccessor(1), (Value *)Last,
((BranchInst *)*i)->getParent());
BranchInst::Create(((BranchInst *)i)->getSuccessor(0),
((BranchInst *)i)->getSuccessor(1), Last,
i->getParent());
} else {
// False, swap operands

BranchInst::Create(((BranchInst *)*i)->getSuccessor(1),
((BranchInst *)*i)->getSuccessor(0), (Value *)Last,
((BranchInst *)*i)->getParent());
BranchInst::Create(((BranchInst *)i)->getSuccessor(1),
((BranchInst *)i)->getSuccessor(0), Last,
i->getParent());
}
EntryBlock->eraseFromParent();
emuFunction->eraseFromParent();
(*i)->eraseFromParent(); // erase the branch
i->eraseFromParent(); // erase the branch
}
// Erase all the associated conditions we found
for (std::vector<Instruction *>::iterator i = toDelete.begin();
i != toDelete.end(); ++i)
(*i)->eraseFromParent();

for (Instruction *i : toDelete)
i->eraseFromParent();
return true;
} // end of doFinalization
}; // end of struct BogusControlFlow : public FunctionPass
Expand Down
Loading

0 comments on commit faf2037

Please sign in to comment.