014、框架—段定义与程序入口
返回:网络安全知识库 · 上一节:C 语言与汇编程序框架 · 下一节:加减乘除基础
为什么要划分段
程序中的代码、只读常量和可写变量具有不同用途与权限。汇编源文件通过段声明组织内容,链接器再把它们合并到 PE 的相应节区中。
| MASM 声明 | 常见内容 | 典型属性 |
|---|---|---|
.code |
机器指令 | 读、执行 |
.data |
已初始化可写数据 | 读、写 |
.data? |
未初始化数据 | 读、写 |
.const |
只读常量 | 读 |
1 | .data |
源代码里的“段”与 PE 文件里的“节”在语境上经常混用,但并非完全等价。最终怎样合并、命名和设置权限由汇编器、编译器与链接器共同决定。
三种数据形式
已初始化数据
1 | .data |
初始值需要保存在文件中,程序加载后映射到内存。
未初始化数据
1 | .data? |
只需要记录所需大小,文件中通常不必为每个字节保存实际内容,加载后由系统提供零初始化存储。
只读数据
1 | .const |
只读属性能降低意外修改常量的风险,但是否真正只读仍要看最终 PE 节区属性和页面保护。
代码段特性
代码段存放 CPU 将要解码执行的机器指令。常见 PE 中,代码节往往名为 .text,并具有可读、可执行属性。
可写且可执行的页面会扩大安全风险。正常程序通常把代码页设为 RX,把数据页设为 RW,遵循“写入”和“执行”尽量分离的原则。
程序入口点
入口点(Entry Point)是模块映像完成必要加载后,系统开始执行模块代码的位置。
在 PE 可选头中,AddressOfEntryPoint 保存的是入口点相对于映像基址的 RVA:
1 | 入口点虚拟地址 = ImageBase + AddressOfEntryPoint |
例如:
1 | ImageBase = 00400000h |
OEP(Original Entry Point)通常指程序原始入口点。在分析加壳程序时,当前 PE 入口可能先进入壳代码,脱壳后需要定位原始入口。
main、入口点与导出函数
| 名称 | 含义 |
|---|---|
main / WinMain |
高级语言层面的用户入口函数 |
| PE Entry Point | Loader 完成映射后进入模块的位置 |
| DLL Entry Point | DLL 加载、卸载、线程事件时进入的位置 |
| Export Function | DLL 主动提供给外部调用的函数 |
它们可能相互调用,但不能混为一谈。
从文件到执行
程序启动可以先按下面的主线理解:
1 | 创建进程 |
实际 Windows 加载流程还包含 TLS、异常信息、权限与其他结构,后续 PE 和 Win32 笔记再展开。
逆向定位入口的思路
- 从 PE 头读取
AddressOfEntryPoint。 - 计算实际虚拟地址并在调试器中下断点。
- 判断入口代码属于编译器启动代码、壳代码还是业务代码。
- 关注调用关系、字符串引用和参数准备。
- 结合符号或 IDA 交叉引用逐步定位
main。
入口点只是分析起点,不一定是最值得阅读的业务起点。
学习检查清单
| 检查项 | 状态 |
|---|---|
能区分 .data、.data?、.const 与 .code |
待复盘 |
| 能说明代码页为何通常不应同时可写 | 待复盘 |
| 能用 ImageBase + RVA 计算入口点 VA | 待复盘 |
能区分 main、PE 入口点和导出函数 |
待复盘 |
| 能复述程序从映射到进入业务逻辑的主线 | 待复盘 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ruiqy~!











