导入表解析 导入表结构 在程序加载前INT和IAT内容一致指向同样的结构体,但是在程序加载后INT不变但是IAT会变PE加载器填充为函数地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; }; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DWORD FirstThunk; } IMAGE_IMPORT_DESCRIPTOR; typedef struct _IMAGE_THUNK_DATA32 { union { PBYTE ForwarderString; PDWORD Function; DWORD Ordinal; PIMAGE_IMPORT_BY_NAME AddressOfData; } u1; } IMAGE_THUNK_DATA32; typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; BYTE Name[1 ]; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
导入表_IMAGE_IMPORT_DESCRIPTOR
中主要包含了
Name
导入模块的名称
OriginalFirstThunk
记录函数名称的IAT表(加载前和INT相同)
FirstThunk
记录函数地址的INT表
完整解析导入表
PE -> DOS -> NT -> OPT -> section[1]导入表 -> IAT/INT -> PIMAGE_IMPORT_BY_NAME、Address
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 #include <Windows.h> #include <stdio.h> #define PATH L"C:\\Test.dll" bool IsPeFile (LPVOID lpFileBuffer) { PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpFileBuffer; if (IMAGE_DOS_SIGNATURE == dosHeader->e_magic) { PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((LONG)lpFileBuffer + dosHeader->e_lfanew); if (IMAGE_NT_SIGNATURE == ntHeader->Signature) return true ; } return false ; } DWORD RvaToFoa (DWORD rva, LPVOID lpFileBuffer) { PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpFileBuffer; PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((LONG)lpFileBuffer + dosHeader->e_lfanew); PIMAGE_FILE_HEADER fileHeader = (PIMAGE_FILE_HEADER)&ntHeader->FileHeader; PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION (ntHeader); for (int i = 0 ; i < fileHeader->NumberOfSections; i++) { if (sectionHeader[i].VirtualAddress <= rva && rva <= sectionHeader[i].SizeOfRawData + sectionHeader[i].VirtualAddress) { DWORD foa = rva - sectionHeader[i].VirtualAddress + sectionHeader[i].PointerToRawData; return foa; } } return 0 ; } void ParseImportTable (LPVOID lpFileBuffer) { PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpFileBuffer; PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((LONG)lpFileBuffer + dosHeader->e_lfanew); PIMAGE_OPTIONAL_HEADER optHeader = (PIMAGE_OPTIONAL_HEADER)&ntHeader->OptionalHeader; DWORD importTableRva = optHeader->DataDirectory[1 ].VirtualAddress; DWORD importTableFoa = RvaToFoa (importTableRva, lpFileBuffer); PIMAGE_IMPORT_DESCRIPTOR importTable = (PIMAGE_IMPORT_DESCRIPTOR)(importTableFoa + (DWORD)lpFileBuffer); while (importTable->Name != 0 ) { DWORD moduleNameFoa = RvaToFoa (importTable->Name, lpFileBuffer); PCHAR name = (PCHAR)(moduleNameFoa + (DWORD)lpFileBuffer); printf ("导入的模块名称为: %s\n" , name); DWORD iatFoa = RvaToFoa (importTable->FirstThunk, lpFileBuffer); PIMAGE_THUNK_DATA iat = (PIMAGE_THUNK_DATA)(iatFoa + (DWORD)lpFileBuffer); while (iat->u1.AddressOfData != 0 ) { bool isOnlyOrdinal = IMAGE_SNAP_BY_ORDINAL (iat->u1.Ordinal); if (isOnlyOrdinal == false ) { DWORD importByNameTableRva = RvaToFoa (iat->u1.AddressOfData, lpFileBuffer); PIMAGE_IMPORT_BY_NAME nameTable = (PIMAGE_IMPORT_BY_NAME)(importByNameTableRva + (DWORD)lpFileBuffer); printf ("导入函数序号为: 0x%02X , 函数名称为: %s \n" , nameTable->Hint, nameTable->Name); } else { printf ("函数的导入序号为: %x\n" , iat->u1.Ordinal & 0x7FFFFFFF ); } iat++; } importTable++; } } int main () { HANDLE hFile = CreateFile ( PATH, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { printf ("打开文件失败" ); system ("pause" ); return 0 ; } DWORD real_size = 0 ; DWORD file_size = GetFileSize (hFile, NULL ); char * pFileBuffer = new char [file_size]; ReadFile (hFile, pFileBuffer, file_size, &real_size, NULL ); CloseHandle (hFile); if (IsPeFile (pFileBuffer) == true ) { printf ("是有效的PE文件\n" ); ParseImportTable (pFileBuffer); } else { printf ("不是有效的PE文件\n" ); } system ("pause" ); return 0 ; }
导出表解析 导出表结构
name -> ordinal -> address / address -> ordinal -> name // 序号表用作名称和地址转换和函数标识
上述已经解析过PE头,这里直接就展示核心函数,解析导出表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 void get_export_information (LPVOID fileBuff) { PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBuff; PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((LONG)fileBuff + dosHeader->e_lfanew); PIMAGE_OPTIONAL_HEADER optHeader = (PIMAGE_OPTIONAL_HEADER)&ntHeader->OptionalHeader; DWORD exportTableRva = optHeader->DataDirectory[0 ].VirtualAddress; DWORD exportTableFoa = RvaToFoa (exportTableRva, fileBuff); PIMAGE_EXPORT_DIRECTORY exportTable = (PIMAGE_EXPORT_DIRECTORY)((DWORD)fileBuff + exportTableFoa); DWORD exportTableModuleName = RvaToFoa (exportTable->Name, fileBuff); printf ("模块的名称为:%s\n" , exportTableModuleName + (DWORD)fileBuff); DWORD base = exportTable->Base; DWORD exportOrdinalTableRva = RvaToFoa (exportTable->AddressOfNameOrdinals, fileBuff); PWORD ordinalTable = (PWORD)(exportOrdinalTableRva + (DWORD)fileBuff); DWORD exportNameTableRva = RvaToFoa (exportTable->AddressOfNames, fileBuff); PDWORD nameTable = (PDWORD)(exportNameTableRva + (DWORD)fileBuff); DWORD exportAddressTable = RvaToFoa (exportTable->AddressOfFunctions, fileBuff); PDWORD addressTable = (PDWORD)(exportAddressTable + (DWORD)fileBuff); for (int index = 0 ; index < exportTable->NumberOfFunctions; index++) { int i = 0 ; bool isNameExport = false ; for (; i < exportTable->NumberOfNames; i++) { if (index == ordinalTable[i]) { isNameExport = true ; break ; } } if (isNameExport) { DWORD nameRva = nameTable[i]; DWORD nameFoa = RvaToFoa (nameRva, fileBuff); printf ("函数名称为:%s\n" , nameFoa + (DWORD)fileBuff); } else if (addressTable[index] != 0 ) { printf ("函数名字为 NULL, 地址RVA为:0x%08X\n" , addressTable[index]); } } }
三个表之间的寻找对应关系如下图所示:
参考文章
https://blog.csdn.net/Apollon_krj/article/details/77417063
https://blog.51cto.com/u_15744744/6121082
《加密与解密》