滴水逆向-绑定导入表

课堂知识点

文字知识点

点击查看代码
打印绑定导入表

绑定导入表结构:

PE加载EXE相关的DLL时,首先会根据IMAGE_IMPORT_DESCRIPTOR结构中的TimeDateStamp来判断是否要重新
计算IAT表中的地址。

TimeDateStamp == 0  未绑定

TimeDateStamp == -1 已绑定 真正的绑定时间为IMAGE_BOUND_IMPORT_DESCRIPTOR的TimeDateStamp

绑定导入表的定位:

绑定导入表位于数据目录的第12项


typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    NumberOfModuleForwarderRefs;
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_BOUND_FORWARDER_REF {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    Reserved;
} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;

特别说明:

当IMAGE_BOUND_IMPORT_DESCRIPTOR结构中的TimeDateStamp与DLL文件标准PE头中的TimeDateStamp值不相符
时,或者DLL需要重新定位的时候,就会重新计算IAT中的值.

打印绑定导入表相关代码

点击查看代码
//绑定导入表打印
//IMAGE_BOUND_IMPORT_DESCRIPTOR
VOID LogBoundImportTable(IN LPVOID pFileBuffer)
{
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNTHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
    PIMAGE_DATA_DIRECTORY pDataDirectory_BoundImportTable = NULL;
    PIMAGE_BOUND_IMPORT_DESCRIPTOR pBoundImportTable = NULL;
    PIMAGE_BOUND_FORWARDER_REF pBoundForwarderTable = NULL;
    
    if (pFileBuffer == NULL)
    {
        printf("FileBuffer获取失败!\r\n");
        return;
    }
    
    //判断是否是有效的MZ标志
    if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
    {
        printf("无效的MZ标识\r\n");
        return;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    
    //判断是否是有效的PE标志
    if (*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    {
        printf("无效的PE标记\r\n");
        return;
    }
    
    //定位各种头
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
    pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory;
    
    //根据可选PE头里面的数据目录这个数组准确定位到导入表位置,导入表是在数据目录的第二个位置,下面两种方式都可以
    //#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
    //pDataDirectory_BoundImportTable = &pDataDirectory[11];
    pDataDirectory_BoundImportTable = &pDataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT];
    
    if (!pDataDirectory_BoundImportTable->VirtualAddress)
    {
        printf("pDataDirectory_BoundImportTable 这个程序不存在绑定导入表\r\n");
        return;
    }
    
    //验证打印导出表RVA和FOA地址
    printf("BoundImport Table RVA: %#010x\r\n",pDataDirectory_BoundImportTable->VirtualAddress);
    DWORD FOA_BoundImportTable = RvaToFileOffset(pFileBuffer,pDataDirectory_BoundImportTable->VirtualAddress);
    printf("BoundImport Table FOA: %#010x\r\n",FOA_BoundImportTable);
    //确认好FOA地址之后,开始指针偏移到文件的导入表位置
    pBoundImportTable = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((DWORD)pDosHeader+FOA_BoundImportTable);

    //打印查看对应结构体pBoundImportTable的3个字段的值
    printf("pBoundImportTable->NumberOfModuleForwarderRefs: %#x\r\n",pBoundImportTable->NumberOfModuleForwarderRefs);
    printf("pBoundImportTable->OffsetModuleName: %#x\r\n",pBoundImportTable->OffsetModuleName);
    printf("pBoundImportTable->TimeDateStamp: %#d\r\n",pBoundImportTable->TimeDateStamp);

    //验证偏移好的pBoundImportTable内存地址和对应内存地址的内容
    printf("*pBoundImportTable: %#010x\r\n",*pBoundImportTable);
    printf("pBoundImportTable: %#010x\r\n",pBoundImportTable);
    DWORD BoundImportTableBase = (DWORD)pBoundImportTable;
    printf("BoundImportTableBase: %#010x\r\n",BoundImportTableBase);

    //根据绑定导入表的算法,和上面验证的结果,得出结论是要像得到绑定导入表的名称,需要使用偏移的内存地址;
    //使用此偏移的内存地址然后加上绑定导入表的OffsetModuleName的值,即可得到准确的绑定导入表的名称对应的内存地址;
    //然后就可以直接打印内存地址对应的名称即可;
    while (*(PDWORD)pBoundImportTable)
    {
        PDWORD pOffsetModuleName = (PDWORD)(BoundImportTableBase+pBoundImportTable->OffsetModuleName);
        printf("BoundImportTable Module Name: %#s\r\n",pOffsetModuleName);
        pBoundImportTable++;
    }
}

打印结果

posted @ 2021-09-29 15:04  皇帽讲绿帽带法技巧  阅读(169)  评论(0)    收藏  举报