Windows API逆向:常用API的调用识别与参数分析
做逆向分析,说白了就是跟操作系统打交道。而Windows API,就是系统给我们开的门。你逆向一个PE文件,十有八九会遇到MessageBox、CreateFile、ReadFile、WriteFile这几个老朋友。今天我就带你把这些API的调用特征、参数结构、以及逆向时的识别技巧,一次性讲透。
一、MessageBox:最显眼的断点
MessageBox这个API,我愿称之为逆向入门的第一道门槛。为什么?因为它太显眼了。你随便拖一个恶意软件样本进IDA,看到弹窗,十有八九就是它。
函数原型:
int MessageBox(
HWND hWnd, // 父窗口句柄,可为NULL
LPCTSTR lpText, // 消息文本
LPCTSTR lpCaption, // 标题文本
UINT uType // 按钮和图标类型
);
在x86环境下,参数从右往左压栈。你看到连续四个push指令,然后一个call,基本就能锁定。我个人习惯在OD或x64dbg里直接下断点:bp MessageBoxW。注意,有W和A两个版本,W是Unicode,A是ANSI。现在大部分程序都用W版本。
实战技巧:我在分析一个勒索软件时,发现它弹窗显示"你的文件已被加密"。直接下断MessageBoxW,堆栈里就能看到字符串地址。顺着字符串引用往上翻,很快就找到了加密逻辑的入口。这招屡试不爽。
二、CreateFile:文件操作的起点
CreateFile这个名字有点误导人。它不光能创建文件,还能打开文件、管道、甚至物理设备。逆向时看到这个API,意味着程序要开始读写数据了。
HANDLE CreateFile(
LPCTSTR lpFileName, // 文件名
DWORD dwDesiredAccess, // 访问模式
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性
DWORD dwCreationDisposition, // 创建方式
DWORD dwFlagsAndAttributes, // 文件属性
HANDLE hTemplateFile // 模板文件句柄
);
参数分析时,我最关注的是dwDesiredAccess和dwCreationDisposition。前者告诉你程序要读还是写,后者告诉你它是新建文件还是打开已有文件。
| dwDesiredAccess 常见值 | 含义 |
|---|---|
| GENERIC_READ (0x80000000) | 只读 |
| GENERIC_WRITE (0x40000000) | 只写 |
| GENERIC_READ | GENERIC_WRITE | 读写 |
| dwCreationDisposition 常见值 | 含义 |
|---|---|
| OPEN_EXISTING (3) | 打开已有文件 |
| CREATE_ALWAYS (2) | 总是新建 |
| OPEN_ALWAYS (4) | 存在则打开,否则新建 |
嗯,这里要注意。如果看到CREATE_ALWAYS配合GENERIC_WRITE,基本可以断定程序在写新文件。我曾经分析过一个后门程序,它就是用这种方式在临时目录下释放DLL文件。
三、ReadFile 与 WriteFile:数据搬运工
这两个API通常成对出现。一个读,一个写。逆向时看到它们,意味着数据在流动。
BOOL ReadFile(
HANDLE hFile, // 文件句柄
LPVOID lpBuffer, // 接收数据的缓冲区
DWORD nNumberOfBytesToRead, // 要读取的字节数
LPDWORD lpNumberOfBytesRead, // 实际读取的字节数
LPOVERLAPPED lpOverlapped // 重叠I/O结构
);
BOOL WriteFile(
HANDLE hFile, // 文件句柄
LPCVOID lpBuffer, // 要写入的数据
DWORD nNumberOfBytesToWrite,// 要写入的字节数
LPDWORD lpNumberOfBytesWritten,// 实际写入的字节数
LPOVERLAPPED lpOverlapped // 重叠I/O结构
);
参数分析的核心在于lpBuffer和nNumberOfBytesToRead/Write。缓冲区地址指向哪里?读/写多少字节?这些信息直接告诉你程序在操作什么数据。
避坑指南:我曾经在分析一个加密程序时,看到它ReadFile读取了0x1000字节,然后调用了一个自定义函数。我一开始以为那个函数是加密算法,结果跟进去发现只是个memcpy。真正的加密逻辑在更后面。所以,别被API调用顺序骗了,一定要跟踪数据流。
四、调用识别:静态与动态结合
识别API调用,我一般分两步走:
- 静态分析:在IDA里看导入表(IAT)。如果看到user32.dll里有MessageBoxW,kernel32.dll里有CreateFileW,那基本八九不离十。然后交叉引用(XREF)找到调用点。
- 动态调试:在OD或x64dbg里下断点。观察堆栈参数,确认实际传入的值。有时候静态分析看到的参数是变量,动态才能看到具体数值。
你想想看,静态分析就像看地图,动态调试就像亲自走一遍。两者结合,才能把API调用彻底搞清楚。
五、参数分析的实战技巧
参数分析,说白了就是回答三个问题:
- 谁在调用?—— 看调用者的上下文
- 传了什么?—— 看堆栈或寄存器
- 返回值怎么用?—— 看后续代码
举个例子。你在x64dbg里断在CreateFileW,堆栈显示:
0019F8E0 | 00401000 | lpFileName = "C:\config.ini"
0019F8E4 | 80000000 | dwDesiredAccess = GENERIC_READ
0019F8E8 | 00000001 | dwShareMode = FILE_SHARE_READ
0019F8EC | 00000000 | lpSecurityAttributes = NULL
0019F8F0 | 00000003 | dwCreationDisposition = OPEN_EXISTING
0019F8F4 | 00000080 | dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL
0019F8F8 | 00000000 | hTemplateFile = NULL
看到没?程序以只读方式打开一个已有的配置文件。接下来大概率会调用ReadFile读取内容。这时候你可以在ReadFile上下断,看看它读了多少数据,存到了哪里。
我的习惯:在分析未知样本时,我会先给所有文件操作API下断点。然后运行程序,观察它依次调用了哪些API。这样能快速勾勒出程序的行为轮廓。比如:CreateFile -> ReadFile -> 一些计算 -> WriteFile -> CloseHandle。这基本就是一个文件处理流程。
六、知识体系总览
下面这张图,是我梳理的Windows API逆向核心逻辑。你看一眼,心里就有谱了。
这张图把整个流程串起来了。从API识别开始,到参数分析,再到行为推断。四个常用API各自对应不同的操作场景。你只要记住这个框架,遇到任何样本都能快速上手。
七、写在最后
Windows API逆向,说白了就是跟操作系统对话。你读懂了API调用,就读懂了程序想干什么。MessageBox告诉你它想跟你交互,CreateFile告诉你它要动文件,ReadFile和WriteFile告诉你数据在流动。
我个人觉得,逆向分析最核心的能力不是记住所有API,而是学会观察和推理。看到API调用,问自己三个问题:它为什么调这个API?参数是什么?返回值怎么用?想清楚这三个问题,你就已经掌握了80%的分析工作。
嗯,今天就聊到这里。下次你遇到一个陌生样本,不妨先从这几个API入手。相信我,你会打开新世界的大门。
公众号:蓝海资料掘金营,微信deep3321