You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:53:27