Windows PE文件.text段运行时变动区域预测相关技术问题咨询
PE文件.text段运行时修改与重定位问题解答
问题1:call指令重定位是否是.text段加载后被修改的唯一原因?
不是,正常无调试、无第三方代码注入的加载场景下,Windows对.text段的修改全部来自基址重定位,但重定位修正的范围远不止call指令:
- 绝对地址寻址的
jmp、retf等跳转指令 - 直接引用全局变量、静态变量绝对地址的内存操作指令
- 取函数地址、取变量地址的
mov、lea等指令 - 导入函数调用中间接引用IAT绝对地址的指令
- 代码中内嵌的绝对地址常量(比如函数指针表的条目)
只有当PE恰好加载到编译时预设的首选基址时,上述所有重定位操作才会被跳过,.text段和磁盘文件内容完全一致。
问题2:是否可以通过静态分析检测出.text段中可能被修改的部分?
完全可以,不需要逐行识别指令,核心依据是PE文件内置的基址重定位表(.reloc段):重定位表是编译器生成的、专门给系统加载器使用的修正清单,里面明确列出了.text段(以及其他含绝对地址的段)中所有加载时需要修改的字节偏移,100%覆盖所有会被系统修改的位置。
如果要通过指令特征排查,重点关注以下几类指令:
- 采用绝对寻址的
call/jmp指令 - 直接引用全局/静态变量地址的内存读写指令
- 取函数、变量绝对地址的赋值指令
- 间接引用IAT地址的外部函数调用指令
问题3:减少重定位数量的代码规范与编译器开关
编译器开关(以Windows平台主流的MSVC编译器为例,MinGW等编译器有对应等价选项)
- 可选
/DYNAMICBASE:NO:关闭ASLR(地址空间布局随机化),让PE固定加载到编译时预设的首选基址,只要基址没有被其他模块占用,就不会触发任何重定位 - 可选
/FIXED:强制生成固定基址PE,直接删除.reloc段,加载时如果无法分配到首选基址就直接加载失败,完全消除重定位(仅推荐EXE使用,DLL使用容易出现地址冲突导致加载失败) - 优先编译为x64架构:x64默认采用RIP相对寻址,绝大多数指令不需要绝对地址,天生重定位数量远少于x86架构
- 开启
/OPT:REF、/OPT:ICF优化:删除冗余符号、合并重复代码,减少不必要的地址引用
代码规范
- 尽量避免跨模块传递全局函数指针、全局变量指针,优先用局部变量、参数传递地址
- 不要硬编码任何绝对地址,优先用相对偏移实现自定义跳转、寻址逻辑
- 减少DLL的导出函数、导出变量数量,跨模块引用越少,重定位数量越少
- 尽量把需要频繁取地址的函数、变量放在同一个模块内,避免跨模块地址引用
针对你的代码完整性校验场景补充:如果运行环境可控,优先开启
/FIXED+/DYNAMICBASE:NO,可以直接消除所有重定位,不需要跳过任何位置就能直接对比.text段哈希;如果不能关闭ASLR,直接解析.reloc段拿到所有需要跳过的偏移即可,比指令识别效率更高、准确率更高。
内容的提问来源于stack exchange,提问作者Tyson
相关产品推荐
相关产品推荐

