0

I've successfully injected a .dll into an .exe and need to access a value through multi level pointers.

This is a working example that's getting the correct value:

#include <Windows.h>
#include <iostream>
#include <vector>
#include <TlHelp32.h>
#include <tchar.h>
using namespace std;

DWORD dwGetModuleBaseAddress(TCHAR *lpszModuleName, DWORD pID)
{
    DWORD dwBaseAddress = 0;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pID);
    MODULEENTRY32 moduleEntry32 = { 0 };
    moduleEntry32.dwSize = sizeof(MODULEENTRY32);
    if (Module32First(hSnapshot, &moduleEntry32))
    {
        do {
            if (_tcscmp(moduleEntry32.szModule, lpszModuleName) == 0)
            {
                dwBaseAddress = (DWORD)moduleEntry32.modBaseAddr;
                break;
            }
        } while (Module32Next(hSnapshot, &moduleEntry32));
    }
    CloseHandle(hSnapshot);
    return dwBaseAddress;
}

int main()
{
    DWORD pID;
    DWORD off1, off2, off3, off4, off5;
    DWORD baseAddress;
    DWORD xAddress;
    int newX;
    int currentX;
    char moduleName[] = "TibiaInjected2.exe";
    HWND hGameWindow;
    HANDLE pHandle;

    // Getting handles
    hGameWindow = FindWindowA(NULL, "Tibia - 127.0.0.1:7171");
    GetWindowThreadProcessId(hGameWindow, &pID);
    pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);

    // Getting base address
    DWORD clientBase = dwGetModuleBaseAddress(_T(moduleName), pID);

    ReadProcessMemory(pHandle, (LPCVOID)(clientBase + 0x0031D0CC), &baseAddress, sizeof(baseAddress), NULL);
    cout << "Base address: " << hex << baseAddress << endl;

    ReadProcessMemory(pHandle, (LPCVOID)(baseAddress + 0x4), &off1, sizeof(off1), NULL);
    cout << "Offset 1: " << hex << off1 << endl;

    ReadProcessMemory(pHandle, (LPCVOID)(off1 + 0x4), &off2, sizeof(off2), NULL);
    cout << "Offset 2: " << hex << off2 << endl;

    ReadProcessMemory(pHandle, (LPCVOID)(off2 + 0xA0), &off3, sizeof(off3), NULL);
    cout << "Offset 3: " << hex << off3 << endl;

    ReadProcessMemory(pHandle, (LPCVOID)(off3 + 0x100), &off4, sizeof(off4), NULL);
    cout << "Offset 4: " << hex << off4 << endl;

    ReadProcessMemory(pHandle, (LPCVOID)(off4 + 0x14), &off5, sizeof(off5), NULL);
    cout << "Offset 5: " << hex << off5 << endl;

    cin.get();
}

I'd rather use my statically injected DLL and from what I've heard I can replace the whole dwGetModuleBaseAddress with GetModuleHandle(NULL) since it's from within the injected DLL. I also don't need to open any process. But if I don't do all that, what to replace the ReadProcessMemory with?

ReadProcessMemory(pHandle, (LPCVOID)(clientBase + 0x0031D0CC), &baseAddress, sizeof(baseAddress), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(baseAddress + 0x4), &off1, sizeof(off1), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off1 + 0x4), &off2, sizeof(off2), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off2 + 0xA0), &off3, sizeof(off3), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off3 + 0x100), &off4, sizeof(off4), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off4 + 0x14), &off5, sizeof(off5), NULL);

I've managed to access value from static addresses directly by doing:

int* exampleValue = *(int*)0x12345678;

But can't figure out how to do the same with pointers and offset.

snzm
  • 29
  • 1
  • 4

2 Answers2

1

Yes you can use GetModuleHandle(NULL); to get the handle to the main .exe module or replace NULL with a string that matches the DLL name.

You can use this function that loops through the offsets, de-referencing and adding offsets at each level:

uintptr_t FindDMAAddy(uintptr_t ptr, std::vector<unsigned int> offsets)
{
    uintptr_t addr = ptr;
    for (unsigned int i = 0; i < offsets.size() ; ++i)
    {
        addr = *(uintptr_t*)addr;
        addr += offsets[i];
    }
    return addr;
}

uintptr_t ammoAddr = FindDMAAddy(dynamicPtrBaseAddr, { 0x374, 0x14, 0x0 });

//or

int * ammoAddr = (int*)FindDMAAddy(dynamicPtrBaseAddr, { 0x374, 0x14, 0x0 });

You could also do some crazy thing like:

int * ammo = (int*)((*(uintptr_t*)((*(uintptr_t*)(dynamicPtrBaseAddr)) +0x374)) + 0x14);

But it's more confusing and annoying than it's worth.

GuidedHacking
  • 3,628
  • 1
  • 9
  • 59
  • It didn't work for me, but I found the answer. Anyways, thank you. – snzm Aug 27 '18 at 14:52
  • @snzm In my code dynamicPtrBaseAddr is the pointer to the object not the address of the object. In your code you do: \*(DWORD*)(clientBase + 0x0031D0CC) which de-references the pointer first. If you used the address of the object in place of dynamicPtrBaseAddr in my code, it wouldn't work because it's not the correct arg. If you used the pointer (clientBase + 0x0031D0CC) instead, it should work fine. Is that why you had a problem? Let me know so I can update my answer to be better. It is good to use uintptr_t or similar so you don't have to update code for x64, instead just change build – GuidedHacking Aug 28 '18 at 16:19
0

This worked for me (could be put in a loop like the other answer did):

DWORD base = *(DWORD*)(clientBase + 0x0031D0CC);
DWORD offsets[] = { 0x4, 0x4, 0xA0, 0x100, 0x14 };

DWORD off1 = *(DWORD*)(base + offsets[0]);
DWORD off2 = *(DWORD*)(off1 + offsets[1]);
DWORD off3 = *(DWORD*)(off2 + offsets[2]);
DWORD off4 = *(DWORD*)(off3 + offsets[3]);
DWORD off5 = *(DWORD*)(off4 + offsets[4]);
cout << "Value: " << off5 << endl;
snzm
  • 29
  • 1
  • 4