64位C++内存地址偏移计算问题求助
64位内存地址偏移计算错误排查
问题概述
计算带偏移的64位内存地址时出现错误:32位场景下可正常实现,但64位场景结果不符合预期。例如,基地址0x000002586F08CE30加上偏移0x88后,实际得到0x2586F08CEB8,但预期结果应为0x25825C4C880。
错误代码分析
用户的错误代码片段如下:
void aVoid() { DWORD64* add = (DWORD64*)0x000002586F08CE30; cout << add << endl; DWORD64* off = (DWORD64*)0x88; cout << off << endl; DWORD64* BaseTimeAddress = (DWORD64*)((char*)add + (DWORD64)off); cout << BaseTimeAddress << endl; // Gets 000002586F08CEB8 }
核心错误点:
- 混淆指针地址与指针指向的值:代码直接将基地址指针
add作为数值与偏移相加,但实际需要先读取add指向的内存中存储的64位地址值,再加上偏移。 - 偏移类型冗余:将偏移
0x88定义为DWORD64*指针类型完全多余,直接用数值类型DWORD64存储即可。
修正方案
1. 本地进程地址计算(直接解引用)
如果目标地址属于当前进程,可直接解引用获取指针指向的值,再添加偏移:
void aVoid() { // 基地址(数值形式存储) DWORD64 basePtr = 0x000002586F08CE30; cout << hex << basePtr << endl; // 偏移量(数值形式存储) DWORD64 offset = 0x88; cout << hex << offset << endl; // 读取基地址指向的内存中的64位地址值 DWORD64 targetBase = *(DWORD64*)basePtr; // 计算最终目标地址 DWORD64 targetAddr = targetBase + offset; cout << hex << targetAddr << endl; // 得到预期的0x25825C4C880 }
2. 远程进程地址计算(使用ReadProcessMemory)
如果目标地址属于其他进程(如代码中的游戏进程),必须通过ReadProcessMemory读取远程内存中的值:
// 假设已获取远程进程句柄hProc DWORD64 basePtr = 0x000002586F08CE30; DWORD64 offset = 0x88; DWORD64 targetBase; // 读取远程进程中basePtr地址的64位值 if (ReadProcessMemory(hProc, (LPVOID)basePtr, &targetBase, sizeof(targetBase), NULL)) { DWORD64 targetAddr = targetBase + offset; cout << hex << targetAddr << endl; }
3. 代码中其他64位兼容性修正
GetModuleBaseAddress函数返回值类型从DWORD改为DWORD64,避免64位地址截断:
DWORD64 GetModuleBaseAddress(TCHAR* lpszModuleName, DWORD pID) { DWORD64 dwModuleBaseAddress = 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) { dwModuleBaseAddress = (DWORD64)ModuleEntry32.modBaseAddr; break; } } while (Module32Next(hSnapshot, &ModuleEntry32)); } CloseHandle(hSnapshot); return dwModuleBaseAddress; }
GetPointerAddress函数中的地址变量改为DWORD64类型:
DWORD64 GetPointerAddress(HWND hwnd, DWORD64 gameBaseAddr, DWORD64 address, vector<DWORD64> offsets) { DWORD pID = NULL; GetWindowThreadProcessId(hwnd, &pID); HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID); if (!phandle) return 0; DWORD64 pointeraddress = 0; ReadProcessMemory(phandle, (LPVOID*)(gameBaseAddr + address), &pointeraddress, sizeof(pointeraddress), 0); for (size_t i = 0; i < offsets.size() - 1; i++) { ReadProcessMemory(phandle, (LPVOID*)(pointeraddress + offsets[i]), &pointeraddress, sizeof(pointeraddress), 0); } pointeraddress += offsets.back(); CloseHandle(phandle); return pointeraddress; }
完整修正后的核心代码片段
int main() { HWND hWnd = FindWindowA(0, "Halo Wars: Definitive Edition"); if (hWnd == 0) { cerr << "Could not find window." << endl; return 1; } DWORD PID; GetWindowThreadProcessId(hWnd, &PID); HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, PID); if (!hProc) { cerr << "Cannot open process." << endl; return 1; } // 正确的64位地址偏移计算 DWORD64 basePtr = 0x000002586F08CE30; DWORD64 offset = 0x88; cout << hex << "Base pointer: " << basePtr << endl; cout << hex << "Offset: " << offset << endl; DWORD64 targetBase; if (ReadProcessMemory(hProc, (LPVOID)basePtr, &targetBase, sizeof(targetBase), NULL)) { DWORD64 targetAddr = targetBase + offset; cout << hex << "Target address: " << targetAddr << endl; } else { cerr << "Failed to read process memory." << endl; } CloseHandle(hProc); cin.get(); return 0; }
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

