1

我在枚舉kernel32.dll中的函數名時遇到了問題。我檢索了它的IMAGE_EXPORT_DIRECTORY結構並存儲了指向每個函數名稱的字符數組的指針數組:char** name_table = (char**)(image+pExp_dir->AddressOfNames); //pExp_dir is a pointer to the IMAGE_EXPORT_DIRECTORY structure。我現在試圖迭代函數名稱,並將它們匹配到一個字符串,該字符串包含我需要的RVA函數的名稱。遍歷IMAGE_EXPORT_DIRECTORY結構的AddressOfNames成員的問題

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 
} 

任何幫助,將不勝感激!

+0

這裏只是一個猜測,但我認爲它可能與我描述的問題有關[在我的這個舊答案中](http://stackoverflow.com/questions/18440205/casting-void-to-2d-array-的-INT-C/18440456#18440456)。數組數組與指針指針不同。 –

+0

@JoachimPileborg有什麼建議修復它,或者它們「簡單地不兼容」? –

+0

我是不正確的,它*是一個指針數組,其中指針指針將工作。但是,它看起來不是C風格字符串的數組,因爲類型(根據[此MSDN文檔](https://msdn.microsoft.com/en-us/library/ms809762.aspx))是'PDWORD * AddressOfNames'。即它基本上是一個指向'DWORD'的數組。我對這種格式一無所知,但你總是可以將「指針」轉儲出來,看看它們有什麼值,如果它們看起來像內存指針或偏移量或其他東西。 –

回答

0

Docs (Section 6.3)說下一個大約AddressOfNames

導出名稱指針表是地址(的RVAs)的陣列到 導出名稱表。這些指針每個都是32位,並且相對於圖像庫的 。這些指針按照詞彙順序排列,以便進行二進制 搜索。

而關於AddressOfFunctions

在導出地址表中的每個條目是使用兩個 格式之一,場...如果指定的地址不是出口部分 內(如由可選的 標題中指示的地址和長度定義),該字段是導出RVA:代碼中的實際地址或 數據。否則,該字段是Forwarder 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.名稱表是有序的,所以你可以使用二進制搜索。

+0

最後!非常感謝!它甚至沒有出現在我身上,我想這是因爲我直到最近纔在32位筆記本電腦上編程。非常感激! –