Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  14 1787
Tjohei. Jeg runda Hitman Bloodmoney her om dagen og fant det for godt å skrive en liten artikkel om hvordan man kan lage en trainer til det.

Egentlig ville jeg vise hvor mye rart man kan gjøre hvis man lærer seg litt assembly. Alt av programkode er utsatt for endring, så man kan endre på programmer til å få den oppførselen _du_ vil at de skal ha. I dette tilfellet skal jeg bare vise kort hvordan man kan gå frem for å få uendelig liv og ammo i nyeste hitman.
Tools:
Tsearch v1.6 - kjekt "gamehacking"-program
IDA pro - Disassembler og Debugger

Hitman Bloodmoney fixed exe av Reloaded, slik at vi slipper beskyttelsen mot debuggere etc. Denne releasen er vel egentlig flawed har jeg hørt, men funker greit nok til at vi kan bruke den til å lage en trainer.

Del 1 - Å finne minneadressene til ammo og liv.

Fyr opp Hitman. Sørg for å kjøre spillet i "windowed mode", så slipper vi trøbbel når vi debugger det. Start på et vilkårlig brett, men sørg for å ta med deg en pistol eller no. Fyr så opp Tsearch. Velg "Open process" og finn HitmanBloodMoney.exe. I spillet: Ta opp våpenet og se hvor mye ammo du har. I mitt tilfelle står det 9/36. Det betyr 9 skudd i clip'et og 36 tilsammen i alle clip'ene. Trykk deretter på forstørrelsesglasset i Tsearch der det står "Init new search". La det stå på "Exact Value" og "4 bytes", men skriv inn 9 som value. Trykk OK og la den søke seg ferdig. Det kan ta litt tid, mye minne å søke igjennom =)
OK, jeg fikk 24481 treff på verdien 9. Det kan variere fra gang til gang så ikke bry dere med det. Cluet her er å få disse treffene ned til så få som mulig, helst 1.
I spillet: Skyt et par skudd for å dekrementere ammo. Jeg har nå 7 skudd i klippet. I Tsearch trykker du nå på forstørrelsesglasset med tre punktum under. "Search next". Skriv inn verdien 7 og søk videre. Nå er det bare 13 treff hos meg =) Gjør det samme en gang til. Skyt litt og søk igjen. Jeg får tre minneadresser som alltid inneholder antall
ammo i clip. Mine adresser er:

289D3314
28A19600
29347BC0

Dere vil ikke få samme adresser, siden spillet allokerer minne forskjellig hver gang et brett starter. Dobbeltklikk på hver av de tre adressene for å få dem over i det andre vinduet. Nå må vi finne ut hvilken av disse tre som er "dominant". De to andre adressene er altså kopier av den dominante og ikke like viktig. Det kan vi gjøre ved å check'e den
checkboksen ved adressen vi vil teste. Du vil få et lite smilefjes i checkboksen. Dette indikerer at minneverdien er "låst" og ikke vil endre seg. Jeg prøvde først på den første av minneverdiene. Gå inn i spillet og skyt et skudd. Jeg mista et skudd, så denne adressen er ikke riktig. Prøv så neste. Wee. Den funka! Vi har nå uendelig ammo.
Men det jeg vil gjøre er å endre på selve programkoden slik at den ikke dekrementerer ammo, isteden for at Tsearch sitter og skriver en verdi til spillets minne hele tiden.
Velg "AutoHack" menyen til Tsearch og trykk på "Enable Debugger". Høyreklikk på adressen vi fant og velg "Autohack". Ta så opp "Autohack"-vinduet ved å gå på menyen.
Gå inn i spillet og skyt et skudd. I autohack-vinduet dukket dette opp hos meg:

5140AB: mov [esi+0x94], ecx

Dette er altså assemblyinstruksjonen som legger inn ny ammoverdi i ammovariabelen. Ved å NOP'e denne instruksjonen vil den aldri bli eksekvert og vi vil aldri miste ammo. NOP står for "No operation" og er en assemblyinstruksjon som ikke gjør noe som helst.

Skriv ned adressen til denne instruksjonen: 5140AB

OK, da har vi uendelig ammo. Nå over til noe mye vanskeligere, å finne adressen for liv. Her har vi ikke bestemte verdier å gå ut ifra, bare en liv-bar. Vi vet heller ikke hvilken
datatype som er brukt til å representere liv. Det kan være en byte, en word, en dword, en float eller en double. Av erfaring vet jeg at det er ganske normalt å bruke float,
men det er ikke alltid tilfellet. En annen ting er at vi ikke vet mengde liv vi har i utgangspunktet, så vi kan ikke søke etter en "exact value", slik som vi gjorde for ammo.
Her har jeg dessverre ingen "oppskrift" på hvordan man skal gå frem. Det jeg gjorde var vel mer eller mindre gjetning. Jeg fant ihvertfall at verdien til å begynne med er 150.0
i float (vanligvis er det 100,150,200 etc), og at koden som endrer verdien er på adresse 005FB617. Instruksjonen på denne adressen er:

fstp dword ptr [esi+0xFA4]

Dette er en floating point instruksjon som lagrer en float på adresse esi+0xFA4. Problemet her er at koden før den her sannsynligvis har en fld-instruksjon eller noe lignende, og den må vi også huske å fjerne hvis vi skal NOP'e ut denne instruksjonen, ellers blir det feil på fpu-stacken. For dere som kan assembly blir det som om vi push'er en verdi, men glemmer å pop'e den. Jeg brukte ihvertfall ida pro til å se på koden rundt den adressen der. Å disassemble spill i ida pro kan ta svært lang tid btw, siden den
er så nøye =)

.text:005FB60D fld dword ptr [esi+0FA4h]
.text:005FB613 fsub dword ptr [esp+8]
.text:005FB617 fstp dword ptr [esi+0FA4h]

Her er ihvertfall koden. Vi vil helst NOP'e alle disse instruksjonene. Det er 17h-0Dh = 10h = 16 bytes. Siden en NOP bare er en byte må vi altså fyre inn 16 NOP's på adresse 005FB60D.

Vel, da har vi alt vi trenger for å lage en trainer.

Vi må bare NOP'e bort disse instruksjonene:


6 bytes:
5140AB: mov [esi+0x94], ecx

16 bytes:
5FB60D: fld dword ptr [esi+0xFA4]
5FB613: fsub dword ptr [esp+8]
5FB617: fstp dword ptr [esi+0xFA4]


Del 2. Kode en trainer.


Her har jeg kun tenkt å ta med koden som er relevant for å NOP'e instruksjonene. Ikke noe fin GUI eller noe sånt. Jeg valgte dessuten å kode traineren C# siden jeg lærte
det for et par dager siden og vil øve meg =) En ordentlig trainer burde selvfølgelig ha muligheten til å fjerne cheaten igjen, men det orker jeg ikke kode inn nå. Det er uansett
en smal sak å skrive de orginale bytene tilbake istedenfor NOP's (0x90).

Her er koden min. Det skal vel bare være å paste inn f.eks
i eventhandleren til en knapp eller no.

Kode

            IntPtr hWnd = WIN32API.FindWindow(null, "Hitman Blood Money");
            uint processId;
            WIN32API.GetWindowThreadProcessId(hWnd, out processId);
            IntPtr hProcess = WIN32API.OpenProcess(0x1F0FFF, false, processId); //0x1f0fff = PROCESS_ALL_ACCESS
            IntPtr nBytesWritten;
            uint oldprotect;

            //Uendelig Ammo
            IntPtr lpAddress = new IntPtr(0x5140ab);
            UIntPtr dwSize = new UIntPtr(6);            
            WIN32API.VirtualProtectEx(hProcess, lpAddress, dwSize, 0x40, out oldprotect); //0x40 = PAGE_EXECUTE_READWRITE            
            byte[] lpBuffer = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
            WIN32API.WriteProcessMemory(hProcess, lpAddress, lpBuffer, dwSize, out nBytesWritten);


            //Uendelig liv
            lpAddress = new IntPtr(0x005fb60d);
            dwSize = new UIntPtr(16);
            WIN32API.VirtualProtectEx(hProcess, lpAddress, dwSize, 0x40, out oldprotect);//0x40 = PAGE_EXECUTE_READWRITE
            byte[] lpBuffer2 = {0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
            WIN32API.WriteProcessMemory(hProcess, lpAddress, lpBuffer2, dwSize, out nBytesWritten);

            WIN32API.CloseHandle(hProcess);
Og her er koden min for WIN32API klassen:

Kode

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

namespace HitmanTrainer
{
    class WIN32API
    {

        public static bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect)
        {
            return API.VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect,out lpflOldProtect);
        }

        public static IntPtr FindWindow(string lpClassName, string lpWindowName)
        {
            return API.FindWindow(lpClassName, lpWindowName);
        }

        public static uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId)
        {
            return API.GetWindowThreadProcessId(hWnd, out lpdwProcessId);
        }

        public static bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead)
        {
            return API.ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
        }

        public static bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr nSize, out IntPtr lpNumberOfBytesWritten)
        {
            return API.WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, out lpNumberOfBytesWritten);
        }

        public static IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId)
        {
            return API.OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
        }

        public static Boolean CloseHandle(IntPtr hObject)
        {
            return API.CloseHandle(hObject);           
        }

        internal class API
        {
            [DllImport("kernel32.dll")]
            public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
               UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

            [DllImport("user32.dll", SetLastError = true)]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

            [DllImport("user32.dll", SetLastError = true)]
            public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

            [DllImport("kernel32.dll")]
            public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle,
               uint dwProcessId);

            [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
            public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
               [Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);

            [DllImport("kernel32.dll")]
            public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
               byte[] lpBuffer, UIntPtr nSize, out IntPtr lpNumberOfBytesWritten);

            [DllImport("kernel32.dll")]
            public static extern Boolean CloseHandle(IntPtr hObject);

        }
    }
}
Sist endret av Evinyatar; 31. mai 2006 kl. 15:32.
Pip-Boy 3000
Grimdoc's Avatar
Donor
Takk for at noen tar seg bryet med å skrive slike lange og bra poster.
Kommer nok ikke til å prøve men, vil ikke jukse meg til seier i det
Hehe, nei, jeg ville ikke jukse jeg heller =)

Fant frem noen urls til steder med mer info om gamehacking, i tilfelle noen var interessert.

http://www.ghu.as.ro/
http://www.cheaters-heaven.com <- de har en tutorials seksjon
http://www.gamehacking.co.uk/ <- tror man må være regga for å lese tuts her
http://www.gamehacking.com/ <- virker ganske nyoppstarta. kommer sikkert tuts her etterhvert.
#gamehacking@efnet

EDIT: for litt mer avansert gamehacking kan dere søke etter [sheep] sine tuts

http://www.fhcf.net/tutorials/02.zip <- norsk gamehacking tutorial jeg skrev for lenge siden. hvordan man kan traine starcraft ^^
Sist endret av Evinyatar; 2. juni 2006 kl. 16:15.
▼ ... over en uke senere ... ▼
hvis du holder på med cheat programmering er http://gamedeception.net siden, jeg vil si gd er de "ledende" utviklerne for cheats i mange spill. Står utrolig mye nyttig der.
http://www.cheatengine.org/ liker de forumene ganske godt også!
▼ ... over en uke senere ... ▼
Hvis jeg hadde gjort dette når jeg spilte cs, hadde det blitt VAC ban på meg da?
m0b
m0b's Avatar
DonorAdministrator
Med nettverksspill og slikt så går det meste av informasjon fra serveren og til klientene, så det vil sannsynligvis ikke virke i det hele tatt. Dessuten har vel CS en hel del sjekking av slikt, bli oppdaget med én gang og du får sikkert ikke joinet server engang.
Kan du poste hele koden til traineren?
Jeg kan ikke C godt nok til å skrive den selv.. så for det meste er denne tutorialen nytteløs for meg.
m0b
m0b's Avatar
DonorAdministrator
Grantax: Traineren er skrevet C# og ikke C. En vesentlig forskjell mellom de to språkene. Dessuten tror jeg egentlig du kun har lest igjennom denne tutorialen, og ikke faktisk prøvdt ut sakene selv for og så hvordan det funker. Dessuten er det der all kode du trenger for å få dette til å funke. Det vil si, utenom "standard" koden til å få et program opp å gå.

Hvis du det hadde gjort, så ville du straks funnet ut av ved metoden han har brukt her så ville du faktisk funnet feil adresse til 5140AB. Snakket med Evinyatar for en stund siden angående dette, og vi fant ikke helt ut hvorfor adressen ble feil. (du må legge til 200 ellerno på verdien du får, for å få rette verdi) Men vi fant i alle fall ut at du får rett adresse ved å kjøre dette i ollybg.
For det første har jeg ikke bare lest.
Til å begynne med prøvde jeg å få evig liv på et spill laget med Game Maker som heter Terav. (Med online score også )
Fikk det til, når jeg fant ut at det var lagret som double.
Sitter nå med denne:

402A74: std

Edit: Etter mer undersøkelse ser det ut som om Game Maker er et minnekrevende program, siden det tydeligvis lagrer alle tall som double..

Edit: Etter enda mer undersøkelse fant jeg ut at uansett hvilken adresse jeg 'Autohacker' så ender jeg opp med 402A74: std.. er vel fordi at game maker ikke kompilerer spillene skikkelig..
Sist endret av TanteSpiker; 25. juni 2006 kl. 23:00.
Litt OT: men er spillet bra? Har rundet de andre og vurderer å kjøpe meg det nye spillet
Ja, spillet er kjempebra. Jeg har syntes toeren av de tre første var best, men lurer på om Blood Money får min førsteplass av dem alle.
Bare pass på å få patchet spillet så du unngår bugs o.l.
m0b
m0b's Avatar
DonorAdministrator
Okey, vel - laget en lynkjapp trainer sak. Det du trenger å gjøre her er å lage en form med to knapper, av og på. Så linker du knappene mot funksjonene CheatOn_Click og CheatOff_Click. Har kun laget et vanlig IDE-generert prosjekt med Visual Studio, så denne filen vil eksempelvis erstatte form1.cs


(dersom du vil at koden skal vises skikkelig må du faktisk bruke Internet Explorer)

Kode

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace HitmanTrainer
{
  public partial class Form1 : Form
  {
    [DllImport("kernel32.dll")]
    public static extern bool VirtualProtectEx( IntPtr hProcess, IntPtr lpAddress, 
      UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect );

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle,
       uint dwProcessId);

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
       [Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);

    [DllImport("kernel32.dll")]
    public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
       byte[] lpBuffer, UIntPtr nSize, out IntPtr lpNumberOfBytesWritten);

    [DllImport("kernel32.dll")]
    public static extern Boolean CloseHandle(IntPtr hObject);

    public Form1()
    {
      InitializeComponent();
    }

    private IntPtr hProcess;
    private IntPtr nBytesWritten;
    private uint oldProtect;

    private void Form1_Load(object sender, EventArgs e)
    {
      IntPtr hWnd = FindWindow( null, "Hitman Blood Money" );
      uint processId;
      GetWindowThreadProcessId( hWnd, out processId );
      hProcess = OpenProcess( 0x1F0FFF, false, processId );
    }

    // Cheat på-knapp
    private void CheatOn_Click(object sender, EventArgs e)
    {
      IntPtr lpAddress = new IntPtr( 0x5140ab );
      UIntPtr dwSize = new UIntPtr( 6 );
      VirtualProtectEx( hProcess, lpAddress, dwSize, 0x40, out oldProtect );
      byte[] lpBuffer = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, };

      WriteProcessMemory( hProcess, lpAddress, lpBuffer, dwSize, out nBytesWritten );
    }

    // Cheat av-knapp
    private void CheatOff_Click(object sender, EventArgs e)
    {
      IntPtr lpAddress = new IntPtr( 0x5140ab );
      UIntPtr dwSize = new UIntPtr( 6 );
      VirtualProtectEx( hProcess, lpAddress, dwSize, 0x40, out oldProtect );
      byte[] lpBuffer = { 0x89, 0x8e, 0x94, 0x00, 0x00, 0x00, };

      WriteProcessMemory( hProcess, lpAddress, lpBuffer, dwSize, out nBytesWritten );
    }
  }
}
Sist endret av m0b; 1. juli 2006 kl. 15:25.
▼ ... over en uke senere ... ▼
Sitat av Evinyatar
[b]T I dette tilfellet skal jeg bare vise kort hvordan man kan gå frem for å få uendelig liv og ammo i nyeste hitman.
Vis hele sitatet...
skjønner facsinerende lite om koding, men har jeg forstått dette rett handler dette om å få uendlig ammo å liv på Hitman: BloodMoney?

klart ar man kan jo gjøre det på den vanskelig måten, eller så kan man ;

1. søk etter Konfigurasjonsinnstillings mappen som heter "HitmanBloodMoney" (på min data; CProgramfiler\Eidos\Hitman Blood Money)

2. dra nå denne inn i gode gamle notisblokken, da vil du få en tekst som ligner denne;
Resolution 1024x768
StartUpperPos 0,0
DefaultScene=HitmanBloodMoney.gms
ReadMainIni 0
Audio_Volume_Sfx 100.000000
Audio_Volume_Dialog 100.000000
Audio_Volume_Music 100.000000
Audio_Volume_Ambience 100.000000
Audio_Volume_Movie 100.000000
SelfShadows 0
PostFilterLOD 0
LevelOfDetail 0
Anisotropy 0
BlurShadows 1
ShadowDetail 1

Så tar man enkelt å greit å legger en fin tekst ved navn " EnableCheats " mellom DefaultScene=HitmanBloodMoney.gms, og ReadMainIni 0 altså;
Resolution 1024x768
StartUpperPos 0,0
DefaultScene=HitmanBloodMoney.gms
EnableCheats
ReadMainIni 0
Audio_Volume_Sfx 100.000000
Audio_Volume_Dialog 100.000000
Audio_Volume_Music 100.000000
Audio_Volume_Ambience 100.000000
Audio_Volume_Movie 100.000000
SelfShadows 0
PostFilterLOD 0
LevelOfDetail 0
Anisotropy 0
BlurShadows 1
ShadowDetail 1

PS! lag en backup på gamle kodingen. ellers... skyld deg selv


3. gå nå inn i spillet, velg en map, å vent til hitman er klar for action, nå trykker man enkelt å greit på knappen "C" å man vil nå få opp en meny i gul tekst, fks,

0 Godmode. Bruk piltastene å gå ned til GodMode å bruk fks. scrollern til å bytte ut 0, med 1. trykk nå ESC.

Have Fun
Sist endret av rotskrot; 14. juli 2006 kl. 04:13.
Sitat av rotskrot
skjønner facsinerende lite om koding, men har jeg forstått dette rett handler dette om å få uendlig ammo å liv på Hitman: BloodMoney?
Vis hele sitatet...

Det var vel heller ett eksempel på hvordan man skriver en trainer, vil jeg tro.