通过WINNT.H定义的结构体,获取进程IAT表

在前面的文章里,学习PE结构都是通过手动的方式去计算PE结构的NT映象头,NT可选头之类的,手动计算确实有利于加深对PE结构的熟悉程度,但是,在实际编程的时候,利用一些数据结构会让程序更高效,更简洁..于是,顺便记录了下通过WINNT.H自定义的结构体,来获取本进程的IAT表

注 : 转载请注明来源 enjoy5512的博客 http://blog.csdn.net/enjoy5512

打开WINNT.H文件可以看到里面定义了大量的结构体,正是这些已定义好的结构体,让我们能更方便的去获取PE文件的结构信息

通过WINNT.H定义的结构体,获取进程IAT表_第1张图片


获取IAT表大致过程:


1) 获取模块信息
2) 获取DOS头
3) 获取NT映象头
4) 获取NT可选映象头
5) 获取IAT表地址
6) 循环遍历IAT表,获取导入函数信息


测试代码

具体解释请看代码的注释


/////////////////////////////////////////////////////////////////////////////
//  文件名 : test.c
//  工程 : test
//  作者 : enjoy5512   修改者 : enjoy5512   最后优化注释者 : enjoy5512
//  个人技术博客 : blog.csdn.net/enjoy5512
//  个人GitHub   : github.com/whu-enjoy
//  csdn code    : code.csdn.net/enjoy5512
//  描述 : 使用WINNT.h中自带的PE文件结构体,获取本进程的IAT表
//  主要函数 :
//  版本 : 最终确定版  完成日期 : 2016年6月2日 19:06:21
//  修改 :
/////////////////////////////////////////////////////////////////////////////

#include 
#include 

int main()
{
    HMODULE hMod;                               //保存模块句柄
    PIMAGE_DOS_HEADER pDosHeader;               //PE DOS头结构体
    PIMAGE_NT_HEADERS pNTHeaders;               //PE NT头结构体
    PIMAGE_OPTIONAL_HEADER pOptHeader;          //PE可选头结构体
    PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor; //PE函数导入表结构体

    //多导入一个dll函数测试
    MessageBox(NULL,"导入了user32.dll 的MessageBox函数","test",NULL);

    //获取本进程模块句柄
    hMod = GetModuleHandle(NULL);

    //获取本进程PE DOS结构体
    pDosHeader = (PIMAGE_DOS_HEADER)hMod;

    //根据DOS的e_lfanew得到NT映像头结构体
    pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hMod + pDosHeader->e_lfanew);

    //获取本进程的NT可选头结构体
    pOptHeader = (PIMAGE_OPTIONAL_HEADER)&(pNTHeaders->OptionalHeader);

    //获取本进程的函数导入表结构体
    pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hMod + pOptHeader->DataDirectory[1].VirtualAddress);

    //循环遍历函数导入表的IMAGE_IMPORT_DESCRIPTOR结构体
    while(pImportDescriptor->FirstThunk)
    {
        //获取函数名地址IMAGE_THUNK_DATA结构体
        PIMAGE_THUNK_DATA pFuncNameAddr = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->OriginalFirstThunk);

        //获取函数在内存中的地址IMAGE_THUNK_DATA结构体
        PIMAGE_THUNK_DATA pFuncAddr = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->FirstThunk);

        //获取本导入dll的dll文件名
        char *pDllName = (char *)((BYTE *)hMod + pImportDescriptor->Name);
        printf("%s\n",pDllName);

        //循环遍历函数导入表的函数名列表
        while(pFuncNameAddr->u1.Function)
        {
            //获取函数导入序号
            WORD *iNo = ((BYTE *)hMod + (DWORD)pFuncNameAddr->u1.AddressOfData);

            //获取函数名
            char *pFuncName = (char *)((BYTE *)hMod + (DWORD)pFuncNameAddr->u1.AddressOfData + 2);

            //获取函数名对应的函数在内存中的地址
            PDWORD lpAddr = pFuncAddr->u1.AddressOfData;

            printf("%0 4X : %s    %#X\n",*iNo, pFuncName, lpAddr);

            //指向下一个函数
            pFuncNameAddr++;
            pFuncAddr++;
        };

        getchar();
        //指向下一个dll
        pImportDescriptor++;
    };

    return 0;
}

你可能感兴趣的:(C语言学习)