ReadProcessMemory only works with breakpoint

115 views Asked by At

I start off creating a process, logging if it fails, and then a while loop to wait for the window to be found.

PROCESS_INFORMATION p;
STARTUPINFO s;
ZeroMemory(&s, sizeof(s));
s.cb = sizeof(s);
ZeroMemory(&p, sizeof(p));
if (!CreateProcessA("D:\\SteamLibrary\\steamapps\\common\\Fallout 4\\Wolf4SDL.exe", "", NULL, NULL, FALSE, 0, NULL, NULL, &s, &p))
{
    _MESSAGE("CreateProcess failed (%d).", GetLastError());
}
//wait for the process to start
while (FindWindowA(NULL, "Wolfenstein 3D") == NULL);

Then set up the vars - x64 for both processes, so 64-bit addresses. "addr" is a pointer. addrOff is a static offset.

HANDLE procHandle = p.hProcess;
unsigned long long addr;
unsigned long long addrOff = 0x00000001401a7718;
SIZE_T NumberOfBytesToRead = sizeof(addr); 
SIZE_T NumberOfBytesActuallyRead;

Now the Read, and some basic debug messaging

ReadProcessMemory(procHandle, (LPCVOID)(addrOff), &addr, NumberOfBytesToRead, &NumberOfBytesActuallyRead);
_MESSAGE("addr: %p",addr);
_MESSAGE("numBytesRead: %d", NumberOfBytesActuallyRead);

So here's the issue - If I drop a breakpoint in this, addr will have the appropriate value for the static offset being read. If I do not, addr will have the value of 0x0000000000000000. In both cases, NumberOfBytesActuallyRead will have the appropriate value of 8. Which, even without looking at my log, the process is present and accounted for - but looking at my log confirms this.

Needless to say, this makes debugging this issue damn near impossible. Now, one oddity came to mind - I've noticed in examples where people add the offset to the base address, while I'm just using the offset. So, with the possibility that my value of addrOff includes the base address, I checked the base address in both situations - and they were both the same. And for the sake of completion, the base address code.

unsigned long long dwBase = -1;

EnumProcessModules(procHandle, hModules, 0, &cModules);
hModules = new HMODULE[cModules / sizeof(HMODULE)];

if (EnumProcessModules(procHandle, hModules, cModules / sizeof(HMODULE), &cModules)) {
    for (size_t i = 0; i < cModules / sizeof(HMODULE); i++) {
        if (GetModuleBaseName(procHandle, hModules[i], szBuf, sizeof(szBuf))) {
            if (std::string("Wolf4SDL.exe").compare(szBuf) == 0) {
                dwBase = (unsigned long long)hModules[i];
                break;
            }
        }
    }
}
1

There are 1 answers

0
user253751 On BEST ANSWER

It's pretty straightforward.

The variable you are reading is still 0 when you read it.

When you use a breakpoint, the time delay where you look at the code and press continue is when the other process sets the variable.