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;
}
}
}
}
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.