joppiesaus
joppiesaus

Reputation: 5750

Converting "application's" memory address

So I am writing my very first trainer for Microsoft's Spider Solitaire. First I needed to backwards-engineer all memory adresses until I found a static one. I used offsets so I can easily revert them back.

I've found this:

1000157F78  <-- starting value(never changes)
+ E8        <-- offsets to pointers
+ 14
002DC3D4    <-- final adress(changes every time)

This is how my trainer gets his final memory address:

DWORD FindFinalAddr(HANDLE hProc, BYTE offsets[], DWORD baseAddress, unsigned char pointerLevel)
{
    DWORD pointer = baseAddress;
    DWORD pTemp = 0;
    DWORD pointerAddr = 0;

    // set base address
    ReadProcessMemory(hProc, (LPCVOID)pointer, &pTemp, (DWORD)sizeof(pTemp), NULL);

    for (int c = 0; c < pointerLevel; c++)
    {
        pointerAddr = pTemp + (DWORD)offsets[c];
        ReadProcessMemory(hProc, (LPCVOID)pointerAddr, &pTemp, (DWORD)sizeof(pTemp), NULL);
    }

    return pointerAddr;
}

In this case, I do(roughly) this: FindFinalAddr(hProc, {0xE8, 0x14}, 0x1000157F78, 2);

This works fine when Spider Solitaire is open and I have just found the static value. But when I close it and re-open it's no longer valid.

I found out that 1000157F78 is actually SpiderSolitaire.exe+B5F78 It's like a offset. If I enter this in cheat engine I get the right memory address, but I can't just simply enter it in my code.

Now is my question: How do I convert SpiderSolitaire.exe+B5F78 to the right memory adress?

Note: SpiderSolitaire.exe is 64 bit.

EDIT: I've tried the following:

void * entryPoint = (void*) hProc;

DWORD base_addr = ((DWORD)(entryPoint) + 0xB5F78);

But that doesn't work, because the entry point is 5C. The adress it should give(in this session) is FF7A5F78, but what really happens is 5C + B5F78 = B5F4D.

Upvotes: 1

Views: 1325

Answers (2)

joppiesaus
joppiesaus

Reputation: 5750

After a long period of research I've found my own answer! This piece of code gets the module base address(AKA entry point)(you need to include TlHelp32.h and tchar.h):

DWORD getModuleBaseAddr(DWORD procId, TCHAR * lpszModuleName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, procId);
    DWORD moduleBaseAddr = 0;

    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 mentry32 = { 0 };
        mentry32.dwSize = sizeof(MODULEENTRY32);

        if (Module32First(hSnapshot, &mentry32))
        {
            do
            {
                if (_tcscmp(mentry32.szModule, lpszModuleName) == 0)
                {
                    moduleBaseAddr = (DWORD)mentry32.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnapshot, &mentry32));
        }
    }
    else
    {
        std::cout << "Error on finding module base address: " << GetLastError() << "\n";
    }

    return moduleBaseAddr;
}

You give it the pid and the name of the module(like game.exe), then it browses through modules and check if they are the same, and then it returns the base address.

Now, I tested this with Spider Solitaire. It gave me an error. That is because my compiled code was 32 bit and SpiderSolitaire.exe was 64 bit, which was caused because my Windows 7 was 64 bit.

So make sure your code has the same platform target as the code you're aiming for!

Upvotes: 1

Jester
Jester

Reputation: 58762

I think you can query the load address using GetModuleInformation, passing NULL for the module handle parameter. If that doesn't work, you can take the longer route through EnumProcessModules and GetModuleBaseName.

Upvotes: 1

Related Questions