WINAPI ReadProcessMemory всегда один и тот же адрес

Я прочитал некоторые данные из процесса (адрес: 0x58F03C) с помощью функции WINAPI ReadProcessMemory:

DWORD proc_id;
GetWindowThreadProcessId(hwnd, &proc_id);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proc_id);
int value=0;

while (1)
{
    ReadProcessMemory(hProcess, (LPVOID)0x58F03C, &value, sizeof(value), 0);
    cout << "val: " << value << endl;
}

Так как адрес меняется каждый раз, когда я перезапускаю процесс, я задавался вопросом, есть ли способ всегда получить один и тот же адрес? Должен быть один, потому что я вижу много "программ для тренеров", которые могут это сделать. Как они получают правильное значение адреса для чтения / записи?

В настоящее время я получаю его путем сканирования значения с CheatEngine и выполните следующее сканирование для измененного значения.

Благодарю.

2 ответа

Решение

Вы столкнулись с динамическим выделением памяти. В мире CheatEngine их называют "указателями".

Рассмотрим некоторые данные (например, uint32_t/DWORD) внутри памяти которая была malloc"D. Если вы найдете адрес данных, нет гарантии, что при следующем запуске процесса адрес будет таким же. Это потому, что память возвращается malloc может быть основан в другой точке памяти.

Уловка, используемая для устранения динамического выделения памяти, состоит в том, чтобы найти статический адрес кучи, который может привести вас к адресу интересующего вас значения. В учебнике CheatEngine показано, как это сделать. То же самое относится и к многоуровневым указателям. На более высоком уровне это соответствует динамически распределенной памяти, которая содержит указатель на некоторую другую динамически распределенную память и так далее.

Метод, используемый в CheatEngine для получения указателей, работает примерно так:

  • Установите аппаратную точку останова доступа по адресу интересующего вас значения данных
  • Когда код обращается к нему, аппаратная точка останова покажет вам, как выглядит код

Код будет выглядеть примерно так:

mov eax, 0x1234ABCD 
dec dword ptr ds:[eax+0x85]

Это может соответствовать некоторому коду, который уменьшает ваш HP при ударе врага. В этом случае 0x1234ABCD - указатель, а 0x85 - смещение. В коде C это могло произойти:

struct some_struct* blah = malloc(...);
...
blah->HP--;

0x1234ABCD будет адресом blah, Значение HP живет где-то внутри блока, на который указывает blah, Смещение в блок памяти составляет 0x85. Тогда, если бы вы писали тренер, вы бы прочитали DWORD (QWORD если 64 бит) в 0x1234ABCD и добавьте 0x85 к значению. Это даст вам адрес значения HP.

Это будет работать, если адрес находится в исполняемой части раздела данных, где находятся предварительно выделенные переменные (не подходит для кучи и стека)...

Взгляните на пример "Перечисление всех модулей для процесса" в MSDN.

Он использует EnumProcessModules(), чтобы получить дескрипторы модуля. Это базовые адреса изображений.

Вы можете получить базовый адрес образа для исполняемого файла и настроить его по нему.

Другие вопросы по тегам