24K Опубликовано 19 февраля, 2012 Поделиться Опубликовано 19 февраля, 2012 В этом учебнике я собираюсь обрисовать основной API, необходимый для создания трейнера в Дельфи. Основы знания Дельфи предпочтительны, но Дельфи итак довольно прост в освоении.Концепция.Хорошо, вот что мы хотим от трейнера. Мы запускаем игру. После этого ALT+TAB в Windows. Мы запускаем трейнер, и жмем кнопку. Это действие запишет некие значения в некоторые адреса в игре. Так, например, если мы знаем адрес денег в памяти игры, мы сможем хакать деньги, используя этот трейнер.Вот что нам надо для этого:Название окна игрыЗапускаем игру, потом переходим в Windows по Alt+Tab. Ищем в панели задач нашу игру и записываем е_ точный заголовок. (К примеру, запустив Red Alert 2, в панели задач Вы увидите кнопку с ее названием - Red Alert 2. Это и есть заголовок главного окна программы. Кстати, Red Alert 2 взломать способом, описанным здесь, не удастся - это DMA игра. Читайте пару документов здесь, посвященных именно A.G.T. и борьбе с DMA)Адреса в памяти игры (в шестнадцатеричном виде)Используем программу, подобную GameHack или MTC (Magic Trainer Creator), мы можем найти любое значение в игре и соответствующий ему адрес в памяти. К примеру, адрес в шестнадцатеричном виде 41D090. Запишем и это тоже.Значение, которое мы хотим записать (в шестнадцатеричном виде):Так, у нас есть адрес в памяти. Что мы хотим в него записать? Скажем, я хочу 50 единиц золота. То есть первым делом мне надо перевести 50 в шестнадцатеричную форму, используя соответствующий конвертер (подойдет и Калькулятор из Стандартных программ Windows - не забудьте включить инженерное представление - прим.пер.) Конвертер скажет 32. Так что запишите и это значение также.Число байт, которое мы хотим писатьВ том значении, которое мы получили выше, мы должны знать также сколько байт это займет в памяти. К примеру, число 32 займет только 1 байт, но FF07 займет уже два байта. В общем случае, две цифры будут занимать один байт.Начнем кодитьМы собираемся использовать Win32 API чтобы записывать значения в память другого процесса. Вот те функции, которые мы будем использовать. По порядку:FindWindowGetWindowThreadProcessIDOpenProcessReadProcessMemoryWriteProcessMemoryCloseHandle(Прочтите описания этих функций в файле Win32.hlp (или MSDN - прим.пер.) для полного описания. )Я буду показывать только основы, так что начинающие могут просто копировать код из этого документа и вставлять его в свой проект.)Итак, начало. Во-первых, мы объявляем наши переменные. Скопируйте и вставьте это в свой проект:Var WindowName : integer;ProcessId : integer;ThreadId : integer;buf : PChar;HandleWindow : Integer;written : cardinal;Теперь надо объявить следующие константы. Скопируйте и этот раздел. Эти константы устанавливаются в соответствии с тем, что вы записали выше.Const WindowTitle = 'prog test';Address = $41D090;PokeValue = $32;NumberOfBytes = 1;Теперь, чтобы записать значения, вы должны получить хэндл памяти игры. Невозможно сделать это в одно действие, поэтому мы сделаем следующее.Получаем хэндл главного окнаС этим хендлом мы получаем идентификатор процесса (process identifier - pID)С этим pID, мы получаем хэндл области памяти.С этим хэндлом мы можем начинать хакать.Во-первых, нам надо получить хэндл главного окна. Используем функцию FindWindowWindowName := FindWindow(nil,WindowTitle);If WindowName = 0 thenbeginMessageDlg('Игра должна быть запущена до трейнера.Запустите ее, потом трейнер', mtwarning,[mbOK],0);end;Заметим, что код проверяет, равен ли нулю хэндл этого окна. Если оно равно, это значит, что игра не запущена, так что мы предупреждаем пользователя и говорим ему о том, чтобы он запустил игру.Теперь нам нужен pID. Мы используем функцию GetWindowThreadProcessId. После этого мы получаем хэндл области памяти через OpenProcess. Скопируйте код, приведенный ниже.ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);Вот оно. Теперь нам надо использовать WriteProcessMemory чтобы писать что-то внутри этого хэндла. Как только мы это сделаем, мы закрываем хэндл. Так принято. Так безопасно. Скопируйте код, приведенный ниже:GetMem(buf,1);buf^ := Chr(PokeValue);WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write);FreeMem(buf);CloseHandle(HandleWindow);Вот исходный код для всего трейнера. Для начинающих программистов, чтобы быстро сделать трейнер, требуется только поменять константы, объявленные в начале программы.Var WindowName : integer;ProcessId : integer;ThreadId : integer;buf : PChar;HandleWindow : Integer;write : cardinal;Const WindowTitle = 'prog test';Address = $41D090;PokeValue = $32;NumberOfBytes = 1;############################################################ (Вставьте следующий код в обработчик OnClick кнопки )############################################################beginWindowName := FindWindow(nil,WindowTitle);If WindowName = 0 thenbeginMessageDlg('Игра должна быть запущена до трейнера.Запустите ее, потом трейнер', mtwarning,[mbOK],0);end;ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);GetMem(buf,1);buf^ := Chr(PokeValue);WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write);FreeMem(buf);CloseHandle(HandleWindow);end; 3 Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 19 февраля, 2012 Поделиться Опубликовано 19 февраля, 2012 Я уже не раз и не в одной теме на нашем форуме писал, что указанных функций мало для создания трейнера к современым играм. Необходимо обязательно упомянуть о функции VirtualProtectEx, позволяющей менять защиту взламываемой памяти процесса. Ссылка на комментарий Поделиться на другие сайты Поделиться
Synapsehome Опубликовано 22 февраля, 2012 Поделиться Опубликовано 22 февраля, 2012 Вот оно. трейнер моей мечты ps. какое же это извращение писать на дельфи ^^) я как после ФГС стал считать за богов девушек, так и после того как мне два последние года учебы парили в школе паскаль я стал считать за богов тех у кого хватает терпения прописывать эти var, begin и прочую муть, поэтому в 11 классе я был максимум на двух уроках информатики. Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 25 февраля, 2012 Поделиться Опубликовано 25 февраля, 2012 Чисто понять основы + попрактиковаться на сапёре\косынке - вполне. Не хватает ещё архива с собранным трейнером и его прокомментированными исходниками. 1 Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 9 марта, 2012 Поделиться Опубликовано 9 марта, 2012 Как можно сделать программу, чтобы, к примеру, в Label показывалось мое кол-во жизней в игре?PS: Адрес есть... Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 9 марта, 2012 Поделиться Опубликовано 9 марта, 2012 Таймер - ReadProcessMemory - Конвертация в нужный формат - Вывод на Label, например. Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 9 марта, 2012 Поделиться Опубликовано 9 марта, 2012 Разобрался, спс. А как можно в текст вывести?ReadProcessMemory(HandleWindow, ptr($01162420), @bb, 4, wread);На что это поменять надо? Ссылка на комментарий Поделиться на другие сайты Поделиться
Xipho Опубликовано 11 марта, 2012 Поделиться Опубликовано 11 марта, 2012 Ни на что. Надо полученное значение в буфере сконвертировать в текст. Функции из SysUtils помогут (судя по коду, ты используешь Дельфи), или же их заменители - тут вопрос к гуглу. Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 11 марта, 2012 Поделиться Опубликовано 11 марта, 2012 Еще вопрос Почему на некоторых ОС не работает трейнер? Т.е. адреса все совпадают, но на нажатие кнопки никак не реагирует? Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 11 марта, 2012 Поделиться Опубликовано 11 марта, 2012 Еще вопрос Почему на некоторых ОС не работает трейнер? Т.е. адреса все совпадают, но на нажатие кнопки никак не реагирует?Тут что угодно может быть - нужно отлаживать. Отдельные компоненты могут не работать в разных осях, но WinAPI у нас на все винды в принципе одинаковые. Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Еще вопрос Почему на некоторых ОС не работает трейнер? Т.е. адреса все совпадают, но на нажатие кнопки никак не реагирует?Нужно больше конкретизировать. Мы же не телепаты.Какой трейнер и для какой игры? Есть ли исходный код? Какие операционные системы? Как было определено, что адреса совпадают, когда нажатия кнопок не срабатывают? Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 varWindowName: integer;ProcessId: integer;ThreadId: integer;HandleWindow: Integer;write: cardinal;buf: dword;constWindowTitle = 'Name'; Address = $007B5678;NumberOfBytes = 4;beginWindowName := FindWindow(nil,WindowTitle);If WindowName = 0 then beginMessageDlg('Игра должна быть запущена до трейнера. Запустите ее, потом трейнер', mtwarning,[mbOK],0);end;ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);buf:=$0;WriteProcessMemory(HandleWindow, ptr(address), @buf, 4, write);end;Можно и в таком варианте:varWinClass : TWndClass;hInst: HWND;Handle: HWND;Msg: TMSG;hFont: HWND;win: hwnd;WindowName: integer;ProcessId: integer;ThreadId: integer;buf: PChar;HandleWindow: Integer;write: cardinal; constWindowTitle= 'Name';Address= $007B5678;PokeValue= $0;NumberOfBytes= 4;begin WindowName := FindWindow(nil,WindowTitle); If WindowName = 0 then begin MessageBox(win,'Игра должна быть запущенна до трейнера.'+#13+#10+ ' Запустите её,а потом трейнер','Ошибка',MB_OK or MB_ICONINFORMATION); end; ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId); HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId); GetMem(buf,1); buf^ := Chr(PokeValue); WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write); FreeMem(buf); CloseHandle(HandleWindow);end;У большинства людей работает. Не работает на: Win 7 x32 Максимальная, Win 7 x64 UltimateРаботает на: Win XP SP2 x32, Win XP SP3 x32, Win 7 x64 Домашняя, Win 7 x64 Максимальная...Адреса были проверены через CheatEngine, соответственно на компьютере где не работает. Ссылка на комментарий Поделиться на другие сайты Поделиться
MasterGH Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 А как именно не работает? Как ошибка вылазит, если вылазит?1) Если вылазит сообщение "Игра должна быть запущенна до трейнера", то может быть в названии окна есть какие-то проблемы с русскими символами, если они там есть. 2) Сделай аналогичные сообщения для проверки ProcessId, Handlewindow.Проверь WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write) на исключение. Если исключение возникает выведи мессагу. Возможно у адреса защита от записи. Или блокировка Антивирусом.3) Потом мне не нравится GetMem c переменной buf, т.е. вот эти манипуляции. GetMem(buf,1); buf^ := Chr(PokeValue);//...FreeMem(buf);Проверь существует ли действительно адрес buf4) Я точно не помню, но кто знает, может WriteProcessMemory не успевает выполнится по каким-то причинам и тут же идёт сразу FreeMem(buf) и CloseHandle(HandleWindow);5) Может быть нужно какие-то параметры компиляции поставить. 6) Может быть требуется присутствие каких то dll-ок. См. пункт 5Короче поставь мессаги на каждой функцией. И обверни блок кода от begin до end в обработку исключения с выводом мессаги о об этом исключении. Можно также извлечь информацию об этом исключении используя WinAPI. К сожалению я не буду заниматься тестированиями. Подсказал чем смог. Ещё предлагаю поискать примеры на дельфи без GetMem -> FreeMem... Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Я написал 2 примера кода, ни 1 из них на указанных ОС не работают.п. 1 не подходит, не понял пункты 3, 5 и 6 а п.4 не думаю что не успевает, если только на некоторых ОС не работает, антивируса нету. Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Я написал 2 примера кода, ни 1 из них на указанных ОС не работают.п. 1 не подходит, не понял пункты 3, 5 и 6 а п.4 не думаю что не успевает, если только на некоторых ОС не работает, антивируса нету.Просто поставь такую же проверку, как в функции FindWindow (через MessageBox), после вызова всех функций. Где ошибку выдаст - там её и искать. Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 WindowName := FindWindow(nil,WindowTitle); If WindowName = 0 then begin MessageBox(win,'Игра должна быть запущенна до трейнера.'+#13+#10+ ' Запустите её,а потом трейнер','Ошибка',MB_OK or MB_ICONINFORMATION); end; ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId); If ThreadID := 0 then begin ShowMessage('ThreadID.');end; HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);if HandleWindow = 0then beginShow Message('HandleWindow');end;Как я понял эту часть надо сделать так, а дальше как сделать? Можно код плиз? GetMem(buf,1); buf^ := Chr(PokeValue); WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write); FreeMem(buf); Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Что-то типа:varWinClass : TWndClass;hInst: HWND;Handle: HWND;Msg: TMSG;hFont: HWND;win: hwnd;WindowName: integer;ProcessId: integer;ThreadId: integer;buf: PChar;HandleWindow: Integer;write: cardinal; constWindowTitle= 'Name';Address= $007B5678;PokeValue= $0;NumberOfBytes= 4;begin WindowName := FindWindow(nil,WindowTitle); If WindowName = 0 then begin MessageBox(win,'Игра должна быть запущенна до трейнера.'+#13+#10+ ' Запустите её,а потом трейнер','Ошибка',MB_OK or MB_ICONINFORMATION); end; ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId); If ThreadId = 0 then begin MessageBox(win,'Error!'+#13+#10+ 'Couldn't get thread id.','Ошибка',MB_OK or MB_ICONINFORMATION); end HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId); If HandleWindow = 0 then begin MessageBox(win,'Error!'+#13+#10+ 'Couldn't get window handle.','Ошибка',MB_OK or MB_ICONINFORMATION); end GetMem(buf,1); buf^ := Chr(PokeValue); If buf = 0 then begin MessageBox(win,'Error!'+#13+#10+ 'Buffer is empty.','Ошибка',MB_OK or MB_ICONINFORMATION); end WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write); FreeMem(buf); CloseHandle(HandleWindow);end;Вообще, не пробовал под отладчиком пошагово пройти всю программу? Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Заодно можешь выложить скомпилированный файл. Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 GetMem(buf,1); buf^ := Chr(PokeValue);If buf = 0 thenbeginMessageBox(win,'Error!'+#13+#10+'Buffer is empty.','Ошибка',MB_OK or MB_ICONINFORMATION);end;На выделенную строчку ругается... Operator not applicable to this operand type Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Я не совсем понимаю, что делают эти строчки:GetMem(buf,1);buf^ := Chr(PokeValue);GetMem выделяет 1 байт памяти и кладёт указатель на начало этой памяти в buf. После этого в buf кладётся сконвертированный при помощи Chr нолик. Затем всё это добро записывается по адресу 007B5678. Я правильно понимаю, да? Если да - зачем такие махинации с выделением одного байта и т.п.? Не проще сразу ноль записать? Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Ещё можно [вот такой] вариант попробовать. 4-й пост сверху. Первая процедура ищет хэндл нужного процесса, вторая - пишет указанные данные по указанному адресу. В конце поста показано, как это дело вызывать. Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Я просто код копировал с 1 поста этой темы, не заметил 1 в GetMem(buf,1);Если я правильно понимаю надо 1 поменять на 4 ? или вообще убрать эту часть кода? Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Попробуй вместо:GetMem(buf,1);buf^ := Chr(PokeValue);WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write);FreeMem(buf);Написать сразу:WriteProcessMemory(HandleWindow,ptr(Address),$00,1,write); Ссылка на комментарий Поделиться на другие сайты Поделиться
FarmHitman Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Так вообще даже у меня не работает Ссылка на комментарий Поделиться на другие сайты Поделиться
keng Опубликовано 12 марта, 2012 Поделиться Опубликовано 12 марта, 2012 Значит твой код верен, но отлаживать его всё равно нужно. На всех ОСях трейнер запускался с админскими правами? У меня просто под рукой компилятора нет, да и дельфи я последний раз видел лет 10 назад. Ссылка на комментарий Поделиться на другие сайты Поделиться
Рекомендуемые сообщения