How to get stable Address from a dll?

2019-06-14 09:13发布

问题:

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:

  1. what makes the higher order word stable and the lower order word vary?

  2. how do I get the stable addresses that Lee found in the MSO.dll?

  3. how do I find out which one is the clearclipboard and getClipboardCount function should I find a stable address?

回答1:

1.) "what makes the higher order word stable and the lower order word vary?" - at first this is not true at all. if take CONCRETE binary mso.dll - every func have some RVA (relative VA from module base). but if you take any another mso.dll build - with almost 100% posibility - you got another RVA for functions. you looking for VA - absolute address. but VA = ImageBase + RVA, where ImageBase - address(HMODULE) at which your mso.dll is loaded. however it call all time load at different addreses (ASLR) - so VA will be not stable at all. RVA will be stable only while you use same mso.dll version (in another versions and RVA will be another)

2.) how do I get the stable addresses that Lee found in the MSO.dll? - Lee nothing found. this, as i describe, mistake question at all. if function exported - you can got in address by name or ordinal (ordinal may be also not stable, but this is very depended from dll). also possible, if you have pdb file, get public symbol address (RVA), from pdb by name(even for not exported symbols)

3)how do I find out which one is the clearclipboard and getClipboardCount function should I find a stable address? - again - no any "stable address" exist. only exports or symbols in pdb