20111222

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

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


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
Трейнер наш после этих телодвижений будет выглядеть вот так:






3 комментария:

  1. Анонимный26/12/11 02:19

    Grom-Skynet

    Привет Keng.
    Вот у тебя адрес записан в виде 0x004256BF Все работает один раз пока игру не перезагрузишь... ну я имею ввиду не ту игру которую ты ломал ... а вообще...
    и при новой загрузке эта инструкция на новом адресе...
    как записать адрес с модульной адресацией..? Очень волнует этот вопрос...

    Спс.

    ОтветитьУдалить
  2. Скоро будет урок на эту тему.

    ОтветитьУдалить
  3. Анонимный26/12/11 17:40

    Grom-Skynet

    вот этого я и жду.... трейнер готов .. а вот с этим проблема ..
    VC#

    ОтветитьУдалить

Не люблю мат и низкий уровень грамотности. Чем конкретнее поставите свой вопрос и чем лучше он будет выглядеть - тем большая вероятность на мой ответ. :)