You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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替换

  1. 编译后验证:用反汇编工具(如x64dbg)查看提取的Shellcode,确认末尾存在默认占位符或NOP填充块
  2. Python替换逻辑:
    • 读取Shellcode二进制数据
    • 查找默认占位符(如b'DEFAULT_MSG')的偏移
    • 将新消息填充到该偏移位置,不足部分用\x00或\x90填充(不超过100字节)
    • 写入修改后的Shellcode并执行

内容的提问来源于stack exchange,提问作者drexco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 08:17:34