Analiza gry „Max Payne” (patch v1.05) w celu stworzenia Trainera.

Tak jak obiecałem w pierwszym wpisie, kolejny będzie dotyczył tworzenia trainera dla gry „Max Payne”.  Trainer napiszemy w Borland Delphi 7 Personal pod WinAPI z wykorzystaniem zmodyfikowanych modułów dostępnych tutaj, pozwalających na stworzenie mniejszego exeka po kompilacji, a przed jego ewentualnym potraktowaniem UPX’em lub innym packerem. Ok, zaczynamy. Najpierw lista potrzebnych rzeczy (kolejność‡ prawie przypadkowa ;)).

  • Mózg (bez myślenia ani rusz :)).
  • Program „Cheat Engine” dostępny tutaj.
  • Podstawowa wiedza o instrukcjach assmeblera i ich opcodach.
  • Dużo wolnego czasu na spokojne napisanie trainera i analizę gry.
  • Kalkulator przeliczający na Hex (może być calc.exe z Windowsa).
  • Total Commander do wygodnej pracy z plikami (pobierzesz go stąd).
  • Borland Delphi 7 Personal (znajdziesz je na pewno jeśli pogooglujesz).
  • ResEd – edytor, którym stworzymy okno dialogowe Trainera (pobierz stąd).
  • Grę Max Payne z patchem w wersji 1.05 (również znajdziesz jak pogooglujesz).
  • Plik maxpayne.exe, pozwalający grać bez CD / obrazu ISO (dostępny np. tutaj).
  • Kilka narzędzi reversera jak OllyDbg, W32Dasm, HIEW i inne. Wygoogluj je sobie.

Na sieci znajduje się mnóstwo tutoriali (w tym video) opisujących jak przy użyciu Cheat Engine szukać i zmieniać wartości w pamięci procesu jak i ustalać‚ Pointery. Dlatego w tym wpisie to sobie daruję. Wiadomo również, że można skorzystać z cheatu pod F12, po uruchomieniu exeka gry z parametrem -developer, jak i kombinować z trainerami, które dostępne są na sieci. Jednak mam nadzieję, że chcesz zrobić taki trainer samodzielnie, aby się czegoś nauczyć. Dodam, że ja analizowałem wersję gry z polskimi napisami oraz dubbingiem Radosława Pazury, ale to nie powinno mieć wpływu, bo liczy się wykorzystany exek, który poza tym że jest bez zabezpieczenia CD Check, to rownież jest w postaci rozpakowanej, a więc pozwala na swobodną analizę go pod różnymi narzędziami reversera 🙂

Zamrożenie ilości naboi aktualnej broni.

Zaczynamy od najprostszej do ustalenia wartości czyli ilości amunicji w aktualnie posiadanej broni. Dla ułatwienia rozpocznijmy trening i zbierzmy bronie w nim dostępne. Na przykład wybieram Berettę i mam aktualnie 18 naboi. Wyszukajmy tę wartość przy użyciu Cheat Engine w procesie maxpayne.exe dla value type: 2 Bytes. Strzelmy ze trzy razy, czyli powinniśmy mieć 15 naboi. Wyszukajmy tę wartość przez kliknięcie na przycisk „Next Scan”. Jeszcze jeden strzał i mamy 14 naboi. Na liście znalezionych wartości znajdą się dwie pozycje. Obstawiam, że właściwa będzie ta druga. Dodaję ją do listy adresów i zamrażam. Przełączam się z powrotem na grę i strzelam kilka razy i jak widać zarówno licznik naboi Beretty jak i Śrutówki stoi w miejscu. Normalnie teraz wyszukali byśmy adresy pointerów, ale od razu Was uprzedzę, że w tej grze to nie zdaje rezultatów, ponieważ za ponownym załadowaniem gry lub jej rozpoczęciem nawet bez zamykania miejsca w pamięci totalnie się zmieniają.  Dlatego musimy w tym przypadku spróbować zmodyfikować kod. Klikamy prawym klawiszem na dodaną do listy wartość naboi i wybieramy polecenie „Find out what writes to this address”. Strzelmy raz z aktualnie posiadanej broni i widzimy, że na liście dodała się jedna linijka. Kliknijmy na przycisk „More information” i mamy takie informacje:

EBX=007D1334
ECX=0ACE3AB4
EDX=00000001
ESI=0ACE3AB4
EDI=03A11030
EBP=0018F8E0
ESP=0018F8B4
EIP=00757F56

Probable base pointer =0ACE3AB4

00757f4e - nop
00757f4f - nop
00757f50 - dec [ecx+000001cb]
00757f56 - inc [ecx+00000223]
00757f5c - ret

Nie trzeba być geniuszem i mieć jakąś niewyobrażalną znajomość assemblera, żeby wiedzieć iż ta instrukcja zmniejszy o jeden wartość w rejestrze ECX, do której dodajemy  000001CB. Jak wspomniałem, nie ma co tutaj bawić się w Pointery. Nasz trainer będzie więc wyszukiwał ciągu bajtów tej instrukcji i ją podmieniał. Ale skoro mamy rozpakowany exek możemy sprawdzić jak zadziała modyfikacja „na sztywno” poprzez zmianę bajtów w pliku maxpayne.exe. Zapiszmy grę, zamknijmy ją i zróbmy kopię zapasową pliku  maxpayne.exe na przykład pod nazwą  „maxpayne.ex” . Otwórzmy plik  maxpayne.exe w HIEW. I naciśnijmy F5 aby przejść do adresu. Ponieważ będziemy przechodzić do adresu wirtualnego wpisujemy: . 00757f50 (konieczna jest kropka, a zera wiodące można pominąć). Teraz naciskamy F3 aby edytować i zastanówmy się jakiej dokonać modyfikacji. Możemy oczywiście dać sześć razy $90 czyli nop, ale później kiedy nasz trainer będzie wyszukiwał odpowiednie wartości w pamięci procesu, a my byśmy chcieli stwierdzić czy w pamięci nie ma zmodyfikowanej wartości po to aby przywrócić oryginalne bajty, to takich instrukcji jak sześć „nopów” moglibyśmy znaleźć w pamięci wiele takich wartości. Dlatego najlepiej jak wykonamy trzy instrukcje dwu bajtowe mianowicie skoki o linijkę kodu niżej czyli wpisujemy EB 00 EB 00 EB 00. Z pewnością wielu z Was kojarzy stare tutoriale o crackingu, bo pewnie wielu z Was zaczynało naukę od tych dołączonych do słynnej bazy numerów seryjnych „Oscar” autorstwa grupy Phrozen Crew. Także pewnie znacie niektóre przydatne opcody na pamięć, a jeśli nie to polecam sobie pogooglować za aktualnymi tutorialami na temat reverse engineeringu. Po zmodyfikowaniu instrukcji pod HIEW, naciskamy F9 aby zapisać zmiany i F10 lub Escape aby wyjść. Ponownie uruchommy grę i sprawdźmy efekt naszych zmian. Strzelamy i ilość naboi się nie zmniejsza. Super. Zapiszmy sobie te wartość w jakimś pliku najlepiej od razu w przygotowanym kodzie trainera pisanego w Delphi, czyli na przykład:

//...
const
//...
  Bytes_Array_Length = 6;
//...
  Ammo_Bytes_Arr : array[0..Bytes_Array_Length - 1] of Byte =
    ($FF, $89, $CB, $01, $00, $00);
  Write_Values_Ammo_Arr : array[0..Bytes_Array_Length - 1] of Byte =
    ($EB, $00, $EB, $00, $EB, $00);
//...

Mamy tutaj tablice oryginalnych opcodów do wyszukania w pamięci oraz tablicę opcodów, którą ją zastąpimy, natomiast kiedy zechcemy przywrócić oryginalne opcody, wyszukamy tablicę zmienionych bajtów i zapiszemy pod znalezionym adresem tablicę oryginalnych. Czyli  Ammo_Bytes_Arr – oryginalne opcody, Write_Values_Ammo_Arr – zmodyfikowane.

Zamrożenie wartości Bullet Time.

Ze znalezieniem wartości Bullet Time również nie powinno być problemów. Wystartujmy trening. Zapiszmy grę klawiszem F5 z pełnym zapasem Bullet Time, a następnie w Cheat Engine wyszukujemy „Unknown initial value” dla „value type”: 4 Bytes, a później naciśnijmy prawy przycisk myszki, pozwalając wartości Bullet Time się zmniejszać, pauzujmy grę co chwilę, następnie wyszukujmy Decrased Value w Next Search. W końcu załadujmy Quick Save klawiszem F9 i wyszukujmy Same as first scan. Mi dzięki takim zabiegom zostały na liście znalezionych tylko cztery wartości, a prawidłową była ta wynosząca 1065353216. Dla pewności zamroziłem ją i sprawdziłem. Tak, Bullet Time się nie zmniejsza. No to co? Oczywiście znowu korzystajmy z polecenia  „Find out what writes to this address” dla znalezionej wartości. Znalazło kilka, ale z opisem „Store Real”, spójrzmy więc na pierwszą ze znalezionych i widzimy:

EAX=072FD280
EBX=07BBEF00
ECX=00000060
EDX=0AA1D408
ESI=07B11B20
EDI=07BBEF00
EBP=0018FDB8
ESP=0018FC44
EIP=0044CBF8

Probable base pointer =07BBEF00

0044cbe9 - fmul dword ptr [ebp+08]
0044cbec - fadd dword ptr [ebx+000012f0]
0044cbf2 - fst dword ptr [ebx+000012f0]
0044cbf8 - fcomp dword ptr [007cbdd0]
0044cbfe - fnstsw ax

Jak widać różne operacje, ale kliknijmy na  przycisk „Show  dissasembler”. Kawałek niżej pod adresem .0044cc03 znajduje się instrukcja:skoku warunkowego: jne 0044cc12. A co by się stało gdyby ten skok się nie wykonał? Sprawdźmy to. Zamknijmy grę. Otwórzmy pod HIEW plik maxpayne.exe, naciśnijmy F5 i wpiszmy: .0044cc03 (można też użyć kombinacji klawiszy Shift + Insert aby wklejać wartości do HIEW w odpowiednie pola). Naciskamy teraz F3 i wpisujemy EB 00 aby skakać tylko o linijkę niżej. Potwierdzamy zmiany klawiszem F9 i wychodzimy z HIEW. Uruchamiamy grę, ładujemy save, wciskamy prawy przycisk myszki i co? Bullet Time nie ubywa. Super 🙂 Czyli uzupełniamy deklaracje stałych o tablicę opcodów oryginalnych oraz do zmiany.

const
//...
  Bytes_Array_Length = 6;
//...
  Bullet_Time_Bytes_Arr : array[0..Bytes_Array_Length - 1] of Byte =
    ($75, $0D, $BE, $00, $00, $80);
  Write_Values_Bullet_Time_Arr : array[0..Bytes_Array_Length - 1] of Byte =
    ($EB, $00, $BE, $00, $00, $80);
//..

Ok – jedziemy dalej.

Zamrożenie wartości zdrowia.

Teraz przed nami najtrudniejsze. Aby znaleźć odpowiednie miejsce w pamięci, gdzie następuje zmiana wskaźnika na ilość energii będziemy musieli pokombinować. Najpierw radzę uruchomić grę w oknie i bez wcześniejszego dialogu z opcjami. Najprościej utworzyć sobie plik *.bat o dowolnej dopuszczalnej w systemie nazwie z taką treścią:

@start "" maxpayne.exe -nodialog -window

Grę uruchamiamy w oknie po to, aby później kiedy użyjemy debuggera i założymy pułapkę czyli breakpoint na konkretnie miejsce w kodzie, łatwiej będzie się można na ów debugger przełączyć, ponieważ normalnie musielibyśmy naciskać wiele razy kombinacje klawiszy , jak na przykład: Alt + Tab, Ctrl + Shift + Escape i tym podobne aby przejść do okna debuggera.. Dlatego najlepiej rozpoczynijmy nowy trening i zapiszmy quick save w momencie gdy jesteśmy przy przycisku, który przywołuje przeciwników. W Cheat Engine wybieramy oczywiście proces maxpayne.exe,  jako scan type: „Unknown initial value”, a jako value type: 4 bytes. Szukamy, następnie przywołujemy przeciwnika i pozwalamy aby lekko nas uszkodził, robimy pauzę klawiszem „P” i szukamy następnej wartości jako „Decrased value”. Po kilku takich powtórzeniach wybieramy jako scan type „Same as first scan”. Nadal jednak pozostaje sporo znalezionych wartości na liście. Proponuje w takim wypadku załadować Quick Save, poruszać się nieznacznie Maxem po planszy treningowej i co jakiś czas wybierać wyszukiwanie jako „Unchanged value”. U mnie nadal pozostaje na liście 47 wartości. Mimo powtarzania powyższych czynności. Wyszło mi do rymu 😉 Proponuje więc wybrać Bigger than i ponieważ szukamy wartości czterobajtówych to zaznaczyć „Hex” i wpisać FFFFFF. Pozostały tylko 23, to najlepiej wybierajmy dla próby te występujące na końcu listy. Ja od razu podpowiem, dzięki wcześniejszej mojej analizie, że przy pełnym zdrowiu Maxa będzie to ta, której wartość hex wynosi 42700000. Dodajmy ją więc do listy i zamróźmy na chwilę. Przełączmy się na grę i przywołajmy przeciwnika. Energia nie ubywa. Czyli prawie jesteśmy w domu. Dlaczego prawie? Ano dlatego, że jak wspominałem powyżej. Ustalanie Pointera na ten adres nic nam nie da, po ponownym załadowaniu innej gry lub jej rozpoczęciu od nowa, wartość ta będzie w innym miejscu pamięci procesu. Ok, teraz  klikamy prawym klawiszem na dodaną do listy wartość energii i wybieramy polecenie „Find out what writes to this address”. Oczywiście wcześniej ją odmrażając. Przełączamy się na grę i dajemy się zranić przeciwnikowi. Zobaczymy, że debugger znalazł takie miejsce w kodzie (wartości rejestrów mogą się u Ciebie oczywiście różnić):

EAX=425C0000
EBX=FFFFFF00
ECX=0987076E
EDX=007CF974
ESI=09870540
EDI=437F0000
EBP=0018F428
ESP=0018F3A4
EIP=006D71AA

Probable base pointer =0987076E

006d719f - nop
006d71a0 - mov eax,[esp+04]
006d71a4 - mov [ecx+00000085],eax
006d71aa - ret 0004
006d71ad - nop

Od razu uprzedzę, że po tym ret 0004 możemy wnioskować iż jest to wywołana (najpewniej z kilku miejsc w kodzie) funkcja która zmienia zawartość rejestru EAX. Teraz można posłużyć się wieloma narzędziami. Ja tutaj może trochę na przekór zaproponuje bardzo stary, ale dla mnie jary tool mianowicie W32Dasm. Otwierając w nim plik maxpayne.exe i po jego wczytaniu wybierając z menu „Dissasembler” polecenie „Save Disassembly Text File and Create Project File” uzyskamy ważny dla nas sporych rozmiarów plik tekstowy o nazwie maxpayne.alf. Wyszukajmy więc w nim linijkę zawierającą tekst: „006d71a4” (bez cudzysłowów oczywiście). Polecam do tego jakiś szybki i wygodny edytor. Ja z przyzwyczajenia pod Total Commanderem używam tego edytora i przeglądarki, które dostępne są w managerze plików FAR (można go pobrać z tej strony).

Po wyszukaniu w listingu W32Dasm widzimy coś takiego:

* Referenced by a CALL at Addresses:
|:00686D50 , :0069595C , :00696269 , :006964E7
|
:006D71A0 8B442404 mov eax, dword ptr [esp+04]
:006D71A4 898185000000 mov dword ptr [ecx+00000085], eax
:006D71AA C20400 ret 0004

Wyszukajmy od początku pliku linijkę pod adresem 00696269. Od razu uprzedzę, bo wiem to dzięki wcześniejszej analizie i kombinowaniu, iż to miejsce w kodzie to wspólny kod który wykrywa trafienia zarówno zadane nam przez przeciwników, jak i te które to my im zadajemy, dlatego na przykład wstawienie instrukcji  ret 0004 pod adres: 8B442404, spowodowało by, że nie tylko my, ale również przeciwnicy byli by nieśmiertelni, a nam chodzi tylko o to by to nasz bohater był niepokonany 🙂 Przeskrolujmy podgląd nieco wyżej by zobaczyć czy wcześniejszy kod nie jest skądś wywoływany. Po dłuższym przytrzymaniu strzałki w górę widzimy taki oto kod:

* Referenced by a CALL at Addresses:
|:0068F5A6 , :00695B04 , :00695DC7 , :00699AF4
|
:00695FB0 83EC10 sub esp, 00000010
:00695FB3 53 push ebx
:00695FB4 56 push esi

(...)

Od razu uprzedzę, po wcześniejszej analizie, że call z pod adresu  00699AF4 nie jest tym, którego szukamy. Przejdźmy więc do 00695DC7. I sprawdźmy więc jego. Tutaj przyda się na chwilę OllyDbg. Otwieramy pod nim maxpayne.exe i naciśnijmy Ctrl + G i wpiszmy lub wklejmy wartość:  00695DC7. Pod Ollym wyraźnie widzimy, że przed callem jest PUSH ECX, które Olly zakomentował jako Arg1. Oznacza to, że  przed wywołaniem funkcja z linijki  00695DC7 przyjmuje jakąś wartość, która jest w rejestrze ECX.

00695DC1 |. 51 PUSH ECX ; |Arg1
00695DC2 |. 8BCE MOV ECX,ESI ; |
00695DC4 |. D91C24 FSTP DWORD PTR SS:[ESP] ; |
00695DC7 |. E8 E4010000 CALL maxpayne.00695FB0 ; \maxpayne.00695FB0

Najlepiej więc skorzystać nadal z Cheat Engine, ponieważ attachowanie do procesu maxpayne.exe pod OllyDbg może być niemożliwe. Kliknijmy w Cheat Engine na przycisk „Memory View” i następnie prawym przyciskiem na listing kodu w górnym oknie i wybierzmy polecenie „Go to address” i wklejmy 00695DC7. Przejdźmy kawałek wyżej na linijkę z PUSH ECX. Naciśnijmy klawisz F5 aby zastawić breakpoint na te linię kodu. Następnie przełączamy się na grę i dajmy się trafić przeciwnikowi. Debugger załapał. O! Czyli jesteśmy w domu 🙂 Teraz dzięki temu, że grę Max Payne uruchomiliśmy w oknie (gdyby nie było takiej możliwości trzeba by było kombinować z programami typu DXWnd lub wiele razy wywoływać managera zadań i wciskać kombinacje o których wspomniałem, bo debuggowanie gier czy aplikacji DirectX na pełnym ekranie było by możliwe pod debuggerem Soft ICE, a jego działające wersje wyszły tylko dla XP, a kombinując z jego uruchomieniem pod maszyną wirtualną moglibyśmy mieć problemy z załadowaniem go. Także przełączmy się kilka razy Alt + Tab, ewentualnie Ctrl + Alt + Del i po chwili powinniśmy odzyskać „władzę”  na myszką. Przełączmy się na Cheat Engine i widok modułu „Memory View”. U mnie wygląda to tak jak na zrzucie ekranu poniżej…

Widzimy w podglądzie rejestrów, że ECX zawiera wartość: 0987076E. Klikamy dwukrotnie myszką na ECX w oknie „Registers” i kopiujemy tę wartość do schowka przez kombinację Ctrl + C z pola edycyjnego w nowym oknie, które się nam pokaże. Proponuje również wyłączyć BreakPoint na tę linijkę, która jest podświetlona. I teraz przechodzimy do okna głównego Cheat Engine i wyszukujemy nową wartość 0987076E z zaznaczonym CheckBoxem „Hex” oraz value type: 4 Bytes. Znalazło wiele wartości, ale nas interesuje ta pierwsza. Dodajemy ją do listy na dole okna. Następnie klikamy na tę wartość, na wysokości kolumny „Address”. Kopiujemy adres z pola tekstowego (u mnie 07C057F5). Zaznaczamy CheckBox „Pointer” i w pole „Address of pointer” wklejamy 07C057F5, a w „Offset (Hex)” 85, bo jak pamiętamy taka wartość byłą dodawana do rejestru, w znalezionym wcześniej callu modyfikującym wartości energii naszej oraz przeciwników. Zatwierdzamy zmiany przyciskiem „Ok”. Jak widzimy w kolumnie „Address” mamy tekst „P->098707F3” czyli wskazuje nam na identyczny adres jaki wcześniej mozolnie poprzez zmiany i sprawdzanie ustaliliśmy dla energii. Jednak od razu uprzedzam, adres tego Pointera zmieni się dla ponownie uruchomionej gry. Jak więc zrobić Trainer, który zmieni go na stałe. Najlepiej jak przy poprzednio zamrażanych wartościach czyli amunicja oraz Bullet Time, posłużymy się wyszukiwaniem bajtów. Tutaj nieco uproszczę swój opis, ponieważ żeby teraz ustalić jakie bajty wyszukać należało by powtórzyć całą operację z „namierzaniem” pointera na energię raz jeszcze. Ale wcześniej w oknie „Memory View” kliknąć na okno z zawartością pamięci prawym przyciskiem wybrać polecenie „Goto address”, wkleić 07C057F5, kliknąć na „OK” i nad tym adresem skopiować jakaś ilość linijek z wartościami hex. Ja kopiowałem ich szesnaście (oczywiście liczba w tym przypadku dziesiętna, czyli 16 ;)). Później zachowując je do pliku tekstowego i powtarzając operację wyszukiwania i ponownie zapisując te 16 linijek nad adresem Pointera do innego pliku tekstowego po wklejeniu hexów ze schowka. Uzyskałem dzięki porównywaniu plików tekstowych pod Total Commanderem informację, z której mogłem wywnioskować, że są to następujące bajty, które oczywiście w kodzie Trainera dodałem jako stałą:

const
//...
  Energy_Pointer_Offset = $85;
//...
  Energy_Pointer_Bytes_Shift = $74;
//...
  Minimum_Energy_Value = $42700000;
//...
  Energy_Marker_Range_Begins = $7000000;
  Energy_Marker_Range_TheEnd = $9000000;
//...
  Energy_Bytes_Marker_Arr : array[0..46] of Byte =
    ($12, $00, $00, $00, $1F, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF, $FF, $FF, $01);
//...

Stałe  Energy_Marker_Range_Begins oraz  Energy_Marker_Range_TheEnd zawierają granicę adresową w pamięci procesu gdzie będzie występował ten „znacznik” bajtów, jak go nazwałem. Po prostu nie ma sensu przeszukiwać całej pamięci procesu, bo będzie to trwać zbyt długo. Dodałem również stałą: Energy_Pointer_Bytes_Shift, która wynosi: $74. A uzyskałem ją odejmując od adresu znalezionego Pointera adres początku wystąpienia w pamięci tego ciągu bajtów. Czyli po prostu nasz Pointer jest $74 bajtów później. Czyli teraz tworzony Trainer  po wybraniu odpowiedniego CheckBoxa powinien w wątku zapisywać pod tak ustalony adres Pointera i dodając do niego $85, wartość zerową dla energii czyli w tym przypadku $42700000, co warto ustalić pod jakąś stałą, w moim przypadku nazywa się ona  Minimum_Energy_Value.

Końcowe uwagi dotyczące kodu Trainera.

Trainer będzie wyglądał tak:

Sam dialog stworzyłem pod wspomnianym na początku edytorem ResEd. Ponieważ zależało mi aby trainer był mały rozmiarem i zgrabny, a nie jak różne „opasłe” twory wygenerowane pod Cheat Engine lub przez jakiś neo kidsów, którzy chwalą się jak kodzili pod visual basiciem (sic!) jakieś niby trainery i wrzucali o tym niskiej jakości filmiki na YouTube. to musimy użyć część kodu z innych modułów tak aby kompilowały się .tylko z „mało tuczącymi” dla exeka modułami jak Windows, Messages, TlHelp32. W kodzie użyłem własnych modułów takich jak:

  • hotkeyhandler2_ver2.pas – moduł napisany w WinAPI na bazie kodu tego z Cheat Engine, korzysta on z tablicy statycznej oraz pozwala na obsługę zarejestrowanych HotKeyów również kiedy używamy aplikacji nieokienkowej czyli na przykład gry napisanej pod DirectX. Działa on na zasadzie sprawdzania w wątku funkcji API: GetAsyncKeyState, a także pozwalający naciskać dany przycisk raz i później czekający na jego puszczenie, tak aby prawidłowo reagować na uaktywnianie oraz deaktywowanie wartości do zmiany
  • keystotext.pas – zamienia kody vk klawiszy na tekst, jest to wyodrębniona najważniejsza część – pozwalająca osiągnąć ten efekt pod WinAPI – modułu VCL Menus. Kod jego uzyskałem ze źródeł dołączonych do Delphi w wersji Enterprise.
  • mini_shellapi.pas – zawiera najważniejszy wycięty dla potrzeb WinAPI kod modułu ShellApi, wykorzystany po to aby móc użyć funkcji ShellExecute do otwierania strony www po kliknięciu w label z adresem. Kod modułu ustalony w ten sam sposób jak wspomniałem powyżej.
  • useful_winapi.pas – zebrane przeze mnie najważniejsze funkcje i procedury przydatne dla mnie podczas tworzenia aplikacji w czystym WinAPI.

Dodatkowo wspomnę iż wykorzystałem tutaj fragment kodu modułu SimpleTcp autorstwa Mateusza Piechnata. Moduł można pobrać stąd. Wykorzystałem kod do tworzenia wątków tak aby dla pewności w sposób prawidłowy przekazywać między wątkami Pointery na tworzone obiekty z odpowiednimi parametrami. Zasoby okna dialogowego oraz ikonki przebudować i kod Trainera szybko skompilować, usuwając zbędne pliki *.dcu można przy użyciu pliku build.bat, który również spakuje plik wykonywalny UPX’em (do pobrania stąd) z parametrem –best, zapewniającym najlepszą kompresję, a rozmiar pliku dodatkowo zmniejszają użyte moduły o których wspominam na początku tego wpisu. Użycie tych modułów jest zainicjowane odpowiednim wpisem w pliku *.dof (SearchPath=$(Delphi)\LIB\FOR_WINAPI). I to by było na tyle. W razie pytań czy nieścisłości proszę piszcie w komentarzach. Dla wytrwałych, którzy uważnie przeczytali ten artykuł do końca zamieszczam skompilowany exek jak i źródła trainera w postaci archiwum ZIP – tutaj. Proszę również o wszelkie uwagi i opinie na temat artykułu. Z góry przepraszam za mój rozpisany i być może nie zawsze do końca precyzyjny styl, ale to mój pierwszy artykuł od bardzo dawna i pierwszy dotyczący tworzenia trainerów.

Comments (4)

  1. 18:16, 06.07.2012MSM  / Odpowiedz

    Ech, pobawiłbym się w to, tylko że ściąganie gry z jakiegoś torrenta oraz cracka do niej wygląda dość nieszczególnie…

  2. 21:58, 06.07.2012olesio  / Odpowiedz

    @MSM: patchnięty exek akurat szybko można pobrać. A samą grę polecam sobie wygooglować na forach z linkami do hostinów. Da się częściej stamtąd szybciej pobrać starsze pozycje niż z torrentów.

  3. 14:29, 12.07.2015Xurel  / Odpowiedz

    Czy tutaj propaguje się piractwo, bo jakby pomyśleć deasembleracja komercyjnej gry jest zabroniona przez autorów

    • 17:25, 12.07.2015olesio  / Odpowiedz

      Nikogo nie namawiam do stosowania trainera. Operuję tutaj wyłącznie na pamięci procesu. A żadne pliki nie są stale modyfikowane. Było zainteresowanie takim tematem kiedyś, to się podzieliłem gotowym rozwiązaniem na swój trainer pisany w Delphi. Masz opory, to nie musisz korzystać. Należy rozróżnić ułatwienia w grze bez wpisywania kodów z trybu developerskiego, od łamania zabezpieczeñ w grze. Nie jest to imo to samo. Pozdrawiam.

Dodaj komentarz

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Pingbacks (0)

› No pingbacks yet.