zoukankan      html  css  js  c++  java
  • WindowsAPI解析IAT地址

    #include <stdio.h>
    #include <windows.h>
    
    int main(int argc,char* argv[]){
        /*
        typedef struct _IMAGE_IMPORT_DESCRIPTOR {
            union{
                DWORD   Characteristics;
                DWORD   OriginalFirstThunk;
            };
            DWORD   TimeDateStamp;
            DWORD   ForwarderChain;      
            DWORD   Name; // DLL名称的RVA偏移
            DWORD   FirstThunk; // IAT真实地址的RVA偏移
        }IMAGE_IMPORT_DESCRIPTOR;
        */
    
        /*
        typedef struct _IMAGE_THUNK_DATA32{
            union{
                DWORD ForwarderString;
                DWORD Function;
                DWORD Ordinal;
                DWORD AddressOfData; // RVA指向_IMAGE_IMPORT_BY_NAME 
            }u1;
        }IMAGE_THUNK_DATA32;
        */
    
        /*
       typedef struct _IMAGE_IMPORT_BY_NAME{
            WORD    Hint;
            BYTE    Name[1];
        }IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
        */
        HMODULE hmod;
        PIMAGE_DOS_HEADER pdos;
        PIMAGE_NT_HEADERS pnt;
        PIMAGE_OPTIONAL_HEADER popt;
        PIMAGE_IMPORT_DESCRIPTOR piid;
        PIMAGE_THUNK_DATA pfuncname_addr,pfunc_addr;
        
        hmod = GetModuleHandle(NULL); // HMODULE类型不能直接参与运算,要强制转换为字节流
        pdos = (PIMAGE_DOS_HEADER)hmod;
        pnt = (PIMAGE_NT_HEADERS)((BYTE *)hmod + pdos->e_lfanew); // NT_offset = dos.e_lfanew
        popt = (PIMAGE_OPTIONAL_HEADER)(&(pnt->OptionalHeader));
        piid = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hmod+popt->DataDirectory[1].VirtualAddress); // Base_addr + RVA_addr
        while(piid->FirstThunk){
            pfuncname_addr = (PIMAGE_THUNK_DATA)((BYTE *)hmod + piid->OriginalFirstThunk);
            pfunc_addr = (PIMAGE_THUNK_DATA)((BYTE *)hmod + piid->FirstThunk);
            char* pdll_name = (char *)((BYTE *)hmod + piid->Name);
            printf("DLL:%s
    ",pdll_name);
            printf("|
    ");
            while(pfuncname_addr->u1.Function){
                char* func_name = (char *)((BYTE *)hmod + pfuncname_addr->u1.AddressOfData+2);
                DWORD lpAddr = pfunc_addr->u1.AddressOfData;
                printf("Func_Name:%s	",func_name); // OriginalFirstThunk对应一个结构体数组,分别是每个函数的名称
                printf("Addr:0x%04x
    ",lpAddr); // FirstThunk对应一个结构体数组,开始与OriginalFirstThunk相同,之后填入函数的真实地址
                pfuncname_addr++;
                pfunc_addr++;
            }
            printf("
    ");
            piid++; // 每个DLL对应一个IID项
        }
        getchar();
        return 0;
    }
    
    简单解释

    通过获取本进程的模块句柄,从而定位到文件载入的内存区域!再用 DOS 头的 e_lfanew 偏移到 NT 头,用 NT 头找到 Optional 头。其中 Optional 的 DataDirectory 的第一个索引项就对应第一个 IID 项,再通过 IID 定位到 OriginalFirstThunk 和 FirstThunk,循环获取每一个函数的名称与内存地址!再外层循环每一个 DLL!最终打印出所有 DLL 的 IAT 函数名称与内存地址!

    注意

    OriginalFirstThunk指向的 u1.AddressOfData 是 Hint/Name 所在的结构体
    FirstThunk指向的 u1.AddressOfData 此时已经填入函数在内存的真实地址

  • 相关阅读:
    迭代器、生成器、装饰器(转)
    Python小数据池
    接阿里云oss有感
    VSCode快捷键
    前端跨域调请求 nginx反向代理
    Git生成密钥
    【westorm系列之二】配置格式化
    钉钉安卓端无法渲染数据
    express 写接口
    js正则匹配身份证号 有坑
  • 原文地址:https://www.cnblogs.com/laohaozi/p/12537624.html
Copyright © 2011-2022 走看看