课堂知识点 文字知识点 点击查看代码 打印绑定导入表 绑定导入表结构: PE加载EXE相关的DLL时,首先会根据IMAGE_IMPORT_DESCRIPTOR结构中的TimeDateStamp来判断是否要重新 计算IAT表中的地址。
课堂知识点
文字知识点
点击查看代码
绑定导入表结构:
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++;
}
}
打印结果
迷茫的人生,需要不断努力,才能看清远方模糊的志向!