This repository has been archived by the owner on Jul 1, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 47
/
FunctionWrapper.cpp
133 lines (131 loc) · 5.21 KB
/
FunctionWrapper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License).
//===----------------------------------------------------------------------===//
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Obfuscation/Obfuscation.h"
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
using namespace llvm;
using namespace std;
static cl::opt<int>
ProbRate("fw_prob",
cl::desc("Choose the probability [%] For Each CallSite To Be "
"Obfuscated By FunctionWrapper"),
cl::value_desc("Probability Rate"), cl::init(30), cl::Optional);
static cl::opt<int> ObfTimes(
"fw_times",
cl::desc(
"Choose how many time the FunctionWrapper pass loop on a CallSite"),
cl::value_desc("Number of Times"), cl::init(2), cl::Optional);
namespace llvm {
struct FunctionWrapper : public ModulePass {
static char ID;
bool flag;
FunctionWrapper() : ModulePass(ID) { this->flag = true; }
FunctionWrapper(bool flag) : ModulePass(ID) { this->flag = flag; }
StringRef getPassName() const override {
return StringRef("FunctionWrapper");
}
bool runOnModule(Module &M) override {
vector<CallSite *> callsites;
for (Module::iterator iter = M.begin(); iter != M.end(); iter++) {
Function &F = *iter;
if (toObfuscate(flag, &F, "fw")) {
errs() << "Running FunctionWrapper On " << F.getName() << "\n";
for (inst_iterator fi = inst_begin(&F); fi != inst_end(&F); fi++) {
Instruction *Inst = &*fi;
if (isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
if ((int)llvm::cryptoutils->get_range(100) <= ProbRate) {
callsites.push_back(new CallSite(Inst));
}
}
}
}
}
for (CallSite *CS : callsites) {
for (int i = 0; i < ObfTimes && CS != nullptr; i++) {
CS = HandleCallSite(CS);
}
}
return true;
} // End of runOnModule
CallSite *HandleCallSite(CallSite *CS) {
Value *calledFunction = CS->getCalledFunction();
if (calledFunction == nullptr) {
calledFunction = CS->getCalledValue()->stripPointerCasts();
}
// Filter out IndirectCalls that depends on the context
// Otherwise It'll be blantantly troublesome since you can't reference an
// Instruction outside its BB Too much trouble for a hobby project
// To be precise, we only keep CS that refers to a non-intrinsic function
// either directly or through casting
if (calledFunction == nullptr ||
(!isa<ConstantExpr>(calledFunction) &&
!isa<Function>(calledFunction)) ||
CS->getIntrinsicID() != Intrinsic::ID::not_intrinsic) {
return nullptr;
}
if (Function *tmp = dyn_cast<Function>(calledFunction)) {
if (tmp->getName().startswith("clang.")) {
// Clang Intrinsic
return nullptr;
}
for(auto argiter = tmp->arg_begin(); argiter!= tmp->arg_end(); ++argiter) {
Argument& arg=*(argiter);
if(arg.hasByValAttr()){
// Arguments with byval attribute yields issues without proper handling.
// The "proper" method to handle this is to revisit and patch attribute stealing code.
// Technically readonly attr probably should also get filtered out here.
// Nah too much work. This would do for open-source version since private already
// this pass with more advanced solutions
return nullptr;
}
}
}
// Create a new function which in turn calls the actual function
vector<Type *> types;
for (unsigned i = 0; i < CS->getNumArgOperands(); i++) {
types.push_back(CS->getArgOperand(i)->getType());
}
FunctionType *ft =
FunctionType::get(CS->getType(), ArrayRef<Type *>(types), false);
Function *func =
Function::Create(ft, GlobalValue::LinkageTypes::InternalLinkage,
"HikariFunctionWrapper", CS->getParent()->getModule());
//Trolling was all fun and shit so old implementation forced this symbol to exist in all objects
appendToCompilerUsed(*func->getParent(), {func});
BasicBlock *BB = BasicBlock::Create(func->getContext(), "", func);
IRBuilder<> IRB(BB);
vector<Value *> params;
for (auto arg = func->arg_begin(); arg != func->arg_end(); arg++) {
params.push_back(arg);
}
Value *retval = IRB.CreateCall(ConstantExpr::getBitCast(cast<Function>(calledFunction),CS->getCalledValue()->getType()), ArrayRef<Value *>(params));
if (ft->getReturnType()->isVoidTy()) {
IRB.CreateRetVoid();
} else {
IRB.CreateRet(retval);
}
CS->setCalledFunction(func);
CS->mutateFunctionType(ft);
Instruction *Inst = CS->getInstruction();
delete CS;
return new CallSite(Inst);
}
};
ModulePass *createFunctionWrapperPass() { return new FunctionWrapper(); }
ModulePass *createFunctionWrapperPass(bool flag) {
return new FunctionWrapper(flag);
}
} // namespace llvm
char FunctionWrapper::ID = 0;
INITIALIZE_PASS(FunctionWrapper, "funcwra", "Enable FunctionWrapper.", true,
true)