如何从dll获取稳定的地址?

时间:2016-06-22 14:57:59

标签: c++ winapi dll reverse-engineering

DLL具有一组其他应用程序可以调用的导出函数。通常,要调用这些函数,您可以使用函数名称或序号。

MSO.dll中,DLL的大多数导出入口点都没有名称,因此无法通过常规方式实际调用我想要的函数。

经过一些谷歌搜索后,我遇到了一个声称找到了我想要调用的函数的稳定地址(地址不会改变)的博主。

这些地址的问题在于,从Office的一个版本到另一个版本,甚至从一个更新到下一个版本,都不能指望它们是相同的。因此,我需要了解Lee Benfield在撰写blog post时如何在MSO.dll中找到这些稳定的地址。您可以在他的博客上找到源代码。

我试图理解李的代码部分:

image

这是我写的一些代码来找到这些地址:

#include <Windows.h>
#include <stdint.h>
#include <iostream>
#include <map>

int main()
{
    HMODULE hGetProcIDDLL = LoadLibrary("C:\\Program Files\\Microsoft Office 15\\root\\vfs\\ProgramFilesCommonX86\\Microsoft Shared\\OFFICE15\\mso.dll");

    PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)((char *)hGetProcIDDLL + ((PIMAGE_DOS_HEADER)hGetProcIDDLL)->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)((char *)hGetProcIDDLL + header->
        OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    char** names = (char**)((int)hGetProcIDDLL + exports->AddressOfNames);
    std::cout << "Total # of functions: " << exports->NumberOfFunctions << std::endl;
    std::cout << "Total # of named functions: " << exports->NumberOfNames << std::endl;

    std::map<uintptr_t, char*> addressToName;

    for (uint16_t i = 0; i < exports->NumberOfNames; i++)
    {
        char* name = (char*)hGetProcIDDLL + (int)names[i];
        void* fn = GetProcAddress(hGetProcIDDLL, name);
        addressToName[(uintptr_t)fn] = name;
        //std::cout << "Export: Name: " << name << " Address: " << fn << "\n";

    }

    for (uint16_t i = 1; i < exports->NumberOfFunctions; i++)
    {
        void* fn = GetProcAddress(hGetProcIDDLL, MAKEINTRESOURCE(i));
        std::map<uintptr_t, char*>::iterator it;
        it = addressToName.find((uintptr_t)fn);
        std::cout << "oridinal #: " << i << " address: " << fn << " Name: " << (it != addressToName.end() ? it->second : "N\\A") << "\n";
    }

    // Free the DLL module.
    if (!FreeLibrary(hGetProcIDDLL))
    {
        return E_FAIL;
    }

    return 0;
}

它基本上与Dumpbin.exe /Export做同样的事情,但也打印出procAddress,名称和序数值。下面你可以看到两个运行差异的图片。高阶字的两个字节是稳定的。

diff example

请参阅bin dump 1bin dump 2

我的问题有几个部分:

  1. 是什么让高阶词稳定而低阶词变化?

  2. 如何获取Lee在MSO.dll中找到的稳定地址?

  3. 如果找到稳定的地址,如何找出clearclipboardgetClipboardCount函数?

1 个答案:

答案 0 :(得分:0)

1。)“是什么让高阶词稳定而低阶词变化?” - 起初这根本不是真的。如果采用CONCRETE二进制mso.dll - 每个func都有一些RVA(来自模块库的相对VA)。但如果你采取任何另一个mso.dll构建 - 几乎100%的可能性 - 你有另一个RVA的功能。你寻找VA - 绝对地址。但VA = ImageBase + RVA,其中加载了mso.dll的ImageBase - 地址(HMODULE)。然而,它会将所有时间负载调用到不同的地址(ASLR) - 因此VA根本不会稳定。只有在使用相同的mso.dll版本时RVA才会稳定(在另一个版本中,RVA将是另一个版本)

2.。如何获取Lee在MSO.dll中找到的稳定地址? - 没有找到李。正如我所描述的那样,这完全是错误的问题。如果函数导出 - 你可以通过名称或序数获取地址(序数也可能不稳定,但这非常依赖于dll)。也可以,如果你有pdb文件,从pdb按名称获取公共符号地址(RVA)(即使对于未导出的符号)

3)如果找到稳定的地址,如何找出clearclipboard和getClipboardCount函数? - 再次 - 没有任何“稳定地址”存在。只有pdb中的导出或符号