如何在Windows x86位置无关Shellcode末尾引用添加的数据
解决方案:在Shellcode末尾预留可修改的字符串缓冲区
要在Shellcode末尾预留可被Python脚本替换的字符串缓冲区,核心是确保编译器保留缓冲区且无绝对重定位,同时代码能通过相对寻址正确引用它。以下是两种可靠实现方式:
方法一:汇编标记+相对寻址(推荐)
直接在code_func末尾嵌入汇编定义缓冲区,通过当前指令地址计算缓冲区的相对偏移,完全避免重定位问题:
#include <windows.h> typedef HMODULE(WINAPI* LoadLibraryA_ptr)(LPCSTR); typedef INT(WINAPI* MessageBoxA_ptr)(HWND, LPCSTR, LPCSTR, UINT); __declspec(naked) void start_func() { __asm { jmp code_func } }; PVOID get_module_address(BYTE* mod){/* 你的原有实现 */} PVOID get_function_address(HMODULE mod, BYTE* func){/* 你的原有实现 */} void code_func(){ BYTE kernel32_string[] = {'k','e','r','n','e','l','3','2','.','d','l','l','\0'}; BYTE loadlibrary_string[] = {'l','o','a','d','l','i','b','r','a','r','y','\0'}; BYTE user32_string[] = {'u','s','e','r','3','2','.','d','l','l','\0'}; BYTE messagebox_string[] = {'m','e','s','s','a','g','e','b','o','x','a','\0'}; HMODULE kmod = get_module_address(kernel32_string); LoadLibraryA_ptr LoadLibraryA = get_function_address(kmod, loadlibrary_string); HMODULE umod = LoadLibraryA(user32_string); MessageBoxA_ptr MessageBoxA = get_function_address(umod, messagebox_string); // 计算缓冲区相对地址 LPCSTR msg_buffer; __asm { lea eax, [buffer_start] mov msg_buffer, eax } MessageBoxA(NULL, msg_buffer, msg_buffer, MB_OK); // 预留100字节缓冲区,放在函数末尾 __asm { buffer_start: db 'DEFAULT_MSG', 0 ; 默认占位符 times 100 - ($ - buffer_start) db 0x90 ; 用NOP填充到固定长度 } }
核心优势:
- 汇编块属于函数代码的一部分,编译器不会因优化移除
- 通过
lea指令获取相对地址,无绝对重定位,完全适配Shellcode的内存无关性 - 固定长度的缓冲区方便Python脚本准确定位替换
方法二:自定义数据段强制缓冲区位置
通过__declspec(allocate)将缓冲区放到特定数据段,确保链接时位于代码段之后,同时用相对偏移计算地址:
#include <windows.h> typedef HMODULE(WINAPI* LoadLibraryA_ptr)(LPCSTR); typedef INT(WINAPI* MessageBoxA_ptr)(HWND, LPCSTR, LPCSTR, UINT); __declspec(naked) void start_func() { __asm { jmp code_func } }; // 定义自定义数据段,确保在普通数据段之后链接 #pragma section(".shellcode_data$zzz", read, write, execute) __declspec(allocate(".shellcode_data$zzz")) char msg_buffer[100] = "DEFAULT_MSG"; PVOID get_module_address(BYTE* mod){/* 你的原有实现 */} PVOID get_function_address(HMODULE mod, BYTE* func){/* 你的原有实现 */} void code_func(){ BYTE kernel32_string[] = {'k','e','r','n','e','l','3','2','.','d','l','l','\0'}; BYTE loadlibrary_string[] = {'l','o','a','d','l','i','b','r','a','r','y','\0'}; BYTE user32_string[] = {'u','s','e','r','3','2','.','d','l','l','\0'}; BYTE messagebox_string[] = {'m','e','s','s','a','g','e','b','o','x','a','\0'}; HMODULE kmod = get_module_address(kernel32_string); LoadLibraryA_ptr LoadLibraryA = get_function_address(kmod, loadlibrary_string); HMODULE umod = LoadLibraryA(user32_string); MessageBoxA_ptr MessageBoxA = get_function_address(umod, messagebox_string); // 计算缓冲区相对地址(避免绝对重定位) LPCSTR buffer_addr; __asm { call get_current_eip get_current_eip: pop eax add eax, msg_buffer - get_current_eip ; 计算相对偏移 mov buffer_addr, eax } MessageBoxA(NULL, buffer_addr, buffer_addr, MB_OK); }
关键说明:
.shellcode_data$zzz段名中的$zzz会让链接器将该段放在所有普通.data段之后,靠近代码段末尾- 通过
call/pop获取当前指令地址,加上缓冲区的相对偏移,彻底避免绝对地址引用
编译验证与Python替换
- 编译后验证:用反汇编工具(如x64dbg)查看提取的Shellcode,确认末尾存在默认占位符或NOP填充块
- Python替换逻辑:
- 读取Shellcode二进制数据
- 查找默认占位符(如
b'DEFAULT_MSG')的偏移 - 将新消息填充到该偏移位置,不足部分用
\x00或\x90填充(不超过100字节) - 写入修改后的Shellcode并执行
内容的提问来源于stack exchange,提问作者drexco
相关产品推荐
相关产品推荐

