Skip to content

Instantly share code, notes, and snippets.

@rakisaionji
Created February 27, 2021 11:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rakisaionji/a5ea8f2b3971b16032654ad5b8109505 to your computer and use it in GitHub Desktop.
Save rakisaionji/a5ea8f2b3971b16032654ad5b8109505 to your computer and use it in GitHub Desktop.
Dumps IAT table from existing PE file.
#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