Created
February 27, 2021 11:08
-
-
Save rakisaionji/a5ea8f2b3971b16032654ad5b8109505 to your computer and use it in GitHub Desktop.
Dumps IAT table from existing PE file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <stdio.h> | |
int main(int argc, char* argv[]) | |
{ | |
if (argc < 2) goto SHOW_HELP; | |
char fileName[MAX_PATH] = { 0 }; | |
memcpy_s(&fileName, MAX_PATH, argv[1], MAX_PATH); | |
BOOL cfgMinCsv = FALSE; | |
BOOL cfgAllCsv = FALSE; | |
for (int i = 1; i < argc; i++) | |
{ | |
char* arg = argv[i]; | |
if (strcmp(arg, "--min") == 0) { cfgMinCsv = TRUE; } | |
else if (strcmp(arg, "--csv") == 0) { cfgAllCsv = TRUE; } | |
else if (strcmp(arg, "--help") == 0) | |
{ | |
SHOW_HELP: | |
printf("%s [input] [--csv|--min]\n", argv[0]); | |
return 0; | |
} | |
} | |
if (cfgAllCsv && cfgMinCsv) | |
{ | |
printf("Initialize() failed\n"); | |
return -1; | |
} | |
DWORD fileSize; | |
DWORD bytesRead; | |
HANDLE file = NULL; | |
LPVOID fileData = NULL; | |
PIMAGE_DOS_HEADER dosHeader = NULL; | |
PIMAGE_NT_HEADERS32 imageNTHeaders32 = NULL; | |
PIMAGE_NT_HEADERS64 imageNTHeaders64 = NULL; | |
PIMAGE_SECTION_HEADER sectionHeader = NULL; | |
PIMAGE_SECTION_HEADER importSection = NULL; | |
PIMAGE_IMPORT_DESCRIPTOR importDescriptor = NULL; | |
PIMAGE_THUNK_DATA32 thunkData32 = NULL; | |
PIMAGE_THUNK_DATA64 thunkData64 = NULL; | |
UINT64 thunk; | |
UINT64 thunkAddr; | |
UINT32 addressSize; | |
UINT64 ordinalFlag; | |
DWORD_PTR rawOffset; | |
BOOL bResult; | |
// Open file | |
file = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (file == INVALID_HANDLE_VALUE) { | |
printf("CreateFile() failed\n"); | |
return -1; | |
} | |
// Allocate heap | |
fileSize = GetFileSize(file, NULL); | |
fileData = HeapAlloc(GetProcessHeap(), 0, fileSize); | |
// Read file bytes to memory | |
bResult = ReadFile(file, fileData, fileSize, &bytesRead, NULL); | |
if (!bResult) | |
{ | |
printf("ReadFile() failed\n"); | |
return -1; | |
} | |
// Get pointer to DOS header | |
dosHeader = (PIMAGE_DOS_HEADER)fileData; | |
if (!dosHeader) | |
{ | |
printf("IMAGE_DOS_HEADER is NULL\n"); | |
return -2; | |
} | |
// Get pointer to NT header | |
imageNTHeaders32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)fileData + dosHeader->e_lfanew); | |
imageNTHeaders64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)fileData + dosHeader->e_lfanew); | |
if (!imageNTHeaders32 || !imageNTHeaders64) | |
{ | |
printf("IMAGE_NT_HEADERS is NULL\n"); | |
return -2; | |
} | |
BOOL is64bit; | |
size_t sectionSize; | |
WORD numberOfSections; | |
DWORD_PTR sectionLocation; | |
DWORD_PTR importDirectoryRVA; | |
// Get optional header to determine 64-bit | |
if (imageNTHeaders64->OptionalHeader.Magic == 0x20B) | |
{ | |
addressSize = 16; | |
is64bit = TRUE; | |
ordinalFlag = IMAGE_ORDINAL_FLAG64; | |
sectionSize = sizeof(IMAGE_SECTION_HEADER); | |
numberOfSections = imageNTHeaders64->FileHeader.NumberOfSections; | |
sectionLocation = (DWORD_PTR)imageNTHeaders64 + sizeof(DWORD) + (DWORD)(sizeof(IMAGE_FILE_HEADER)) + (DWORD)imageNTHeaders64->FileHeader.SizeOfOptionalHeader; | |
importDirectoryRVA = imageNTHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; | |
} | |
else | |
{ | |
addressSize = 8; | |
is64bit = FALSE; | |
ordinalFlag = IMAGE_ORDINAL_FLAG32; | |
sectionSize = sizeof(IMAGE_SECTION_HEADER); | |
numberOfSections = imageNTHeaders32->FileHeader.NumberOfSections; | |
sectionLocation = (DWORD_PTR)imageNTHeaders32 + sizeof(DWORD) + (DWORD)(sizeof(IMAGE_FILE_HEADER)) + (DWORD)imageNTHeaders32->FileHeader.SizeOfOptionalHeader; | |
importDirectoryRVA = imageNTHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; | |
} | |
// Get section data | |
for (int i = 0; i < numberOfSections; i++) | |
{ | |
sectionHeader = (PIMAGE_SECTION_HEADER)sectionLocation; | |
// Save section that contains import directory table | |
if (importDirectoryRVA >= sectionHeader->VirtualAddress && importDirectoryRVA < sectionHeader->VirtualAddress + sectionHeader->Misc.VirtualSize) { | |
importSection = sectionHeader; | |
} | |
sectionLocation += sectionSize; | |
} | |
if (!importSection) | |
{ | |
printf("IMPORT_SECTION_HEADER is NULL\n"); | |
return -3; | |
} | |
// Get file offset to import table | |
rawOffset = (DWORD_PTR)fileData + importSection->PointerToRawData; | |
// Get pointer to import descriptor's file offset | |
importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(rawOffset + (importDirectoryRVA - importSection->VirtualAddress)); | |
// Print out imports table | |
DWORD spacing = -20; | |
char separator = ' '; | |
char* moduleName = NULL; | |
if (cfgAllCsv || cfgMinCsv) | |
{ | |
spacing = 0; | |
separator = ','; | |
} | |
for (UINT64 addressOfData; importDescriptor->Name != 0; importDescriptor++) | |
{ | |
moduleName = (char*)(rawOffset + (importDescriptor->Name - importSection->VirtualAddress)); | |
thunk = importDescriptor->OriginalFirstThunk == 0 ? importDescriptor->FirstThunk : importDescriptor->OriginalFirstThunk; | |
thunkData32 = (PIMAGE_THUNK_DATA32)(rawOffset + (thunk - importSection->VirtualAddress)); | |
thunkData64 = (PIMAGE_THUNK_DATA64)(rawOffset + (thunk - importSection->VirtualAddress)); | |
thunkAddr = importDescriptor->FirstThunk; | |
while (1) | |
{ | |
if (is64bit) addressOfData = thunkData64->u1.AddressOfData; | |
else addressOfData = thunkData32->u1.AddressOfData; | |
if (addressOfData == 0) break; | |
// Print import detail if needed | |
if (!cfgMinCsv) | |
{ | |
printf("0x%.*llx%c", addressSize, (UINT64)thunkAddr, separator); | |
printf("0x%.*llx%c", addressSize, (UINT64)addressOfData, separator); | |
} | |
printf("%*s%c", spacing, moduleName, separator); | |
// Cheap and probably non-reliable way of checking if the function is imported via its ordinal number | |
if (addressOfData > ordinalFlag) { | |
// Show lower bits of the value to get the ordinal | |
printf("Ordinal#%d\n", (WORD)addressOfData); | |
} | |
else { | |
printf("%s\n", (char*)(rawOffset + (addressOfData - importSection->VirtualAddress + 2))); | |
} | |
if (is64bit) | |
{ | |
thunkAddr += 8; | |
thunkData64++; | |
} | |
else | |
{ | |
thunkAddr += 4; | |
thunkData32++; | |
} | |
} | |
} | |
// Completed | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment