跳转至

生成骨架 Shellcode 并分配内存

使用与清单 7-2 相同的方法,你可以为这个洞穴生成 shellcode,如清单 7-8 所示。

BYTE codeCave[31] = {
    0x60, // PUSHAD
    0x9C, // PUSHFD
    0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0
    0xB8, 0x00, 0x00, 0x00, 0x00, // MOV EAX, 0x0
    0xFF, 0xD0, // CALL EAX
    0x83, 0xC4, 0x08, // ADD ESP, 0x08
    0x9D, // POPFD
    0x61, // POPAD
    0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0
    0xC3 // RETN
};
// 这里需要添加一些代码,把线程的 EIP 放入 threadContext.Eip
memcpy(&codeCave[3], &remoteString, 4);
memcpy(&codeCave[8], &times, 4);
memcpy(&codeCave[13], &func, 4);
memcpy(&codeCave[25], &threadContext.Eip, 4);

清单 7-8:创建线程劫持 shellcode 数组

与清单 7-3 一样,用 memcpy() 把变量放入骨架。与那个清单不同,有两个变量不能马上复制;times 和 func 立即可知,但 remoteString 是分配的结果,threadContext.Eip 只有在线程冻结后才会知道。在冻结线程之前分配内存也是合理的,因为你不想让线程冻结超过必要时间。

int stringlen = strlen(string) + 1;
int cavelen = sizeof(codeCave);
int fulllen = stringlen + cavelen;
auto remoteString =
    VirtualAllocEx(process, 0, fulllen, 
MEM_COMMIT, PAGE_EXECUTE);
auto remoteCave =
    (LPVOID)((DWORD)remoteString + stringlen);

分配代码与线程注入相同,所以你可以复用同一段代码。