#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
// http://hatriot.github.io/blog/2017/09/19/abusing-delay-load-dll/
// https://blog.csdn.net/adam001521/article/details/84658708
/* index values of DataDirectory
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
*/
/*
* get DOS header (base) --> location of NT header
* get NT header {
* _IMAGE_FILE_HEADER
* IMAGE_OPTIONAL_HEADER : DataDirectory array
* }
* DataDirectory { RVA SIZE }
*
*/
/* export table
struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; // dll name
DWORD Base; // ordinal base, link a func: @(base + unbased ordinal)
DWORD NumberOfFunctions;
DWORD NumberOfNames; //
DWORD AddressOfFunctions; // function address array
DWORD AddressOfNames; // name array, with the same order of ordinals, but not functions
DWORD AddressOfNameOrdinals; // unbased ordinals, the index in functions
}
*/
/* import address table is not in Directory
struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // by name or ordinal
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; // dll name
DWORD FirstThunk; // pointer to a pos in IAT, its value firstThunk->u1.function is the address
} IMAGE_IMPORT_DESCRIPTOR;
struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString;
DWORD Function; // func address (firstthunk, its one address in IAT)
DWORD Ordinal; // by ordinal
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
}
*/
/* delay table
struct _IMAGE_DELAYLOAD_DESCRIPTOR {
union {
DWORD AllAttributes;
struct {
DWORD RvaBased : 1; // Delay load version 2
DWORD ReservedAttributes : 31;
};
} Attributes;
DWORD DllNameRVA; // RVA to the name of the target library (NULL-terminate ASCII string)
DWORD ModuleHandleRVA; // RVA to the HMODULE caching location (PHMODULE)
DWORD ImportAddressTableRVA; // RVA to the start of the IAT (PIMAGE_THUNK_DATA)
DWORD ImportNameTableRVA; // RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData)
DWORD BoundImportAddressTableRVA; // RVA to an optional bound IAT
DWORD UnloadInformationTableRVA; // RVA to an optional unload info table
DWORD TimeDateStamp; // 0 if not bound,
}
*/
void GetTables(char *pDllName)
{
PIMAGE_EXPORT_DIRECTORY pExportTable;
PIMAGE_IMPORT_DESCRIPTOR pIMportTable;
PIMAGE_DELAYLOAD_DESCRIPTOR pDelayTable;
HMODULE hModule;
PDWORD Address, Name;
PWORD Ordinal;
PIMAGE_DOS_HEADER pImgDos;
PIMAGE_NT_HEADERS pImgNt;
//Sleep(20 * 1000);
hModule = LoadLibraryEx(pDllName, NULL, 0);
pImgDos = (PIMAGE_DOS_HEADER)(hModule);
pImgNt = (PIMAGE_NT_HEADERS)((LPBYTE)pImgDos + pImgDos->e_lfanew);
// the first section
// PIMAGE_SECTION_HEADER pSech = IMAGE_FIRST_SECTION(pImgNt);
// import table
pExportTable = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)hModule + pImgNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
Address = (PDWORD)((LPBYTE)hModule + pExportTable->AddressOfFunctions);
Name = (PDWORD)((LPBYTE)hModule + pExportTable->AddressOfNames);
Ordinal = (PWORD)((LPBYTE)hModule + pExportTable->AddressOfNameOrdinals);
printf("there are %d functions in the export table, %d are exported by name\n", pExportTable->NumberOfFunctions, pExportTable->NumberOfNames);
for (int i = 0; i<pExportTable->NumberOfNames; i++)
{
printf("find function %s at %p ordinal: %d \n", (char*)hModule + Name[i], (LPBYTE)hModule + Address[Ordinal[i]], Ordinal[i] + pExportTable->Base);
}
// export table
printf("-----------------------------------------------------------------------------------\n");
pIMportTable = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)hModule + pImgNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (pIMportTable->Name != NULL)
{
printf("Import DLL: %s\n", (LPBYTE)hModule + pIMportTable->Name);
PIMAGE_THUNK_DATA pInfoEntry = (PIMAGE_THUNK_DATA)((LPBYTE)hModule + pIMportTable->OriginalFirstThunk);
PIMAGE_THUNK_DATA pAddressEntry = (PIMAGE_THUNK_DATA)((LPBYTE)hModule + pIMportTable->FirstThunk);
while (pInfoEntry->u1.AddressOfData != NULL)
{
if (pInfoEntry->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
printf("\tfunc ordinal: %d addr: %p\n", IMAGE_ORDINAL(pInfoEntry->u1.Ordinal), pAddressEntry->u1.Function);
}
else
{
IMAGE_IMPORT_BY_NAME* pImport = PIMAGE_IMPORT_BY_NAME((LPBYTE)hModule + pInfoEntry->u1.AddressOfData);
printf("\tfunc name: %s addr: %p entry addr %p\n", pImport->Name, pAddressEntry->u1.Function, pAddressEntry);
}
pInfoEntry++;
pAddressEntry++;
}
pIMportTable++;
}
// delay table
printf("-----------------------------------------------------------------------------------\n");
pDelayTable = (PIMAGE_DELAYLOAD_DESCRIPTOR)((LPBYTE)pImgDos +
pImgNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress);
for (IMAGE_DELAYLOAD_DESCRIPTOR* entry = pDelayTable; entry->ImportAddressTableRVA != NULL; entry++) {
char *pDllName = (char*)((LPBYTE)hModule + entry->DllNameRVA);
PIMAGE_THUNK_DATA pInfoEntry = (PIMAGE_THUNK_DATA)((LPBYTE)hModule + entry->ImportNameTableRVA);
PIMAGE_THUNK_DATA pAddressEntry = (PIMAGE_THUNK_DATA)((LPBYTE)hModule + entry->ImportAddressTableRVA);
printf("delay import module: %s\n", pDllName);
while (pInfoEntry->u1.AddressOfData != NULL)
{
if (pInfoEntry->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
printf("\tfunc ordinal: %d addr: %p\n", IMAGE_ORDINAL(pInfoEntry->u1.Ordinal), pAddressEntry->u1.Function);
}
else
{
IMAGE_IMPORT_BY_NAME* pImport = PIMAGE_IMPORT_BY_NAME((LPBYTE)hModule + pInfoEntry->u1.AddressOfData);
printf("\tfunc name: %s addr: %p\n", pImport->Name, pAddressEntry->u1.Function);
}
pInfoEntry++;
pAddressEntry++;
}
}
}
int main(int argc, char **argv)
{
GetTables(argv[1]);
return 0;
}