WELCOME TO INFOCHEATS.NET

INFOCHEATS is a community-driven platform focused on free game cheats, cheat development, and verified commercial software for a wide range of popular games. We provide a large collection of free cheats shared by the community. All public releases are checked for malicious code to reduce the risk of viruses, malware, or unwanted software before users interact with them.

Alongside free content, INFOCHEATS hosts an active marketplace with many independent sellers offering commercial cheats. Each product is discussed openly, with user feedback, reviews, and real usage experience available to help you make informed decisions before purchasing.

Whether you are looking for free cheats, exploring paid solutions, comparing sellers, or studying how cheats are developed and tested, INFOCHEATS brings everything together in one place — transparently and community-driven.

byte_corvus

Newbie
Newbie

byte_corvus

Newbie
Newbie
Status
Offline
Joined
Mar 3, 2026
Messages
247
Reaction score
7
Решил выкатить небольшой дамп для тех, кто ковыряет The Division 2. Тут классика работы с памятью через ReadProcessMemory и WriteProcessMemory. Если вам нужно было понимание того, как резолвить цепочки указателей в этом движке, этот пример как раз для вас.

Техническая часть:
Данный код считывает базовый адрес модуля и проходит по цепочке офсетов для доступа к нужному значению. В примере реализован цикл, который постоянно перезаписывает значение на "999" (своего рода фикс, чтобы не проседало).

Code:
Reading
#include <windows.h>
#include <iostream>
#include <vector>
#include <TlHelp32.h>
#include <Psapi.h>

// Get process ID by name
DWORD GetProcessIdByName(const wchar_t* processName) {
DWORD processId = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W entry;
entry.dwSize = sizeof(entry);
if (Process32FirstW(snapshot, &entry)) {
do {
if (wcscmp(entry.szExeFile, processName) == 0) {
processId = entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &entry));
}
CloseHandle(snapshot);
}
return processId;
}

// Follow a pointer chain with multiple offsets
uintptr_t ResolvePointerChain(HANDLE hProcess, uintptr_t baseAddr, std::vector<uintptr_t> offsets) {
uintptr_t addr = baseAddr;
for (size_t i = 0; i < offsets.size(); ++i) {
if (!ReadProcessMemory(hProcess, (LPCVOID)addr, &addr, sizeof(addr), nullptr)) {
std::cerr << "Failed to read memory.\n";
return 0;
}
addr += offsets[i];
}
return addr;
}

int main() {
const wchar_t* processName = L"TheDivision2.exe";
DWORD pid = GetProcessIdByName(processName);

if (pid == 0) {
std::cerr << "Process not found.\n";
return 1;
}

HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!hProcess) {
std::cerr << "Failed to open process.\n";
return 1;
}

// Base address from Cheat Engine pointer (you may need to get actual module base)
uintptr_t baseAddress = 0x06DE73D0;

// Get actual module base of the process
HMODULE hMods[1024];
DWORD cbNeeded;
uintptr_t moduleBase = 0;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
moduleBase = (uintptr_t)hMods[0]; // Assuming first module is the main EXE
}

uintptr_t pointerBase = moduleBase + baseAddress;

std::vector<uintptr_t> offsets = { 0x18, 0x48, 0x8, 0x10, 0x240, 0x5C8, 0x148 };

uintptr_t finalAddr = ResolvePointerChain(hProcess, pointerBase, offsets);

int value = 0;
if (ReadProcessMemory(hProcess, (LPCVOID)finalAddr, &value, sizeof(value), nullptr)) {
std::cout << "Final value: " << value << std::endl;
} else {
std::cerr << "Failed to read final value.\n";
}

CloseHandle(hProcess);
return 0;
}

Write 999
#include <windows.h>
#include <iostream>
#include <vector>
#include <TlHelp32.h>
#include <Psapi.h>

DWORD GetProcessIdByName(const wchar_t* processName) {
DWORD processId = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W entry;
entry.dwSize = sizeof(entry);
if (Process32FirstW(snapshot, &entry)) {
do {
if (wcscmp(entry.szExeFile, processName) == 0) {
processId = entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &entry));
}
CloseHandle(snapshot);
}
return processId;
}

uintptr_t ResolvePointerChain(HANDLE hProcess, uintptr_t baseAddr, std::vector<uintptr_t> offsets) {
uintptr_t addr = baseAddr;
for (size_t i = 0; i < offsets.size(); ++i) {
if (!ReadProcessMemory(hProcess, (LPCVOID)addr, &addr, sizeof(addr), nullptr)) {
std::cerr << "Failed to read memory.\n";
return 0;
}
addr += offsets[i];
}
return addr;
}

int main() {
const wchar_t* processName = L"TheDivision2.exe";
DWORD pid = GetProcessIdByName(processName);

if (pid == 0) {
std::cerr << "Process not found.\n";
return 1;
}

HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!hProcess) {
std::cerr << "Failed to open process.\n";
return 1;
}

uintptr_t baseAddress = 0x06DE73D0;

HMODULE hMods[1024];
DWORD cbNeeded;
uintptr_t moduleBase = 0;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
moduleBase = (uintptr_t)hMods[0]; // First module is usually the .exe
}

uintptr_t pointerBase = moduleBase + baseAddress;

std::vector<uintptr_t> offsets = { 0x18, 0x48, 0x8, 0x10, 0x240, 0x5C8, 0x148 };

uintptr_t finalAddr = ResolvePointerChain(hProcess, pointerBase, offsets);

int value = 999;

// Optionally: infinite loop to freeze the value
while (true) {
if (WriteProcessMemory(hProcess, (LPVOID)finalAddr, &value, sizeof(value), nullptr)) {
std::cout << "Value 999 written successfully." << std::endl;
} else {
std::cerr << "Failed to write value." << std::endl;
}

Sleep(100); // Sleep 100ms to avoid CPU overload
}

CloseHandle(hProcess);
return 0;
}

/* cut here */
//Write 999
#include <windows.h>
#include <iostream>
#include <vector>
#include <TlHelp32.h>

DWORD GetProcessIdByName(const wchar_t* processName) {
DWORD processId = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W entry;
entry.dwSize = sizeof(entry);
if (Process32FirstW(snapshot, &entry)) {
do {
if (wcscmp(entry.szExeFile, processName) == 0) {
processId = entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &entry));
}
CloseHandle(snapshot);
}
return processId;
}

uintptr_t ResolvePointerChain(HANDLE hProcess, uintptr_t baseAddr, std::vector<uintptr_t> offsets) {
uintptr_t addr = baseAddr;
for (size_t i = 0; i < offsets.size(); ++i) {
if (!ReadProcessMemory(hProcess, (LPCVOID)addr, &addr, sizeof(addr), nullptr)) {
std::cerr << "Failed to read memory.\n";
return 0;
}
addr += offsets[i];
}
return addr;
}

int main() {
const wchar_t* processName = L"TheDivision2.exe";
DWORD pid = GetProcessIdByName(processName);

if (pid == 0) {
std::cerr << "Process not found.\n";
return 1;
}

HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!hProcess) {
std::cerr << "Failed to open process.\n";
return 1;
}

uintptr_t baseAddress = 0x06DE73D0;

HMODULE hMods[1024];
DWORD cbNeeded;
uintptr_t moduleBase = 0;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
moduleBase = (uintptr_t)hMods[0]; // First module is usually the .exe
}

uintptr_t pointerBase = moduleBase + baseAddress;

std::vector<uintptr_t> offsets = { 0x18, 0x48, 0x8, 0x10, 0x240, 0x5C8, 0x148 };

uintptr_t finalAddr = ResolvePointerChain(hProcess, pointerBase, offsets);

int value = 999;

// Optionally: infinite loop to freeze the value
while (true) {
if (WriteProcessMemory(hProcess, (LPVOID)finalAddr, &value, sizeof(value), nullptr)) {
std::cout << "Value 999 written successfully." << std::endl;
} else {
std::cerr << "Failed to write value." << std::endl;
}

Sleep(100); // Sleep 100ms to avoid CPU overload
}

CloseHandle(hProcess);
return 0;
}

[*] Убедитесь, что запускаете студию от имени администратора, иначе OpenProcess вернет ноль.
[*] Офсеты могут улетать после обновлений игры, мониторьте client_dll или основной экзешник.
[*] Использование бесконечного цикла с Sleep(100) — это самый простой способ держать значение, но не забывайте про риск обнаружения примитивных методов записи.

Кто пробовал это на актуальных версиях? Есть ли сейчас триггеры на WPM в TD2 или игра пока еще «прощает» такие внешние манипуляции с памятью? Делитесь результатами тестов, если кто-то уже пытался внедрять этот код в свой лоадер.
 
Top