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

为何32位EXE加载到内存时.text节内容会被Windows修改?

32位Windows可执行文件.text节运行时地址修改的原因分析

现象回顾

文件中存储的.text节起始字节:

68 50 a0 d0 00 e8 3c 68 84 00 59 c3 cc cc cc cc ..

对应反汇编:

push 0xd0a050
call 0x846846
pop ecx
ret
int3
int3
int3
int3
..

程序运行后,内存中.text节的对应字节变为:

68 50 a0 1b 01 e8 3c 68 84 00 59 c3 cc cc cc cc ..

对应反汇编:

push 0x11ba050
call 0x846846
pop ecx
ret
int3
int3
int3
int3
..

可见push指令后的立即数地址发生了变化,而64位版本的可执行文件运行时,文件与内存中的.text节完全一致。


核心原因:32位PE的基地址重定位机制

  1. 32位程序的默认加载基地址:MSVC 2019 x86编译的32位Windows程序,默认编译基地址为0x00400000。
  2. 动态加载地址调整:当系统加载该程序时,如果默认基地址已被其他进程占用,Windows加载器会将程序重新映射到一个未被占用的备选基地址。
  3. 绝对地址的重定位修正:你代码中push的是一个硬编码的绝对内存地址,这类地址会被PE加载器识别为需要重定位的目标。加载器会读取PE文件中的重定位表,将原地址修正为实际加载基地址对应的目标地址。
    • 计算验证:原地址0xd0a050与内存中地址0x11ba050的差值为0x4b0000,这正是实际加载基地址与默认基地址的偏移量(默认基地址0x00400000 + 0x4b0000 = 实际加载基地址0x008b0000),修正后的地址 = 实际加载基地址 + (原地址 - 默认基地址),完全匹配内存中的值。

64位版本无变化的原因

64位Windows程序默认采用地址无关代码(PIC),结合RIP相对寻址方式:

  • 所有内存地址引用都是相对于当前指令指针(RIP)的固定偏移量,而非硬编码的绝对地址。
  • 无论程序加载到哪个基地址,RIP的位置加上固定偏移就能得到正确的目标地址,因此不需要修改.text节的内容,文件与内存中的代码完全一致。

补充验证点

  • 可以查看PE文件的重定位表(在PE可选头的Data Directory中找到Base Relocation Table),里面会记录所有需要修正的绝对地址位置。
  • 如果编译32位程序时使用/FIXED:YES链接选项,程序会强制要求加载到默认基地址,此时若基地址被占用程序会启动失败,且.text节不会被修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:45:20