迭代IMAGE_EXPORT_DIRECTORY结构

时间:2016-07-08 01:21:59

标签: arrays pointers winapi portable-executable pointer-arithmetic

我在枚举kernel32.dll中的函数名时遇到问题。我检索了它的IMAGE_EXPORT_DIRECTORY结构并存储了一个指向每个函数名的char数组的指针数组:char** name_table = (char**)(image+pExp_dir->AddressOfNames); //pExp_dir is a pointer to the IMAGE_EXPORT_DIRECTORY structure。我现在正在尝试遍历函数名称并将它们匹配到一个字符串,该字符串包含我需要的RVA函数的名称。

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
        }

但如果找不到该功能,程序就会崩溃。在查看DBG调试器中的内存转储后,我可以看到name_tables包含所有函数名称,包括我正在寻找的函数,但是我的程序似乎跳过了几个元素,即使我正在迭代它元素一次一个。用户stijn suggested我不应该使用intptr_tchar*强制转换为DWORD以用于指针算术。所以我的问题是关于迭代name_table的正确方法,因为好像这是一个指针算术问题。这是获取文件映像的函数和实际获取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
}

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:2)

Docs (Section 6.3)接着说AddressOfNames

  

导出名称指针表是一个地址数组(RVAs)   导出名称表。指针各32位,相对于   图像库。指针是词法排序的,以允许二进制   搜索。

关于AddressOfFunctions

  

“导出地址表”中的每个条目都是使用两个中的一个的字段   格式,...如果指定的地址不在导出部分中   (由Optional中指明的地址和长度定义   标题),该字段是Export RVA:代码中的实际地址或   数据。否则,该字段是转发器RVA,它在其中命名符号   另一个DLL。

您的变量不是void**char**,但实际上所有变量都是DWORD*,因为这些表包含RVA。尝试下一个代码:

    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
        }
    }

因此,当您的代码在32位计算机上运行时,它应该可以正常工作,无论不正确的var类型,但如果您使用的是64位 - 指针的长度是DWORD的两倍,它将跳过表中的奇数条目并且超出数组范围,这可能会导致崩溃。

P.S。名称表是有序的,因此您可以使用二进制搜索。