"Патчер памяти" или "Пишем флайхак" [Delphi]
Причин к написанию данной темы было три:
1. Меня попросили.
2. Когда-то давно я очень долго искал подобную тему, и не нашел.
3. Флайхаки работают только на фришках.
Итак начнем.
Первым делом опишу какие функции мы будем использовать:
1.
FindWindow (модуль Windows)
function FindWindow(lpClassName, lpWindowName: PChar): HWND; stdcall;
lpClassName - Имя класса окна (для PW - ElementClient Window)
lpWindowName - Текст заголовка окна (для PW - Element Client, для офа ПВ - Perfect World)
С помощью этой функции мы получим дескриптор (handle) окна.
2.
GetWindowThreadProcessId (модуль Windows)
function GetWindowThreadProcessId(hWnd: HWND; lpdwProcessId: Pointer = nil): DWORD; stdcall; overload;
hWnd - дескриптор окна.
lpdwProcessId - указатель на переменную типа Dword, после использования функции в него скопируется идентификатор потока создавшего окно.
От этой функции нам нужен идентификатор потока (PID).
3.
OpenProcess (модуль Windows)
function OpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;
dwDesiredAccess - Устанавливает права доступа к объекту (мы будем получать полные права доступа PROCESS_ALL_ACCESS)
bInheritHandle - Параметр дескриптора наследования.
dwProcessId - идентификатор потока.
С помощью этой функции мы получим права доступа к памяти объекта, и идинтификатор объекта.
После окончания работы с идентификатором объекта необходимо закрыть его функцией CloseHandle.
4.
ReadProcessMemory (модуль Windows)
function ReadProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer;
nSize: DWORD; var lpNumberOfBytesRead: DWORD): BOOL; stdcall;
hProcess - Идентификатор объекта
lpBaseAddress - указатель на адрес из которого будем читать
lpBuffer - указатель на переменную-буфер, в которую будем читать значение из памяти.
nSize - количество байт, которое мы хотим прочитать.
lpNumberOfBytesRead - переменная-буфер, в которой устанавливается значение соответствующее количеству прочитанных байт.
С помощью этой функции мы будем "подбираться" к нужному нам адресу.
5.
WriteProcessMemory (модуль Windows)
function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer;
nSize: DWORD; var lpNumberOfBytesWritten: DWORD): BOOL; stdcall;
hProcess - Идентификатор объекта
lpBaseAddress - указатель на адрес в который будем писать
lpBuffer - указатель на переменную-буфер, значение которой будем записывать в память.
nSize - количество байт, которое мы запишем в память
lpNumberOfBytesRead - переменная-буфер, в которой устанавливается значение соответствующее количеству записанных байт.
Теперь немного о структуре памяти Perfect World.
На жуке и иных порталах много говорят о оффсетах, но не все понимают что же это за зверь.
Оффсет это смещение относительно некоего адреса памяти.

На скриншоте все что выше красной стрелки - отрицательные смещения, все что ниже - положительные.
К примеру у нас есть базовый адрес игры Perfect World - $009C0E6C и есть смещение $1C.
Запись вида [ba]+$1C значит что нужно прочесть значение лежащее по адресу $009C0E6C и прибавить к нему $1C, таким образом мы получим адрес начала блока игровой сессии, который по незнанию называют базовым адресом (более приемлимое (и принятое) название base pointer - базовый указатель) и используют в PWGtm (то есть можно сказать что [ba]+$1C=bp).
Запись вида [ba]+$1C+$20 значи что нам нужно прочесть значение лежащее по базовому адресу, прибавить к нему $1C, и получить базовый указатель, затем прочитать значение лежащее по адресу базового указателя и прибавить к нему $20. Таким образом мы получим указатель на начало структуры данных о персонаже.
$668 - смещение адреса в памяти отвечающего за полет (на самом деле в по этому адресу находится битовая структура с флагами состояния персонажа, но для простоты мы будем работать с целым байтом), относительно начала структуры данных о персонаже. Путь [ba]+$1C+$20+$668 приведет нас к нему.
Итак надеюсь все понятно, начнем кодить

Для начала бросим на форму две кнопки, и назовем их ВКЛ и ВЫКЛ

Переключимся на редактор кода и напишем процедурку:
Код:
procedure FlyHack(state:bool); const base_addr=$009C0E6C; fly_offset=$668; var WndHndl:THandle; buf:byte; ipbuf,PID,hProcess,BytesCount:dword; begin WndHndl:=findwindow('ElementClient Window',nil); GetWindowThreadProcessId(WndHndl, @PID); hProcess:=OpenProcess(PROCESS_ALL_ACCESS, False, PID); if hProcess <> 0 then // Проверяем получен ли идентификатор объекта try ReadProcessMemory(hProcess, ptr(base_addr), @ipbuf, sizeof(ipbuf), BytesCount); ReadProcessMemory(hProcess, ptr(ipbuf+$1C), @ipbuf, sizeof(ipbuf), BytesCount); ReadProcessMemory(hProcess, ptr(ipbuf+$20), @ipbuf, sizeof(ipbuf), BytesCount); ReadProcessMemory(hProcess, ptr(ipbuf+fly_offset), @buf, sizeof(buf), BytesCount); if (buf<>$0) and (buf<>$10) then messagebox(0,'Неверная версия клиента','Пишем флайхак',16) else begin if state=true then // Если нажали "ВКЛ" begin buf:=$10; writeprocessmemory(hProcess,ptr(ipbuf+fly_offset),@buf,1,BytesCount); messagebox(0,'Клиент пропатчен','Пишем флайхак,64); end; if state=false then // Если нажали "ВЫКЛ" begin buf:=$0; writeprocessmemory(hProcess,ptr(ipbuf+fly_offset),@buf,1,BytesCount); messagebox(0,'Клиент пропатчен','Пишем флайхак',64); end; end; finally closehandle(hProcess); end; end;
Теперь в обработчики событий OnClick наших кнопок запишем:
для "ВКЛ" - FlyHack(true);
для "Выкл" - FlyHack(false);
Вуаля, флайхак готов.
В аттаче исходник проекта.
Вложения

флайхак.rar (2.1 Кб, 676 просмотров)