Problems iterating through AddressOfNames member of IMAGE_EXPORT_DIRECTORY structure

匆匆过客 提交于 2019-12-02 06:25:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!