A DLL has a set of exported functions that other applications can call. Typically to call these functions you either have a function name or an ordinal number.
In MSO.dll
, most of the exported entry points to the DLL don't have names, so I can't call the function I want pragmatically by normal means.
Upon a bit of Google searching I ran into a blogger that claims to have found stable addresses (addresses that don't change) to the very function I want to call.
The issue with these addresses is that they can't be counted on to be the same from one release of Office to another, or even from one update to the next. So I need to find out how Lee Benfield found these stable addresses in MSO.dll
when he wrote his blog post. You can find the source code on his blog.
The portion of Lee's code I am trying to understand:
Here is some code I wrote to find these addresses:
#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;
}
It essentially does the same thing as Dumpbin.exe /Export, but also prints out the procAddress
, name, and ordinal value. Below you can see a picture of a diff of two runs. The two byte of the higher order word are stable.
see bin dump 1 and bin dump 2.
My question has a few parts:
what makes the higher order word stable and the lower order word vary?
how do I get the stable addresses that Lee found in the MSO.dll?
how do I find out which one is the
clearclipboard
andgetClipboardCount
function should I find a stable address?