
一个简单的PoC,通过使用隐藏调用来调用加密的shellcode。
使用隐藏调用来调用加密shellcode的简单PoC。
此代码使用一个简单技巧隐藏实际跳转到我们shellcode的指令。这应当使静态分析或模拟更具挑战性。
与往常一样,如果这个概念已在其他论文中解释过,请给我发消息,我会很乐意将其添加到参考文献中。
使用此技术的内存布局是标准的,如图1所述。
┌───────────────────────────────┐
│ │
│ │
│ │
│ │
│ encrypted shellcode │
│ │
│ │
│ │
│ │
│ │
│ │
├───────────────────────────────┤
│ │
│ │
│ decryption loop │
│ │
│ │
└───────────────────────────────┘
图1. 内存布局
解密循环将解密shellcode并跳转到它。所有"魔法"都在解密循环内部,因为在完成解密shellcode后,解密循环将开始解密自己的代码。第一条指令的解密将导致跳转到我们的shellcode,并在下一次循环迭代时执行:)
以下是相关部分:
@decryption:
xor word ptr [eax], 06799h ; <jmp esi 字节> XOR <此指令的前两个字节>
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(XOR密钥)之间的XOR运算是e6ffh,它被汇编为jmp esi。换句话说:
0x8166 (xor word ptr ds:[eax],...) XOR 0x6799 (解密密钥) == 0x6eff (jmp esi)
通过将ESI寄存器设置为我们shellcode的起始地址,我们可以实现执行:)
下面是一个调试示例。最初,加密的shellcode被复制,接着是用于解密和调用shellcode的代码。可以注意到,在解密循环第三次执行后,指令xor word ptr ds:[eax],6799变为jmp esi。

使用此技术的步骤如下:
为了使解密代码更不易被识别,可以使用替代方法来调用shellcode。为了拥有更多自由度,我们可以考虑增加每次迭代加密的块大小。在我的PoC中,我使用了2字节,因为jmp esi需要两个字节,但我们可以使用4字节或8字节的块大小,使操作者拥有更多适合4或8字节块的替代方案。根据选择的调用shellcode的方式,加密常量也将改变。