跳转到内容
She11code Blog
Go back

从0开始的逆向工程(一):PE与IDA的正确使用方法

Edit page

这是「从0开始的逆向工程」系列的第一篇文章。本文将介绍 PE 文件的基础结构,以及如何正确使用 IDA Pro 进行逆向分析。

Table of contents

Open Table of contents

概述

在开始逆向一个 Windows 程序之前,你需要了解两件事:

  1. 你面对的是什么 - PE 文件格式
  2. 你用什么工具 - IDA Pro 的正确使用方法

PE 文件

PE(Portable Executable) 是 Windows 操作系统下的可执行文件格式,包括:

扩展名类型
.exe可执行文件
.dll动态链接库
.sys内核驱动
.ocxActiveX 控件

PE 文件整体结构

+------------------+
|    DOS Header    |  ← 64 字节,兼容 DOS 系统
+------------------+
|  DOS Stub (可选)  |  ← "This program cannot be run in DOS mode"
+------------------+
|    PE Signature  |  ← "PE\0\0" (4 字节)
+------------------+
|    COFF Header   |  ← 机器类型、节数量等
+------------------+
|  Optional Header |  ← 入口点、镜像大小等
+------------------+
|  Section Headers |  ← 节表,描述各个节
+------------------+
|     Sections     |  ← .text / .data / .rdata 等
+------------------+

更详细的数据结构可以直接参考微软文档:https://learn.microsoft.com/zh-cn/windows/win32/debug/pe-format

关键结构解析

DOS Header

typedef struct _IMAGE_DOS_HEADER {
    WORD   e_magic;      // "MZ" (0x5A4D)
    // ... 省略其他字段 ...
    LONG   e_lfanew;     // PE 签名的偏移 (重要!)
} IMAGE_DOS_HEADER;

PE Signature & COFF Header

// PE 签名
DWORD Signature;  // "PE\0\0" (0x00004550)

// COFF 头
typedef struct _IMAGE_FILE_HEADER {
    WORD   Machine;              // 0x14c = i386, 0x8664 = AMD64
    WORD   NumberOfSections;     // 节数量
    DWORD  TimeDateStamp;        // 编译时间戳
    DWORD  PointerToSymbolTable;
    DWORD  NumberOfSymbols;
    WORD   SizeOfOptionalHeader; // Optional Header 大小
    WORD   Characteristics;      // 文件属性
} IMAGE_FILE_HEADER;

Optional Header

这是 PE 文件中最重要的头之一:

typedef struct _IMAGE_OPTIONAL_HEADER64 {
    WORD                 Magic;              // 0x10b = PE32, 0x20b = PE32+
    // ... 省略 ...
    DWORD                AddressOfEntryPoint; // 入口点 RVA (重要!)
    DWORD                BaseOfCode;          // 代码节起始 RVA
    ULONGLONG            ImageBase;           // 首选加载地址
    DWORD                SectionAlignment;    // 内存对齐
    DWORD                FileAlignment;       // 文件对齐
    // ... 省略 ...
    DWORD                NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[16];   // 数据目录表
} IMAGE_OPTIONAL_HEADER64;
📋 重要字段说明
字段说明逆向中的用途
AddressOfEntryPoint程序入口点程序开始执行的位置
ImageBase首选加载地址计算 VA = ImageBase + RVA
DataDirectory[1]导入表找程序调用了哪些 API
DataDirectory[0]导出表DLL 导出了哪些函数

Section Header(节表)

typedef struct _IMAGE_SECTION_HEADER {
    BYTE  Name[8];           // 节名称,如 ".text"
    DWORD VirtualSize;       // 内存中的大小
    DWORD VirtualAddress;    // 内存中的 RVA
    DWORD SizeOfRawData;     // 文件中的大小
    DWORD PointerToRawData;  // 文件中的偏移
    // ... 省略 ...
    DWORD Characteristics;   // 节属性
} IMAGE_SECTION_HEADER;

常见节及其用途:

节名内容属性
.text代码可执行、可读
.data已初始化数据可读、可写
.rdata只读数据可读
.bss未初始化数据可读、可写
.rsrc资源可读
.reloc重定位表可读

RVA 与 VA 的转换

逆向中最常遇到的地址概念:

VA (Virtual Address)  = ImageBase + RVA (Relative Virtual Address)
FOA (File Offset Address) = 文件中的实际偏移

RVA → FOA 转换公式

FOA = PointerToRawData + (RVA - VirtualAddress)
🔧 转换示例

假设:

  • ImageBase = 0x140000000
  • RVA = 0x1010
  • .text 节:VirtualAddress = 0x1000, PointerToRawData = 0x400

计算:

  • VA = 0x140000000 + 0x1010 = 0x140001010
  • FOA = 0x400 + (0x1010 - 0x1000) = 0x410

导入表(IAT)

导入表记录了程序从其他 DLL 导入的函数:

程序调用 MessageBoxA

IAT 中查找 MessageBoxA 地址

从 user32.dll 加载实际地址

逆向时,查看导入表可以快速了解程序的功能:


IDA

IDA 界面介绍

C:\blog\src\assets\images\从0开始的逆向工程\1.png

常用快捷键

快捷键功能使用场景
F5反编译查看伪代码
N重命名给函数/变量起有意义的名字
X交叉引用查看谁引用了这个地址
G跳转地址快速跳到指定地址
;添加注释记录分析心得
/添加结构体偏移注释标记结构体字段
Space切换视图文本/图形视图切换
Ctrl+S搜索字符串查找字符串
Ctrl+F当前窗口搜索局部搜索
Shift+F12字符串窗口查看所有字符串
Ctrl+E入口点列表查看程序入口

IDA 工作流程

1. 切入点

方法一:从字符串入手
Shift+F12 → 搜索关键字符串 → 双击 → X 查看交叉引用

通过软件在关键时刻暴露出的字符串来定位到PE文件的关键函数。

方法二:从 API 入手
查看导入表 → 找感兴趣的 API → X 查看交叉引用

通过找到关键函数一定会调用的API,然后反向查看交叉引用找到关键函数。


方法三:从入口点入手
从 main/WinMain 开始 → 跟踪调用链

最常见,直接主函数硬上。

方法四:从导出表函数入手
某些情况,导出函数也是非常关键的。

直接看PE文件的导出函数

2. 分析函数

F5 反编译 → 阅读伪代码 → 重命名变量 → 添加注释

命名规范

良好的命名习惯能让分析事半功倍:

类型命名格式示例
函数sub_功能描述sub_init_socket
变量v_类型_描述v_socket_fd
结构体直接用原名_IMAGE_DOS_HEADER
全局变量g_描述g_config_ptr


Edit page
Share this post on:

Previous Post
从0开始的逆向工程(二):C++虚函数机制
Next Post
初探 Windows 下的现代内存寻址