Помните процедуру диалогового окна нашего трейнера? Приведу её исходный код ещё раз, вот:
Функцией SendMessage мы обманываем глупую виндовс и говорим ей, что мы якобы не просто нажали ЛКМ, а нажали её на заголовке, о чём нам говорит цифра "2" в аргументах этой функции. По сути, функция эта умеет слать сообщения вручную - как если бы они к нам приходили извне. В аргументах функция требует указать, кому слать сообщение (указываем hwnddlg - хэндл нашего диалогового окна), само сообщение (WM_NCLBUTTONDOWN - нажатие ЛКМ. На самом деле - не совсем ЛКМ, а ЛКМ вне пределов клиентской области окна, но нам этого пока знать не обязательно) и место, какой части окна шлём, в аргументах. У нас этим аргументом является цифра "2", она обозначает заголовок окна.
Итак, как это выглядит? Мы зажали левую кнопку в окне, двигаем мышью - а окно двигается вместе с ней, как если бы мы таскали его за заголовок. Здорово? Здорово!
Но если вы смотрели предыдущие статьи и урок, то уже смело возражаете мне - "Как же так? Новая WinAPI-функция, а в секции импорта мы её не описали! Использовать не сможем! Безобразие!". Да, всё верно. Вот наша старая секция импорта:
А вот - новая:
Не забудьте в имени функции поставить букву А - SendMessageA. Дело в том (опять я в подробности полез), что существует две версии этой (и других) функций - с буквой A и с буквой W. Обозначают эти буквы разные кодировки - ANSI и Unicode. Что это такое - выясняйте сами, т.к. это уже выходит за рамки тематики моего блога. Или просто не заморачивайтесь и используйте версии с А. :)
Ну и, в завершение, избавим наше диалоговое окно от заголовка, который теперь нам стал катастрофически не нужен. Идём в секцию ресурсов и меняем описание диалога вот на такое:
Полный исходный код (синим цветом - изменения):
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
Трейнер наш после этих телодвижений будет выглядеть вот так:
Grom-Skynet
ОтветитьУдалитьПривет Keng.
Вот у тебя адрес записан в виде 0x004256BF Все работает один раз пока игру не перезагрузишь... ну я имею ввиду не ту игру которую ты ломал ... а вообще...
и при новой загрузке эта инструкция на новом адресе...
как записать адрес с модульной адресацией..? Очень волнует этот вопрос...
Спс.
Скоро будет урок на эту тему.
ОтветитьУдалитьGrom-Skynet
ОтветитьУдалитьвот этого я и жду.... трейнер готов .. а вот с этим проблема ..
VC#