一个简单的PoC,通过使用一个隐藏的调用来调用一个加密的shellcode
作者:Sec-Labs | 发布时间:
BrokenFlow
一个简单的 PoC,通过使用隐藏调用来调用加密的 shellcode。
介绍
这段代码使用了一个简单的技巧 来隐藏有效跳转到我们的 shellcode 的指令 。 这应该会使静态分析或仿真更具挑战性。
与往常一样,如果这个概念已经在其他一些论文中进行了解释,请给我发消息,我会很乐意将其添加到参考文献中。
细节
使用此技术的内存布局是标准布局,如图 1 中所述。
┌───────────────────────────────┐
│ │
│ │
│ │
│ │
│ encrypted shellcode │
│ │
│ │
│ │
│ │
│ │
│ │
├───────────────────────────────┤
│ │
│ │
│ decryption loop │
│ │
│ │
└───────────────────────────────┘
图1。 内存布局
解密循环将解密 shellcode 并跳转到它。 所有的“魔法”都在解密循环中,因为在完成对 shellcode 的解密后,解密循环将开始解密自己的代码。 第一条指令的解密将导致跳转到我们的 shellcode,在下一个循环迭代中执行 :)
在相关部分下方:
@decryption:
xor word ptr [eax], 06799h ; <jmp esi bytes> XOR <first two bytes of this instruction>
add eax, sizeof word
dec ecx
loop @decryption
如您所见, 解密循环不包含任何跳转到解密 shellcode 的指令 。 汇编代码以如下二进制格式汇编:
66:8130 9967 | xor word ptr ds:[eax],6799
83C0 02 | add eax,2
49 | dec ecx
E2 F5 | loop 450006
在这种情况下,解密密钥 必须是 06799h ,因为 8166h(解密循环第一条指令的前两个字节)和 6799h(异或密钥)之间的异或运算是 e6ffh,它被汇编为 jmp esi 。 换句话说:
0x8166 (xor word ptr ds:[eax],...) XOR 0x6799 (decryption key) == 0x6eff (jmp esi)
通过将 ESI 寄存器设置为我们的 shellcode 的开头,我们可以实现执行:)
下面是调试的例子。 最初复制加密的 shellcode,然后是用于解密和调用 shellcode 的代码。 可以注意到,在第三次执行解密循环后,指令 xor word ptr ds:[eax],6799 变为 jmp esi 。


用法
使用此技术的步骤是:
- 使用 XOR 密钥 0x6799 加密您的 shellcode。 加密循环迭代必须有一个 WORD 大小的步长(2 字节);
- 创建图 1 中报告的内存布局。加密的 shellcode 大小必须是二的倍数;
- 设置寄存器ECX为分配内存的大小;
- 将寄存器 ESI 设置为分配内存的起始地址(该地址包含要执行的 shellcode);
- 调用shellcode解密代码
可能的改进
为了使解密代码不易识别,可以使用替代方法调用 shellcode。 为了有更多的自由,我们可以考虑增加每次迭代期间加密的块大小。 在我的 PoC 中,我使用了 2字节,因为 jmp esi 需要两个字节,但我们可以使用 4 或 8 字节的块大小,允许操作员有更多适合 4 或 8 字节块的替代方案。 根据选择的调用 shellcode 的方式,加密常量也会发生变化。