使用LLVM传递混淆整数常量

使用LLVM传递混淆整数常量,llvm,obfuscation,Llvm,Obfuscation,读完之后,我想我会继续对它进行一些调整,以混淆任意整数常量 但是,我的过程似乎被忽略,或者对生成的LLVM位代码(甚至二进制可执行文件)没有任何影响 简单的模糊处理工作如下:生成一个随机int,然后用这个键对要隐藏的常量进行异或。对结果应用二的补码 这将生成一个整数,然后通过发出所需的LLVM位代码将其计算为原始值 这是我的PoC(改编自): 我编译LLVM过程如下: clang -g3 -shared -fPIC MyPass.cpp -o pass/MyPass.so // replV

读完之后,我想我会继续对它进行一些调整,以混淆任意整数常量

但是,我的过程似乎被忽略,或者对生成的LLVM位代码(甚至二进制可执行文件)没有任何影响

简单的模糊处理工作如下:生成一个随机int,然后用这个键对要隐藏的常量进行异或。对结果应用二的补码

这将生成一个整数,然后通过发出所需的LLVM位代码将其计算为原始值

这是我的PoC(改编自):

我编译LLVM过程如下:

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;