使用LLVM传递混淆整数常量
读完之后,我想我会继续对它进行一些调整,以混淆任意整数常量 但是,我的过程似乎被忽略,或者对生成的LLVM位代码(甚至二进制可执行文件)没有任何影响 简单的模糊处理工作如下:生成一个随机int,然后用这个键对要隐藏的常量进行异或。对结果应用二的补码 这将生成一个整数,然后通过发出所需的LLVM位代码将其计算为原始值 这是我的PoC(改编自): 我编译LLVM过程如下:使用LLVM传递混淆整数常量,llvm,obfuscation,Llvm,Obfuscation,读完之后,我想我会继续对它进行一些调整,以混淆任意整数常量 但是,我的过程似乎被忽略,或者对生成的LLVM位代码(甚至二进制可执行文件)没有任何影响 简单的模糊处理工作如下:生成一个随机int,然后用这个键对要隐藏的常量进行异或。对结果应用二的补码 这将生成一个整数,然后通过发出所需的LLVM位代码将其计算为原始值 这是我的PoC(改编自): 我编译LLVM过程如下: clang -g3 -shared -fPIC MyPass.cpp -o pass/MyPass.so // replV
clang -g3 -shared -fPIC MyPass.cpp -o pass/MyPass.so
// replValue = ~(originalInt ^ key) -1
Value *obfuscateInt(BasicBlock &BB, Instruction &Inst, Constant *C) {
srand(time(NULL));
int key = std::rand();
int32_t replacedValue = ~(C->getUniqueInteger().getLimitedValue() ^ key);
Constant *replValue = ConstantInt::get(C->getType(), replacedValue),
*keyValue = ConstantInt::get(C->getType(), key);
IRBuilder<> Builder(&Inst);
// allocate enough space on the stack to store a 32-bit value. Var name = "AA"
AllocaInst *varAlloc = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, "AA");
// Store the key in AA, set "volatile" to true
Builder.CreateStore(keyValue, varAlloc, true);
// read the variable "AA"
LoadInst *loadVar = Builder.CreateLoad(varAlloc, true, "AA");
// use it
Value *repl = Builder.CreateXor(replValue, loadVar);
Value *finValue = Builder.CreateNeg(repl);
return Builder.CreateSub(finValue, Builder.getInt32(1));
}
然后,我对上述简单测试的LLVM位代码运行pass:
opt -S -load pass/MyPass.so -MyPass bin/simple_test.ll -o bin/out.ll
bin/out.ll的内容与bin/simple_test.ll相同,这显然与我想要的相反:
; ModuleID = 'bin/simple_test.ll'
source_filename = "tests/simple_test.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 0, i32* %1, align 4
store volatile i32 3, i32* %2, align 4
%3 = load volatile i32, i32* %2, align 4
%4 = add nsw i32 %3, 1337
store volatile i32 %4, i32* %2, align 4
%5 = load volatile i32, i32* %2, align 4
ret i32 %5
}
attributes #0 = { noinline nounwind optnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{!"clang version 7.0.1 (tags/RELEASE_701/final)"}
当然,我认为编译器优化了我的小混淆尝试,但是在手动将小转换应用到测试程序之后,我可以在结果反汇编中看到额外的XOR、NEG和SUB操作,这使我认为优化器在这里没有错
我感兴趣的是一个概念证明,其中常数1337(稍微)“隐藏”,只是为了它。不太感兴趣的评论说模糊处理是徒劳的,或者指出代码中与问题无关的您不喜欢的东西。这里的问题是IRBuilder,它默认在创建新的IR指令时执行 为了解决这个问题,我必须在IR中创建一个新的volatile(volatile不是必须的,但我可以这样做),对它执行“模糊化”算术运算,并用结果值替换使用“1337”的指令的操作数 除了函数obfuscateInt(…)外,代码与问题中的代码相同,现在看起来如下所示:
clang -g3 -shared -fPIC MyPass.cpp -o pass/MyPass.so
// replValue = ~(originalInt ^ key) -1
Value *obfuscateInt(BasicBlock &BB, Instruction &Inst, Constant *C) {
srand(time(NULL));
int key = std::rand();
int32_t replacedValue = ~(C->getUniqueInteger().getLimitedValue() ^ key);
Constant *replValue = ConstantInt::get(C->getType(), replacedValue),
*keyValue = ConstantInt::get(C->getType(), key);
IRBuilder<> Builder(&Inst);
// allocate enough space on the stack to store a 32-bit value. Var name = "AA"
AllocaInst *varAlloc = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, "AA");
// Store the key in AA, set "volatile" to true
Builder.CreateStore(keyValue, varAlloc, true);
// read the variable "AA"
LoadInst *loadVar = Builder.CreateLoad(varAlloc, true, "AA");
// use it
Value *repl = Builder.CreateXor(replValue, loadVar);
Value *finValue = Builder.CreateNeg(repl);
return Builder.CreateSub(finValue, Builder.getInt32(1));
}
反汇编显示1337在任何地方都没有出现,但程序的行为仍然保留:
0000000000001140 <main>:
1140: 55 push rbp
1141: 48 89 e5 mov rbp,rsp
1144: 48 83 ec 10 sub rsp,0x10
1148: 31 c0 xor eax,eax
114a: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
1151: c7 45 f8 03 00 00 00 mov DWORD PTR [rbp-0x8],0x3
1158: 8b 4d f8 mov ecx,DWORD PTR [rbp-0x8]
115b: c7 45 f4 02 77 c4 31 mov DWORD PTR [rbp-0xc],0x31c47702
1162: 8b 55 f4 mov edx,DWORD PTR [rbp-0xc]
1165: 81 f2 c4 8d 3b ce xor edx,0xce3b8dc4
116b: 29 d0 sub eax,edx
116d: 83 e8 01 sub eax,0x1
1170: 01 c1 add ecx,eax
1172: 89 4d f8 mov DWORD PTR [rbp-0x8],ecx
....
0000000000001140:
1140:55推动rbp
1141:48 89 e5 mov rbp,rsp
1144:48 83 ec 10子rsp,0x10
1148:31 c0 xor eax,eax
114a:c7 45 fc 00 mov DWORD PTR[rbp-0x4],0x0
1151:c7 45 f8 03 00 mov DWORD PTR[rbp-0x8],0x3
1158:8b 4d f8 mov ecx,DWORD PTR[rbp-0x8]
115b:c7 45 f4 02 77 c4 31 mov DWORD PTR[rbp-0xc],0x31c47702
1162:8b 55 f4 mov edx,DWORD PTR[rbp-0xc]
1165:81 f2 c4 8d 3b ce xor edx,0xCE3B 8DC4
116b:29 d0子eax,edx
116d:83 e8 01子eax,0x1
1170:01 c1添加ecx、eax
1172:89 4d f8 mov DWORD PTR[rbp-0x8],ecx
....
IRBuilder(如问题作者在其报告中所述)
要在IRBuilder
中禁用常量折叠,请按如下方式创建它
IRBuilder<NoFolder> Builder;
IRBuilder;
是否尝试过调试?对于指令
、基本块
和函数
类,有一个很好的dump()
方法,因此您可以在修改IR的过程中检查它。实际上,在最新版本的LLVM中,函数dump()已被删除,尽管可以使用“print()”。这确实很有帮助,你确定吗?
IRBuilder<NoFolder> Builder;