【问题标题】:How to get stable Address from a dll?如何从 dll 中获取稳定的地址?
【发布时间】:2016-10-24 14:43:20
【问题描述】:

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

MSO.dll中,大部分导出到DLL的入口点都没有名字,所以我无法通过正常的方式务实地调用我想要的函数。

通过 Google 搜索,我遇到了一位博主,他声称找到了我想要调用的函数的稳定地址(不会更改的地址)。

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

我想要理解的 Lee 的代码部分:

这是我为找到这些地址而编写的一些代码:

#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、名称和序数值。您可以在下面看到两次运行差异的图片。高位字的两个字节是稳定的。

参见bin dump 1bin dump 2

我的问题有几个部分:

  1. 是什么让高位词稳定,低位词变化?

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

  3. 如何知道clearclipboardgetClipboardCount函数是哪一个,应该找到稳定的地址?

【问题讨论】:

  • 您为什么希望能够调用未记录的私有接口?你为什么要这样黑客攻击?
  • 如果您想在您拥有的未记录的私有逆向工程接口之上构建您的程序。但是你不应该期望任何稳定性。如果 MS 不想为您提供 API,那完全是他们的特权。
  • “我怀疑 MS 会在意。”我们关心,因为这意味着用户安装了新版本的 Office,而您的应用程序停止工作。然后用户说“新版本的 Office 不起作用。它使这个应用程序崩溃。我依靠这个应用程序进行日常工作。这是 Office 中的一个严重错误。”
  • 剪贴板已经有自己的一套API函数。为什么需要 Office 中的任何内容?
  • 不仅函数的地址会发生变化,而且函数签名或行为也会发生变化。由于它们没有公开曝光,微软可以随心所欲地改变事情——他们只需要在自己的团队内部协调这些改变。我希望我能在这里提供更多帮助,但我不能。

标签: c++ winapi dll reverse-engineering


【解决方案1】:

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

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

3)如何找出 clearclipboard 和 getClipboardCount 函数是哪一个,我应该找到一个稳定的地址? - 再次 - 不存在任何“稳定地址”。仅在 pdb 中导出或符号

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    • 2022-09-22
    • 2014-02-18
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多