问题
I'm having problems enumerating function names in kernel32.dll
. I retrieved its IMAGE_EXPORT_DIRECTORY
structure and stored an array of pointers to char arrays of each function name: char** name_table = (char**)(image+pExp_dir->AddressOfNames); //pExp_dir is a pointer to the IMAGE_EXPORT_DIRECTORY structure
. I'm now trying to iterate through the function names and match them to a string containing the name of the function whom's RVA I need.
for(int i=0;i<pExp_dir->NumberOfNames;i++) //until i is 1 less than how many names there are to iterate through elements
{
printf("%s ", (char*)(image+(DWORD)(uintptr_t)name_table[i])); //print the name of each function iterated through, I went back and read through these names and didn't see GetProcAddress anywhere
if(proc_name == image+(DWORD)(uintptr_t)name_table[i]) //if(strcmp(proc_name, (const char*)image+(DWORD)(intptr_t)name_table[i]) == 0) //Is it the function we're looking for?
{
address = (DWORD)(uintptr_t)func_table[ord_table[i]];//If so convert the address of the function into a DWORD(hexadecimal)
system("pause");
system("CLS"); //Clear the screen
return address; //return the address of the function
}
But if it doesn't find the function then the program crashes. And after looking in the memory dump in the DBG debugger I can see that name_tables
contains all of the function names including the function I'm looking for but my program seems to skip several elements even though I'm iterating through its elements one at a time. User stijn suggested that I shouldn't use intptr_t
to cast char*
to DWORD
to use for pointer arithmetic. So my question is really about the correct way to iterate through name_table
because it seems as if this is a pointer arithmetic problem. Here's the function to get the file image and the function that actually gets the RVA:
void* GetFileImage(char path[]) //Get maps the image of the file into memory and returns the beginning virtual address of the file in memory
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);//Get a handle to the dll with read rights
if(hFile == INVALID_HANDLE_VALUE){printf("Error getting file handle: %d", (int)GetLastError());return NULL;} //Check whether or not CreateFile succeeded
HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap"); //Create file map
if(file_map == INVALID_HANDLE_VALUE){printf("Error mapping file: %d", (int)GetLastError());return NULL;} //Did it succeed
LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0); //Map it into the virtual address space of my program
if(file_image == 0){printf("Error getting mapped view: %d", (int)GetLastError());return NULL;} //Did it succeed
return file_image; //return the base address of the image
}
DWORD RVAddress(char* image, const char* proc_name) //Gets the relative virtual address of the function and returns a DWORD to be cast to void*.
{
DWORD address = 0xFFFFFFFF;
PIMAGE_DOS_HEADER pDos_hdr = (PIMAGE_DOS_HEADER)image; //Get dos header
PIMAGE_NT_HEADERS pNt_hdr = (PIMAGE_NT_HEADERS)(image+pDos_hdr->e_lfanew); //Get PE header by using the offset in dos header + the base address of the file image
IMAGE_OPTIONAL_HEADER opt_hdr = pNt_hdr->OptionalHeader; //Get the optional header
IMAGE_DATA_DIRECTORY exp_entry = opt_hdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExp_dir = (PIMAGE_EXPORT_DIRECTORY)(image+exp_entry.VirtualAddress); //Get a pointer to the export directory
void** func_table = (void**)(image+pExp_dir->AddressOfFunctions); //Get an array of pointers to the functions
WORD* ord_table = (WORD*)(image+pExp_dir->AddressOfNameOrdinals); //Get an array of ordinals
char** name_table = (char**)(image+pExp_dir->AddressOfNames); //Get an array of function names
for(int i=0;i<pExp_dir->NumberOfNames;i++) //until i is 1 less than how many names there are to iterate through elements
{
printf("%s ", (char*)(image+(DWORD)(uintptr_t)name_table[i])); //print the name of each function iterated through, I went back and read through these names and didn't see GetProcAddress anywhere
if(proc_name == image+(DWORD)(uintptr_t)name_table[i]) //if(strcmp(proc_name, (const char*)image+(DWORD)(intptr_t)name_table[i]) == 0) //Is it the function we're looking for?
{
address = (DWORD)(uintptr_t)func_table[ord_table[i]];//If so convert the address of the function into a DWORD(hexadecimal)
system("pause");
system("CLS"); //Clear the screen
return address; //return the address of the function
}
}
return (DWORD)0; //Other wise return 0
}
Any help would be much appreciated!
回答1:
Docs (Section 6.3) say next about AddressOfNames
table
The Export Name Pointer Table is an array of addresses (RVAs) into the Export Name Table. The pointers are 32 bits each and are relative to the Image Base. The pointers are ordered lexically to allow binary searches.
And about AddressOfFunctions
:
Each entry in the Export Address Table is a field that uses one of two formats, ... If the address specified is not within the export section (as defined by the address and length indicated in the Optional Header), the field is an Export RVA: an actual address in code or data. Otherwise, the field is a Forwarder RVA, which names a symbol in another DLL.
Your variables is not void**
and char**
, but actually all are DWORD*
because these tables hold RVA. Try next code:
DWORD* func_table = (DWORD*)(image+pExp_dir->AddressOfFunctions); //Get an array of pointers to the functions
WORD* ord_table = (WORD*)(image+pExp_dir->AddressOfNameOrdinals); //Get an array of ordinals
DWORD* name_table = (DWORD*)(image+pExp_dir->AddressOfNames); //Get an array of function names
for(int i=0;i<pExp_dir->NumberOfNames;i++) //until i is 1 less than how many names there are to iterate through elements
{
printf("%s ", (char*)(image+name_table[i])); //print the name of each function iterated through, I went back and read through these names and didn't see GetProcAddress anywhere
if(strcmp(proc_name, (const char*)(image+name_table[i])) == 0) //Is it the function we're looking for?
{
// TODO should we distinguish between normal and forwarded exports?
WORD ordinal_base = 1; // TODO read it from export directory
address = func_table[ord_table[i] - ordinal_base];//If so convert the address of the function into a DWORD(hexadecimal)
system("pause");
system("CLS"); //Clear the screen
return address; //return the address of the function
}
}
So when your code runs on 32-bit machine it should work regardless of the incorrect var types, but if you are on 64-bit - pointers are twice longer than DWORD
and it will skip odd entries in tables and goes out of array bound, that may cause crash.
P.S. Name table is ordered, so you can use binary search.
来源:https://stackoverflow.com/questions/38257621/problems-iterating-through-addressofnames-member-of-image-export-directory-struc