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(), чтобы получить дескрипторы модуля. Это базовые адреса изображений.
Вы можете получить базовый адрес образа для исполняемого файла и настроить его по нему.