DLL具有一组其他应用程序可以调用的导出函数。通常,要调用这些函数,您可以使用函数名称或序号。
在MSO.dll
中,DLL的大多数导出入口点都没有名称,因此无法通过常规方式实际调用我想要的函数。
经过一些谷歌搜索后,我遇到了一个声称找到了我想要调用的函数的稳定地址(地址不会改变)的博主。
这些地址的问题在于,从Office的一个版本到另一个版本,甚至从一个更新到下一个版本,都不能指望它们是相同的。因此,我需要了解Lee Benfield在撰写blog post时如何在MSO.dll
中找到这些稳定的地址。您可以在他的博客上找到源代码。
我试图理解李的代码部分:
这是我写的一些代码来找到这些地址:
#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 1和bin dump 2。
我的问题有几个部分:
是什么让高阶词稳定而低阶词变化?
如何获取Lee在MSO.dll中找到的稳定地址?
如果找到稳定的地址,如何找出clearclipboard
和getClipboardCount
函数?
答案 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中的导出或符号