使用C语言在Windows下解析PE文件时的IAT定位问题求助
问题分析与修复方案
核心问题1:跨进程内存直接访问非法
你直接将远程进程的ImageBase(array_modules[i])作为本地指针解引用,这是完全错误的。array_modules中存储的是目标进程虚拟地址空间里的模块基址,本地进程的地址空间和目标进程完全隔离,直接访问会触发内存访问错误(通常程序会崩溃或无响应,导致后续代码不执行)。
必须使用ReadProcessMemory函数,将目标进程的PE头数据读取到本地缓冲区后再解析。
核心问题2:字符串API不匹配
VS默认采用Unicode字符集编译,TCHAR会被定义为wchar_t,但你用了ANSI版本的strstr来查找字符串,这会导致无法匹配到"OneDrive.exe",所以VS中连ImageBase都不会输出。应该使用_tcsstr(TCHAR版本的字符串查找函数)。
其他代码错误
- 错误的格式化字符串:
printf("Handle not retrieved %s", error);:error是DWORD类型,应该用%lu输出,用%s会导致非法内存访问。printf("%s", dosHeaders->e_magic);:e_magic是WORD类型(值为0x5A4D,对应字符"MZ"),用%s会把它当作指针,应该用%04X输出十六进制值,或者%c%c输出字符。
- 未检查内存读取操作的返回值:读取远程内存时必须确认是否成功,否则后续解析会基于无效数据。
修复后的代码示例
#include <windows.h> #include <stdio.h> #include <psapi.h> #include <tchar.h> int main() { DWORD pid = 11596; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess == NULL) { DWORD error = GetLastError(); printf("无法获取进程句柄,错误码:%lu\n", error); return 1; } printf("进程句柄:%p\n", hProcess); HMODULE hModules[1024]; DWORD cbNeeded; if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) { printf("枚举模块失败\n"); CloseHandle(hProcess); return 1; } TCHAR szModuleName[MAX_PATH]; for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { if (!GetModuleFileNameEx(hProcess, hModules[i], szModuleName, MAX_PATH)) { continue; } if (_tcsstr(szModuleName, _T("OneDrive.exe")) != NULL) { printf("模块基址:%p\n", hModules[i]); // 读取DOS头到本地缓冲区 IMAGE_DOS_HEADER dosHeader; if (!ReadProcessMemory(hProcess, hModules[i], &dosHeader, sizeof(dosHeader), NULL)) { printf("读取DOS头失败,错误码:%lu\n", GetLastError()); continue; } if (dosHeader.e_magic == IMAGE_DOS_SIGNATURE) { printf("DOS签名验证通过:0x%04X (MZ)\n", dosHeader.e_magic); } else { printf("DOS签名无效\n"); continue; } // 读取NT头到本地缓冲区 IMAGE_NT_HEADERS ntHeader; LPVOID ntHeaderAddr = (LPVOID)((DWORD_PTR)hModules[i] + dosHeader.e_lfanew); if (!ReadProcessMemory(hProcess, ntHeaderAddr, &ntHeader, sizeof(ntHeader), NULL)) { printf("读取NT头失败,错误码:%lu\n", GetLastError()); continue; } if (ntHeader.Signature == IMAGE_NT_SIGNATURE) { printf("NT签名验证通过:0x%08X\n", ntHeader.Signature); } else { printf("NT签名无效\n"); continue; } // 获取导入表目录 IMAGE_DATA_DIRECTORY importDir = ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; if (importDir.VirtualAddress == 0 || importDir.Size == 0) { printf("导入表不存在\n"); continue; } printf("导入表VA:0x%08X,大小:0x%08X\n", importDir.VirtualAddress, importDir.Size); // 后续读取导入表内容需继续使用ReadProcessMemory... } } CloseHandle(hProcess); return 0; }
额外说明
- VSCode和VS表现不同,大概率是因为两者默认的字符集设置不同:VSCode可能用了多字节字符集,
strstr能正常工作;VS默认Unicode,strstr无法处理宽字符串导致匹配失败。 - 解析远程进程PE结构时,所有数据都必须通过
ReadProcessMemory读取,绝对不能直接访问远程地址。 - 尽量避免使用全局变量(比如你的
int i),改用局部变量更安全。
内容的提问来源于stack exchange,提问作者Pieter Jansen
相关产品推荐
相关产品推荐

