混淆整数常量与LLVM通

问题描述 投票:0回答:2

在阅读this nice article from Quarkslab on obfuscating zeroes后,我想我会去提前调整它有点混淆任意整数常量。

然而,似乎我的通行证被忽略或不具有对所得到的LLVM位码(甚至是二进制可执行文件)的任何影响。

简单的模糊处理的工作原理如下:随机INT产生,那么常量隐藏异或与此键。 2的补加的结果。

这产生的整数,它然后通过发射所需LLVM位码计算到其原始值。

这是我的PoC(改编自1):

#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <sstream>

using namespace llvm;

namespace {
class MyPass : public BasicBlockPass {
public:
  static char ID;

  MyPass() : BasicBlockPass(ID) {}

  bool runOnBasicBlock(BasicBlock &BB) override {

    bool modified = false;
    for (typename BasicBlock::iterator I = BB.getFirstInsertionPt(),
                                       end = BB.end();
         I != end; ++I) {

      Instruction &Inst = *I;

      if (!isValidCandidateInstruction(Inst))
        continue;

      for (size_t i = 0; i < Inst.getNumOperands(); ++i) {

        if (Constant *C = isValidCandidateOperand(Inst.getOperand(i))) {
          std::stringstream stream;
          stream << std::hex << C->getUniqueInteger().getLimitedValue();
          std::string result(stream.str());
          errs() << "Found an integer: 0x" << result << "\n";

          if (C->getUniqueInteger().getLimitedValue() == 1337) {
            errs() << "Obfuscating constant 1337\n";
            if (Value *New_val = obfuscateInt(Inst, C)) {
              Inst.setOperand(i, New_val);
              modified = true;
              errs() << "Replaced with " << New_val << "\n";
            } else {
              errs() << "ObfuscateZero: could not rand pick a variable for "
                        "replacement\n";
            }
          }
        }
      }
    }
    return modified;
  }

  // replValue = ~(originalInt ^ key) -1
  Value *obfuscateInt(Instruction &Inst, Constant *C) {

    srand(time(NULL));
    int key = std::rand();
    int64_t replacedValue = ~(C->getUniqueInteger().getLimitedValue() ^ key);

    Constant *replValue = ConstantInt::get(C->getType(), replacedValue),
             *keyValue = ConstantInt::get(C->getType(), key);

    IRBuilder<> Builder(&Inst);
    Value *repl = Builder.CreateXor(replValue, keyValue);
    Value *finValue = Builder.CreateNeg(repl);

    return Builder.CreateSub(finValue, ConstantInt::get(C->getType(), 1));
  }

  // only interested in integer values  
  Constant *isValidCandidateOperand(Value *V) {
    Constant *C;
    if (!(C = dyn_cast<Constant>(V)))
      return nullptr;

    if (!C->getType()->isIntegerTy()) {
      return nullptr;
    }

    return C;
  }

  bool isValidCandidateInstruction(Instruction &Inst) {
    if (isa<GetElementPtrInst>(&Inst)) {
      errs() << "Ignoring GEP\n";
      return false;
    } else if (isa<SwitchInst>(&Inst)) {
      errs() << "Ignoring Switch\n";
      return false;
    } else if (isa<CallInst>(&Inst)) {
      errs() << "Ignoring Calls\n";
      return false;
    } else {
      return true;
    }
  }
};

} // namespace

char MyPass::ID = 0;
static RegisterPass<MyPass> X("MyPass", "Obfuscates 1337", true, false);

// register pass for clang use
static void registerMyPassPass(const PassManagerBuilder &,
                               llvm::legacy::PassManagerBase &PM) {
  PM.add(new MyPass());
}

static RegisterStandardPasses
    RegisterMBAPass(PassManagerBuilder::EP_OptimizerLast, registerMyPassPass);

而简单的测试程序:

int main(void)
{
    volatile int a = 3;
    a += 1337;
    return a;
}

我编译LLVM通过如下:

clang -g3 -shared -fPIC MyPass.cpp -o pass/MyPass.so

然后我跑在前面提到的简单测试的LLVM位码通:

opt -S -load pass/MyPass.so -MyPass bin/simple_test.ll -o bin/out.ll

斌/ out.ll的内容是一样的斌/ 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是(略)“隐藏”,只是为了它的缘故。不甚感兴趣的评论说,混淆是徒劳的,或指出的东西,你不要在不相关的问题的代码一样。

llvm obfuscation
2个回答
0
投票

这里的问题是IRBuilder,它在创建新的IR指令默认执行Constant Folding

为了解决这个问题,我不得不创建一个新的挥发性(挥发性不是强制性的,但我可以,所以我做)的IR变量,对其执行了“混淆”的算术运算,并更换指令的使用“1337操作数“与所得到的值。

该代码是相同的问题,除了功能obfuscateInt(...),现在看起来如下:

  // 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));
  }

生成的IR现在看起来像:

  %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 = alloca i32
  store volatile i32 525933950, i32* %4
  %5 = load volatile i32, i32* %4
  %6 = xor i32 -525932616, %5
  %7 = sub i32 0, %6
  %8 = sub i32 %7, 1
  %9 = add nsw i32 %3, %8
  store volatile i32 %9, i32* %2, align 4
  %10 = load volatile i32, i32* %2, align 4
  %11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([41 x i8], [41 x i8]* @.str, i32 0, i32 0), i32 %10)
  %12 = load volatile i32, i32* %2, align 4
  ret i32 %12

和拆卸显示,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
    ....

0
投票

IRBuilder performs basic constant folding by default(所报告的在他的answer问题作者)。

IRBuilder禁用常量合并如下创建它。

IRBuilder<NoFolder> Builder;
© www.soinside.com 2019 - 2024. All rights reserved.