自动x86指令混淆

时间:2011-10-30 19:47:50

标签: assembly automation x86 obfuscation

我正在研究x86 asm混淆器,它将英特尔语法代码作为字符串输出,并输出一组模糊的操作码。

以下是一个例子:

mov eax, 0x5523
or eax, [ebx]
push eax
call someAPI

变成类似的东西:

mov eax, 0xFFFFFFFF ; mov eax, 0x5523
and eax, 0x5523     ;
push [ebx]          ; xor eax, [ebx]
or [esp], eax       ;
pop eax             ;
push 12345h         ; push eax
mov [esp], eax      ;
call getEIP         ; call someAPI
getEIP:             ;
add [esp], 9        ;
jmp someAPI         ;

这只是一个例子,我没有检查过这不会搞砸标志(可能会这样)。

现在我有一个XML文档,其中列出了指令模板(例如push e*x)和可以使用的替换指令列表。

我正在寻找的是一种自动生成操作码序列的方法,该操作码产生与输入相同的结果。我不介意做一个受过良好教育的暴力,但我不确定我是怎么做到的。

2 个答案:

答案 0 :(得分:15)

您需要的是代码描述操作的代数,以及一组允许您确定等效操作的代数定律。

然后对于每条指令,你查找它的代数描述(为了举个例子, 一个

 XOR  eax,mem[ecx]

其代数等价物是

 eax exclusive_or mem[ecx]

使用这些代数等价物枚举代数等价,例如:

 a exclusive_or b ==> (a and not b) or (b and not a)

为您的XOR指令生成等效的代数语句

 eax exclusive_or mem[ecx] ==> (eax and not mem[ecx]) or (mem[ecx] and not eax)

你可以对此应用更多的代数定律,例如de morgans定理:

 a or b ==> not (not a and not b)

获取

(not (not (eax and not mem[ecx])) and (not (mem[ecx] and not eax)))

此时你有一个代数计算的规范 和原版一样。有你的蛮力。

现在您必须通过匹配指令将“编译”到机器指令 会怎么说这个。像任何编译器一样,您可能希望优化 生成的代码(两次获取mem [ecx]没有意义)。 (所有这些都很难......它是一个代码生成器!) 生成的代码序列如下:

mov ebx, mem[ecx]
mov edx, ebx
not edx
and edx, eax
not eax
and eax, ebx
not eax
or eax, edx

这是手动构建的很多机器。

另一种方法是利用程序转换系统,该系统允许您将源到源转换应用于代码。然后你可以将“等价”编码为直接重写代码。

其中一个工具是DMS Software Reengineering Toolkit

DMS采用语言定义(基本上作为EBNF),自动实现解析器,AST构建器和prettyprinter(反解析器,将AST转换回有效的源文本)。 [DMS目前没有ASM86的EBNF,但有几十种EBNF用于各种 已经为DMS构建了复杂的语言,其中包括一些用于其他非x86汇编程序的语言 因此,您必须将ASM86 EBNF定义为DMS。这非常简单; DMS 有一个非常强大的解析器生成器]。

使用它,DMS将允许您直接在代码上编写源代码转换。您可以编写以下转换,直接实现XOR等效和DeMorgan定律:

  domain ASM86;

  rule obfuscate_XOR(r: register, m: memory_access):instruction:instruction
  =  " XOR \r, \m " 
      rewrites to
     " MOV \free_register\(\),\m
       NOT \free_register\(\)
       AND \free_register\(\),\r 
       NOT \r
       AND \r,\m
       OR \r,\free_register\(\)";

 rule obfuscate_OR(r1: register, r2: register):instruction:instruction
 = " OR \r1, \r2"
     rewrites to
    " MOV \free_register\(\),\r1
      NOT \free_register\(\)
      AND \free_register\(\),\r2
      NOT \r2
      AND \r1,\r2
      NOT \r1";

在称为“free_register”的元过程中有一些额外的魔法来确定哪些寄存器 代码中的那个(AST匹配)是免费的。 (如果您不想这样做,请使用堆栈顶部 就像你在你的例子中所做的那样暂时的。)

你需要一堆重写来覆盖你想要混淆的所有情况,使用带有寄存器和内存操作数的组合数据。

然后可以要求转换引擎在代码中的每个点随机或多次应用这些转换来加扰它。

您可以看到fully worked example of some algebraic transforms being applied with DMS.

答案 1 :(得分:0)

看看Obfusion项目。它可以很好地混淆x86 shellcode。但是,它似乎不支持64-bit。不过,该项目中的大多数代码,算法和想法都可以满足您的需求。

另一个值得研究的很好的项目是ADVobfuscator,但它适用于C/C++通过宏进行的源代码混淆。

另一种方法可能是在反汇编器引擎的内部Zydis等指令的内部实现转换。

不要忘记LLVM-obfuscator,它是带有混淆标志的C/C++编译器。