之前有了解过一点点VMP的虚拟机,其中存在一种混淆机制,就是在执行之后将虚拟机的寄存器轮转,这样每个指令的寄存器就不一样了,极大的增加了数据流分析的难度。可能理解有点问题,但是这种思想也可以应用于源码级混淆。所以我就基于LLVM实现了一种变量轮转的混淆方式,发现能够能够阻碍数据流分析,迷惑看代码的人。
在LLVM中,函数内部的变量都是通过allocainst进行分配的,其分配的结果是一个指针类型,在IDA中对应的就是栈空间。
在这里,由于LLVM的分配类型并不相同,不能像虚拟寄存器那样方便轮转。所以先想个办法将这些分配的allocainst统一一下。
具体算法实现很简单,给一个数组指针,数组长度,移位位数,然后移位就可以了。
c代码实现如下
这里并不是重点,熟悉llvm的ir的很快就能写出来。
编译成so,并应用于ll文件。
IDA打开,可以看到f5代码中的变量的意义已经完全不一样了,如果忽略轮转函数,则代码完全没有意义,而想要恢复,则需要脑子一点点去演算变量地址才行。
Function
*
VariableRotation::createRotateFunc(Module
*
m,PointerType
*
ptrType,Twine &name)
{
std::vector<
Type
*
> params;
params.push_back(ptrType);
params.push_back(
Type
::getInt32Ty(m
-
>getContext()));
params.push_back(
Type
::getInt32Ty(m
-
>getContext()));
Type
*
rawType
=
ptrType
-
>getPointerElementType();
FunctionType
*
funcType
=
FunctionType::get(
Type
::getVoidTy(m
-
>getContext()),params,false);
Function
*
func
=
Function::Create(funcType,GlobalValue::PrivateLinkage,name,m);
BasicBlock
*
entry1
=
BasicBlock::Create(m
-
>getContext(),
"entry1"
,func);
BasicBlock
*
cmp1
=
BasicBlock::Create(m
-
>getContext(),
"cmp1"
,func);
BasicBlock
*
entry2
=
BasicBlock::Create(m
-
>getContext(),
"entry2"
,func);
BasicBlock
*
cmp2
=
BasicBlock::Create(m
-
>getContext(),
"cmp2"
,func);
BasicBlock
*
shift
=
BasicBlock::Create(m
-
>getContext(),
"shift"
,func);
BasicBlock
*
end2
=
BasicBlock::Create(m
-
>getContext(),
"end2"
,func);
BasicBlock
*
end1
=
BasicBlock::Create(m
-
>getContext(),
"end1"
,func);
Function::arg_iterator
iter
=
func
-
>arg_begin();
Value
*
ptr
=
iter
;
Value
*
len
=
+
+
iter
;
Value
*
times
=
+
+
iter
;
IRBuilder<> irb(entry1);
Value
*
zero
=
ConstantInt::get(irb.getInt32Ty(),
0
);
Value
*
one
=
ConstantInt::get(irb.getInt32Ty(),
1
);
AllocaInst
*
i
=
irb.CreateAlloca(irb.getInt32Ty());
AllocaInst
*
j
=
irb.CreateAlloca(irb.getInt32Ty());
AllocaInst
*
tmp
=
irb.CreateAlloca(rawType);
AllocaInst
*
array
=
irb.CreateAlloca(ptrType);
irb.CreateStore(zero,j);
irb.CreateStore(ptr,array);
irb.CreateBr(cmp1);
irb.SetInsertPoint(cmp1);
irb.CreateCondBr(irb.CreateICmpSLT(irb.CreateLoad(j),times),entry2,end1);
irb.SetInsertPoint(entry2);
irb.CreateStore(zero,i);
irb.CreateStore(irb.CreateLoad(irb.CreateInBoundsGEP(irb.CreateLoad(array),{zero})),tmp);
irb.CreateBr(cmp2);
irb.SetInsertPoint(cmp2);
irb.CreateCondBr(irb.CreateICmpSLT(irb.CreateLoad(i),irb.CreateSub(
len
,one)),shift,end2);
irb.SetInsertPoint(shift);
Value
*
ival
=
irb.CreateLoad(i);
Value
*
arr
=
irb.CreateLoad(array);
irb.CreateStore(irb.CreateLoad(irb.CreateInBoundsGEP(arr,{irb.CreateAdd(ival,one)})),irb.CreateInBoundsGEP(rawType,arr,{ival}));
irb.CreateStore(irb.CreateAdd(ival,one),i);
irb.CreateBr(cmp2);
irb.SetInsertPoint(end2);
irb.CreateStore(irb.CreateAdd(irb.CreateLoad(j),one),j);
irb.CreateStore(irb.CreateLoad(tmp),irb.CreateInBoundsGEP(irb.CreateLoad(array),{irb.CreateSub(
len
,one)}));
irb.CreateBr(cmp1);
irb.SetInsertPoint(end1);
irb.CreateRetVoid();
return
func;
}
Function
*
VariableRotation::createRotateFunc(Module
*
m,PointerType
*
ptrType,Twine &name)
{
std::vector<
Type
*
> params;
params.push_back(ptrType);
params.push_back(
Type
::getInt32Ty(m
-
>getContext()));
params.push_back(
Type
::getInt32Ty(m
-
>getContext()));
Type
*
rawType
=
ptrType
-
>getPointerElementType();
FunctionType
*
funcType
=
FunctionType::get(
Type
::getVoidTy(m
-
>getContext()),params,false);
Function
*
func
=
Function::Create(funcType,GlobalValue::PrivateLinkage,name,m);
BasicBlock
*
entry1
=
BasicBlock::Create(m
-
>getContext(),
"entry1"
,func);
BasicBlock
*
cmp1
=
BasicBlock::Create(m
-
>getContext(),
"cmp1"
,func);
BasicBlock
*
entry2
=
BasicBlock::Create(m
-
>getContext(),
"entry2"
,func);
BasicBlock
*
cmp2
=
BasicBlock::Create(m
-
>getContext(),
"cmp2"
,func);
BasicBlock
*
shift
=
BasicBlock::Create(m
-
>getContext(),
"shift"
,func);
BasicBlock
*
end2
=
BasicBlock::Create(m
-
>getContext(),
"end2"
,func);
BasicBlock
*
end1
=
BasicBlock::Create(m
-
>getContext(),
"end1"
,func);
Function::arg_iterator
iter
=
func
-
>arg_begin();
Value
*
ptr
=
iter
;
Value
*
len
=
+
+
iter
;
Value
*
times
=
+
+
iter
;
IRBuilder<> irb(entry1);
Value
*
zero
=
ConstantInt::get(irb.getInt32Ty(),
0
);
Value
*
one
=
ConstantInt::get(irb.getInt32Ty(),
1
);
AllocaInst
*
i
=
irb.CreateAlloca(irb.getInt32Ty());
AllocaInst
*
j
=
irb.CreateAlloca(irb.getInt32Ty());
AllocaInst
*
tmp
=
irb.CreateAlloca(rawType);
AllocaInst
*
array
=
irb.CreateAlloca(ptrType);
irb.CreateStore(zero,j);
irb.CreateStore(ptr,array);
irb.CreateBr(cmp1);
irb.SetInsertPoint(cmp1);
irb.CreateCondBr(irb.CreateICmpSLT(irb.CreateLoad(j),times),entry2,end1);
irb.SetInsertPoint(entry2);
irb.CreateStore(zero,i);
irb.CreateStore(irb.CreateLoad(irb.CreateInBoundsGEP(irb.CreateLoad(array),{zero})),tmp);
irb.CreateBr(cmp2);
irb.SetInsertPoint(cmp2);
irb.CreateCondBr(irb.CreateICmpSLT(irb.CreateLoad(i),irb.CreateSub(
len
,one)),shift,end2);
irb.SetInsertPoint(shift);
Value
*
ival
=
irb.CreateLoad(i);
Value
*
arr
=
irb.CreateLoad(array);
irb.CreateStore(irb.CreateLoad(irb.CreateInBoundsGEP(arr,{irb.CreateAdd(ival,one)})),irb.CreateInBoundsGEP(rawType,arr,{ival}));
irb.CreateStore(irb.CreateAdd(ival,one),i);
irb.CreateBr(cmp2);
irb.SetInsertPoint(end2);
irb.CreateStore(irb.CreateAdd(irb.CreateLoad(j),one),j);
irb.CreateStore(irb.CreateLoad(tmp),irb.CreateInBoundsGEP(irb.CreateLoad(array),{irb.CreateSub(
len
,one)}));
irb.CreateBr(cmp1);
irb.SetInsertPoint(end1);
irb.CreateRetVoid();
return
func;
}
using namespace llvm;
namespace
{
struct VariableRotation : public ModulePass
{
static char
ID
;
VariableRotation() : ModulePass(
ID
) {}
Function
*
createRotateFunc(Module
*
m,PointerType
*
ptrType,Twine &name);
void processFunction(Function &f,SetVector<Function
*
> &shift);
bool
processVars(Function &f,SetVector<AllocaInst
*
> &
vars
,Function
*
rotateFunc);
bool
isUsedByInst(Instruction
*
inst,Value
*
var)
{
for
(Value
*
ops:inst
-
>operands())
if
(ops
=
=
var)
return
true;
return
false;
}
bool
runOnModule(Module &m) override
{
Twine fname1
=
Twine(
"shiftFuncitonI8"
);
Function
*
shiftFunc
=
createRotateFunc(&m,
Type
::getInt8PtrTy(m.getContext()),fname1);
SetVector<Function
*
> shifts;
shifts.insert(shiftFunc);
for
(Function &f:m)
{
if
(&f
=
=
shiftFunc)
continue
;
if
(f.hasExactDefinition())
processFunction(f,shifts);
}
return
true;
}
};
}
char VariableRotation::
ID
=
0
;
static RegisterPass<VariableRotation> X(
"varobfu"
,
"varobfu"
);
bool
VariableRotation::processVars(Function &f,SetVector<AllocaInst
*
> &
vars
,Function
*
rotateFunc)
{
if
(
vars
.size()<
2
)
return
false;
IRBuilder<> irb(&
*
f.getEntryBlock().getFirstInsertionPt());
Value
*
zero
=
ConstantInt::get(irb.getInt32Ty(),
0
);
DataLayout data
=
f.getParent()
-
>getDataLayout();
int
space
=
0
;
SetVector<
int
> value_map;
printf(
"function: %s\n"
,f.getName());
for
(
int
i
=
0
;i<
vars
.size();i
+
+
)
{
AllocaInst
*
a
=
vars
[i];
value_map.insert(space);
printf(
"address: %d\n"
,space);
space
+
=
data.getTypeAllocSize(a
-
>getAllocatedType());
}
ArrayType
*
arrayType
=
ArrayType::get(irb.getInt8Ty(),space);
AllocaInst
*
array
=
irb.CreateAlloca(arrayType);
int
prob
=
30
;
for
(BasicBlock &bb:f)
{
int
offset
=
0
;
BasicBlock::iterator
iter
=
bb.getFirstInsertionPt();
if
(&bb
=
=
&f.getEntryBlock())
iter
+
+
;
while
(
iter
!
=
bb.end())
{
Instruction
*
inst
=
&
*
iter
;
irb.SetInsertPoint(inst);
for
(
int
i
=
0
;i<
vars
.size();i
+
+
)
if
(isUsedByInst(inst,
vars
[i]))
{
if
(rand()
%
100
<prob)
{
int
times
=
rand()
%
(
vars
.size()
-
1
)
+
1
;
int
delta
=
(space
+
value_map[(offset
+
times)
%
vars
.size()]
-
value_map[offset])
%
space;
irb.CreateCall(FunctionCallee(rotateFunc),{irb.CreateGEP(array,{zero,zero}),ConstantInt::get(irb.getInt32Ty(),space),ConstantInt::get(irb.getInt32Ty(),delta)});
offset
=
(offset
+
times)
%
vars
.size();
}
int
index
=
(space
+
value_map[i]
-
value_map[offset])
%
space;
Value
*
gep
=
irb.CreateGEP(array,{zero,ConstantInt::get(irb.getInt32Ty(),index)});
Value
*
cast
=
irb.CreateBitOrPointerCast(gep,
vars
[i]
-
>getType());
int
c
=
0
;
for
(Value
*
ops:inst
-
>operands())
{
if
(ops
=
=
vars
[i])
inst
-
>setOperand(c,cast);
c
+
+
;
}
break
;
}
iter
+
+
;
}
if
(offset!
=
0
)
{
irb.SetInsertPoint(bb.getTerminator());
irb.CreateCall(FunctionCallee(rotateFunc),{irb.CreateGEP(array,{zero,zero}),ConstantInt::get(irb.getInt32Ty(),space),ConstantInt::get(irb.getInt32Ty(),(space
-
value_map[offset])
%
space)});
}
}
return
true;
}
void VariableRotation::processFunction(Function &f,SetVector<Function
*
> &shift)
{
SetVector<AllocaInst
*
>
list
;
for
(BasicBlock &bb:f)
for
(Instruction &instr:bb)
if
(isa<AllocaInst>(instr))
{
AllocaInst
*
a
=
(AllocaInst
*
)&instr;
list
.insert(a);
}
if
(processVars(f,
list
,shift[
0
]))
{
for
(AllocaInst
*
a:
list
)
a
-
>eraseFromParent();
}
}
Function
*
VariableRotation::createRotateFunc(Module
*
m,PointerType
*
ptrType,Twine &name)
{
std::vector<
Type
*
> params;
params.push_back(ptrType);
params.push_back(
Type
::getInt32Ty(m
-
>getContext()));
params.push_back(
Type
::getInt32Ty(m
-
>getContext()));
Type
*
rawType
=
ptrType
-
>getPointerElementType();
FunctionType
*
funcType
=
FunctionType::get(
Type
::getVoidTy(m
-
>getContext()),params,false);
Function
*
func
=
Function::Create(funcType,GlobalValue::PrivateLinkage,name,m);
BasicBlock
*
entry1
=
BasicBlock::Create(m
-
>getContext(),
"entry1"
,func);
BasicBlock
*
cmp1
=
BasicBlock::Create(m
-
>getContext(),
"cmp1"
,func);
BasicBlock
*
entry2
=
BasicBlock::Create(m
-
>getContext(),
"entry2"
,func);
BasicBlock
*
cmp2
=
BasicBlock::Create(m
-
>getContext(),
"cmp2"
,func);
BasicBlock
*
shift
=
BasicBlock::Create(m
-
>getContext(),
"shift"
,func);
BasicBlock
*
end2
=
BasicBlock::Create(m
-
>getContext(),
"end2"
,func);
BasicBlock
*
end1
=
BasicBlock::Create(m
-
>getContext(),
"end1"
,func);
Function::arg_iterator
iter
=
func
-
>arg_begin();
Value
*
ptr
=
iter
;
Value
*
len
=
+
+
iter
;
Value
*
times
=
+
+
iter
;
IRBuilder<> irb(entry1);
Value
*
zero
=
ConstantInt::get(irb.getInt32Ty(),
0
);
Value
*
one
=
ConstantInt::get(irb.getInt32Ty(),
1
);
AllocaInst
*
i
=
irb.CreateAlloca(irb.getInt32Ty());
AllocaInst
*
j
=
irb.CreateAlloca(irb.getInt32Ty());
AllocaInst
*
tmp
=
irb.CreateAlloca(rawType);
AllocaInst
*
array
=
irb.CreateAlloca(ptrType);
irb.CreateStore(zero,j);
irb.CreateStore(ptr,array);
irb.CreateBr(cmp1);
irb.SetInsertPoint(cmp1);
irb.CreateCondBr(irb.CreateICmpSLT(irb.CreateLoad(j),times),entry2,end1);
irb.SetInsertPoint(entry2);
irb.CreateStore(zero,i);
irb.CreateStore(irb.CreateLoad(irb.CreateInBoundsGEP(irb.CreateLoad(array),{zero})),tmp);
irb.CreateBr(cmp2);
irb.SetInsertPoint(cmp2);
irb.CreateCondBr(irb.CreateICmpSLT(irb.CreateLoad(i),irb.CreateSub(
len
,one)),shift,end2);
irb.SetInsertPoint(shift);
Value
*
ival
=
irb.CreateLoad(i);
Value
*
arr
=
irb.CreateLoad(array);
irb.CreateStore(irb.CreateLoad(irb.CreateInBoundsGEP(arr,{irb.CreateAdd(ival,one)})),irb.CreateInBoundsGEP(rawType,arr,{ival}));
irb.CreateStore(irb.CreateAdd(ival,one),i);
irb.CreateBr(cmp2);
irb.SetInsertPoint(end2);
irb.CreateStore(irb.CreateAdd(irb.CreateLoad(j),one),j);
irb.CreateStore(irb.CreateLoad(tmp),irb.CreateInBoundsGEP(irb.CreateLoad(array),{irb.CreateSub(
len
,one)}));
irb.CreateBr(cmp1);
irb.SetInsertPoint(end1);
irb.CreateRetVoid();
return
func;
}
static RegisterStandardPasses Y(PassManagerBuilder::EP_EarlyAsPossible,
[](const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
PM.add(new VariableRotation());
});
using namespace llvm;
namespace
{
struct VariableRotation : public ModulePass
{
static char
ID
;
VariableRotation() : ModulePass(
ID
) {}
Function
*
createRotateFunc(Module
*
m,PointerType
*
ptrType,Twine &name);
void processFunction(Function &f,SetVector<Function
*
> &shift);
bool
processVars(Function &f,SetVector<AllocaInst
*
> &
vars
,Function
*
rotateFunc);
bool
isUsedByInst(Instruction
*
inst,Value
*
var)
{
for
(Value
*
ops:inst
-
>operands())
if
(ops
=
=
var)
return
true;
return
false;
}
bool
runOnModule(Module &m) override
{
Twine fname1
=
Twine(
"shiftFuncitonI8"
);
Function
*
shiftFunc
=
createRotateFunc(&m,
Type
::getInt8PtrTy(m.getContext()),fname1);
SetVector<Function
*
> shifts;
shifts.insert(shiftFunc);
for
(Function &f:m)
{
if
(&f
=
=
shiftFunc)
continue
;
if
(f.hasExactDefinition())
processFunction(f,shifts);
}
return
true;
}
};
}
char VariableRotation::
ID
=
0
;
static RegisterPass<VariableRotation> X(
"varobfu"
,
"varobfu"
);
bool
VariableRotation::processVars(Function &f,SetVector<AllocaInst
*
> &
vars
,Function
*
rotateFunc)
{
if
(
vars
.size()<
2
)
return
false;
IRBuilder<> irb(&
*
f.getEntryBlock().getFirstInsertionPt());
Value
*
zero
=
ConstantInt::get(irb.getInt32Ty(),
0
);
DataLayout data
=
f.getParent()
-
>getDataLayout();
int
space
=
0
;
SetVector<
int
> value_map;
printf(
"function: %s\n"
,f.getName());
for
(
int
i
=
0
;i<
vars
.size();i
+
+
)
{
AllocaInst
*
a
=
vars
[i];
value_map.insert(space);
printf(
"address: %d\n"
,space);
space
+
=
data.getTypeAllocSize(a
-
>getAllocatedType());
}
ArrayType
*
arrayType
=
ArrayType::get(irb.getInt8Ty(),space);
AllocaInst
*
array
=
irb.CreateAlloca(arrayType);
int
prob
=
30
;
for
(BasicBlock &bb:f)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2022-3-14 11:30
被R1mao编辑
,原因: