How do I get the (physical) baseaddress of an .DLL used in a process?

7k views Asked by At

I recently started a new c++ win32 console Project. It basically rewrites the value of a given Address in Memory.

The point is, I want it to use a pointer-map with offsets to recalculate the address it should use. Here is an image of the pointer map in Cheat Engine.

As I said, I managed it to rewrite the value (1147 in this case) manually if I just type the address, but I want it to be automatic! Hope you understand my problem

have a nice day.

2

There are 2 answers

0
GuidedHacking On

To get the base address of a module(DLL or EXE) in memory you can enumerate the loaded modules using ToolHelp32Snapshot Windows API function. Microsoft provides documented source code to find the module. Basically you need 2 functions, one to grab the ProcessId and then one to get the base address.

bool GetPid(const wchar_t* targetProcess, DWORD* procID)
{
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snap && snap != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 pe;
        pe.dwSize = sizeof(pe);
        if (Process32First(snap, &pe))
        {
            do
            {
                if (!wcscmp(pe.szExeFile, targetProcess))
                {
                    CloseHandle(snap);
                    *procID = pe.th32ProcessID;
                    return true;
                }
            } while (Process32Next(snap, &pe));
        }
    }
    return false;
}

char* GetModuleBase(const wchar_t* ModuleName, DWORD procID)
{
    MODULEENTRY32 ModuleEntry = { 0 };
    HANDLE SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procID);

    if (!SnapShot) return NULL;

    ModuleEntry.dwSize = sizeof(ModuleEntry);

    if (!Module32First(SnapShot, &ModuleEntry)) return NULL;

    do
    {
        if (!wcscmp(ModuleEntry.szModule, ModuleName))
        {
            CloseHandle(SnapShot);
            return (char*)ModuleEntry.modBaseAddr;
        }
    } while (Module32Next(SnapShot, &ModuleEntry));

    CloseHandle(SnapShot);
    return NULL;
}

Then you do:

DWORD ProcId;
GetPid(L"ac_client.exe", &ProcId);
char* ExeBaseAddress = GetModuleBase(L"ac_client.exe", ProcId);

If you've injected into the process in an internal hack you can use GetModuleHandle because as of posting the handle returned is just the address of the module:

 DWORD BaseAddress = (DWORD)GetModuleHandle(L"ac_client.exe");

To calculate the dynamic address pointed to by a multi-level pointer you can use this function, it basically de-references the pointer externally for you using ReadProcessMemory():

uintptr_t FindDmaAddy(int PointerLevel, HANDLE hProcHandle, uintptr_t Offsets[], uintptr_t BaseAddress)
{
    uintptr_t pointer = BaseAddress;
    uintptr_t pTemp;

    uintptr_t pointerAddr;
    for(int i = 0; i < PointerLevel; i++)
    {
            if(i == 0)
            {
                ReadProcessMemory(hProcHandle, (LPCVOID)pointer, &pTemp, sizeof(pTemp), NULL);
            }
            pointerAddr = pTemp + Offsets[i];

            ReadProcessMemory(hProcHandle, (LPCVOID)pointerAddr, &pTemp, sizeof(pTemp), NULL);
    }
    return pointerAddr;
}
0
Bonita Montero On

This is a more complete example in C++20 (because of lambdas in unevaluated context):

#define NOMINMAX
#include <Windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <memory>
#include <limits>

using namespace std;

using XHANDLE = unique_ptr<void, decltype([]( void *h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle( (HANDLE)h ); })>;
using XHMODULE = unique_ptr<void, decltype([]( void *h ) { h && FreeLibrary( (HMODULE)h ); })>;

[[noreturn]]
void throwSysErr( char const *errStr );

int main( int argc, char *argv[] )
{
    try
    {
        if( argc < 3 )
            return 0;
        XHMODULE xhm( GetModuleHandleA( argv[1] ) );
        if( !xhm.get() )
            xhm.reset( LoadLibraryA( argv[1] ) );
        static char const enumErr[] = "error enumerating modules";
        XHANDLE xhSnapshot( CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, GetProcessId( GetCurrentProcess() ) ) );
        if( xhSnapshot.get() == INVALID_HANDLE_VALUE )
            throwSysErr( enumErr );;
        MODULEENTRY32W me;
        me.dwSize = sizeof me;
        if( !Module32FirstW( xhSnapshot.get(), &me ) )
            throwSysErr( enumErr );;
        size_t moduleLength = strlen( argv[1] );
        wstring moduleName;
        moduleName.resize( strlen( argv[1] ), 0 );
        for( size_t i = 0; i != moduleLength; ++i )
            moduleName[i] = (unsigned char)argv[1][i];
        for( ; ; )
        {
            if( _wcsicmp( me.szModule, moduleName.c_str() ) == 0 )
                break;
            me.dwSize = sizeof me;
            if( !Module32NextW( xhSnapshot.get(), &me ) )
                if( GetLastError() == ERROR_NO_MORE_FILES )
                    return 0;
                else
                    throwSysErr( enumErr );;
        }
        cout << (void *)me.modBaseAddr << endl;
        void *procAddr = GetProcAddress( (HMODULE)xhm.get(), argv[2] );
        if( !procAddr )
            throwSysErr( "GetProcAddress() failed" );
        ptrdiff_t offset = (char *)procAddr - (char *)me.modBaseAddr;
        // here the code fails because if a very large positive
        // offset near the wrap-around (32 bit process)
        if( offset < 0 || (size_t)offset >= me.modBaseSize )
            return 0;
        cout << "relative address " << hex << offset << endl;
        return offset <= numeric_limits<int>::max() ? (int)offset : 0;
    }
    catch( exception const &exc )
    {
        cout << exc.what() << endl;
        return 0;
    }
}

[[noreturn]]
void throwSysErr( char const *errStr )
{
    throw system_error( (int)GetLastError(), system_category(), errStr );
}