汇编操作码是相同的,因此生成无空 shellcode 的常规技巧仍然适用,但进行系统调用的方式不同。
在 Linux 中,您使用“int 0x80”指令进行系统调用,而在 Windows 中,您必须使用 DLL 库并对其导出的函数进行正常的用户模式调用。
因此,在 Windows 上,您的 shellcode 必须:
- 硬编码 Win32 API 函数地址(很可能只在您的机器上工作)
- 使用 Win32 API 解析器 shellcode(适用于每个 Windows 版本)
如果您只是在学习,那么现在对您在调试器中看到的地址进行硬编码可能会更容易。要使调用位置独立,您可以将地址加载到寄存器中。例如,调用具有 4 个参数的函数:
PUSH 4 ; argument #4 to the function
PUSH 3 ; argument #3 to the function
PUSH 2 ; argument #2 to the function
PUSH 1 ; argument #1 to the function
MOV EAX, 0xDEADBEEF ; put the address of the function to call
CALL EAX
请注意,参数以相反的顺序推送。在 CALL 指令 EAX 包含返回值之后,堆栈将与之前一样(即函数弹出自己的参数)。 ECX 和 EDX 寄存器可能包含垃圾,所以不要依赖它们在调用后保持它们的值。
直接的 CALL 指令不起作用,因为它们是位置相关的。
为避免地址本身出现零,请尝试使用 x86 shellcode 的任何无 null 技巧,有很多技巧,但我最喜欢(虽然很长)是使用 XOR 指令对值进行编码:
MOV EAX, 0xDEADBEEF ^ 0xFFFFFFFF ; your value xor'ed against an arbitrary mask
XOR EAX, 0xFFFFFFFF ; the arbitrary mask
您也可以尝试 NEG EAX 或 NOT EAX(符号反转和位翻转),看看它们是否有效,它便宜得多(每个两个字节)。
您可以在此处获取有关可以调用的不同 API 函数的帮助:http://msdn.microsoft.com
您需要的最重要的可能如下:
第一个启动命令,后两个用于加载DLL文件并获取其函数的地址。
这是编写 Windows shellcode 的完整教程:http://www.codeproject.com/Articles/325776/The-Art-of-Win32-Shellcoding