20111229

Уроки и трейнеры.

Скоро допишу уроки по нормальному созданию rapidfire-hack'а (быстрая стрельба), может немножко в Direct3D залезу.

Трейнер, который я с вами курочу, в принципе, уже достаточно работоспособен для благополучного использования. Что ещё к нему прикрутим? Предложения - в комменты. :)

20111228

Нашёл ещё одну неплохую [доку] по изучению Ассемблера. На русском, да. :)

Апдейт: А [вот тут] лежит куча-куча всяких примеров кода.

20111227

Работа с указателями, или дописываем наш трейнер.

Ещё один небольшой, но ответственный и важный шажок в создании трейнера - работа с указателями. В [видео] кратко пересказана суть этого явления, а так же живой пример вместе с пошаговой отладкой в OllyDbg. Смотрим, задаём вопросы. Извините, что сбиваюсь - хотелось спать. :)

Полный исходный код трейнера (жирным синим шрифтом - новое) из этого урока на Flat Assembler:



format PE GUI 4.0
entry start
include 'c:\fasm\include\win32a.inc'
section '.data' data readable writable
error_message   db 'Error! :(',0
caption         db 'Fasm Trainer',0
pid             dd 0
 ;Необходимо для вызова процедуры чтения указателя через invoke
Poke            dd _Poke 
ReadPointer     dd _ReadPointer
windowcap       db 'Minesweeper',0
addr            dd 0x004256BF
godmode_on      db 0x90,0x90,0x90,0x90,0x90,0x90
godmode_off     db 0xD9,0x9F,0xC4,0xE5,0x48,0x00 
;Новые переменные  
 ;Базовый адрес указателя 
pointer_base    dd 0xFFD9AA38  
buffer          dd ? ;Буфер для чтения байт из памяти 
phandle         dd ? ;Переменная для хранения хэндла процесса


section '.text' code readable executable
start:
        invoke  GetModuleHandle,0
        invoke  DialogBoxParam,eax,37,HWND_DESKTOP,DialogProc,0
        invoke  ExitProcess,0
proc DialogProc hwnddlg,msg,wparam,lparam
     cmp        [msg],WM_CLOSE
     je         .wmclose
     cmp        [msg],WM_COMMAND
     je         .wmcommand
     cmp        [msg],WM_LBUTTONDOWN
     je         .move
     cmp        [msg],WM_INITDIALOG
     je         .init
     cmp        [msg],WM_TIMER
     je         .timer
     xor        eax,eax
     jmp        .finish
  .wmcommand:
     cmp        [wparam],BN_CLICKED shl 16 + 1
     je         .poke
     cmp        [wparam],BN_CLICKED shl 16 + 2
     je         .wmclose
  .poke:
     invoke     Poke,[addr],godmode_on,6
     jmp        .finish
  .wmclose:
     ;invoke     Poke,[addr],godmode_off,6
     invoke     EndDialog,[hwnddlg],0
  .move:
     invoke     SendMessage,[hwnddlg],WM_NCLBUTTONDOWN,2,0
     ret
  .init:
     invoke     SetTimer,[hwnddlg],0,100,0
     ret
  .timer:
     invoke     GetAsyncKeyState,VK_F11
     cmp        eax,0
     je         .finish
     invoke     ReadPointer,[pointer_base] ;Читаем указатель  
.finish:
     ret
endp
proc _Poke,memadd,memval,bytes
     invoke     FindWindow, 0, windowcap
     cmp        eax,0
     je         .error
     invoke     GetWindowThreadProcessId,eax,pid
     cmp        [pid],0
     je         .error
     invoke     OpenProcess,PROCESS_ALL_ACCESS,0,[pid]
     cmp        eax,0
     je         .error
     invoke     WriteProcessMemory,eax,[memadd],[memval],[bytes],0
     cmp        eax,0
     je         .error
     ret
.error:
     invoke     MessageBox,HWND_DESKTOP,error_message,caption,MB_OK
     ret
endp
proc _ReadPointer,address ;Процедура чтения указателя      
invoke     FindWindow,0,windowcap      
cmp        eax,0      
je         .error      
invoke     GetWindowThreadProcessId,eax,pid      
cmp        [pid],0      
je         .error      
invoke     OpenProcess,PROCESS_ALL_ACCESS,0,[pid]      
;Сохраняем хэндл процесса после его открытия     
cmp        eax,0     mov        [phandle],eax 
je         .error          
;Читаем содержимое базового адреса указателя в буфер
invoke     ReadProcessMemory,[phandle],[address],buffer,4,0       
cmp        eax,0      
je         .error     
 ;Прибавляем к содержимому буфера первое смещение
add        [buffer],0x18       
;Читаем полученный адрес
invoke     ReadProcessMemory,[phandle],[buffer],buffer,4,0  
 cmp        eax,0      
je         .error     
 ;Прибавляем второе смещение     
add        [buffer],0x20 
;Читаем полученный адрес
invoke     ReadProcessMemory,[phandle],[buffer],buffer,4,0       
cmp        eax,0      
je         .error           
ret 
.error:      
invoke     MessageBox,HWND_DESKTOP,error_message,caption,MB_OK      
ret  
endp
section '.idata' import data readable writeable
  library kernel,'kernel32.DLL',\
          user,'user32.DLL'
  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess',\
         OpenProcess,'OpenProcess',\
         WriteProcessMemory,'WriteProcessMemory',\
;Объявляем новую функцию для работы с ней
         ReadProcessMemory,'ReadProcessMemory'

  import user,\
         DialogBoxParam,'DialogBoxParamA',\
         EndDialog,'EndDialog',\
         MessageBox,'MessageBoxA',\
         FindWindow,'FindWindowA',\
         GetWindowThreadProcessId,'GetWindowThreadProcessId',\
         SendMessage,'SendMessageA',\
         SetTimer,'SetTimer',\
         GetAsyncKeyState,'GetAsyncKeyState'
section '.rsrc' resource data readable
  directory RT_DIALOG,dialogs
  resource dialogs,37,LANG_ENGLISH+SUBLANG_DEFAULT,demonstration
  dialog demonstration,'Crimsonland +1 trainer by keng',70,70,190,175,WS_POPUP
         dialogitem 'STATIC','Press OK for toggle godmone on. Visit me at: www.gamehacklab.ru',-1,0,0,163,188,SS_LEFT + WS_VISIBLE+  SS_CENTER
         dialogitem 'BUTTON','OK',1,85,150,45,15,WS_VISIBLE
         dialogitem 'BUTTON','Cancel',2,135,150,45,15,WS_VISIBLE
  enddialog

PS: Как вы уже могли догадаться, квадратные скобки означают содержимое переменной, а их отсутствие - адрес этой переменной. :)

20111226

Наш трейнер.

В следующем видеоуроке мы с вами узнаем, как работать с указателями. Если кто не помнит, то это такой адрес, который на матрёшку похож - [базовый адрес + смещение1 + смещение2 + смещение3] и так далее. :)

У меня тут вопрос один к вам возник: Может, стоит добавить в уроки музыку? Я обычно слушаю online-радио жанра trance - помогает сосредоточиться. Могу один урок записать с фоновой музыкой - если не будет особо мешать просмотру - так и оставлю. Мнения - в комментарии к записи.

20111225

Ломаем игры по заявкам читателей.

На этот раз ломаем закись азота (N2O) в игре Need For Speed: Carbon. Попутно узнаём ещё одну новую инструкцию по работе с дробными (float) числами. :)

[Ссылка] на урок.

FASM - добавляем горячие клавиши.

Записал очередной видеоурок, в котором вкратце рассказано о работе с горячими клавишами. Тыкнули кнопку, находясь в игре, - сработал трейнер. Удоообно! :)

Для реализации используем две новых WinAPI-функции - [SetTimer] и [GetAsyncKeyState].

Подробности - в [видео].

20111223

Уроки.

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

PS: А может быть, ещё и один новый инструмент освоим. ;)

Удобный редактор кода.

Для удобного чтения (и быстрого редактирования) исходного кода на всяких разных языках (в том числе и на ассемблере) рекомендую пользоваться [вот этим] текстовым редактором. Весит мало, бесплатен, удобен. :)

20111222

Поболтушечки.

Как вам блог-то, в целом? Интересно? Понятно более-менее? Я адекватен?

Я могу, конечно, его и просто так вести (структуризация и запись приобретённых знаний и умений - это круто!), но мне будет сильно приятнее знать, что стараюсь я не только для себя. :)

Вы пишите, периодически, всё ли у вас получается. Я ж готов помогать, ну! :D

Немного улучшаем внешний вид трейнера.

Помните процедуру диалогового окна нашего трейнера? Приведу её исходный код ещё раз, вот:


proc DialogProc hwnddlg,msg,wparam,lparam
     cmp     [msg],WM_CLOSE
     je      .wmclose
     cmp     [msg],WM_COMMAND
     je      .wmcommand
     xor     eax,eax
     jmp     .finish
  .wmcommand:
     cmp     [wparam],BN_CLICKED shl 16 + 1
     je      .poke
     cmp     [wparam],BN_CLICKED shl 16 + 2
     je      .wmclose
  .poke:
     invoke  Poke,[addr],godmode_on,6
     jmp    .finish
  .wmclose:
     invoke  Poke,[addr],godmode_off,6
     invoke  EndDialog,[hwnddlg],0
  .finish:
     ret
endp
Давайте сделаем так, чтобы можно было окошко нашего трейнера таскать мышкой не только за синий заголовок, но и за любую часть окна. Добавляем несколько строчек:

 proc DialogProc hwnddlg,msg,wparam,lparam
     cmp     [msg],WM_CLOSE
     je      .wmclose
     cmp     [msg],WM_COMMAND
     je      .wmcommand
     cmp     [msg],WM_LBUTTONDOWN ;Если сообщение - клик левой кнопкой мыши
     je      .move ;Пытаемся его обработать
     xor     eax,eax
     jmp     .finish
  .wmcommand:
     cmp     [wparam],BN_CLICKED shl 16 + 1
     je      .poke
     cmp     [wparam],BN_CLICKED shl 16 + 2
     je      .wmclose
  .poke:
     invoke  Poke,[addr],godmode_on,6
     jmp    .finish
  .wmclose:
     invoke  Poke,[addr],godmode_off,6
     invoke  EndDialog,[hwnddlg],0
  .move: ;Метка обработчика сообщения об ЛКМ
     invoke SendMessage,[hwnddlg],WM_NCLBUTTONDOWN,2,0 ;Какая-то хитрая функция
  .finish:
     ret
endp
Синим цветом - добавленный код, зелёным - комментарии. Итак, происходит следующее. Как только мы кликаем по нашему окну левой кнопкой мыши (ЛКМ) - в процедуру обработки окна приходит сообщение - "Аааа! Нажали ЛКМ!! Что делать?!!". Вот теперь наша процедура как раз знает, что делать. :)
Функцией SendMessage мы обманываем глупую виндовс и говорим ей, что мы якобы не просто нажали ЛКМ, а нажали её на заголовке, о чём нам говорит цифра "2" в аргументах этой функции. По сути, функция эта умеет слать сообщения вручную - как если бы они к нам приходили извне. В аргументах функция требует указать, кому слать сообщение (указываем hwnddlg - хэндл нашего диалогового окна), само сообщение (WM_NCLBUTTONDOWN - нажатие ЛКМ. На самом деле - не совсем ЛКМ, а ЛКМ вне пределов клиентской области окна, но нам этого пока знать не обязательно) и место, какой части окна шлём, в аргументах. У нас этим аргументом является цифра "2", она обозначает заголовок окна.

Итак, как это выглядит? Мы зажали левую кнопку в окне, двигаем мышью - а окно двигается вместе с ней, как если бы мы таскали его за заголовок. Здорово? Здорово!

Но если вы смотрели предыдущие статьи и урок, то уже смело возражаете мне - "Как же так? Новая WinAPI-функция, а в секции импорта мы её не описали! Использовать не сможем! Безобразие!". Да, всё верно. Вот наша старая секция импорта:


section '.idata' import data readable writeable
  library kernel,'kernel32.DLL',\
 user,'user32.DLL'
  import kernel,\
GetModuleHandle,'GetModuleHandleA',\
ExitProcess,'ExitProcess',\
OpenProcess,'OpenProcess',\
WriteProcessMemory,'WriteProcessMemory'
  import user,\
DialogBoxParam,'DialogBoxParamA',\
EndDialog,'EndDialog',\
MessageBox,'MessageBoxA',\
FindWindow,'FindWindowA',\
GetWindowThreadProcessId,'GetWindowThreadProcessId'

А вот - новая:


section '.idata' import data readable writeable
  library kernel,'kernel32.DLL',\
          user,'user32.DLL'
  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess',\
         OpenProcess,'OpenProcess',\
         WriteProcessMemory,'WriteProcessMemory'
  import user,\
         DialogBoxParam,'DialogBoxParamA',\
         EndDialog,'EndDialog',\
         MessageBox,'MessageBoxA',\
         FindWindow,'FindWindowA',\
         GetWindowThreadProcessId,'GetWindowThreadProcessId',\
         SendMessage,'SendMessageA'
Синим цветом добавлена новая функция. кстати, запятая и косая черта обозначает перенос строки - по функции на строку читается удобнее, мне кажется. :)

Не забудьте в имени функции поставить букву А - SendMessageA. Дело в том (опять я в подробности полез), что существует две версии этой (и других) функций - с буквой A и с буквой W. Обозначают эти буквы разные кодировки - ANSI и Unicode. Что это такое - выясняйте сами, т.к. это уже выходит за рамки тематики моего блога. Или просто не заморачивайтесь и используйте версии с А. :)


Ну и, в завершение, избавим наше диалоговое окно от заголовка, который теперь нам стал катастрофически не нужен. Идём в секцию ресурсов и меняем описание диалога вот на такое:

dialog demonstration,'Crimsonland +1 trainer by keng',70,70,190,175,WS_POPUP
Как видите, мы просто убрали часть флагов из последнего аргумента, который отвечает за внешний вид нашего окна.

Полный исходный код (синим цветом - изменения):


format PE GUI 4.0
entry start
include 'c:\fasm\include\win32a.inc'
section '.data' data readable writable
error_message db 'Error! :(',0
caption db 'Fasm Trainer',0
pid dd 0
Poke dd _Poke
windowcap db 'Crimsonland',0
addr dd 0x004256BF
godmode_on db 0x90,0x90,0x90,0x90,0x90,0x90
godmode_off db 0xD9,0x9F,0xC4,0xE5,0x48,0x00

section '.text' code readable executable
start:
        invoke  GetModuleHandle,0
        invoke  DialogBoxParam,eax,37,HWND_DESKTOP,DialogProc,0
        invoke  ExitProcess,0
proc DialogProc hwnddlg,msg,wparam,lparam
     cmp     [msg],WM_CLOSE
     je      .wmclose
     cmp     [msg],WM_COMMAND
     je      .wmcommand
     cmp     [msg],WM_LBUTTONDOWN
     je      .move

     xor     eax,eax
     jmp     .finish
  .wmcommand:
     cmp     [wparam],BN_CLICKED shl 16 + 1
     je      .poke
     cmp     [wparam],BN_CLICKED shl 16 + 2
     je      .wmclose
  .poke:
     invoke  Poke,[addr],godmode_on,6
     jmp    .finish
  .wmclose:
     invoke  Poke,[addr],godmode_off,6
     invoke  EndDialog,[hwnddlg],0
  .move:
     invoke SendMessage,[hwnddlg],WM_NCLBUTTONDOWN,2,0

  .finish:
     ret
endp
proc _Poke,memadd,memval,bytes
     invoke     FindWindow, 0, windowcap
     cmp        eax,0
     je         .error
     invoke     GetWindowThreadProcessId,eax,pid
     cmp        [pid],0
     je         .error
     invoke     OpenProcess,PROCESS_ALL_ACCESS,0,[pid]
     cmp        eax,0
     je         .error
     invoke     WriteProcessMemory,eax,[memadd],[memval],[bytes],0
     cmp        eax,0
     je         .error
     ret
.error:
     invoke     MessageBox,HWND_DESKTOP,error_message,caption,MB_OK
     ret
endp
section '.idata' import data readable writeable
  library kernel,'kernel32.DLL',\
          user,'user32.DLL'
  import kernel,\
         GetModuleHandle,'GetModuleHandleA',\
         ExitProcess,'ExitProcess',\
         OpenProcess,'OpenProcess',\
         WriteProcessMemory,'WriteProcessMemory'
  import user,\
         DialogBoxParam,'DialogBoxParamA',\
         EndDialog,'EndDialog',\
         MessageBox,'MessageBoxA',\
         FindWindow,'FindWindowA',\
         GetWindowThreadProcessId,'GetWindowThreadProcessId',\
         SendMessage,'SendMessageA'
section '.rsrc' resource data readable
  directory RT_DIALOG,dialogs
  resource dialogs,37,LANG_ENGLISH+SUBLANG_DEFAULT,demonstration
  dialog demonstration,'Crimsonland +1 trainer by keng',70,70,190,175,WS_POPUP
         dialogitem 'STATIC','Press OK for toggle godmone on. Visit me at: www.gamehacklab.ru',-1,0,0,163,188,SS_LEFT + WS_VISIBLE+  SS_CENTER
         dialogitem 'BUTTON','OK',1,85,150,45,15,WS_VISIBLE
         dialogitem 'BUTTON','Cancel',2,135,150,45,15,WS_VISIBLE
  enddialog
Трейнер наш после этих телодвижений будет выглядеть вот так:






Третья часть про трейнеры!

На этот раз - видео. Вот [ссылка].
Заодно выкладываю [архив] с исходным кодом и скомпилированным трейнером.

Нагуглите и прочитайте обо всём, что не стало понятным из урока (в частности - про новые WinAPI-функции), спросите об оставшеимся тут, в комментариях на youtube или на [форуме], медитируйте, делайте зарядку и чистите зубы 2 раза в день. :)

Согласен, урок получился довольно скомканным - но у меня очень мало времени, простите. Работа, да и праздники, как-никак.

PS: Очень полезно будет загрузить скомпилированный трейнер в Olly (File -> Open) и посмотреть на его работу пошагово. Многое запросто может встать на свои места. Попробуйте, не бойтесь экспериментировать! Это же так весело и интересно. :)

20111221

Трейнеры, снова.

Я опять слегка загружен на работе, так что сегодня вечером постараюсь выложить следующее видео, а пока что ещё немного поканифолю вам, дорогие мои читатели, ваши светлые головы. Собственно, о чём сказать-то хочется? "Hello, world!", минимальную программу, умеющую говорить "Привет!" и радостно закрываться, мы более-менее написали и проанализировали. Скажу по секрету - для трейнера нам придётся написать нечто посолиднее. Давайте вспомним алгоритм работы простейшего трейнера, о котором я упомянул в [предыдущей] статье. Вот он:

1. Запуститься, показать своё окно
2. Ждать нажатия на кнопку от пользователя
3. Если пользователь всё-таки это сделал - включить (или выключить) какую-то из опций-читов
4. Корректно завершить работу после закрытия


Теперь неспеша (заварив себе ещё чашечку чая, да взяв тех французских булок™) разберём его, начиная с первого пункта. Нам нужно запуститься и показать окно трейнера. Простого MessageBox тут недостаточно, потому что оно закроется сразу после нажатия кнопки "ОК" и мы ничего с этим поделать не можем. Нужно что-то другое. К счастью, хитрые разработчики Microsoft это самое "другое" уже придумали - мы можем сделать окно! Да не просто окно, а диалоговое окно. Оно отличается от обычного окна тем, что очень хорошо умеет работать со всякими кнопочками и менюшками (а кнопочки у нас в трейнере ещё как будут), ну и чтобы создать его нужно написать меньше кода, чем для создания просто окна.


Вот что нам понадобится:


Для начала - исходный код и скомпилированное приложение, которые можно скачать по [этой ссылке]. Качаем, запускаем, читаем дальше и разбираемся.


1. Сразу после старта трейнера, получить handle (хэндл) нашего трейнера. Хэндл - суть идентификатор (номер) исполняемого файла, чтобы винда не перепутала его с какой-нибудь другой программой. Нужен он нам для того, чтобы сотворить от имени нашей программы окно (в нашем случае - диалоговое). Вот как это выглядит:



invoke GetModuleHandle,0
invoke DialogBoxParam,eax,37,HWND_DESKTOP,DialogProc,0
invoke ExitProcess,0

Значит, ведём пальчиком по строчкам или подкладываем линейку. Первая строчка - функция [GetModuleHandle], принимающая один аргумент - ноль. Служит она для получения того самого хэндла какого-то исполняемого файла, а если в аргументах передаётся ноль, то возвращает она хэндл того исполняемого файла, который её вызвал. Результат после вызова функции запихивается в регистр еах. Вроде бы, ничего сложного? Идём дальше. :)

Дальше у нас идёт [DialogBoxParam], которая, собственно, создаёт диалоговое окно. Ей в аргументах нужно передать хэндл того, кто хранит процедуру работы этого окна (её опишем ниже), имя-идентификатор (в нашем случае - номер), описывающий внешний вид этого окна, хэндл того, кому окно будет принадлежать (в нашем случае - рабочему столу, Desktop), процедуру, описывающую поведение окна и параметры инициализации (забиваем на них, передавая ноль).

Круто? Круто! Но сложновато. Не паникуйте, эту штуку нам придётся написать один раз и забыть о ней - тут менять мы ничего не будем. Сейчас я напишу что-нибудь про третью строчку (которая просто завершает процесс трейнера), а потом вернёмся дальше ко второй - в частности, к процедуре поведения нашего диалогового окна. В-ж-ж-ж-ж-ж-ж!.. Вот, возвращаюсь. :)

Итак, хэндл получили, диалоговое окно вызывали, а когда оно завершило работу - завершаем вслед за ним и работу процесса. Всё просто. Но самое интересное - это процедура работы диалогового окна.

Если вы что-нибудь до этого слышали о программировании, то поймёте меня быстро. Всё поведение диалогового окна - один здоровый цикл. Это, по сути, участок кода, который быстро-быстро бормочет повторяет одно и то же и тем самым взаимодействует с системой. Взаимодействует он при помощи так называемых сообщений. Ну вот например:

-Нажали на крестик сверху-справа - диалоговое окно говорит - "Я ща закроюсь!11", послав сообщение о попытке закрытия. Винда ему отвечает - "Окей, валяй!". Оно берёт и закрывается. 
-Тыкнули в окне левой (или правой) кнопкой мыши - диалоговое окно и говорит - "Меня тыкают! Щекотно! Что делать?". И если мы опишем, что делать, оно что-нибудь сделает.

Удобно? Удобно. Делать нам нужно не много - проверять, не нажал ли пользователь какую-нибудь кнопку на клавиатуре, да уметь закрываться. Вот, собственно, простейшая процедура этого самого диалогового окна:



proc DialogProc hwnddlg,msg,wparam,lparam
        cmp     [msg],WM_CLOSE
        je      .wmclose
        xor     eax,eax
        jmp     .finish
  .wmclose:
        invoke  EndDialog,[hwnddlg],0
  .finish:
        ret
endp


Начнём с того, что процедура [DialogProc] описана в MSDN. Она принимает аж четыре аргумента - хэндл диалога, в котором крутится (ох уж эти хэндлы!), сообщения, которые ей шлёт созданный диалог и два дополнительных параметра, в которых иногда хранится дополнительная информация (каменты!) к приходящим сообщениям. По сути, эта процедура для диалога - она как мозги. Диалог только паникует и орёт, что с ним происходит, а процедура всё это выслушивает и что-то делает. В случае успеха - возвращает ноль, в случае неуспеха - 1. Теперь давайте построчно.


"proc DialogProc hwnddlg,msg,wparam,lparam" - начало процедуры, её имя и описание. Слово proc - сокращение от Procedure (англ. Процедура) - говорит нам о том, что мы пишем процедуру. Дальше - имя и параметры, которые она принимает.


cmp [msg],WM_CLOSE


Вот тут, значит, мы сравниваем входящее сообщение (от диалога) с WM_CLOSE - эта штуковина присылается при попытке этот самый диалог закрыть. Следующей строчкой:


je .wmclose


Мы говорим, переходить нам к завершению процедуры (и закрытию диалога), или же идти дальше. Напомню, je значит Jump if Equal (англ. Прыгнуть, если равно). ".wmclose" - это специальная метка, говорящая о том, где лежит код закрытия. Получается, что если сообщение будет равно WM_CLOSE - мы будем выполнять код, лежащий после метки ".wmclose".


Если же нет - переходим к следующим двум строчкам:



xor eax,eax
jmp .finish


Первой строчкой мы помещаем (то же самое, что и mov eax,0) в регистр еах нолик, говорящий о том, что всё хорошо, а дальше переходим на метку завершения работы процедуры (не диалога!). Причём в этом случае прыжок идёт безусловный - мы ничего ни с чем не сравниваем. Просто еах = 0 - и на выход!


Остаётся вот этот кусок:



.wmclose:
        invoke EndDialog,[hwnddlg],0
.finish:
        ret
endp


Начинается он с метки, на которую мы прыгаем в случае завершения работы диалога. И вызывается после неё ни что иное, как [EndDialog] - функция, которой передаёшь хэндл (!) завершаемого диалога и нолик, говорящий о том, что всё завершается хорошо и без ошибок.


Дальше идёт метка завершения работы процедуры (обработки сообщений диалога), которая просто возвращает управление созданному диалогу командой ret, а тот ждёт новых сообщений, которые, если приходят, опять нашей процедуре и скармливает.


Последнее - endp - обозначает конец описания процедуры. Служебная конструкция, типа. 




Вот и выходит, что диалог создаётся, у него есть простенький мозг - процедура, которая обрабатывает его сообщения. И обрабатывать она умеет (пока что) только одно - сообщение о выходе. А это Alt+F4 и крестик сверху-справа.


Ребята, в исходном коде, который приложен в начале статьи, есть ещё пара непонятных моментов. В самом начале исходника:


format PE GUI 4.0
Эта строчка указывает компилятору, что мы хотим от него получить именно EXE-файл под Windows и ничего другого. Про сам формат (PE - Portable Executable) мы всё выясним чуть позже, сейчас нам о нём следует знать только пару вещей, а именно, что он делится на секции. В нашей программе их будет аж три - секция кода и секция данных, которая будет делиться на данные для импорта и секцию ресурсов. Вот как это выглядит:


Сначала - секция кода. Мы об этом компилятору говорим вот такой строкой:


section '.text' code readable executable
Секция такая-то, а последние три слова говорят, что это код, который можно как читать, так и выполнять.


Идём дальше. Секция импорта (сразу напишу её содержимое):



section '.idata' import data readable writeable
  library kernel,'kernel32.DLL',\
 user,'user32.DLL'
  import kernel,\
GetModuleHandle,'GetModuleHandleA',\
ExitProcess,'ExitProcess'
  import user,\
DialogBoxParam,'DialogBoxParamA',\
EndDialog,'EndDialog'



В этой секции описываются те внешние библиотеки, которые программа должна подключить себе для корректной работы. Корректная работа заключается в доступе к тем самым WinAPI-функциям, да-да. Как видите, мы подключили две библиотеки ("kernel32.dll" и "user32.dll"), указали, какие функции хотим использовать, после чего просто вызывали их из кода.


Согласен, сложно. Запомните, что для доступа к нужным функциям нужно подключить библиотеки, в которых эти функции хранятся. И всё, больше заморачиваться не стоит.


Остаётся секция ресурсов. Вот она:



section '.rsrc' resource data readable
  directory RT_DIALOG,dialogs
  resource dialogs,\
  37,LANG_ENGLISH+SUBLANG_DEFAULT,demonstration
  dialog demonstration,' DialogBox Example ',70,70,190,175,WS_CAPTION+WS_POPUP+WS_SYSMENU+DS_MODALFRAME
  enddialog


На ней мы подробно остановимся в следующей статье (и уроке), но кратенько скажу, что она хранит в себе описание самого диалогового окна и всех его элементов. Размеры окна, заголовок, внешний вид, всякие кнопочки и всё подобное хранится именно тут.


В секции ресурсов из нашего примера описывается одно-единственное диалоговое окно, у которого будет заголовок "DialogBox Example" и, в общем-то, сам системный заголовок (синяя блямба в верхней его части и кнопкой с крестиком справа).


Вот, как-то так. Надо вызубрить, что программа делится на секцию кода, которая может выполняться и на секцию данных, где лежит всё остальное.



Всё, чай уже должен был закончиться, так что отдыхайте, читайте MSDN, спрашивайте непонятное, а в следующей статье соберём это всё в готовую программу-каркас и приступим к написанию кода, который сможет писать в память игры. :)









20111220

Трейнеры.

Совсем скоро будет выложен следующий видеоурок по созданию трейнеров на самом развесёлом языке программирования - ассемблере. Кода там будет чуть больше одной строчки, так что давайте немного повторим пройденный материал из первого урока и заодно распишем план действий на дальнейшие. :)


Итак, привожу исходный код программы из первого урока. Вот он (после точки с запятой идёт комментарий):

; Исходный листинг hello.asm из примеров по flat assemblerinclude 'win32ax.inc' ; Подключаемая библиотека для работы с WinAPI-функциями

.code ; Начало секции кода
  start: ; Единственная метка - точка входа в программу
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK ; Вызов информационного окна
invoke ExitProcess,0 ; Закрытие программы
.end start ; Закрывающая конструкция для входной метки



Давайте теперь разберём каждую строчку, начиная с первой. Итак:

1. Команда include (англ. подключить) - служит для подключения для внешней библиотеки, позволяющей нам использовать WinAPI-функции. Очень необходимая штука, без неё ничего работать не будет - просто запомните. :)

2. Штучка .code сообщает компилятору, что мы собрались писать код. Это - секция кода, подробнее будет в следующем уроке.

3. start: (англ. начало) и end start ("end" - англ. конец) - обозначают начало и конец единственной процедуры нашей программы. Процедур в программе может быть больше одной, так что мы явно просим компилятор начать именно отсюда.

4. На команде invoke (англ. вызвать), которую мы в нашей программе используем аж дважды, остановлюсь чуть подробнее. Если очень просто, то этой командой мы вызываем WinAPI-функцию, передав функции необходимые аргументы. Вот вам простой пример:

Лето, Сочи, жара +35, идём мы себе в гавайских шортах и сланцах по улице, а тут нас неожиданно одолевает жажда. Заворачиваем за угол и - о, чудо! - видим автомат по продаже кока-колы.
Подходим к автомату, трясём карманы - находим мелочь. Теперь - самое интересное. Чтобы купить бутылку, автомату нужно дать взятку денег - тут всё понятно. Так вот, автомат - это функция, а деньги - это аргументы этой функции. Бывает даже так, что функция после вызова присылает нам какой-то ответ. В случае автомата это будет или "Иди на фиг, денег мало" или "Вот Ваш напиток, Господин!". На языке ассемблера мы могли бы купить колы вот так:

invoke Автомат,35

Начинает проясняться, правда? :)

Ладно, возвратимся к нашей программе, в которой мы вызываем две функции. Первой мы показываем информационное окошко с каким-то текстом и кнопочкой "ОК", а второй просто завершаем работу. Подробнее про обе функции можно почитать вот тут:

[MessageBox]
[ExitProcess]


Потихоньку привыкаем читать документацию на английском, это правда очень сильно пригодится, поверьте мне. Если не получается сходу - воспользуйтесь помощью гугл-переводчика, сделайте его капельку счастливее. :)


Для тех, кто до сих пор не понял, что за слово такое - "компилятор" - объясняю: это программа, делающая из нашего исходного кода исполняемый EXE-файл. Подробнее пока знать ни к чему, ещё успеем.

Если устали от многабукав - сходите попейте чаю или книжку почитайте, потому что дальше мы будем думать о вечном - о том, как устроен трейнер. :)

В общих чертах, трейнер должен делать вот такое:

1. Запуститься, показать своё окно
2. Ждать нажатия на кнопку от пользователя
3. Если пользователь всё-таки это сделал - включить (или выключить) какую-то из опций-читов
4. Корректно завершить работу после закрытия

Как видите, всё довольно прозрачно. А подробности - в следующем уроке. :)

PS: Полный исходный код и скомпилированное приложение можно найти в папке \examples\hello из дистрибутива [flat assembler].

20111217

Видеоурок по стратегиям.

Пока что, думаю, заключительный - начнём уже трейнеры писать, наконец. :)

Делать мы будем не абы чо, а Map Hack (!) - грозу всея онлайн-комьюнити, штуковину, позволяющую брать и бессовестно подглядывать за вражьим игроком, делая себе нифига себе такое преимущество.

Метод достаточно идиотский - наткнулся на него случайно, может работать не во всех играх. А может и работать, я во всех играх ещё не проверил. :)


PS: !!!Не пытайтесь!!! играть с этой штукой онлайн - велик риск быть забаненным. А я в этом не виноват, потому что сейчас это написал.

[ссылка на урок]

20111216

Напоследок.

Завтра я сотворю следующее видео по ассемблеру и трейнерам, честно-честно. И по гонкам что-нибудь, если успею. Вспомнил, что от меня хотели speedhack - неприличной скорости ускорение. Точнее, показать, как оно делается. :D

ВНЕЗАПНО, видеоурок!

По стратегиям, который я всё-таки записал, самым невероятным образом. Расскажу - не поверят!. Итак, опираясь на недоперевод статьи из предыдущих постов - переходим к наглядной практике:

[ссылка на урок]

Уже после записи урока хотел бы добавить пару слов - не обязательно лезть в дебри отладки и кода, когда можно чуток включить голову, ну правда. :)

Если сложно и не ломается - да забейте вы на этот отладчик, попейте чаю, возьмите листочик с карандашом и порисуйте лучше. Ну, в смысле, как на ваш взгляд всё это должно работать. Тогда может и идея какая придёт в светлую голову, так-то!

И в очередной раз можно убедиться в исключительной полезности гугла и петабайт справочных материалов, по сети раскиданных. Встретили команду, но не знаете нафига она? Гугл! Забыли как правильно пишется какое-то слово? Гугл! Хотите научиться ломать игры? Г!.. Ан-нет, - keng. :)


20111215

Новогоднее настроение!


Вроде середина декабря, новый год скоро и вообще, а я, вместо пожирания мандаринок, сижу и готовлю материал для следующих уроков. Неплохой бонус к новогодним праздникам, мне кажется. :)

А чем вы заняты в такое радостное время?

Ещё немножко про трейнеры.

Пока я тут скучаю на работе - накидаю вам небольшой план по дальнейшим урокам касательно чёрной магии ассемблера:

Собственно, алгоритм работы сферического трейнера в вакууме не представляет из себя ничего хитрого. Трейнеру для счастья и комфорта нужно всего ничего - запустить своё окошко и что-нибудь там показать-рассказать и дать послушать, затем - ждать, пока пользователь что-нибудь сделает - тыкнет в кнопку мышкой или нажмёт на клаве кнопку. Если вдруг такое происходит - сделать, что приказано, а потом тихо закрыться.

Вот в пункте "сделать, что приказано" и будет происходить самое интересное, и имя ему - запись в память. Да, я серьёзно. Именно в этот момент нам и понадобятся все наши найденные адреса и всё остальное, так-то!

Как видите, алгоритм простой. Поэтому я объявляю конкурс бесплатно без смс скачать - попробуйте реализовать этот алгоритм сами. Само собой, на любимом языке, если такой у вас есть. Если вдруг удастся (или нет) - пилите исходник в архив и, вместе с описанием, суйте всё это в комменты к этой записи.

Ну как, круто я придумал? :)

Дырявая моя голова!11

Забыла выложить [ссылку] на Flat Assembler. (:
PS: Нам нужна версия для Windows, можете мне поверить.

Прошу любить и критиковать - первый видеоурок по ассемблеру!

Или мнёмся на пороге, приступая к работе. (:

[ссылка]

20111214

Обломинго, товарищи!

Ребята, у меня сейчас конец квартала на работе, так что я там практически живу. После нескольких очень спешных, но безуспешных попыток найти сейчас современную стратегию без навешанных на неё защит и прочих усложнителей нашей геймхакерской жизни, я сейчас постараюсь изложить нужный материал в виде статьи, чтобы вы хоть как-то не скучали, а потом перейдём к ассемблеру и трейнерам, т.к. там для уроков ничего искать не нужно и времени у меня (которого и так катастрофически ни на что нет) отнимать будет не много - следовательно, уроки будут выкладываться чаще.

Собственно, статья будет переводом одного зарубежного ресурса с моими небольшими дополнениями. Переводить (скорее даже - вольно пересказывать)  я буду основные моменты, т.к. в той статье использовались не совсем актуальные на данный момент инструменты, но суть способа передаётся отлично в любом случае. Итак:

-------------------------------------

Задача: Мгновенная постройка только для игрока.
Инструменты:

-Игра жанра RTS
-Сканер памяти (Cheat Engine)
-Отладчик (тоже Cheat Engine)
-Начальные навыки взлома игр - теория по DMA, инъекции кода

Теория:

Главное, что нужно понять в теории к этой теме - разницу между игрой человека и компьютера, проще говоря - бота. Посидев с чашкой любимого чая и парой бутербродов над раздумьями, мы приходим к мысли, что человеку необходимо видеть происходящее на экране, чтобы принимать решения. Т.е. вся информация (количество ресурсов, построенные здания, положение армии и так далее) не просто обрабатывается алгоритмами игры, но и выводится для человека на экран в привычном человеку виде.

Компьютерному же боту нафиг не сдалось ни на экран смотреть ни тем более звуки слушать - у него есть определённый набор условий и переменных, где хранятся необходимые данные (ресурсы, координаты построек\армии и всё прочее) - он их из памяти прочитает и отдаст алгоритмам команду действовать, исходя из условий.

Грубо говоря, для игрока всё видимое на экране - это дублирование внутриигровых значений, т.е. можно искать, скажем, ресурсы, а найти только адрес, значение которого выводит их на экран, но не будет истинным значением ресурсов. Как-то так. А вот у бота всё попроще - он сразу из памяти читает.

Практика:

Как вы все уже могли догадаться, первая половина взлома происходит достаточно просто:

1. Мы знаем, что постройка чего либо занимает определённое время. Начинаем строить какое-то здание, видим на экране отображение прогресса строительства - или полоску:

[|||||||||||||||||||||||||||||||=>75 %        ]

или просто здоровье здания\проценты в цифрах.

2. Возможных алгоритмов поиска будет аж три штуки. Вот они:
-Неизвестное значение, уменьшилось-уменьшилось-уменьшилось.
-Неизвестное значение, увеличилось-увеличилось-увеличилось.
-Неизвестное значение, изменилось-изменилось-изменилось.

Тип данных - а когда как, на самом деле. От целого 1 байт до с плавающей точкой.

3. Итак, ставим новое здание, пока строится - пробуем искать по описанным выше способам.

В конце концов находим адрес, вешаем на него брейкпоинт и смотрим отладчиком, какая инструкция туда пишет. Вот тут - очень важный момент:

Где-то рядом с этой инструкцией будет сравнение (человек \ бот) и затем - условный переход или call (вызов) функции. По сути, для бота алгоритм будет примерно таким:

-Проверить, не достроилось ли здание
-Если достроилось - сообщить об этом

А вот для человека - таким:

-Проверить, не достроилось ли здание
-Обновить экранное значение (полоску или проценты)
-Если достроилось - сообщить об этом

Вот после сравнения как раз и будет идти инструкция, нужно ли игре обновлять значение на экране. И бывает так, что эта штука - единственное, как можно отличить игрока-человека от бота.

Сама по себе инструкция постройки будет тоже простецкая, как-нибудь вот так:

cmp edi, ebx //сравниваем значение текущего прогресса с 100%
je done //если достроилось - выходим и сообщаем об этом игроку
sub edi, eax //достраиваем ещё кусочек

Т.е. мы просто берём и в инъекции вычитаем из edi его же значение - вуаля, всё будет строиться сразу же. Но перед этим нам необходимо будет проверить, человек ли строит, т.к. код-то один и тот же - ну, с парой отличий. :)

Так как игра в любом случае должна отличать игроков друг от друга, смотрим код выше и ищем все сравнения, ставим на них брейкпоинты и внимательно изучаем значения регистров - сравниваться может что угодно, от ника того, кто строит, до цвета и просто флажка вида "Свой - чужой". В нашей инъекции обязательно это используем для отсеивания ботов.

Как видите, всё достаточно просто. Самое полезное в этой теме - понимание теории про экранные значения, процесс поиска нужного нам адреса (просто так бывает и не догадаешься так искать) и (довольно часто) - новые способы сравнения игроков между собой. В остальном этот урок на 90% схож с темой one hit kill (убийство с одного выстрела), которую я показывал на примере Crimsonland.


PS: Я изо всех сил стараюсь выкроить время для нормальной записи урока и покажу всё это на примере - так информация воспримется лучше, но пока что буду обращать больше внимания на трейнеры и ассемблер, т.к. это правда займёт меньше времени. Спасибо всем, кто это прочитал, прочитает или даже поделится ссылкой с другом. Если захочется почитать оригинальную статью на английском, то её можно найти, к примеру, тут.