Sie sind auf Seite 1von 805

Gamehacking Archive @ GHA Offline Version

by Razali Rambli @ ßié


http://www.bie.cjb.net | razali_bie@hotmail.com

Gamehacking Archive @ GHA Online Version


by ^chaos^
idxchaos@hotmail.com
The Best Gamehacker

you woke in a sunny day


and jump in the chair to play.
start the game and load a save
and you say in mind : <<let's rave !>>

but you can't bypass a boss


all you see is : "you have lost"
red and pissed you couldn't play,
you go search cheats for the game.

but what you could find is : nothing !


and that monster is still laughing...
<< argh >> you say, << this isn't fair !
i can't beat him in his lair ! >>

then you go to school - good boy


drained of life, without no joy
a friend stops his words at you
having the same problem, too...

but he said he knew a way


teaching you to make your day.
getting back home from the school,
having TSearch as new tool.

this TSearch is like a finder,


helpful when you catch the "gangster"
that's making your life a mess.
acting wisely and not guess...

you're now home... you ran the way


feeling in shape in that day.
as soon as you're in your chair,
you feel water drops in hair...

start up TSearch, then choose game


nothing here you have to say...
write down the value you want -
it's as easy as a charm.

select byte-type, and press find


lot of addresses will shine
after that, back to the play
shoot the monster in your way

what's the thing that can be next ?


pause the game will be the best.
then it comes the same routine :
alt+tab in the TSearch's screen !

type in there the newest number,


since the wanted is now less.
and press next - you'll see the progress
2-3 addresses should struggle...

illuzions are in your head


you don't know which one to choose -
like a little baby goose
in front of the milk and bread...

everything's unclear for you


all is darkness, all you see
"shadows move where light should be"
and your mind don't have a clue.

but something comes from the sky


like a magic bowl of light
then it steps out of your sight
and your wet hair becomes dry...

yes, that is the inspiration


holy power blessed on us,
helps on what you want to pass
by the nature of it's creation.

and now you say to yourself :


<< why didn't i think of it ?
play around a little bit
with the addresses and health ! >>

from now on you think more clearly


seeing with the cells of mind
because your eyes are still blind
not knowing what's far, nor nearly...

and because of that you stop.


poking random numbers might
turn the game into a flight
from where nothing will be pop...

you decide to try once more


hoping this time will be better,
'cause for game it doesn't matter
you are pressed by time's huge floor.

as soon as you're back to game


shooting fire after fire,
throwing knives and cut the wire -
you'll hurt the monster again.

switching back now to your friend


seeing what you did is right
you roar with the lion's might :
<< in the hell you will be send !! >>

so, you find the correct place


and by instinct you poke zero
turning you into a hero,
blowing the monster in space...

filled with joy is all your heart,


happy time and inner trust !
watching back into your past
realise hacking's an art...

from that tiny moment on


all the games you'll ever play
on your desk arranged will stay
waiting gamer - but he's gone...

yes, he's gone and won't come back...


instead there will be a hack.
and not Kevin, Mat, John, Jack,
nor Michelle, Paul, Roy or Black.

lifeless robot now you are


without any human feeling
cheating's all that you are willing
bowing to the hacking star...

minutes, hours, days were passing


you work hard without relaxing...
in short time there will you be -
hacking bullets, mana, money !

everything that can be hacked


in your little brain is packed...
then you start to read some tuts
teaching how to speed the boots,

how to break through metal walls


and to throw the cannon balls...
then you read about new tools,
considered expensive jewless.

you went get'em right away


preparing yourself to "play"...
examining one by one,
thinking this will bring more fun !

amoung them it is SoftIce


a debugger they had said
used to be the chief, the head
in catching\backtrace the dice...

but for wearing this grand jewel


and to find the wanted place
you need to practice for days
'cause it doesn't like the foul !

you start practicing... OK...


venturing in cracking's wood
you find there a realm so rud,
that you don't quite feel to stay...

but you want to be the best


and SoftIce it is a must.
so you start by breathing dust,
in your little, tiny chest.

after you became an "icer",


after tones of cracked examples,
after learning breaking samples,
you find out SoftIce's view nicer...

but this route to cracking's world


not just made you SoftIce's master
but your mind's now thinking faster,
realize : << SoftIce is gold !>>

also, the tools didn't stop...


so well-known in realm of cracking -
Hacker's View on you is watching
guiding you to be in top...

another friend you had made


it is called WinDasm, i think.
dissasembles in a blink
every program, on the plate.

yes, you're now feeling the power


cracking world was very funny
but you want to "load" the journey
in hacking, from where you were...

you are more relaxed right now...


Hacker's View, WinDasm, SoftIce
are there to help you to rize
and to strike the shaddows down...

so you take one random game


for testing the newest tools
then you scream << those cool tools rulez !>>
and in that day you're insane...

your feelings are comming back,


you're playing the games with passion.
but you soon fall for the fashion,
transforming all into hack...

you are ill of this "hack life"


the dissease don't have a cure
the game's hacked - that is for sure
but everything's black and white...

after that you find a trainer


for a game you hacked before
testing it and test some more,
you decide you were a lamer...

but why's that ? how had this been ?


you had done more advanced hacks,
but you're blaming on your acts
'cause your work cannot be seen...

so you're hunting now the fame


what good if you are the best
if you're not known by the rest ?
AND THIS THINKING MADE YOU LAME...

then you release tons of trainers,


you're well known to all the people
everything is now more simple !
you can flirt with hacking's majors.

years were passing over you


without feeling changing-wind
sing and hacking, hack and sing
<< i'm one of the best, yahoooo !>>

that was true, nothing to say


but according to your thinking,
to be well-known you were willing !
now and forever that way...

here you did the big mistake


instead of writing hack ways
you've just made trainers in place
and all the fame was a fake...

all the trainers that you've written


for a favorite public game
when that game had lost it's name,
your creation was forgotten...

soon you'll have yourself a life


a wife and maybe some kids
hacking don't belong your needs
and it's throwed the forget-dice...

and the nasty thing of life


is that this cannot be hacked
it's a kind of a huge stack
and push\pops belong to dice...

and this thing cannot be touched


WinDasm, Hacker's View can't help
and the rolling dice can melt
even mighty SoftIce's bright !

then you'll look back in the past


nostalgy will rize in mind
realising you were blind,
you'll pray you won't be the last...

and you're not, i can tell you


in the day you'll pass the throne
another kid will be born
choosing the hacking path, too.

day by day as he'll be grown


he wishes to become the best -
and like you, won't be the last
and so on... and so on...

Prof. Dr. Sorin

"De-oi urma să scriu în versuri, teamă mi-e ca nu cumva


Oamenii din ziua de-astăzi să mă-nceap-a lăuda.
Dacă port cu usurintă si cu zâmbet a lor ură,
Laudele lor desigur m-ar mâhni peste măsură"

Mihai Eminescu
Know more link? Email me razali_bie@hotmail.com with subject line "More Link For Gamehacking Archive", email with different subject will be ignore.

Gamehacking Team Homepage:

Devious
Extalia
CES
GHU
X2

Gamehacker Homepage:

Sheep - Trainer for PC and Xbox, Tutorial on PC and Xbox, Gamehacking Tool
Eedok - Trainer, Gamehacking and programming tutorial, Java Games
Bie - Simple game Trainer, downloadable tutorial [GHA], Simple Gamehacking tool
Brzi -Trainer, Tutorial, Gamehacking Tool
Dopey - aka Tsongkie
Shinero - Trainer, Gamehacking and programming Tutorial.
Shaikh Adeel - Trainer, Gamehacking tutorial.
DDH - Tutorial, source code.
Victor D Wolverine - Trainer and Trainer source code, Gamehacking tutorial.
Rainy - Source code, Trainer and tutorial.
NTSC - The person who inspired me to involve with Gamehacking. Tutorial & Trainer.
Primal Secret - Trainer, Gamehacking and hacking tutorial.
Snake & Max Power - Trainer, Gamehacking and Programming Tutorial, Source code and Gamehacking tools
Whiteys - Trainer and Tutorial
eVoByte - Tutorial, Crackme and Tools

Once a great gamehacker homepage:

Chaos - Down 19 March 2004


GlomYar - Down 19 March 2004

Programing Homepage:

Iczelion's Win32 Assembly Homepage [Masm32]

Memory Searcher:

Tsearch
Artmoney
Gamehack

Trainer Maker Kits:

TMK - Easy trainer maker for newbie


GTS - Best ASM Trainer Maker

Misc Tools

SAS - Code Cave Tool by Sheep

Gamecheater Homepage:

http://www.xcheater.com/
http://gameguru.box.sk/
http://www.pccheater.co.uk/
http://happysurfer.com/cheats.html
http://www.cmgsccc.com/ps2/

Game Programming: Learn to create games

Game Programming University [Free]


User comment:

User Comment
Shinero Pretty fuc.kin nice
.empty. cool now all the Newbie here download read it love it and do it.
[3y3]$!nn3r really gr8 work! keep it up
Neat stuff.

One should sticky this one as it's a pretty good reference.


Christoph
greets
Christoph
Xanatos Nice

Sorin SUPERB
hey! that's me!!!: real picture of us. other gamehacker who want to put they picture here, send zip picture & email to me razali_bie@hotmail.com

ßié (Bie) Eedok& DGF joeismyname micral Renzo

Malaysia Canada Vietnam

Dopey Synbios Hotfloppy D.N.A eVoByte

Philippine Malaysia England

erhan
Killing DMA and making Trainer

I- Table of contents:

I- Table of contents :)
II- Thanks
III- Needed Tools
IV- Basic about Game Hacking
V- Kill DMA with TSearch 1.4a
VI- How to kill DMA in your trainer with Trainer Maker Kit
VII- Using Anti-TrainerSpy in your Trainer
VIII- Contact

II- Greetz goes to....

MiCRaL
Shaikh Adeel
Tsongkie
Vivien Abner
MacDeath ťť Thanks for fixing errors with my english...

III- Needed Tools:

First of all, you'll need a brain :)


Little knowledge about Memory Finder
Little GameHacking knowledge
TSearch 1.4a (I'll call it TS1.4a) - This tool is fast and free....I like it too.
Trainer Maker Kit 1.51 (I'll call it "TMK")
Trainer Spy (I'll call it "TS") - It's only for testing your TS protection
Monopoly Tycoon (v 1.0 #516) - I'll hack this game.
IV- Basic about GameHacking:

Before you make a trainer, you'll need:


1- Your Brain - It's very important
2- Patience - It's important too.
3- Tools
4- Address of value.
5- Knowledge in any language or you can use TMK.

V- Killing DMA with TSeatch.

Now we have the address. Let's add it in to TSearch hack table. First of all you need select select
Monopoly Tycoon in the process list.
If you don't know how to select it, read my tutorial about TSearch.
P.S.: You can get the address with differents tools and use TSearch to kill DMA only.

Now we need the Description (Money Hack) of the cheat, Address (Yet? Yeah!!!) and Type (Float)

Cool. We have total control of this address now. Let's remove the DMA!
Click "AutoHack" / "Enable Debugger"

Now, click "AutoHack" / "AutoHack window"

We will see the "AutoHack" Window

Back to TSearch (ALT+TAB). Click "Money Hack" (with the right button) and click "AutoHack"
Well, now you'll need to go back to "AutoHack" window (ALT+TAB)
You'll see "crazy codes". hehehe ;)

Now it is easy to kill DMA. Back to the game (ALT+TAB) and build any item. Go back to the AutoHack
window and BINGO!!!
To test if it will work, you'll use the two selected images.

Freeze image: Click here and go back to game (ALT+TAB), build any item, and see if your money
doesnt decrease.
Unfreeze image: Click here and go back to game (ALT+TAB), build any item, and see if your money
decreases.
If the two icons work, CONGRATULATIONS! You have killed DMA!
Now you can make a trainer. Use any programming language or TMK....i'll help you with TMK.....Let's go!

VI- Using TMK to make a Trainer

Start a new project and add one button...


Right-Click in Button and click in "Write memory actions"

I'll see the "Code-Editor"


Now, get your code (in my case is Poke XXXXXX 909090 --ť U get it with T-Search) and post here....

Save your project and compile ;)

VII- Using T-Spy protection in TMK trainer

Its very easy, only insert Poke 0 FF 52 19 FF XX in your code....


P.S.: XX is number of your button option in HEX, in this case is 01
ťť Tutorial by [D.N.A] ŤŤ
tekz (c) 2002
do not use without permission our plz

contact : dna.netz@ig.com.br
Gamehacking Tutorial

Last Update: 2004-04-16

Subject: Dynamically Allocated Chunks of Memory


Basic --> Intermediate Game Hacking
Author: Sain
Notes: This wont work on win95,98,ME, though you can do it another
way. Some person who cares may enlighten you. Not me though
Other Notes: I am not affiliated with any Game Hacking group, nor do I
release trainers. Don't bother asking me to write one for you.
If you want assistance with a problem ask and I might help.
Thanks to: [Sheep], for being the only person around who answered a
question.
-------------------------------------------------------------------------------

Alrighty, lets get started. The target game for todays tutorial is 3D Pinball.
The game is ideal for us, basically because most people will have it (it comes
with Windows XP, 2000 etc), and its easy as hell to train.

Our object today is to train the game using a "code cave" (gah! I hate that
phrase) that we add to the program with our trainer, rather than the usual
process of searching through the program for one that already exists. This is
useful for when you want to do things like using entire c++ functions, or for
launching custom dlls into a process.

oh yeah, and you'll need tsearch or some other memory searcher and a debugger

Step 1 - Find your balls


========================
Okay, this is really simple and shouldn't present a problem for anybody. Use
tsearch or whatever to find the memory location for the number of balls left.
If you have any trouble, try working backwards from 3.

I got 0x90314e as the location for my balls, yours should be different.

Once you have found your balls, whop a 4 in (so we have some balls to play
with) and then fire up autohack (go to the autohack menu and hit the enable
debugger item, then the autohack window item). In the autohack window set
a breakpoint on the address you found (just a write breakpoint will do)
and then go and lose a ball. Once you've lost the ball autohack should
have the line which modified the ball count. It should be remarkably similair
to:

1015f02: mov [esi+0x146],eax

which means move the value in eax into the memory location pointed to by [esi+0x146]

Step 2 - Create a standard Code Cave


====================================
Right, now we know where to insert our jump to the code we are going to inject,
we need to figure out that code and where we are going to inject it. For now
we are going to inject the code at 0x10bc0 (this will change later, when we
flip to a dynamically allocated memory block).

Fire up the tsearch easywrite thing, and put the following in the top section
(don't bother with the <-- stuff)

offset 0x10bc0
cmp eax,0x1 <-- compare the number of balls left to 1
jg 0x10bca <-- if we have more, skip the next line
mov eax,0x3 <-- if we have less, give em 3 balls
mov [esi+0x146],eax <-- write the number of balls left back
jmp 0x1015f08 <-- and return to just after we jumped
here

offset 0x1015f02
jmp 0x10bc0 <-- jump to our injected code above
nop <-- do nothing (for neatness)

and the following in a bottom section:

offset 0x1015f02 <-- restore the origional program code


mov [esi+0x146],eax <-- just moves the number of balls left
into the memory location

Alrighty, try it out. For those whos assembler isn't crash hot, here is whats
going to happen when the game goes to write the new number of balls back: it
jumps to our code, where its compared to 1 (i.e 1 ball remaining). If there is
more than 1 ball left the number is written back as normal, otherwise 3 balls
are written back. That code is much more complex than it needs to be for our
purposes, but it will help to illustrate relative addressing (later).

At this point we have successfully trained the game, using a "code cave" to
"defeat" "DMA" (lots of phrases i hate). Everything beyond this point is
optional, and you'll probably only use it when your injecting complex code,
such as an entire c++ function.

Step 3 - Dynamically Allocated Caves


====================================
This is where things get a little trickier. Take a look at the disassembler
dump for the address 0x1015f02 - it should look something like:

01015f02 E9B9ACFFFE jmp 0x00010BC0

Breaking that down the E9 is the jump instruction and the B9ACFFFE bit is the
address to jump to, or more accurately, the distance to the address to jump to
from the end of the instruction.
This means is the trainer is going to have to figure out what these 4
bytes are at run time. Lucky you - i'm going to provide you with a function to
do that (in c - i'm sure you asm gurus can convert it on your own):

void GenerateJmp(unsigned char *code,unsigned char *JumpDestination,


unsigned char *JumpSource=0)
{
if (!JumpSource) // if the user hasn't specified a source address
JumpSource=code; // assume we are writing at the "code" location

*code++=0xe9; // the jmp command

// the next line calculates the 4 bytes of the destination address


// which is simply the address of the destination - the address of the jmp + 5
*((int *&)code)++=JumpDestination - (JumpSource+5);
}

For those who prefer calls to jmps, change the *code++=0xe9 to *code++=0xe8 and
it will work the same.

Next we use VirtualAllocEx to allocate a hunk of memory for ourselves in the


game's process. VirtualAllocEx has the following definition:

LPVOID VirtualAllocEx(
HANDLE hProcess, // process to allocate memory
LPVOID lpAddress, // desired starting address
SIZE_T dwSize, // size of region to allocate
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);

For our purposes we call it like:


DstBlockAddress=VirtualAllocEx(GameHandle,NULL,Number_of_bytes_required,
MEM_COMMIT,PAGE_EXECUTE_READWRITE);

We then have a chunk of memory in the remote preocess allocated just for us
where we can write our code with WriteProcessMemory, pretty much the same as we
normally would, with our trainer adding the jumps on the fly. A function to do
this is as follows:

int CreateDynamicHook(int HookAddress,int RetnAddress,unsigned char *data,int data_size)


{
// At the location specified by HookAddress, insert a jmp to an allocated block
// of memory, insert the bytes contained in data and add a jmp back to the
// location specified by RetnAddress.

unsigned char tmp[6];


LPVOID address;

// attempt to allocate memory in the remote process


address=VirtualAllocEx(phandle,NULL,data_size+5,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (address==NULL)
return 0; // failed to allocate mem

// now write the users data


WriteProcessMemory(phandle,(LPVOID)address,data,data_size,NULL);
// add the return address
GenerateJmp(tmp,(unsigned char *)RetnAddress,(unsigned char *)address+data_size);
WriteProcessMemory(phandle,(LPVOID)((int)address+data_size),tmp,5,NULL);
// and finaly the hook into the program
GenerateJmp(tmp,(unsigned char *)address,(unsigned char *)HookAddress);
WriteProcessMemory(phandle,(LPVOID)HookAddress,tmp,5,NULL);

// return the address, so it can be passed to VirtualFreeEx


return (int)address;
}

Of course you should add better error checking, but I can't be stuffed. In
order to use the function you just pass it the hex values from your code block
(the one we created earlier) without a returning jmp and it will do the rest of
the work for you. So, going back to our pinball code from earlier we would
pass in the hex for the following asm:

10bc0 83f801 cmp eax,0x1


10bc3 7f05 jg 0x10bca
10bc5 b803000000 mov eax,0x3
10bca 8986646010000 mov [esi+0x146],eax

note that the jg is still there. This will still function, because the jg used
a relative offset, meaning it says jump over the next 5 bytes. i.e to the 2nd
mov instruction.
The hex we would pass to the function is:

83f8017f05b8030000008986646010000

And thats it, pretty simple really. Some source code to implement a very basic
trainer for pinball is below. There is lots left for the

Note that it is simpler to use the call/retn method, rather than the jmp, jmp
method shown here.

Enjoy
Sain

-------------------------------------------------------------------------------
File: main.cpp
-------------------------------------------------------------------------------

/* Pinball 3D trainer
** By Sain
*/

/*
** Okay, this is really untidy, but hey, its just to demonstrate how to use the
** dynamicly allocated chunk of memory. Use this for whatever you want, if you
Game-Hacking Tutorial

Target : Heroes II
~~~~~~~~~~~~~~~~~~

Description : Hacking the +buildings/units+ and map-revealing (saved-game hacking


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Tools Needed :
~~~~~~~~~~~~~~

- Hex Workshop

Level : Beginner
~~~~~~~~~~~~~~~~

INTRO
~~~~~

Hello again ! - Tell me I'm not speaking alone - hehehe - I'm not krazy - huhu
Or at least I think so...

Want to learn some saved-game hacking techniques ? If yes then follow this tut
else go and bake a pizza ! I

So... You want to stay, heh ? okye dokey !

Let's Begin
~~~~~~~~~~~

I'm going to show you how to hack a beautiful game : Heroes 2 :)

First, let's think at our hack method -> saved-game_file hacking. This means you
don't need memory searchers or something, just a hex editor (HEXWORKSHOP). I
would make your life "miserable" by throwing SoftIce in the battle, but it
simply refused to collaborate with his video-adapter on this old (but great)
game. So, lucky you - No SoftIce :)

Remark : Maybe you think why would I use SoftIce (a debugger) on this kind of
hacking. Answer is simple : We could trap the game when it reads
data inside that save file after we modify it. For a better understanding,
of course. So a debugger would bring more understanding to you..
Unfortunately, I have only SoftIce and only with it I feel "read
battle", but as I told you, it refused to cooperate... No cookie
you, mister SoftIce ! You're a bad guy !

Ok.... What are you waiting then ? Enter the game, choose to play a campaign and
the good_guy - Roland (the portrait in the right).

Now, pay attention : DON'T do anything in the game ! Don't even scroll the screen
save it under "abc", let's say.
We now have a saved-game file. But what to do with it ? We can search for the
of gold/crystals/gems etc... This will be boring... (I'll show you how to do
too).

Let's try something else... But first note on a piece of paper the amount of each
resource you have : gold/wood/sulfur etc. Now build the "Foundry" in your castle,
and without doing anything else, save the game under "abc1".

The smart-ones of you already guessed what we'll hack - the buildings :) Enter He
and compare the 2 files - abc.gmc and abc1.gmc ! Here's what it should look l

Now... Comes some thinking : We are not interested in "matches", but in replaceme
(because when we build, we don't have only the same buildings, but a new one)
Also, take a look at the replacements number. There are 4 repl. Why's that ?

Well, when you build, the game modify some "things" :


- the resources number (it decrease it)
- some bytes telling that a new building is up (the respective building's ID)
- the "you can't build anything else in this day" flag. This game is TBS (tur
strategy), and this means you and your opponents are playing one at a t
And ALL TBS games let you build only 1 structure in a day. Then you "en
turn", then your opponents will play (you will wait until they finish),
number 2 will come and you can build again, and so on.

But what's the 4th replacement meaning ? Heh.. The game keeps the name of the sav
inside the files. So the repl. is that "abc.gmc" <> (is different from) "abc1
Also, if your mind is sharp enough, would have noticed that when you build a stru
some "monsters" will be available too inside that structure JUST AFTER YOU BUILD
(without being necessary to wait a new week to be able to recruit the monster
This is a VERY IMPORTANT remark, and with it we can distinguish between the
replacements (this replacement is for money, that is for buildings etc).
But with this repl. we have 5. And HexWorkshop says there are only 4. Maybe i
'involved' with one of the 4 repl...

But let's watch them :

Here's the first replacement :

After you noticed, this is because we have 2 saved-files with different names abc
This is not important to us.

The second replacement :

Do you still got that piece of paper where you noted the resources amount ? Take
on them. What ? You get no match ? Hehe, that's because in the save_files the
are in HEX format. Take a look at first 1E. If you convert it in decimal, you get
Look on the paper for 30 and tell me what resource it is. It's wood, right ?
be ore ? Look at the second 1E... Hmm, one could be for wood and the other fo
I bet the first is for wood and the second for ore. :)
In "abc1" file we have 19 instead of 1E. Decimal of 19 is 25. When you build
the "Foundry", the game substracts 5 wood, 5 ore and 1500 gold-> check it in
Now look at E02E. To find it's decimal we take it backwards : 2EE0. And 2EE0 in d
is 12000 (the gold). 12000-1500(foundry_cost)=10500 that is in hex 2904. And
"abc1" file is hold as 0429 (the backwards of 2904). See ? And the other reso
those "000A". If you don't believe me, modify them, then load the respective
then see for yourself !

So we found out where the resources are stored. Great !

Let's look at relp. no 3 :

First look at that 04 in "abc1". Can it be the amount of new monsters that you ca
JUST AFTER you build something ? To be sure go back in the game and click on
"Foundry". You can recruit 4 Golems. YES ! Change that 4 in 20, for example,
result :) And take a closer look at the following 00 (with a red underline).
be the amount of other monsters you can recruit from the other structures. So
build their respective structures, modify their amount as you please. (they a
as word).

Now look at that 38. It doesn't look familiar to us. It can be that "no more buil
flag, or the "Foundry"'s ID. Because it is near to that "4 golems", we can pr
it's the ID.

But it is not changed from 00, but from 18 (look in "abc"). So here we make anoth
supposition : if we want to have all the buildings, we could try to set that
a big number (it was 18 when we hadn't had the "Foundry", it is 38 when we have t
"Foundry", let's set it to FF hoping to have all buildings :) ). But usually
use just a single byte for this, but a word or d-word. Let's try with d-word.
next 4 bytes from that 2C into this : First byte in FE and the next 3 in FF.
Because I tried with FF to all, but the game crashed :(. So you'll have this

... 0000 2CFE FFFF FF 00 ...

Load the saved and voila ! All buildings except... MageGuild :(. No problem. Buil
Guild, then compare the new saved file (with Mage-Guild) with the one in whic
don't have Mage Guild. Then compare.... But to save you from this I'll tell y
to work with the MageGuild. Remember the above bytes that I told you to trans
FF ? After the last FF it comes a 00, right ? Change that 00 to 04.
Like this :

... 0000 2CFE FFFF FF 04 ...

Why ?
To have level 4 Mage-Guild. Why level 4 and not level 5 ? Because YOU MUST bu
least a level of Mage-Guild to let the game initialize the spells, or else you wi
not have any spell in the guild (or you could "initialize" them yourself by c
the next ~22 bytes after the last monster recruiting_amount (see above the re
to any numbers that you might think of.
Then go back in the game too see the result. You can crash the game or :
- you can get all the spells in the MageGuild;
- you can get some ultimate artifacts like 'Ultimate Sword of Dominion' o
EVERY HERO that you hire from that castle (a programming bug?);
- some skrewling like "Expert on Set Water Guardian" as a SKILL;
- you can upgrade, for example, the boar to golem then to steel_golem (an
- many many other kool things.

As you might noticed, these are castle specific. They can be called "castle prope
you scroll down from the replacement, you'll see the castle name. So, when yo
castle name, you can edit its properties by changing the bytes above its name

If you scroll up from the replacement, you'll notice some FFs followed by some 00
them too, to see what's happening. The FF means nobody is in the garrison of
in the FF's slot. There are 5 slots where you can leave some army. Change the
other values (monsters IDs) to have army in respective slot, and change the r
00 to desired amount of troops. So FF place stands for monster type and 00 st
monster quantity in the garrison of the respective castle.

And finally comes the last replacement :

Only one thing can this mean : the "one_building_per_day" flag.


You see, we have 00 in "abc" file (when we haven't build anything) and 08 in
when "Foundry" was build. So, 00 means we can build a structure today, and 08
we can't build anymore today because we already build something.

Ahh... What beautiful life...

"In the sky Sun is the king


And the Clouds were in his army...
But they trade him for the Wind
Who's colder and not so shiny."

Speaking of sun, let's try to make a map hack in Heroes 2, using this saved-game_
hacking method. This map_cheating will be all we need, cause we've just found
hack resources/army/castles/spells (we can cheat as well on enemy_castles/her
your imagination ;) ).

So, restart Heroes 2 and like above, choose to play a campaign and select the goo
Roland. Now, you know the trick : DON'T DO ANYTHING in the game, just save it
"def". Ok... We want a map_hack, so let's discover a little map, by moving yo
down from the castle, but just a bit. And without doing anything else, save t
under "def1".

And here comes the 'technique' you've just learnt : compare the 2 files ("def.gmc
"def1.gmc"). We start, as usual, by thinking what can be changed between thes
- first of all is your hero position on them map (you moved your hero to disc
some map, right ?)
- then maybe your hero facing (where is his 'face' : left/right/up/down)
- then some map changes (undiscovered is discovered in the second file)

You could have less or more replacements, depending on how much you moved your he
darkness. Also, when you're trying to map-hack, you must know that you don't
'strange' replacements, but something like this :
- a lot of bytes (one after another) representing the map. Usually, one by
one little square on the map. Majority of these bytes are the same in both
save files (in our case "def" and "def1") because we have walked jus
with our hero, and this majority also represent the darkness (in bot
darkness is 'more present' than the reveal)

Let's have a look at some of these repl. :

Hmm... 00 could be darkness and 01 could be 'light'. Here's another one :

Nope... Maybe a match will be more relevant :


YES !

So, it is now clear for everybody : 00 stands for square_with_darkness and 01 for
reveal_square.

As I told you in a previous essay, games hold their map in matrix. We have just f
Heroes2's map_storing matrix. To reveal the map, just change all these 00s in

NOTE : Some bytes holding 80 value could be in the matrix. Don't worry about
overwrite them with 01 to reveal the map in that square.

Now, look at above replacement (the one with 'Mandigal' string). Mandigal is the
my hero in the game. And the replacement could be because we changed his posi
the game (we moved him). Hehe... I bet it is... So, like the castles, heroes'
are near their names (that bunch of bytes you see up and down the hero's name
the army he's carrying, his artifacts, spells, skills etc. I let you discover

Final words
~~~~~~~~~~~

Man... I worked a bit on this tut. Even if it sounds simple : "saved-game hacking
it's not like this. This game (Heroes2) was an easy "target" because it store
in classic format in the saved_files. Some games encrypt their data when they
and decrypt the data when they load the respective file. So there you can't g
with a hex-editor, you'll most likely need a debugger and A LOT of patience a
nerves.

CHEERS & GREETS (order doesn't matter)


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Groza (great dude - check http://www.grozatt.cjb.net/ for more of this stuff...


- NanoBot2k (thanks goes to you, too ! http://www.nanobot2k.org/ )
- Snaky & Gran (MORTAL KOMBAT !!!!!!!!!)
- Biciuila (maybe the smartest man in these times)
- T-RaiNeR (long time - no see :(( )
- ParaBytes (my cracking teacher - a BIG THANKS ; like above, long time - no see
- All GHU members (GHU=tseB) hehehe...
- All in GameHacking's forum
- JUVENTUS (I love JUVE... Wait ! You have to hear this : In the last 4 matches,
had ONE draw and 3 loses. It can't be possible ! What's hapening guys ????)
- YOU
- and all who publish my work
romanian:
*******************************
* Salutari celor din Romania! *
* Fiti si voi mai fericiti !! *
*******************************

Prof. Dr. Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


"We care about YOU".
GHU ( http://www.ghu.as.ro/ ).

2004
eof
How do you make a trainer? DDH There are a few ways to make a trainer. You can use a trainer making program or you can program your own. A couple of trainer making programs are MTC
(Magic Trainer Creator) and TMK (Trainer Maker Kit). TMK is the newest. If you really want to make a good trainer and better understand what you're doing, you can learn how to create a trainer
in a programming language. Visual Basic is easy, but requires large DLLs. C/C++ is the most common language used. Assembly isn't used by many, but produces the smallest/fastest trainers.

What memory searcher is the best?


Whichever one you like. Everyone has their favorite memory scanner for whatever reasons. Try as many as you can and pick the one you like the best.

Why don't my address work after I restart the game?


The game is using what's called "DMA."

What is DMA?
DMA (Dynamic Memory Allocation) causes the offsets of the variable information in a program to change each time it's run. Since only the variable information offsets change, you can still defeat
DMA. All you need to do is load a debugger and modify the code of the game (Which the offset never changes) instead of poking the offset you had before. This requires at least a small
knowledge of assembly. When you're making a trainer, you just poke the code offset with your op codes. Op codes are the hex representation of assembly.

What is code injection?


Code injection is almost just like working with DMA (Defeating DMA can be called code injection). Sometimes when working with DMA, the computer will receieve the same benefits as you. This is
because the programer uses the same function for the computer and the player. To get around this you need to get the program to jump to a clean area in the game's memory. Once there you
can do whatever you want. Usually a register holds a certain value when the function is working with a player. YOu can check this and then work according to what you find. You usually have to
replace the command you removed when you wrote your jump. Sheep's tutorial is a nice one on code injection.

What are packets?


Packets are how online games (Online anything really) communicate. If you're talking on the phone, when you talk your voice is converted into eletricity, sent to the other person, and converted
into audio again. You can think of packets this way. Packets are information the game/server sends over the internet and are then read and acted on by the target. Packets can be encrypted just
like your voice.

What is packet editing/forging?


Packet editing/forging is the act of modifying a packet in order to cheat in the game.

Why packet edit?


Some games can't have much done to them by memory editing. Sometimes you can do pretty much anything in the game as long as you send the correct packets. It really depends on the game
on if packet editing will help or not. Sometimes you'll be able to do next to nothing...others you can control the whole game.

I can't minimize the game, help!


The programmer added code to disable your ability to minimize the game. You can try an alt+tab hack program and see if that works. If not you can try some cheap tricks. Press ctrl+esc to make
the start menu comes up. That can minimize games sometimes. TSearch has a network feature so you don't need to minimize the game if you have two PCs on the internet.

What is a debugger?
A debugger is basically a program that allows you to set breakpoints on memory and act on them. A debugger is required for getting by DMA.

What debugger to use?


There are many debuggers out there, but only two are really used in the game hacking world. SoftIce and Tsearch.. Which is best? Well SoftIce is hands down. No one can argue otherwise. TSearch
is the newbie debugger and only allows for basic DMA stuff. If you want to do code injection you'll have to use SoftIce. No matter what anyone says, SoftIce can not physically ruin a hard drive any
more than notepad can. Most botched SoftIce installs are due to user error and not program error.

What is memory scanning?


Memory scanning is the act of using a program (GameTrainer, ArtMoney, etc) to scan the memory of a program for a value. The value can be anything from zero to a sentence. This is the simplest
form of game hacking.

What is save game editing?


Save game editing is when you attempt to figure out how/where certain values of interest to you are saved when you do a save game. When you save, all important data is dumped out to a file
for the next time you play. If you had 100 gold in the game, it could be put into the save game and modified there. Save games can be dynamic and encrypted, which can make it very difficult to
edit them. They are also not in a simple format (usually). I.e. (using the gold example above) You will probably not find "Gold: 100" in the file. You will most likely have to look at a hex view of
the file.

What is HEX? (binary,decimal,etc)


Hex is a number system based on base 16. Values in memory are represented as hex because the hex numbers are smaller and easier to work with than decimal numbers. Hex uses the numbers 0
- 9 and the letters A - F.

Binary is a base 2 number system. 1001110011100111 is a binary number. You will most likely not have to use this in game hacking.

Decimal is the number system you are probably most familiar with. It is the standard number system and uses a base 10 format. 1,2, 3, 4, 5, 6, 7..etc

Octal is a base 8 number system.


Edited: Cracking example on Specific Program have heen removed
because to make sure only the information is distribute
and not the crack it self.

A beginners Guide to Cracking

Chapter 1 overview

Chapter 2 some tips on how to use the debugger

Chapter 3 some basic cracking techniques

Chapter 4 walk through of an easy crack

Chapter 5 how to use the disk editor

Chapter 6 other cracking tools

Chapter 7 source code to a simple byte patcher

Chapter 8 conclusion

CHAPTER 1 OVERVIEW
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

You might be wondering what type of programming skills you need to become a
cracker. Knowing a higher level language such as Basic, Pascal, or C++ will
help you somewhat in that you will have an understanding of what's involved in
the process of writing a program and how certain aspects of a program
function. If you don't have any programming skills at all, you have a long
road ahead of you. But even if you can program in a high level language, in
order to crack you have to know assembly...

It really doesn't matter what language a program was written in in order to


crack it, because all programs do the same thing. And that is issue commands
to the microprocessor. And all programs when broken down to their simplest
form are nothing more than a collection of 80XXX instructions and program
specific data. This is the level of assembly language. In assembly you have
total control of the system. This is also the level that the debugger operates
at.

You don't have to become a master at assembly to crack a program, but it


helps. You do need to learn some rudimentary principles, and you absolutely
have to become familiar with the registers of the cpu and how the 8088
instruction set uses them. There is no way around this.

How proficient you are at assembly will determine how good of a cracker you
become. You can get by on learning a few basic instructions, how to use a
debugger, and one or two simple techniques. This will allow you to remove a
few shareware nag screens, and maybe you'll luck out and remove the copy
protection from a game or two, but that's it.

As soon as a programmer throws some anti-debugging code into a program or


starts revectoring interrupts, you'll be whining for someone to post a crack
for this or that... And you can forget about ever learning to crack windows
programs.

It's much much easier to learn to crack in DOS than windows. DOS is the
easiest environment to debug in. This guide will focus on DOS programs as
cracking windows apps is a little bit overwhelming unless you are already an
experienced cracker. And if you are, your wasting your time by reading this.
This manual is geared towards the raw beginner who has no clue as to where to
start and needs a little hand holding in order to get going.

There are several good beginners manuals out there, but most of them assume a
person has at least some experience in cracking or knows how to use the
different tools of the cracker, and the raw beginner usually becomes
frustrated with them very quickly because they don't understand the concepts
contained in them.

I wrote this guide as sort of a primer for the beginner to read before reading
the more comprehensive guides. I tried to keep it as simple as possible and
left a great deal of information out so as not to overwhelm anyone with too
much information at once. Hopefully after reading this guide it will be easier
for the beginner to understand the concepts of the more arcane guides out
there. So if you are reading this and it seems a little bit remedial,
remember, at one time you didn't know what a debugger was used for either.

Now in case your not familiar with the debugger and disk editor and what their
different roles in cracking are, I'll give a brief explanation of each. As
these are the crackers most used tools.

The debugger is what you will use to actually crack the program. When you load
a program you wish to crack into the debugger, it will load the program and
stop at the first instruction to be executed within the code segment. Or, you
can also optionally break into an already running program and it will halt the
program at the instruction you broke into it at and await further input from
you. At this point, you are in control of the program.

You can then dynamically interact with the program and run it one line of code
at a time, and see exactly what the program is doing in real time as each line
of code is executed. You will also be able to re-assemble instructions (in
memory only), edit the contents of memory locations, manipulate the cpu's
registers, and see the effects your modifications have on the program as it's
running. This is also where all your system crashes will occur... There is a
lot of trial and error involved in cracking.

As stated above, the debugger will only modify the program while it's up and
running in memory. In order to make permanent changes, you need to load the
program file to be patched into the disk editor and permanently write the
changes you've made to disk. A detailed explanation of how to do this will be
made in chapter 5.

So, with this in mind, you need a few essential tools... The first one is a
good debugger. The original draft of this guide gave explicit instructions on
how to use my favorite debugger. After considerable deliberation, I decided to
re-write it and make the instructions more generic so you could apply them to
most any debugger. You will also need a disk editor, it doesn't matter which
one you use as long as it will load the program file, search for and edit the
bytes you want to change.

I uuencoded a few cracking tools that you will find indespensible and placed
them at the end of this guide. I won't go into the use of the cracking tools
right now. But believe me, you absolutely need one of them, and the other one
will save you a lot of effort. I also uuencoded the program that we will crack
in the walk through and included it in this guide as well.

As you get better, you'll have to write programs that will implement your
patches if you decide to distribute them. The patches themselves don't have to
be written in assembly.

The source code I included in this manual for the byte patcher is the first
patcher program I ever wrote, and is extremely simple. It's written in
assembly because that's the only language I know how to program in. but if you
are already proficient in a higher level language, it should be trivial for
you to duplicate it's methods in your preferred language.

CHAPTER 2 SOME TIPS ON HOW TO USE THE DEBUGGER


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Ok, before I begin, I'd just like to stress how important it is that you know
at least some assembly before trying to continue. If you don't, you will get
lost pretty quick from here on out. Comprehension of the base 16 (hexadecimal)
number system is also required.

I'm not about to give a remedial course on assembly or hex math, that would
take too long and I'd probably leave too many questions un-answered. Besides,
there is enough information on them available from a myriad of other sources.

So, from now on in this guide, I'm assuming you have a fair working knowledge
of assembly and hexadecimal. If I say something you don't understand or you
cannot grasp some concept, look it up somewhere...

I've tried to make this section as generic as possible. I used general


descriptions when explaining HOTKEYS and COMMANDS as different debuggers will
use different keys and command syntax to implement these functions.

You should be able to translate these instructions to the actual key strokes
and commands that your debugger uses... If you don't know how to use a
debugger, PAY ATTENTION!!! If you already know how to use a debugger you can
skip this section as it is only a general overview of different windows and
functions designed for the absolute beginner who has no clue as to what he is
looking at.

The reason I included this section is because most manuals for debuggers tell
you how to use the various features of the debugger, but they don't give any
insight on how to apply those features, as they assume the person reading them
already knows how to debug a program.

First, I'll give an overview on the different windows that most debuggers use.

REGISTER WINDOW:

The register window contains the general purpose and flags registers of the
cpu. You will notice that the general purpose registers contain hexadecimal
values. These values are just what happened to be in there when you brought up
the debugger. you will also notice that some of the flags are highlighted
while some are not. Usually, the highlighted flags are the ones that are SET.
While the ones that are not highlighted are CLEARED. The layout of this window
will vary from debugger to debugger, but they all basically are the same.

From this window you will be able to manipulate the contents of the cpu's
registers. some debuggers accomplish this by clicking on the register to
modify with the mouse and then entering a new value. Other more powerful
debuggers use a command line interface, you'll have to discover how your
debugger goes about this yourself.

You can change the values of the registers while debugging a program in order
to change the behavior of the running program. Say you come across a JNZ
instruction (jump if not zero), that instruction makes the decision on whether
or not to make the jump based on the state of the (Z)ero flag. You can modify
the condition of the (Z)ero flag in order to alter the flow of the programs
code.

By the same token, you can modify the general purpose registers in the same
manner. Say the AX register contains 0000, and the program bases it's actions
on that value, modifying the AX register to contain a new value will also have
the effect of modifing the flow of the code. After you become comfortable with
using a debugger you'll begin to appreciate just how powerful this window is,
and you'll aslo discover soon enough just how totally it can screw your
system.

DATA WINDOW:

The data window will display data as it exists in memory. From this window you
can usually display, search, edit, fill, and clear entire ranges of memory.
The two most common commands for this window are display and edit. The search
command is also useful in cracking. But for the level of debugging I'll be
teaching you in this guide, we won't make much use of this window. You have a
lot to learn before this window becomes an asset to you.

CODE WINDOW:

The code window is the window in which you will interact with the running
program. This is the most complex window, and it is where the bulk of
debugging occurs. I'll just go over some keystrokes and a few commands here,
as the majority of learning how to use this window will come when I show you
how to crack a program.

The layout of the window is pretty simple, the group of 8 numbers with the
colon in the middle of them to the far left of the window is the
address:offset of that line of code. Each line of code in this window is an
instruction that the program will issue to the microprocessor, and the
parameters for that instruction. The registers that contain the address for
the current instruction waiting to be executed are the CS:IP registers (code
segment and instruction pointer).

You will also notice a group of hex numbers to the right of the addresses,
this group of numbers is the hexadecimal equivalent of the mnemonic
instructions (pronounced new-mon-ik). The next group of words and numbers to
the right of the hex numbers are the mnemonic instructions themselves.

HOTKEYS AND COMMANDS:

Now we'll move onto the HOTKEYS. I won't go into all of them, only the most
useful ones, same for the commands.

The RESTORE USER SCREEN KEY: This key will toggle the display between the
debugger and the program you are debugging without actually returning control
to the program itself. it's useful to check what the program is doing from
time to time, especially after stepping over a CALL.

The HERE KEY: This key is the non-sticky breakpoint key. To use it, Place the
cursor on a line of code and hit it. The program will then run until it
reaches that line. When (and if) the program reaches that line, program
execution will halt, control will be returned to the debugger and the
breakpoint will be removed.

The TRACE KEY: This key will execute one line of code at a time and will trace
into all calls loops and interrupts.

The BREAKPOINT KEY: This is the sticky breakpoint key. This will enable a
permanent (sticky) breakpoint on the line of code that the cursor is on. When
a sticky breakpoint is enabled, program execution will halt and control will
be returned to the debugger every time that line of code is encountered within
the running program until you manually remove it.

The SINGLE STEP KEY: The most used key on the keyboard. This key will execute
one line of code at a time but will not trace into calls loops or interrupts.
When you step over a call interrupt or loop with this key, all the code
contained within the sub-routine is executed before control is returned to the
debugger. If the program never returns from the sub-routine, you will lose
control and the program will execute as normal.

The RUN KEY: This key will return control to the program being debugged and
allow it to execute as normal. Control will not be returned to the debugger
unless a breakpoint that you've set is encountered.

Now for a few commands. The GO TO command functions like the HERE key in that
it will insert a non-sticky breakpoint at the specified address.

When you enter this command the debugger will return control to the program
until the line of code you specified in the GO TO command is reached. When
(and if) the CS:IP registers equal the address you typed in, the program will
halt, control will be returned to the debugger and the breakpoint will be
removed.

You might be wondering why you would want to type all this in when you can
just hit the HERE KEY instead. The answer is this; the HERE KEY is great if
you want to set a local breakpoint. By a local breakpoint I mean that the
breakpoint you want to set is somewhat close to your current location in the
program.

But what if you want to set a breakpoint on a line of code that isn't in the
current code segment? You wouldn't want to use the HERE KEY cause the address
is no where near the point you are at in the program. This, among other uses
is where the GO TO command comes in.

The ASSEMBLE command is the command you will use to re-write the programs
instructions. This command will allow you to assemble new instructions
beginning at the address you type in, or at the current CS:IP. The
instructions you enter will replace (in memory only) the existing program code
at the address you specified. This is another method you will use to alter the
running program to behave as you wish and not as the programmer intended it
to.

EXAMPLE: Lets say that there is a line of code that reads JNZ 04FC, and we
want to change it to read JMP 04FC. You would issue the ASSEMBLE command and
specify the address of the code you wish to change, then type in JMP 04FC.
Now the line of code in the code window who's address you specified in the
ASSEMBLE command will be overwritten with the code you typed in. Some
debuggers automatically default to the address contained in the CS:IP for this
command.

There are a whole host of other commands available in this window depending on
what debugger you are using, including commands to set breakpoints on
interrupts, memory locations, commands that list and clear breakpoints,
commands to un-assemble instructions etc etc...

Well, that's pretty much it on debuggers without going into explicit


instructions for specific debuggers. The only other thing I can tell you is
that the more you use it, the easier it'll get. Don't expect to become
familiar with it right away. As with anything, practice makes perfect. It's
taken me 5 years and thousands of hours of debugging to reach the level I'm at
now. And I still learn something new, or re-learn something I forgot on just
about every program I crack.

CHAPTER 3: SOME BASIC CRACKING TECHNIQUES


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The first thing I want to do before going into some simple techniques is to
explain the purpose of one of the uuencoded cracking tools at the end of this
guide. And also to go over some general procedures you should perform before
actually loading a program you wish to crack into the debugger.

Nowadays a lot of programmers will compress the executable files of their


programs to save space and to make it difficult for people who don't know any
better to hack those files. There are a lot of losers out there who will get
ahold of a program and lacking any skill or talent of their own, will load the
program into a disk editor and hex edit their name into it. Or they will make
other similarly feeble modifications.

This is the reason I encrypt all of the cracks that I distribute. The routines
I write are not that hard to defeat, but I figure anyone with the skill to
crack them is far above having to hack their name into them...

Ok, back to the file, the name of the program is UNP and it is an executable
file expander. It's purpose is to remove the compression envelope from
executable programs. And it supports most of the compression routines
currently in use...

A lot of the compression routines will cause a debugger to lock up if you try
to step through the compressed file, especially PKLITE v1.15. And seeing as
how the file is compressed, if you load it into a disk editor it will just
look like a bunch of garbage and you'll not be able to find the bytes you want
to edit anyway.

UNP is very easy to use, just type UNP [filename] and if there is any type of
compression envelope that UNP understands on the file, UNP will remove it. You
can then load the file into a debugger and hack away...

But before you load a program into the debugger you should run the program a
few times and get a feel for it. You want to see how the protection is
implemented. Whether it's nag or delay screens and at what point in the
program they fist appear, or where in the program does the first mention of
being unregistered or an evaluation copy appear?

This is important. Because before the program displays the first mention of
being unregistered, it has to do the protection check. and this is where you
will usually want to concentrate. Also look for registered functions being
disabled, and sometimes date expirations. The program could also be looking
for a registration key.

In the case of commercial software what type of copy protection is used? Is it


a doc check, or does the program want you to input a serial number before it
will install itself? Once you see how and where the offending routines are
implemented you can begin to develop an overall strategy on the best approach
to circumvent them. It's also a good idea to read the docs, you can pick up a
lot of useful info from doc files.

There are basically three categories that shareware programs fall into... They
are begware, crippleware, and deadware.

The begware category is comprised of programs that have all the registered
features enabled but every time you run them they will display screens that
bug you to register. This is usually the easiest form of protection to remove
and it's the type I'll go over in the walk through.

The crippleware category is comprised of programs that in the unregistered


version have certain functions disabled, and maybe nag screens as well. This
type of protection can be more complex, but often times is just as easy to
defeat as a simple nag screen.

The deadware category is comprised of programs that are totally stripped of


the code for the registered features so there is really nothing to crack. A
good example of this is DOOM by ID software. You can get the shareware version
just about anywhere, however no matter how much you hack at it you cannot make
it into the commercial version cause it only contains the code for the first
episode.

The sample code fragments in this section are not taken from actual programs.
I just made them up off the top of my head while I was writting this guide,
and there are bound to be some errors in them. Please dont write me and tell
me this, I already know it.

Most forms of copy protection have one weak spot, and this is the spot you
will concentrate on. They have to perform the protection check and then make a
decision based on the results of that check. And that decision is usually a
conditional jump. If the check was good the program will go in one direction,
if it was bad it will go somewhere else.

So, you've run the program through a few times and you know at what point the
routines you want to modify first appear, you've also run UNP on it and have
removed any compression envelopes. Now you load the program into the debugger
and wonder what to do next...

What you want to do is to step through the code until something significant
happens like a nag screen gets displayed, or a doc check comes up or the
program tells you that the function you just tried to use is only available in
the registered version. When you reach that point you can then start to
evaluate what portion of code to begin studying.

Let's say you have a program that displays a nag screen and you want to remove
it. You step through the program until the nag screen pops up, you now think
you know the location of the instructions that are causing it to be displayed.
So you reload the program and trace back to a point a few instructions before
the call to the nag screen, and this is what you see:

09D8:0140 CMP BYTE PTR [A76C],00


09D8:0145 JNZ 014B
09D8:0148 CALL 0C50
09D8:014B MOV AH,18

Now, let's assume that the memory location referenced by the first line of
code does indeed contain 00 and that it is the default value placed in there
by the programmer to indicate that the program is unregistered.

The first line of code is checking the value contained in the memory location
to see if it is 00 or not. If the location does contain 00, the compare
instruction will cause the Zero flag to be set. If the location contains any
other value than 00, the Zero flag will be cleared.

The second line of code makes the decision on how to proceed based on the
results of the compare instruction. The JNZ instruction will make the jump to
the fourth line of code if the zero flag is cleared. This will bypass the call
to the nag screen on the third line. If the zero flag is set, no jump will
occur and the call will be made.

The third line of code contains the call to the nag screen. If it is executed
the nag screen will be displayed. The fourth line of code is just the next
instruction in the program.

Once you have found and analyzed this piece of code within the program, you
can now decide on how to bypass the call on the third line. There is no single
way to do this. I can think of a half dozen different ways to patch the
program so it will not make the call. But there is a best way...

First, you could just replace the JNZ 014B with JMP 014B. This is an
unconditional jump and it will bypass the call on the third line no matter
what the memory location that the first line of code is referencing contains.

You could also change it to read JZ 014B so that the jump will be made if the
location contains 00, and not the other way around. You could even change the
CMP BYTE PTR [A76C],00 instruction to JMP 014B.

Or you could just NOP out the call on the third line altogether seeing as how
it's a local call. By a local call I mean that the code contained within the
call resides in the same code segment as the call instruction itself.

This is an intersegment call. You will see other calls that reference lines of
code outside of the current code segment. These are intrasegment calls, and
have to be handled differently. They will look something like CALL 0934:0AC5,
or CALL FAR 0002. I'll go over how to handle intrasegment calls later on.

NOP is short for no op-code, and it is a valid instruction that the


microprocessor understands. It is only one byte in length, and the call
instruction is three bytes in length. So if you wanted to nop out the call
instruction you would have to enter the NOP instruction three times in order
to replace it. And if you replaced the CMP BYTE PTR [A76C],00 with JMP 014B,
you would have to pad it out with a few nop's as well.

The compare instruction is 5 bytes and the jump instruction is only 2 bytes,
so you would have to add 3 nops in order to equal the length of the original
compare instruction. Otherwise you would throw off the address of every
instruction after it in the program and end up with a bunch of unintelligible
garbage. Not to mention a major system crash...

When the NOP instruction is encountered no operations will take place and the
CS:IP will then be incremented to the next instruction to be executed. A lot
of compilers leave nop's in the code all the time and it's a great instruction
you can use to wipe out entire lines of code with.

The above methods of bypassing the call are called 'dirty' cracks in that they
have only modified the end result of the protection check and have done
nothing to alter the actual protection check itself.

All the techniques I showed you above are only implemented after the check is
made. They will bypass the nag screen, but what if the program also has
registered features that are disabled or displays another nag screen upon
exit? The above methods only remove the original nag screen and don't address
the reason the screen is being displayed in the first place.

A much cleaner way to crack the above piece of code would modify the cause and
not the effect. And could be written like this:

original code new code

09D8:0140 CMP BYTE PTR [A76C],00 09D8:0140 MOV BYTE PTR [A76C],01
09D8:0145 JNZ 014B 09D8:0145 JMP 014B
09D8:0148 CALL 0C50 09D8:0148 CALL 0C50
09D8:014B MOV AH,18 09D8:014B MOV AH,18

Remember that the protection check is basing it's actions on the value
contained in the memory location that the first line of code is checking. The
original code displayed the nag screen if the value of that location was 00,
meaning it was unregistered. So that means a value of 01 indicates a
registered copy. It could be the other way around as well, it just depends on
how the programmer worded the source code. But we know in this case that
00=false so 01=true. These are Boolean expressions and most compilers use the
AX register to return these values.

By changing the first line from CMP BYT PTR [A76C],00 to MOV BYTE PTR
[A76C],01 the program no longer performs the protection check. Instead, it
places the correct value in the memory location to indicate a registered copy.
Now if the program checks that memory location again later on it will think
that it is registered and activate all of it's disabled features, or not
display a second nag screen upon it's exit if it has one.
I changed the second line of code to an unconditional jump because the compare
instruction on the first line no longer exists, and the conditional jump on
the second line may still access the call to the nag screen on the third line
if the Z flag was already set before the old compare instruction was
encountered.

Don't think that all programs are this easy, they're not. I just
over-simplified this example for instructional purposes. And I really wouldn't
patch the code like that, although the last method should work fine for all
registered features to be enabled. Remember I told you there was a best way to
crack this?

What I would actually do is to trace further back into the program and find
the line of code that sets up the memory location referenced by line one of
the code for the protection check in the first place and modify it there. This
is an example of a 'clean' crack.

I just did it in the above manner to try and show you the difference between
clean and dirty cracks without totally confusing you. And to give you a
general idea on how to creatively modify existing code.

If you are using soft ice as your debugger, an easy way to find the
instruction that sets up the memory location for the protection check is to
set a breakpoint on the location when it gets 00 written to it. The syntax
would be BPM XXXX:XXXX W EQ 00, where XXXX:XXXX is the address of the memory
location referenced by the compare instruction on line 1.

Now when the program wrote 00 to that memory location, soft ice will pop up
and the CS:IP will be sitting at the next instruction after the one that wrote
00 to the memory location. You will now be able to evaluate the code around
the instruction that writes to the memory location and decide on how to
proceed.

This also could just be a general purpose location that the program uses for
generic references (especially if it's in the stack segment), and it could
write 00 to it several times throughout the course of the program for a
variety of different functions. You should let the program run normally after
soft ice broke in to see if it will trigger the breakpoint again. If it
doesn't you know that the location is only used for the protection check. But
if the breakpoint gets triggered several more times, you will have to figure
out which set of instructions are being used to set up for the protection
check before proceeding.

The above examples were based on shareware programs. Now I'll go over a few
techniques to remove copy protection from commercial games that have doc
checks in them as the methods are slightly different...

shareware programs are usually coded so that they check a variable in memory
before deciding if they are registered or not and how to proceed. Commercial
games with doc checks take a different approach as they check nothing before
calling the copy protection. It always gets called every time you play the
game no matter what. As a result, the doc check routine is usually easier to
find, and there are basically two types of doc checks... The passive check,
and the active check.

The passive doc check is easier to defeat than the active. In the passive doc
check, the program will issue a call to the copy protection routine. And if it
is unsuccessful will either abort the program, or loop back to the beginning
of the routine and give you a few more tries before aborting. The entire
protection routine will be included in a single call, so merely nopping out
or bypassing the call will be sufficient to remove the copy protection.

A few good examples of this are Spear of Destiny by ID, and the Incredible
Machine by Sierra. Yes I know that they are old, but if you happen to have a
copy of either one laying around they are excellent examples of passive doc
checks to practice on.

Look at the following piece of code:

0277:01B5 MOV [AF56],AX


0277:01B8 PUSH BX
0277:01B9 PUSH CX
0277:01BA CALL 0234
0277:01BD POP CX
0277:01BE POP BX
0277:01BF JMP 0354

The first three lines of code are just setting up for the call, the call on
the fourth line is the protection check itself. It will display the input
window asking for a word from the manual, will perform the protection check,
and will display an error message if you input the wrong word. It can also
optionally give you a few more tries if you type in the wrong word.

If you fail the protection check, the program will abort without ever having
returned from the call. The fifth, sixth, and seventh lines are the next
instructions to be executed if the protection check was successful and the
program returns from the call.

This type of protection is trivial to defeat, all you have to do is the


following:

original code new code

0277:01B5 MOV [AF56],AX 0277:01B5 MOV [AF56],AX


0277:01B8 PUSH BX 0277:01B8 PUSH BX
0277:01B9 PUSH CX 0277:01B9 PUSH CX
0277:01BA CALL 0234 0277:01BA NOP
0277:01BD POP CX 0277:01BB NOP
0277:01BE POP BX 0277:01BC NOP
0277:01BF JMP 0354 0277:01BD POP CX
0277:01BE POP BX
0277:01BF JMP 0354

Simply nopping out the call to the protection routine will be sufficient to
crack this type of doc check. No window asking for input will appear, and the
program will continue on as if you had entered the correct word from the
manual. Remember that I told you that the NOP instruction is only one byte in
length, so you have to enter as many nop's as it takes to equal the length of
the code you are modifying.

The active doc check is more complex. The program will issue the check and
unlike the passive protection, will set a variable in memory somewhere and
reference it later on in the program.

You can crack this type of protection somewhat using the methods for the
passive check and it might run fine for a while. But if you didn't crack it
right, later on when the next episode gets loaded or you reach a crucial point
in the game, the program will reference a memory location and bring up the
copy protection again, or abort. This type of protection is more akin to how
most shareware programs operate and MUST be done with a CLEAN crack.

Look at the following piece of code:

0234:0B54 MOV CX,0003 ;Sets up to give you three tries


0234:0B57 DEC CX ;deducts one for every time through the loop
0234:0B58 JCXZ 031A ;when CX=0000, program will abort
0234:0B60 PUSH CX ;just setting up for the call
0234:0B61 PUSH DS ;" "
0234:0B62 PUSH ES ;" "
0234:0B63 CALL 035F:112D ;call to input window and validation routine
0234:0B68 OR AL,AL ;seeing if check was successful
0234:0B6A JNZ 0B6E ;yes, continue on with the program
0234:0B6C JMP 0B57 ;no, set up for another try
0234:0B6E CALL 8133 ;next line in the program if check was good

The above code is the outer loop of the protection routine. Look at the call
on the seventh line and the compare instruction on the eighth line. When the
call to the input routine or in the case of shareware, the check routine is
paired with a compare instruction in this manner, You can bet that the program
set a memory variable somewhere inside the call. Especially suspicious is the
unconditional jump on line 10 that jumps backwards in the code.

This won't always be the case as no two programs are alike, and simply
changing line 9 of the code from JNZ 0B6E to JMP 0B6E to force the program to
run even if you fail the doc check may allow the program to run just fine.
Let's say that this is how you patched the program and it runs. Great, your
work is done... But what if before the first level loads, or at some other
point within the program the input window pops up again asking for a word from
the manual?

You realize that you should have patched it right in the first place as you
now have to go back in there and fix it. This is why so many groups have to
release crack fixes, they patch the program in a hurried manner and don't even
run it all the way through to see if it's going to work.

Ok, back to the problem at hand... The above method of patching the program
didn't work, so you now have to load the program back into the debugger and
trace into the call on line seven to see whats going on in there. And you
can't NOP this kind of call out either, this is an intrasegment call.

Certain things in programs get assigned dynamic memory locations, and


intrasegment calls are one of those things. When the program gets executed,
the code segment, data segment, extra segment, and stack segment get assigned
their respective addresses based on the memory map of your computer.

And when a program does a FAR call (a call to a segment of memory outside the
current code segment), The program goes to the address that was assigned to
that segment at run time. The CS, DS, ES, and SS will be different on every
computer for the same program.

And seeing as how these addresses don't get assigned until run time, the
actual bytes for the addresses of far calls don't exist in the program file as
it resides on your disk. That's why you can't just NOP a CALL FAR instruction
out.

However, the bytes for calls that are within the same segment of code as the
calling instructions themselves will be contained within the file as it
resides on disk. And that is because even though the program doesn't get the
addresses for the actual segments until run time, the offsets within those
segments will always be the same.

Back to the example, let's say you've traced into the call on line seven and
this is what you see:

035F:112D MOV [324F],BX ;


035F:1131 CMP BYTE PTR [BX+06],03 ; just some error checking
035F:1135 JNZ 0339 ;

035F:1137 CALL F157 ; call to the input window that


; asks you to type a word in from
;the manual

035F:113A MOV DI,[0332] ; this routine is comparing the


035F:113D MOV ES,DX ; word you typed in to a word
035F:1140 MOV DS,BX ; in memory that the program is
035F:1144 MOV SI,[0144] ; referencing. As long as the
035F:1148 MOV CX,[0097] ; bytes match the loop will
035F:114C REPE CMPSB ; continue.

035F:114F JCXZ 1154 ; This is the routine that sets


035F:1151 JMP 1161 ; the memory variable. 01 will be
035F:1154 MOV AX,0001 ; placed in it if you typed in
035F:1159 MOV [0978],AX ; the correct word. 00 will be
035F:115E JMP 116B ; placed in it if you typed in
035F:1161 MOV AX,0000 ; the wrong word.
035F:1166 MOV [0978],AX ;
035F:116B POP ES ; setup to return from call
035F:116C POP DS ; " "
035F:116D POP CX ; " "
035F:116E RETF ; return from call

Again, this code is over simplified as I figured all of the code would be
overwhelming and really is not needed to get my point across. And as I've
stated before, every program will be different anyway, so the actual code
wouldn't help you. Instead, I want to give you a general overview on what to
look out for.

So, what do you think is the best way to patch the above piece of code? Take a
few minutes to study the code and formulate some ideas before reading on. Then
compare your methods to mine. And remember, as with any code there is no
single way. But as always, there is a best way... I'll go over few of them one
at a time, starting with the dirtiest and finishing up with the cleanest.

The dirtiest crack for this piece of code also happens to be the method you
will use to nop out intrasegment calls. It really isn't nopping out, but
seeing as how you can't nop it out, just let the program make the call and
change the first line of the code within the call to RETF. This will return
from the call without ever having executed any of the code contained within
it.

In the case of registers needing to be restored as in the above code, change


the first line of code to jump to the part of the routine that restores the
registers for the return. However, in the above example if you use this method
and just return from the call without executing any of the code, you will also
have to patch the outer loop as well.

Remember that this call only displays the input window and sets the memory
variable. The outer loop of the routine makes the decision on how to proceed
based on the results of the call.

To do this, you would change line one of the call from MOV [324F],BX to JMP
116B. This will restore the registers and return from the call without ever
having executed any of the code within the call. But seeing as none of the
code got executed, you'll have to patch line 9 of the outer loop from JNZ 0B6E
to JMP 0B6E as you now need an unconditional jump to force the program to
continue. This doesn't address the problem of the memory variable though, and
the program won't be completely cracked. That's why if you did it like this
you would end up releasing a fix.

A cleaner crack would be to change line 11 of the call from JCXZ 1154 to JMP
1154. Now when the window pops up and asks for a word, it will set the correct
memory variable and the program will run no matter what word you type in. This
method is still not desirable because the end user will get the input window
and have to type something every time they play the game.

The cleanest way to crack this, and the way I would do it is to change line 4
of the call from CALL F157 to JMP 1154. This method will totally bypass the
input window, place the correct variable in memory and return from the call
without the end user ever having seen even a hint of copy protection.

With this method, the outer loop does not need to be patched cause the program
now thinks that it displayed the input window and the correct word was typed
in. Now when the program checks that memory variable later on, it will think
that you successfully passed the original check and skip the second protection
check.

There is also an added benefit to the last method... Some games will bring up
the protection check between each and every level of the game even though you
type the correct word in every time. But if you've completely killed the
routine as in the last example, you'll never be bothered by it again no matter
how many times the program tries to bring it up.

Please be aware of the fact that these are not the only methods that
programmers will use in copy protection schemes. These are just the basics and
there are several variations on these routines. The only way to be able to
know what any given routine is doing at any time is to master assembly
language.

Before we move onto the walk though, there is one other technique I want to go
over with you. And that is how to get out of a loop. You will get stuck in
loops constantly during the course of debugging a program and knowing how to
get out of them will save you a lot of time and frustration. You will find
that programs contain loops within loops within loops etc... Some loops can
execute hundreds of times before the program will advance, especially ones
that draw screens.

When you realize that you are stuck in a loop, execute the loop several times
and keep an eye on the highest address the loop reaches before jumping
backwards within the code. Once you have found the end of the loop, write down
the address of the jump that re-executes the loop, and then look for
conditional jumps inside the loop that will put you past the address of that
backwards jump. You will want to set a breakpoint on the address this
instruction jumps to and then let the program run normally. The HERE KEY is
excellent for this type of situation.

If you guessed right, control will be returned to the debugger when the
program reaches that instruction. If you guessed wrong, you will lose control
of the program and will have reload it and try again. This is where writing
down the address comes in handy, just reload the program and then issue the GO
TO command and supply it the address of the backwards jump that you wrote
down.

The program will run until it reaches that address and control will then be
returned to the debugger. This will save you from having to trace all the way
through the code again in order to reach the point where you lost control of
the program in the first place. You could just use sticky breakpoints instead,
but what you will end up with is a half dozen or so breakpoints in as many
different locations in the code, and it's very easy to loose track as to which
breakpoint is which.
That's why I use non-sticky breakpoints and write down the address I'm
currently at before executing suspicious looking calls and jumps. My desk is
usually scattered with scraps of paper filled with notes and addresses. I only
use sticky breakpoints for specific situations. It's much easier to just
reload the program and use the GO TO command to get back to the point in the
program where I lost control.

CHAPTER 4 WALK THROUGH OF AN EASY CRACK


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

First of all, I want to go over some of the criteria I used in choosing the
program I used for the walk through. An important factor was the programs
size. I want to keep this manual as small as possible, and I chose the program
that is included in this guide because among other things it is the smallest
one I could find that best illustrated the example of a simple nag screen.

Whether or not the program was one that you would actually find useful was not
a consideration, as you should eventually be able to crack just about any
program you wish if your serious about cracking. If you come across a program
that has you stumped, leave it alone for a while and then try again after
you've cracked something else. You may find that whatever you were having
problems with is now easier to understand.

Before we start I want to go over one other thing. When you load a program
into a debugger, the debugger will load the program and halt at the very first
instruction to be executed within the program. You can also at this point let
the program run normally and then break back into it at a later point.

When you use the second method it will halt the program at the current
instruction and return control to the debugger, but you may not end up in the
program itself. You could have broken into the program while it was in the
middle of executing either a DOS or BIOS interrupt, and the code you are in
belongs to either DOS or BIOS and not the program you are debugging.

You can tell by looking at the addresses of the instructions in the code
window where you are, low segment addresses indicate you are in DOS, and
addresses that start with FXXX indicate a BIOS routine.

If you break into the program while it is in one of these interrupt routines
you will have to trace your way back into the programs code, this will usually
be indicated by an IRET (interrupt return) instruction. When you do get back
to the program code, you will then have to trace your way back to the top of
the call that issued the interrupt you broke into. Then you may also have to
trace back to the top of that call, and to the top of that call, etc etc,
until you reach the top level of the program. After you've done this a few
times you'll begin to recognize when you've gotten back to the main flow of
the program...

On the other hand, when you load a program into the debugger and begin
stepping through the code from the very first instruction to be executed
within the program, you have the best picture on the overall flow of the
program as you are sitting on top of everything.

But some programs don't access the copy protection until they are further
along in the code. In this case, it's best to let the program run normally and
then break into it at a later point. Otherwise, you will have a ton of code to
trace through before the protection routine is accessed, and this can become
quite tedious. Which method you choose will be determined after you've run the
program through a few times and decide how and where you want to break into
it.

One last thing, DOS will always load a program into the same memory range
provided that no other programs are run in the interim. It's important that
you always boot with the same config files and don't run any other memory
resident programs between cracking sessions.

If you load a program into the debugger and start tracing, then quit. And
before The next time you load that same program into the debugger, you boot
with a different config or load a memory resident program that you didn't have
loaded the first time you started cracking that program, the segment addresses
will change and the addresses you wrote down will be useless. This is because
the memory map of your computer will change.

When I boot with my debugging config (when I use my DOS debugger, Windows
manages memory differently and these steps are not needed), the only things I
load are a mouse driver, 4DOS, my debugger and ansi.sys (needed for cracking
bbs doors). This way I'm assured that the program I want to crack gets loaded
into the same memory region every time I run it, providing I don't run any
other memory resident programs before loading the program to be cracked into
the debugger.

Take soft ice as an example, if you load a program into it using LDR.EXE and
begin debugging, then later on you decide to just execute the program and
break into it without first loading it with LDR.EXE, the segment addresses
will change. That's because LDR.EXE is a program and using it will throw the
segment addresses off by one word as opposed to just breaking into an already
running program without first loading it with LDR.EXE.

The program we will crack is budget minder, it is an extremely simple crack


(it took me about 2 minutes to crack it) and is ideal for the lesson on how to
remove nag screens from otherwise fully functional programs. It also deals
with intrasegment calls, so it serves a dual purpose. That's another reason I
chose it for the lesson.

From now on, when I say step, step through, or step over, I want you to use
the SINGLE STEP key. When I say trace, I want you to use the TRACE key once
and only once!!!! The TRACE key is a highly specialized key and is not
intended to be used multiple times like the SINGLE STEP key. If you don't
follow these instructions, your gonna get lost...

OK, once you've run budget minder a few times you will notice that it displays
a nag screen before the main program is executed. You will also notice that
this nag screen is the only type of protection that the program has. It
doesn't contain any features that are disabled, nor does it display an
additional nag screen upon exit.

It's okay to apply a dirty crack to this program as all you want to do is kill
the nag screen, so you have a little more leeway on how to patch it. And if
you want to try different methods of patching it than the ones I give, it
should still work fine.

That was the most important factor in my decision to use this program for the
lesson. I wanted to walk you through a program so you would become comfortable
with it's flow, and I also wanted the program to be easy enough so that once
you became familiar with it, there was enough room for you to experiment and
try out your own methods.

In this case, it's best to load the program into the debugger and start
stepping through it right away. The protection is implemented very close to
the beginning of the program, and this method of loading the program will put
you right on top of everything.

Allowing the program to run and breaking into it later on will not serve any
useful purpose. You'll just end up having to trace your way back to the top.
Besides, the nag screen comes up so fast you'll probably miss it if you try
the second method anyway.

Before you load it into the debugger, run UNP on BUDGET.EXE... AHA! The file
was compressed with EXEPACK. It's now ready to debug as you've removed the
compression envelope. Just for the hell of it, run UNP on it again. I've come
across a few programs that have had multiple compression routines on them. If
it shows up negative, your set to go.

Now load BUDGET.EXE into the debugger, the program will be sitting at the
first instruction to be executed awaiting your next command... Use the SINGLE
STEP key to start stepping through the code and keep an eye on the
instructions as you are stepping through them.

Shortly you will come to a couple of calls, before you step over the first
one, write down it's address. Now step over the first call with the SINGLE
STEP key. Nothing happened, so you have to continue stepping through the code.
But if something did happen when you stepped over this call like the nag
screen being displayed or if you lost control of the program, you could just
reload the program and issue the GO TO command to get back to that point using
the address you wrote down.

Step over the second call, nothing again. Ok, keep stepping through the code
and keep an eye on the instructions. You will encounter a third call about 6
instructions or so after the second call, step over it with the SINGLE STEP
key... Bingo, you have found the call to the nag screen. Hit a key to exit the
nag screen and you will now be sitting in the main program screen.

But you no longer have control of the program. Remember I said you would loose
control if you step over a call loop or interrupt and the program never
returns from it? Hopefully you wrote down the address of that last call before
you executed it. Now you can just quit out of the program and reload it. Then,
once it's reloaded, issue the GO TO command to get back to the call without
having to trace your way back there. So go ahead and do this before reading
on...

Ok, we are all back at the third call. It's address will be CS:0161, remember
that the segment adresses will always be different for every computer, but the
offsets will be the same. So from now on I'll write the addresses in that
manner...

We know that the last time we executed this call, the program never returned
from it. So now we are going to have to trace into it for a closer look. Trace
into the call with the TRACE key, don't use the SINGLE STEP key this time or
you'll loose control again.

You will now be inside the code for that call, start stepping through it again
with the SINGLE STEP key, you will see some calls. Better write down your
address before you step over them.

Step over the first two calls, nothing... Use the RESTORE USER SCREEN key to
toggle the display between the debugger and the program. Still a blank screen,
so nothing important has happened yet. Now toggle the RESTORE USER SCREEN key
to get the debugger screen back and continue stepping through the code.

You will see another call and some more code, just step through them until you
reach the RETF instruction and stop there. Toggle the display with the RESTORE
USER SCREEN key, the screen is still blank...

But we executed all of the code within the call and are ready to return
without anything happening. The nag screen didn't get displayed nor did we
loose control and end up in the main program, How come?

Step over the RETF instruction with the SINGLE STEP key and you'll see why...
The address that we return to is not the next instruction after the original
call. Part of the code within the call we traced into revectored the return
address for the original call and sent us to an entirely different location
within the program.

This is why we lost control when we first stepped over the call, the debugger
was expecting the program to return to the next instruction after the original
call, but it never did...

So the instruction that we returned to was not the original line of code that
was expected, instead we are at another far call. If you haven't gotten lost
you should be at CS:0030 CALL CS:28BC.

Write down the address of the CS:IP and then step over this call with the
SINGLE STEP key, there is that annoying nag screen again. Hit a key to exit
the nag screen and control will be returned to the debugger. This time the
program returned from the call and you are in control again. So you now know
that this call is the one that displays the nag screen and it is the one you
want to kill.

Hit the RUN key and let the program run, now quit out of it from the main
program screen and reload it into the debugger. Use the GO TO command and
supply it the address for the call to the nag screen.

Ok, now lets see if the program will run or not if we don't execute the call
to the nag screen. The call is at CS:0030 and the next instruction after the
call is at address CS:0035... A quick way to jump past this call without
executing it is to just increment the instruction pointer register to the next
instruction.

In this case we want to manipulate the IP register, and we want to set it to


point to the instruction at CS:0035 instead of the instruction it is currently
pointing to at CS:0030. You are going to have to figure out the command on how
to do this with the debugger you are using yourself.

If you are using turbo debugger, place the mouse cursor on the line of code at
CS:0035 and right click the mouse. A window will pop up, then left click on
new IP, or increment IP. If you are using soft ice, type rip=0035 and hit
enter. Any other debugger, I have no clue...

Now that we've moved the IP past the call to the nag screen let's see if the
program is going to run. Hit the RUN key, this time the nag screen doesn't
come up, instead you are brought right into the main program screen.

It looks like getting rid of that call is going to do the trick. Now that we
know the program will run without making that call, it's time to decide on how
to patch the program so the call is never made again.

Think back to the original call we traced into for a minute, that call was the
one that revectored the return address and brought us to the call to the nag
screen. Therefore, it's reasonable to assume that that call is the protection
check, and it might be a good idea to have another look at it.

Before we do that there is one other thing I want to show you, and that's how
to allow the program to make the call to the nag screen and return from the
call without executing any of the code contained within it.

This isn't the method we will use to patch this program, but it's an important
concept to grasp as you'll end up doing it sooner or later on some other
program anyway. Remember that this is a far call and you can't just nop it
out.

Quit the program, reload it, and get to the address of the call to the nag
screen. Last time through we just incremented the IP to bypass it. Now we will
trace into it to see what it is doing.

Hit the TRACE key and trace into the call. Now start stepping through it with
the SINGLE STEP key, don't bother writing any addresses down for now. There
are several dozen calls in this routine along with shitloads of other code.

Toggle the display with the RESTORE USER SCREEN key after you step over a few
of the calls and you will see that the program is in the process of drawing
the nag screen.

Keep stepping through it and you'll see more and more of the screen being
drawn as the code progresses. This is getting boring, so stop stepping through
the code and start scrolling the code window down with the down arrow key and
watch the code. If you are using soft ice, the F6 key toggles the cursor
between the code and command windows, and the cursor must be in the code
window in order to scroll it.

What you are looking for is the RETF instruction as this is the end of the
call. Keep scrolling, I told you this call had a ton of code in it. When you
do find the RETF instruction write down it's address, it is CS:2B0E in case
your having trouble finding it. Ok, you've got the address of the RETF far
instruction written down so now just let the program run, quit out of it,
reload it, and get back to the call for the nag screen.

You should now be sitting at the call to the nag screen, trace into it and
stop. The first instruction of the call is MOV CX,0016 and this is where the
CS:IP should be pointing to. What we want to do now is to jump to the RETF
instruction and bypass all of the code within the call itself. So let's
re-assemble the MOV CX,0016 instruction and replace it with a new one.

First, make sure you are at this instruction, if you've traced passed it your
gonna have to reload the program and get back to it... OK, we are all sitting
at the MOV CX,0016 instruction and it's address is contained in the CS:IP
registers.

Now ASSEMBLE JMP 2B0E (the offset address of the RETF instruction) and specify
the address of the CS:IP. The MOV CX,0016 instruction will be replaced with
JMP 2B0E. And seeing as how both of these instructions are the same length we
didn't have to pad it out with any nop's.

Now hit the RUN key, you are brought into the main program and the nag screen
didn't get displayed! We allowed the program to make the call, but we didn't
allow any of the code within the call to be executed. And as far as the
program is concerned, it made the call and the nag screen was displayed.

Now let's go back and take another look at the call that we suspect is the one
that contains the protection check itself. Reload the program and go to the
original call that revectored the return address, now trace into it. I've
traced into the calls that are contained in here and they are setting up the
addresses for the RETF instruction at the end of this call among other things.
You don't need to trace into them as you might not understand what's going on,
but if you feel up to it, go right ahead.

What I want to concentrate on are the last four lines of code in the call as
they are the ones that finally set up the address to return to. Step through
the code until you are at CS:00A8 and take a look:
CS:00A8 8B04 MOV AX,[SI] DS:SI=0000
CS:00AA 053000 ADD AX,0030
CS:00AD 50 PUSH AX
CS:00AE CB RETF

The first instruction is loading the AX register with the contents of the
memory location that the SI register is pointing to. And you can see by
looking at the memory location that the DS:SI pair is pointing to that it
contains 0000. (this is where the display command and data window come in
handy).

The second instruction is adding 0030 to the contents of the AX register.

The third instruction is placing the contents of the AX register onto the top
of the stack.

The fourth instruction is returning from the call, and where do you think that
the RETF instruction gets the address for the return? Yep, you guessed it, it
gets it off the top of the stack. Funny that the instruction right before it
just placed something there isn't it?

Also funny is that it happens to be the address of the nag screen. Look at
what is being added to the AX register on the second line of code. Boy that
sure looks like the offset address to the nag screen to me.

Remember that the next instruction after the nag screen is CS:0035, now look
at the first line of code. The contents of the memory location it's
referencing contains 0000, and I'll bet that if your copy was registered it
would contain 0005 instead.

Why? because if the first instruction placed 0005 in the AX register, when the
second line of code added 0030 to it, you would end up with 0035 which happens
to be the address of the next line of code after the nag screen.

Then the third instruction would place 0035 on the stack and that is where the
RETF instruction would go to. If this were the case, the nag screen would
never get displayed...

Well, what do you think we should do? We could trace further back in the
program and try to find the instructions that place 0000 in that memory
location and modify them to place 0005 in there instead, but this process is
somewhat involved and I don't want to throw too much at you at once.

Instead, I have an easier solution. Seeing as how the memory location will
always contain 0000, why don't we just change the ADD AX,0030 instruction to
ADD AX,0035? This should get the correct address placed on the stack for the
RETF instruction to bypass the nag screen...

Let's try it and see how it works. SINGLE STEP through the code until the
CS:IP is at the instruction ADD AX,0030. Now, ASSEMBLE the instruction to read
ADD AX,0035 and hit the RUN key. We are placed in the main program screen
without any stinkin' nag screen getting displayed!

Congratulations! you have just cracked your first program :) Try other methods
of patching the program besides the ones I went over. The next chapter will
deal with how to make the changes you've made permanent.

CHAPTER 5 HOW TO USE THE DISK EDITOR


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Ok, we cracked budget minder in the debugger and know it's going to work. Now
we need to make those changes permanent. The first thing we have to do before
we load the file into the disk editor is to create a search string.

So we are going to have to reload budget.exe into the debugger and trace back
to the location where we want to make the patch in order to get the hex bytes
of the instructions we want to search the disk file for.

Load budget.exe back into the debugger and trace back to the last four
instructions of the original call that revectored the return address. You
should be looking at this:

CS:00A8 8B04 MOV AX,[SI]


CS:00AA 053000 ADD AX,0030
CS:00AD 50 PUSH AX
CS:00AE CB RETF

The group of numbers to the right of the addresses are the hexadecimal
representations of the mnemonic instructions. These are the bytes that we will
use for our search string. So write them down beginning from top left to
bottom right so you end up with this: 8B0405300050CB

This is the byte pattern that we will search for when we load the file into
the disk editor. We have a search string, but we also need to make a patch
string as well. In order to do this, we will have to assemble the new
instructions in memory, and then write down the changes we've made to the
code.

So ASSEMBLE ADD AX,35 and specify the address for the old ADD AX,0030
instruction. The new code should look like this:

CS:00A8 8B04 MOV AX,[SI]


CS:00AA 053500 ADD AX,0035
CS:00AD 50 PUSH AX
CS:00AE CB RETF

Notice that we only re-assembled the second line of code and that is the only
difference between the new code and the original code. So what I want you to
do is to write down the changes under the old code it replaced so it looks
like this:

8B0405300050CB <-- search string


^
5 <-- patch string

Now we are all set to load the file into the disk editor. We have a string to
search for and another one to replace it with. Load budget.exe into your disk
editor, select the search function, and input the search string.

NOTE: some disk editors default to an ASCII search so you may have to toggle
this to hex search instead. If your in the wrong mode, the disk editor will
not find the byte pattern your looking for.

Once the disk editor finds the byte pattern of the search string, just replace
the bytes of the old code with the bytes to the new code and save it to disk.
The program is now permanently cracked.

Sometimes however, the code you want to patch is generic enough that the
search string will pop up in several different locations throughout the file.
It's always a good idea to keep searching for the byte pattern after you've
found the first match. If the disk editor doesn't find any more matches your
all set.

If the string you are searching for is contained in more than one location and
you patch the wrong one the crack will not work, or you will end up with a
system crash when you run the program. In this case, you'll have to reload the
program back into the debugger and create a more unique search string by
including more instructions around the patch site in the search string.

One last thing, you cannot include instructions that reference dynamic memory
locations in the search string. These bytes are not contained in the disk
file. So keep this in mind when you are creating your search strings...

And the protection might not be included in the main executable either. If you
cannot find the search string in the main exe file, load the other program
files into the disk editor and search them as well, especially overlay files.
Fortunately for you, I've included a tool to help you do this.

CHAPTER 6 OTHER CRACKING TOOLS


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

In addtion to UNP, there are several other tools that you can utilize to make
your job easier. These tools were not designed with the cracker in mind, but
they can be adapted to serve our purposes rather than the ones which they were
written for.

UNP and other programs like it were written to remove the compression
envelopes from exectables so you would be able to scan those files with a
virus scanner among other things. If someone were to attach a virus to an exe
file and then compress it, the file for all intents and purposes would be
encrypted. Now when you downloaded that file and ran your virus scanner on it,
it might not find the virus.

But crackers found a different use for these types of programs. We use them to
remove the compression envelope so that we can find the byte strings we want
to search the files for. I'm sure most of the programmers who wrote these
programs never intended them for this purpose. There are some out there though
that were written by crackers with this exact purpose in mind.

Don't just rely on UNP as your only program to do this. No one program will be
able to remove evrything you come across. It's a good idea to start collecting
these types of programs so you have more than one alternative if you come
across a compressed file, and your favorite expander doesn't understand the
routines. Be aware though that some programs are actually encrypted and not
compressed. In this case the expander programs will prove useless.

Your only recourse in this instance is to reverse engineer the encryption


routine while the program is decrypting to memory, and modify your search
string to search for the encrypted version of the bytes. Or you could write a
tsr patcher that impliments your patch after the program is decrypted to
memory.

There is another category of programs you can adapt to your use and they work
in conjunction with the file expanders. These types of programs will scan
entire directories of files and pop up a window that displays which files are
compressed and what they are compressed with. They won't remove the
compression routines from the files themselves, but will only inform you which
files are compressed and which are not. UNP also includes a command line
switch to do this...

Now instead of blindly running UNP on several different program files to see
if they are compressed or not, you can see at a glance if you even need to run
it at all. And if you do, you'll know exactly which files to run it on. This
is another time saving type of program and there are several out there, you
just have to look for them.

Another type of program that you will find useful will scan entire
disks/directories/subdirectories of files for specific hex or ascii byte
patterns contained within those files, and this is the purpose of the second
uuencoded cracking tool contained in this guide.

One method I use to determine if a shareware program is registerable or not


before actually loading it into the debugger is to use this tool.

I usually will have it scan all the programs files and input the string REG.
This will show all files that contain the string unREGistered and REGistered.
If it returns a string that contains REGistered in a file other than the doc
files, I know the program can be made into the registered version. This is
just a quick check I do on programs that have certain features diabled to
determine if the program does contain the code for the registered version.

An added feature of this program is that after you've cracked a program and
have a byte string to search for, you can run this program in hex mode and
input your search string. Now it will search all of the programs files and
return the name of the file that contains your search string, then you can
just load that file into the disk editor and make the patch.

It will also let you know if your search string is contained in more than one
location within the file. Remember, if this is the case you'll have to reload
the program back into the debugger and create a larger search string by
including more instructions around the patch site.

The programs name is SS303 and it's very easy to use, just read the docs for
it...

These are the 'accessory' tools I use in cracking, there are several more out
there, I just don't have any use for them. And if you are dilligent, these are
all you'll really need as well.

CHAPTER 7 SOURCE CODE TO A SIMPLE BYTE PATCHER


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

As I've stated in the overview chapter, if you want to distribute your patches
you are going to have to write a patcher program. Simply releasing the patched
version of the program file is not desirable. For one thing it's illegal,
another consideration is size. Some files you patch will be 300K or more, and
this is quite a large crack to release. The patcher program included in this
guide is much much smaller, it will assemble to about 600 bytes or so,
depending on the size of your logo.

And what if you want the end user to be able to register the program in their
own name? A patched .exe or .ovr file will not allow this.

When you release a patch that you yourself wrote, you are not breaking any
laws. The program was written by you and is your intellectual property to do
with as you see fit, including making it available for public use. The person
breaking the law is the end user who will use it to illegally modify someone
elses intellectual property contrary to the licencing terms they agreed to
when they installed the program. Remember, it's not illegal to write and
distribute a crack, but it is illegal to apply a crack.

That's why all of the programs I've included in this guide are shareware
programs in the original archives as released by the authors and have not been
tampered with in any way. I'm not about to release a modified version of
someone elses copyrighted property. The only thing I am doing is supplying you
with the original archive and the information on how to modify it if you wish,
this is not illegal. If you decide to take the program and modify it that's
your problem, not mine...

This patcher routine is very simple, I wrote it about 5 years ago and it was
my very first patcher program. It is a brute force patcher in that it will not
do any error checking and blindly patch the program you specify with the byte
pattern you supply. This method has it's advantages and disavantages.

The disadvantage to this method is that seeing how the program does not
perform any error checking it will patch the file specified with the
replacement string even if it's not the correct version of the program. If the
filename is the same, the patch will be applied.

Let's say you crack a program called Ultimate Menu and the version number is
1.0, and the file you patch is called menu.exe. Now let's say a little while
later version 1.5 of the program comes out and someone who has your patch for
version 1.0 decides to run it on version 1.5 of the program.

This byte patcher will not check the new menu.exe for any changes before
making the patch, it will just patch the program in the location you specified
with the string you supplied even if the code you want to change is no longer
there. This could very well be the case if the programmer has significantly
re-written the code between versions, and what will end up happening is the
file will be corrupted and probably crash the system when it is run.

But this is also the advantage of my byte patcher. If the code to be replaced
is still in the same location in the new version, you'll not have to release a
new crack for each version of the program. Bear in mind that when I wrote this
program I was just starting out and didn't consider these possibilities. The
reason I included it in this guide was to give you an idea on how to write
your own patcher or to modify this one to suit your own purposes.

The patcher program that I use now is extremely complex and would just confuse
the hell out of you. Basically what I do is to make a backup of the original
file I am going to patch and then patch the original file. Then I run my
patcher program on the two files, it compares the differences between the
original file and the patched one and saves them to a data file. I then
assemble a patch using the data file.

What I end up with is a patch that will check the file you are running it on
to see if it is indeed the correct version before applying the patch. If it's
not, the patch won't be made. This method also allows me to make multiple
patches at different locations throughout the program. The byte patcher
included in this guide will only allow one string to be patched in one
location. But if you do a clean crack, that's all you'll usually need anyway.

Ok. here is the source code to the patcher program, I've commented as much as
I could throughout the code to make it more understandable. I also wrote it to
be generic enough so that you can re-use it over and over simply by plugging
in certain values and re-assembling it.

NOTE: the patch offsets are not the segment:offset adresses of the code as it
resides in memory, but the offset from the beginning of the disk file.

.model small
.code
ORG 100H
start: JMP begin
;******************************************************************************
; these are all the variables you set to crack a file,
; simply change the values and then assemble the program
;******************************************************************************

msb EQU 0000H ;the first part of the patch offset


lsb EQU 055AH ;the second part of the patch offset
cnt EQU 3H ;number of bytes in your patch
patch_data DB 'EB2E90',0 ;the byte string to be written
file_name DB 'go.pdm',0 ;the name of the file to be patched

logo DB 'Cracked by Uncle Joe',0AH,0DH


DB ' -=W.A.S.P. 92=- ',0AH,0DH

error1 DB 'FILE NOT FOUND',0AH,0DH


DB 'Make sure you have GO_CRACK.COM in the same',0AH,0DH
DB 'directory as GO.PDM',0AH,0DH
DB '$'

error2 DB 'A fatal error has occured',0AH,0DH


DB 'the crack was not applied',0AH,0DH
DB '$'

error3 DB 'GO.PDM has the read only attribute set',0AH,0DH


DB 'reset it before attempting to make the patch',0AH,0DH
DB '$'

handle DW 0

;******************************************************************************
; this procedure opens the file to be cracked
;******************************************************************************

open_it PROC near


MOV DX,offset file_name ;setup to open file to be
MOV AX,3D02H ;cracked
INT 21H
JNC done ;if successful, continue

CMP AX,05H
JZ read_only
MOV AH,09H ;else display error message
MOV DX,offset error1 ;and exit
INT 21H
JMP exit
read_only: MOV AH,09H
MOV DX,offset error3
INT 21H
JMP exit

done: MOV handle,AX ;store the file handle for


RET ;use later and return
open_it ENDP

;******************************************************************************
; this procedure sets the file pointer to the patch location
;******************************************************************************

move_it PROC near


MOV AH,42H ;setup to move the file
MOV AL,00H ;pointer to the patch site
MOV BX,handle ;load the file handle
MOV CX,msb ;the first part of offset
MOV DX,lsb ;and the second part
INT 21H ;move the pointer
JNC ok ;if successful, continue

MOV AH,09H
MOV DX,offset error2
INT 21H ;else print error message and
JMP exit ;exit
ok: RET
move_it ENDP

;******************************************************************************
; this procedure writes the crack to the file and closes it
;******************************************************************************

patch_it PROC near


MOV AH,40H ;setup to write the crack
MOV BX,handle ;load file handle
MOV CX,cnt ;load number of bytes to write
MOV DX,offset patch_data ;point DX to patch data
INT 21H ;make the patch

JNC close_it ;if successful, contintue


MOV AH,3EH
INT 21H
MOV AH,09H ;if not then something
MOV DX,offset error2 ;is wrong, disk may be write
INT 21H ;protected. If so, print error
JMP exit ;message and exit

close_it: MOV AH,3EH ;crack was successful


INT 21H ;close file and return
RET
patch_it ENDP

;******************************************************************************
; the main program
;******************************************************************************

begin PROC near


CALL open_it ;open file to be patched
CALL move_it ;move pointer to patch site
CALL patch_it ;make the patch and close file
MOV AH,09H
MOV DX,offset logo ;display logo
INT 21H

exit: MOV AX,4C00H ;and exit


INT 21H
begin ENDP

END START

CHAPTER 8 CONCLUSION
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Hopefully this guide has been useful in helping you understand the cracking
process. It is by no means an all inclusive guide, the main goal I had in mind
when I wrote it was to give beginners a push without confusing the hell out of
them.

It is not feasable to try and include all of the tricks of the trade that a
beginner might find useful into one single guide, nor would I want to do this.
For one thing, this guide would be ten times the size it is now, and even then
it would not be an encyclopedia of what to do for every situation. If your
serious enough about cracking, you will discover enough tricks and develop
your own methods as you progress. And you have to be creative! What works in
one situation may not work again in a similar one.

Instead, I tried to give you a general idea on how a programs code might
operate and what to look for. A successful cracker is not someone who
memorizes a specific set of actions to perform on a specific piece of code. A
successful cracker is someone who understands the flow of the code, and how to
adapt his methods to successfuly re-write the programs code to behave as he
wishes and not as the programmer intended it to. There are no set rules for
this, the very nature of the PC won't allow it.

If you have any questions about cracking or are stumped by something, drop me
a note at an575063@anon.penet.fi, I'll be glad to give any advice I can. Or if
you simply just wish to discuss cracking techniques or anything of that
nature.

NOTE: Do NOT mail me and ask me to crack programs for you! I'm not interested
in cracking for the masses. If you need something cracked, learn how to crack
it yourself. If you are unwilling to learn how, then register it.
Archea Hacking - Intro to GameHacking

<~~ http://www.archeahacking.com ~~>

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>

***What is GameHacking?***

There are two main ways people hack games.

I.) Editing values.


You can edit the values in your memory for health
and such by finding the "hexadecimal address" of
the value. A hex address specifies a specific location
in your memory or a file. Once you know the hex
address of the value you want to change, you can
hack it by "writing" to the address what value you
want it to be.

II.) Editing code.


You can change the functioning of a program/game
to make it perform how you want it to. The most
common gamehacking method is to NOP a command in
the game's code that will, as example, decrease
your health when you are shot. By NOP'ing a command,
instead of the program thinking it should, in our
example, decrease your health, it reads no operation
and continues with the rest of the code. You can also
change the code to a different function, like have it
INCREASE your health when you are shot as opposed to
decreasing it.

--What is Hex?

Hex is a base 16 numeric system. That means it has 16


characters. In hex you count up to F, which is 15 in our
number system.

Decimal: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Hex: 0 1 2 3 4 5 6 7 8 9 A B C D E F

FYI, Decimal is the number system we use day to day.

--What is Hex Editing?

Hex editing is editing the contents of a file or memory


in hex (pretty simple eh?). You use hex editing when you
are hacking saved game files and such.

--What's a *TRAINER*?

A trainer is a program that writes to your memory hacking


the specified game for you. Trainers are either made with
kits that can be found on the internet, or by writing your
own in one of the various programming languages.

--Why do those stupid people say they're 1337 4nD t41K 1iK3
tH1s?
There are some people who make idiots of themselves online,
dont be one of them. ;-)

--What's a Saved Game Editor?

Well, it edits saved games, if you couldn't figure that out.

--What are *Packets*?

Packets are chunks of information sent between a client and


a server. These chunks of information can be intercepted and
edited. By many this is considered a more advanced type of
gamehacking, but thats because none of them seem to understand
it ;-).

--How do I find hex addresses so I can hack games?

You need a memory scanner to find hex addresses. You can


find both tutorials on how to use them and links to where
you can download them at www.archeahacking.com.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>
Note from author:
This is just a little something I whipped together as an intro,
if you think there is something more i should include, email
me at archea47@archeahacking.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>

-=Archea47=-
Archea Hacking
www.archeahacking.com

== DO NOT EAT ==
FINDING AND USING STRINGS IN PROTECTED EXE's

Tools:
TSearch.

What you will learn:


These days, most commercial games are protected with wrappers such as
SAFEDISC, which encase the original EXE and add protection to it such as
ways to read data from an original CD, it its not present then DO NOT
LOAD GAME. Then there are PACKERS such as ASProtect. These take an
exe, shrink its file size and add a whole bunch of other protections such as
anti- debugging code. The real EXE gets unpacked in memory only.

What I am trying to say is that you can not DISASSEMBLE these files using
WinDASM or any other disassembler because the program entry point and
import address tables are changed or corrupted. This is bad because you
can't look through the disassembled code for string references. These can
USUALLY help you locate important game functions.

Start:
I will use the game HelBreath for my example, because it is protected with
ASProtect. One thing to note is that search.dll from HelBreath contains anti-
TSearch code, so please rename TSearch.exe to anything but TSearch.exe,
such as TS.exe. Otherwise the game will exit for you.

So now you are playing the game, and lets say that you put your health
potion in the EXCHANGE window. If you try to use a health potion now, it
will tell you the following: "You can't use a potion while exchanging" in the
bottom left corner of the game screen.

Jump back into TSearch, select HelGame.exe as the process. And now
click on the Hex Editor Button.

This should bring up the Hex View window. (Pictured below)


Click on the find button, under value select ASCII. Type in "You can't use a potion while exchanging"
(without the quotes). Hit Find Next.

You should come to the above. (I did the highlighting in a GFX editor, you will not see it). You can
see that the string is stored at address 4A5230 in memory. (A string consists of a bunch of chars,
terminated with a NULL (0x00)) It starts at 4A5230 and ends at 4A5258 with a 00.

In order to use a string a program must first PUSH it. So if we were able to disassemble the EXE (if
it was unpacked) with WinDasm you would see something similar to the following:

*Possible string reference "You can't use a potion while exchanging"


ADDRESS HEX ASM OP CODES
:xxxxxxxxxx 6830524A00 PUSH 4A5230

But we do not have the luxury of an unpacked exe. So we cannot just click on the string reference in
WinDasm and find out where that string is PUSHed in game code. We can do the next best thing
though.

The PUSH op code in hex is represented as 0x68. Then follows the address to push in REVERSE
BYTE ORDER. So 0x4A5230 becomes 0x30 0x52 0x4A 0x00. That last 0x00 is there because in
reality it is PUSH 0x004A5230, most disassemblers just do not show it. So our complete PUSH
004A5230 looks like this: 68 30 52 4A 00

Now go and click on the GO TO ADDRESS button in your HVIEW window, and type in 400000 to
get back to the beggining of the game's memory space. Now click on FIND, but this time select HEX
rather then ASCII and type in 68 30 52 4A 00.
You will find two results at 0x446481 and 0x4465E2, so at those two places in game code there is a
PUSH 004A5230.

Click on AUTOHACK. Enable Debugger. Then click on show Autohack window. Now select the
Autohack Window and click on EDIT -> DISASSEMBLE. When the window pops up type in
446481. Now click on the TAB called Disassembler.

:446474 83BD74DE040001 cmp dword ptr [ebp+0x4de74], 0x1


:44647b 750E jnz short 0x0044648b
:44647d 6A01 push 0x1
:44647f 6A0A push 0xA
:446481 6830524A00 push 0x4A5230

You should now be at :446481. Now if you scroll up, by right clicking and hitting JUMP 50 LINES
BACKWARDS. You will see a conditional jump at 44647b. The code compares some value inside
of [ebp+0x4de74] with 1 at :446474. If the value is not 0, then it should jump to some other part of
the code. If the value is 0, then it should continue with the code, and it will push the "You can't use a
potion while exchanging" string onto the STACK and then it will give the user that error. So what we
need to do here, is change that JNZ to a JMP. So change the 75 to an EB.

Now we go to the second part where we found the PUSH reference.

:4465d5 83BD74DE040001 cmp dword ptr [ebp+0x4de74], 0x1


:4465dc 750E jnz short 0x0044648b
:4465de 6A01 push 0x1
:4465e0 6A0A push 0xA
:4465e2 6830524A00 push 0x4A5230

Looks like its doing the same thing, checking if some value is not 0, and then react accordingly. So
again, change the JNZ to an JMP.

Conclusion:
Now you will be able to use health potions / mana potions while in trade mode. But more
importantly, you will be able to use string references to your advantage even without being able to
take apart the EXE with WinDasm.

^chaos^
December 11th, 2002

chaos world (c) 2002


Do not distribute as your own
Making one sided one hit kill hacks - Register compare method
by EEDOK
best read in 800x600 resolution
Mr_eedok@hotmail.com
-------------------------------------------------------------------------------------
Foreword:
Yea I know I've been putting off a lot of gamehacking for my game, and I've been
meaning to do this tutorial for a while, but just for you guys, I'm going to take
some time off my game and write this tutorial for you. :)
-------------------------------------------------------------------------------------
Recommended for this tutorial:
Artmoney
Softice
A game that uses the same routine for both player and npc
Knowing how to find addresses.
Knowing how to make a general 1 hit kill hack.
Basic ASM
-------------------------------------------------------------------------------------
Theory:
The problem with forcing jumps in routines is that the computer ends up getting the
same advantage, and you end up dying instantly too. One way around this is to find
the area of the function which identifies the player being killed and make it so
instant death only runs when it's not you.
-------------------------------------------------------------------------------------
Getting Started:

1. Open up your memory searcher, and find your health address.

2. Open up Softice, and set a on write breakpoint on your health address.

3. make your health decrease so you end up at the health decrementing routine.

4. Moving down the code you may notice something interesting after the health decrementing
routine, looks like cmp _____ , 0x0 and a jump after that.

5. force the jump after that to make sure it's the code to determine death.

6. If the condition of 5 is done look at the register for the area of the memory that's being
compared to 0, there's 3 possibilities: Your health pointer, a static identifier register, or
a dynamic identifier register.

7. Make the:
cmp ___, 0
jle deathroutine
portion of the code
to jump to a code cave, what you enter depends on the result of 6.

If it is your health pointer:

8. In the code cave make it something like this.

cmp [healthpointer], identifier register


jne deathroutine
jmp back

If it's not your health pointer:

8. Search for a pointer to the identifier.

If you can find a pointer:

8a. Make a function like this in your code cave:

cmp [identifier address], identifier


jne deathroutine
jmp back

If it's a static identifier:

If there's an unused register:

8a. Make a function like so:


mov unused register, identifier value
cmp unused register, identifier
jne deathroutine
jmp back

If there isn't an unused register:

8a. function:
push register not used in routine
mov register just pushed, identifier value
cmp unused register, identifier
jne _routine1
pop register pushed at beginning
jmp back
_routine1:
pop register pushed at beginning
jmp deathroutine
-----------------------------------------------------------------
Special note: If you can use your health pointer in this routine, use it!!! as
Identifiers are different on different operating systems!
-----------------------------------------------------------------
Shouts to:

Devious: Stonerifik, Tsongkie, Omega, Synbios, Micral, Mini^Me, brzi, Invader, Sn0w

renzo, bie, ddh, Vortexion, routine_error, [Ginger], Ultimate, Zekk

Web sites:

http://devious.tsongkie.com
http://voidofmind.com/eedok
http://www.ghu.as.ro

Feel free to tell me about corrections, or additions I should make to this tutorial.
If you find a copy of this tutorial on a site not listed above, feel free to contact
me about it, I'll take care of the rest.
Defeating DMA - Pointer Searching using Tsearch
by EEDOK
best read in 800x600 resolution, maximized
Mr_eedok@hotmail.com

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

What you'll need to do this tutorial:


Tsearch 1.5 or later
Tsongkie's GHME - available at http://www.devious.tsongkie.com/devious.php?id=tra
Hexadecimal Calculator

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

Theory:
In many games that use DMA it is common to see commands like this: mov [esi+0x4],
means is copy eax to an area of memory 4 bytes from a pointer. The pointer it ref
normally stored somewhere in the memory of the program. So to be able to hack pro
this, we would just read the pointer add the offset manually, and we would then h
which we want to hack.
This is beneficial over nopping, or reversing asm commands because:
1. You don't have to modify any of the asm code.
2. You can make the address any value, anytime.
3. A segment of code does not have to be initialized.
4. Allows for one sided hacks where certain functions are shared between the CPU

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

Getting started:

1. Open up Tsearch and the GTM, pause the GTM and find the address for money

2. In Tsearch hit Autohack>enable debugger, Go into the GTM and unpause it until
changes, then go back into Tsearch, and hit Autohack>Autohack Window.

3. In the Autohack Window it should have popped at 4011DB: sub [esi+0x4],eax, wha
is subtract the value of eax, from the area of memory 4 bytes away from the point
to know here is that the current address is +0x4 bytes from the pointer.

4. Open up your hexadecimal calculator and put in your current address(in hex), t
from it(also in hex).

5. Convert the result of the previous step to decimal format and search for it in
done correctly you should have the address 403138.

6. Hit the restart button so the location of the address of money changes, you sh
value of 403138 changes.

7. Read the value of 403138, convert the value to hexadecimal, then add 4 to it,
you the new location of money. This will work even if you restart the program.

8. Make a function in your trainer to read address 403138 and add 4 to it, then w
offset.

------------------------------------------------------------
Possible problem and solution:

I noticed this when I was playing GTA3 and wanted to hack my health, and the prob
when I did a search for pointers I ended up with more than 50 addresses.. So here
A)Had Artmoney to search for the new locations of my health value.
B)Had Tsearch open to find my pointer.
Well first I did the search for the pointer in Tsearch and immediately got 54 add
restarted GTA3. After restarting I used artmoney to refind my health address, and
it I searched for my pointer value again. This resulted in 14 results for a point
restarted the program again, and deleted the possible pointers that turned to 0,
they're definitely not a pointer to what I wanted. I repeated finding my health a
for a new pointer, which resulted in 6 addresses being found. At this time I noti
time I restarted the game, all 6 addresses were the same as each other, no matter
at what time I started the game, so I just used the one closest to the programs e

-----------------------------------------------------------------
Shouts to:

Devious: Stonerifik, Tsongkie, Omega, Synbios, Micral, Mini^Me, brzi, Invader, Sn

renzo, bie, ddh, Vortexion, routine_error, [Ginger], Ultimate, Zekk

Web sites:

http://devious.tsongkie.com
http://voidofmind.com/eedok
http://www.ghu.as.ro

Feel free to tell me about corrections, or additions I should make to this tutori
If you find a copy of this tutorial on a site not listed above, feel free to cont
me about it, I'll take care of the rest.
*********************************************************************************

ÜÜÜÜÛÛÜÜÜÜÜÜ
Û²ÛÛÛÛÛÛÝ
ßÛ Û²ÛÛÛÛÛÛ Ûßß ß
Û Û²ÛÛÛÛÛÛ Û ÜÜÜÜÜÜ nmls^bafh
ÜÜÜÜÜÜ Û²ÛÛÛÛÛÛÞÜÜÛÛÛÛ²ÛÛ ÜÜÜÜÜÜ ÜÜÜÜÜÜ
ÜÜÜÛßßßßÛÜÜÛßß ÜÜ ßß ÛÛ²ÛÛÛÛÛßßßßßßßßß ÜÜÛßß ÜÜ ßßßÛÜÜÜ ÜÜÛßß ÜÜ ßßßÛÜÜÜ
ÜÜÜÛÛÜÜÜÜÜÜÛÛÛÛÛÛÛÜÜÞßßÛÛÛÛ Ûßßßßßßßß ÜÛßß ÜÜÛÛÛÛÛÛÛÜÜÜ ßß ÜÜÜÛÛÛÛÛÛÛÜÜÜ ßßß
° ÝÛÛÛÛÛÛÛÛÝßßÛÛÛÛ²ÛÛÛÛÛÞßÛÛÛ ÜÜÜÛßßßßßÛÜ ÜÜÛÛÛßßßÛÛÛÛÛÛ²ÛÛÛÞßÛÛßÝßÛÛÛÛÛÛ²ÛÛÜ
° Û²ÛÛÛÛÛÛ ° ÝÛÛÛÛÛÛ²ÛÛÛÞÛÛÛÞÛ ÜÜÜÛÛÛÜÜÜÜÞß²ÛÝ° ÝÝÛÛÛÛÛÛÛ²ÛÛÞÛÝ ° ßÛÛÛÛÛÛ²ÛÛ °
±° Û²ÛÛÛÛÛÛ °°ÝÛÛÛÛÛÛÛ²ÛÛÞÛÛÛ ± ÝÛÛÛÛÛÛ²ÛÛÛÞ²ÛÞ±° ÜÛÛÛÛÛÛÛÛÛßÞÛ °°±ÝÛÛÛÛÛÛÛÛÝ °
±± Û²²ÛÛÛÛÛ ±° ÛÛÛÛÛÛÛ²ÛÛÞÛÛÛ ±² ÛÛÛÛÛÛÛ²ÛÛÝßÛÛÜÜÜÜÜÜÜÜÞßÞ ÝÜÛÛ °±² ÜÜÜÜÜÜÜ ±°
²± ÛÛ²ÛÛÛÛÛÞ²± ÛÛÛÛÛÛÛ²ÛÛÞÛÛÛÞ²²ÞÛÛÛÛÛÛÛ²ÛÛÝÞÝßßßßßÛÛÛÛÛÛÛÛÜÞßÛÞ²² ÞÛÛÛÛÛÛÛÛÜ ±
²²ÞÛÛ²ÛÛÛÛÛÞ²²ÞÛÛÛÛÛÛÛ²ÛÛÞÛÛÛÞ²ÞÜÛÛÛÛÛ²ÛÛÛÛÞ²ÜÞ²² ÞÞÛÛÛÛÛÛ²ÛÛÞ²Þ ²ÞÜÛÛÛÛÛÛ²ÛÛ ²
²²ÞÛÛÛÛÛÛÛÛÞ² ÞÛÛÛÛÛ²ÛÛÛÛÞ²ÛÛÜÜÛÛÛÛÛÛÛÛßßßÞÜÛÛÛÜÜÜÛÛÛÛÛÛÛ²ÛÛß ÛÛÜÞÜÛÛÛÛÛÛ²ÛÛß ²
² ßßßßßÛÛßß Ü ßßßßßßßßßß ÜÜÜÜÜÜÜÜ ßßß ÜÜ ßßßßßßßÛÛÛÛÛßßßßßß Ü ßßßÛÛÛÛÛÛÛßßß ÜÜÜ
ßßßßßÛÜÜÜÜÛß ßßßßßßßßßßßßß ßßßßßßß ßßßßßßÛÜÜÜÜÜÜÜÛßßßßßßßßÛÜÜÜÜÜÜÜÜÜÛßßß

Training Games on PC´s (Windows specific)


written by [NtSC] over/2001/2002

*********************************************************************************
Disclaimer:
-----------
If you request Nuke for People,when they release a Trainer with the same Options
you have,just delete this Tutorial,and kill yourself.It was in Case not written
for kiddie Morons wich make 50% of the todays Internet.

About me..
----------
I am doing Trainers / Reverse Engineering of code since 1986...
C-64,Amiga,SuperNES,GameBoy Advanced and Pc now..

Began training Games on PC in January 2001

Tools I use to train:


---------------------
- W32Dasm
- SoftIce
- GameHack v2.0
- MagicTrainerCreator
- BlindFind (my own Tool,for Alt-Tab protected Games..)
- Icedump < for Mem-Dumps + Anti-Debugging Features >

Language I code in:


-------------------
- No Masm,just Tasm.. (Borland Turbo Assembler v5.0)

Lets start our little Tutorial..

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

The Search:
-----------

(with SoftIce useable)


- Fastest Way is to use a GameHack-Tool and search for the Option
Adresses.When Adresses are found set an Breakpoint on Region with
Softice. (Adress: 4df000 / bpr 4df000 4df001 w) this means...
SoftIce will break up when a (w)rite Access appears to that
Adress.When SoftIce pops up,you should be at the Decrement for
the Adress.

(SoftIce unuseable,due to GFX-Setup of Game)

- Find Adresses with GameHack-Tool.Start W32Dasm and disassemble


the Game.exe.Go to search Option and search for the Adress your
GameHack-Tool provided.You should find Inits, or Decrements when it uses
static Memory Adresses. DMA Adressing would end in no Results (normally...)..!

W32Dasm Problems:
-----------------

- SomeTimes when you try to disassemble an Program with W32DASM


you will not get any Code Line.This is done via an manipulation
of the PE-Header Section Flags. The fucked up Flags look
like: 400000C0 or 600000C0..you have to patch these Flags,in case
you want to disassemble it correctly.With these Flags set,
the .code Section is declared as an Data Section and W32Dasm
will not disassemble them correctly.Change the Flags to: E0000020
for most of the normal Sections,and just give the code section
20000060 and try then...should work....if the Program is packed,
W32Dasm will give no correct Informations anyway.You´ll have to
depack it first.

* Note: Nowadays,for Shareware mangled Section Flags are 90% of 100 done
through Pe-Crypters or Packers like for example Asprotect..
In that Case you will have to find some Depacker for that
Crypter/Packer used on that Program..
Or just dump and rebuild...Can you?..

Alt-Tab Protections:
--------------------
Some Things i found through the Time are:

a) check the existing Windowname / WindowClasses / .exe Names of running Proces


for known GameHack-Tools.
WindowName or WindowClass = one of known GameHackTool = shutup Game
Name of an running Process = one of known GameHackTool = shutup Game
Solution = change WindowName / WindowClass/ .exe Name of y

b) Key Combination setup.


Variants:
...Alt-Tab disabled
...no switch back to Game,after Alt-Tab
...if Alt-Tab pressed,quit Game

See Examples for more Info on that....

c) poor Game coding...the Game isnt able to restore the Screen after Task-Switc
At this time,you have only the Chance to use SoftIce-Plugins.

d) Auto-Setback Game Window to Foreground-Window


Check Actual ForeGroundWindow,if it is not the GameWindow,set GameWindow
back to actual ForeGroundWindow.
Done with a nice Timer,itll make the lil Trainerguys dizzy I think...

Alt-Tab-Protection-Examples:
----------------------------

Example from Game: The Smurfs,lets get loose


Dll: wkeykill.dll
---------------------------------------------------------------------------------

Header from wkeykill.dll / W32Dasm Output

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++


Number of Imported Modules = 2 (decimal)

Import Module 001: KERNEL32.dll


Import Module 002: USER32.dll

+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++

Import Module 001: KERNEL32.dll

Addr:000020B0 hint(00FE) Name: GetModuleHandleA


Addr:00002094 hint(0051) Name: DisableThreadLibraryCalls

Import Module 002: USER32.dll

Addr:000020D2 hint(00D7) Name: GetAsyncKeyState


Addr:000020E6 hint(0011) Name: CallNextHookEx
Addr:000020F8 hint(0248) Name: UnhookWindowsHookEx
Addr:0000210E hint(0234) Name: SystemParametersInfoA
Addr:00002126 hint(0225) Name: SetWindowsHookExA

+++++++++++++++++++ EXPORTED FUNCTIONS ++++++++++++++++++


Number of Exported Functions = 0001 (decimal)

Addr:10001210 Ord: 1 (0001h) Name: Kill

+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++


//********************** Start of Code in Object .text **************
Program Entry Point = 10001000 (wkeykill.dll File Offset:00001800)

This Nice dll kills just the Alt-Tab switching..


But no big Deal...

Number of Exports = 1, Function-Name: Kill ...uhhh..ph3aR!!!!

Load the Exe into W32Dasm...


Use StrnRef and look up WkeyKill.dll
You land here...

* Referenced by a CALL at Address:


|:0041509D
|

* Possible StringData Ref from Data Obj ->"WKeyKill.dll"


|
:00431E60 6820EB4C00 push 004CEB20
* Reference To: KERNEL32.LoadLibraryA, Ord:01C2h
|

Obfuscatlly,when training and not using SOftIce-Plugins, we need to remove the Al


Protection... Notice that :Referenced by a CALL at Address:|:0041509D
Lets hook that one up.....

:00415094 A1D4CF6300 mov eax, dword ptr [0063CFD4]


:00415099 85C0 test eax, eax
:0041509B 7405 je 004150A2
:0041509D E8BECD0100 call 00431E60

* Referenced by a (U)nconditional or (C)onditional Jump at Address:


|:0041509B(C)
|
:004150A2 FF05CCCF6300 inc dword ptr [0063CFCC]

Hmm... Loads an Dword-Adress into Eax,and tests..If Pointer Value = 0 WKeyKill,dl


will not be loaded..Fine..
So,no big Deal,..change the conditional Jump at Adess 41509b to an Jmp,and we are

:0041509B EB05 jmp 004150A2 <-- Should look like this..

Fine,ready,go and Train...Alt-Tab switchable now...

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

GameHack-Tool-Protections:
--------------------------

- just checking for WindowNames,WindowClasses / active Processes of known GameHac


Means...Check...if Window "GameHackTool V1.0" is active,fake Adresses or
Shutup...Solution = change GameHackTool-Title,same for WindowClass,Tool .exe Na

Option-Hint #1 (with SoftIce):


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

- lets say you find an Adress at d93200 wich offers the Lifes you have
in an Game.Set a Breakpoint on Region with SoftIce

bpr d80000 db0000 w ; this means, SoftIce pops up when there is an


(w)rite access to an Adress in the Area from
d80000 db0000..In case most Options are stored
in the same Area of Game-Memory, just loose
something (Wepon-Shot,Energy...)..if SoftIce
pops up, you may have found a new Adress.
To search up the Decrement/Increment use the
Technic already descibed above.

Option-Hint #2 (with SoftIce):


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

- you need at least one Option-Adress..


Set a Breakpoint on your found Adress..and press Escape or whatever to go back
Game-Menu..Start a new Game..Softice should in 70% of 100 cases popup at a nice
init-Routine where the Games sets up the Values,..Lives,Level,..whatever..
Just write down the ADresses that are initialized,and check em Ingame..
Set them to 0/1 or whatever,and check what the change Affects..

Advanced Training #1(without SofIce/GameHackTools):


---------------------------------------------------
- needed : some knowledge of Assembler Programming (Instructions)

- use W32Dasm to disassemble the Game (if protected read Section above)
lets say you have 300 Minutes of Time in the Game,just look for an
Assembler Instruction that mov´s the Hexadezimal-Value to an Memory
Adress ( 300 dezimal = 012c hexadezimal)...write down MemoryAdress
were Value is stored,or Adress of Instruction that mov´s the Value.
In most cases you should find only some Instructions/Adresses and
you can check them via Patching in the Code.Adresses outside the
Memory can be checked via an Beta-Ingame-Key Tester.

-----------------------------------------------------------------------
Avoiding the Failure to take DMA as an direct Memory Adress:
------------------------------------------------------------
- DMA Memory is alloctacted by the Game..Its mostly used when the Game has an
Save-Option,or either is big in Size..These Adresses change..That means,
every time you start your Game, it normally has changed Adresses....
If you just access the Dma-Adresses as direct ones,your Trainer prolly
would not work..

Getting a useable Pointer to DMA-Adresses:


------------------------------------------
- Find at least one Option Adress..Just say Lives....
Go on,and set a breakpoint on the Adress..
Lose 1 Life,and our Numega Friend (SoftIce) should pop up...
what do we see now??...

Lets say...The Instruction on your actual EIP-3 is..


dec [ecx+14] .. What does this tell us?
It prolly decrements from Memory Adress ecx+14...
On easy Cases ecx just contains your DMA-Baseadress...
fine...how do we find the actual store Adress of it??
ecx = 02213567
s 0 l ffffffff 67 35 21 02 <-- we search for that Adress in Memory
| | (Adress is BACKWARDS,notice that...)
| |___ EndAdress
|___StartAdress (program Base-Adress,normally,400000,not ever..)

If SoftIce says: Pattern found at 0030:004bc4f6

It will mean...the Pointer to your DMA is stored at Adress 4bc4f6 by the


Program..

Example on How to access our found DMA-Adress:


----------------------------------------------
PAdress1 equ 004bc4f6h <-- the SoftIce ´Pattern foun

call ReadProcessMemory,PHandle,PAdress1,edx,Byte4,0 <-- Read 4 Bytes (DMA-Base)


add dword ptr [edx],014h <-- Add Value to get to Optio
(remember dec [ecx+14])
|__= Valu
mov dword ptr ecx,[edx]
mov [AdressStore],ecx
call ReadProcessMemory,PHandle,ecx,edx,Byte4,0 <-- Read our ´Update´ Dma-Adr
(should contain Adress of Li
add dword ptr [edx],001h <-- Add one Life
mov ecx,[AdressStore]
call WriteProcessMemory,PHandle,ecx,edx,Byte4,0 <-- Store Updated Adress

Thats it..
No Mythos...Just a bit Experience..
It was an easy Example..there are also Games wich store an Adress over another Ad
you would have to read out both Adress,before you can modify your one..

-------------------------------------------
No valueable DMA-Pointer found,what now?
-------------------------------------------
Lets say,you found an Memory Adress,for Example 1ab3d00.
It holds Money you have in the Game...: $1.000.000
You put a Memory-Breakpoint on it,bpm 1ab3d00.
Buy something,so hopefully SoftIce will pop up,since the Adress will get changed.
SoftIce pops up at: 4432a3: mov [ecx+14],edx
[Ecx+14] = Adress 1ab3d00 , and we have not found a valid Pointer to the DMA-
Adress to read it out in our Trainermenu.
Edx holds the new Value to be inserted ($1.000.000 - what we bought...)
So,we do an Maximum Money Option for it...
How?..We just change the code before that mov [ecx+14],edx.
I guess a Subtract will be done,before the mov [ecx+14],edx.
Change the Subtract to: mov edx,$5f5e100 = maximum Money [$5f5e100 = 100.000.000]
Make sure the Instructions have the same Length,otherwise Nop out the obfuscating
That means now...
Everytime the Game would normally Subtract our Money,
We fill up the Money Adress with maximum Value [$100.000.000]

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

-------------------------------------------------
Examples of Different-Routines,stolen from Games:
-------------------------------------------------

Example from: Pearl Harbor - Strike at Dawn German [Energy]


------------------------------------------------------------
Mainly, you can handle Energy Adresses like an Normal Value.
That means,..Energy = 05 Hex,wsprintf -> decimal -> Display -> Energy: 05
Most non Shareware-Games use other Display Methods like
for an Example a Bar that fades out, moving Display...
These Routines mostly have an look like the Routine below,
as they are mostly handled through float operations.

:004312FF D9442418 fld dword ptr [esp+18]


:00431303 D8642410 fsub dword ptr [esp+10]
:00431307 DEC9 fmulp st(1), st(0)
:00431309 D8442410 fadd dword ptr [esp+10]
:0043130D D95C2418 fstp dword ptr [esp+18] <-- Store float

Example from: Sega Bass Fishing [Line]


---------------------------------------
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00478414(U), :00478421(C)
|
:0047842B D90560A77501 fld dword ptr [0175A760]
:00478431 D80D00064B00 fmul dword ptr [004B0600]
:00478437 D8C1 fadd st(0), st(1)
:00478439 D80DF0034B00 fmul dword ptr [004B03F0]
:0047843F D91D60A77501 fstp dword ptr [0175A760] <-- Store float
:00478445 A160A77501 mov eax, dword ptr [0175A760]
:0047844A 50 push eax

Example from: Sega Bass Fishing [Time]


---------------------------------------
:0045CA5B A148AD7501 mov eax, dword ptr [0175AD48]
:0045CA60 40 inc eax
:0045CA61 83F83C cmp eax, 0000003C <-- Time/Millis
:0045CA64 A348AD7501 mov dword ptr [0175AD48], eax
:0045CA69 7C77 jl 0045CAE2 <-- if not 60 g
:0045CA6B A150AD7501 mov eax, dword ptr [0175AD50]
:0045CA70 48 dec eax <-- if 60 = dec
:0045CA71 A350AD7501 mov dword ptr [0175AD50], eax

Example from: Sega Marine Fishing [Time]


-----------------------------------------
:0044A6C6 F6C308 test bl, 08
:0044A6C9 752F jne 0044A6FA <-- eb and go..
:0044A6CB 8B0D680B6500 mov ecx, dword ptr [00650B68]
:0044A6D1 85C9 test ecx, ecx
:0044A6D3 7408 je 0044A6DD
:0044A6D5 D905E4C24C00 fld dword ptr [004CC2E4]

Example from: Sega Marine Fishing [Line]


-----------------------------------------
The tricky Part was here,the Line itself was splitted into 2 Counters.

:004ABC6C 890D04FE6400 mov dword ptr [0064FE04], ecx


:004ABC72 D91510FE6400 fst dword ptr [0064FE10] <-- needs to be
:004ABC78 7C06 jl 004ABC80
:004ABC7A 893D04FE6400 mov dword ptr [0064FE04], edi

* Referenced by a (U)nconditional or (C)onditional Jump at Address:


|:004ABC78(C)
|
:004ABC80 D91D14FE6400 fstp dword ptr [0064FE14] <-- needs to be
:004ABC86 E895B4FCFF call 00477120
:004ABC8B D90514FE6400 fld dword ptr [0064FE14]

Example from: Shark Hunting the Great White [Energy / shark_game.dll]


----------------------------------------------------------------------
:100124B4 8B86A0000000 mov eax, dword ptr [esi+000000A0]
:100124BA D986040F0000 fld dword ptr [esi+00000F04]
:100124C0 8B4830 mov ecx, dword ptr [eax+30]
:100124C3 D986800F0000 fld dword ptr [esi+00000F80]
:100124C9 8B5034 mov edx, dword ptr [eax+34]
:100124CC 894C2408 mov dword ptr [esp+08], ecx
:100124D0 8954240C mov dword ptr [esp+0C], edx
:100124D4 DC4C2408 fmul qword ptr [esp+08]
:100124D8 DEE9 fsubp st(1), st(0)
:100124DA D99E040F0000 fstp dword ptr [esi+00000F04] <-- Store floa

Example from: Hunting Unlimited [Time / ho_game.dll]


-----------------------------------------------------
:100416A7 D944240C fld dword ptr [esp+0C]
:100416AB D88608010000 fadd dword ptr [esi+00000108]
:100416B1 D99E08010000 fstp dword ptr [esi+00000108]
:100416B7 D98604010000 fld dword ptr [esi+00000104]
:100416BD D864240C fsub dword ptr [esp+0C]
:100416C1 D95C240C fstp dword ptr [esp+0C]
:100416C5 D944240C fld dword ptr [esp+0C]
:100416C9 8B44240C mov eax, dword ptr [esp+0C]
:100416CD D81D54990710 fcomp dword ptr [10079954]
:100416D3 898604010000 mov dword ptr [esi+00000104], eax <-- Store flo
:100416D9 DFE0 fstsw ax

Example from: MegaMan Man Legends [MegaMan.exe / Energy]


---------------------------------------------------------
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004AD9CE(C)
|
:004AD9D9 668B516E mov dx, word ptr [ecx+6E] <-- Load Energ
:004AD9DD 6685D2 test dx, dx <-- already ze
:004AD9E0 7E1A jle 004AD9FC <-- if yes,bye
:004AD9E2 89D0 mov eax, edx
:004AD9E4 29D8 sub eax, ebx <-- otherwise
:004AD9E6 6689416E mov word ptr [ecx+6E], ax <-- and store
:004AD9EA 6685C0 test ax, ax <-- Zero now?
:004AD9ED 7F15 jg 004ADA04 <-- if not,jum
:004AD9EF 66C7416E0000 mov [ecx+6E], 0000 <-- otherwise
:004AD9F5 E88A8FF8FF call 00436984
:004AD9FA EB08 jmp 004ADA04

Example from: Autobahn Total - Die Verfolgungsjagd *German* - [Track Unlocker]


-------------------------------------------------------------------------------
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00419058(C)
|
:00419235 85DB test ebx, ebx
:00419237 7513 jne 0041924C
:00419239 F744241000000100 test [esp+10], 00010000 <-- Track unlo
:00419241 0F84EC050000 je 00419833 <-- no,go away
:00419247 E9C8000000 jmp 00419314 <-- yes,enable

On this,we just change:


:00419239 F744241000000100 test [esp+10], 00010000 <-- Track unlo
to
:00419239 C744241000000100 mov [esp+10], 00010000 <-- Track alwa

Ok,the Track will prolly not be enabled now...We need to kill the jmp at adress
00419241 too...I did it by writing EB04 to adress 00419241,this will insert a Jum
419247...but,you can also insert 6 Nops (6 x 90) to clear the instruction..
Main Idea is the same,writing my jump is 2 Bytes,noping is 6 Bytes...Choose
yourself...!

Example from: From Dusk till Dawn *GERMAN* - [Energy] / Code Fake
-----------------------------------------------------------------
:005119CB A804 test al, 04
:005119CD 7409 je 005119D8
:005119CF 5F pop edi
:005119D0 B801000000 mov eax, 00000001
:005119D5 5E pop esi
:005119D6 59 pop ecx
:005119D7 C3 ret

* Referenced by a (U)nconditional or (C)onditional Jump at Address:


|:005119CD(C)
|
:005119D8 8B8FF74D0000 mov ecx, dword ptr [edi+00004DF7]
:005119DE 2BCA sub ecx, edx
:005119E0 898FF74D0000 mov dword ptr [edi+00004DF7], ecx

The Test al, 04 at Adress 5119CB checks for any Sprite Collision.
This can be an Enemy or You. We see the sub ecx,edx at Adress 5119de
but if we erase it, we AND our Enemies will also be invincible.
So,CHECK your Register when you enter the Sub-Routine at Adress
5119d8. If an Collision was detected Register ESI sets the Flag to
compare between us,and Enemy.We land at, an Collision that would
decrease our Energy would be Register ESI = 0.
What to do now?

:005119CB A804 test al, 04


:005119CD 7409 je 005119D8

We simply change that to:

:005119CB 85f6 test esi, esi


:005119CD 7509 jnz 005119D8

And thats it,...If a Collision on our Player is counted,well will simply


not conditional Branch to the Sub-Routine wich subtracts the Energy.
If its an enemy Collision <ESI not 0> it will still branch.

Example from: DownTown [Game Init] / Delphi-Game,High Adresses + Alt-Tab Protecte


---------------------------------------------------------------------------------
:0049C262 C705A001EE05C8000000 mov dword ptr [05EE01A0], 000000C8
:0049C26C C705A401EE05C8000000 mov dword ptr [05EE01A4], 000000C8
:0049C276 C705A801EE05C8000000 mov dword ptr [05EE01A8], 000000C8

Ok,quick Step...000000C8 = Decimal 200,a Value I found in the Game.


I used W32Dasm and searched 00c8,initiated by a mov instruction.
[To land in the Game init]...Works..Alt-Tab would close the Game btw!

Example from: Dexters Laboratory: Science Ain´t Fair [Energy]


--------------------------------------------------------------
:00417BFC 754F jne 00417C4D <-- change to EB
:00417BFE D9460C fld dword ptr [esi+0C]
:00417C01 D82584494700 fsub dword ptr [00474984]
:00417C07 D9560C fst dword ptr [esi+0C]
:00417C0A D81D14454700 fcomp dword ptr [00474514]
:00417C10 DFE0 fstsw ax
:00417C12 F6C401 test ah, 01
:00417C15 0F84DB000000 je 00417CF6
:00417C1B 68DC050000 push 000005DC

Example from: Trade Empires *GERMAN* [Money]


---------------------------------------------
Original Code was:

0177:004B11CF 90 NOP
0177:004B11D0 55 PUSH EBP
0177:004B11D1 8BEC MOV EBP,ESP
0177:004B11D3 8B510C MOV EDX,[ECX+0C] <-- Adress Mo
0177:004B11D6 8B4508 MOV EAX,[EBP+08] <-- Adress In
0177:004B11D9 03D0 ADD EDX,EAX

eax can here now be an -,or + Value. That means our add instruction
can add a Value,but if the Value eax is negative it can also sub a Value.

0177:004B11DB 89510C MOV [ECX+0C],EDX <-- Store new


0177:004B11DE 5D POP EBP
0177:004B11DF C20400 RET 0004
0177:004B11E2 90 NOP

The Code i came up with for my Trainer:

0177:004B11D0 55 PUSH EBP


0177:004B11D1 8BEC MOV EBP,ESP
0177:004B11D3 8B4508 MOV EAX,[EBP+08] <-- Get Inc/D
0177:004B11D6 85C0 TEST EAX,EAX <-- is it 0?
0177:004B11D8 7E04 JLE 004B11DE <-- or a - Va
0177:004B11DA 01410C ADD [ECX+0C],EAX <-- if not,le
0177:004B11DD 90 NOP
0177:004B11DE 5D POP EBP
0177:004B11DF C20400 RET 0004

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

Hints on Values:
----------------

Options search:
---------------

Suche Wert: 5 -------->


5
4/-1
6/+1

Unlock:
-----------
Gamestart: 0 -------->
1
not equal

Cars/Tracks:
-------------
Gamestart: 0 -------->
1
not equal
Datafields /1/ne

Invincible:
-------------
Gamestart: 0 --------> Flicker Timer
greater than
less than
equal
General Unlocking:
--------------------
Manipulate the Game, for example racing Games to always be first.
Play the Game,until a new Car/Track is unlocked and examine the
Changes.

Invincibility:
**************
- first 0
After a Collision some Timer gets initialized,wich is counted down afterwards.

Level-Skip:
***********
- most Games offer an defined Ammount of Items to get/destroy
(Example: 40 Items to destroy/Zero the Byte,and Level is skipped)

Timers:
*******
- can be stored as 2 Bytes (0801)

Lives:
******
- can be stored -1 (Display says 5 / 4 in Memory)
- can be stored as obfuscating Values 3/3 (use MemChange-Trainertool)

Weapons (Selector):
*******************
- there is mostly an Range of compares to the Adress
0001,0002,0003.....use W32Dasm to find multiple Adress compares

Cheat-Mode enable:
******************
- use W32Dasm to check for CheatMode-Text. If found, a CheatMode
is often made through a Password typed in.Patch the Password-Routine
to always enable/disable Cheat.Use a Memory-Compare-Tool to find the Byte wich
is set to enable/disable CheatMode.

Difficult Values:
-----------------
- Hard to find Timers / Level-Skip-Value Adresses can best be found
with an GameHack-Tool that has an ´Memchange´-Option like ´MTC´

***********************************************************************

Error-Fixing on Trainer-Programming:
-------------------------------------
This is an OpenProcess-Routine wich enables you to read and write to the
specified Game.The Flags are w9x/me + w2k tested.

call GetWindowThreadProcessId,eax,offset Pid

call OpenProcess,PROCESS_VM_READ OR PROCESS_VM_WRITE OR PROCESS_VM_OPERATION,


mov PHandle,eax
cmp eax,0
jz Error

Avoid to do ReadProcessMemory into Registers!


----------------------------------------------
Under W9x/me it worked well,but w2k messed it up..
So,this is how it should look like < Example => Check that Toggle1 >

call ReadProcessMemory,PHandle,0077e7a0h,offset Toggle1,Byte4,0


add [Toggle1],064h
call WriteProcessMemory,PHandle,0077e7a0h,offset Toggle1,Byte4,0

***********************************************************************

For any Contact or Exchange of Stuff: Trainerdude@hotmail.com


$$$$$$$$$$$$$$$$$ : $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$ : /| ?_?_? $
$ ._ / |__ ____ ____ ____ ____ ____ ____ $
$ ____| \/ \ _/ \/ \_ /: \/ \_ / ? \ $
$ / |o \ _// _\ | _/_|\ \ |/ ? \_ $
$ \ : /_ ) ____ \/\ |/ / \ _|_ \ $
$ / . \ \/ \ \ | / ?_ \ | /\/? ? $
$ / \ / \ / | \ | / _? + $
$ _ _ \__ |_____/___/\ /:___ /____ /__|_ / | \ \ / $
$ | |RECLAIM! |/ |/ |/ \_:_/ | \ \ / $
$ |_ | : : : \_ ? _\ \_/ $
$$$$$$$$ \ | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$: \___/\___/ $$$$$$$$$$$$$$
\|

Advanced Game Training by [sheep] a.k.a RECLAIM!


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

(best viewed in 1024x768)

LESSON : 1.

SUBJECT: DMA - Dynamic Memory Allocation.

TOOLS NEEDED: Softice, memory searcher (ur choice).

U now have in ur possetion (part 1) of an ever expanding tutorial covering


ADVANCED GAME HACKING (A.G.H).. Over the next few months i hope to write a series
of tutorials covering all aspects of A.G.H.. The lessons i will be teaching in
these tutorials will give u the needed skills to make the transition between
NEWBIE GAME HACKER to GAME HACK REVERSER..

Apart from the beginner stuff im about to introduce ive never seen any of the
information in my tutorials written anywhere else this may be due to people eithe
not wanting to give out advanced information that has taken them a long time to s
OR.. they just cant be bothered to write an extensive essay about this subject..
either way it doesnt matter because u are about to learn ALL!!

LESSON START
------------

WHAT IS DMA?
------------

Im sure u have all heard about DMA by now.. understanding what this is and how
to defeat it are the first steps of a mighty ladder. Ill try and stick to telling
u how DMA affects us (THE GAME HACKER) and not stray into too much technical deta

When a game uses DMA the memory locations it uses are allocated dynamically
whereby the game grabs the next available slot of memory and gives it to
whoever asked for it..

Generally there are so many variations going on while ur computer is running its
unlikely that the memory locations u get on one occasion will be the same next ti
reload the game.. this is why ur trainers only work just after u have collected t
addresses and NOT once u have reloaded.. Once the game is reloaded it will grab a
NEW set of memory locations for itself thus making ur OLD set of memory locations
To defeat DMA and create a trainer that will work 100% of the time u need to come
the realms of the NEWBIE and into the NEW LAND :)

NEW TOOL!
---------

This is where we start adding NEW tools to our cheaters arsenal.. the first tool
to add is called SOFTICE its a software debugger that enables u to manipulate the
code (on the fly) which means while the game is still running..

I wont go into installing softice in this tutorial.. there are plenty of other tu
that do that for u.. so from here on ill assume u already have it installed.

SOFTICE SETUP
-------------

When u press CTRL-D to pop softice u should see the following windows..

REGISTER WINDOW - this window is always at the very top of the softice window
(WR [return]) and displays the contents of all the registers..

DUMP WINDOW - generally situated close to the top of the softice window
(WD [return]) contains a split screen display.. one side is ascii the
other is hex.
CODE WINDOW - this is the main window.. sits just under the DUMP WINDOW
(WC [return]) contains the code of whatever process maybe running when
u pop softice.. the code is represented in ASSEMBLY LANGUAGE
instrutions..

The comments in the brackets are what u need to type to turn the different window
also u need to type CODE ON.. this will bring up the OPCODES which are a set of n
displayed to the left of each ASM instruction and to the right of every memory lo
in the CODE WINDOW..

(if u dont understand any ASM then i suggest u go away now and read up on a basic

DEFEATING DMA
-------------

THEORY
------

At the end of this section i will show u how DMA is defeated IN PRACTICE.. ill us
game ive recently trained showing u code listings so that u can apply the theory
example.. so dont worry if im not going into too much detail about setting breakp
etc.. it will all be covered in the PRACTICAL section....

As we cannot change the memory locations of a DMA game we need to get right to th
and by that i mean the GAME CODE.. once u have found ur memory locations in a NON
game u generally make ur trainer poke numbers into the locations u have found and
makes an affective trainer.. we know that this doesnt work for DMA so what we hav
is STOP the game code from decreasing our locations.. we do this by WATCHING what
happends to our memory locations while the game is running.. thankfully we dont n
sit there and do the WATCHING ourselves.. our new friend SOFTICE does it all for

example...
lets say i have 5 lives and the location of these lives is 490000.

We can all think logically so we know that when we die in the game the GAME CODE
decrease the location 490000 by 1.. We need to stop this from happening..

The way we do this is by setting something called a BREAKPOINT.. there are a few
of breakpoint available to us but the one we need at the moment is a MEMORY BREAK
this breakpoint will WATCH a memory location for us.. if anything should affect o
memory location then softice will then pop at the exact piece of code that affect
this means that when we die inside the game and the GAME CODE decreases our lives
will pop and we will find ourselves looking at the GAME CODE that decreases our l
GOOD STUFF EH? :)

Unfortunately this is where it starts to get tricky.. u NEED to be able to unders


u are looking at.. by this i mean u HAVE to learn at least the basics of ASSEMBLY
for some people this is too much and thats why they have given in.. but for many
have struggled and stuck to it and have at least got a small understanding of ASM

GAME CODE
---------

There is something VERY advantagious about GAME CODE.. IT NEVER CHANGES LOCATION.
right.. on every single game EVEN DMA GAMES.. if we find the GAME CODE that decre
lives at 453000 then u can bet ur life that the next time u load the game the EXA
code is at 453000 and this is the key to defeating DMA.. instead of poking values
DATA memory locations.. we are going to poke values into CODE memory locations..
they are the same thing fundamentally they just behave in different ways..

CODE KILLING
------------

This is what u will see inside softice..

ADDRESS...... OPCODES............ ASSEMBLY LANGUAGE.....

0120:00008096 01585A ADD [EAX+5A],EBX


0120:00008099 7404 JZ 0000809F
0120:0000809B B486 MOV AH,86
0120:0000809D EB17 JMP 000080B6
0120:0000809F 55 PUSH EBP
0120:000080A0 1E PUSH DS
0120:000080A1 50 PUSH EAX
0120:000080A2 E86E078ED8 CALL D88E8815

This is just a random code snippet taken from softice.. it has nothing to do with
of any kind i just wanted to show u what was what when it came to the CODE WINDOW
as this is the place u will be spending most of ur time...

now i will show u a section of code taken from a message board.. this is from a R

ADDRESS...... OPCODES........ ASSEMBLY LANGUAGE.......

016F:xxxxxxxx 0000 MOV EAX,[EDI]


016F:xxxxxxxx 0000 DEC EAX
016F:xxxxxxxx 0000 MOV [ESI+0C],ECX
016F:xxxxxxxx 0000 MOV [EDI],EAX
016F:xxxxxxxx 0000 MOV EDI,EAX

Ok, the assembly instructions are the only valid thing in the above code the rest
either been filled with 0000 for opcodes or xxxxxxxxx for the addresses.. these a
important at this time anyway....

The above code probably means absolutly nothing to u and dont worry because it sh

NOW!!! let me add a story and some comments to the above code...

We are playing a game... we have got 20 LIVES.. we find the location of these LIV
at 445566 we place a breakpoint on this location inside softice.. so that when so
affects our LIVES softice will pop and we can see the code that is affecting them

WE FALL DOWN A HOLE AND DIE!!!!

BANG!!!!

SOFTICE POPS!!!!!

this is what we see.....

ADDRESS...... OPCODES........ ASSEMBLY LANGUAGE.......

016F:xxxxxxxx 0000 MOV EAX,[EDI] <------ number of LIVES we already


is read from [EDI] and pla
EAX. (EDI=445566) (EAX=20)

016F:xxxxxxxx 0000 DEC EAX <------ EAX is decreased by 1 (EAX

016F:xxxxxxxx 0000 MOV [ESI+0C],ECX <------ store ECX.

016F:xxxxxxxx 0000 MOV [EDI],EAX <------ place NEW LIVES ammount ba


location 445566. (EDI=4455
(EAX=19)
SOFTICE LANDS HERE UNDER THE INSTRUCTION THAT
AFFECTED THE LIVES.... |
|
016F:xxxxxxxx 0000 MOV EDI,EAX

I hope the picture has become more clear to u now.. the lives are read from our l
then decreased by 1 and then placed back into our location.. im sure the clever o
reading this will already have figured out what we have to do.. but for the slowe
ill continue :)

016F:xxxxxxxx 48 DEC EAX <------ EAX is decreased by 1 (EAX =

Ok.. this is the NASTY instruction that is killing our poor little character... a
u can see ive put in the REAL OPCODE for this instruction its 48..

This instruction decreases our lives by 1 each time.. what we need to do is GET R
if we do then there is nothing to kill our little character and he can live forev
Thankfully we can do this within softice.. u need to replace the DEC EAX with som
else.. the all time fave for replacing stuff that isnt needed is an equally small
instruction called NOP which is NO-OPERATION.. thats correct.. when this instruct
executed absolutely nothing is done.. so KEEP this little NOP by ur side at all t

so if we replace

016F:xxxxxxxx 48 DEC EAX <------ EAX is decreased by 1 (EAX =

with..

016F:xxxxxxxx 90 NOP <------ NO OPERATION

then we have infinite lives.. its as easy as that..

THE THING ABOUT NOP


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

When u are replacing instructions inside a program u have to make sure that if an
instruction has 5 opcodes then u MUST replace it with 5 opcodes..

example...

0120:00008121 E86C04EB10 CALL 10EB8592

if i wanted to get rid of the above call.. i couldnt just put 1 NOP.. because NOP
i need to FILL E8-6C-04-EB-10 so instead of just NOP(90) i would need 5 NOPS 90-9
otherwise the program will most definately crash on u... so once u have replaced
it should look like this...

before...

0120:00008121 E86C04EB10 CALL 10EB8592

after....

0120:00008121 90 NOP
0120:00008123 90 NOP
0120:00008125 90 NOP
0120:00008127 90 NOP
0120:00008129 90 NOP

MAKING THE DMA TRAINER


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

A DMA trainer is no differnt in any way to a NORMAL trainer.. all u are doing is
values into the CODE section instead of the DATA section..

eaxmple...

replace..

016F:0000412345 48 DEC EAX <------ EAX is decreased by 1 (EAX

with..
016F:0000412345 90 NOP <------ NO OPERATION

Same Code but this time ive added the addresses and the correct OPCODES.. if i wa
make a trainer that worked 100% on this DMA game.. all i need to do is poke 90 (N
into location 412345.. this would turn the DEC EAX to a NOP and the game would ha
infinite lives.. no need to worry about DMA locations anymore.. 412345 WILL ALWA
be the place to poke 90 and get infinite lives.. GAME CODE DOES NOT CHANGE LOCATI

As i said at the beginning i havent gone into much detail about how to set breakp
this will all be taken care of in the next part of the tutorial..

PRACTICAL EXAMPLE (Serious Sam 2)


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

As i dont like to do things by half i will now show u a practical approach to def
DMA with code listings and softice commands.. this is just a backup of what is wr
above.. after this u should be able to understand the entire tutorial.. that is i
already :)...

These code listings and commands all come from the game SERIOUS SAM 2.. u dont ne
go and find this game but if u have it then it will make it a lot easier for u to
a go with what we have learnt today...

On this game ive decided to show u BULLETS instead of lives because the life tota
SS2 is worked out slightly differently (something i will be tackling in another t

ok.. lets begin..

1. I did a normal EXACT VALUE search to find the address for the bullets ..
i got the address 6AFEF28.

2. I POPPED softice with CTRL-D so that i could set a breakpoint on the bullets l

3. Inside softice i typed BPM 6AFEF28 W (the W means WRITE so when ever something
to our address softice will pop) then i pressed RETURN to set the breakpoint..

4. Return to the game.. SHOOT! BANG! SOFTICE POPS!

5. I scrolled the code window up a bit and this is the code listing...

ADDRESSES.... OPCODES............ ASSEMBLY LANGUAGE.........

017F:60570C50 55 PUSH EBP


017F:60570C51 8BEC MOV EBP,ESP
017F:60570C53 A1E8625E60 MOV EAX,[605E62E8]
017F:60570C58 8B08 MOV ECX,[EAX]
017F:60570C5A FF15E4625E60 CALL [605E62E4]
017F:60570C60 8B4854 MOV ECX,[EAX+54]
017F:60570C63 85C9 TEST ECX,ECX
017F:60570C65 7508 JNZ 60570C6F
017F:60570C67 8B4508 MOV EAX,[EBP+08] <--- Address of BULLETS
017F:60570C6A 8B4D0C MOV ECX,[EBP+0C] <--- Amount of BULLETS
decrease by.(ECX=1
017F:60570C6D 2908 SUB [EAX],ECX <--- subtract ECX(1)fro
017F:60570C6F 5D POP EBP <--- WE LAND HERE WHEN
017F:60570C70 C3 RET

As u can see even though its not the same code as before its VERY similar.. thats
thing about ASM there are only a couple of instructions that decrease the value o
address so they are easy to spot most of the time.. this time they use SUB.. whic
SUBTRACT.. ok.. to defeat this we need to get rid of that SUB instruction...

6. I typed A 60570C6D then pressed return.. this lets me manipulate the code at l
60570C6D..

7. I typed NOP [return] NOP [return] the returns mean i pressed return :) just to
any confusion.. I used 2 nops as u can see because remember we need to get rid
bytes of OPCODES 29-08 so we need to replace them with 2 bytes of our own OPCO
90-90..

8. I then pressed return a 3rd time without entering anything and softice drops o
assemble mode..

9. Now we are all done and ready to test it.. CTRL-D got me back into the game..
have infinite bullets.. and the dma is defeated..

dont forget.. game code doesnt change location.. to make a 100% working bullet tr
for this game all u need to do is poke 90,90 into location 60570C6D...

WELL!! we have come to the end of this tutorial.. i hope u managed to follow it a
obtain all the knowledge u need to defeat DMA.. keep a look out for other tutoria
in this series..

If u have any problems or questions then please email me at sheeprec@operamail.co


please be patient for a reply...

PLEASE FEEL FREE TO SPREAD THIS DOCUMENT TO ANY SITES!!!!!


$$$$$$$$$$$$$$$$$ : $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$ : /| ?_?_? $
$ ._ / |__ ____ ____ ____ ____ ____ ____ $
$ ____| \/ \ _/ \/ \_ /: \/ \_ / ? \ $
$ / |o \ _// _\ | _/_|\ \ |/ ? \_ $
$ \ : /_ ) ____ \/\ |/ / \ _|_ \ $
$ / . \ \/ \ \ | / ?_ \ | /\/? ? $
$ / \ / \ / | \ | / _? + $
$ _ _ \__ |_____/___/\ /:___ /____ /__|_ / | \ \ / $
$ | |RECLAIM! |/ |/ |/ \_:_/ | \ \ / $
$ |_ | : : : \_ ? _\ \_/ $
$$$$$$$$ \ | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$: \___/\___/ $$$$$$$$$$$$$$
\|

Advanced Game Training by [sheep] a.k.a RECLAIM!


************************************************

(best viewed in 1024x768)

LESSON : 2 (part 1)

SUBJECT: CODE INJECTION - DMA to STATIC Address.

TOOLS NEEDED: Softice, memory searcher (ur choice) gamehack.

U now have in ur possetion (Part 2 Section 1) of an ever expanding tutorial cover


ADVANCED GAME HACKING (A.G.H).. Over the next few months i hope to write a series
of tutorials covering all aspects of A.G.H.. The lessons i will be teaching in
these tutorials will give u the needed skills to make the transition between
NEWBIE GAME HACKER to GAME HACK REVERSER..

Before we do actually start i warn u that if u dont have certain prior knowledge
before attempting this tutorial then u wont get much out of it..

I suggest u most certainly read my previous tutorial which covers DMA in full det
U also need to know at least the basics of the ASM language...

with all that out the way lets continue....

SOFTICE SETUP
*************

When u press CTRL-D to pop softice u should see the following windows..

REGISTER WINDOW - this window is always at the very top of the softice window
(WR [return]) and displays the contents of all the registers..

DUMP WINDOW - generally situated close to the top of the softice window
(WD [return]) contains a split screen display.. one side is ascii the
other is hex.
CODE WINDOW - this is the main window.. sits just under the DUMP WINDOW
(WC [return]) contains the code of whatever process maybe running when
u pop softice.. the code is represented in ASSEMBLY LANGUAGE
instrutions..

The comments in the brackets are what u need to type to turn the different window
also u need to type CODE ON.. this will bring up the OPCODES which are a set of n
displayed to the left of each ASM instruction and to the right of every memory lo
in the CODE WINDOW..

LESSON START
************

ok.. To achieve the final goal of defeating DMA with CODE INJECTION u will need t
a few new concepts that u may not have come across before.. ive listed the concep
we will be covering below...

i) Code Injection Theory


ii) Offset Theory
iii) DMA to STATIC Outline
iv) DMA to STATIC Practical Code Injection

Once u have learnt the first 3 concepts u will most certainly be ready to tackle
4th and final one... good luck :))

CODE INJECTION THEORY


*********************

Code injection is a method used by advanced game hackers to achieve certain tasks
that cannot be achieved with NORMAL game training methods.. The main aim of code
injection is to create a pathway FROM the main GAME loop TO ur own code.. u then
jmp back to the main game loop after ur code has been executed.. what ur code doe
is only limited by ur knowledge of the game and of course ur knowledge of asm :))

Code injection is so flexible u can do pretty much anything u like.. breaking fre
of the restrictions of the normal NOP hacks....

Example...

This is a code snippet i used in my last tutorial.. its just an example so it doe
matter...

0120:00008096 01585A ADD [EAX+5A],EBX


0120:00008099 E9xxxxxxxx .---- JMP 500000 <--- we create our gatew
0120:0000809B B486 | MOV AH,86 <----.
0120:0000809F 55 | PUSH EBP |
0120:000080A0 1E | PUSH DS |
0120:000080A1 50 | PUSH EAX |
0120:000080A2 E86E078ED8 | CALL D88E8815 |
| |
| |
0120:00500000 OUR CODE! <---' |
0120:00500002 OUR CODE! |
0120:00500004 OUR CODE! |
0120:00500006 JMP 809B -------------------------------' <--- once our code is do

if u destroy any valuable instructions while making ur gateway.. u must make sure
re-create them inside the OUR CODE section.. or u will most likely crash the game
Dont forget this is only the theory.. a fully detailed "HOW TO" will follow in th
section lower down..

OFFSET THEORY
*************

We all know that DMA causes the variables of a game to change location every time
either start a new game or reboot completely.. Even though this is true.. DMA var
actually stay in the same place relevant to each other.. WHAT DO I MEAN?? i hear

ok.. ill give u an example...

00456777 : LIFE TOTAL


00456778 :
.........:
.........:
etc......:
.........:
00456999 : BULLET TOTAL

The above diagram is a hypothetical situation of 2 DMA variables.. we have LIFE T


at address 456777 and we have BULLET TOTAL at 456999 if u subtrack those 2 addres
from each other u get what is called an OFFSET.. 456999h-456777h = 222h (h = hex)
u will understand why we need offsets in just a second...

OK!! I RESTART MY GAME!!!

00659123 : LIFE TOTAL


00659124 :
.........:
.........:
etc......:
.........:
00659345 : BULLET TOTAL

Now we have restarted the variables have changed location.. BUT!! notice the actu
659345h-659123h = 222h. Even though the variables are allocated different memory
they always stay the same distance apart.. this is the KEY to the whole process..

The reason they stay the same distance apart is because each variable isnt actual
seperate memory locations.. a large chunk of memory containing most if not all ga
would be allocated the memory at run time...

Using offsets we can make a detailed map of every variable we need.. all we would
to do is pick 1 variable as the MASTER and find this address every time.. from th
address u will instantly know where the other variables are located in memory...

Another example....

Here is a made up offset map...

HEALTH COUNTER location = MASTER VARIABLE <--- find this address.


BULLETS location = MASTER VARIABLE + 3445h
LIVES location = MASTER VARIABLE + 2345h
SKILL POINTS location = MASTER VARIABLE + 334h

now.. we start our game... and find HEALTH COUNTER..

000657444 : HEALTH COUNTER

we can now change that map into REAL addresses.. like this..

HEALTH COUNTER location = 657444h + 0h = 657444h


BULLETS location = 657444h + 3445h = 65A889h
LIVES location = 657444h + 2345h = 659789h
SKILL POINTS location = 657444h + 334h = 657778h

So now u can see by making a Variable map using 1 MASTER variable we can find all
other variables with offsets :)) its pretty cool stuff eh? :)))

ok.. its pretty vital that u understand offsets BEFORE u go on.. if u dont unders
it then go back and RE-RE-RE READ....

DMA TO STATIC OUTLINE


*********************

Once u understand at least the basics of code injecting such as i explained ealie
u should'nt have too much trouble understanding the DMA to STATIC principles..

The outline goes something like this :-

We find a place in the game code that contains a POINTER to a variable we are usi
i.e LIVES, HEALTH, BULLETS etc..

Once we have found this POINTER we need to make sure that it is a SPECIFIC POINTE
which means it ONLY!! points to 1 location.. if the POINTER is GENERAL it will cy
through many places and manipulate many memory locations this is useless to us...

A pointer will look something like this .. MOV EAX,[EBX+00000208]

EBX will contain a DMA base address.. the 208 is an offset added to EBX to form t
POINTER which points to our variable (LIVES)..

Lets say that we know EBX+208 = LIVES.. we now need to find out if this is a SPEC
(points to only 1 address) and not a GENERAL pointer (points and manipulates many
we do this by placing a breakpoint on the MOV EAX,[EBX+00000208] instruction then
F5 to get out of softice.. every time softice pops up again look at the contents
if the number inside EBX doesnt change then we know that we have a SPECIFIC point
number inside EBX changes, even once, then this pointer is no good to us.. to get
if the address in EBX is SPECIFIC u should check the value in EBX at least 10 or
make sure its not changing...

ok, once we have found our SPECIFIC pointer.. we need to store away the DMA base
lies inside EBX (NOTE!! EBX doesnt always contain the DMA base value.. it could b
REGISTER.. u need to look at the pointer and see what REGISTER IS USED.. ie..

MOV EAX,[EBX+00000208] <-- EBX contains the store away value


MOV EAX,[ECX+00004564] <-- ECX contains the store away value
MOV EAX,[EDX+00001122] <-- EDX contains the store away value
MOV EAX,[ESI+00000234] <-- ESI contains the store away value
MOV EAX,[EDI+00004408] <-- EDI contains the store away value

just keep all that in mind.. pointers can take on many forms but i think the abov
than likely the type of thing u will encounter in most games...

ok.. so we need to store our DMA base value away into static memory.. we do this
pathway to our own code (code injection).. our code will then place the DMA base
inside EBX into a static address so that our trainer can read that address every
its own pointer by adding offsets to it.. and then poking values into that pointe

Here is a diagram to explain it a little more....

We have found our pointer.. below

Before we make our gateway...


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

0041A736 MOV EAX,[EBX+00000208] <----- pointer here...


0041A73C FLD REAL4 PTR [EBX+000000CC]
0041A742 FDIV REAL4 PTR [EBX+000000C8]
0041A748 MOV [00786CA4],EAX

After we make our gateway...


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

0041A736 JMP 9000000 <----- gateway has been created..


0041A73C FLD REAL4 PTR [EBX+000000CC]
0041A742 FDIV REAL4 PTR [EBX+000000C8]
0041A748 MOV [00786CA4],EAX

Our code section...


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

09000005 MOV EAX,[EBX+00000208] ; re-create instruction we destroyed to ma


09000010 MOV [9000100],EBX ; mov DMA base value in ebx into a static
09000015 JMP 41A73C ; Jump back to main game loop..
09000100 0000000000 ; location to store value from EBX

Once the above code has been executed u can now read the value from 9000100 and e
when the game changes its memory locations ur code will put the correct value bac
inside 9000100.. so all u need to do is read that value.. add 208 to it and u
have the exact location of LIVES.. remember?? lives = EBX+208...

thats pretty much the whole deal.. apart from the code that reads the value from
ill show u that in the PRACTICAL section below... dont worry if all that was a bi
take in.. keep flipping back to this section to re-read.. with the fully explaine
section u should be able to put them both together and understand it all..

DMA TO STATIC PRACTICAL CODE INJECT


***********************************

The game ive chosen for this tutorial is called SPACE TRIPPER..(thanks keyboardju
u can dload it from here.. http://www.pompom.org.uk/STpage1.htm
lets start...

First thing we need to do is find a MASTER variable.. ive chosen LIVES..


unfortuantly this game is a bit of a bitch for finding the LIVES value.. but with
asm knowledge (which u all should have by now :)) u will be fine...

oki.. we do the usual search.. die.. search die..

If u do it correctly u will only find 1 address .. and it will be this.. 786ca4


If u try and change this location u will notice that the screen updates but thats
about it.. u still have the same amount of LIVES as before thats because u havent
REAL address for LIVES.. dont worry!! i didnt expect u to.. ill tell u why.. this
just allocate memory every time u start a new game.. it allocates memory after ev
u die.. so its impossible for u to find the REAL value with a mem searcher.. than
the ON SCREEN variable is STATIC.. so from this variable we can quickly find the

This is how its done...

Using softice place a breakpoint on the ON SCREEN variable like this..

type BPM 786ca4 W (return)

lose a life..

softice POPS!!!!

u should see this...

0041A736 8B8308020000 MOV EAX,[EBX+00000208]; pointer moves REAL LIVES into


0041A73C D983CC000000 FLD REAL4 PTR [EBX+000000CC]
0041A742 D8B3C8000000 FDIV REAL4 PTR [EBX+000000C8]
0041A748 A3A46C7800 MOV [00786CA4],EAX ; Move REAL LIVES value into ON
; (ON SCREEN variable = 2 )

As u can see [EBX+00000208] is a POINTER to the REAL LIVES address in memory.. EB


a DMA base address which we need to store away and 208 is added to it so that EBX
The value from the REAL LIVES location is moved into EAX and then EAX is placed i
ON SCREEN variable memory location... to prove all this u need to do this..

In softice..

type D EBX+208 (return)

Now edit the memory location in the top left hand corner of the DUMP window and u
update properly.. showing u that we have found the REAL LIVES memory location...

Luckily enuff we have found 2 vital things with just 1 breakpoint.. we have found
memory address.. we have also found a potential POINTER to use in our CODE INJECT
if this POINTER is SPECIFIC or GENERAL.. once again we take to softice..

First of all we need to clear all other breakpoints so ...

type BC* (return)

then place a breakpoint on the 41a736 address...


type BPX 41A736 (return)

then press F5 to get out of softice..

softice should POP!! straight away..

Look at the content of EBX.. has the value changed??

keep pressing F5..

keep looking at the EBX content :))

is the value inside EBX changing?? if no!! we are IN!!! YAY!!!

So, now we have found a valid place to inject and save our POINTER into a static
address.. all we need to do now is find a nice place to put OUR CODE!! u can do t
a few ways..

1. Look up and down the code close to where u are injecting and see if there is a
cluster of NOPs.. (this is empty code).. also a large cluster of 0's signals a
OUR CODE location aswell..

2. If nothing turns up close to ur injecting address then do a search in softice


909090909090.. read the manual if u dont know how to search.. u should do by n

3. This is the method i use.. people tell me that they have encountered problems
this method but ive created about 20 to 30 trainers using it and its never giv
me a NON working trainer.. so until it does ill continue to use it..

i) type TASK (return) inside softice..


ii) find the name of ur game window..
iii) type MAP32 <game window name> (return)
iv) this will bring up all the sections of the game.. what we want to do is ad
the end of the data section.. here is what i get from Space Tripper...

:map32 spacetripper
Owner Obj Name Obj# Address Size Type
SPACETRIPP.text 0001 017F:00401000 0004BE10 CODE RO
SPACETRIPP.data 0002 0187:0044D000 00006718 IDATA RW
SPACETRIPP.bss 0003 0187:00454000 0035CDB4 UDATA RW
SPACETRIPP.idata 0004 0187:007B1000 000014F0 IDATA RW
SPACETRIPP.rsrc 0005 0187:007B3000 0000095C IDATA RO SHARED

The .data section starts at 44d000 but we need to use the end of the data section
usually a lot of buffered space on the end of the data section so we can happily
messing with any REAL data used by the game) so what we do is look at the next se
which is .bss the start of the .bss section is just after the very end of the .da

so, lets hunt for a nice place to put OUR CODE..

inside softice again...

type D 454000 (return)

Just to be on the safe side we need to scroll the dump window up a bit.. so that
on the end of the data section.. u will notice that when we scroll upwards the te
of the dump window will change.. from
SPACETRIPPER! .bss
to
SPACETRIPPER! .data+<offset>

to scroll the dump window up u need to do this..

type EB (return)

then use the PAGE UP / PAGE DOWN keys to move the window up and down :))

ive decided that 453f00 is a good place for use to place our code.. so the first
to do is write that memory address down.. so that u dont forget it...

now we have the address of OUR CODE.. we need to go back to the pointer at (41a73
our gateway.. it should still be inside ur code window but if it isnt then so do

type U 41a736 (return)

that will place 41a736 at the top of ur CODE window..

now we create the gateway...

***NOTE!!***
The next steps are all done one after the other .. u cannot break in the middle o
or attempt to come out of softice or u will crash the game....

type A 41a736 (return)


type jmp 453f00 (return)
type nop (return) ( we need this nop to ballance the opcodes and to avoid
type (return) ( this return on its own will take us out of (A)ssemble

at this point u should see the code window change from...

ORIGINAL CODE...
0041A736 8B8308020000 MOV EAX,[EBX+00000208]
0041A73C D983CC000000 FLD REAL4 PTR [EBX+000000CC]
0041A742 D8B3C8000000 FDIV REAL4 PTR [EBX+000000C8]
0041A748 A3A46C7800 MOV [00786CA4],EAX

to

AFTER GATEWAY CREATED...


0041A736 E9C5970300 JMP 00453F00
0041A73B 90 NOP
0041A73C D983CC000000 FLD REAL4 PTR [EBX+000000CC] <-- we jmp back here aft
0041A742 D8B3C8000000 FDIV REAL4 PTR [EBX+000000C8]
0041A748 A3A46C7800 MOV [00786CA4],EAX

ok.. next steps...

type U 453f00 (return)


type A 453f00 (return)

we are now ready to create the OUR CODE section...


First we must re-create the instruction that we destroyed to make our gateway...

type mov eax,[ebx+208] (return)

Now we need to store the POINTER into a static memory address.. all of the addres
around u are static.. so u can pick any one u like.. nothing too close to the cod
section .. i have chosen 453f30....

type mov dword ptr [453f30],ebx (return)

Now finally we need to jump back to the game code...

type jmp 41a73c (return) <-- 41a73c is just after our NOP instruction in the g

type (return) <-- gets u out of (A)ssemble mode..

ok.. after alllll that... ur code locations should look like this....

GATEWAY SECTION...
0041A736 E9C5970300 JMP 00453F00
0041A73B 90 NOP
0041A73C D983CC000000 FLD REAL4 PTR [EBX+000000CC]
0041A742 D8B3C8000000 FDIV REAL4 PTR [EBX+000000C8]
0041A748 A3A46C7800 MOV [00786CA4],EAX

OUR CODE SECTION...


00453F00 8B8308020000 MOV EAX,[EBX+00000208]
00453F06 891D303F4500 MOV [00453F30],EBX
00453F0C E92B68FCFF JMP 0041A73C
00453F11 0000 ADD [EAX],AL
00453F13 0000 ADD [EAX],AL

if ur code does not mirror that of mine then u have done something wrong.. u need
go back and redo it...

NOW!! if u HAVE the same code as me.. which u should have.. u can now press F5 to
exit softice.. and the game should be running fine...

we can now do something pretty cool to demostrate that this is ACTUALLY working..

go back into softice with CTRL-D..

type D *453f30+280 (return)

(if it says something like INVALID ADDRESS) u need to exit softice and then re-en
again...)

if all goes to plan in the top left hand corner of the dump window u will see the
address.. u can modify this and ur lives will change..

NOW FOR THE COOL PART!!!

lose all ur lives.. so that it says GAME OVER..

start a new game.. (dont reload the game) just start a new game...
if u look at the dump window.. u will notice that the LIVES location has changed.
ITS DMA !! :)))

but.. our code is still doing its job... its still storing away the dma value at
address so all u need to do to find the REAL lives value again.. is type that com

type D *453f30+280 (return)

and now in the top left hand corner of the dump window u will see the REAL LIVES

pretty damn cool eh?? :))

we have defeated DMA .. the DMA base address will ALWAYS!!! be stored at 453f30 a
to do is add 208 to it.. and u get the REAL LIVES address...

FINAL WORDS
***********

What can we do with this?


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

im sure the clever ones out there have already worked out how to use this in ur t
for those who are a little slower on the uptake ill explain...

once ur code is injected into the game.. u can then use READPROCESSMEMORY to gath
base address from 453f30.. then u just poke values into DMA_BASE_ADDRESS+208..
its as simple as that...

Injecting ur Code Injection! :)


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

Once u have done all that u obviously dont wanna go through all those steps every
need to inject ur code.. so u must create a trainer to inject the code for u.. it
simple..infact its the same process as ALL trainers.. except u will be dealing wi
bytes than usual....

Example for this tutorial...


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

For the code injection to work every time.. this is what u would need to poke in

At address 41a736..

u would need to poke E9,C5,97,03,00

At address 5f3f00

u would need to poke 8B,83,08,02,00,00,89,1D,30,3F,45,00,E9,2B,68,FC,FF

and thats it.. u will be able to read the DMA base address from 5f3f30..

basically all u do is poke all the OPCODES of the instructions we just wrote back
correct memory locations...

WORD OF WARNING!! always poke OUR CODE section OPCODES first... then the GATEWAY
FEW!!! another tutorial finished.. man!! its a lot of work..

*********************************************************************************
*********************************************************************************

If u have any questions or comments then email me at... RECLAIM22@HOTMAIL.COM

visit my site for more tutorials.. http://WWW.SHEEPREC.CJB.NET

I would just like to greet some people that support and inspire me....

Odin, MiraMax, Keyboard Junkie, Calligula, Orr, DarkLighter, Kilby, LordFinal, Ev


MiNiSTER, [NTSC], [Drone], Rizzah, Bengi...

No order.. just GREAT people..

If i missed anyone.. grab me and ill add u next time :))

PLEASE FEEL FREE TO SPREAD THIS DOCUMENT TO ANY SITES!!!!!


-= GAME HACKING : CODE INJECTION =-
WRITTEN BY: STRYKER1080
DATE: FEB 21, 2002
TUTORIAL: WORKING PAST DMA WITH CODE INJECTION 1 of 2

SPECIAL THANKS TO SHEEP FOR TEACHING ME THIS STUFF


I COULDNT HAVE DONE THIS WITHOUT YOU

** You should have a basic understanding of softice, and should be


able to NOP certain instructions, if you know this, you can inject
your own code.. If not, read a tutorial on DMA and using softice,
I suggest you reads Sheeps tutorial at http://geocities.com/smil0r26/agtp1.txt

First of all, if you dont know what code injection is i will explain
it to you. Just two weeks ago i did not know anything about code
injection... Just recently, 2 days ago, i did my first code injection
hack... So technically im a newbie at this, but i hope this will help
me explain this to you better.

Lets say you are playing your game, you found your health address..
ALLRIGHT, you poke it and you have infinite health. Now you pass the
level, and it doesnt work anymore!! WHAT THE HELL?? This is DMA, it
causes your memory addresses to change, so they are different all the
time... This is annoying, you can stop it from decreasing your health
by finding the operation that decreases it , and then by NOPING it,
but what if you want to do more?? What if you want to poke a value
into your changing memory addres? What if you want it to increase
instead of decreasing? Or what if just want some crazy stuff to happen
when u get shot? This can all be done by injecting your own code. All
you basically need is a paper, Softice, and the will to learn. I know
this can be hard, i had problems all the time, but you gotta keep
trying!! When you finnally learn you will be unstopable!

Ok lets get started. Ill be showing you what i did to hack


GTA 2, and get all weapons (plus the extra hidden ones), this hack
will work in single player and multiplayer...
Ok, i found my addy for my 1st weapon the pistol. THe addy is 047C45678,
now every level this addy would change. So what i do is i hide the gun,
Pop into softice, type

BPM 047C45678 W

THen i cycle weapon so i have gun, softice pops up. Here is what it says:

** I ONLY WROTE THE FIRST ADDRES DOWN BECAUSE THATS ALL I NEED, BUT I
NEED THE NEXT 3 COMMANDS... LIKE MOV EAX,[EDI+14] ....

ADDRES
005DBEO4 MOV [EDI],AX <- this puts a value into my ammo ([edi])
MOV EAX,[EDI+14] <- softice pops here
MOV ECX,[EAX+50]

So write down the first address on a paper on the left side, on the total
right side write down the command it does.... SO i would write this on paper:

ADDRES
005DBEO4 MOV [EDI],AX
MOV EAX,[EDI+14]
MOV ECX,[EAX+50]

Ok now we have the address that checks to see how much ammo we got. The
game at puts our ammo address's 047C45678 *VALUE into [EDI], [edi] is the
value of EDI... SO if EDI=047C45678, [EDI] would equal our amount of ammo...
BTW one bullet in GTA2=10... Ok still with me? Now since we have the line of
code(s) that we want to change we have to look for a place to put our code,
it just cant come out of nowhere. So this is what you do... You type
MAP32 <gamename>
You can find out what to write in <gamename> because it says it in the bottom
right corner of softice... For me it says GTA2 so i would write : MAP32 GTA2
**Some games have longer names like unrealtournament, and in softice itll only
show the first 8 letters i believe, so just write the name of the .exe you are
running. So if your playing a game and you are running the file game.exe,
you would type MAP32 GAME.

When you type that it should show you this:

OWNER OBJ NAME OBJ# ADDY SIZE TYPE

GTA2 .TEXT 0001 00401000


GTA2 .RDATA 0002 005C7000
GTA2 .DATA 0003 00610000
GTA2 .RSRC 0004 00705000

Ok, we have that. But what good does that do? See where it says .rsrc? Its at
0070500 right? Above rsrc 9/10 times there is no code. It is safe to put your
code there... So in softice type:
U 00705000
This will show you 00705000 in the main window. Now press ctrl+up or shift+up
to scroll up... **TYPE: CODE ON
Now you can scroll up, see all those 0000 above the address 00705000? ITs safe
to put your code here. Pick a address that you wanna put your code, pick
something easy to write down like 00704900, once your picked one, write down
the address. Ok we have ourselves a place to put our code. Now lets put our
own code in :)
type :
A <yournewcodelocation>
So if you picked 00704900 you would type A 00704900, it ask you to write a
instruction. Now remember those instruction we wrote down before, the
MOV [EDI],AX
MOV EAX,[EDI+14]
MOV ECX,[EAX+50]
we will place that first instruction into our first line of code. So when it
asks your to write the instruction write : MOV [EDI],AX
now it asks you to write the instruction for next address, it asks to write
it for 00704906, so write the second instruction and press enter. then put
in the third. Ok we put those instructions into our code. Just to make sure
the game is running or it didnt freeze because u made a mistake, pop out of
softice, and check if the game is still runing. If it is, pop back into
softice and type U 005DBEO4. Remember 005dbe04? THats the one addy we wrote
that we were gonna replace. Now we can see 005DBE04 in the main window
(code window). Now lets make the first line of code, the former MOV [EDI],AX
into a JMP so it jumps to our code... So type
A 005dbe04 <enter>
type : JMP 00704900 <enter>
As soon as you did that look what happens to our code:
BEFORE AFTER

005DBE04 MOV [EDI],AX 005DBE04 JMP 00704900


005dbe09 MOV EAX,[EDI+14] 005dbe09 ADD BX, EC
005dbe1c MOV ECX,[EAX+50] 005dbe1c JE 007112341

We only change one line of code, but everything else changed... WHAT THE HELL??
If we poped out of softice now into our game, i bet it would crash... SO lets
not make it crash.

Right after u typed : JMP 00704900


It asks you to type the next command. ALWAYS type in NOP for the next line.
THis will even the code out, trust me, you always need to NOP after the JMP.
Once we type the NOP look what happens:

*** IT MIGHT NOT LOOK LIKE THIS BUT IM JUST GIVING U AN EXAMPLE

BEFORE AFTER

005DBE04 JMP 00704900 005dbe04 JMP 00704900


005dbe09 ADD BX, EC 005dbe09 ADD BX, EC
005dbe1c JE 007112341 005dbe10 NOP
005dbe1c MOV ECX,[EAX+50]

LOOK AT 005DBE1C AFTER WE NOP!! THE COMMAND IS THE SAME AS IT USE TO BE BEFORE
WE EVEN ADDED OUR JMP!! SUCCES!! OK NOW LOOK BELOW 005dbe1c, the addy right
after it is the addy we will return to from OUR code. We cant just have the
game go to our code and nothing, it needs to return! IN OUR CODE THE LAST
LINE OF CODE WE PUT WAS MOV ECX,[EAX+50]. Now the next line of code after
that needs to be something that was in the original code, so the game thinks
its running normally, or else it could crash... So write down the next address
after 005dbe1c, it might be 005dbe1F...
Now type in
U 00704900 <enter> <-- so we can see our code in the main window
now the last line of code we put in was at lets say 0070491C, and the next
addy after that is 0070491F, we need to change taht 0070491f so it jumps
back to the original game code. So type
A 0070491f <enter>
INSTRUCTION: JMP 005dbe1F <enter>
<esc>

Now it should jump back to the original game code. Now this new code we put
in doesnt do anything special, we just put it in to see if the game would
still run if we put our new code in. This is the best way to check if u did
it right. By putting in the original code into the new code and jumping back
to original. Now pop out of softice, if your in the game playing normally
CONGRATULATIONS! You did code injection, if you were succesfull you probably
already know what you wanna change and how you can do it.. If the game got
frozen, or quit you did something wrong on the way. I know how upsetting it
can be, i was yelling at my computer just 1 week ago. Keep trying, look
carefully what your doing, make sure u dont mispell an address or something.
KEEP TRYING!!! YOU DONT KNOW HOW WORTH IT IT REALLY IS, ONCE YOU CAN DO THIS
YOUR UNSTOPPABLE!!!! I HACKED SO MANY GAMES THAT I COULDNT HAVE HACKED USING
THE NORMAL GAMEHACKING TECHNIQUES... ITS GREAT, YOU WILL BE UNSTOPPABLE, SKY
IS THE LIMIT WITH CODE INJECTION.

**** IF YOU HAVE ANY QUESTIONS ABOUT THIS TUTORIAL, OR JUST WANNA CHAT, MY
MSN IS STRYKER1080@HOTMAIL.COM. ID BE GLAD TO HELP YOU OUT.... *************
ALL THIS POSSIBLE BECAUSE OF SHEEP, THANKS FOR STICKING WITH ME AND TEACHING
ME.... SHEEP RULES!

- stryker
Simple In-game Trainer Menus
----------------------------
Author: Orr

NOTE!
This tutorial is _Definetly_ NOT for newbies. Best read with NOTEPAD.

Introduction
------------
Say you made a trainer with 10 or more options. The game you trained uses routine
protect against Alt+Tabbing outside the game. Say that the gamer using your train
forgot what are the trainers options, or he forgot what keys to use. He can do tw
things now. Quit the game, or try to press all the keys and see how it affects hi
Is there a solution for this kind of situation? Well, There is!

The method I will suggest in this tutorial was not invented by me. As far as I kn
it was already done in the old DOS days. That method is called Ingame Trainer Men
The purpose, is to show the trainer option menu, inside the game, when the user h
a hotkey.

What I will show in the tutorial, is how to make a trainer with one hotkey, that
pressed, will pop up a Message Box from inside my favorite target game: (pam pam
"The House of the Dead 2".

The tools I will be using are SoftICE, IDA, HIEW, and Visual C++ (not a must).

Theory
------
Basically the idea I will suggest works like that:

1. The user presses the menu hotkey.


2. The Trainer injects some code to a free space in the game's memory.
3. The Trainer overwrites a place in the gameloop.
4. The code injected will be run (the code is a messagebox) by the game.
5. The Trainer fixes the place it overwritten in the gameloop.

In case you don't know how to perform in-mem code injections, I suggest you go re
alittle about it in [SHEEP]'s tutorial, or keep reading on, as I will explain som
fundumentals of injections.

Finding a Game Loop


-------------------
A Problem arises with what we want to do. We want to inject code to the game, and
the game run it by itself. Injecting the code isn't much of a problem, it is actu
quite easy. But how do we make the GAME run OUR code?

The solution is quite simple.

If we find a place that is getting executed ALL the time (like, in a huge loop :)
could locate a good place to patch there, and inject our code to am empty space.
question is, how do we find a place, a loop that runs all the time?

Basically, what I did was, whiile playing that game alittle, I poped SoftICE for
times, until I saw I am in the correct process (look in the bottom-right corner o
for the CLSID), in my case it is HOD2. I poped SoftICE in times that I wasn't doi
so I would see what code is executed even when I am IDLE.

After poping up in a place that looked OK, I began tracing alot. Some cases I did
manually, and some cases I did it using the T command (T 100 will trace 100 instr
After a while, I saw that some loop is being executed alot of times, so I wanted
it out. I disassembled the file with IDA, and got to that location. I am terribly
to tell you I really forgot what location it was... What I did though, was seeing
function that location was, and then seeing who calls it... for example:

.text:004A4EA0 sub_4A4EA0 proc near ; CODE XREF: sub_4A41C0+142p


.text:004A4EA0 push ebx
.text:004A4EA1 push ebp
:
:
:
.text:004A4F47 test ah, 41h ; Say, this location :)
:
:
:
.text:004A4FDA pop ebp
.text:004A4FDB pop ebx
.text:004A4FDC retn
.text:004A4FDC sub_4A4EA0 endp

This function is called from the location sub_4A41C0. So I went there. and there
I found a cool place that executed many API's. Anyway, I chose this location:

.text:004A5967 push ecx ; lpMsg


.text:004A5968 call ds:GetMessageA
.text:004A596E test eax, eax

Why? Because GetMessage is a Windows API that gets executed all the time. I check
for my suspicion by simply setting a breakpoint at that location, and I saw that
I couldn't even play for one sec, because SoftICE kept popping after I pressed F1

Also, I am a fan of overwriting API calls. Why?


a) They have a sufficient amount of OPCodes (6, in many cases).
b) They can be executed later on from anywhere in the program, with the same opco
c) Because Micro$oft coders did them (and because I couldn't find another reason

OK, So we found a place to overwrite with our jump... now we actually need a plac
to jump to!

To summarize:
You can do 2 things in order to find a place that is getting executed all the tim

- Find a place that loops alot manually, by simply stopping the game in an IDLE
point, and trace from there. Tracing can be done manually, or it can be done
using the T command in SoftICE.

- Breakpoint on known API's that are likely to get executed all the time:
GetMessage, GetTickCount.

Finding a Place to Inject


-------------------------
OK, This is my favorite part.

Windows EXE's are based on the PE (Portable Executable) file format. The PE forma
supports sectioning of the file. Every section of the file has a different job.
There are Code/Data/Resource/Import/Export/etc sections. Most sections are differ
in size, so they all must be aligned. Because of that nice feature compilers leav
us, there are often alot of 'dead' NULL bytes, that are simply wasted just to ali
the section size. There is a difference between those code caves, because these a
mapped to memory, while there may be cases you will see empty places, but they wo
be mapped into memory, thus you cannot jump to them.

There are few ways to find the alignments in the exe:

1. You simply scroll through the entire EXE looking for those alignments. Once yo
see empty spaces, you check if they are indeed code caves (later on how to check)

2. In a hex editor, look for a binary string that contains nothing but 00's. It w
you to many odd places, but eventually to a cave.

3. You do the "proffesional" way. In IDA (or any other PE editor), we get some in
about the sections. We go to the beginning of the code (generally on top), and we

.text:00401000 ; File Name : D:\Games\THoTD2\Hod2.exe


.text:00401000 ; Format : Portable executable for IBM PC (PE)
.text:00401000 ! ; Section 1. (virtual address 00001000)
.text:00401000 ! ; Virtual size : 000C1940 ( 792896.)
.text:00401000 ; Section size in file : 000C2000 ( 794624.)
.text:00401000 ; Offset to raw data for section: 00001000
.text:00401000 ; Flags 60000020: Text Executable Readable
.text:00401000 ; Alignment : 16 bytes ?
.text:00401000 ; OS type : MS Windows
.text:00401000 ; Application type: Executable 32bit

You see that the Virtual Address is 1000, and that the Virtual Size is C1940?
You add those up together, and you get C2940. You go to that OFFSET in the file,
will see a nice and clean code cave. :)

In order to check if this is indeed a CODE cave, and not just a dead cave, in HIE
notice if there is a dot (.) before the address of not. The address will be 4C294
see this: .004C2940, then this is code... if you see just 004C2940 then it won't
Trust me on this one, I spent a lot of hours figuring why it didn't work on some
I was working on a while ago.

What to Inject?
---------------
OK, So we know where to jump from, and where to jump to. But all of this is usele
we inject something! In this tutorial, I will show how to inject a simple Message

A standard MessageBoxA call looks like that:

push Style
push Caption
push Text
push WindowHandle
call MessageBoxA
But remember, that we have overwritten an API... so we need to execute it again,
to the location we came from (actually we jump to the instruction after the API c

call GetMessage
jmp 4A596E

After that, we need to actually inject the text for MessageBox caption and text.
location 4C2970 for the caption, and 4C2980 for the actual text. The style will b
So we have this code now:

push 0
push 4C2970
push 4C2980
push 0
call MessageBoxA
call GetMessage
jmp 4A596E

But this code won't work... because we push 0 as the window handle. If we use 0 a
handle, then the MessageBox will be shown OUTSIDE the game, and sometimes cause i
crash. So how do we solve this? We need to find the window handle, and push it. B
the Window Handle is saved in a variable after the window was created. So we go b
IDA, and we track down the CreateWindowExA function. We see where it is reference
and we find this location:

.text:004A5885 call ds:CreateWindowExA


.text:004A588B test eax, eax
.text:004A588D mov dword_7DC8AC, eax

So we see that the hWnd is saved in a global variable which is located inside the
memory address 7DC8AC. So now, we have to get that value, and push it, instead of

push 0
push 4C2970
push 4C2980
mov eax, [7DC8AC]
push eax
call MessageBoxA
call GetMessage
jmp 4A596E

OK, now we get a little practical and summarize what we have:

1. A place to jump from : 4A5968


2. A place to jump to : 4C2949 (not 4C2940, because I want to leave some space
3. A place to put strings: 4C2970
4. A place to return to : 4A596E

Make a copy of hod2.exe, and name if hod2_.exe or whatever. We will be doing all
changes to this one. Open up HIEW, select HOD2_.exe, and then press F4 and go to
mode. Press F5, and type ".4A5968" (Without quotes ofcourse). Now you are in this

.text:004A5968 call ds:GetMessageA

Press F3 (to be in EDIT mode), and then press F2 (to be in ASSEMBLE mode), and ty
jmp 4C2949 [Enter]
nop [Enter]
[Escape]

Press F9 to update.

now go to the cave (.4C2949), and assemble the code block we wanted to add (see a
For API's you cannot assemble, so you will have to leave 6 nop's for each API. ho
add an API? Simply. Do you remember that I told you that it can be executed from
in the program, and also with the same opcodes all the time? Simply go to a locat
that calls GetMessage (4A5968), and a location that calls MessageBoxA (49E148), a
the opcodes (FF 15 xx xx xx xx).

After that go to add the strings (F3 and then TAB), and simply write them. Rememb
In order to separate strings there has to be a 00 between them:

.004C2970: 54 72 61 69-6E 65 72 20-4F 70 74 69-6F 6E 73 00 Trainer Options


.004C2980: 48 69 21 Hi!

OK, I believe we are all set.

The Trainer
-----------

This is how the source of the trainer looks like:

#include <windows.h>
#include "resource.h"

// Define sizes for writing into memory.


#define OPT1 6
#define OPT2 58

char wname[]="The House of the Dead 2"; // Window Name


BYTE opt1[OPT1]={0x90,0xE9,0xDC,0xCF,0x01,0x00}; // Jump my_injectio
BYTE opt1_off[OPT1]={0xFF,0x15,0x34,0x32,0x4C,0x00}; // Call GetMessage(

// The rest of the


BYTE opt2[OPT2]={0x90,0x6A,0x00,0x68,0x70,0x29,0x4C,0x00,0x68,0x80,0x29,0x4C,0
0xA1,0xAC,0xC8,0x7D,0x00,0x50,0xFF,0x15,0xFC,0x31,0x4C,0x00,0
0x15,0x34,0x32,0x4C,0x00,0xE9,0x01,0x30,0xFE,0xFF,0x00,0x00,0
0x54,0x72,0x61,0x69,0x6E,0x65,0x72,0x20,0x4F,0x70,0x74,0x69,0
0x6E,0x73,0x00,0x48,0x69,0x21};

LRESULT CALLBACK main (HWND, UINT, WPARAM, LPARAM);


HINSTANCE hInst;
HWND g;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin


{
// Basic Windows API main entry

hInst = hInstance;
DialogBox(hInst, MAKEINTRESOURCE( IDD_DIALOG1 ), 0, (DLGPROC)main);
return(0);
}

int Write(char windowname[], long address, BYTE *writearr, long sizeofarr)


{

// My WRITE engine

HWND hwnd;
HANDLE phandle;
DWORD pid,bytesw;

hwnd = FindWindow(0, windowname);


if (hwnd == 0) {
SetDlgItemText(g, ID_EDIT1, "Error: Cannot Find Game Window!");
goto quit;
}

GetWindowThreadProcessId(hwnd, (unsigned long *)&pid);

phandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);


if (phandle == 0) {
SetDlgItemText(g, ID_EDIT1, "Error: Cannot Open Game Process!");
goto quit;
}

WriteProcessMemory(phandle, (void *)(address), &writearr[0],sizeofarr, &bytesw);


return(1);

quit:
return(0);
}

BOOL GetKeyPress(int key)


{
// HotKey handling routine
return ((GetAsyncKeyState(key) & 1)==1);
}

VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
// This is the actual thing!
{
if (GetKeyPress(VK_F4)) { // If F4 was pressed
Write(wname, 0x4C2949, opt2, OPT2); // Write The injection
Write(wname, 0x4A5968, opt1, OPT1); // Patch the call
Sleep(2000); // Wait a little (2 seconds)
Write(wname, 0x4A5968, opt1_off, OPT1); // Change back the call
}
}

LRESULT CALLBACK main(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

// Main Message function


g = hDlg;
switch (uMsg)
{
case WM_INITDIALOG:
SetTimer(hDlg,0, 100, TimerProc);
break;

case WM_COMMAND:
if (wParam == ID_QUIT) ExitProcess(0x31337);
break;

default : return(FALSE);
}

return(TRUE);
}

Explanation:
What I did, was writing all the injected bytes into memory. First I wrote the inj
then I Patched the place to jump from, then waited for 2 seconds, and then patche
back again. I didn't bother to Zero out all the injection, because it won't get e
anyway.

Ending
------
Phew! That was a lot to write! I have been working 2 days on this menu + another
actually WRITING this. Looking back, it wasn't very tough, I just had to reboot a
due to blue screens and other sorts of page faults and weird exceptions.

What you have to keep in mind while doing an ingame menu, is:

1. Finding a place that runs all the time.


2. Finding a code cave.
3. Adding your code, followed by doing the instructions you overwritten.
4. Finally jumping back to the place.

There can be many problems and diffuculties that can occur. For example, what hap
if you don't find a global variable that contains the Window Handle? For that cas
can simply use FindWindow(0,"Window Name"). But what happens if you don't have Fi
imported in the EXE? You can import it like this:

push offset "User32.dll" ; Find the address of User32.DLL in memory p


call GetModuleHandle ; eax contains the address c

push offset "FindWindowA" ; Function to find p


push eax ; what DLL? (the one we found eariler) p
call GetProcAddress ; eax contains the address of the function c

push offset "Window Name" ; What window name? p


push 0 ; What CLSID? p
call eax ; call FindWindowA c

Finally, my little advice, BE CREATIVE. Think of more ideas, like adding DIALOG B
many more options, or perhaps even injecting the ENTIRE trainer to the game, so y
even have to use an external program besides a memory patcher.

Attached to this package is the trainer source, and a nice pic hehe :)

Thanks:
[SHEEP]: Encouragement, and for telling me the Window Handle thing
Duelist: For telling me where to find that Window Handle thing :)

Greets:
iCARUS, Have_No_Mercy, calligula, jmp_fce4, Keyboard Junky, ddh, MacDeath, Dang,
and all the other dudes in #gamehacking which I forgot to add. Please bitch
me if I forgot :)

Orr in July 2002.


OrrAghion@hotmail.com

LONG LIVE ISRAEL!

/\
____/__\____
\ / \ /
\/ \/
/\ /\
/__\____/__\
\ /
\/
OpenGL Hack Methods
by Phar Lap (JeSelected@Hotmail.com)

This How-To is for experienced programmers who need to know how they can implemen

?Feature #1: Transparent walls

In your hooked glBegin, check if the mode is GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_

glGetFloatv(GL_CURRENT_COLOR, &curcol)

We now have the color as float-values with single precision which equals 32 bits
curcolor[0] = red portion
curcolor[1] = green portion
curcolor[2] = blue portion

Secondly, we want to use blending instead of depth-testing, so we turn one thing

glDisable(GL_DEPTH_TEST)
glEnable(GL_BLEND)

Thirdly, we have to choose the desired blend-mode:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

I used this combination in my OpenGL Hack because I think this looks best. You ca

GL_ZERO
GL_ONE
GL_SRC_COLOR
GL_ONE_MINUS_SRC_COLOR
GL_SRC_ALPHA
GL_ONE_MINUS_SRC_ALPHA
GL_DST_ALPHA
GL_ONE_MINUS_DST_ALPHA
GL_DST_COLOR
GL_ONE_MINUS_DST_COLOR
GL_SRC_ALPHA_SATURATE

Finally, we can choose how transparent we want the walls (also called alpha-value

glColor4f(curcol[0], curcol[1], curcol[2], 0.5f)

Basically, we have transparent walls now. But we won't have much fun with it as l

You have to hook glClear and check if the given parameter is GL_DEPTH_BUFFER_BIT.

glClearColor(0.0f, 0.0f, 0.0f, 0.0f)

Now you can call the original glClear function.

That's it!

To see what the different OpenGL-modes mean, take a look > here <
?Feature #2: White walls

Again, we check in glBegin for GL_TRIANLGES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN o

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)

That will remove any texture from every wall, making it bright white.

?Feature #3: Wireframe mode

In glBegin we check the mode to be GL_POLYGON and if it is, we want it to be wire

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
glLineWidth(1.0)

Now we can set the lines to a nice green color like that:

glColor3f(0.0f, 0.7f, 0.0f)

After that, we're finished and can call the original glBegin.
Last thing to do: If the mode is not GL_POLYGON :

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

This will turn off wireframe for everything which is not drawn in GL_POLYGON, lik
Remember that this wireframe mode also requires the buffer being cleared between

?Feature #4: Lambert only

The feature called "Lambert" will prevent models from being shaded, so you will s

glColor3f(1.0f, 1.0f, 1.0f)

?Feature #5: Smoke removal

This one is actually very easy and I can't understand why some people use the HL-

glGetFloatv(GL_CURRENT_COLOR, &curcol)

Now we can easily determine if HL wants to draw smoke by checking for a grey colo

Now in glVertex3fv, we check for bSmoke to be true and if so, we return to the ca

Et voil?
?Feature #6: Flashbang removal

This one needs two hooked functions: glBegin and glVertex2f.


HL draws simple quads like console, VGUI etc with Vertex2f... also the flashbang

In glBegin, we check mode for GL_QUADS. If so, we fetch the current color:

glGetFloatv(GL_CURRENT_COLOR, &curcol)

Now we look for pure white, which means red = 1.0, blue = 1.0 and green = 1.0 ...
In order to communicate between glBegin and glVertex2f, we have to use a flag (bo
The next step is to retrieve the current screen dimensions since we need them to

glGetFloatv(GL_VIEWPORT, &coords)

Which saves the screen size into coords:


coords[0] = 0
coords[1] = 0
coords[2] = width
coords[3] = height

Last thing to do in glBegin is: in case the quad is not white we have to set bFla

Now in our hooked glVertex2f, we firstly look for bFlash being 1 ... if not, we c

glColor4f(curcol[0], curcol[1], curcol[2], 0.01f)

?Feature #7: Sky removal

This feature is only useful when used together with transparent walls or wirefram

So the first step is to hook those functions. Next step is to define another bool

In glVertex3fv, just check for bSky to be true and if so, return to the caller wi

Please remember that "smoke removal" also uses glVertex3f so make sure that those

?Feature #8: XQZ-style wallhack (model-hack)

In glBegin, check for GL_TRIANGLE_STRIP or GL_TRIANGLE_FAN. If one of those two m

glDisable(GL_DEPTH_TEST)

... which is telling OpenGL to skip the testing whether you can see an object bas

glEnable(GL_DEPTH_TEST)

?Feature #9: Extra Crosshair


There are probably many ways to find a place for drawing your own things, but I c

So far so good ... now in glEnable check for bDrawn to be FALSE (0) and if not, j

glPushMatrix()
glLoadIdentity()
glDisable(GL_TEXTURE_2D)

<< your draw code here >>

glEnable(GL_TEXTURE_2D)
glPopMatrix()

This ensures that you don't touch the current matrix with all the information of

The code of my crosshair used since v1.7 of the OpenGL Hack is the following:

glGetIntegerv(GL_VIEWPORT, &iDim)
glColor4f(1.0f, 0.0f, 1.0f, 1.0f)
glLineWidth(3.0f)

glBegin(GL_LINES)
?glVertex2i(iDim[2]/2, (iDim[3]/2)-12)
?glVertex2i(iDim[2]/2, (iDim[3]/2)-5)

?glVertex2i(iDim[2]/2, (iDim[3]/2)+5)
?glVertex2i(iDim[2]/2, (iDim[3]/2)+12)

?glVertex2i((iDim[2]/2)-12, iDim[3]/2)
?glVertex2i((iDim[2]/2)-5, iDim[3]/2)

?glVertex2i((iDim[2]/2)+5, iDim[3]/2)
?glVertex2i((iDim[2]/2)+12, iDim[3]/2)
glEnd()

glColor3f(1.0f, 0.0f, 0.0f)

glBegin(GL_POINTS)
?glVertex2i((iDim[2]/2)-3, iDim[3]/2)
?glVertex2i((iDim[2]/2)+3, iDim[3]/2)
?glVertex2i(iDim[2]/2, (iDim[3]/2)-3)
?glVertex2i(iDim[2]/2, (iDim[3]/2)+3)
glEnd()

?Feature #10: Fullbright

What lambert does to models does fullbright to the walls: ignores shadows so you
Shadows are drawn with black textures which are blended over the walls and which

Now we know if HL wants to draw textured objects, so the last thing to do is in g

glDisable(GL_TEXTURE_2D)

Mission accomplished!
The Ancient Art Of Training Or What The Mega
Trainer Gods Stuff Is All About Not Assigned
04 June
1999 by A Nameless Stranger
slightly edited
Courtesy of Reverser's page of reverse engineering
by reverser+
I feel some sadness and disappointment in this contribution (see the
drink/imposing bit :-)
Yet it is indeed a valid contribution. The Author wrote to me the
following:
lately my students requested a little excursion to the
mystified world of trainers.
This little essay is the result of the lesson I held
about this topic.
My students most happily refer to your site and
teachings.
So it might be fair to give your students the
possibility to refer to my work.

Yours sincerely,
fra_00xx
980604 a nameless stranger
anamstra and the author of this essay is right: the strainer world is a very
1100 interesting reversing world, and I invite all readers to have a (deep) look
NA at it. There are sites on the web that have perfectioned the softice
PC techniques we use everyday ONLY with the purpose of modifying games.
Make a search for +softice +doom (or quake, or whatever) and you'll see
what I mean.
Yeah, of course "pure" crackers and reversers are not alone: there are
all kinds of reversers out there in the great great Web. Some of these
'revkinds' are quite alien for us, some are very near, some touch 'our
interests' only marginally, but many others have (quite) something to
teach us, like the demomakers, for instance, and also the trainers'
experts like "A nameless stranger", here and now.

"This is the MINIMUM trainer (i.e. a hotkey and memory patching)! Just a
starting point."
Indeed! Awaiting much MORE! :-)
Outside they call them gods
Magicians with mighty rods
Inside it's just little work
Can be done by every jerk.
Rating ( )Beginner (x)Intermediate ( )Advanced ( )Expert
All in all this is something every beginner should be able to understand and reproduce. It's rated
intermediate 'cause it's assumed that the reader knows basic data types, a bit assembly, a bit C and
basic reversing techniques. A little knowledge of programming with Win32 API should be helpful.

The Ancient Art Of Training


Or What The Mega Trainer Gods Stuff Is All About
Written by A Nameless Stranger

Introduction
This essay covers the concept of trainers in Windows9x environments in FAQ style.
If the reader needs a ready made trainer 'skeleton' this is definitely the wrong essay,
but the author covers all topics the reader needs to know for coding his/her own trainer.
This way the reader will have the possibility to be proud of his/her own work and he/she won't have
to lie about the credits.

Tools required
SoftIce
GameHack
C compiler
The reader doesn't need any special drink and/or music. The author won't impose his/her preferences
on the reader.

Target's URL/FTP
Trainer targets are usually games which can be found at any game store or any major distro site.
The reader might have already one or two games at home. The author mostly used Expendable in the
examples.

Program History
A very brief history of trainers:

Once upon a time cracker groups didn't only crack. They coded their own intros, demos, trainers...
As long as there were such cracker groups trainers were coded.
Later the cracker groups stopped coding and specialized in changing jne/je to nop.
A few individuals conquered the free space and tried to build something like a trainer scene.
Today the warez groups try to revive the glory of the old days by producing intros, demos and trainers
again.

Essay
What's a trainer?

A trainer is a program that allows to manipulate certain values of games such as life points,
experience points, ammo, credits, tiberium, gold, armor, .... at run time. In short words - A trainer lets
the player cheat.

What's a 'mega' trainer?

A mega trainer is a trainer which allows cheating on multiple values.


It not only freezes life points. It freezes time, ammo, life points, credits, skips levels, adds weapons
or whatever.

What does 'freezing' mean?

'Freezing' is the effect a player experiences when a trainer stops values from changing.
This can be accomplished by modifying the game's code in a way that the value won't be accessed
anymore or by updating the value in short intervals. Another way to 'freeze' values is to change the
code which accesses the value.

Example:
If the code that drains your life points looks like this:
'sub [esi+1C6FCF6],ax' change it to 'mov [esi+1C6FCF6],64'
and you'll always have 100 LP.

How does a trainer work?

In most cases a trainer reacts upon defined key strokes (hotkeys). If the right key is pressed the
trainer's 'engine' attemps to patch the memory of the target's process at the address where the desired
value/code is located.

How do I patch the memory of a target's process?

This is no secret. A lot of material can be found on this topic in various books, magazines, journals...
The main idea is to utilize the Win32 API function WriteProcessMemory().
The Win32 API reference sates:

BOOL WriteProcessMemory(
HANDLE hProcess, // handle to process whose memory is written
LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // pointer to buffer to write data from
DWORD nSize, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);

How do I find out all these parameters?

1. parameter: handle to process whose memory is written to

A handle to a process can be obtained by calling the functions FindWindow(),


GetWindowThreadProcessId() and OpenProcess() like this:

HANDLE hWndTarget = FindWindow( NULL, "Your target's window name");


DWORD dwProcessId;
GetWindowThreadProcessId(hWndTarget, &dwProcessId);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);

If you're unsure about the target's window name use any of those nice little utilities which list the
windows' names.

Remark:
If you're using OpenProcess() you should use CloseHandle() too else you will produce a nice little
memory leak. Closing a process' handle does NOT cause closing of the associated process!
For a detailed description of the above functions consult the 'Appendix - Win32 functions used'.

2. parameter: address to start writing to

To find the address where you have to patch the target's memory is the trickiest part of it all.
But there's help. The easiest way to find the right address is to use GameHack 2.0
(www.gamehack.com).
This little program allows the user to scan a traget's memory for specified values and shows the
associated addresses. When the desired value changes the user lets GameHack scan the found
addresses for the new value. This way GameHack sorts out the wrong addresses until there are only a
few left.
Get it. Take a look at it. For composing trainers it's a very valuable tool. Of course you can write
such a memory scanner on your own and add some advanced pattern scan methods. It's not very
difficult if you've coded your own trainer you're already half the way down. Creating the UI is the
worst of it all.
Anyway, use GameHack to find the address where your target stores the desired value.
Sounds easy, doesn't it? Well, it is, but you may experience some problems relying only on
GameHack's addresses. The problem is that you can't take for granted that the desired values are
always stored at the same addresses.
Example:
You can use addresses found with GameHack to train e.g. Heroes of Might & Magic 3 which works
fine in a single scenario or in the first campain but later, in the next campain or in multi player mode
the memory layout changes i.e. the addresses of the values change and become useless.

You see it's necessary to check if your addresses work all the time not only the first five minutes.
If the address(es) change it's a good idea not to patch the value but the code that accesses the value.
The address of the code can be easily located by putting a memory breakpoint on the value's address.
(i.e. 'bpm address w' or 'bpr addr1 addr2 w' in SoftIce).

Example:
You've found with GameHack that your target stores life points in a WORD at address 0x1C6FCF6.
Start your target.
Set a breakpoint 'bpmw 1C6FCF6 w' in softice.
Resume your target.
When your life points change SoftIce pops up at a location like this:

:004657FA 668986F6FCC601 mov word ptr [esi+01C6FCF6], ax

This line of code changes the value of your life points. To stop the program killing you simply nop it
out by writing 7 times 90 (nop) to address 4657FA. If you want to disable your trainer restore the
original bytes at address 4657FA.

Of course there some other ways to locate the right address - scanning for specifc patterns or even
dead listing - but I think you got the idea, didn't you?

3. parameter: pointer to buffer to write data from

A buffer with data to write from looks like this:

BYTE bNewData[]={0x90,0x90,0x90,0x90,0x90,0x90,0x90};

Yes, that's really all. Simply create an array holding the bytes you want to write. Pay attention to the
Intel byte order!

4. parameter: number of bytes to write

Count your bytes or let the function sizeof() count them for you:

DWORD dwNewDataSize = sizeof(bNewData);


5. parameter: actual number of bytes written

We don't want to know. Set it to NULL.

The complete trainer 'engine' should look like this:

BYTE bNewData[]={0x90,0x90,0x90,0x90,0x90,0x90,0x90};
DWORD dwNewDataSize = sizeof(bNewData);
HANDLE hWndTarget = FindWindow( NULL, "Expendable");
DWORD dwProcessId;
GetWindowThreadProcessId(hWndTarget, &dwProcessId);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
WriteProcessMemory(hProcess, 0x4657FA, &bNewData, dwNewDataSize, NULL);
CloseHandle(hProcess);

Yes, it's that simple. You've already trained Expendable's life points.
See 'Appendix - a live record' for a brief description of the whole process.

How do I realize hotkeys?

Using the Win32 API you can realize hotkeys in various ways.

1. You can use RegisterHotkey(),


but you shouldn't 'cause it doesn't work reliable in every case.

2. You can use SetWindowsHook().


It works reliable most times but you have to code a DLL to use it for trainer purposes. If another
process starts after your trainer wich uses SetWindowsHook() too and doesn't call CallNextHook()
your hotkey will be disabled. See the Win32 API reference for details.

3. You can use GetAsyncKeyState().


The Win32 API reference states:

The GetAsyncKeyState function determines whether a key is up or down at the time the function is
called, and whether the key was pressed after a previous call to GetAsyncKeyState.
SHORT GetAsyncKeyState(
int vKey // virtual-key code
);

Parameters:

vKey - Specifies one of 256 possible virtual-key codes.


See 'Appendix - All the virtual keys with their values'.
Return Values:

If the function succeeds, the return value specifies whether the key was pressed since the last call to
GetAsyncKeyState, and whether the key is currently up or down....

To use this function for hotkeys the only thing you have to do is polling. Polling means to let it run in a
loop.
If you call it in a loop like:

while(1)
{
if (GetAsyncKeyState(VK_F12)) // if F12 is down or was down since the las
{
train(); // call the trainer engine
}
};

it will consume too much if not all of the cpu time. So it is important to time the 'loop' carefully.
A timed loop is nothing else than a timer callback function. You can realize it like this:

void CALLBACK PollKeys (HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)


{
if (GetAsyncKeyState(VK_F12)) // if F12 is down or was down since the la
{
train(); // call the trainer engine
}
}

Now you need to activate the timer with:


SetTimer(hWnd, 666, 1000, (TIMERPROC) PollKeys);

Parameters:

hWnd = your trainer's window handle (HANDLE)


666 = a unique identifier (UINT)
1000 = timer interval in ms (UINT)
PollKeys = address of timer procedure (TIMERPROC)

Generally it's a good idea to check the game's key layout before choosing your hotkey i.e. don't use F5
if the game uses this for e.g. quicksave.

Remark:
The timer callback for the hotkeys consumes cpu time everytime it's called. You shouldn't set the
timer interval to very short periods (<75 ms) to avoid slow downs of the running target. Usually a
~1000 ms interval is an acceptable choice.
See the 'Appendix - Win32 functions used' for detailed information.
That's all?

Yes! This is all you need to know for coding trainers. You know how find the right addresses, how to
patch memory and how to realize hotkeys. You may need to work out the address finding part a bit but
with GameHack on your side you'll soon discover how easy things really are.
All what's left to do is assemble what you've learned to a working Win32 program and ready is your
trainer. You've mastered your way to the olympus of the 'trainer gods'.

Remark:
The author tried to make this as short and simple as possible. This is the MINIMUM trainer (i.e. a
hotkey and memory patching)! Just a starting point. If you think your trainer won't work this way
'cause you need an in built memory scanner or the use of the debug interface or whatever, good, very
good: CODE IT YOURSELF!

Appendix - a live record

This is just an EXAMPLE for illustration purposes. If you think that some code locations should be
patched another way, good, do so. You should of course add some sanity checking i.e. error handling
to your trainer code!

- Chosen target: Expendable

- Used GameHack to find the adressses: 04A0134 - time (WORD)


1C6FCF6 - life points (WORD)
1C6FCxx - various ammo (WORD)

- Used 'bpmw 04A0134 w' in Softice to track down the code that modifies
the time value.

- Found code that counts down the time value at:


0041C63E 48 dec eax

- Wrote down the address and the original byte 48.


Byte that eliminates the count down: 90 - nop.

- Used 'bpmw 1C6FCF6 w' in Softice to track down the code that modifies
the life points.

- Found code that counts down the life points at:


004657FA 668986F6FCC601 mov word ptr [esi+01C6FCF6], ax

- Wrote down the address and the original bytes 66 89 86 F6 FC C6 01.


Bytes that 'freeze' the life points 7 x 90 - nop.

- Used 'bpmw 1C6FCxx w' on the various ammo values.


- Found and eliminated all code that counts down ammo values at:
0046BB0E 2B44241C sub eax, dword ptr [esp+1C]
Bytes that eliminate the ammo count down: 4 x 90 - nop.

- Testing showed that grenades aren't handled by the above ammo


count down.

- Used bpmw .... to track down the grenade count down code.

- Found code that counts down grenades at:


0041F53C 48 dec eax
Byte that eliminates that code 90 - nop.

- Used GameHack to get Expendable's window name: 'Expendable'

- Set up the trainer engine to open Expendable's process:

HANDLE hWndTarget = FindWindow( NULL, "Expandable");


DWORD dwProcessId;
GetWindowThreadProcessId(hWndTarget, &dwProcessId);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);

- Set up the trainer code to handle 3 hotkeys (time, life, ammo):

void CALLBACK PollKeys (HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)


{
if (GetAsyncKeyState(VK_F10))
}
TrainTime();
}
if (GetAsyncKeyState(VK_F11))
{
TrainLife();
}
if (GetAsyncKeyState(VK_F12))
{
TrainAmmo();
}
}

- Set up the trainer's engine like this:

BYTE bTimeDataNew = 0x90; // the new code to patch


BYTE bTimeDataOld = 0x48; // the old code to restore
BYTE temp = 0; // guess

void TrainTime()
{
WriteProcessMemory(hProcess, 41C63E, &bTimeDataNew, 1, NULL); // patch the me

BYTE temp = bTimeDataNew; // swap bTimeDataNew


bTimeDataNew = bTimeDataOld; // with bTimeDataOld
bTimeDataOld = temp; // to make sure the next time the hotkey
// is pressed the trainer switches correct on/off
}

- Did the same with ammo and life points.


- Compiled. Tested. Ready.

Appendix - Win32 functions used

WriteProcessMemory

The WriteProcessMemory function writes memory in a specified process.


The entire area to be written to must be accessible, or the operation fails.

BOOL WriteProcessMemory(
HANDLE hProcess, // handle to process whose memory is written to
LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // pointer to buffer to write data to
DWORD nSize, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);

Parameters

hProcess

Identifies an open handle to a process whose memory is to be written to.


The handle must have PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the proc

lpBaseAddress

Points to the base address in the specified process to be written to.


Before any data transfer occurs, the system verifies that all data in the base ad
and memory of the specified size is accessible for write access.
If this is the case, the function proceeds; otherwise, the function fails.

lpBuffer

Points to the buffer that supplies data to be written into the address space of t
specified process.

nSize

Specifies the requested number of bytes to write into the specified process.

lpNumberOfBytesWritten

Points to the actual number of bytes transferred into the specified process.
This parameter is optional. If lpNumberOfBytesWritten is NULL, the parameter is i

Return Values

If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero.
To get extended error information, call GetLastError.
The function will fail if the requested write operation crosses into an area of t
that is inaccessible.

Remarks

WriteProcessMemory copies the data from the specified buffer in the current proce
address range of the specified process. Any process that has a handle with PROCES
and PROCESS_VM_OPERATION access to the process to be written to can call the func
The process whose address space is being written to is typically, but not necessa
debugged. The entire area to be written to must be accessible. If it is not, the
fails as noted previously.

FindWindow

The FindWindow function retrieves the handle to the top-level window whose class
window name match the specified strings. This function does not search child wind

HWND FindWindow(
LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);

Parameters

lpClassName

Points to a null-terminated string that specifies the class name or is an atom th


identifies the class-name string. If this parameter is an atom, it must be a glob
created by a previous call to the GlobalAddAtom function. The atom, a 16-bit valu
be placed in the low-order word of lpClassName; the high-order word must be zero.

lpWindowName

Points to a null-terminated string that specifies the window name (the window's t
If this parameter is NULL, all window names match.

Return Values

If the function succeeds, the return value is the handle to the window that has t
specified class name and window name. If the function fails, the return value is
To get extended error information, call GetLastError.

GetWindowThreadProcessId

The GetWindowThreadProcessId function retrieves the identifier of the thread that


the specified window and, optionally, the identifier of the process that created
This function supersedes the GetWindowTask function.

DWORD GetWindowThreadProcessId(
HWND hWnd, // handle of window
LPDWORD lpdwProcessId // address of variable for process identifier
);
Parameters

hWnd

Identifies the window.

lpdwProcessId

Points to a 32-bit value that receives the process identifier. If this parameter
GetWindowThreadProcessId copies the identifier of the process to the 32-bit value
it does not.

Return Values

The return value is the identifier of the thread that created the window.

OpenProcess

The OpenProcess function returns a handle of an existing process object.

HANDLE OpenProcess(
DWORD dwDesiredAccess, // access flag
BOOL bInheritHandle, // handle inheritance flag
DWORD dwProcessId // process identifier
);

Parameters

dwDesiredAccess

Specifies the access to the process object. For operating systems that support se
checking, this access is checked against any security descriptor for the target p
Any combination of the following access flags can be specified in addition to the
STANDARD_RIGHTS_REQUIRED access flags:

Access Description
PROCESS_ALL_ACCESS Specifies all possible access flags for the process ob
PROCESS_CREATE_PROCESS Used internally.
PROCESS_CREATE_THREAD Enables using the process handle in the CreateRemoteTh
to create a thread in the process.
PROCESS_DUP_HANDLE Enables using the process handle as either the source
in the DuplicateHandle function to duplicate a handle.
PROCESS_QUERY_INFORMATION Enables using the process handle in the GetExitCodePro
GetPriorityClass functions to read information from the process
object.
PROCESS_SET_INFORMATION Enables using the process handle in the SetPriorityCla
to set the priority class of the process.
PROCESS_TERMINATE Enables using the process handle in the TerminateProce
to terminate the process.
PROCESS_VM_OPERATION Enables using the process handle in the VirtualProtect
WriteProcessMemory functions to modify the virtual memory of the
process.
PROCESS_VM_READ Enables using the process handle in the ReadProcessMem
to read from the virtual memory of the process.
PROCESS_VM_WRITE Enables using the process handle in the WriteProcessMe
to write to the virtual memory of the process.
SYNCHRONIZEWindows NT only: Enables using the process handle in any of the
wait functions to wait for the process to terminate.

bInheritHandle

Specifies whether the returned handle can be inherited by a new process created b
current process. If TRUE, the handle is inheritable.

dwProcessId

Specifies the process identifier of the process to open.

Return Values

If the function succeeds, the return value is an open handle of the specified pro
If the function fails, the return value is NULL. To get extended error informatio
call GetLastError.

Remarks

The handle returned by the OpenProcess function can be used in any function that
handle to a process, such as the wait functions, provided the appropriate access
requested. When you are finished with the handle, be sure to close it using the C
function.

GetAsyncKeystate

The GetAsyncKeyState function determines whether a key is up or down at the time


is called, and whether the key was pressed after a previous call to GetAsyncKeySt

SHORT GetAsyncKeyState(
int vKey // virtual-key code
);

Parameters

vKey

Specifies one of 256 possible virtual-key codes.

Windows NT: You can use left- and right-distinguishing constants to specify certa
See the Remarks section for further information.
Windows 95: Windows 95 does not support the left- and right-distinguishing consta
on Windows NT.

Return Values

If the function succeeds, the return value specifies whether the key was pressed
last call to GetAsyncKeyState, and whether the key is currently up or down.
If the most significant bit is set, the key is down, and if the least significant
the key was pressed after the previous call to GetAsyncKeyState. The return value
a window in another thread or process currently has the keyboard focus.
Windows 95: Windows 95 does not support the left- and right-distinguishing consta
If you call GetAsyncKeyState on the Windows 95 platform with these constants, the
is zero.

Remarks

You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as v
vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without dist
between left and right.

SetTimer

The SetTimer function creates a timer with the specified time-out value.

UINT SetTimer(
HWND hWnd, // handle of window for timer messages
UINT nIDEvent, // timer identifier
UINT uElapse, // time-out value
TIMERPROC lpTimerFunc // address of timer procedure
);

Parameters

hWnd

Identifies the window to be associated with the timer. This window must be owned
calling thread. If this parameter is NULL, no window is associated with the timer
nIDEvent parameter is ignored.

nIDEvent

Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this paramet

uElapse

Specifies the time-out value, in milliseconds.

lpTimerFunc

Points to the function to be notified when the time-out value elapses. For more i
about the function, see TimerProc.
If lpTimerFunc is NULL, the system posts a WM_TIMER message to the application qu
The hwnd member of the message's MSG structure contains the value of the hWnd par

Return Values

If the function succeeds, the return value is an integer identifying the new time
An application can pass this value, or the string identifier, if it exists, to th
function to destroy the timer. If the function fails to create a timer, the retur
is zero.

Remarks

An application can process WM_TIMER messages by including a WM_TIMER case stateme


window procedure or by specifying a TimerProc callback function when creating the
When you specify a TimerProc callback function, the DispatchMessage function simp
the callback function instead of the window procedure. Therefore, you need to dis
messages in the calling thread, even when you use TimerProc instead of processing

The wParam parameter of the WM_TIMER message contains the value of the nIDEvent p

TimerProc

The TimerProc function is an application-defined callback function that processes


messages.

VOID CALLBACK TimerProc(


HWND hwnd, // handle of window for timer messages
UINT uMsg, // WM_TIMER message
UINT idEvent, // timer identifier
DWORD dwTime // current system time
);

Parameters

hwnd

Identifies the window associated with the timer.

uMsg

Specifies the WM_TIMER message.

idEvent

Specifies the timer's identifier.

dwTime

Specifies the number of milliseconds that have elapsed since Windows was started.
This is the value returned by the GetTickCount function.

Return Values

This function does not return a value.

Remarks

TimerProc is a placeholder for the application-defined function name.

Appendix - All the virtual keys with their values.

/*
* Virtual Keys, Standard Set
*/
VK_LBUTTON 0x01
VK_RBUTTON 0x02
VK_CANCEL 0x03
VK_MBUTTON 0x04 /* NOT contiguous with L & RBUTTON */

VK_BACK 0x08
VK_TAB 0x09

VK_CLEAR 0x0C
VK_RETURN 0x0D

VK_SHIFT 0x10
VK_CONTROL 0x11
VK_MENU 0x12
VK_PAUSE 0x13
VK_CAPITAL 0x14

VK_ESCAPE 0x1B

VK_SPACE 0x20
VK_PRIOR 0x21
VK_NEXT 0x22
VK_END 0x23
VK_HOME 0x24
VK_LEFT 0x25
VK_UP 0x26
VK_RIGHT 0x27
VK_DOWN 0x28
VK_SELECT 0x29
VK_PRINT 0x2A
VK_EXECUTE 0x2B
VK_SNAPSHOT 0x2C
VK_INSERT 0x2D
VK_DELETE 0x2E
VK_HELP 0x2F

/* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */

VK_LWIN 0x5B
VK_RWIN 0x5C
VK_APPS 0x5D

VK_NUMPAD0 0x60
VK_NUMPAD1 0x61
VK_NUMPAD2 0x62
VK_NUMPAD3 0x63
VK_NUMPAD4 0x64
VK_NUMPAD5 0x65
VK_NUMPAD6 0x66
VK_NUMPAD7 0x67
VK_NUMPAD8 0x68
VK_NUMPAD9 0x69
VK_MULTIPLY 0x6A
VK_ADD 0x6B
VK_SEPARATOR 0x6C
VK_SUBTRACT 0x6D
VK_DECIMAL 0x6E
VK_DIVIDE 0x6F
VK_F1 0x70
VK_F2 0x71
VK_F3 0x72
VK_F4 0x73
VK_F5 0x74
VK_F6 0x75
VK_F7 0x76
VK_F8 0x77
VK_F9 0x78
VK_F10 0x79
VK_F11 0x7A
VK_F12 0x7B
VK_F13 0x7C
VK_F14 0x7D
VK_F15 0x7E
VK_F16 0x7F
VK_F17 0x80
VK_F18 0x81
VK_F19 0x82
VK_F20 0x83
VK_F21 0x84
VK_F22 0x85
VK_F23 0x86
VK_F24 0x87

VK_NUMLOCK 0x90
VK_SCROLL 0x91

/*
* VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
* Used only as parameters to GetAsyncKeyState() and GetKeyState().
* No other API or message will distinguish left and right keys in this way.
*/
VK_LSHIFT 0xA0
VK_RSHIFT 0xA1
VK_LCONTROL 0xA2
VK_RCONTROL 0xA3
VK_LMENU 0xA4
VK_RMENU 0xA5

#if(WINVER >= 0x0400)


VK_PROCESSKEY 0xE5
#endif /* WINVER >= 0x0400 */

VK_ATTN 0xF6
VK_CRSEL 0xF7
VK_EXSEL 0xF8
VK_EREOF 0xF9
VK_PLAY 0xFA
VK_ZOOM 0xFB
VK_NONAME 0xFC
VK_PA1 0xFD
VK_OEM_CLEAR 0xFE
Ob Duh,
does not apply here!

You are deep inside reverser's page of reverse engineering, choose your way out:

homepage links search_forms +ORC how to protect academy database


reality cracking how to search javascript wars
tools anonymity academy cocktails antismut CGI-scripts mail_reverser
Is reverse engineering legal?
_._____
\ | ____
| | |____|
| |______ ________ _ _______ | \_
| ._ \ ._ \_._ /__|\| |
| |/ / |/ | / | |
_ __| | /_ | | | |_ __ _
__ _ _______________| |____________|_______________
____________________ | | _brzi_________________________
__ |_ | __
|___________________ \____| ___________________________|

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
REVERSING, FUNCTIONS ADDITION,MODIFICATION OF THE EXISTING CODE
A TYPICAL TARGET FROM MICRO$FOT:NOTEPAD.EXE
PART 1

By [brzi] of DEViOUS (http://devious.tsongkie.com)

¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

INTRODUCTION
************

So here we are again.. after my last tutorial... about injecting ShellExecute


i decided to give u something better.. much better!
In this tute and the tut's coming i'll give u a detailed description about how to
notepad.exe and in general many other programs in order to add/remove/modify some
As i said, this tutorial wishes to introduce u to the world of reverse engineerin
most interesting aspect: Addiotion of Functions in an Alien Target. You'll discov
not such a monster to add new stuff to targets infact it's really simple u just n
until u master it! I'll try to explain things in the easiest way i can, but i war
things: first u must have (at least) basic knowlegde of the Win32 assembly langua
read something about PE headers and Windows executable files and they work.It hel
a little intro about w32 executables but that will not replace a detailed PE expl

TOOLS NEEDED/USED
*****************

-> W32Dasm v8.93


-> SoftICE v4.5
-> TSearch v1.6
-> HIEW 6.15
-> Borland Resource Workshop v4.5
-> API Refenrence

WHERE TO FIND THE TOOLS


***********************

-> W32Dasm v8.93 -> http://www.gamehacking.com


-> SoftICE v4.5 -> http://www.newhua.com/down/si405w9x.zip s/n: 4001 2345fb bf
-> TSearch v1.6 -> http://www.gamehacking.com
-> HIEW 6.15 -> http://www.gamehacking.com
-> Borland Resource Workshop v4.5 -> http://protools.cjb.net
-> API Reference -> A forgot the link - search it, it's on the net

MISSION
*******

As first tutorial of this kind we will add only a menu item in notepad's Help
inform us about who made to patch.

FEW WORDS ABOUT W32 EXECUTABLES


*******************************

Every win95 executable file consists of 2 parts : the PE header and the sectio
header contains all kind of information for the os about how to threat this file.
are grouped by their functionality. For example there is one section for the prog
one for its data, one with its resources, one with the table of imported function

Now, what happens when win95 loads a program is this:

First an environment is created for the program where it gets its own virtual a
Then win95 has to decide where in this virtual address-space it should place the
information is available in the PE header. The PE header contains the desired ima
of the program, this is the address the program wants to be loaded at.

Then windows takes all the sections and places them in memory beginning at the
(default imagebase is 400000h). Where exactly it places the sections is also stat
header. Every section has its own so called RVA (Relative Virtual Address). This
just an offset relative to the imagebase.

Once the sections are in memory, windows has to know how to threat those sectio
know which section contains a stucture with the resources, which one has the scru
import table etc.That is also stated in the PE header with RVA's to the beginning
various so called data directories.

Then finally windows has to jump to the programs code. This entrypoint is in th
the entrypoint RVA.

The above words about the PE header is not meant as a replacement for the PE do
mentioned at the beginning of this tutorial. I would recommend u to study the PE
It will give you a much better understanding of win95 programs.

LESSON START
************

THE NEW MENU


¯¯¯¯¯¯¯¯¯¯¯¯
So.. we must to understand what are we goind to do to our target - we are goi
item to the Help menu, but we must keep in mind that during the session we have t
file - in our case the menu, we'll have to add part to the windows procedure that
selected menu IDs relative to our new menu. As u know every item from menus to bu
boxes have an ID that is needed to allow the program to distinguish among various
We sad that we want to add menu right, so we'll start looking how to program beha
a menu: (in our case the Help menu) the API that we will break on will be WinHelp
winhelp.exe in the windows directory that is needed to run the any .hlp file in i
In SoftICE breakpoint on WinHelpA: bpx WinHelpA
Then goto notepad - select Help and then Help Topics.. SoftICE will break.. push
at the caller which is here:

:00401E51 FF7514 push [ebp+14]


:00401E54 57 push edi
:00401E55 FF7508 push [ebp+08]
:00401E5D E80FF3FFFF call 0040116C <- we come back from this call
................
................
................

OK, let's see what's inside the call:

* Reference by a CALL at Address:


|:00401E58
|
:0040116C 55 push ebp
:0040116D 8BEC mov ebp,esp
:0040116F 81EC04010000 sub esp,00000104
:00401175 33C0 xor eax,eax
:00401177 56 push esi
:00401178 57 push edi
:00401189 BE38614000 mov esi,00406138
:0040117E 8DBDFCFEFFFF lea edi, dword ptr [ebp+FFFFFEFC]
:00401184 B940000000 mov ecx, 00000040
:00401189 A4 movsb
:0040118A 8DBDFDFEFFFF lea edi, dword ptr [ebp+FFFFFEFD]
:00401190 F3 repz
:00401191 AB stosd
:00401192 66AB stosw
:00401194 AA stosb
:00401195 0FB7750C movzx esi, word ptr [ebp+0C] ; <- ID VALUE OF THE CHOSEN
:00401199 83FE20 cmp esi, 00000020 ; COMPARES ID VALUE AND 20h
:0040119C 8BC6 mov eax, esi
:0040119E 7F1A jg 004011BA ; IF ID > 20h, TAKE THE JUMP
:004011A0 0F84C1030000 je 00401567
:004011A6 48 dec eax
:004011A7 83F81B cmp eax, 0000001B
:004011AA 7736 ja 004011E2
:004011AC 0FB68838174000 movzx ecx, byte ptr [eax+00401738]
:004011B3 FF248DF8164000 jmp dword ptr [4*ecx+004016F8] ; OTHERWISE PROCESS
; ACCORDINGLY

So we have the menu ID in esi and then a check to see if esi>20h (20h = 32 dec) s
value greater then 32 will be processed by a variable jump. So we'll better give
value > 32 so that we will be able to process it folowing the jg at 0040119E whic

* Referenced by a JUMP at Address:


|:0040119E(C)
|

* Possible Ref to Menu: MenuID_0001, Item: "Cut Ctrl+X"


|
:004011BA 3D00030000 cmp eax, 00000300 ; 300h (768 dec) = "Cut" menu
:004011BF 7C21 jl 004011E2
* Possible Ref to Menu: MenuID_0001, Item: "Copy Ctrl+C"
|
:004011C1 3D01030000 cmp eax, 00000301
:004011C6 0F8E0F030000 jle 004014DB

* Possible Ref to Menu: MenuID_0001, Item: "Paste Ctrl+V"


|
:004011CC 3D02030000 cmp eax, 00000302
:004011D1 0F8427030000 je 004014FE
..............
..........

and so on .. So we found a good point to insert a jmp to our code which will proc
ID value relative to the new menu, but we need to create this menu don't u think
So run BRW (Borland Resource Workshop) and open notepad.exe (create a backup firs
menu section and under Help menu add a new item called "Patch Info". Now give it
Remember any ID value > than 33 is good. Now save and run notepad. U'll see a new
Help menu. But when u click it nothing happens. Well we are going to inject a Mes
"Patch Info" is selected it will show u a nice little msgbox.
So now we have to add the code to the file. How can we do this??? =:[ CODE INJECT

OK now we will jump from 00401BA to our CODE CAVE - 00404959. Here we GO....

was:

:004011BA 3D00030000 cmp eax,00000300


:004011BF 7C21 jl 004011E2

becomes:

:004011BA xxxxxxxxxxx jmp 00404989 -> towards our new code


:004011BF 90 nop
:004011C0 90 nop

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

our code:

:00404989 cmp eax,23 <- eax holds current item ID's. 23h -> ID of our new menu
jz 00404999 <- if u clicked our menu, process it

cmp eax,300 <- these are the 2 code lines that we replaced with the jmp
jl 004011E2 ; we restore them

jmp 004011C1 <- continue with other checks - jmp back

:00404999 push 0 <- push style of the msgbox


push 004049B9 <- push caption of the msgbox
push 00404959 <- push the text of the msgbox
push - <- push hWnd
call dword ptr [00407430]
jmp 004016EB <- jmp back

So when the "Patch Info" is selected the code above will be executed and a msgbox
will be displayed saying "wINDOWS nOTEPAD pATCH v1.0 by [brzi] of DEViOUS"
Here's the final TSearch script:

// BEGIN TSEARCH SCRIPT //

// WRITE OUR MSG CAPTION


offset 004049DD
asc "pATCH iNFO"
hex 00

// WRITE OUR MSG TEXT


offset 00404959
asc "wINDOWS nOTEPAD pATCH v1.0 by [brzi] of DEViOUS"
hex 00

// POKE OUR CODE CAVE's


offset 00404989
cmp eax,23
jz 004049BB

cmp eax,300
jl 004011E2

jmp 004011C1

// MAIN CODE CAVE


offset 004049BB
//push the style of the msgbox
push 0
//push the caption of the msgbox
push 004049DD
//push the text of the msgbox
push 00404959
//push hWnd - 0 = NULL
push 0
//call MessageBoxA
call dword ptr [00407430]
//jmp
jmp 004016EB

// POKE MAIN CODE


offset 004011BA
// jmp to our code cave
jmp 00404989
nop
nop
// END TSEARCH SCRIPT //

ok, maybe this was not very explained but it's very easy to understand (unless u
Now in TSearch in the EasyWrite Script press the Tmk button and the press the Che
give u the opcodes that u need when u will patch the file - by this i mean not wh
running but patch notepad so it will contain this code forever.
Well that's all for this tutorial.. Watch for others...

GREETS
******
-> Greets in no special order ^_^

[sheep] +=+ Omega +=+ Stoner +=+ EEDOK +=+ PCP +=+ VBTrainer +=+ Bie +=+ Synbios
Rat +=+ everybody on CES and DEViOUS forums and everything that belongs here...
And thanks to [sheep] for the ascii logo...

Copyright© [brzi] - 05/11/2003


brzi@devious.tsongkie.com
This short and easy to follow tutorial provided by Phoenix will teach you how to hack (use a memory
scanner) game timers. What this means is for example the time between reloading a gun. Maybe you
want to find the reload addy and make a quick reload hack. Although this tutorial will not work with
every game, it will work with most. The reason for this not working for every game is that some
games use different methods for their timing system…

To begin, we will assume that you want to hack the reload time for a gun in one of your favorite
games. Let’s also assume that this gun by default takes 6 seconds to reload after one shot has been
fired (gun reloads automatically.) If and when we’re successful at hacking the reload timer for our
gun, the gun will be capable of firing like a machine gun (this depends on the game.)

Using the info above, we will now attempt to find the address of the reload timer. To do this we must
follow these steps:

Step #1:
Open memory searcher and do an advance search by searching for an unknown value (1 byte.) <-- 1
byte because timer values are usually less than 255 in value.

Step #2:
Fire your gun one time and freeze the game immediately after firing the shot (once the shot is fired the
reload timer becomes active,) now go back to the memory searcher and search next: advanced search
- decreased (1 byte.) <-- we search decreased because in most cases the timer goes something like
this: default – 6.0 | shot fired (1 second wait before pause) – 5.0 <-- the timer decreases the longer
you wait, but once it hits 0 the gun is fully loaded. Take note that if this way fails, you may reread this
guide and replace decrease with increase.

Step #3:
Once again fire one shot from your gun, but this time wait just a tad longer until you freeze the game,
then go to the memory searcher and search next: advanced search - decreased (1 byte.)

Step #4:
Now allow the gun to fully reload, then pause the game and go to the memory searcher; search next:
advanced search - decreased (1 byte.)

Step #5:
Go to the memory searcher and search next: advanced search - unchanged (1 byte.) <-- we now
search unchanged because the value has not change as we didn’t fire any shots this time.

Step #6:
After going through all the steps, your memory searcher should now contain the appropriate addy(s)
for the reload timer, if not try altering a few of the values/search types contained here…Good luck
hacking timers!

- Phoenix -
Resolving Dynamic Memories at Runtime

by Tsongkie

I. Introduction

In this guide, I would try and explain to you a certain advance technique in game training that is
lacking in most game trainers. I will not provide a source code for every coder has his own way of
developing his trainer, so if you are looking for that, dont waste your time reading this tutorial. I will
explain in pseudocode and theory on how it is done. May I remind you that this is only a way, not
THE WAY.

II. Lets Get Our Hands Dirty

In a certain game, I found the following addies, although the values are dynamically allocated by
runtime to different addies.

00465580 --> Gold


00465588 --> Silver
00465590 --> Bronze

Notice that they are separated by 8 bytes. I restarted the game, found 3 different addies but also are
separated by 8 bytes.

Also, when I scroll up and look at the bytes before our addies, i found a 909090EB08909090 exactly
16 bytes before the first addie (Gold). I then restarted the game and find the same bytes over and over
again at exactly 16 bytes before our addies.

III. Our Problem

We want to write a trainer that resolves these addies at runtime. So how do we do that? Lets see what
we know....

1. Our addies, wherever they may be located are always 8 bytes apart.
2. At exactly 16 bytes before our addies we could find the hex bytes 909090EB08909090

IV. Our Solution

Since we already know the facts, we can use it in our trainer to resolve the game addies at runtime.
What we need to do is search for the "signature bytes" and when we find it at 16bytes to that address,
read a dword (gold), add 8 bytes to that addie, read a dword(silver), add another 8 bytes to that addie
and read the final dword (bronze).

Here's what i have done with my code:

* I filled the Structure IMAGE_DOS_HEADER by using ReadProcessMemory at 00400000h


* I then ReadProcessMemory the GameProcess at 00400000h + IMAGE_DOS_HEADER.e_lfanew
in a IMAGE_NT_HEADERS structure
* I made a loop that allocates IMAGE_NT_HEADERS.FileHeader.NumberOfSections amount of
IMAGE_SECTION_HEADER structure. I then red the sections of IMAGE_NT_HEADERS into my
allocated buffer. Now, If the section is a data section:
* Search the GameProcess from the IMAGE_SECTION_HEADER.VirtualAddress for
IMAGE_SECTION_HEADER.SizeOfRawData (This is our "signature bytes")
*When we find it add 16bytes to the pointer, read 8 bytes(dword for gold), add 8 bytes to the pointer
read 8 bytes for the silver and increase the pointer by 8 bytes and read it for the bronze.

V. Final Words

Well, I hope you learned something from it. If there is something vague in the tutorial, pls contoct me
via e-mail : root@tsongkie.com or go to team extalia's homepage. www.extalia.com

Greetz goes to:

* Sheep * ddh * Micral * iCarus * Those in #gamehacking in EFnet * Team Extalia *

Tsongkie
http:/www.tsongkie.com
Extalia
Learn from Trainers WITHOUT Trainer Spy

by Orr
OrrAghion@hotmail.com
*NOTE!*
The reason I am writing this paper is not of teaching the lamers out there another method
stealing other people's hard work, but I want to let the Game Hacking community know a
this finding (though a lame finding, but still something good to keep in mind and be aware
Please Don't be a lamer, and honor other people's hard work.
Target Audience
This tutorial is aimed for the more experienced hackers out there, as I assume that you ha
the slightest knowledge of SoftICE or any other debugger, and that you know how to use
disassembler (such as IDA).

Preface
Today, most of the trainers that are actually CODED and not created using a trainer make
program, contain a certain protection against the notorious program "Trainer Spy" created
by Olivier. Trainer Spy is an amazing program which uses a kernel-mode Virtual Device Dr
(VxD) in order to "Hook" the most common functions used by Trainers: WriteProcessMemo
uhm, ReadProcessMemory (which is not used very frequently).

When I say hooking, I mean that whenever one of those API functions occur, TS intercept
the call, and watches for all the parameters passed to it. Those parameters include
the address and the value the trainer is writing to.

There are many ways to protect against TrainerSpy:

1. Search for the window named "TRAINER SPY" using FindWindow(Ex)A.


2. Look for the file "c:\logwmemory.bin" while TS is active (by ^chaos^);
3. Open a handle for the TS VxD (CreateFile \\.\TRASPY.VXD)
:
:
and many other varieties.

By adding Anti-TS code to the trainer, the coder thinks that he eliminates the option of
viewing his hard work. One must keep in mind that a successful Reverse-Engineering
attack can be accomplished in two ways:
1. Dynamic Analysis; Tools used are Trainer Spy and a Debugger.
2. Static Analysis; Tool used is a good disassembler such as IDA or W32Dasm.

In this short essay I will try to review some of the "attacks" used by a more advanced
hacker, should he try to learn from a trainer.

Essay
Recently, when I tried to cheat in a game, for some strange reason the address I found
wasn't correct and I couldn't train it. I decided to download an exisiting trainer from
the Internet, and check out the address it writes to, so I can find out where I was wrong.

Most trainers use the WriteProcessMemory API function in order to write to memory addre
Here is the function's prototype:

BOOL WriteProcessMemory(
HANDLE hProcess , // handle of process whose memory is written to
LPVOID lpBaseAddress , // address to start writing to
PVOID lpBuffer, // address of buffer to write data to
DWORD cbWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);

A normal call in a high level programming language would have been written like this (Pse

WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, cbWrite, lpNumberOfBytesWritten

But after the compilation it would translate to this:

push lpNumberOfBytesWritten
push cbWrite
push lpBuffer
push lpBaseAddress
push hProcess
call WriteProcessMemory
Did you notice that the data is pushed backwards? That's because of the stack concecpt;
Last In First Out or LIFO.

Enough for the theory, Let's get into practice!

Static Analysis
By disassembling the file, one can learn alot about the target trainer. By Tracking a certai
call to WriteProcessMemory, one can view its parameters, and later analyze and decide th
memory address the trainer is writing to.

I will use an example trainer from CES (www.gamehacking.com). It would be MI2's DII
Trainer. It is a mega trainer, and I must say that it is one of the best trainers
I have ever seen! I hope MI2 doesn't care that I use his trainer as an example..

MI2's trainer contains an Anti-TS protection. Although the trainer uses a protection that
can be bypassed really easily (just by changing the caption of TrainerSpy's Window),
I will demonstrate how to apply my method.

Let's say that I want to know which address is needed for the Dexterity. After I
click the "Dexterity" Hack, I get this message: "Your dexterity is higher!"
So disassemble the file with IDA, and after it is finished, go to the Names window
and look for that string (should be "aYourDexterityI").

Follow the call to that location and soon enough you should end-up here:

00406037 push 40h


00406039 push offset aActive_0 ; "Active"
0040603E push offset aYourDexterityI ; "Your dex
00406043 mov ecx, [ebp+var_C]
00406046 call j_?MessageBoxA@CWnd@@QAEHPBD0I@Z
0040604B
0040604B loc_40604B: ; CODE XREF: sub_
0040604B
0040604B push 0 ; No. of bytes Wr
0040604D push 2 ; Byte Size
0040604F lea eax, [ebp+var_8]
00406052 push eax ; Value
00406053 ****** push 0D188F4h ; Address
00406058 mov eax, [ebp+var_4]
0040605B push eax ; Process
0040605C call ds:WriteProcessMemory
00406062 jmp $+5

So you see that the address the trainer is writing to is D188F4, easy isn't it?

Dynamic Analysis
By using a system-level debugger(Such as our lovely SoftICE), the attacker can monitor
any call to the WriteProcessMemory API function, and view its parameters.

Sometimes, the address parameters will not be shown in such a visible way as in the
previous example. Sometimes the address will be hidden and shown inside a register,
or inside another memory address. A common way of seeing it is (TMK1.4a compiles its
trainers this way):

PUSH ECX ; Bytes Returned


LEA ECX, [EDI+1]
PUSH ECX ; Size
LEA ECX, [EBP-01FC]
SUB EAX, EDI
PUSH ECX ; Value
PUSH EAX ; Address
PUSH DWORD PTR [EBP-04] ; Handle
CALL WriteProcessMemory

You see that the address is not shown in a clear way, but inside the EAX register.
In this case the attacker would simply apply the '? eax' command inside SoftICE,
and the address would get crystal clear to him.

Protection and Prevention


Now we have come to the most important part of this essay, which is more vital to
trainer makers rather than attackers and lamers.

Protecting from Static Analysis:

There are quite alot of methods of protection when it comes to static analysis:

1. You can encrypt the file using a PE-Packer (I like UPX and PETITE), and
by this hiding the code and protecting it. This method can be easily bypassed with
the use of an UnPacker such as ProcDump.

2. You can "encrypt" the address you are writing to. By XOR'ing a value twice
with the same number you get the same result you had before. Here is a little
Visual Basic code snippet to help you visualize my thoughts:

Dim address as Long


address = &H123ABC Xor 89
:
:
:
WriteProcessMemory phandle, address xor 89, value, 1, 0

Be creative! Think of some more yourself and then post them! :)


ý

Protecting from Dynamic Analysis:


There aren't many ways of protecting against a debugger, but my suggestions are:

1. Add as many Anti-TS tricks as you can and apply them in


your trainer, not just at startup, but in a timer, that
checks for its presence every once in a while (1 min sounds good :)
I am sure that more experienced hackers would be happy to help you with that.

2. Adding Anti-SoftICE might also be a good idea. Explore this


subject, and learn how to add common SoftICE tricks to your trainer.

Ending
I hope you enjoyed reading this essay as much as I did writing it. I hope I
shed some light on this somewhat 'dark' subject, and brought an important issue
to the attention of some people.

You must remember that the really determined reverse-engineer cannot be stopped
from viewing your addresses, and that the above methods are only here to keep
lamers away. Know that if anyone can read your addresses after applying some of
the methods suggested above, he is also capable of finding those addresses himself :)

For Comments (I like comments :), Suggestions, "Bug Fixes", Flames, Love Letters,
Anthrax Envelopes or Moeny, Mail to OrrAghion@hotmail.com

Thanks for reading this!!


Orr, End of October 2001.

/\
____/__\____
\ / \ /
\/ \/
/\ /\
/__\____/__\
\ /
\/
Game Hacking
by Sorin
An Overview
Intro:
In the following, I'll show you what GameHacking is, an how you
can work it out :)

1. What is GameHacking ?

All of you must played even for one time a game that you couldn't finished,
or couldn't pass X level, or something like that. The solution was :

a) make use of the game's cheat_codes (if any). But with this you are
treated by the game like an ordinary cheater : NO HIGHSCORE !
b) put yourself together, download some useful tools from the web and
try to make yourself the law for the game (i.e. : make your pistol
bullets be unlimited without using any game's cheat_code)

Well, in this tut we'll be discussing the b) part...

NOTE: If you like very much the game, then have the patience to finish it
without any game_hacking. After that, hack it until your eyes will be stic
on the PC's monitor !!

2. What tools do we need ?

Yeah, that's a real question... Here's the needed :

a) a good Debugger (Soft Ice, of course) - we'll use the debugger in advanced
techniques of game_hacking, when you need to trace the game's code.

b) a Memory_Searcher (TSearch, ArtMoney, GameHack, Game Trainer) - we'll use


the memory_searcher to find the addresses where the game holds our wanted
data (lives, bullets, energy, mana, money etc).

c) a Hex-Editor (HexWorkshop, Hackers View) - we'll use the hex editor when
hacking the saved_game files, or when we modify the game's .exe/.dll ...

d) a Dissasembler (W32Dasm, IDA) - we'll use the dissasembler when we have to


deal with a dead-listing. A dead-listing is the game's code listed in ASM
when the program isn't running in memory.

e) a Trainer-Maker (Trainer Maker Kit) OR some programming knowledge. These ar


OPTIONAL, needed only when you want to build up a trainer.

These tools can be found at :

- http://www.protools.cjb.net/
- http://www.gamehacking.com/
- http://www.ghu.as.ro/
- and at many more sites...

Here's some pictures representing the respective tool:

SoftIce ; Game Trainer ; GameHack ; W32Dasm ; HexWorkshop ; Hiew ; TMK ; TSearc


3. Types of Game-Hacking :

Well, we have several ways to do our hack :

I. Memory Hacking
a) Value poking (when changing the amount of grenades, for example)

b) Memory patching (when we overwrite game's instructions in memory)

i.e. ASM instruction HEX value of "dec ecx"


dec ecx 49

Ecx holds our energy. We have found the instruction that decrease it.
To avoid decreasing, we patch like this:

ASM instruction HEX value of "nop"


nop 90

By changing "dec ecx" with "nop" (49 with 90), we prevent our energy for
beeing decreased. Preety kool, huh ? This method is EXTREMELY EFFECTIV
when we have to deal with DMA.

II. Executable (DLL) Hacking


a) .EXE/.DLL patching (same as I-b point except the changes we make are permanent

III. Saved_Game Hacking


a) .SAVED pathching

Here's why we need Hex-Editors: If the game you want to hack has a
"save curent game" option, you can hack that .saved file...

With all this clarified, we can go down to business :)

< WHAT IS DMA >


DMA (Dynamic Memory Allocation) is how the game_you_want_to_hack messes with your
PC memory... Like the name says, the game allocates the memory dynamicaly. T
means every time you restart the game, it holds your data at a different mem
location. Here's an example :

you found your bullets at address 100


you found your grenades at address 120
you found your life at address 150

........ after you restart the game, ..........

you find your bullets at address 510


you find your grenades at address 530
you find your life at address 560

........ after you restart the game second time, ..........

you find your bullets at address 610


you find your grenades at address 630
you find your life at address 660

What did we deduce ? The game changes the locations of your data EVERY TIME !
BUT, let's take a closer look... In all 3 cases, the difference between the add
is THE SAME !

1st case: 100+20=120


120+30=150

2nd case: 510+20=530


530+30=560

3rd case: 610+20=630


630+30=660

This means our DMA problem ('till now) reduces to : FIND THE PATERN ADDRESS whi

in the first case : 100


in the second case : 500
in the third case : 600

By knowing the PATERN ADDRESS, we can easily add the difference to get the othe
addresses !

This is an overview of DMA...

< CODE INJECTION >

Well, we clarified what is DMA... But how can we bypass that ? SIMPLE ! Code
Injection ! (or kill the instructions that makes your day miserable)

Code Injection is, like the name says, Injection of Code :) hehehe...

Here's an example:

mov eax,[ecx] - ecx = pointer to bullets' address


dec byte ptr [eax] - eax = bullets' address
mov eax,[ecx+20] - ecx+20 = pointer to grenades' address
dec word ptr [eax] - eax = grenades' address
mov eax,[ecx+50] - ecx+50 = pointer to mana's address
dec dword ptr [eax] - eax = mana's address

This is DMA... We found that "PARENT ADDRESS(POINTER)" is ecx. But since is DMA
ecx also changes. So we need to keep this ecx stored in a place from where
we can mess with it all time, knowing it's value...

How to do that ? SIMPLE ! Find somewhere in the game's code a place full of 0's
There we will inject our code. The injection routine is very simple:

- find some empty space in game's memory a.k.a the 0's (or FFh)
- overwrite an instruction with a "jump" or "call" instruction that jumps to th
place full of 0's
- reconstruct the overwritten instruction
- overwrite some of 0's with our code (to catch the parent address)
- jump back (or "ret" if we used a "call") to the initial place (game's code)

So, for our example, this should look like this :

ORIGINAL MODIFIED
mov eax,[ecx] | jmp 4455 (place full of 0's)
dec byte ptr [eax] | dec byte ptr [eax] <-------<---------<----<-
mov eax,[ecx+20] | > mov eax,[ecx+20]
dec word ptr [eax] | dec word ptr [eax]
mov eax,[ecx+50] | mov eax,[ecx+50]
dec dword ptr [eax] | dec dword ptr [eax]
...................
offset 4455: (where we found the 0's)
mov eax,[ecx] - we reconstruct overwritten instr.
mov dword ptr[5555],ecx - save parent to a STATIC addr
jump back to "dec byte ptr [eax]" ----->--->--->------

With this, we defeated DMA by saving the PARENT pointer to a STATIC memory loca
And in our trainer we just read the PARENT pointer from address 5555 (stati
then add the difference to obtain the pointers for other addresses (for
life, money, etc).

To obtain the amount of bullets with your trainer, u can do this:


_________________________
| read from 5555 in temp
| push temp
| pop ecx -> ecx=POINTER to address of bullets
| mov ecx,[ecx] -> ecx=address of bullets
| mov eax,[ecx] -> eax=the effective number of bullets
--------------------------

Also NOTE : that 5555 address is where there are lots of 0's, too ! If u find 0'
1234, then don't use 5555, use 1234 !

!! A BIG THANKS GOES TO SHEEP FOR HIS DMA TUTS. THEY WORTH READING !!

Now, that we have finished DMA & CODE INJECTION, let's have a look on the differe
hack methods...

< SAVED_GAME PATCHING >

Let's take first the .SAVE file patching... What can we do here ? Well, search th
saved_file and replace the wanted value with the new value...

Let's take for example WarCraft II. Play a single player game. After a while, sa
game under XXX (for example). And remember your gold amount !!! Now, load
XXX file in HexWorkshop and do some searching... But the search type must
under "32 Bit Unsigned long". That's because u search for a base 10 number
this number can be greater than 65535 (biggest word value). Got the idea ?
Now you type in the "Value" edit_box the amount of money, and click OK...
Simple, heh ?

But there are also A LOT of games that save their data ENCRYPTED (like StarCraft

In this case, we try

< VALUE POKING >

Yes, the well known method...

Here we need the memory_searcher ! So, fire it up (TSearch, ArtMoney, etc) selec
process the game you want to cheat in, and search for the wanted value. The
memory_searcher will find many addresses containg your value. To bypass this
go back in the game and CHANGE that value. Pause the game, go back in mem_se
and search for the new value ! Repeat these steps until you will find only a
addresses. Then all you have to do is to try changing the value in those add
and see (in the game) how affects you and what is the one you need...

You can also might want to try

< MEMORY PATCHING >

YES ! This is awesome ! And sticks very_well with DMA & CODE INJECTION !

But to master this technique, you must have (some) asm knowledge...

Here's an example :

You find your bullets at addr. 100. Open SoftIce (^D), and put a bpm on that ad
< bpm 500 >. BUT YOU MUST BE IN THE GAME PROCESS !!! (Check SoftIce's lower
corner. If it says the name of the game, then you're IN !)

Shoot a bullet in the game... SI should pop:

.............
xx: mov eax, [44]
yy: dec eax -> you land here in SoftIce
zz: mov dword ptr [44], eax
............

What do we see ? The game moves in eax your bullets number stored in memory at
[44]. Then it comes that UGLY instruction "dec eax", then update your decre
bullets back in [44]. So, to prevent bullets for decreasing, we just "nop"
operation) that "dec eax". You can do it in SoftIce by typing:

asm yy [ENTER]
nop [ENTER]
[ENTER]

,where yy is the memory offset of the respective instruction...

Yeah, this is a GOOD method, but we don't want to do this SI thing all the time..
OK ! There are 2 solution :
a) make a trainer
b)

< EXECUTABLE/DLL PATCHING >

This is almost like above, except we change the instructions permanently ...

We'll use Hiew. Fire it up and load in it the game's .exe. Press F4, select "De
then press F5 (goto address) and type that yy number you had from SoftIce.
press F3 (edit), then F2 (asm), then write your "nop" instruction. Then pre
[ENTER], then [ESC], then F9 (save) and you're done !

REMEMBER : Sometimes, the instructions that dec your life, money etc are not in
.exe file, but in some game's .DLL. You can easily find this out wi
SI by looking at the offset of the respective instruction. If it sa
something like 1XXXXXXX or so, then your in some DLL ! You can also
at the lower right corner of SI.

Example of game that uses a .dll to dec the life : HERCULES

In the following there will be presented some techniques on hacking different thi
in a game...

BULLETS, LIFE, MANA, GRENADES etc (when you know their real amount) :

-search with mem_searcher for that value


-change it in the game
-search for new value
-repeat these steps until you find only a few addresses (usualy 2-3)
-change the value at those address to see how affects you

ENERGY BARS, BULLETS, LIFE, MANA, GRENADES etc (when you don't know real amount)

-dump the memory


-change your energy, bullets etc inside the game
-search the dumped memory for the addresses whose values are changed
-repeat these steps until you find only a few addresses
-change the value at those address to see how affects you

*** The value of a full energy-bar is usualy around 250 !!! ***

INSTANT BUILD HACKING TECHNIQUES :

-dump the memory


-change your energy inside the game
-search the dumped memory for the addresses whose values are decreased (usualy)
-repeat these steps until you find only a few addresses
-change the value at those address to see how affects you

WAYS OF MAP STORING :

< well, this is the most complicated part of all >

In 2D strategy games, map is probably held in matrix


___________________________
| a[1,1] a[1,2] .... a[1,n] |
| a[2,1] a[2,2] .... a[2,n] |
| ...............X......... | -> X are your units, and that purple color means
| .....................X... | the map in that place
| a[m,1] a[m,2] .... a[m,n] |
-----------------------------

representing the screen. When your unit is moved on a[5,6] (for example), then t
puts in that place in matrix the coded_byte for place_without_fog. When you m
your unit from that place, the game puts back at that place in matrix the cod
for place_with_fog.

So, the game have 2 options :

a) refresh the map in a timer


b) refresh the map when a unit is moved

My personal opinion...

PS: Don't bitch me if u find a game that has diff. ways to store the map...

In the ending, I wish all of you a "nice hacking" :)

< CHEERS & GREETS >

I want to thank some people who helped me directly/indirectly


(you know, order doesn't matter :) )

- Groza (BEST publisher :) - I'm still & still waiting that tut on C&C map_hack :
when you'll have time, of course... )
- Snaky (toate cele bune ! )
- T-RaiNeR (n-am mai vorbit de mult... nasol e cu bac'u asta :((( )
- ParaBytes (my cracking teacher - a BIG THANKS)
- Some in GameHacking's forum ( some of u are great, but some are made of cocoa :
- All GHU members (Cei mai buni ! - Biciuila esti si tu inclus, cacaciosule !)
- JUVENTUS (I love JUVE)
- YOU
romanian:
*******************************
* Salutari celor din Romania! *
*******************************
Special Greet Goes To Synbios -> he knows why and I hope he'll forgive me someday

Advertising:

Currently we are looking for quality tut/useful_progies writers. If u can handle

the task, drop us an email ( GHU_Federation@email.ro ).

Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


GHU ( http://www.ghu.as.ro/ ).

2003
eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: GAMEHACKING TUTORIAL PART 1 ::


:: BY BLIZZARD ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

This will be a introduction to gamehacking.


I think all of you that play games have cheated in it sometimes.
Maybe just that once or maybe you do it all the time.
Most of the time you go on the internet to some site thathas lots of cheats on it

Now wouldn't it be fun to cheat in every game without searching


the internet every time you got a new game? Or maybe even make your own trainer !

We'll start with cheating only in this tutorial and maybe later you will learn ho
a trainer. Here I will only give you an impression of what is possible.
I assume you are on a windows computer and you have Minesweeper on it.
You will need an easy program called the "Cheat 'O Matic" by Nick Shaffner.

Download it from my site:http://www.mytestpage.coolfreepages.com/ghtut1.zip

Start up minesweeper and AFTER that the Cheat 'O Matic (CM from now on).
When you are in minesweeper and you click on one of the boxes the time begins to
Now minimize minesweeper, wait 5 seconds and then maximize it again.

You notice that the time is the same as when you minimized it. That is helpful fo

From the drop-down box select Minesweeper. Go back to Minesweeper and start a new
Then click once so the time begins to run. Now look at the time and minimize it.

Now press the SEARCH button.CM will now search 7 in the memory (DMA) in your comp

After a while it will stop and say: (Change the value in the program, then enter

We will do exactly that. So go back to Minesweeper and wait a few seconds until t
has become a little bigger. Say for example that it is 14 now.
Go back to CM, fill in 14 and press SEARCH.Again it will search for the value you

Change the time again and search again until you get a message like this.Cha-chin

Now what we shall do is freeze the time.On the down left you will see LOCK. Check
Now in Minesweeper press the smiley and start playing. You will see that you have

Congratulations !!!

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Greetings go out to all of Computer knightS (EFNET, #computerknights) especially
Greetings go out to all of Extalia members especially SnokGreetings to [Sheep] fo
Greetings to #cracking4newbies.
Greetings to #gamehacking.
Greetings for all the others. You know who you are ;-)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

BliZZard, blizzard_1337@hotmail.com
1.Tutorial about using trainers
by Reaper
e_nesovski@yahoo.com or
reaper@extalia.com
www.extalia.com
################################################################################
Intro:
In this tutorial I will tech you how to use and to learn
how a trainer works, I know these is very easy, but there
are some people that don't even now what a trainer is.
################################################################################
Needed things:
1.A trainer
2.The game that the trainer is made for
################################################################################
How does the trainer work?
The trainer is used to poke memory addresses of a game.
Poking means changing or freezing the values of some addresses.
The trainer only works with the game that is made for, which means you
can't use a trainer for all the games, only for 1 and only with the
version of the game that the trainer is made for (ex. counter-strike 1.1, 1.3...)
A trainer doesn't always have the options the you want, if some game
has lives, ammo, shield, that doesn't mean that in the trainer you can
change all of that.
When the trainer pokes in some game, it can make you have unlimited
life's, money, wood, gold, ammo, reveal map...to do this the trainer writes, adds
or freezes the value of a memory address. As the trainer must work while the game
most of the trainers will require you to minimize the game (With ALT + TAB) so yo
use the trainer, but some of them have hotkeys which you can use while playing
the game. Sometimes if you use a trainer, it could happen the game to crash or
the anti-virus program to think that the trainer is a virus, but the trainer
isn't a virus in anyway and if the game crashes while using the trainer that
means the game has some protections and it may be unstable while using a
trainer, therefore you can continue playing the game with the trainer or find
cheats for it. Also note that trainers are legal only if they work with single pl
games, while using a trainer in multi player games can sometimes be illegal and m
lose its fun for you and the other players that are playing with you.
################################################################################
How to use a trainer?
1.You must have a game, example Age of Empires 2.
2.Now go to some cheating site that has trainers and download the trainer for thi
(some cheating sites with trainers are: www.extalia.com www.gamehacking.com www.x
www.megagames.com www.dlh.net ...)
3.Almost always the trainer comes in zip or rar files, so you will have to extrac
some folder.
4.Now go to that folder and start the trainer
5.Now start the game (the trainer must be working)
6.Start playing the game, and press ALT + TAB
7.Now your back to the trainer (the game is still running) and click on a button
the trainer to start poking (ex. chose to have 1000000 wood, gold, rock, food or
8.Go back to the game, and you will see that you have 1000000 wood, gold, rock, f
There are also some trainers that have hotkeys, if you know the hotkey for some f
trainer (ex. life's, ammo) you don't have to ALT + TAB to go back to the trainer,
hotkey and trainer will start poking (ex. if the hotkey for ammo is SHIFT + R, in
playing press SHIFT + R and you will have get ammo without having to minimize the
################################################################################
Now that you know how to use a trainer, maybe you want to find out more about gam
and learn how to make a trainer. To learn this read my tutorial on how to make a
and Part 2.

THE END
- What Is "Gamehacking" - By Elissaios.

This guides describes detailed the following topics.

1. What is Hacking and what is the truth about it.


2. Gamehacking structure and process.
3. Why, When and How Gamehacking is not illegal.

1 :: What is Hacking and what is the truth about it.


First of all you need to know what "hacking" refers to and what it means. "Hackin

The illegal stuff are starting to flow when a personal/computer system security i

2 :: Gamehacking process.
When we hack a game we do not actually hack its contents within, but its stambed

3 :: Why, When and How Gamehacking is not illegal.


Gamehacking is not illegal but TOTALLY legal. And that prouves it by its non-modi

The only case gamehacking can turn illegal, is to hack online multiplayer games.

- Game Server Hacking. You dont have the right to hack memory table of company's
- Various of complains to game companies by gamers saying "I had full health and
- Luck of online gaming fun! Its the first reason why u shouldn't hack multiplaye
- Its not fair! Be an online gamer, not an online lamer!

I hope you've learned some things you were questioning before. Thanks for reading

-Elissaios.
Tutorial Written By x-UnDeaD " undead@extalia.com "
Take a fast visit at www.extalia.com :D

___________________

A trainer can be alot of things,a Trainer(Cheat) that helps you in a game, where

Or a trainer,like a " Dog Trainer" Master Trainer,bla blah blah !!!!


But the most use of an " Trainer " is used by cheaters which code them in program

Where they add an help function like AutoKnife,so it makes you'r knife ,knife fas
Or it could also be speedso you can run from a guy that is hunting you or move WW

As in E X T A L I A,we do not provide ANY MP(Multi Player) Trainer, which is ille


Cause the cheat that u activate hits the server(which make it illegal),and backs

But a SP(Single Player) trainer doesn't hit any server or host,it only hits the g
Which is NOT illegal,cause it is Legal :-)..
That's why WE only and are only going to provide SP trainers.....

By x-UnDeaD
What is hotkey(s) used for and what can they do?

----------------------------------
By x-UnDeaD
__________________________________

Hotkeys can be a hotkey in the game or a trainer, most used hotkeys is in a train
I use the hotkey function in vb GetAsyncKeyState , someother's use SendMessage.
To get an example of this read the text below :
__________________________________

You are in a game the ALT+TAB function has been disabled by the people that made
You think,darn this sucks,how am I now going to use the new cheat I downloaded?..

That is why hotkeys exsist, so u can press them instead of ALT+Tabbing Out if it
-Just a small simple tutorial about hotkeys..

By x-UnDeaD
Contact Me At : undead@extalia.com or register at the Extalia forums and send me

UnDeaD..
BY x-UnDeaD
Contact Me At undead@extalia.com Or Visit The Extalia EXP site At: www.extalia.co

WHY DO PEOPLE CHEAT?


----------------------
Well,some games can be harder than others, so they must use a cheat/trainer if th
Unlike other people,that keeps going on and on and on,and they finnaly win the ga
Red Alert 2 Yuris Revenge ect,i found that as a cool game when playing skirmish,

So i made an cheat for it,where u get UN-Killable...


But there is more cheats out for it..
----------------------------------
In other games like Delta Force 2 V1.06.15 Which I played before (if you think yo

Back to Delta Force.I played that A long time ago,when it first was released, the
n00b's asked guys that got cheats if they could tell them where they got it or ho
..................................

Tutorial Written By x-UnDeaD " Extalia Releaser "


Contact Me :undead@extalia.comor at our IRC channel : http://www.darksystem.com/c

Later / x-UnDeaD
:::::::::::::::::::::::::::::::::::::::::::::
:: GAMEHACKING TUTORIAL PART 2 ::
:: BY BLIZZARD ::
:::::::::::::::::::::::::::::::::::::::::::::

I assume you have also read part 1 of my tutorial. In the first tutorial you saw

Okey let's do that.In this tutorial I will teach you how to make a trainer. You w

Okey let's start. You have to download a program called TSearch. It is available

So I start a skirmish game and look around. Let me build a Marketplace. Mmmm mone

Then I press the small button of a magnifying glass just under the OPEN PROCESS b

I fill in 2000 and I get 97 results. Back to the game. I will buy some iron so my

Fill in 1775 and press OK. I get 1 result. For me the address is D5E168. For you

Remember DMA and STATIC, they are important in gamehacking!

Click on your (DMA) value 1 time and press the green + symbol a little above it.

Okey let's make a trainer. Remove the blue smiley by clicking on your line and pr

Again go to AUTOHACK and now select AUTOHACK WINDOW.


Another window pops up which we call the Autohack Window. Minimize it for now and

Now go back into Stronghold:Crusader and buy something 1 time! Then ALT+TAB back
* 40FF98: add [eax], ecx* 40FFBF: mov [ebp+0xD5A774], edx* 464FA2: mov [edi+0xD5A

Now we are going to use what they call the TRIAL AND ERROR way of which one is th

Go back to the game. Now buy something.


What you will see is that your iron will become 0 and your money will still decre

As you will see your money will not be decreased anymore! NOTE: In the autohack w

Okey so we know now that the line:* 464FA2: mov [edi+0xD5A774], ecx is the line t

But what do we do with it now? Select the * 464FA2: mov [edi+0xD5A774], ecx line

:::::::::::::::::::::::::::::::::::::::::::::::
Tmk button script
Copy and Past into tmk using ctrl+V
Ex: Patched script for a ON button and Unpatched script for a OFF button

Patched script:
Poke 464FA2 90 90 90 90 90 90

UnPatched script:
Poke 464FA2 89 8F 74 A7 D5 00
:::::::::::::::::::::::::::::::::::::::::::::::

Copy this into a text file because we will use it to build our final trainer!
But that in the next tutorial ;-)

:::::::::::::::::::::::::::::::::::::::::::::::
Greetings go out to all of Computer knightS (EFNET, #computerknights) especially
Greetings go out to all of Extalias members especially Snok
Greetings to [Sheep] for helping me out.
Greetings to #cracking4newbies.
Greetings to #gamehacking.
Greetings for all the others. You know who you are ;-):::::::::::::::::::::::::::

BliZZard, blizzard_1337@hotmail.com
Welcome To A Tutorial I Know Alot Of People Will Have A Use Of.

FINDING AMMO

Wouldn't it be hot/cool to have unlimited ammo for you'r favourite gun?

Well sometimes i think it is :) !

Back to the tut,so c'mon let us start ;-)

______________________________________________________________

Well,first choose you'r game.(must be guns included :D).

Open your memory searcher ( gamehacker,i use Tsearch,cuz it r0x.)'

Go back into your game,select the gun you want ammo for(knife cannot be used.)

See how much clips you have,two ect

ALT+TAB out of the game,open Tsearch,

Search for the EXACT VALUE in the game,for me it's 2

now u should get one heck of codes.

Go back in the game,and waste one clip so it should show that you have 1 clip lef

ALT+TAB out of the game again,and search for 1 ,and now you should have one addre

there it is,you have now found the ammo code.U can freeze it so it doesnt increas

Or just change the value ::-) you'r choise

now u can keep every0ne in single player,great huh :D ...

Hacking And Finding Ammo Code For Single Player By x-UnDeaD

Contact :

undead@extalia.com

REMEMBER : EXTALIA EXP DOES NOT PROVIDE ANY MULTI PLAYER HACKING OR TUTORIALS.

Even if you have this in join it will not work.


X-UnDeaD
Hex Editing : The Basics
Due to popular request (100's), here is an very brief guide to hex editing so that all you
folks who want to give yourself 16 billion credits in Imperium Galactica (or any other cheat
in any other game!) so you can spend, spend, spend and wipe the galaxy floor with your
enemies.

WARNING: always make a backup copy of files before you start dissecting them, I am not
taking responsibility if you accidentally disassemble your Main Battle Flagship or manage to
edit a file so that it corrupts your entire game - (some games just don't like to be messed
with....[e.g. Age Of Empires].

Tools Of The Trade : The Editor


All right, first thing you need is a hex editor. The one I have provided here is shareware and
the only one I recommend, written by Jonathan Durward (jon@durward.com), its the
smallest, and it sure has a lot of useful features, including searching in ASCII as well as
hex, can load large file sizes (some save games can be over 1Mb in size), count number of
string occurrences, ansi colour (to aid your eyes) and most useful - a HEX/DEC converter.
The file is only about 68Kb and it is zipped, so it will download quickly, you will need either
Winzip or similar program to decompress it!

ANY DOWNLOAD ISSUES - send an email to my self or Jon!

*****************************************************************************************
The Registered Version of this program can be purchased and
received immediately on the Internet at Albert's Ambry.

Registration at Albert's also eliminates shipping and handling so please go to :

http://www.alberts.com/

Search on: hextool.zip and then Click on the "Buy It" Hotlink to register this software.
*****************************************************************************************

Hands On Experience
Basically, a hex editor lets you view the hexadecimal code in which most save games are
compiled/saved. When you're trying to cheat by adding money, attributes, ships, gold,
lumber, ammo etc., you'll be looking for a string of hex characters that will look something
like this:
08 49 FA 9B 58 09 DA

and replacing it with an altered string that the cheat file/hex editor tells you to. All you're
doing is the same as changing "credits=1000" to "credits=1000000". So, load the hex
editor, (its easier if you place the hex editor files in your Utils directory so if you have a
DOS path set to include \Utils, you can use the program anywhere on your drive) by typing
'hex ' and the filename you need to edit in order to get your credit bonus - e.g. C:>hex
save1.sav. When it opens, it'll look something like below:

The column on the right is the ASCII code generated by the characters to the left. So, in
this example, the amount of credits I have in the game is 14847889 (I already cheated!!!!).
So we are looking for the string "14847889" but we don't know the hex equivalent, you can
use the converter (ALT B) and type in your decimal figure. Hexadecimal is what we call a
base-16 system, which just means that instead of counting 0-10 for each decimal place,
you count 0-16, using A-F instead of 10-15, so, if 11=0B, then 15=0F and 16=10 and so
forth. It takes a little practice, but it's really not too hard, especially if you keep a pad and
pencil handy for notes, but again being kind old Mogsy, the editor I use can convert
decimal, hexadecimal and 2 others (told you it was good), so as I said, you can convert
back and fore from hex/decimal at your leisure!

Back to the editing, so as per the picture, to convert '148478889' to hex in order to find its
location its hex address), use ALT B and type in the decimal figure, this then tells us the
HEX equivalent which is 'E2 8F 91', but here is the twist so READ carefully - any hex figure
that uses more than 1 byte i.e. over FF (255) must be reversed before editing it to your
hex file. So it now becomes '91 8F E2' and we do a search using F5 and type in the string.
It tells us that it is located at offset 2D (shown in green text on far right of screen). The
offset is used so you know where to return to the next time (use ALT G and type Offset
number). Phew!!!!

Some cheats lists will tell you to replace a complete string, others just say the first
occurrence and so on. If you've backed up your files, you should be free to experiment with
whatever variables you can find, and believe me they sometimes are hard to find! Then,
rename your original file (save1.sav -----> save1.bak), save your edited file under the
original file name (save1.sav), load the game and load your save game, now you should
have enough credits to buy an army/armada/fleet. Be aware, that some games will crash,
should you insert some weird values, Alien v Predator and most MS based game are bad
for this.

That's all for now, I will do an update soon, for all the new types of games.

Any comments or queries, just email 'em to me with Header/Subject : Hex Edit Query
You use a tool like Hex Workshop. Basically you need two tools to hex edit successfully.

A hex editor:
http://www.bpsoft.com/

That is the one I use, I use AXE (Advanced HeX Editor) too but Hex Workshop pretty much suits my needs.

A disassembler:
ftp://underhalls.ftphost.net/pub/st...es/w32dasm7.zip

I use Windasm, which I linked above. I also use IDA Pro, but that program does not even have a trial
download (at least I think) so I can't give you a dl link.

The last thing you need takes a bit more time, and that is knowledge of assembly. Now don't think this is
the only thing you will use it for; I promise you if you ever want to be a really good game hacker you are
going to have to learn it.

What you do is use the disassembler to disassemble your target program into its assembly equivalent.
Please do not confuse this with a decompiler, which interprets the program and displays its contents in the
language it was programmed in.

You use your knowledge of assembly and follow the disassembled code around to find the code you need
to alter to accomplish whatever goal you may have. The disassembled code will look something like this:

:004010F8 740B je 00401887

What’s that stuff mean? Check this out :

Code Location
004010F8

Opcodes
740B

Assembly Instructions
je 00401887

je = a conditional jump. Two values were compared and it jumps to the code location 401887 if the values
are equal (that code location would be a tag in the original code, like say maybe this is for a cheat detector
and it jumps to NoCheat: if the values are equal (maybe it did a checksum and is making sure its value
matches up with the hardcoded value) when the program is assembled it gets turned into that address). As
you may see je stands for Jump Equal (jump if equal).

Ok know I am sure you want to know how this stuff is useful? You use the assembly intructions (and the
code location) to follow the code around and find what you need to alter to make the program do what
you want. I will tell you know that in game hacking you will almost always be playing with a jump.

Say I discovered what I need to do to make my game allow me to play with cheats (remember in this
example we are defeating some sort of cheat protection albeit very simple protection) is force this jump. In
other words make it jump to NoCheats: even if the checksums do not match because a cheat was found.
What I would need to do is go to that code location and change the opcodes to make it jump no matter
what (an unconditional jump). There is a problem though, the code location is not the same address as it
will be in the hex. The code location is a Relative Virtual Address (RVA). What I need to do is use my
disassembler and have it tell me what the RVA is as the hex address. In Windasm you do this by highlighting
the line and reading the status bar.

Now you need to convert the assembly instructions (mnemonics) into their hex equivalent. Je = 74 as you
see in the opcode, and we want to change it to EB (jmp = EB). So what I do is open the program in my
hex editor and go to the hex address I obtained and change the line 740B to EB00. Since I replaced a
conditional jump with an unconditional jump, I did what is called "forcing" the jump. Now it will go to
NoCheat: even if a cheat was found.

Wow this ended up being a long post. I didn't really mean to write a tutorial, but it looks like I did. I hope
you followed it. I decided to write a general overview of how to do it because I didn't know of any good
text and pretty much taught myself all this
How To Hack Games So You Can Skip Levels
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Tools Needed :
-Game Hack 2.0(Free And Good)
-Game With Levels

Finding The Address


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Ok.First Load The Game And Start A Mission.(Doesnt Matter What Mission Number But
To Pass Usually).Ok After You Get That, Pass Almost All Of The Mission Objectives
Is 0.So Alt+Tab Out Of The Game And Start Game Hack 2.0 And Select Your Game In T
Search And Select ADVANCED From The Drop Down Menu.After Game Hack Has Searched F

Step One > Go Back Into The Game And Pass The Mission.Then Alt+Tab Into Game Hack
Menu,Select Increase And Search.You Should Still Get Too Many Addresses For Game

Step Two > Go Back Into The Game And Load The Save Game That You Just Saved,Alt+T
Out Into Game Hack,Make A Next Search But Select Decrease This Time.

Step Three > Repeat The Two Steps Above Until You Have The Least As Possible Addr

Step Four > Now Reload The Game And You Will See All Your Address Values Turn To
Game.Now Try To Finish The Mission.Just As You Are About To Win,Alt+Tab Out Of Th

Step Five > Now,WATCH CAREFULLY!!! See The Values That Turn From 0 To 1 ? Delete
Ok The Easiest Part Is Here. Just Quit The Game And Reload It Again.Load Your Sav
Trial And Error Method To Change The Values Of The Address You Have One By One Fr
In The Game By Turning Up Your Sound And Listening The Victory Sound.

Step Six > Create Your Trainer With The Address And Poking It To 1 And You Will h

=-=-=-=-=-=-=-=-=-=
By SubZero

C.E.S

If It's In The Game,It's In The Release!


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

|Hexing: A Quick Guide to an Art Form

|Written By Max_Power (12-9-03) Accept No Substitutes

|You will only need about 15 minutes for this.

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

Introduction:

_____________

I am going to keep this short and sweet so don't blink. This does not include an

Tutorial:

_____________

Basically you need two tools to hex edit successfully.

A hex editor:

http://www.bpsoft.com/

That is the one I use, I use AXE (Advanced HeX Editor) too but Hex Workshop prett

A disassembler:

ftp://underhalls.ftphost.net/pub/st...es/w32dasm7.zip

I use Windasm, which I linked above. I also use IDA Pro, but that program does no

The last thing you need takes a bit more time, and that is knowledge of assembly.

What you do is use the disassembler to disassemble your target program into its a
You use your knowledge of assembly and follow the disassembled code around to fin

:004010F8 740B je 00401887

What’s that stuff mean? Check this out :

Code Location

004010F8

Opcodes

740B

Assembly Instructions

je 00401887

je = a conditional jump. Two values were compared and it jumps to the code locati

Ok know I am sure you want to know how this stuff is useful? You use the assembly

Say I discovered what I need to do to make my game allow me to play with cheats (

Now you need to convert the assembly instructions (mnemonics) into their hex equi

That is it. I hope this all made sense.


Pointers and Code Injection: An alternative to staple intersections
-------------------------------------------------------------------

by Tsongkie

www.tsongkie.com
www.gamehacking.com

A little Intro
--------------

I've read tutorials by [sheep] and eedok and somehow I have learned
to fuse the two great tutorials in 1 unique way that can help most
gamehackers in training games. I have seen several vague tutorials
on this also that may not be to the specific point on what readers
want to learn. I would try to be as clear as we go on...

Needed Files
------------

1. Falcon's Beertender - www.tsongkie.com (under goodies)


2. Tsearch - also available in www.tsongkie.com (under goodies)
3. Poke Generator by Divine Shadow - www.tsongkie.com

Pointers
--------

Let's define what a pointer is. Get Falcon's Beertender from my website
and run it. Play around with it for a while. As you would notice, you have
4 lives, but in the screen when you have all the lives it shows III. Thats
because when you get killed it turns to II - I - NIL respectively. You
get the idea, right?

Ok, play again and search for 4 in tsearch. It will help if you pause the game
using the File Menu of the game. Click spel - spelegrer. That should have shown
an about box and the game paused. =p Die and sieve again to 3.

I get the address 9304C4 (4bytes). Enable autohack and show autohack window. Righ
click on the address and choose autohack. Get back to the game and loose another
Pause the game.

In the autohack window, it shows this: mov [ecx+0x4],eax

what this means is the value at eax is being moved to [ecx+0x4] which is our life
address. Try NOPping It and get back to the game. Lose a life... great! our life
isn't decreasing but our points are not increasing either. Not only that, you don
advance after you win the game...

Thats because the code mov [ecx+0x4],eax is also being used by some other parts o
the game like our points. Restore the original code by unNOPing it.

The easiest way on defeating this is to find a pointer to our life address. This
how to do it:

In Tsearch's calculator, click on H beside 0 so that the calculator is in hex mod


Type in the address we found which is 9304C4. Remember the code: mov [ecx+0x4],ea
[ecx+0x4] = 9304C4 therefore ecx is equal to 9304C4 - 4. Be sure that you underst
this before you continue reading...

Ok lets get what ecx is. Using Tsearch's calculator, subtract 4 from 9304C4 which
should then give you 9304C0 (lol we dont even need a calculator for that :) ). An
convert 9304C0 to decimal by clicking the "D" beside 0. I got 9635008. Then searc
9635008 in Tsearch. The result is the pointer.

We should all have the same pointer which is the address 417CC4. Whatever is in t
address and it by 4 is your life address!!! Alright, let's test this. Restart a n
game. Read the value at 417CC4. Type it in the calculator, convert it to hex and
You got the new life address!!! hooray!!!

What you can do with this is have your trainer read 417CC4 and add 4. You should
the right address to your life. Congratulations, you resolved a dynamic memory in
runtime.

Code Injection
--------------

I'm a lazy ass and i want to resolve all this by just injecting my code. This is
very useful when it comes to games that uses the same code to a computers life ro
and your life routine.

Ok we have:

mov [ecx+0x4],eax

Just go one step backward and you should get this:

mov eax,[esp+0x4]
mov [ecx+0x4],eax

Alright, we already found out our pointer address which is 417CC4. What we need t
is compute if ecx is equal to the value in 417CC4. Remember that the value in [41
plus four is equal to the life address and ecx plus 4 is also equal to the life a
therefore we conclude that ecx = [417CC4]

Note:
[417CC4] - means the value IN 417CC4 not 417CC4 itself.

OK. Heres what i did with easywrite:

Enable code:

offset 0x400000 //code cave


mov eax,[esp+0x4] //copy what we will overwrite
mov [ecx+0x4],eax //copy what we will overwrite
mov eax,[417cc4] //mov the pointer to eax
cmp ecx,eax //compute ecx and eax (ecx and the pointer)
jne 403247 //jump back to the code if not equal
mov dword ptr[ecx+0x4],4 //if equal then [ecx+0x4] is our life address! mov the m
jmp 403247 //jmp back to game's routine

offset 0x403240
jmp 0x400000 //jump to our code cave
NOP

DISABLE CODE:

offset 0x403240 //this is the original code.


mov eax,[esp+0x4]
mov [ecx+0x4],eax

Enable this easywrite hack while playing the game. We have hacked Falcon's Beerte
The score is now also increased and the stages loads normally. *sigh*

Tool to help you


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

Poke Generator by Divine Shadow


(Convert the easywrite - tmk codes to assembly codes)
Good job bro. get it www.tsongkie.com

Final Words
-----------

Another tutorial done, I hope you learned something from it. :)

greetz goes to:

* [sheep] * eedok * stoner * Team DVS * Divine Shadow * Team CES *


* #gamehacking -efnet people * and to all i forgot *

~Another fine release to fuck the NOPPER wannabees~


Preventing Game Trainers from Modifying
Your Game
A game trainer is an external program that modifies settings in your game. These settings can make the
gameplay easier, or downright simple for someone to play your game.

Some game trainers modify (increase/decrease) values, such as your health, or lives. Others prevent
those values form changing. So you never take damage.

If you just want to know about the protection methods you can just go on further but if you want to see
these protections at work, I recommend having this software before you continue.

Any C++ Compiler (Tested on Borland C++ 5.02)


TSearch:
http://membres.lycos.fr/tsearch/tsearch_16.zip
http://www.gamehacking.com/download.php?type=tools&file=memfinders/tsearch_16.zip
Also, read the Help File included in TSearch on how to search/modify/freeze
values.Once you do that, you are ready to continue.

Before I begin let me explain what a trainer is. A Trainer is a seperate program that has the ability to
access the Primary memory used by another program in an
attempt to change valuable data ( in this case ammunition, health, Lives etc.)

In short Trainers are like external cheat codes. They seem to be fun if you are the gamer but if you end
up being a developer it's a lot frustrating as the whole action and difficulty of the game is lost.

Even though trainer protection is not very critical it still is a good way to ensure that the game is
played the way it is meant to be played. Some game developers are now trying to stop creating cheat
codes in their games since the whole point of the game is lost.

An example is the game Uplink Hacker Elite by Introversion in which the patch for version 1.3
onwards disables cheats. CD-Protection schemes do not prevent cheats from being used, CD-
Protection schemes are used to prevent piracy. Trainers turn out as substitutes for cheats. This Article
will help game developers to make trainer creation difficult if not impossible.

I would like to discuss the techniques that don't work first.


PROTECTION MECHANISMS THAT DONT WORK

(i).Some people think that displaying a value such as health in a graph stops beginners from making
trainers.But this is not so.Assuming you are playing a game in which your health is displayed in the
form of a graph. Now you start the trainer maker program which can search for values within an
application.Nowadays these Apps have become so intelligent that they can even monitor changing
values. So in this case we would set the search mask for "a decreasing value" and do our best in the
game to keep losing health. Eventually the address is found. Overcoming this is explained later.

(ii)Another frequent method used is to use floating point numbers to store data. But Again Trainers
allow mere users to search for float and double values.So this wont work either.

(iii)Adding/Subtracting/Multiplying/Dividing Numbers and using the result as the actual data has also
lost importance. Because all you have to do is to find the value when your health(or whatever) is
FULL and then "Freeze" the memory location as your health decreases. This way people can even
overcome this protection without even knowing the calculation mechanism.

(iv) Using two or more variables even of different data types isn't of much help the reasons of which
are the same as the one described above.

These are the basic protection mechanisms used to fight trainers but dont work. Now we shall see
what really can be done to stop trainer creation.
MORE POWERFUL PROTECTION MECHANISMS
1) THE PLAIN CONDITIONAL
If you tell a software developer that you check the value of a variable just after you assign a value to
it he might think that you are the dumbest programmer but it is not so. Look at this example that stops
the game when a trainer is detected.

While Executing the code below make sure TSearch is Started and the EXE is included as a process.
Then keep searching for 100/90/80 as the output is shown.
When you find the memory address freeze it or modify it and see the MessageBox Popping Up!!
#include <iostream.h>
#include <windows.h>
#include <conio.h>
#include <stdlib.h>

void trainer()
{
MessageBox(0,"TRAINER DETECTED!","WARNING",MB_OK);
exit(0);
}

void main()
{
int health=100;
cout<<"HEALTH="<<health><<endl;
getch();
health-=10;
if((health+10)!=100)
{
trainer();
}
cout<<"HEALTH="<<health><<endl;
getch();
health-=10;
if((health+20)!=100)
{
trainer();
}
cout<<"HEALTH="<<health><<endl;
getch();
health-=5;
if((health+25!=100))
{
trainer();
}
cout<<"HEALTH="<<health><<endl;
getch();
health-=5;
if((health+30)!=100)
{
trainer();
}
cout<<"HEALTH="<<health><<endl;
getch();
}

So checking whether the value has been actually assigned is a very simple yet effective measure.A
Similar type of protection is used in "Prince of Persia: Sands of Time".Try making a trainer on this
game and you will see an ERROR Message and the Game will Quit.

2) RELY on SECONDARY STORAGE INSTEAD OF PRIMARY STORAGE


As long as your game is not using big-time graphics it's not a bad idea to store such data into files.
Start TSearch again and test this program.
#include <fstream.h>
#include <conio.h>

void main()
{
int health;
char *fname="E:\\aaa.txt";
ofstream out(fname);
out<<100;
out.close();
ifstream in(fname);
in>>health;
in.close();
cout<<"HEALTH="<<health<<endl;
getch();
out.open(fname);
out<<90;
out.close();
in.open(fname);
in>>health;
cout<<"HEALTH="<<health<<endl;
getch();
in.close();
out.open(fname);
out<<80;
out.close();
in.open(fname);
in>>health;
cout<<"HEALTH="<<health<<endl;
getch();
in.close();
out.open(fname);
out<<70;
out.close();
in.open(fname);
in>>health;
cout<<"HEALTH="<<health<<endl;
getch();
in.close();
}
The most interesting part of this type of protection is that even if we find the memory address and
modify it or freeze it, the correct value still appears on the screen.However,then the file which stores
the data has to be either encrypted or stored in Binary Format. With Binary Format you can only view
the file correctly if you have the correct contents of the file structure.

3) MORE METHODS......
The previous two are some of the primary protection methods but the right one to choose depends on
the type of the game. If the game requires speed and the FILE STORAGE protection wouldn't be
perfect.If the game size is important the conditional may not be suitable. But the whole idea of setting
up a Anti-Trainer protection is to surprise the people who make trainers. Using a DLL File or the
Registry to store data while Running the game is very frustrating for the game-hackers as no one
would expect keeping such data in DLL Files or in the Registry.

No developer is as of now interested in putting a trainer protection since game development takes a
lot of time and effort. But a Neat Game is a game which only allows people to play the game the way
it is supposed to be played.

Author Information:

Sanchit Karve
http://
born2c0de@hotmail.com
How to Hurt the Hackers: The Scoop on Internet
Cheating and How You Can Combat ItBy Matt Pritchard
Gamasutra
July 24, 2000
URL: http://www.gamasutra.com/features/20000724/pritchard_01.htm

I had planned to begin this article by sharing my own true experiences with online cheating as it pertained to
a particular game. But I think the long version of my story would cast an unnecessarily negative light on the
game and the company that made it. And since the developers are good friends of ours, I'll stick to the
short version that goes like this.

Last year I became hooked on a certain first-person shooter (FPS) game. After a couple months of
addictive online gaming, I became convinced that some players were cheating and things suddenly changed
that day. I was ready to walk away from the game in disgust and tell everyone else to do the same.
Instead, I decided it was time to learn what I could about the alleged cheaters, their motivations, and most
importantly their methods. In my case, I discovered at least three distinctly different methods of cheating
that could explain what I experienced -- though as just a player I could not prove conclusively which
methods, if any, were being used against me.

The aim of this article is to bring the subject of online/multiplayer cheating out of the shadows and talk
about it in terms of real problems with real games and to help build a framework for classifying and
understanding the various details. I will cover some of the ways that players are able to cheat at various
games; at times I will go into the working details, ways to prevent those cheats, and limitations of various
game architectures as they relate to multiplayer cheating. This is by no means a comprehensive and
exhaustive tome on the issue, but it is a start. There is a serious lack of information on this subject, and
paranoia among developers that talking about it will reveal secrets that will only make the problem
significantly worse. Several individuals at various companies declined to talk to me about cheating and their
games for this and other similar reasons. I respect that, but I think developers have everything to gain by
sharing our knowledge about cheaters and how to combat them.

Just how seriously should you as a developer take the possibility of online cheating? If your game is single-
player only, then you have nothing to worry about. But if your game is multiplayer only, the success of
your entire product is at stake. If your game does both, you're somewhere in the middle. As more games
are released with online play as an integral component, drawing ever-larger audiences (and the corollary
development of online communities and sites based around the game), it becomes ever more important to
insure that each online game player experiences what they believe to be a fair and honest experience. I'm
reminded of a quote from Greg Costikyan's excellent report, "The Future of Online Gaming"
(http://www.costik.com/): "An online game's success or failure is largely determined by how the players
are treated. In other words, the customer experience -- in this case, the player experience -- is the key
driver of online success." Our short version is, "Cheating undermines success."

Consider the well-known case of Blizzard's Diablo -- deservedly a runaway best-seller and great game that
acquired a significant reputation for a horrible multiplayer experience because of cheaters. Many people I
know either refused to play it online, or would only play over a LAN with trusted friends. Blizzard did their
best to respond, patching it multiple times, but they were fighting an uphill battle.

Cheating hit closer to home for me while I was working on the final stages of Age of Empires II: The Age of
Kings. Cheating online became a widespread problem with the original Age of Empires. Tournaments had to
be cancelled due to a lack of credibility, the number of online players fell, and the reputation of my company
took a direct hit from frustrated users. Unable to spare the resources to fix the game properly until after
Age of Kings was done, we just had to endure our users turning their anger upon us -- probably the most
personally painful thing I've experienced as a developer.

What about your next game? This is a good time to introduce my first two rules about online cheating:
Rule #1: If you build it, they will come -- to hack and cheat.

Rule #2: hacking attempts increase with the success of your game.

Need more reasons to take online cheating seriously? Go onto eBay and type in the name of your favorite
massively multiplayer game. Now look at the real money changing hands for virtual characters and items.
What if those items being sold were obtained via some sort of cheat or hack? Let's not overlook the
growth of tournaments and contests for online games. Consider the public relations nightmare that would
ensue if the winner of a cash prize in a tournament had cheated. Enough to give you a headache, eh?

Understanding the Hackers and Cheaters

The sad truth is that the Internet is full of people that love to ruin the online experiences of others. They get
off on it. A great many cheaters use hacks, trainers, bots, and whatnot in order to win games. But while
some openly try to wreak havoc, many really want to dominate and crush opponents, trying to make
other players think they are gods at the game -- not the cheaters they are. The only thing that seems to
bother them is getting caught. Beyond that, no ethical dilemmas seem to concern them. The anonymity
and artificiality of the Internet seems to encourage a moral vacuum where otherwise nice people often
behave in the worst possible way. A big factor in this is a lack of consequences. If a player is caught, so
what? Are they fined or punished? No. Are they rejected by the people they played against? Usually, but it's
so easy to establish another identity and return to play that discovery and banishment are no barrier to
those with ill intent.

Another interesting aspect of online cheating is the rise of clans and how cheats get propagated. If a
member of a clan hacks a game or obtains a not-readily-available program for cheating, it will often be
given to other members of the clan with the understanding that it's for clan use only and to be kept secret.
The purpose being, of course, to raise the standing and prestige of the clan. If the cheater is not a clan
member, odds are he will keep the secret to himself for a while and not advertise his advantage. The logic
here is simple: If anyone goes public with a cheat, a) he will lose his advantage, b) he will probably be
identified by his opponents as a cheater, and c) the developer can then patch the game, invalidating the
cheat. As a result of this secretive behavior we get to rule number three.

Rule #3: Cheaters actively try to keep developers from learning their cheats.

Tools of the Hackers

So how do they discover the hacks and create the programs to cheat at your game? Consider rule number
four:

Rule #4: Your game, along with everything on the cheater's computer, is not secure. The files are not
secure. Memory is not secure. Services and drivers are not secure.

That's right, you gave them a copy of your game when they purchased it. The hackers have access to the
same tools that you had while making the game. They have the compilers, dissemblers, debuggers, and
utilities that you have, and a few that you don't. And they are smart people - they are probably more
familiar with the Assembly output of an optimized C++ file than you are. The most popular tool among the
hackers I surveyed was NuMega's excellent debugger, SoftIce - definitely not a tool for the wimpy. On
another day, you just might be trying to hire these people. Many of them possess a true hacker ethic,
doing it just to prove it can be done, but more do it specifically to cheat. Either way we get the same
result: a compromised game and an advantage to the cheater.

Hacking games is nothing new, it's been going on as long there have been computer games. For single-
player games, it has never been an issue, since no matter what a player does with a game, he's only doing
it to himself (and therefore must be happy about it). What's new is bringing the results of the hacking to
other players, who never wanted or asked for it.
I've lost count of the number of developers I've encountered who thought that because something they
designed was complicated and nobody else had the documentation, it was secure from prying eyes and
hands. This is not true, as I learned the hard way. If you are skeptical, I invite you to look at the custom
graphics file format used in Age of Empires. Last year, I received a demanding e-mail from a kid who
wanted the file format for a utility he was writing. I told him to go away. Three days later he sent me the
file format documentation that he reverse-engineered, and asked if he missed anything. He hadn't. Thus,
this is a perfect example of rule number five. Yes, I've borrowed it from cryptography, but it applies equally
well here.

Rule #5: Obscurity is not security.

Sometimes we do things, such as leaving debug information in the game's executable, that make the
hacker's job easier. In the end, we cannot prevent most cheating. But we can make it tough. We don't
want effective cheating to be a matter of just patching six bytes in a file. Ideally we want hacking a game to
be so much work that it approaches the level of having to completely rewrite the game -- something that
goes outside the realm of any reasonableness on the hacker's part.

One of biggest things we often do that makes it easier for a hacker, and thus harder on us, is include Easter
eggs and cheat codes in the single-player portion of our games. Considered to be practically a requirement,
they expose extralegal capabilities of our game engines and make it much easier for the hackers to locate
the data and code that controls that functionality.

Models of Multiplayer Communications

Most online games use one of two communication models: client-server and peer-to-peer. For our
discussion, the deciding factor is where game event decisions are made. If only one player's (or a separate)
computer makes game event decisions or has the game simulation data, it is client-server. If all players'
computers make some or all of the game event decisions, or have the full game simulation, then it's peer-
to-peer. Many of the cheating methods described here are applicable to both models. I've organized the
various cheats, trainers, exploits, and hacks that I've learned about into the categories listed in Table 1.

Table 1. Cheating Oh Look, It's the Terminator...


classifications
The first type of cheat is reflex augmentation, which is when a computer program
Reflex replaces human reaction to produce superior results. This type of cheating is really
augmentation only applicable to games where reflexes and reaction times matter, and thus is most
applicable to action games.
Authoritative
clients During my FPS obsession, I believe that I encountered a form of reflex augmentation
known as an aiming proxy. An FPS aiming proxy works like this: The proxy program
Information is run on a networked computer and the player configures it with the address of the
exposure server they are going to play on. They then run the FPS game on another machine
and connect to the proxy machine, which in turn connects the game to the server,
Compromised acting just like an Internet packet router.
servers
The only hitch is that the proxy monitors and attempts to decode all of the packets it
Bugs and design is routing. The program keeps track of the movements and locations of all the
loopholes players the server is reporting to the game, building a simple model. When the proxy
sees a Fire Weapon command packet issued by the cheating player, it checks the
Environmental locations and directions of all the players it is currently tracking and picks a target
weaknesses from them. It then inserts a Move/Rotate command packet into the stream going to
the server in front of (or into) the Fire Weapon command packet that points the
player straight at the selected target. And there you have it: perfect aim without all the mouse twisting.

When aiming proxies for Quake first appeared a couple of years ago, their targeting wasn't too
sophisticated and didn't take into account things such as the player's field-of-view (FOV) or lag. Giveaways,
such as players shooting weapons out of their backs, tipped people off that something foul was afoot. One
of the first countermeasures to be developed was a server add-on that statistically identified players whose
aim was too good to be true, then kicked out and banned the perpetrators. This naturally proved
controversial, since some people really are "railgun gods," and the issue of possibly falsely identifying a
person as a cheater was raised (and has yet to go away). And of course, the aiming proxies evolved with
time. Later versions were improved to consider only the player's current FOV and compensate for lag, and
added just enough randomness in their aim to stay below a server's "too good to be legit" identification
threshold.

This big vulnerability is summed up in rule number six. Since the proxy is not running on the same computer
as the game client, definitive detection can be next to impossible. Making the development of the proxy
extremely difficult then becomes a priority.

Rule #6: Any communication over an open line is vulnerable to interception, analysis, and modification.

One way to inhibit this form of cheating is to encrypt the command packets so that the proxies can't
decode them. But there are limits to the extent that encryption can be used on communications. Most FPS
games can send and receive a couple of kilobytes of data or more per player per second, and have to allow
for lost and out-of-order packets. The encryption therefore has to be fast enough not to impact frame
rate, and a given packet's encryption can not be dependent on any other packet unless guaranteed delivery
is used. And once the encryption is cracked, the game is vulnerable until the encryption is revised, which
usually involves issuing a patch. Then the hacking starts over.

Another way to make life more difficult for the proxy creator is to make the command syntax dynamic.
Using something as simple as a seed number that's given to the game when it connects and a custom
random number function, the actual opcodes used in the communication packets can be changed from
game to game, or even more often. The seed itself doesn't have to be transmitted; it could be derived
from some aspect of the current game itself. The idea here is that since a proxy sees all the
communications, but only the communications, the random seed is derived from something not explicitly
communicated. Foolproof? No. But it's far more difficult to hack, forcing the hackers to start from scratch.

If guaranteed delivery is used, another communications protection technique is to serialize each packet.
Taking it a bit further, you could make a portion of the next serial number dependent on a checksum of the
last packet. While there are speed issues with the delivery, it's an excellent way to make it difficult to insert
or modify packets.

Though reflex augmentation seems to be exclusive to FPS games, the vulnerability extends to any game
where quick reflexes can make a difference and game communications can be sniffed.

The Client Is Always Right

The next major class of cheats is exploiting authoritative clients. This is when one player's modified copy of
an online game tells all the other players that a definitive game event has occurred. Examples of the
communications would be "player 1 hit player 2 with the death-look spell for 200 points of damage,"
"player 2 has 10,000 hit points," and so on. The other players' games accept these as fact without
challenging them and update their copy of the game simulation accordingly.

In this case, a hacked client can be created in many ways: The executables can be patched to behave
differently, the game data files can be modified to change the game properties on the hacked client, or the
network communication packets can be compromised. In any case, the result is the same - the game
sends modified commands to the other players who blindly accept them. Games are especially vulnerable
to this type of exploit when they are based on a single-player game engine that has been extended to
support online multiplay in the most direct (read: quickest to develop) manner.

Fortunately there are several steps that a game developer can take to eliminate most problems with
authoritative clients. A first step is to install a mechanism in the game that verifies that each player is using
the same program and data files. This means going out and computing a CRC or similar identifier for all the
data in question, not just relying on a value stored in the file or the file size. A nice side benefit is that this
method also detects out-of-date files during the development process.

For peer-to-peer games, cheating can be made difficult by changing from a game engine that issues
commands to one that issues command requests. It's a subtle distinction but one that requires engineering
changes throughout the game. It also requires that each player's machine run a full copy of the game
simulation, operating in lockstep with the other players.

Command processing in a single-player game typically works in the manner shown in Figure 1. The player
issues some sort of command via the game's user interface. The game then performs a validation check on
the command to see if the player has the resource, the move is legal, and so on. The game then performs
the command and updates its internal game simulation. Figure 2 shows game engine command processing
extended to support multiple players in the most direct way possible. The process stays the same except
for the addition of a communications packet that's sent out to inform the other players of what has taken
place. The receiving players integrate the data directly into their world simulation.

Figure 1. Single-player-game command


processing steps.
Figure 2. Single-player-game command
processing extended to support multiplayer
operation.

With the shift to command requests, the order of events changes a bit, which is shown in Figure 3. After
determining that the command is a legal one, a command request describing the command is sent out to
other players and is also placed into the player's own internal command queue, which contains command
requests from other players as well as his own requests. Then the game engine pulls command requests
from the queue and performs another validation check, rejecting the request if it fails. The fundamental
difference is that every player has a chance to reject every action in the game based solely on the
information on that player's machine. No other machine provides the information to make the
determination on what is right and wrong. A hacked game cannot reach out and alter what's on an honest
player's machine with this approach. Note that such an architecture works equally well for a single-player
game.

Figure 3. Command processing steps when


using command requests.

Preventing a dishonest command from being accepted on an honest player's machine is only half the task.
The game also has to be able to determine whether someone is playing the same game and if not, it must
do something about it. For instance, when a received command request is rejected for reasons that should
have prevented it from being issued in the first place (remember, the issuer is supposed to have checked it
for validity before passing it to the other players), all other players should assume that a cheater is in their
midst, and take some sort of action.

Often though, due to design issues (such as posting command requests to a future turn), it is not possible
to thoroughly ensure that all command requests passed to other players won't be rejected if a player is
being honest. A good way to deal with this is to add synchronization checking to the game. At various
points during the game, each player's machine creates a status summary of the entire game simulation on
that computer. The status, in the form of a series of flags, CRCs, and checksums, is then sent to all the
other players for comparison. All the status summaries should be the same, provided the game program
and data files are the same for each machine. If it turns out that one player has a different status from all
the rest, the game can take action (like drop the player from the game). The idea is that a hacked game
should cause that player's game simulation to produce different results.

Alternatively, you can make life even more difficult for the hacker by easing up on the received command
request evaluations. By allowing command requests to bypass the verification check only on the machine
that issued it, you're deliberately allowing the game to go out of synch if the initial verification check or data
has been hacked. Combine this with a synchronization check that occurs somewhat infrequently and you've
presented the hacker with something of a mystery -- on his machine the cheat worked, but then a while
later the other players booted him out of the game.

This status synchronization has a huge benefit for the development process as well. Getting a complicated
game engine to produce the same game simulations results while having different player views, inputs, and
settings is a very difficult task. It's difficult to keep the simulation-independent code from accidentally
impacting the simulation. For example, a compare against the current player number variable in the
simulation code, or randomly playing a background sound based on an object in the player's view using the
same random function used by the simulation, could cause future executions to produce different results on
different machines. Judicious use of status synchronization allows a developer to quickly narrow down the
portion of the game that isn't executing the same for all players.

Client-server games unfortunately can't benefit as much from these techniques, as they lack full game
information and by design must rely on the authority of the server. We will look at this more a bit later.

The Game Emperor's New Clothes

The next major class of cheats is what I've dubbed "information exposure." The principle is simple: On a
compromised client, the player is given access or visibility to hidden information. The fundamental difference
between this and authoritative clients is that information exposure does not alter communications with the
other players. Any commands sent by the cheater are normal game commands - the difference is that the
cheater acts upon superior information.

The first-person-shooter cheats of modified maps and models arguably fall under this classification, as they
let cheating players see things that they normally wouldn't be able to (in the case of modified maps), or see
them more easily (in the case of a modified player model that glows in the dark). Any game whose game
play relies on some information being hidden from a player has a lot to lose to these types of cheats.

The real-time strategy (RTS) genre suffers severely from this. The most obvious being hacks that remove
the "fog of war" and "unexplored map" areas from the display. With a fully visible map, the cheating player
can watch what other players are planning and head them off at the pass, so to speak.

There are a couple of ways the hacker accomplishes this. The hacker may go after the variables that
control the display characteristics of the map. With the help of a good debugger and single-player cheat
codes to reveal the whole map, finding the locations in memory that control the map display is fairly simple.
Then either the game .EXE file is modified to initialize those map control values differently, or a program is
made that attaches to the game's memory space and modifies the variable values while the game is
running. To combat this, the values of those variables should be regularly reported to other players in the
form of a checksum or CRC code. Unfortunately, that only raises the stakes; the hackers then just attack
the code that reads those control values (easy enough to find quickly), inverting or NOP'ing out the
instructions that act upon them.

Additional techniques are needed to detect the hacked game view. There are a couple of ways to take
advantage of the fact that the full game simulation is run on all clients. One way is to borrow a technique
from the "authoritative client" section and check each command request for the side effects of a hacked
map on one of the players. We specifically ask the game simulation, which is separate from the screen
display, the question, "Can that player see the object he just clicked on?" In doing this we are assuming
ahead of time that such hacks will be attempted, making sure we consider the side effects by which they
might be detected. Once again, easing up on checks of the player's own machine is very useful. The next
time the game performs a synchronization check, all the other players will agree that the cheating client is
"out of synch" with the rest of the game and can deal with him accordingly.

Another technique that avoids looking at the display control variables is to compile abstract statistics on
what gets drawn to the screen. The statistics are derived from the game simulation data and just filed
away. This doesn't immediately prevent the hacker from cheating; instead, you send the statistics around
as part of the status synchronization and see what the other players think of them.

In the RTS map-hack case, it is necessary for some change to be made to the game; either the code or
some data is in a modified state while the game is running. And if something has been modified, you can
attempt to detect that.

But information exposure cheats can be totally passive. Consider a scenario where a program gains access
to the memory space of an RTS game that is running. It then reads key values for each player in the game
out of memory and sends them to an adjacent networked computer. An industrious hacker once raised
that scenario with me regarding one of the Age of Empires games, saying he had figured out how to read
out of memory the resource amounts for every player. At first we thought that this wasn't very serious. He
then explained that if he polled the values a couple hundred times a second, he could identify nearly every
discrete transaction. A simple Visual Basic program could then display a log window for each player, with
messages for events such as the training of various units (to the extent they could be distinguished from
others on the basis of cost), and messages for events such as building construction, tribute, and
advancement to the next age. Basically, this cheating method was the next best thing to looking over the
shoulders of his opponents.

Rule #7: There is no such thing as a harmless cheat or exploit. Cheaters are incredibly inventive at figuring
out how to get the most out of any loophole or exploit.

Intrigued, I asked him how he could be sure he had found the correct memory locations each time, as they
changed each game since they were stored in dynamically allocated classes. His answer was most
interesting. He first scanned the memory space of a paused game looking for known values for things such
as population, wood, gold, and other very significant game values that he knew about and believed were
unique. He had a simple custom program that looked for the values in basic formats such as long ints and
floats. After his program identified all the possible addresses with those values, he ran the game a bit more
until the values had changed. He then reran the program, checking the prior list of locations for the new
values, reducing the list of possible addresses until he was sure he had found the correct locations. He then
put a read-access breakpoint on the value and looked at how it was accessed from various points in the
code. At one of the breakpoints, the C++ code for accessing the wood amount looked something like this:

GAME_MASTER -> GAME_WORLD->PLAYER[n].


ResourceAmount[Wood_Index];

This is a pointer to a pointer to an object containing an array of integers, one of which contains the value of
the player's current stockpile of wood, and all the objects are dynamically allocated. The hacker's point was
that if you trace back through all the dynamic pointers, you eventually find a static variable or base pointer.
The different spots where his breakpoints were triggered were from member functions at different levels in
the class hierarchy, and even from outside the class hierarchy containing the data. And it was finding an
instance of that latter access condition that was the jackpot. There it was in his debugger's disassembly
window: a base address and the Assembly code to traverse through the classes and handle player and
resource index numbers.

Considering all this, I found a couple of strategies that can greatly reduce the likelihood of this sort of
passive attack. Again, these tips cannot guarantee 100 percent security, but they make the hacker's job
much harder.

The first strategy is to encrypt very significant values in memory at all times. Upon consideration, most
game variables are not significant enough to warrant such protection - the hit points of a particular object
don't tell anyone much, while a drop of 1,000 food and 800 gold from a player's resources does indicate
that the player is advancing to the Imperial Age, which is an event of large strategic importance in our
game. Simple encryption is relatively easy when all access to the variables goes through assessor functions.
A communicative function such as XOR is your friend here, as it alters values upon storing, restores them
upon reading, and is extremely fast. The whole point is to make it very hard for the hacker to find the
variables he is searching for in the first place. Values the hacker would know to look for are not left around
so that a simple scan can find them. In C++, our encrypted assessor functions for game resources look
something like what's shown in Listing 1.

The second strategy for slowing down passive attacks is to never access very significant values from
outside the class hierarchy. Assuming the values are located while using the debugger, try not to access
them in a way that starts with a reliably fixed memory address. Combining this with small, randomly sized
spacing buffer allocations during the main game setup ensures that the memory addresses for vital
information will never be the same from one game to the next. A piece of C++ code you won't see in our
next RTS game would be the following:

GLOBAL_GAME_POINTER -> PLAYER_DATA[n] -> RESOURCE_TABLE[gold] =


SOME_UNIQUE_START_VALUE;

Information access isn't limited to games as complex as RTS games, it can extend to something as simple
as a card game. Consider an online card game such as poker. All it would take to ruin the game is for a
player to see the values of the face-down cards in another player's hand. If the information is on the
machine, hackers can go digging for it. This goes back to rule number four.

Who Do You Trust Baby?

In client-server games, because so much is controlled by the server, the game is only as good as the trust
placed in the server and those who run it.

Rule #8: Trust in the server is everything in a client-server game.

An issue here is brought up because some client-server games can be customized by the user running the
server. Access and configurability are great for many games, as they allow the player community to extend
and evolve a game. But some individuals will test the server to see what can be exploited in the name of
cheating. This in itself is not the problem -- rather it's when honest but unaware players find their way to
the server and don't know that they are not on a level playing field.

You really need to consider your audience here. A successful game will sell hundreds of thousands of copies,
if not millions. You as a developer will be most in tune with the hard-core players -- those that know the
game inside and out. But it's easy to forget about the more casual players, who probably will be the
majority of purchasers of your game once you pass a certain level of success. These are the people who
don't know to check the status of the Cheats_Allowed flag before joining a server, or that game rule
changes are transparently downloaded when they connect. All they probably know is the default game
configuration, and when they see their ReallyBFG27K gun doing only 0.5 points of damage, they're going to
cry foul. It doesn't matter that it was technically legal for the server operator to make the change, you still
wind up with a user that is soured on the game and not likely to recommend it to his buddies anymore.

Naturally, people get a whole lot more unhappy with a game when they encounter modifications with
malicious intent. What if a clan decided to add a tiny server mod to their FPS server that looked something
like this snippet of C code:

If Player.Name->Contains("OUR_CLAN") Taken_Damage = Taken_Damage * 0.80;

Or what if the remote console was hacked to allow normal cheats to be toggled? Dishonest players in with
the server could make a key-bind that resembled this:

Access_password on; set Cheats_Allowed true; Give Big_Ass_Weapon; Give Big_Ass_Ammo; Set
Cheats_Allowed false; Access_Password off;

The important point here is that with user-run servers and powerfully configurable game engines, these
kinds of shenanigans will happen. While we as developers can't protect our more casual users from joining
any game server they wish, we can do a better job of letting them know when they are encountering
something that could be different from what they expect. Quake 3: Arena set a great example when it
introduced the concept of a "pure" server. It's a simple idea that casual users can quickly grasp and set
their gaming expectations by.

But why stop there? If we download data that includes a new set of weapon properties, why not put a
message on the screen saying, "Weapon properties modified"? If single-player cheat commands are issued
in the middle of a game, maybe we should send a message to every client notifying them of that fact, so
even players who aren't near the issuer can be made aware. Empower players to easily determine whether
the games are fair or not.

Rule #9: Honest players would love for a game to tip them off to possible cheating. Cheaters want the
opposite.

Bugs & Design Issues

Technically, this category of cheats is one that we bring upon ourselves: bugs in our games can be
discovered by users and used to disrupt game play. Most bugs don't enable cheating, but a few do.

A good example is the farm-stopping bug in the unpatched version of Age of Empires. When a user had
both a villager and a farm selected, he could issue the Stop command. Because the command was valid for
a villager, it was allowed to go through, but listed both objects as the target of the command. The villager
would stop working as expected and reset its state. The farm would also reset itself, something it never did
normally, and replenish its food supply. Once this was discovered by players, it drastically changed the
game for them, giving them a huge advantage over those who didn't know about it.

I encountered another bug when playing Half-Life. I would get into a firefight with another player, both of us
using the same weapon, but when it came time to reload our weapons, my opponent was able to reload
much more quickly than I could. Sure enough, when the next patch came out, I saw in the release notes
that a bug allowing fast reloads was fixed. There's really not much we can do about these types of bugs,
other than fix them with a patch.

Environmental Weaknesses

My last category of cheats is something of a catchall for exploitable problems a game may have on
particular hardware or operating conditions. A good example is the "construction-cancelled" bug that was
found amazingly in both Age of Empires and Starcraft at about the same time. The element needed to
make it work was extreme lag in network communications, to the point of a momentary disconnection.
When this happened, the game engines stopped advancing to the next game turn while they waited for
communications to resume. During this time, the user interface still functioned, so the player didn't think the
game had locked up. While the game was in this state, a player could issue a command to cancel
construction of a building, returning its resources to the player's inventory - only the player would issue the
command over and over as many times as possible. Normally, a player could only issue one Cancel
command per turn, but because the game simulation was in a holding state, multiple command requests
went into the queue. Because of some necessities of RTS engine design, when an object is destroyed during
a turn by something such as a Cancel command, the destruction is postponed until after all the commands
for that turn have been processed. The result was the command executed multiple times during one game
update.

Once discovered, this had a horrible impact on online games. People deliberately caused massive lags to
take advantage of the cheat. To fix it in Age of Empires, we had to update the validation checks to see if a
similar request was already pending on the current turn and reject duplicates.

Another bug of this type involved the game Firestorm and its interaction with the Windows clipboard. It
seems a clever user found out that if he pasted text from the clipboard into his chats and that text
contained a certain character not normally used, the game would crash when it attempted to print it to the
screen -- on all player's machines. He then treated this knowledge as a personal nuclear bomb that he
could spring on people when he found himself losing.

Yet another example taken from Age of Empires is what happens when a player's network connection is
overloaded or ping-flooded by another player. When such an attack renders a game unable to
communicate with its peers, the other players decide that something is wrong with that player and drop
him from the game- - a totally necessary capability, but one that can be exploited in a modern twist on
scattering all the pieces on a game board when you are losing. This was one the major reasons we added
Multiplayer Save and Restore capabilities to Age of Empires II.

Some Final Thoughts

I hope these examples got you thinking about some of the problems and issues at stake when developers
address the problem of online cheating. We certainly have a lot more ground to cover, from massively
multiplayer games, open source, and consoles, to enabling the online communities to better police the
situation. But we're out of space and time for now.

Listing 1. Hiding the variables that tip off hackers to possible cheats.

void GameResource::SetResource(int Resource_Num, int Resource_Amount)


{
GameResourceAmount[ResourceNum] = Resource_Amount ^ EncryptValue[ResourceNum];
}
int GameResouce::GetResource(int Resource_Num)
{
return( GameResourceAmount[ResourceNum] ^ EncryptValue[ResourceNum] );
}
//and more specific functions...
void GameResource::SetWood(int Wood_Amount)
{
GameResourceAmount[RESOURCE_WOOD] = Wood_Amount ^ EncryptValue[RESOURCE_WOOD];
}
int GameResource::GetWood(void)
{
return( GameResourceAmount[RESOURCE_WOOD] ^ EncryptValue[RESOURCE_WOOD] );
}

Matt Pritchard is busy trying to be a modern renaissance man. When not working hard on his
latest game, he can be found spending time with his family or collecting antique videogames. Send
e-mail to mpritchard@ensemblestudios.com.

Copyright © 2003 CMP Media Inc. All rights reserved.


There are different methods of program
protection against unauthorized
distribution, but every protection can
b e somehow broken. Sometimes it is
just a matter of time, but time plays
also an important role for companies
launching new software on market.
Certainly it is not a success to find out
that an installation CD with a game,
that suppose not to be freeware, is just
couple of days after its release wide
burned among computer people and a
needed crack is easy obtainable form
the Internet.

In duel programmer vs. cracker, a


cracker is the winner in most cases and
it happens because the majority of
programmers and software companies
is not aware of programming
equipment of other programmers and
how big their efforts to break different
keys, to bypass protection of a original
CD, time and other limitations of paid
software are. And while crackers
accumulate their know-how at
numerous web servers, possibly in the
whole world there is no source that
describes the whole AntiCracking
software protection. There are no
doubts that development of a complex
software protection requires huge
amount of knowledge, programming
skills and talents. We hope that in this
part a programmer finds all he was
missing in development of a superior
software protection.

Basics

Before you can protect your software


well, you must first understand the
methods crackers use to crack your
software. Crackers are the people who
try to remove the protection from your
software so that it may be illegally
distributed. The first mistake
developers often make is in
underestimating the power and number
o f crackers; and that’s the worst
mistake any developer of protection
c a n make. Mostly, crackers are very
smart people who will work on
software protection removal for days
at a time, and in extreme cases even for
weeks, for the challenge of it. The
cracker’s success almost always
depends on their motivation.

How Crackers Crack: Debuggers


and Disassemblers

Protection developers often presume


that without source code crackers will
not be able to understand their
software’s protection. This is a huge
mistake. Crackers use two kinds of
utilities for breaking software
protection – debuggers and
disassemblers.

Debuggers
Debuggers allow crackers to trace an
application, instruction by instruction,
and to stop it at any point and trace its
important sections. It is true that
applications written in higher level
languages (like C++, Visual Basic, or
Delphi) may be traced only in
Assembler, but crackers understand
what is happening in the application
code amazingly well – probably better
than most people can imagine. The
truth is, the higher the level the
programming language is, the more
difficult it is to trace, but on the other
hand they offer fewer possibilities for
creating really good protection.
Everything has its bright and dark
sides.

Disassemblers
Disassemblers or decompilers can
translate an application code back into
Assembler, no matter in which
language the application was originally
written. Decompilers translate only
applications written in those languages
for which the particular decompiler
was created. There are, for example,
decompilers for Delphi, Visual Basic
and Java. If the decompiler is really
good it can translate the application
very well. Once an application is
translated it’s easy for the cracker (if
he knows the particular language) to
find sections of interest to him and to
determine how they work. One
advantage that disassemblers offer
over decompilers is that they always
translate into Assembler so the cracker
has to know only that one language.
The resulting translated code depends
on the quality of the disassembler or
decompiler. The best decompilers
even comment on the translated code,
which makes the code that much easier
to understand. For example, if the
cracker finds a ”Wrong serial number”
string and locates its place in the code,
he will be able to find the part of the
code that protects the application. At
t ha t point, nothing can prevent him
from studying the protection and
breaking it.

It’s better to use weaker protection


code than none at all, but you will not
stop the better cracker. Final tuning of
your protection scheme is the most
important part of any protection
strategy. The programmer should then
change into a cracker for a while and,
using the crackers’ programs, he
should test if he has forgotten anything.

Cracking Tools

If you don’t know your enemy’s


weapons you cannot defeat him. Let’s
now talk about the programs most
commonly used by crackers.

SoftIce is one of the best debuggers in


the DOS environment. You will not
find anything better for Windows 9x
and NT. Many crackers therefore say
that NUMEGA (the producer of
SoftICE) is their favorite company.
Since SoftICE is probably the best
debugger we will use it too.
TRW2000 is a debugger for Win9x. It
isn’t as good as SoftICE but its price is
acceptable considering the high
qua l i ty. You’ll find a shareware
versions online.
WinDasm with the IDA is the best
disassembler in the Windows
environment. Compared to IDA,
WinDasm’s disassembled code is
shorter and easier to understand. It’s a
great loss that, unlike IDA, WinDasm
is no longer in development.
SmartCheck is an IDE tune-up tool for
programs written in Visual Basic, is
better then SoftICE for disassembling
Visual Basic applications.
IDA Pro (Interactive DisAssembler
Pro) is a wonderful disassembler for
DOS and Windows programs. It is not
a static disassembler like WinDasm
and it even lets you manage the
translation manually. (A great feature
to have when a program that you want
to study uses various tricks to protect it
from disassembly.) IDA has many
other great features.
Sourcer is a wonderful disassembler
for DOS programs but it is not widely
used for Windows.
Hex Workshop is a HEX editor for
Windows environment.
Hacker’s View is probably the best
HEX editor for the DOS environment.

Anti-Debugging, Anti-Disassembling
and Other Tricks To Improve
Protection

Few programmers realize how


important it is to prevent debugging or
disassembling of their software. This
i s essential for the protection itself,
since if it’s possible to debug a
program it is also possible to easily
understand how the protection works.
Even the simplest anti-debugging tricks
may complicate debugging, and anti-
disassembling macros will make the
debugged code harder to understand.
When well-executed, both make it
much more difficult to remove even the
simplest protection.
We’ve had a look at the compression
and encoding programs that many
programmers rely on to do the “dirty”
work of software protection for them.
These programs alone though are really
no solution, however, since it is only a
matter of time until a new decoder
becomes available and for the better
crackers to remove the encoding
programs themselves, thus leaving the
application with no protection against
debugging.
Anti-debugging and anti-disassembling
tricks aren’t hard to use. It is then very
important to carefully test the protected
application. At this writing there are
only a few anti-debugging tricks for
Windows NT and Windows 2000
because their internal structure differs
from that of Windows 9x. The program
may test which operating system it is
running under and then it decide which
trick to use. Anti-disassembling tricks,
on the other hand, work without such
problems, and it is therefore advisable
to use them as much as possible.
Most of the example programs have
been written in Assembler. Though
some may be programmed in a higher
programming language it’s not a good
idea to do so. While not every
programmer knows Assembler, most
higher level languages let you insert
code in Assembler. Of course, there
are applications that won’t let you do
so which makes it much more difficult
to work with this code, so in such
cases it’s best to insert the anti-
debugging tricks into a separate DLL
library, and then to call its functions
from the protected application. Still,
this is not an ideal solution because a
cracker will be able to remove such
protection quickly and easily.
Our advice to those of you who don’t
know how to work in Assembler is to
learn it. Even though many people
claim that it is a “dead” language, there
are still fields where it is necessary,
a n d programming good software
protection is one of them. The most
important part of programming good
software protection is tunin, which and
this may be done well only in
Assembler. When tuning your code you
will discover the small cracks that
make software protection conquerable
and removable.
Protection Tips and Trics

Detect tracer
here
old times

More or less from the old school -


by reading the current time and
comparing it to an value read some
instructions afterwards.

Detect tracer via overflow here

Enabling the overflow bit in eflags and check it by "into". This causes overflow
exception (interrupt 4 redirected to own handler).

Detect tracer 2 here

Another nice idea.

Detect tracer with API here

... improved only the tracer to handle api calls.

Detect tracer here

It is a nice program I wrote it up to show you that it is pretty simple to detect if


someone is tracing your program (the program is tracing itself).

Ring0 here

About switching programs from Ring3 to Ring0.


Windows detection here

Small routine for detection the type of Windows (useful for anti-debugg tricks).

Are anti-debug tricks important? here

Short article about anti-debug tricks pluses and minuses.

How works with debug breakpoints? here

Article about debug breakpoints.

Debug breakpoints example here

Example of working with breakpoints.

Crypto++ v4.0 here

Very good C++ Class Library of Cryptographic Primitives.

StopIce here

Very simple anti-debug trick for Delphi coders.

CRC32 here

DLL library for calculating CRC32 of any file.

CD-Check here

Example of CD-Check.
© 2001 AntiCracking. All Rights Reserved.
Protecting your programs from piracy
INTRODUCTION
At one Web site I’ve seen a curious discourse, whether your programs should be furnished with anti-pirate devices. It went
like this: No one has a right to enter your house without your consent. The inviolability of your house is protected by law.
Nevertheless, you prefer to have a lock in your front door. Further proceeding with this comparison, we’d have to admit
that after putting a lock on the door many software authors leave their keys at the front door or they lock a wrong door at
all.

Here are some initial remarks.

This article is intended for those software developers who do not professionally engage in issues of protection from
any unauthorized usage. It’s aimed at pointing out the most typical mistakes and helping to create more
impregnable software.

Discussed here are the issues of creation of shareware and trial versions for Windows’95 (and Windows NT, if stated
so). Leaving specific examples aside we can say that everything that is mentioned below is true for other platforms,
too.

This article does not claim to cover the problem in its entirety.

You can contact the author at vitas@ webdon.com. Even if you don’t have any specific suggestions or notices just
send in your opinions about this article. This article may be continued in future, so please give us your opinion about
this, too.

There exists an opinion that hackers are unique specialists and they can be fought only by specialists like them, yet an
ordinary software developer is unable to do it and he shouldn’t even try to. Therefore you shouldn’t try to protect a
program from a break-in, because it wouldn’t save from a hacker and you should only create a simple fool-proof
protection. Meanwhile, as unexpected as it may sound, a typical hacker is not in any way an able specialist; he cracks
programs because he is unable to do anything else (a proverb «It’s easier to break than to build?is true to life!). If you
weren’t seriously into illegal copy protection (don’t waste your time if you were – in this case, this article is not intended for
you) then you are going to discover a number a number of simple, logical and very efficient ways of increasing your
programs’ reliability upon reading this article (at least, I hope so). Well, of course, there are skilled professionals among
hackers, and they could do a lot. The methods which are described here would not stop them. Nevertheless, if reading this
article helps you to improve your program in a few hours well enough to repel a lot of pitiful hackers – it is not so bad, is it?

SHAREWARE programs.
There are two big problems concerning unauthorized copy protection of shareware programs. The first one is how to
prevent a hacker from turning a shareware version into a complete registered one. The second one is a copy protection of
a registered program, that is how to arrange that only the legal owner could use a registered copy. This second problem is
going to be touched upon in the end of this article as it requires a greater separate discussion.

Ways to create a shareware product.

When offering a shareware version of his program an author pursues two goals. On one hand, he wants to get a
potential user interested therefore a program should demonstrate all of its options and be as convenient as possible.
On the other hand he wants to make a user pay for the program. The folowing methods are the most popular ones
for creating shareware programs.

A demo program.
A potential user is receiving an «inferior?program with some options completely missing, Having tried it, he’s buying a normal
version in a usual way. The determining fact here is that there is no way even in theory to turn a demo version into a complete
program. I’m mentioning this choice here, yet I’m not going to discuss it. Sometimes demo versions are made via introduction of
some limitations in a complete version whereas a theoretical possibility to do away with these limitations remains. Let’s
have a look at two examples. A phone directory demo version contains phone numbers from just one phone station.
No hacker can ever turn this demo program to a full-scale phone directory. Another example is a demo version of a
graphics editor, which won’t allow you to open images greater than any predefined size. It is very probable that a
hacker may quickly remove this limitation. The difference between these two examples is that a phone directory has
a part which is totally missing from it. On the contrary, in the second example there is a removable «extra part?

Incomplete functionality
A shareware version does not include some useful functions which only appear after the registration. It’s very
important to determine what functions are going to be inaccessible during the trial period. At the present time the
software market is extremely satiated. For most of the programs there exists an alternative by a competitor. So, if
you deprive a user of many useful functions he may not want to try your program any further and buy it. It is well
known that, when meeting a new person, one’s attitude to him (or her) is formed during the very first seconds of
the acquaintance. The same thing happens to items and programs – it is very important that your program
impresses a user as much as possible. Therefore, the missing functions must be useful but not essential for the first
acquaintance with the program. Moreover, these functions must be evident and intuitive, that is, a user should
clearly see what exactly is going to be at his disposal after the registration and how convenient his work is going to
be. During the trial period a user should get used to your program, get familiar with it and want to use its at its full
power and at any time. Therefore a choice of options to be removed for the trial period is very important.

2. Date of usage and launch count limitations.


It’s a very popular method of protection. It does not have a drawback of a previous method – as soon as at a time of
trial your program is going to be presented at its best for the user. This method is accepted in beta versions of many
programs to limit the time of their usage (testing). Even the well-known Microsoft corp. uses this way of testing.

3. Annoying behavior.
During the trial period a program does something to annoy a user but not to prevent the usage of all options of the
program. Usually it is a reminder about a necessity of the registration. A good example is a popular WinZip program which
recommends to register itself after every launch. This variant differs from the first one by the necessity to «add?
something in case #1 and the necessity to «remove?something in case #3. It is evident that the third method is
outperformed from the point of view of reliability.

4. Registration info.
This option is intended for honest people – a program would just inform them that it is not registered yet or who it is
registered for (on-screen, in a demo or in an About box). This way of protection is present almost in any program, but
usually it is not the only one.

5. Upgrade.
A new version of a program should allow using itself only if a previous version of this program is already installed.

Program registration.

How a program is being registered? Of course there exists an option that, upon paying for the program, a user will receive
a new (or complete) version in a glossy box bundled with complete documentation, possibly delivered by a parcel service.
In this case we’ll have to speak about a demo program which is followed by a purchase of a complete version, yet we
have decided not to discuss this case. Another drawback of this method is that a user does not receive a result
immediately following a money transaction (for example, paying on-line with a credit card), having to wait for it several
days (at best). Moreover, an Internet program distribution without traditional boxes, floppies and manuals allows to cut
expenses down and to increase efficiency, which is so important for various utilities and other inexpensive programs. Upon
a registration a user is naturally supposed to receive something that can turn a program into a registered one from a
program manufacturer. Ususally this something is a registration number, but let us understand it widely – it does not have
to be a number, it is a piece of information given to a user by a program distributor. Given a chance, you should make this
number readable and not too long. Consider, for example, entering such a registration code:
04846718351B3E6B3D717E240A200A29556B7C18347A1162526F5CThis real-life example (well, maybe almost real-life :-) ) is a
registration number from a program named GoldEd. You should make it more readable, that is, use only digits and
separate groups of digits with optional separators, like this: 214-527-822-655-121. If a program is registered on-line then a
problem sorts itself out because a registration process can be automated.

Ways of cracking and ways of protection.


Most of shareware programs can be cracked so easily mostly because their authors cannot imagine what methods are use
by hackers for cracking. Below we are going to discuss the simplest and the most frequently used ways of program
cracking and ways of protection.

Cracking programs with date limitation or launch count limitation.

In case of limitations that are imposed on period of program usage or times a program had been launched some specific
cracking methods become available not only for hacker, but for smart users, too. One of the ways to cheat a protection
goes like this: before installing the program it is necessary to set a date several years ahead, for example, at 12.31.2017.
Let’s say your program only works during two weeks after having been installed. Then it’s protection system would decide
the program is supposed to work till 01.14.2018. Having installed the program, a user reverts to a correct date and uses
your program till the end of the world. How could one counter such a method?

The first palliative is to check a current date and, if it is too big (say, more than six months since program release),
suggest to use a newer version. A more radical way is to check a current date every time a program is being launched. If,
suddenly, it turns out that a current date is lesser than the installation date, then… At this point you may be tempted to
display a message which accuses the user of cheating and maybe even to uninstall a program. DON’T DO IT! The user’s
system might just have a time failure. Alas, if a time failure did happen, your program will stop working short of its time.
This is a rule of thumb – increasing protection reliability leads to increasing your program’s discrimination. A program can be
made to behave a bit smarter – if system time is lesser than the program release time then the system clock has really
failed, because when a failure occurs a date is often set to 1.1.1980. In this case you can suggest a user to correct the
system clock.

The second way of cracking lies in setting a wrong date at the runtime and restoring a correct date afterwards. Of course,
this way is a bit awkward, but, unfortunately, there are programs which help to automate this process. It is extremely hard
to counter this method. You can try the following ways to do it.

It is a radical way which can be afforded only by developers of Internet-based programs. Since a user is supposed
to work online, your program can get a current date and time from a server that provides with exact time and date;
there is quite a lot of them now. At the same time your program can do a good service by synchronizing the
system’s time and date if they are set incorrectly.

Unfortunately, this way is acceptable for very few programs. It can be slightly modified; if a computer works in a
local network, a date can be obtained from a server or from other computers.

If this way is unacceptable, either, we have to admit that without leaving the bounds of a computer, there is no way
your program can find out what date it is. Yet, a fact of altering a date still can be detected. Many programs, for
example, record their relevant information into the Registry. For this reason, the registry modification date usually
matches the current date. When Windows is started, the system creates backup copies for the files
c:\windows\system.da0 and c:\windows\user.da0 (these files are marked as the hidden ones).
You can check the date of their last modification and, if it turns out to be greater than the current one, then a user must
have set the clock to an earlier date. It is important to check the backup Registry files because the current registry files
may already have been modified and therefore their modification date may match the current wrong date. Evidently you
can not only check the Registry files like this, you can also verify your own data files. Here’s how a real current date may
be obtained: as you may or may not know, Windows’ 95 not only stores the creation date/time for each file, it also stores
the time and date of its last access. As a true current date you can consider the last access time of a file which is always
launched or opened once when Windows start up. Autoexec.bat or windows\system\vmm32.vxd may serve as examples of
such files.

The third and the last way of protection that we are going to consider consists of installation and uninstallation of a
program. Modern programs usually have convenient setup utilities which install and deinstall programs. As a result, it may
be not burdensome at all to perform a simple installation procedure once a month. There are different methods to fight
this method. If, for example, your program requires a great deal of setting its options, you can arrange it in such way that
uninstalling a program would cause all options to be lost and a program would have to be set up again after the repetitive
installations. A more radical solution would be to leave a mark in a computer (in a Registry, for example) which would state
that a program had already been used on this computer and to refuse to install a program if such a mark exists. Indeed,
your program would have to be a true perfection so that a user would want to reinstall Windows just to be able to use it.
Should I mention that this mark must not be removed by an uninstaller, it should not be located close to other settings of
your program and the last, but not the least: use your imagination! If your program is named CoolApp.exe, do not name
the register key for its mark as CoolAppWasHere! An alternative of using the Registry may be a small DLL in the Windows
directory which an uninstaller does not remove.

If there is a limitation of a launch count, then a counter must be decremented after each launch. (It may be incremented
– this is totally irrelevant for us. Let’s suppose it is decremented, just to be certain.) It is very probable that this counter is
located in the Registry or in an ini.-file. At times, it’s just amazing to see how clever people who are able to create brilliant
programs show miraculous narrow-mindedness and name this counter, for example, iTimeSpan, like it is named in the
FineReader program. Name this key variable, for instance, RAS32stub and make its value equal to the remaining launches
count with a checksum, encrypted in any code, even a trite XOR. Although this may not help you a great deal – if a
hacker finds the counter, he can just restore its original value every time. A radical remedy which is acceptable for
Internet-based applications is keeping your counter on a server instead of a local computer.

It is possible to store into a parameter a checksum of the remaining parameters, including the counter itself. In this case
all the settings of the program can only be restored together.

You can try and hide the counter outside the Registry, because this location is too evident. You can come up with an
impressive name for an .INI file (which, by the way, may have an extension other than «INI.?, stuff this file with a load of
settings with intimidatingly complex names (the counter is to be one of them), place it in the Windows directory, and, more
importantly, every time you decrement the counter, you should forcefully set the same date for this file, 08.24.95, for
instance. I hope you have been already influenced by the anti-hacker spirit and understand, why I’m suggesting you to
use this date.

Comparing the time-of-usage and launch-count limitations we’ll have to admit that the second option is less reliable because
of the necessity to keep a constantly changing counter which can be found with relative ease.

Methods of hacking without code modification.

Suppose a registration process involves sending a registration number as a response to a user name. All too often, just
after a program is released a key generating program appears. Such a program is able to generate a registration number
for any given user name. Meanwhile, it is not hard to arrange everything in such way that creation of key-generating
programs would be completely impossible. To accomplish this, it would be sufficient for you to use a simple asymmetrical
encryption algorithm. You can find a lot of information about asymmetrical encryption algorithms, often dubbed as open-
key systems, for example, at www.rsa.com. To put it in a nutshell, asymmetrical encryption algorithm is a way of coding
information which requires one key for the encryption and another one for the decryption, yet it is impossible to obtain both
of the keys, knowing just one of them. As a rule one of the keys is made as an «open?one (which one of them it is
depends on the purpose of their usage), that is, a commonly known key, the other one is kept as a secret. Now consider
this: a registration number is a user name which is encrypted with an asymmetrical encryption algorithm, and the
encryption password (a key, that is) is known only by you. A program would perform the verification by decrypting the
registration number (the decryption key is built into the program) and comparing the result with the user name. If such an
algorithm is used correctly, it is totally impossible to create a key generating program. It has to be noticed, however, that
the aforementioned way of protection will not prevent from using someone else’s key and from cracking by modification of
program code. This method is essentially an electronic signature with a registered user name by the program’s author.

Most of modern commercial (non-shareware) programs require entering a serial number during the registration. This would
pose no problem for a legal user – the number can be found in the program package, and could pose a problem for an
illegal one (if we aren’t talking about a pirated CD, that is, because thoughtful pirates often place a file with a required serial
number on the same disk). A serial number has to satisfy several criterias therefore a random number will not work. Yet all
too often an implementation of checking the number validity cannot stand any criticism. For example, most of Microsoft
products can be satisfied with a number which consists only of 1’s. Here’s a method of verification which can be advised
(actually, there can be quite a lot of options): the first part of the serial number is encrypted (even in the most primitive
way), the result checksum is calculated and then a remainder of division of checksum by some number X is calculated.
The resulting remainder should match the second part of the checksum. No matter what kind of verification you use, at
least it should not miss banal numbers like all zeros or all 1’s. It would be a good idea to provide a link between a serial
number and a program name and/or version to make it impossible to use serial numbers from one of your programs with
another one. One quite successful brand of this method of protection is a method which requires entering word # N from
page # M from printed manual which should be provided with the program in this case.

Here’s a bit about upgrades. A newer version of a program which allows to be used only if there is a previous version of
this program already installed on the computer must have some mechanics that scans for the previous version. In a likely
way Windows-95’ upgrade requires presence of Windows 3.1 during the installation. Yet, alas, all of the verification consists
of checking for presence of a file windows\system\win386.exe. It is enough to create a file with this name (you can even
make it 0 bytes long) and Windows ’95 can be installed on a computer where there is no and has never been Windows 3.1
present. Hence the verification should be a bit more complex. For example, an upgrade version of a program may
purposefully omit setting several options in the Registry, provided they match those in the previous version. It is possible to
come up with a lot more of highly reliable methods.

Methods of hacking involving code modification.

Very often hackers turn a shareware program into a full-scale working one, having changed just one byte in its code and
having spent just a few minutes. How do they do it? How do they manage to find a right place in a multi-megabyte
program and spend less than a minute on this search (this is genuine time it takes, not an exaggeration)? The matter of a
fact is that authors of programs seem to do their best to help hackers in their work. Let us discuss one very typical
example. Suppose your program goes something like this:

BOOL isRegistered() {

...

return TRUE or FALSE; /* this function may determine if this program is registered or not, basing on
some probably very complex and perfect criteria

*/

....

//a warning for a user

if(!isRegistered())

MessageBox(“This program is not registered!”, “Register please!”);


....

// here’s a verification of being registered when performing some useful functions if(isRegistered())
doSomethingVeryUseful();
else
MessageBox(“Unregistered copy! This function is available for registered users only!”);

....

//there’s a lot of such tests, and they are stuffed all over the program in various modules

The most funny thing about this is that many authors actually find this kind of protection very reliable. Well indeed, the
isRegistered() function is very complex and the verifications are scattered all over the program in abundance.

What is a hacker going to do to such a program? That’s right – he will just find a string, for example, «Register please!?
and get its address. Now it’s not hard to find a piece of code like this one:

call xxxxx ; function IsRegistered

or eax, eax

jnz yyyyy ; *

...

push <found_address> ; This is the place a hacker will find.

....

call zzzzz ; MessageBox

Now he is going to alter the only byte in the code, the one marked by an asterisk and there will be no demand of
registration any more. Sometimes it’s enough to put a period here. In this case the time of hacking can be measured in
seconds. Yet we are examining a more complex sort of protection – this testing is performed repeatedly. Get rid of an
illusion that a hacker will try to find all of its occurrences (although it is not that difficult). He is merely going to alter a few
starting bytes of a function IsRegistered in such way that it is always going to return a TRUE value. This function may
implement the most brilliant and the most reliable algorithm – but who needs it now?

Pondering over this given example we can reach two conclusions. First, the hackers’ task would get much more difficult,
had he not found this place in the program so easily. Secondly, we cannot live with the fact that there is a theoretical
chance to break a program by replacing just a few bytes. The right place was found only because the right string was
found. Of course, this is a specific case. Instead of text there could be a resource id, if a message is stored as a text
resource or a dialog box. There could be some distinctive number. Suppose an unregistered modification of your program
limits some of its setting by 20. In this case a hacker might be looking for the code

cmp <something>, 20

To hamper the search of the necessary place for a hacker you should diguise such critical segments. Text strings (such as
messages, filenames, Register key names etc.) should be encrypted for storage (in any, maybe even the most primitive
way). The telltale constant numbers should be disguised like this:

#define SLY 21061969

int vSly = SLY;


...

LoadString(IDS_SHAREWAREWARNING - SLY + vSly);

...

Besides, the verification is not to be carried out in the very beginning of a program. It is preferable to have several testing
procedures and perform them repeatedly. You can create a separate thread which performs such necessary check-ups
periodically.

Let us take a more global look at the problem. How to achieve that your program theoretically cannot be broken by
altering just a few bytes? Yes, it is possible. Consider an example:

struct VeryImportant {

/*

Collect all the constants you use in functions which are not available for unregistered users into this
structure. Accordingly, in the functions themselves use the constants upon retrieving them from this
structure. For example, instead of a = b + 2;

write a = b + myconst.two;

Let there be just a few of your constants. They are going to be important and non-ordinary, if possible. A
pointer to a function can be used as a constant and, if necessary, this constant can be used to call this
function by this very pointer.

*/

} myconst = { xxxx };

/*

Here is the most cunning part. xxxx are the constants we need, encrypted in some algorithm. Do not re-create anything
that is well-known, use a professional algorithm, for example, rc2 or rc4 – they are not complicated at all. The necessary
values may be read from a file, a resource or extracted out of a Registry (where they are put by an installer). The last
option is the most attractive one.

*/

....

//This is an unencrypted checksum of our constants.

const MyConstCRC = xxx;


....

//here is our most curious function. It is very simple now!

BOOL IsRegistered()
{

return CalculateCrc(&myconst) == MyConstCrc;

}
....
//this is where the registration number or zeros, if the program is unregistered, are stored.

BYTE regNum [REGNUM_LEN];

.....

// this function should be called once for initialization

void initProtection()
{

// now we decipher our constants with the registration number (or, rather, with its part)
decrypt(&myConst, regNum);

// The following part may be just like the one in the previous example.

Even now a hacker may find the function IsRegistered(). Now modifying it will only make your program stop working,
because the constants which are located in the structure and are necessary for the work cannot be deciphered without the
registration number. In other words, you should follow a simple rule – a value being verified should be used instead of
being compared to a constant. So, we do not check for a presence of a registration number, we use it. Nowhere in a
program a hacker may find what value this number should have. Let’s view one more example of this concept’s usage.
Suppose an unregistered modification of your program allows not more than 40 records in some database. To simplify the
matter we suggest that each user is described by a structure named CUser, and the database is just an array of the
CUser structures. Usually there is something like

array = new array[userNum];

...

if(userNum > 40) ....;

present in the program, and a hacker may simply find an operation

cmp <???-??>, 40

and alter it in the way he wants.

Having learned the aforementioned, you can make his life a bit more complex in this way, for example:

if(userNum*2+1 > 81) ....;

But you can go further:

CUser *array;

// in a registered version initialization is performed by another function

void initUserArray()
{

int x = -83, y = 3;
array = new array[(x+y)/-2];

...

if(userNum*2+1 > 81) ....; // *

In this case, even if a hacker finds the verification (marked by an asterisk), he is going to get himself some very
unpleasant and hard-to-find range check errors when the quantity of records exceeds forty.

It is harder to implement a protection if an unregistered program is supposed to display reminders. This variant is different
in that a hacker is supposed to remove an «extra?to get a full-scale working version, not to add a missing function. To
break is easier than to build, and this applies to this case, too. You can protect your program from cracking to some
extent, if your program does something minute but necessary for your work when displaying a reminder. For instance, a
reminder is implemented as a dialog box. When the WM_INIT message handler (dialog initializer) is executed, a timer can
be set to one second. And when the WM_TIME timer handler is executed, you can initialize some necessary variables or
perform another action which is necessary for the further work. If a hacker finds and suppresses the window output,
simultaneously he renders the program inoperable.

Another evident way to protect your program from cracking is to check its integrity. For example, your program can count
its checksum upon loading (the checksum of a file, not in memory). Although this cannot boost the speed of operation in
any way, it can also help you to locate a virus infection or a violation of a program’s integrity which can occur during the
program’s transfer via communication channels. It has to be kept in mind that, generally speaking, the integrity verification
cannot guarantee the integrity itself, because a hacker may remove the verification subroutine itself. This is where the
«chase?begins, whoever succeeds first. The integrity verification can be logically tied to a digital signature of a program
(a.k.a. its certificate). There has been written a lot about it, so we won’t talk about it here.

Copy protection.

Let’s address another problem now – how to prevent a distribution of the registered program? Generally, its a problem of a
«traditional?copy protection. There is a lot written about it. Listed below are the most popular ways of protection.

Key disk.

This way of protection is practically not used any more. Firstly, it is very inconvenient for a user, secondly, it is unreliable
because of unreliability of disk as an information medium. By the way, a common belief that this method is unreliable
because any disk can be copied with a special program, is not true.

Electronic key.

Aside from some apparent benefits, this method also has its disadvantages. Usage of two programs protected this way on
one computer may turn out to be problematic. Because of a sensible cost, this method may be inappropriate for
inexpensive programs. Besides, this method is only potentially reliable. In practice, however, we may encounter some very
clumsy implementations (here’s a specific example: a verification function is located in a separate DLL and returns a
true/false value «key present/ key not present?

Hardware binding.

Binding a program to equipment seriously limits a user, because a computer upgrade becomes impossible.

Software binding.

This binding may not be evident because program which has a complicated installer that carries out a large preparation
work (entering settings into the Registry, installing common DLLs into the system directory, registering ActiveX controls)
essentially binds a program to a specific copy of software installed on your computer.

Conclusion.
If your program is distributed on CDs and its volume is not too big (that is, a program does not take up a whole CD), than
you may consider filling the free space with the information which is needed for the installation. If you do it skillfully enough,
than pirates would have a question arisen – is it worthwhile to issue a CD which is completely dedicated to your small
program?

Well, pirates strive to place as much of different programs on a CD as possible, in order to increase the quantity of
potential buyers. Your program may be small, yet have a bonus pack of useful, yet non-essential programs included with
it. Pirates can easily «crop?your distribution package, therefore your installer should check for the presence of this extra
information. You can also check if some files or directories previously absent from an original package have appeared on a
CD.

And, just a little notice in conclusion. You can dramatically increase your program’s fortitude, yet it is going to take greater carefulness
and attention than common programming takes. Here’s a small example: when proposing a method of protection by means of setting a
counter of program launches, this article suggested to put this counter into a .ini file with a name that sounds intimidatingly scientific, and
the most important thing was to forcibly set the same old date of modification for this file after each decrement of the counter. I
hope that, upon reading this article, you will not store the name of this file as an open text. To manipulate this .ini-file you
will probably use a WIN API function WritePrivateProfileString. Do you remember that Windows caches .ini-files to increase
the operation speed? Here’s where such a situation may occur: you use the WritePrivateProfileString function, yet saving an
.ini-file is delayed. You then set a date you need for the file. And then the cache is being dumped onto disk with a correct,
yet undesirable date of modification specified. How to counter this problem is mentioned in the description of the mentioned
function – I used this example to show, just how accurate a programming should be.

[MIRRORS/www.litespeed.org/Tutorials/a7.htm]
[MIRRORS/www.litespeed.org/Tutorials/a8.htm]
[MIRRORS/www.litespeed.org/Tutorials/footnote.htm] bot="Include" endspan i-
checksum="7085"
Anti Cracking FAQ
How to make cracking your programs a little harder

Contents
1. How to make cracking your app a little bit harder...
2. More tips you might take into consideration...
3. Advanced tips given by Assembler freaks...
4. Special on Delphi VCL cracking...
5. Some notes on registration numbers...
6. How to find cracks for your apps...
7. What to do if you found a crack for your app...
8. Facts and Myths about Software pirating...
9. Thoughts and letters from crackers
10. Links of interest...

Finding out that the program on which you worked for months or years has been cracked can really hurt
and demotivate.
For me as a Shareware programmer, the reason has never been that I've lost a few cents (I don't want to
do propability calculations here, it might hurt even more..), no, it was simply that I've always tried to hold
my programs as cheap as possible to make them affordable for everyone, even for students or freeware
programmers.

Somehow I can understand the fascination of cracking programs (if you are absolutely intolerant about
software crackers and hackers, please excuse, but one of my educations is Psychotherapy, and I'm always
searching for reasons...) - cracking a restricted software program must be like solving a (sometimes very
tricky) riddle, and you might get addicted to the feeling of solving them (I've found that when I saw my
grandmother doing crossword puzzles all over the time for some months). The problem is (but at the
latest, now we come to the undoubtedly illegal part of the "game"): it doesn't really satisfy the cracker if
he is the the only one who knows about his "genius"...thus, he has to spread the news. He has to publish
his "crack" (just see most crack packages: in most cases they just consist of: 1. the cracking utility 2. a
short description 3. a big file containing claims that the producers are nothing less than the greatest ones
on Earth and that the cracked program is another one which could not stop them with "its lame protection
scheme".)
But now the fun is completely over: by giving out this (let's try to be fair: "study of feasibility") to other
people, by spreading it via Websites, newsgroups, mailing lists, anonymous FTP, CDROM "abonnements"
and whatever, they clearly damage the business of everyone who puts time and energy in their software
product. Even if we assume that typical crackers wouldn't have bought your product under normal
circumstances: spreading the "crack" IS criminal and no one could claim that none of the receivers or
downloaders would never have bought it. It's just like if someone hands out copies of the key to your car
on the marketplace - and it doesn't really matter if he does that for money or not.

In earlier days, I have never put real energy in protecting my programs against cracking, but after finding
several cracks for them around, I thought to myself: why make it too easy? As a programmer, of course I
know that no - really: NO! - program can ever be crack-safe, and I know that of every interesting program
sooner or later cracks (or at least pirated or illegally copied versions) will be around, but at least I could try
to avoid the worst mistakes. Crackers are not super-geniuses .. they are simple programmers who have
learned some techniques to counteract common protection schemes - and if you know where and how
crackers are searching, you can make them lose *much* time! And that's what it is about: there is no
bullet-proof way to protect your programs, but you can dance on the nerves of those people until they
decide for an easier target to "get the feeling"... or even go outside to enjoy the nature instead of sitting in
front of the monitor the whole day. ;-)
Most of the typical 'high language' programmers don't know Assembler anymore, so the 'protection ideas'
they use are in most cases quite weak.
I don't know much about Assembler myself, so I decided to open my eyes and started to collect anti-crack
protection tips wherever I found them. Also I did my best to "learn from the other side" .. many of the tips
you can find here I've found by studying the typical cracking techniques, the various "cracking guides"
around the web and by reading protection tips given even by professional crackers themselves (some of
them generously give us tips to increase their challenge). Well, I hope I've learned my lessons well enough,
but also want to share my experiences with you on this page.
Some rules given here were already stated in various essays on other sites, but are listed here for
completeness. Many of these apply especially to windoze, but can be "ported" to other OS'es or anywhere
else.

PLEASE:

This FAQ is just as good as the experiences that are webbed into it. If you think that I've missed some
points or useful tips a typical Delphi programmer could easily add to his/her programs to improve
protection, please let me know. If you allow it, I'll add it here, otherwise I'll inform you about my
experiences with it.
Don't ask me questions - might be that I'm simply too overburden to answer.
1) As mentioned, I don't have much knowledge of the low-level stuff.
2) I can't send you demo sources, since I don't have anything ready for a publication. If I have
something, you will read it here.
3) Finally, I will not provide anyone with any of the URLs where I've found (or found out) some of
these tips. Please understand, but this is a site dedicated to programming, but not to provide "step-
in's" to available cracks or even to "Cracker hunting".

But finally, here is ..


How to make cracking your app a little bit harder:
(tips are not sorted by importance)

Never use meaningful procedure names such as


function RegistrationOK: Boolean;

How intelligent and complex your code inside this function might ever be - an experienced cracker will
just take about 10-20 seconds to remove it. Believe it or not.
Alternatively, place some required code for your program in such a function. If the cracker disables the
function, your program would produce incorrect results, for example.

Avoid nagscreens or "Gotcha!" messages - this is what crackers are searching first. They will
never dig through the 300K ASM instructions of your program - instead, they are first searching the
location of nagscreens or your "Your evaluation time has expired!" message and start cracking there
(see below for more tips about that). In some cases, it's even enough to remove the form resource
from the EXE and it will show no nagscreen anymore - without any bug showing up! If you really need
such a nagscren, you should build it dynamically at runtime, and generally, the only method to show
the user that he is unregistered should be in the "about" dialog (some programmers also have the
philosophy that nagscreens might cause your users to hate your app which would then also be very
stupid).

Never use meaningful file names such as License.Dat. Why, you say? Please start reading here.
:)

Play with asymetric encryption. Just using unusual filenames is often not enough. Good encryption,
of course, could keep the cracker busy for months (if he likes).
Add long delays. Don't warn the user right after a violation is made. Wait later, maybe until the next
day or two (crackers hate that).

Add short delays. Pause a second or two after a password entry or to your other checking routines
to make brute force cracking unfeasible. Simple to do, but rarely done.

Use checksums in DLL's and in the EXE. Have them check each other. Far away from "safe", but it
just makes it harder to crack.

Self-heal your software. You know, things like the error correction modems and hard drives use.
The technology has been around for years, and no one uses it on their software? The best thing about
this is that if the cracker used a decompiler, they may be looking at a listing that is no longer valid.

Patch your own software! Change your code to call different validation routines each time. Beat
them at their own game.

Store serial numbers in unlikely places like as a property of a database field. Often heard and read:
"..give it a DLL file name and store it in the System directory." Too often heard, don't use it. ;-)

Store serial numbers in several places.

Don't rely on the system date. Get the date of several files, like SYSTEM.DAT, SYSTEM,DA0 and
BOOTLOG.TXT and compare them to the system date. Require that the time be greater than the last
run (but keep in mind that many users might do Y2K-checks these days).

Don't use literal strings that tell the user: "Sorry, but... (whatever)." These are the first things to
look for. Build strings dynamically or encrypt them.

Flood the cracker with bogus calls and hard-coded strings. Decoys are fun.

Have fun with Spaghetti-Code simply eats his time and nerves..

Don't use a validation functions. Every time you validate the user, write your validation code inline
with the current process. That just makes more cracking for the cracker and bewares of just NUL'ing
out your routine.

Use "reserved" names. When using hard-coded keys or passwords, make them look like program
code or function calls (i.e., "73AF" or "GetWindowText"). This actually works very well and confuses
some decompilers.

No "disabled" features. If your program doesn't save data in "crapware" edition, don't include a
"grayed" menu item. No saving means no saving - the code should not be included in the EXE - that's
it. Most programming languages offer you a really easy way to maintain several versions of your code
by simply doing the following:
{$IFDEF trial}
... no action here ...
{$ELSE}
... advanced functionality for registered user ...
{$ENDIF}

Say "Goodbye" to startup/time-limits! This belongs close to the tip above - especially, since there
is simply no way to protect a time-limited demo. You won't believe it - there even exist patched
versions of Windows DLL's (!) which will make your demo think it has never run before on this
computer. At one point or another, you will have to save your date or program start information on
the computer: in a file, in the registry, somewhere - and Windows provides GREAT ways to spy on
any changes made to these devices. "This is a war that can never be won." (D.Filion)

Update often. Frequent updates mean: frequently changing code, so the typical (simple) crack which
is just patching hard-coded byte positions, will possibly already be outdated when published. Also
prevent uploading them to public servers, so that you have better control about where your app sits
around and people don't find older versions the cracks can still use. Yes, this doesn't prevent pirates
from including the version to the crack package, but IF they do so, you can at least contribute to filling
up their harddisks.

Use strong encryption. Just XORing is not really strong - use something with an algorithm that isn't
easily reverse-engineered, and don't put both encryption and decryption code in your app.

Finally, take some time to think about protecting your software. Is it really worth the
protection? Wouldn't it be better to improve your software, rather than improving protections? The
problem of protecting software vanishes if no one will use your software. Don't overestimate your
work's "importance to the world".

More tips you might take into consideration:


Use a serial which is several KB long of arithmetical transforms, to drive anyone trying to crack it
insane. This makes a keygenerator almost impossible - Also, brute force attacks are blocked very
efficiently.

Caution with the Runtime libary! Use it fully when writing the beta versions, in the final release
rewrite some functions at least to make crackers life harder.

Mangle data. Protection that mangles data is usually a good one.


Example: Imagine a charting program .. e.g., just disabling printing and later on enabling it basing on
some registration# is the most often committed suicide. Let your thingo print. When creating data
structures for printing, mangle them in some way. Unmangle them just before printing, using reg# or
something other for that purpose. Even more, make this mangling subtle. Assume that you've got a
pie chart to print. Don't alter anything, but add some not too big random numbers to values of data
series - this is mangling then. The chart will look "not that bad", but will be otherwise unuseable (if the
changes are random and on the order of 20%, for example). Finding such protection, if its connection
with reg# is not self-evident can take much time. One has to delve inside your data structures and
find that dreaded mangling and unmangling code.

Traps. A method I'm not sure about, but I have heard some apps are using it: do a CRC check on
your EXE. If it is modified then don't show the typical error message, but wait a day and then notify
the user using some cryptic error code. When they contact you with the error code, you know that it
is due to the crack. Be aware: such traps could also be activated due to virus infection or incorrect
downloads. Imagine the possible aftereffects if you are blaming your potential customer for software
piracy.
Don't rely on "EXE-packers". For almost any tool which compresses EXE files (Shrinker,
WWPack32, NeoLite - to list the most popular ones) there's an uncompressor around, so
compressors capable for software-protection should at least support configurable encryption.
Unpackers for the above (and other) tools are not very wide-spreaded, however, don't rely on them
as your program's (one and only) "protection" - organized crackers usually have their harddisks full of
such "tools".

Recompile and re-release often! Especially if you are modifying your "anti-cracking" routines often,
even more advanced cracks with code-searching capabilities will be useless.

Control your own distribution! Avoid putting your apps on compilation CDs. If a crack is developed
for a version that is on 30,000 CDs, that version is likely to be pirated. [by Ch.Losinger]
Advanced tips ..given by assembler freaks.

The rcr/rcl trick


If a rcr/rcl is performed on a value, it becomes much more of a pain to crack - you can't reverse it
with by negating it's effects without knowing what the value of the carry flag was before the original
operation. If the carry flag is created as a result of some other pain in the neck operation, you are
probably onto a winner.
Stick conditional jumps in. Everywhere.
Conditional jumps are not fun to reverse engineer. No loops, but jumps which conditionally
bypass/include portions of your wonderful key manipulation code. There is no easy inverse operation
to be performed here.
Use portions of the code as magic number tables.
(preferably critical sections). You have no idea how annoying this can be, if you're like most crackers
and like to change things around using softice (a popular cracking tool).
Play with the cracker's mind.
This one is fun :-) Stick series of nops in, as though you were doing self-modifying code (oh my god!
what the heck! nops? Aha! Self-modifying code! Idiot spends next three years trying to find the code
that should be there.). Pepper the code with junk instructions. Cut the code up into little pieces and
put them all over the executable, with (preferably conditional) jumps between them. - Anything which
you would find a pain in the neck.
Detect SoftIce. Early.
Now crash the computer. You can crash a pentium or a pentium with MMX even without a vxd by the
opcode: F0 0F C7 C8 (illegal form of cmpxchg8b instruction with lock prefix). Beyond that, we have
to resort to the tried and true methods. Using a vxd, take the CPU out of protected mode. Windows
doesn't like that. Wonder why? .. On the other hand,
Don't loose too much time on writing anything that will kill disassemblers or debuggers.
Doing it is worthless, believe me, people who made them or others will soon find the way around, so
shift your interest to more important stuff. Just do things which are easily and fast to afford, like the
above tip.

Special on Delphi VCL cracking


Quoted from a helpful cracking tutorial*) - just read and learn from it!

"Let's learn something about the innards of new Borland's programming tools. This knowledge will allow us
to speed up cracking sessions, as will teach shareware programmers who use Delphi to be more careful
and not to happily expose their 'secrets' to curious eyes B) [..]

VCL stands for "visual component library", a library used by recent Borland visual languages as Delphi and
BC++ Builder.
These environments use a proprietary resource format, that appear as 'RCDATA' when listed by Resource
Workshop. These resources contain 'forms'. In Delphi jargon, forms are the windows of the program. All
the info about their design is stored there. When a typical Delphi app is starting, the initialisation code
creates the forms, loading the required information from the resources. Sometimes this loading is deferred
- forms that aren't used very often are created and destroyed as needed.
This system is the best and the worst of Delphi. It allows a very fast way of programming but, for full-
length apps, it can slow down the loading.

The really interesting part of this information is that the address of the routines - called in response to user
interactions with the elements of the form - are bound at run time by name. So knowing these names we
can find the appropriate addresses!

If you have cracked any Delphi apps, you have surely experienced the long chain of calls inside the library,
from the breakpoints on the API calls to the "do something" code. I hoped that these addresses could help
in pinpointing the relevant code."

I cracked it completely and without problems, as you are about


[..describes his installation of a quite well-known Delphi-writen application..]

to see :=) After first installation the weeks passed and I hadn't had the time to work on it... when I started
it, I found a nasty 'Your evaluation period has expired' message :-(

The first step is to gather the information about the target exe with a resource or form spy tool. You may
be tempted to investigate TVALIDATORDLG, the form where the user name and registration key is
obviously input. But all you'll find is a mere dialog. The real work is accomplished from its caller:
TSPLASHFORM. This is the nag window that appears at the beginning of the program, as well as when it's
shutting down and from the Help->About menu.

You can select TSplashForm and look at the text representation of it. A lot of information about the buttons
and labels will appear. Let's concentrate on the following part, near the end:

object RegButton: TButton


Left = 200
Top = 176
Width = 97
Height = 25
Caption = 'Register'
TabOrder = 1
OnClick = RegButtonClick
end

What's that? This is the button with the caption "Register". You can see its size, position... and something
with a suggestive name: "OnClick". "OnClick" tells us the name of the routine invoked when the user
presses this button. Once we have the name (yes, "nomen est omen" :) we can search for the address of
this routine. This is because the routine is bound to the button at run time by name.

Using a hex editor, I looked for "RegButtonClick" and I found it twice. The second occurrence is the
resource itself, the first is within an address table:

000A4990 ____ ____ ____ BC57 4A00 0E52 6567 4275 ______.WJ..RegBu
000A49A0 7474 6F6E 436C 6963 6B__ ____ ____ ____ ttonClick_______

Now look at the magic numbers before the name. There is a byte ('0E') indicating the length of
"RegButtonClick" (14 characters) and before that an address: 004ABC57.

Some disassemblers seem to think that file is too long and it doesn't disassemble this portion of the exe
correctly - however, with a special tool we can bpx on this and... right! It stops at the point just when we
push the button.

A couple of instructions forward you'll find a CALL. Tracing into it you'll find a "standard stack frame" in
44ECC8:

0044ECC8 55 push ebp


0044ECC9 8BEC mov ebp, esp
...

This is the kind of thing expected at the beginning of a high level routine, made by the application
programmer. We have avoided the whole chain of library calls through the VCL from Windows notifications,
and landed in the right place!
From this point, there are some calls you can easily test by setting breakpoints on them - you'll find that
their purpose is to show the dialog asking for the user name and registration key. Then, the key is
calculated from the user name and compared with the one the user entered. You can enter the name you
choose, and anything as the key, after BPXing 44ED69. Here, a call to a routine compares two strings. D
EDX will show the fake key you entered and D EAX will show the correct calculated key. Easy, isn't it? A ten
minute crack by a beginner!!
[description about spying the key generator routine comes next. It's been an average routine of about 10-20 Object pascal code lines.]

How this way of cracking can be avoided?

Read my tips above. The basics are: don't use automatic methods created by double clicking on the button
or the object inspector. Write your code somewhere else in your program, preferably in another module,
and bind it to the button using code such as:

RegButton.OnClick := RegButtonClick;

Of course you'll need to enter this code after the form is created and before it's called. Best if it's rounded
by a lot of unrelated stuff. This won't necessarily prevent your program from being cracked of course, but
things will not be as easy as you have seen in the lines above O:)

Notes on registration numbers


(if you can't avoid them)

balance between security, feasiblity, programmability and end-user headaches


Too long, non-alphanumeric Reg#'s tend to be continuously entered badly. Think about requiring to
enter a verification field (as commonly used with passwords) or, at least, provide a "non-persistent"
Reg# entry field so that the user will rewrite the Reg# each time, possibly correctly at last. Many
people will just "glance-compare" the entered Reg# and the one (possibly) emailed to them, arriving
at the final thought that they did enter it correctly, whereas the font is too small or they are too tired
to notice that this '1' and 'l' have been interchanged (in a reg# like 'l83jjd_0)pH1lTe' )
Refrain from any user feedback. The Reg# entry box should accept strings of any length, without
any validation. Don't give crackers the knowledge about the type of your Reg# - if you do "online-
verification" which shows that it's 10 chars long or that is contains only uppercase chars helps - so
don't help them!
Calculate the number of potential users! There's nothing bad like if you have to update 9,999
users because you didn't expect that there might be 10,000 of them and have to shoot out a new
version which is capable for these Reg#'s...
If your Reg# is 10 numbers long,.. .. there are 10^10 possible Reg#'s. But since your app might
find let's say only 10^4 (10'000) users, you should invent an algorithm that assigns each one of
10^4 users one of 10^10 reg#'s, and does it somewhat uniformly. This prevents people and
programs (some .vxd based "macro" players, for example) to be used for brute force approach. If
there are only 10^4 users and you allow 10^9 "valid" Reg#s out of 10^10, on average each 10th
Reg# tried brute-force will be valid, whereas on the case of 10^4 prospective users, that many valid
reg#'s and space of 10^10 Reg#s, on average only each 10^6th Reg# tried brute force will be valid.
Ever calculated how much time it would take to brute-force search 10^6 numbers, even using a fast
machine and extremenly fast macro player (keystroke generator simulating Reg# entry and checking
for results)?
the assignment operator that assigns User# to Reg# shouldn't be trivial, and it's
implementation should be done in Assembler by someone experienced both in Maths and Assembler.
Remember that Delphi still allows you to directly use ASM code in your source! Then, check your
operator. create graphs of how it works. Understand your own work, especially its drawbacks and
vulnerabilities
Be inventive. Don't use anything that seems simple, quick and effective unless you've come with
something like Einstein's relativity theory, your approach is yes, simple, yes, quick, but no, not
effective, and yes, easy to crack. I'm sorry, but we aren't geniuses and developing a good protection
scheme takes some time.
Don't have a single registration code. Make the key depend on some user-specific info - have a
way to get the user info out of the registration codes. If you find a code on the web, track down the
user and harass him. Threaten to do this when you give paying users their codes. [Ch.Losinger]
Encrypt your good code - never decrypt it. And encrypt the User-Code to test against your good
code... [Ch.Losinger]

How can I find out if cracks exist for my program?


Use the Search engines
Using search engines is one of the best methods. Most software pirates have overboarding self-
confidence and even submit their illegal pages to popular search engines on the web. If you search
Altavista, Lycos or especially Meta-searchers like MetaCrawler and your software is already present
for more than a few months, you'll maybe have "luck" and find some "Warez Pages" which offer
cracks or Registration codes for your program.

Search pages using Free Webspace


Software pirates, students which think it's cool to offer "Warez" and "Crackz" and other strange kinda
persons especially love the free services offered by sites like GeoCities, Xoom, Tripod and others to
offer their stuff. Most of them offer at least 5 MB free webspace, which is enough to provide
thousands of cracks. Beside that, those sites are busy like BIG railway stations and like there,
criminals feel quite safe to go after their "hobbies" there. Good for us, almost all free webspace
providers also offer search features which allow you to search just all pages of their members, which
is much more accurate and easier than using the big engines of which some are not kept up-to-date
very good. Just connect to their main portal and start your search. If cracks exist for your program,
you have very good chances to find them on some of these member pages.
In such a case, you should contact the maintainers of the service (almost all even provide special
email addresses for piracy reports (such as abuse@geocities.com).

Search newsgroups
Unlike what polititians are trying to suggest to the public, it's in most cases quite easy to track down
who is posting cracks, serial numbers or even full licensed copies of your software in newsgroups like
alt.cracks.* and others. Just let your newsreader display all header fields and check carefully where
those people are writing from. Since almost any news server requires complete authentication before
posting, you have good chances to find out who "hides" hinter strange names like "Hackman" or
"Piratez2000". If you have no success, simply contact the webmaster of the server where the
message comes from or forward him the posting, requesting action against this person.

Make use of "Crack Search Engines"!


The easiness of CGI and increasing success to powerful webservers leaded to some quite powerful
Crack Search Engines during the recent years. They can be of enourmous help for finding cracks for
your software and then starting action against the responsible persons providing these pages and
cracks. Sorry, I won't provide links for those sites here, but you can't miss them during your
"investigations" in those slippy parts of the web.
Here is a link to a crack search engine - try it! Since it is not providing or linking to any cracks by itself,
I decided to list it here just to show you how many cracks actually exist. If you can't find your app,
don't be too happy: it's just one of a number of existing search engines.

Use Web-Robots
Sites like http://202.114.22.131/mirrors/www.netmind.com/default.htm offer robots that notify you
by email when a page changes. Since you can also define result pages of, for example, AltaVista
searches for a crack or key to your program, this is a cool way to get "paged" as soon as some
spider hits a website of a child which "-cool, man!-" offers a crack page. You can even do that for
newsgroup searches!

Subscribe to mailing lists


If you don't know how to go on, ask in the Anti-Warez Mailing-list or other, Shareware-related mailing
lists (see my "Delphi Tips" pages for more links).
Their members watch the activities of most popular cracking groups and have been quite active
closing many of them down during the times. They will surely help you if you yourself don't have
success. Shareware developers should join forces - it pays!
What to do if you found a crack for your app "Blow the whistle!"..

I've heard and read many programmers telling "you can't do everything against them, there are too many
crackers around, too many warez sites on the Net, so that few people ever get caught."
Fact is, however, that you as a software author would have excellent chances to win any lawsuit against
operators of ISP's awaringly keeping crack/warez sites online or against the crackers themselves. Hundreds
of sites have been closed down during the last years due to offering or linking to pirated software. In some
cases, computers were confiscated, and the operators are still paying settlements.
So, you don't have just to accept if you find pirated copies or cracks for your software around .. try to
detect where it comes from and get into action against the source!

Forget about the BSA (http://www.nopiracy.com, http://www.bsa.org) - these are just commercial
organizations which just take "orders" for their paying clients. No, they don't work for everybody -
usually they only come in to action when the target is a large firm, using software from one of their
biggest clients (no prizes for guessing which one). Can you say "M$ Militia" ?
Do internic queries on the crackers site
(http://202.114.22.131/mirrors/www.checkdomain.com/default.htm), contact the sysadmin, explain
the situation. If the ISP is a fair and serious one, there are chances that the crackers will receive a
serious warning to remove all the illegal stuff from their sites or that it will even be closed without
delay.
If this doesn't help (seldom seen, but possible), contact the local authorities of the state where the
ISP is located. Most countries even provide email addresses for reporting crime activities (like
childporn, but they are also open for pirated software), or at least their police administration can be
reached by email. There are good chances that the ISP will be threatened to lose his licence.
Finally: get yourself a good glass of wine and enjoy it. You have written a good program! (otherwise
no one would lose time trying to crack it)

Facts and Myths about Software pirating


Provided by the Business Software Alliance

Myth: "None of the software offered was stored on my site - I only had links to the files."
Fact: You could be liable for anything that you do that contributes to the infringement of copyrighted
works. This includes facilitating a download by linking to remote files.

Myth: "I have a disclaimer on my site that protects me."


Fact: A disclaimer cannot shift your liability to someone else. You are still contributing to copyright
infringement.

Myth: "I thought it was okay to download programs to try them out if I delete them within 24 hours."
Fact: This is a common Net Myth. You may only use the software as described in the end-user license
provided by the software publisher.

Myth: "..there is something called 'freedom of speech' in this country..?"


Fact: Free speech refers to your right to provide opinions and original content without censure. Even so,
free speech has limits. You cannot use this right to break the law. Internet sites that provide access to
others' copyrighted materials - whether it's on the same site or a remote site - violate the author's right to
control distribution of their works, which is against the law.

Myth: "What about "fair use"? I am only providing a service for "educational purposes."
Fact: Fair use is widely accepted to mean the reproduction of a part of a copyrighted work, not the
wholesale copying of an entire program or contributing to software piracy.

Myth: "I only post serial numbers."


Fact: Legal software comes with required numbers or keys to install the software. It should not be
necessary to get these off the Internet. Providing them for others to use with pirated software contributes
to copyright infringement and is illegal."
Myth: What if I lose my serial number or one of my disks is trashed?
Fact: Most software publishers have provisions for replacing media. Contact them to resolve your
problems.

Myth: Writing a book about robbing banks and robbing them yourself are two different things, not?
Fact: A better analogy is "robbing the bank" vs. "driving the getaway car." Or, another analogy is stealing
software vs. marking the computer store window with an big X and telling people that, if they throw a brick
at the X, they can steal the software in the store window. Both are illegal.

Myth: Software is so expensive, and I've wasted a lot of money just to find out that an expensive program
is worthless! If it's any good, then I'll reward the authors. If not, forget the compensation!
Fact: Cars are expensive, too, but society doesn't allow people to use them and decide later if they want
to pay for them or not. In the same way, you cannot use pirated software and pay for it only if you want
to at some later date.

Myth: Isn't everything on the Internet in the public domain?


Fact: An author does not waive copyrights by publishing on the Internet. Pirated software is published on
the Internet by someone other than the author or without the author's explicit permission.

Myth: It's not really illegal to distribute warez.


Fact: An author can seek civil damages in the amount of their actual value, or statutory damages of
$100,000 per work infringed. (Note that some "programs" are actually bundles of more than one
copyrighted work.) Criminal penalties include fines of up to $250,000 and jail terms up to 5 years, or both.
In December 1997, President Clinton signed a law called the "No Electronic Theft" (NET) Act that allows for
criminal prosecution of copyright infringement, even where there is no profit motive, closing a loophole in
U.S. copyright law.

Thoughts and comments from Crackers


Since I've published this FAQ, I've received a number of letters from former and still active crackers which
told me their thoughts about my lines.

"Why the hell should a Cracker provide Richey with tips for his page!", you might ask yourself.. ;-)

As already mentioned, I don't believe that Software protection is the answer to all sales-related problems
(think of the enourmous -also financial!- success of some popular Freeware products, Open Source
projects and not the least weak protected programs like WinZip and so many others!) ... in most cases the
main reasons why developers don't see money is because they are producing the 1000'th clone of already
popular products, provide poor quality or simply don't have any idea of 1) really innovative products 2)
good design and 3) marketing.

However, there ARE reasons why protection might make sense. One of them might be the following: you
are investing 2 years (or many months) of hard work in a brand-new product with some new, advanced
features or logic no one else on the market has ever offered before. You have a limited number of potential
customers for which your product might be of real interest - but want to protect some specific parts of
your program from being reengineered or simply copied -> you need a working protection for that...

Well, I have to admit that I've been suprised that at least some crackers accept that and especially that
some of them even decided to provide us all with tips how to protect our work in a better way. Let me tell
those fair guys a big "THANK YOU" at this place.

BuLLeT's contribution
Note: I'm keeping all letters from Crackers strictly confidential except there's an explicit permission to publish them.

Links of Interest
"Contributory Copyright Infringement Lawsuit Settled Against Internet Pirate" (SPA press release)
How to battle Warez Anti-Warez Mailing List and -Tips
Anti Crack Information by Vitas Ramanchauskas
The "Sam Spade" whois tool find out who publishes Cracks for your Applications
Tracking Down Warez Sites how to find the responsible persons (page provided by Rob from Cat-Soft,
the link above)
Report Software Piracy (BSA / NoPiracy.com)
Report Software Piracy (SPA)
Decompilation page provided by the University of Queensland

Programming-related stuff

efg's CRC Lab good explanation of the "Cyclic Redundancy Check" algorithm and coding examples

Just some thoughts..


:-)
Richey
Thanks to Fravia+ (a cracker), who allowed me to quote some of his experiences and knowledge on this page.

Again: please e-mail me if you have tips or suggestions !


If you want to support my work on this page or simply say "thanks" for opening my treasure box to you, I'd be happy if you would register one of my apps!
Based on your support, page will be updated frequently. Last update: 22-Apr-99
Using Soft Ice to Hack Age Of Empires

By Shaikh Adeel

www.vngamecenter.com

In this tutorial you will learn how to hack games that use DMA (dynamic memory allocation. Ill use
AOE 2 to demonstrate using SI.

Tools Needed:
1. Softice (SI)
2. Game Trainer 2.01 or Game Hack 2.0

Lets find the addies for resources in AOE 2. First of all start Game Trainer and then the game. Start a
new game. While you are in the game see the value of your GOLD. My value was 1000. Press alt +
tab to switch to Game Trainer (GT) in WINDOWS. Select the process Empires2.exe from the process
list. From the type list choose Float coz u will find the address of GOLD in this format. In the value
tab enter the value of your GOLD and press search. You will find several matches. Go back to the
game and spende some GOLD (e.g. build a unit). See the new value of your woods. Now go back to
GT and in the value tab write the new value. Press Sieve. You will find lesser number of matches.
Repeat the same process till you find only 3 matches. Then just use the Trial and Error method to find
which address is the one you are looking for.

TRIAL AND ERROR METHOD:

When you’ll find 3 or 4 matches what you will have to do is to change each value to a different
number. For example if you have found the addresses: 00FF1212, 00FF1244, 00FF7890 you could
change the value of the first one to 10,the second to 20 and the third to 30. Now go back to the game
and see if the value of GOLD changed. Normally it must have changed to one of the numbers above. If
the number has changed to 10 then the address we are looking for is 00FF1212,if the number has
changed to 20 then the address we are looking for is 00FF1244 and so on.

Now lets continue. Note down the address you found. Because you will use softice now you won’t be
able to see this tutorial till you exit from it so you must remember this part. Go back to the game and
press Ctrl+D to bring up softice (be sure that in the down right corner the word Empires2 is written).

Most used Commands:

BPM xxxxxxxxx W this is for 1 byte

BPMD xxxxxxxx W this is for double word

CODE ON turns the Hex representation of the ASM instructions

BL Lists current Breakpoints that you have made


BC cancels the breakpoint you have made

Write this command:

bpm address w

Where address is the address you found. Let’s say that the address is 00FF1212.You should write:

bpm 00FF1212 w

The word bpm in softice sets a breakpoint to a specified address and the w means write.So with this
command we say to softice to breakpoint to the address we specified when a “new” value will be
written. Now when you write to this command press Enter and then F5.You are back to the game.
Now you must loose some GOLD. To do that, build a unit. Softice will pop up by itself and you will
see something like this:

0167:0059F9D1 897C2414 MOV [ESP+14],EDI

0167:0059F9D5 DB442414 FILD DWORD PTR [ESP+14]

0167:0059F9D9 D84C2410 FMUL REAL4 PTR [ESP+10]

0167:0059F9DD D829 FSUBR REAL4 PTR [ECX]

0167:0059F9DF D919 FSTP REAL4 PTR [ECX]

0167:0059F9E1 83C006 ADD EAX,06 <==== this will be

highlighted.

0167:0059F9E4 4A DEC EDX

If u don’t see the no of bytes then write CODE ON and press enter. In the above shown code the byte
representation is in RED.

As I write above the highlighted area is where the softice popped up. So now the general idea is to
use the NOP command (it means No OPeration and it is a special “command” for assembly) the first
command\address (beginning from the highlighted address and up) that decreases our value…That
address never changes. The command we use to decrease a value in assembly is dec or sub or
something like that. The command dec or sub will almost always be contained (e.g. it could be fsub).
So let’s check the first line above the highlighted one. The command is FSTP. Nope it’s not the one
we want…Let’s check the one that is above. FSUBR…Hmmm what’s that? It contains the sub! Maybe
it’s this one…Yes it’s this one! Ok now that we have found the address we must nop it. How can we
do that? Just follow me…As you can see this command reads 2 bytes (D829). So if we want to nop it
we will write in the command window E 0059F9DD (we write this address because that is the one of
the command. See left of the command FSUBR). The cursor will be to another window, the third from
the bottom, the data window. There just write 9090 and then press Enter (we write two 90 because
the command reads 2 bytes…. D829.So if it was reading 6 bytes we would write 909090909090).
Yes that’s it we hacked the game!!! This method can be used in all games.Now type bc * in the
command window to clear all the breakpoints (well the one we made J).Go back to the game by
pressing F5.Now whenever you build a building you will not loose GOLD!

Warning===> Some games have side effects by doing that.Age of Empires has a side effect.If you
build e.g. a unit (that costs 30 GOLD) and you have x golds (where x>=30) the current amount of your
GOLD will become 30!So if you had 1000 woods and built a unit the value would change to
30!!!This is a side effect.In most games you don’t have side effects.To remove the side effect you
must nop the address that causes it! Usually you must nop the address next to the sub address. In our
example is address 0059F9DF. So what you have to do is to nop it by using what you’ve learned so
far. When you do that and go back to the game you will see that the side effect is no longer exists!

NOTE:
This Tutorial is inspired by Miltos Raynor’s ( Miltiades ) tutorial.
U have learned here how 2 use Soft Ice to defeat DMA.
If u have any problems please mail me.
Hack Age of Empires 2 using Softice and Game Trainer 2.01

Tools:
Softice
Game Trainer

Start Game Trainer and then the game.


Start a new game (better choose Random Map).
While you are in the game see the value of your woods.
My value was 1000.
Press alt+tab to switch to Game Trainer (GM for short).
Select the process Empires2.exe from the process list.
From the type list choose Float (that’s the type of our addresses).
In the value edit box enter the value of your wood and press search.
You will find several matches.
Go back to the game and loose some wood (e.g. build a house).
See the new value of your woods.
Now go back to GT and in the value edit box write the new value.
Press Sieve.
You will find less matches.
Repeat the same process till you find only 3 or 4 matches.
Use the Trial and Error method to find which address is the one you are looking for.
Now go back to the game and see if the value of woods changed.
Write down the address you found.
Ctrl+D to go to softice (be sure that in the down right corner the word Empires2 is written).
Write this command: bpm address w where address is the address you found.
Lets say that the address is 00FF1212.
You should write bpm 00FF1212 w.
The word bpm in softice sets a breakpoint to a specified address and the w means write.
So with this command we say to softice to breakpoint to the address we specified when a one value
will be written.Instead of w we could have write r, which mean read, so that softice would
breakpoint to that address when its value would be read.But this would mislead us.Now when you
write to this command press Enter and then F5.You are back to the game.Now you must loose (not
gain) some wood.To do that build a house.Softice will pop up and in the command window (it is the
one you write the commands) you will see something like this (if you don’t see the second column in
the data window write code on and press Enter):

Break due to BPMB #0030:00FF1212 W DR3

MSR LastBranchFromIp=0059F918

MSR LastBranchToIp=0059F9A0
Above the command window is another window.The code window.In this windows you will a
something like this:

0167:0059F9D1 897C2414 MOV [ESP+14],EDI

0167:0059F9D5 DB442414 FILD DWORD PTR [ESP+14]

0167:0059F9D9 D84C2410 FMUL REAL4 PTR [ESP+10]

0167:0059F9DD D829 FSUBR REAL4 PTR [ECX]

0167:0059F9DF D919 FSTP REAL4 PTR [ECX]

0167:0059F9E1 83C006 ADD EAX,06 ç====Softice will pop up here (this will be highlighted)

0167:0059F9E4 4A DEC EDX

As I write above the highlighted area is where the softice popped up.So now the general idea is to
nop (it means no operation and it is a special “command” for assembly) the first command\address
(beginning from the highlighted address and up) that decreases our value…That address never
changes.The command we use to decrease a value in assembly is dec or sub or something like
that.The command dec or sub will almost always be contained (e.g. it could be fsub).So let’s check
the first line above the highlighted one.The command is FSTP.Nope it’s not the one we want…Let’s
check the one that is above.FSUBR…Hmmm what’s that?It contains the sub!Maybe it’s this one…Yes
it’s this one!Ok now that we have found the address we must nop it.How can we do that?Just follow
me…As you can see this command reads 2 bytes (D829).So if we want to nop it we will write in the
command window e 0059F9DD (we write this address because that is the one of the command.See
left of the command FSUBR).The cursor will be to another window,the third from the bottom,the data
window.There just write 9090 and then press Enter (we write two 90 because the command reads 2
bytes….D829.So if it was reading 6 bytes we would write 909090909090).Yes that’s it we hacked
the game!!!This method can be used in all games.Now type bc * in the command window to clear all
the breakpoints (well the one we made J).Go back to the game by pressing F5.Now whenever you
build a building you will not loose resources!
Warning====èSome games have side effects by doing that.Age of Empires has a side effect.If you
build e.g. a house (that costs 30 woods) and you have x woods (where x>=30) the current amount of
your woods will become 30!So if you had 1000 woods and built a house the value would change to
30!!!This is a side effect.In most games you don’t have side effects.To remove the side effect you
must nop the address that causes it!To find that address I use my common sense and my little
knowledge of assembly.Usually you must nop the address next to the sub address.In our example is
address 0059F9DF.So what you have to do is to nop it by using what you’ve learned so far.When you
do that and go back to the game you will see that the side effect is no longer exists!Here’s the above
code with some more notes:

0167:0059F9D1 897C2414 MOV [ESP+14],EDI

0167:0059F9D5 DB442414 FILD DWORD PTR [ESP+14]

0167:0059F9D9 D84C2410 FMUL REAL4 PTR [ESP+10]

0167:0059F9DD D829 FSUBR REAL4 PTR [ECX] ç====This is the address we must nop

0167:0059F9DF D919 FSTP REAL4 PTR [ECX] ç====This is the address that makes the side effect

0167:0059F9E1 83C006 ADD EAX,06 ç====Softice will pop up here (this will be highlighted)

0167:0059F9E4 4A DEC EDX

There are other things you can do instead of noping the address.If you want to know what keep
reading!

2.Do other things using Hiew

Tools you will need for this section:

Hiew any version


Attention:Maybe some people will think that the way I use here is stupid.Please consider that this is
the first way I learnt to do it and didn’t care to learn another way.So please don’t start flaming.

There is another thing you can do instead of noping the address.Why not making the address more
usefull?Here’s what you can do.You can reverse the command.That is instead of sub make it add!By
doing that whenever you build something you will gain money instead of loosing.For this you will
need Hiew (Hacker’s View).I will not use a game for example here.Open Hiew.Find and open the
exe file of your game using the browser of Hiew.The exe file will be in the directory where you
installed the game (when you’ll find it just highlight it and press and Enter).Wow what a mess!Now
press F4 and choose Decode from the menu.Press F5 (we do that to search a specific address) and
write .address where address is the address you found in the previous section.So if the address is
00FF1367 you must write .00FF1367 and press Enter.You will be exactly to the address we want to
change.We want to edit this one so press F3.Oh, by the way write down the bytes of this address so
you can remember them.Ok now we can write and change the command.The problem is that we can
write only numbers and we must find out which number is the command sub (well most times is
number above or below).Wouldn’t it be better to write the command add?So press F2.What’s that?
Hmm we can change the whole command as we are writing assembly!Ok clear the word sub and
write add.Now press enter and then ESC.The byte that changed is colored yellow.Compare the bytes
you have written down with the ones in Hiew.At least one is changed.In your paper write below the
number that has changed, the one that is in Hiew.Now what you have to do is go to the game and
while you are playing press Ctrl+D to go to Softice.Then write e address (where address is the
address you found in the previous section) and then write down the numbers you have in the piece of
paper (of course the new numbers with the changed byte\bytes).For example lets say the bytes were
0981 and after what you did with Hiew the byte 09 changed to 23.In softice you will have to write
2381.Easy huh?You might think it complicated but it’s not.Do it 5-6 times you’ll get used to it.

You could something else too but this is illegal because you’ll modify other’s exe file.So don’t blame
me if go to…….jail ;)!!!!!!Do it at your own risk…Let’s see now.When you change the bytes with
Hiew you can press F9 to update the exe file (you must not playing while doing that).In this way you
won’t need to go to softice every time you exit and reenter a game to change the command .
==================================
=== Age of Wonders 2: Map Hack ===
==================================
by Slurps

Hi there.... I've been working on a map hack for Age of Wonders 2 which I'm
gonna write some about. If you aren't too experienced with SoftIce and assembler
yet, I would recommend you to work on other kind of options first though(and
practicing SoftIce/assembler)... other than that, there's also gonna be a little
C++ and DirectX... but I'll just tell you what you have to know about that...

Another thing is that you have to run SoftIce in universal mode to make this
work. If SoftIce is running it's own full screen, the game won't be repainting
SoftIce which we need to happen to track down the game's drawing routines.
Well... you can track it down in other ways as well, but this is much faster and
easier so I won't bother with anything else.

If you're not running SoftIce in universal mode... just open up the video
setup/settings and hit the Universal Mode checkbox... now restart the computer.
So, that's it, time to start ;)

Finding the game's drawing-routine


¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
The first thing we'll have to do to make this work is to find the routine that
updates the screen... and by that, I mean a call which puts a whole new frame
onto the screen. (the game does this all the time... all games do...)

Start off by entering SoftIce. Right below the code window, you'll see something
like AoW2!CODE+some_number if SoftIce popped up while aow2's code was executing.
If it says something else, you'll have to close and reopen SoftIce until you're
in aow2.

Now that you're there.... this is when you need SoftIce knowledge/experience.
You have to be good at crawling around loops and functions, because that is what
you have to do now. You're gonna step out of loops and functions and execute
loops of code and just any code until SoftIce looks weird, because SoftIce will
look weird once the game updates the screen. Your aim is to get out of as many
loops and functions as possible.... the more functions you return from, the more
likely you are to run across the drawing-routine. This is something that you
HAVE to do on your own... you can appear just anywhere inside the code with
SoftIce, and there's no way I could cover all of it. Just keep in mind to check
that you're inside aow2's code, it has to say AoW2!CODE+some_number below the
code window, otherwise you're gonna have to try closing/opening SoftIce again.

In case you're curious as to what it looks like when you run across this screen
update, put a breakpoint at 4F4A9B, and then hit F10 when SoftIce breaks. This
is what it looks like and this is what you're looking for...

Once you do come across the update.... typing rs in SoftIce and hitting enter
twice will clear it up for you. rs is a command used to hide SoftIce, so that
you can see what is behind it, and it then waits for a key to be hit before it
returns... and once it returns, you'll have a new and fresh view of SoftIce.

If you have trouble getting to this call that paints the screen.... a tip is
that hitting F12 in SoftIce will bring you right below the call which executed
the function you were currently in... I'll show an example, suppose this is the
scenario:
...
push ecx
push eax
call 4785a1
mov ecx, eax
xor ebx, ebx
...

4785a1:
...
mov edx, [edx]
add ecx, edx <----- This is where SoftIce popped up
sub bl, 12
...
ret

Now.... if you hit F12... SoftIce will proceed until it gets to the ret
instruction at the end, execute it... and you're gonna be at the "mov ecx, eax"
instruction.

If you keep doing this and hit F10 ("p" command) to walk you through loops and
code and the like will get SoftIce messed up in time. Once this happens, take
note of the address of the instruction (it'll be a call, always will be...)
which messed up SoftIce.

This will take some messing around... but after doing it a few times you will
get there... you'll just stumble across it soon enough... there isn't really
much I can do to help you get to it.... but if you're familiair with SoftIce I'm
certain you'll find your way. ;)

This is the address which I found: 4F4A9B... now that you've found it, you're
gonna have to trace into(F8) that function and look for a call inside this new
function which messes up SoftIce.... and you do that over and over again...
AND... ultimately, you'll spot a call which jumps into DirectX code ;) (that
is... when it won't say AoW2!CODE+some_value below the code window, it would be
ddraw instead...)

To quickly trace into a function when the highlighted line is below the call...
you just leftclick at the call you wish to trace into, which puts the cursor
right at the call instruction... now hit F7. This will make SoftIce
automatically put a breakpoint on it, and let the game execute till it gets
there. So the call instruction will now be highlighted and you can trace into it
;)

Here are the calls I found by tracing downwards that draws onto the screen:

004F4A9B call [edx+000000C8] (first one)


004F47CB call [edx+48] (found by tracing downwards)
004F541A call [ebx+54] (found by tracing downwards)
00428410 call [eax+1C] (DirectX call)

There... the last one is the DirectX call that puts a new frame on the screen...
as it says ddraw!.text below the code window when you trace into it, you'll know
it's DirectX(DirectDraw) code that you traced into.... and that's as far as we
have to go. Now, we're gonna have a look at this call to mess up the drawing ;)
Switching surfaces
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
I've written down the instructions that call for the screen update(the DirectX
call that is), and here they are:

004283F9 push 10
004283FB mov eax, [ebp-04]
004283FE push eax
004283FF mov eax, [esi+24]
00428402 push eax
00428403 mov eax, [edi+04]
00428406 push eax
00428407 mov eax, [edi]
00428409 push eax
0042840A mov eax, [ebx+24]
0042840D push eax
0042840E mov eax, [eax]
00428410 call [eax+1C]

You should recognize this from SoftIce, where the last instruction being the
call to DirectX. You saw when tracing into it that it's DirectDraw code...
IDirectDrawSurface7 is the latest version of the Direct Draw surface(from
DirectX 7), and if you look up the debug messages, you'll find that it's calling
DirectX 7/8 functions(requires the debug build of the DirectX SDK though)...
this would be enough to look up the IDirectDrawSurface7, but if you'd want a
more sophisticated assumption you can look up how DirectX creates it's surfaces
and break on those functions(I won't cover that, as this is enough).

Now.... as this DirectDraw Surface points to a table with addresses of


functions, what you have to do is check which function [eax+1C] is. Because eax
is the base address, what you do is look up what function +1C points
towards(this is the same for all IDirectDrawSurface7 surfaces)... the address of
each function is 4 bytes long... divide 1C by 4 and you'll get 7. So we look up
the 7th function declared for the surface ;)

What you need now is ddraw.h, which comes with the DirectX SDK for version 7.0
or later(there's a ddraw.h for earlier versions of the SDK as well, but those
versions of ddraw.h are too old).... inside it you'll find this piece of
information:

DECLARE_INTERFCE_( IDirectDrawSurface7, IUnknown )


{
... (6 functions) ...
STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE7, LPRECT, DWORD)
PURE;
... (lots of functions) ...
};

Alright, there.... aow2 is calling BltFast to paint onto the screen. Here's a
reference of this function:

-----------------------------------------------------------
The IDirectDrawSurface7::BltFast method performs a source copy blit or
transparent blit by using a source color key or destination color key.

HRESULT BltFast(DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE7 lpDDSrcSurface,


LPRECT lpSrcRect, DWORD dwTrans);
dwX and dwY
The x- and y-coordinates to blit to on the destination surface.

lpDDSrcSurface
Address of an IDirectDrawSurface7 interface for the DirectDrawSurface object
that is the source of the blit.

lpSrcRect
Address of a RECT structure that defines the upper-left and lower-right
corners of the rectangle to blit from on the source surface.

dwTrans
Type of transfer. The following transfers are defined:
DDBLTFAST_DESTCOLORKEY
A transparent blit that uses the destination color key.
DDBLTFAST_NOCOLORKEY
A normal copy blit with no transparency.
DDBLTFAST_SRCCOLORKEY
A transparent blit that uses the source color key.
DDBLTFAST_WAIT
Postpones the DDERR_WASSTILLDRAWING message if the blitter is busy, and returns
as soon as the blit can be set up or another error occurs.
-----------------------------------------------------------

You might have noticed from the code disssembly that it has 6 pushes, while only
5 parameters are shown in the reference.... you can see at the declaration that
it does take 6 parameters. However, the compiler has been told to add the THIS_
variable automatically so that the programmer won't have to bother with it....
which is why only the other 5 parameters are shown in the function reference.

From this, I'll add some comments to the code:

004283F9 push 10 ; dwTrans


004283FB mov eax, [ebp-04]
004283FE push eax ; lpSrcRect
004283FF mov eax, [esi+24]
00428402 push eax ; lpDDSrcSurface
00428403 mov eax, [edi+04]
00428406 push eax ; dwX
00428407 mov eax, [edi]
00428409 push eax ; dwY
0042840A mov eax, [ebx+24]
0042840D push eax ; THIS_
0042840E mov eax, [eax]
00428410 call [eax+1C]

There.... and you should be able to add those yourself as well if you take a
look at the reference/declaration ;) ... just keep in mind that parameters are
pushed from right to left (when you look at the declaration)...

If you notice that dwX and dwY are zero even though it paints all over the
screen.... that's because when they are zero, DirectX will consider it the whole
screen ;) ... you could try changing those or the RECT structure if you'd like
to, you'll find that the screen starts looking weird or that only half of
SoftIce is messed up soon enough :P

What I've been looking for is just this... the destination surface and the
source surface. Games never paint directly onto the screen... they paint onto a
surface not situated on the screen, so that they can then put everything on
screen later on, otherwise it'll look very strange and far from smooth... as
you'll soon find out ;) First it paints the terrain... then objects/stuff..
and then comes blackness and lighting on top of that... this doesn't happen all
at once on the surface the game paints on which is not the screen(on the screen
it all does come at once)... though it does keep painting this all the time in
that order, which is what we're gonna use to hack the map.

Because THIS_ is a variable that points to the object which calls the
function... and the object is the surface which is shown on the screen(surfaces
call BltFast to paint onto themselves). The surface shown on screen is often
refered to as primary surface. Apparently, THIS_ is located at [ebx+24]... so we
now have the address which stores the primary surface.

Then.... you should see that it uses lpDDSrcSurface to read what is to be


painted onto the primary surface, and this surface is often refered to as
secondary surface(it's something like a backbuffer).

NOW.... what you do is write down the values located at esi+24 and ebx+24... the
values are 4 bytes long... if you take a look at lpDDSrcSurface, it has the lp-
prefix, meaning long pointer(and the rest of the name meaning to a Direct Draw
Source Surface)... and those are 4 bytes... so, now.... we just switch the
surfaces... to do that, you copy the 4 bytes at esi+24 into ebx+24 and the 4
bytes at ebx+24 into esi+24. As the game's other drawing routines write to the
surface pointed to by that memory, they will now be accessing the screen
instead, now that you switched them.

When the surfaces were created by the game... it wanted one to be the surface
shown on the screen, and one to paint to before it's shown. This fact won't
change when you switch them... and when you put the primary surface in place of
the secondary surface, the game will be painting to the screen while it believes
it's just painting to a surface which isn't shown to the player. Then, when it's
done painting, it'll copy what is on the screen to the secondary surface... as
you switched them.

The game isn't really worth playing anymore...... but you can see how the game
paints everything!.... you can see the landscape appear... you can see the trees
grow... how the mountains appear... anything.... ;) ... including the blackness
spreading across the screen :P

Finding the map-drawing routine


¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Our next step is to catch a call which paints the blackness... and to do that
you, do pretty much the same as when trying to catch the call which painted the
whole screen. Open up SoftIce, and then close/open it until you're both inside
AoW2 code and the blackness hasn't yet been painted. Now you're gonna need your
SoftIce knowledge again ;) .... crawl out of loops/functions until you come
along a call which messes up SoftIce. This should have the same effect as
before... just that not all of SoftIce will be painted above... just the part of
the screen which the blackness is painted on. (or... you might come along the
trees being painted or something like that, and they would also be painted above
SoftIce)

Anyway... the call I came across is located at 4653DA... you'll find other
things being painted as well nearby that call if you look around ;)
004653C0 mov edx, ebx
004653C2 mov eax, [ebx+00000260]
004653C8 mov ecx, [eax]
004653CA call [ecx+00000100] ; Paints objects
004653D0 mov edx, ebx
004653D2 mov eax, [ebx+00000260]
004653D8 mov ecx, [eax]
004653DA call [ecx+00000104] ; Paints blackness/some stuff
004653E0 mov eax, [ebx+00000190]
004653E6 mov edx, [eax]
004653E8 call [edx+78] ; Paints blackness/some stuff

However... as these calls also paint some other stuff... that's apparently not
what we want ;) (the rainbow for example, some lightning around glimmery stuff,
objects at the edge of the screen... and more...)

The first call doesn't paint the blackness every time.... but if you follow the
second call, you'll just end up at a Direct3D IM call which isn't what we
want... if we trace the first call a few times, we'll come along this call which
puts the blackness on screen:

004B165A call 0047FAEC

Then, we just trace into that call as well to see what happens... and find some
more interesting code ;) .... and in this new function, you'll find that the
call at 47FB5E also paints the screen..... as there are several conditional
jumps before this point in code, which jumps further down... let's just have a
look at them...

0047FB43 test byte ptr [eax+59], 01


0047FB47 jz 0047FB60
0047FB49 test byte ptr [eax+000000A0], 08
0047FB50 jz 0047FB60

Both of these jump below the call.... perhaps you could try changing them
(turning either of them into jmp instead) and see what happens, it's not the
right one though(but it does affect the graphics)... so we look a bit further
up:

0047FB2B cmp byte ptr [esi+00000112], 00


0047FB32 jnz 0047FB3D
0047FB34 cmp byte ptr [esi+00000113], 00
0047FB3B jz 0047FB6C

Try changing [esi+113] to 0(it should be set to 1 already)... see?... Then, try
setting the byte at [esi+112] to 0(it should also be set to 1 already)......
there, voila ;)

Apparently... these switches cleared the map for us... we can now see everything
and select things where there should have been blackness.... so that's it. Map
hacked ;) .... and this doesn't mess up the graphics for anything but the
blackness...

The cheat
¯¯¯¯¯¯¯¯¯
You should know some about code injection... otherwise, have a look at [sheep]'s
tutorial about it. Anyway.... for the cheat I just injected some code at
47FB2B(where the compare is) to set the flags to show the map... and this is the
little bit of code I injected:

mov word ptr [esi+112], 0


ret

And this is how the cheat turned out:

645FB4 66C786120100000000C3
47FB2B E884641C009090

Thanks
¯¯¯¯¯¯
Thanks a lot [sheep]... you sure did improve the quality of this tutorial a
lot... giving VERY good feedback... spotting all the problems... helping with
improvements.... thanks ;)

slurps_@hotmail.com
http://slurping.cjb.net
.________. .________.
\ | ___///__ ._________ .__///____ | \_
::::::| ____|___ ____|__ |_| /_| / .____|_____ |:::::::
:: | | __/___| | ____/| ____/ | | ::
:: | |____ \_ | | _|_|______._|___|____. | ::
:: | | | | | | | __///___| ::
:: | | | | | | | | ::
:: |_. | |_____|\_____///________|__________| | ::
:: \___///________| |[sheep] |_ | ::::::::::::
:: \__________| |_______| :: :: ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::
Gamehacking Tutorial Collection.. :: ::
::::::::::::

(best viewed in 1024x768)

SUBJECT: DECRYPTING AGE OF MYTHOLOGY - Advanced Gamehacking.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Well, it certainly has been a while since I last decided to take to the keyboard and inform
you lucky people of some of the new techniques and interesting tricks ive come across while
training the best titles the pc has to offer.. All of my tutorials from this point onward
are going to be for the experienced gamehackers, im not going to make allowances for people
who dont understand certain aspects of softice or asm, you should all be capable of working
at an advanced pace by now and if you are not then i suggest you stop reading now.

I seem to have gotten a reputation for being an asshole to newbies.. hehe.. come on .. ME?
all I have to say to this is that it takes a long time to create these tutorials and to be
honest I would be just as happy explaining this shit to JUST my friends.. and not the masses
but I feel that we all deserve a shot at creating cool trainers and understanding something
more than boring NOP hacks.. see.. im not so bad :)

TOOLS NEEDED: Softice, memory searcher (your choice) SAS (my tool for grabbing injected code).

locations...

SOFTICE.........................LOOK FOR IT!!! ITS ON THE WEB!!


MEMORY SEARCHER.................GAMEHACKING.COM or GOOGLE.COM :)
SAS(Sheeps Array of Sunshine)...MY SITE SHEEPREC.CJB.NET

SOFTICE SETUP
*************
When you press CTRL-D to pop softice you should see the following windows..

REGISTER WINDOW - this window is always at the very top of the softice window
(WR [return]) and displays the contents of all the registers..

DUMP WINDOW - generally situated close to the top of the softice window
(WD [return]) contains a split screen display.. one side is ascii the
other is hex.
CODE WINDOW - this is the main window.. sits just under the DUMP WINDOW
(WC [return]) contains the code of whatever process maybe running when
u pop softice.. the code is represented in ASSEMBLY LANGUAGE
instrutions..

The comments in the brackets are what you need to type to turn the different windows on..
you also need to type CODE ON.. this will bring up the OPCODES which are a set of numbers
displayed to the left of each ASM instruction and to the right of every memory location
in the CODE WINDOW..

Well, Its Sunday the 3rd of November 2002 and at this present time only the cheats for
AGE OF MYTHOLOGY has been rlsed to the public.. I have seen no trainers or even heard
of anyone managing a resource hack.. All this is going to change once you have read this
tutorial, I can fully understand why there are no trainers, the usual trainer muppets
that usually produce substandard trainers and then rls them onto the unsuspecting public
would have given up on this game a long time ago because you actually need to do some work
to get a working resource hack :) MAN IM GRUMPY.. :))

LESSON START
************

Sections..

i) Ground Work.
ii) Finding our values (the hard but secure way).
iii) Looking at the Decryption Routine.
iv) Code Injection (making the resource hack).
v) Final Words.

GROUND WORK
-----------

Ok, GROUND WORK is a term I use for the very first information gleaned from the game you are
trying to hack.
The first things I noticed about AGE OF MYTHOLOGY was that the searches take forever :) so its
not going to be a nice quick hack.. :( ..

After doing a few search patterns and wasting about an hour of my life I decided that the game
wasnt using the usual methods of INC/DECing the values, the only alternative was that it used
encrypted (usually XOR'ed) values which would be then converted only when the game uses them.

If there is one thing for certain in this world apart from death and tax its that commercial
programmers are lazy bastards and will certainly not do more work than is absolutely necessary,
for us this is very good news because it translates into there actually being values NOT encrypted
in the game that we CAN get a handle on to find the encrypted resources values..

APPENDED NOTE!!
===============
you can also find the values by doing a VERY long winded CHANGED/NOT CHANGED search, but i
to teach you some advanced techniques that DO have major advantages in the future, all will become
clear soon.. neways.. if you wish to obtain the values in this way be my guest but i suggest you
stick with me and do it the way I did.

FINDING OUR VALUES THE HARD BUT SECURE WAY


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

Ok, there is lots of work to do so lets get on with it. First thing we need to do is find some
values that have direct contact with the ENCRYPTED RESOURCE VALUES but are not actually encry
themselves... This is how its acheived..

Load up Age Of Mythology

Start a single player, random map

It must have 2v2 selected

Once the game has loaded up we can start looking around for something useful to us, ive already
done this bit for you to save time..

Click on the icon of the FOOD RESOURCE, this should bring up a TRIBUTE DISPLAY DIALOGBOX
with all of your resources inside.. (this is for giving supplies to your allies HENCE the 2v2 necessity).

On this screen you will notice that you have 3 boxes with the value 0 in them, all next to
the name of your allies.. these are to indicate how much resource of that type you wish to
send over. If you left click on one of the 0 boxes it should place 90 into the box, now
click the right button on the same box and it will reduce the number to 0 again, do you
feel a search pattern coming on? :)
APPENDED NOTE!!!
================
Finding options in games that are difficult to obtain usually consist of 2 things, 1. a good
logical thought process 2. good debugging skills. In this instance we need to follow a simple
logical pathway to understanding why this resource sending approach will help us.

1. RESOUCE BOX IS CLICKED


|
2. INCREASE RESOURCE_SEND_VALUE
|
3. CLICK "SEND" BUTTON ON TRIBUTE DIALOGBOX
|
4. RESOURCE_SEND_VALUE IS COMPARED TO ENCRYPTED RESOURCE VALUES *link her
|
5. INCREASE ALLIES SUPPLIES BY RESOURCE_SEND_VALUE
|
6. DECREASE YOUR SUPPLIES BY RESOURCE_SEND_VALUE *link here to real value

So you can see that the marked items on the list would be VERY valueable to us because they
are actually affecting the ENCRYPTED RESOURCES but its all linked to the FIRST STEP which is
clicking that resource box.. its just a thing to keep in mind in the future when trying to
get a handle on harder options :)

ok, lets continue..

We now need to do an inc/dec search to find this RESOURCE_SEND_VALUE, this is how we do it..

(i shouldnt need to tell you this shit but here goes)

Start an UNKNOWN VALUE search.. (4 bytes)

Click the resource box with 0 inside (90 is added).

Search Increased..

Right click the box (90 is subtracted)

Search Decreased..

REPEAT!!!

because the RESOURCE_SEND_VALUE isnt too obviously linked to the resource values it seems that
ensemble studio have given us a break and not encrypted it so you will indeed be able to locate
this address eventually.. it took me about 5 minutes to come up with this address..

2974db0 - RESOURCE_SEND_VALUE (your value MAY be different)

ok, once you have found this value we need to breakpoint it so that we can start our investigative
journey.

do this..

BPM 2974db0 <return>

the above instruction will place an OPEN breakpoint on the address which means softice
will pop every time that value is either READ or WRITTEN to..

Once you have done this exit softice with F5 until you are back in the game, make sure you
have something in the resource box to send to your allies, 90 is fine.. and then press the
SEND button at the bottom of the screen.

BANG!!

Immediately you should be looking at softice with the code below in your main code
window display..

At this point you may want to type WF to take a look at the floating point stack.

001B:0042EBD3 33FF XOR EDI,EDI


001B:0042EBD5 81C36C030000 ADD EBX,0000036C
001B:0042EBDB D906 FLD REAL4 PTR [ESI] ; load FP stack position 0 (ST
amount of resources being sent.
001B:0042EBDD D81D6CCC9300 FCOMP REAL4 PTR [0093CC6C] <--------- ; you will be
001B:0042EBE3 DFE0 FSTSW AX
001B:0042EBE5 F6C441 TEST AH,41
001B:0042EBE8 0F858A000000 JNZ 0042EC78
001B:0042EBEE D90570CC9300 FLD REAL4 PTR [0093CC70]
:u
001B:0042EBF4 8B542410 MOV EDX,[ESP+10]
001B:0042EBF8 D8A284030000 FSUB REAL4 PTR [EDX+00000384]
001B:0042EBFE D83E FDIVR REAL4 PTR [ESI]
001B:0042EC00 D95C2414 FSTP REAL4 PTR [ESP+14]
001B:0042EC04 D903 FLD REAL4 PTR [EBX] <----------- EBX contains a pointer to
to the de-crypted resource
value.
001B:0042EC06 D8642414 FSUB REAL4 PTR [ESP+14]
001B:0042EC0A D8156CCC9300 FCOM REAL4 PTR [0093CC6C]
001B:0042EC10 DFE0 FSTSW AX
:u
001B:0042EC12 F6C401 TEST AH,01
001B:0042EC15 755F JNZ 0042EC76

oki.. basically the routine above checks to see if firstly you have entered anything
to send to your allies and then to see if you actually have enough of that resource
to send..

now we must press F10(trace) until we reach location 001B:0042EC04 its marked on the
code above...

before we go on its a good idea to clear all of our old breakpoints so do this...

BC* <return>

Once you have done this we need to dump EBX into our DUMP WINDOW... so type

D EBX <return>

this will display the location stored in EBX into the DUMP WINDOW, in the top left
hand corner of the DUMP WINDOW should now be the de-crypted value of our resource.

once we have got this far we need to place yet another breakpoint on the location
now displayed in the top left hand corner of the DUMP WINDOW this breakpoint needs
only WRITE access and we place it by doing this ..

my DUMP WINDOW was at 2974eb4 so..

BPM 2974eb4 W <return>

Once this is set press F5 until you get back out into the game....

now click back on the FOOD RESOURCE icon to bring up the TRIBUTE DIALOGBOX again...

BANG!!!

LOOKING AT THE DECRYPTION ROUTINE


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

when softice pops you should be looking at the code below in your code window.

001B:0042E9C5 8B4C2434 MOV ECX,[ESP+34]


001B:0042E9C9 53 PUSH EBX
001B:0042E9CA E811791500 CALL 005862E0 <------ ; decrypt value CALL
001B:0042E9CF D91E FSTP REAL4 PTR [ESI] <------ ; you will be here.
this places the
decrypted value
into memory..its
updating our value,
thats why softice
popped.
001B:0042E9D1 8BAEF0FDFFFF MOV EBP,[ESI-0210]
001B:0042E9D7 55 PUSH EBP

ok, so now we know that the main decryption routine will live inside CALL 005862e0
because just after it the decrypted value is placed into the memory.. not always the
case but in this game it is :)

before we continue disable our old breakpoint by doing this..

BD* <return>

so, now we are here we need to breakpoint 42e9ca, this time its an executing breakpoint
so we do this..

BPX 42e9ca <return>

you could also either use your mouse to double click it (if your using one inside softice)
or you could highlight the address and then press F9.. doesnt matter as long as you
breakpoint that address..

so now.. again!! press F5 until you are back into the game..

click CANCEL on the TRIBUTE DIALOGBOX..

then click back on the FOOD RESOURCE icon...

BANG!!!

we are back where we just breakpointed.. but now we are here BEFORE the value is decrypted
so we can see exactly what is going on with our resource values :)

trace into the call at 42e9ca by pressing F8.. you now see this..

001B:005862E0 833900 CMP DWORD PTR [ECX],00 <---- ; you are here...
001B:005862E3 7419 JZ 005862FE
001B:005862E5 8B442404 MOV EAX,[ESP+04]
001B:005862E9 85C0 TEST EAX,EAX
001B:005862EB 7C11 JL 005862FE
001B:005862ED 3B057028A300 CMP EAX,[00A32870]
001B:005862F3 7D09 JGE 005862FE
001B:005862F5 50 PUSH EAX
001B:005862F6 E885FAFFFF CALL 00585D80 <----- ; main decryption routine..
001B:005862FB C20400 RET 0004

once again keep tracing with F10 until you come to 5862f6 then press F8 to
trace into the call.. you will see this...

001B:00585D80 55 PUSH EBP <----- ; you will be here...


001B:00585D81 8BEC MOV EBP,ESP
001B:00585D83 83EC08 SUB ESP,08
001B:00585D86 8B01 MOV EAX,[ECX] ;
001B:00585D88 8945FC MOV [EBP-04],EAX ;
001B:00585D8B 8B4D08 MOV ECX,[EBP+08] ; SET UP POINTERS
001B:00585D8E 8B55FC MOV EDX,[EBP-04] ;

001B:00585D91 8B048D6C9F9B00 MOV EAX,[ECX*4+009B9F6C] ; move decryption ke


001B:00585D98 33048A XOR EAX,[ECX*4+EDX] ; this instruction does the
decrypting.. it takes the
REAL RESOURCE ENCRYPTED
VALUE xor's it with the
decryption key so that
EAX will now contain the
decrypted value..
001B:00585D9B 8945F8 MOV [EBP-08],EAX
001B:00585D9E D945F8 FLD REAL4 PTR [EBP-08]
001B:00585DA1 8BE5 MOV ESP,EBP
001B:00585DA3 5D POP EBP
001B:00585DA4 C20400 RET 0004

few notes..
===========

EDX = start of YOUR RESOURCES STRUCTURE.. ie. EDX+0(GOLD) +4(WOOD) +8(FOOD) +C(F
9b9f6c = DECRYPTION KEY TABLE. consists of 5 values..
12345678...09abcdef...0badf00d...deadbeef...76543210 <-- these are all hexadecimal decryption keys..

WELL!! lots to take in there eh? .. this is where all the business goes down :)
as you can see from my description the value we really need to look at is at
address 585d98.. this address contains the REAL ENCRYPTED ADDRESS of our
RESOURCES.. so now do this..

D ecx*4+edx <return>

and if you have followed this tutorial exactly, in the top left hand corner of the
DUMP WINDOW you should now see the REAL ENCRYPTED GOLD RESOURCE VALUE...

if you now look into EAX you will see the key that is used to decrypt that RESOURCE VALUE
we can do a little test for this..

42c80000 = 100.0 in float hex notation..

^ = XOR in softice

so.. in softice type this..

?12345678^42c80000 <return>

you will get this answer.. 50fc5678

if you enter that number into the top left hand corner replacing your original encryped
RESOURCE VALUE you will have changed your gold value to 100.

press F5 to get out of softice and back to the game and you can make sure that your
gold value is indeed 100. :)

CODE INJECTION - MAKING THE RESOURCE HACK


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

We now have all the information we need to produce a working hack...

return to the game.. without the TRIBUTE DIALOGBOX showing.. now press
the FOOD RESOURCE ICON again..

BANG!!

again softice should take you to here...

001B:0042E9CA E811791500 CALL 005862E0 <------ ; you will be here.


001B:0042E9CF D91E FSTP REAL4 PTR [ESI]

press f10 to trace over the call..

then we examine the REGISTERS...


EAX = 42c80000 (this is 100.0 in hex.. its the decrypted resource value)

EBX = 0 (this is the index used to calculate what key to use from the table)

ECX = 0

EDX = 59d2010 (may be different on yours.. this is the base address of your resource structure.)

oki.. so what we got??

1. BASE address of the decryption key table.. (9n9f6c) STATIC


2. BASE address of the encrypted resource values.. (59d2010) DYNAMIC (may be different on yours)

with these 2 values and a the location to inject at 42e9cf.. we are all ready to do our injecting..

oki.. first thing to do is find a nice spot to place your injected code.. anyone that is still
reading this tutorial AND FOLLOWING IT!! will be able to do this.. so im not going to explain
how to do it.. use your fave method and keep reading once you have done this....

i chose a93e10...

so type..

A 42e9cf <return>

then type

JMP a93e10 <return> (you obviously have to use your code injection place not mine :))
nop <return>
nop <return>
nop <return>

this will balance up the bytes we just destroyed (we need to recreate them in our code injection)

oki.. im going to just give you my injected code and then explain it afterwards..

D91E FSTP REAL4 PTR [ESI] ; re-create the instruction we destroyed with our jmp
8BAEF0FDFFFF MOV EBP,[ESI-0210] ; re-create the instruction we destroyed with our
53 PUSH EBX ; save EBX onto the stack
51 PUSH ECX ; save ECX onto the stack
33DB XOR EBX,EBX ; EBX = 0
8B0C9D6C9F9B00 MOV ECX,[EBX*4+009B9F6C] ; Mov decryption key into ecx
81F10000C842 XOR ECX,46C80000 ; encrypt 25600.0 with the encryption key..
890C9A MOV [EBX*4+EDX],ECX ; move the new encrypted value back into memory
43 INC EBX ; increase loop counter
83FB04 CMP EBX,04 ; have we done ALL resources?
75EA JNZ 00A93E1C ; if we havent it will jump back and do the next resource
59 POP ECX ; restore ECX
5B POP EBX ; restore EBX
E99BAB99FF JMP 0042E9D4 ; jmp back to normal game code execution..

as you can see it looks a little more complex than your usual code injected hacks mainly
because all the code is actually specific to its location .. ie .. you wont be able to
grab the decryption keys and the BASE locations of the encrypted resource from just anywhere
they need to be taken at certain places.. well.. this is it..

what it does is takes the first BASE address of the key.. encryptes the 25600 value with the key
which gives us the value to save back into memory.. we then move this value back where it should
be and carry on to the next KEY and the next VALUE.. doing the same.. until we reach 4 which is
the end of the loop and the amount of resources we are hacking :)

GOLD is now 25600


WOOD is now 25600
FOOD is now 25600
FAVOR is now 25600

:)))

a small note.. the favor resource is regulated by other factors .. during the game it may switch back to
a lower number.. this is its maxxed number.. so dont worry about it..

SO.. now.. everytime you click on the resources and bring up that TRIBUTE DIALOGBOX you will re
all of your resources with 25600 cool eh? :)))

well, once you have done all of that i guess all that remains is to either write down all of those op
codes or you can use my SAS tool which will grab that data for you and place it into a MASM array,
anyone coding a trainer in MASM?? your the lucky ones.. :))

FINAL WORDS
-----------

Man, i love coming to the end of a tutorial.. it means my normal life can continue :).. i hope some of
you guys have learnt something new i know i sure as shit did :).. dont forget.. no matter what you
think you know.. or how good you think you are there is always someone better, so next time that newbi
asks for a little help.. do ME a favor and help him out.. its the decent thing to do..

take care of yourself and each other.. hehe JERRY!!! JERRY!!!!

until next time dudes..

******************************************************************************************
******************************************************************************************

If u have any questions or comments then email me at... sh33pr3c@hotmail.com

visit my site for more tutorials.. http://www.sheeprec.cjb.net/

I would just like to greet some people that support and inspire me....

Odin, MiraMax, KeyboardJunky, Calligula, Orr, DarkLighter, Kilby, LordFinal, ^chaos^.


MiNiSTER, [NTSC], [Drone], Rizzah, Bengi, tko..

No order.. just GREAT people..

PLEASE FEEL FREE TO SPREAD THIS DOCUMENT TO ANY SITES!!!!!


For those of you who are interested and would like to be able to disable AOM's encryption so you
can find values with your favorite memory searcher (I like Game Trainer the best) and simplify the
trainer making process a little, here is what you do.

Simply write 36 0's to address 009B9F6C. No, I'm not joking.

Now wasn't that easy?

I'm not going to go into it but I will tell you this. Starting at 009B9F6C, there is a table of 8
encryption/decryption keys:

12345678h 9ABCDEFh 0BADF00Dh 0DEADBEEFh 76543210h 41C5A90Eh 38931321h


0BAD0FEEDh

After those, there is another key used for encrypting/decrypting other values: 5AA5A5A5h

Now, the reason why we overwrite all these keys with 0 is because of the way the
encryption/decryption scheme works. Its a simple XOR. In case you didn't know, anything XOR'd
with 0 is itself. So therefore, when the program attempts to encrypt/decrypt values, they will always
be the originals.

Once you've patched your exe you can train away and find values a lot quicker. Or if you'd prefer, you
could add code to your trainer to overwrite the keys. Just remember, the game has to be launched
from the trainer so you can overwrite the keys immediately otherwise it will most likely crash after
having encrypted some values with the keys and then having them changed to 0.

NOTE: [sheep] has already done a very good job of explaining how to train this game in his
tutorial and I recommend you read it and learn it. I'm just posting this to open your eyes to a
different way of going about things and to save you some hassle on finding values.

Well that about covers it. I won't be going any deeper into this one.

Have fun dudes and keep up the good work [sheep]

- mrboggles
[Age Of Mythology v1.0]
Resource / Population Hacking

(best viewed at 1024x768)

[PREFACE]
This is my quick and dirty solution to a resource hack for
Age Of Mythology. I will say that [sheep]'s method is by far
more efficient as it only modifies YOUR resources. With this
method the game will modify everyones resources, including
the computer.

[HACKING RESOURCES]
//Begin basic n00b tutorial now
So the problem per say with Age Of Mythology is that the game
used a single function to set the values for a number of things.
It uses the function so that peasants gather resources, like
gold from a gold mine or food from a sheep. This routine was also
responsible for changing the values of the resources depending
on if you had gained or lost some. Also it seems to affect the
"tooltip" part of the game, where if you hold your mouse over
something to build, it will tell you how many resources are
required. By NOP'ing some of this function it would display the
stats for the cost of a peasant. Which in my opinion is very bad
and looks very amatuer.

So anyway to get to this routine in the first place, you need to


locate the value of one of the four resources. Let me tell you that
they are encrypted with a simple XOR opperation so you will have
to use a "changed" / "not changed" to get at them.

Eventually you should come down to like 3-5 addresses, all 4 bytes
each, and in order. For me i had 42059C8, 42059C9, 42059CA. Next
put a BPM W on the address and see if SOFTICE pops. (If you are
using TSearch, the autohack option is the same thing as a BPM)

* Referenced by a CALL at Addresses:..


:00585D38 :00585E3D :00585E90 :00585F0A :00585F5D
:00585FC1 :0058601D :00586060 :0058662C

:00585DB0 55 push ebp


:00585DB1 8BEC mov ebp, esp
:00585DB3 51 push ecx
:00585DB4 8B01 mov eax, dword ptr [ecx]
:00585DB6 8945FC mov dword ptr [ebp-04], eax
:00585DB9 8B4D08 mov ecx, dword ptr [ebp+08]
:00585DBC 8B450C mov eax, dword ptr [ebp+0C]
:00585DBF 8B55FC mov edx, dword ptr [ebp-04]
:00585DC2 33048D6C9F9B00 xor eax, dword ptr [4*ecx+009B9F6C]
:00585DC9 89048A mov dword ptr [edx+4*ecx], eax <~~~ Softice pops here.
:00585DCC 8BE5 mov esp, ebp ~~~~ [edx+4*ecx] is the location
:00585DCE 5D pop ebp ~~~~ of our resource.
:00585DCF C20800 ret 0008

If we NOP this line we will get a variety of errors that make this
a bad method of doing this hack. This prevents new values from being
written into memory, so the game will never adjust resource values or
anything else. Your villagers will chop wood forever, yet never take in
a single piece of wood. Also that display error I mentioned earlier occurs.

So here is our dilemma, we want to prevent the game from adjusting the
values but we can't do it here. Okay well, it took me a while to figure
it out because I wasn't thinking clearly. If we look at the routine in
WinDasm we see that this routine is called 9 times. If you double click on
any of the CALL addresses you will go to that part of the code. I looked
through each of the nine functions and :0058601D contained something interesting.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:..


:0058602A(C)

:00585FFE 56 push esi


:00585FFF 8BCF mov ecx, edi
:00586001 E87AFDFFFF call 00585D80
:00586006 D95C2410 fstp dword ptr [esp+10]
:0058600A 56 push esi
:0058600B 8BCB mov ecx, ebx
:0058600D E86EFDFFFF call 00585D80
:00586012 D86C2410 fsubr dword ptr [esp+10] <~~~ Its a Float subtract function.
:00586016 51 push ecx ~~~~ Change the fsubr (6C hex)
:00586017 8BCF mov ecx, edi ~~~~ to fadd (44 hex)
:00586019 D91C24 fstp dword ptr [esp]
:0058601C 56 push esi
:0058601D E88EFDFFFF call 00585DB0 <~~~ You land here.
:00586022 A17028A300 mov eax, dword ptr [00A32870]
:00586027 46 inc esi
:00586028 3BF0 cmp esi, eax
:0058602A 7CD2 jl 00585FFE
If you look up a couple lines above the call to the Move Value Into Memory
function (call 00585DB0) you will see that there is a float subtract
function. You can either NOP it, or change it to FADD so when you spend
resources, you gain them rather then loose them.

[HACKING POPULATION]
Population is controlled by another routine, the value is XOR encrypted as well.
You should get 3-4 addresses again, BPM on the last one with SI and you
should pop here:

* Referenced by a CALL at Addresses:..


:00534ECB :00535C45 :00535C5F :0053A24D

:00535760 55 push ebp


:00535761 8BEC mov ebp, esp
:00535763 83EC08 sub esp, 00000008
:00535766 8BD1 mov edx, ecx
:00535768 8B4204 mov eax, dword ptr [edx+04]
:0053576B 8945FC mov dword ptr [ebp-04], eax
:0053576E A104549B00 mov eax, dword ptr [009B5404]
:00535773 8B4DFC mov ecx, dword ptr [ebp-04]
:00535776 03C9 add ecx, ecx
:00535778 D3C0 rol eax, cl
:0053577A 8945F8 mov dword ptr [ebp-08], eax
:0053577D 8B4DF8 mov ecx, dword ptr [ebp-08]
:00535780 334D08 xor ecx, dword ptr [ebp+08]
:00535783 894A30 mov dword ptr [edx+30], ecx <~~~ SI breaks here.
:00535786 8BE5 mov esp, ebp
:00535788 5D pop ebp
:00535789 C20400 ret 0004

If you NOP :00535783 you can build as much as you want, and your population will not increase.

//end n00b tutorial

[CONCLUSION]
In conclusion, if you trace back far enough eventually you will find where the game code
actually modifies your values using your run of the mill inc/dec add/sub operations so
from there you can change it to whatever you want. However as noted above, the computer
also uses the same routines to adjust its values so when it spends, it will gain the
resources too. This is why [sheep]'s solution is proper. Mine is the simple solution,
but simple isn't always better.

^chaos^
idxchaos@hotmail.com
www.s-i-n.com/chaos/trainerology.htm

<~~greets~~>
[sheep], MiCRal, Archmage, MrNOP, Visual Perfection, MiraMax, cppdude.
#gamehacking on efnet
By Dumbhead 2003

I'm not sure if this is the correct forum for this, but the most important code I will be showing is
mostly asm, so I'll start here. Feel free to move it if it's not.

I was checking out Sheep's tutorial/trainer for Age of Mythology and figured there had to be a better
way of handling the DMA for the resource values. Turns out there is, atleast for single player mode
not sure if this works for multiplayer or not.

I won't go through all of the groundwork, as Sheep pretty much covered it.

From breaking on a memory write to the resource area after purchasing a villager, and then riding the
ret, we get back to this area of code:

CODE

5381d7 - push edi


5381d8 - lea ecx, DWORD PTR [esi+244]
5381de - call 585fe0

Through some investigating, we come to the conclusion that this is the function call that reduces your resources after you start to build
something. We find that this function is also used by the computer, so we can't just go nuts with the NOPS.

Through our own genius analysis, we figure out that ESI is a pointer to some player-specific structure, and that [ESI+244] holds the
pointer to the beginning of the resource memory for the current player being processed.

But there's no way to tell which player is currently being processed... Or is there?

In fact there is. After riding through here several times with user and computer purchases, we notice a constant pattern. The value of
ESI is always the lowest when your player is being processed. Therefore we can use the value of ESI at this juncture to tell us if this is
us or the computer. You will need to use a code cave to accomplish it.

I chose the following address for my code cave, although Im not sure if it will cause any problems later: 0x400a1f

So at 5381d7 I inject the following code:

CODE

jmp 400a1f

I don't worry about NOPing the addresses between it and the operation at 5381e3, because those addresses will never be accessed
anyway.

Anyway, at 400a1f, I then inject the following code:

CODE

offset 0x400a1f

mov eax, DWORD PTR [400a10]


cmp eax,0
je 400a5f

cmp eax, esi


jge 400a5f

push edi
lea ecx,dword ptr ds:[esi+244]
call 585fe0
jmp 5381e3

offset 0x400a5f

mov DWORD PTR [400a10], esi


mov eax, DWORD PTR [esi+244]
mov DWORD PTR [400a14], eax
push edi
lea ecx,dword ptr ds:[esi+244]
call 585fe0

jmp 5381e3

I use 400a10 as a place to hold some memory that will hold the lowest pointer value, and 400a14 will hold the pointer to the resource
memory.

First I check to see if 400a10 is zero. If it is, then this is the first time we've been here, so we go ahead and set the value to the current
value of esi.

If it is not zero, then we test the currently stored value, against the currently processed value, and if the stored value is greater or equal,
then we need to store esi. If it's not, then it's definitely a computer player, and we just execute the regular code. (We could do some
other stuff here, like reduce their resources even more, since we know for a fact that this is not us.)

There is a catch to this scheme. The value at 400a14 will not hold the pointer to the player's resource memory until the player has
purchased something. It may contain zero, or it may contain the pointer to a computer opponent's resources.

As soon as we buy a villager, however, it will point to our resources, and we can manipulate it at will.

So now what? Well, we want to set some hotkeys for our trainer which will increase the value of our resources at will. I'll do it a bit
different than sheep, instead of setting it at a fixed number, it will increase the resource by a specified number each time you hit the
hotkey. So we would have some functions like this:

CODE

void GAOM Trainer::addGold( float add )


{
DWORD addy = 0;
GProcess* proc = getCurProc();

if (!proc)
return;

addy = proc->readInt( (void*)0x400a14 );

float f = 0;
DWORD val = proc->readInt( (void*)addy );
val = val ^ 0x12345678;
memcpy( &f, &val, sizeof( val ) );
f += add;
memcpy( &val, &f, sizeof( val ) );
val = val ^ 0x12345678;

DWORD dw = val;
addM emorySet( (void*)addy, &dw, sizeof( dw ) );

setAllM emory();
}

void GAOM Trainer::addWood( float add)


{
DWORD addy = 0;

GProcess* proc = getCurProc();

if (!proc)
return;

addy = proc->readInt( (void*)0x400a14 );


addy += 4;

float f = 0;
DWORD val = proc->readInt( (void*)addy );
val = val ^ 0x09abcdef;
memcpy( &f, &val, sizeof( val ) );
f += add;
memcpy( &val, &f, sizeof( val ) );
val = val ^ 0x09abcdef;

DWORD dw = val;
addM emorySet( (void*)addy, &dw, sizeof( dw ) );

setAllM emory();
}

void GAOM Trainer::addFood( float add)


{

DWORD addy = 0;

GProcess* proc = getCurProc();


if (!proc)
return;

addy = proc->readInt( (void*)0x400a14 );


addy += 8;

float f = 0;
DWORD val = proc->readInt( (void*)addy );
val = val ^ 0x0badf00d;
memcpy( &f, &val, sizeof( val ) );
f += add;
memcpy( &val, &f, sizeof( val ) );
val = val ^ 0x0badf00d;

DWORD dw = val;
addM emorySet( (void*)addy, &dw, sizeof( dw ) );

setAllM emory();
}

void GAOM Trainer::addFavor( float add )


{
DWORD addy = 0;

GProcess* proc = getCurProc();


if (!proc)
return;

addy = proc->readInt( (void*)0x400a14 );


addy += 12;

float f = 0;
DWORD val = proc->readInt( (void*)addy );
val = val ^ 0xdeadbeef;
memcpy( &f, &val, sizeof( val ) );
f += add;
memcpy( &val, &f, sizeof( val ) );
val = val ^ 0xdeadbeef;

DWORD dw = val;
addM emorySet( (void*)addy, &dw, sizeof( dw ) );

setAllM emory();
}

These functions make use of a set of generic classes I am creating for game hacking, but you should be able to get the idea of what it is
doing. If not, ask and I'll try to explain it. Eventually I will be releasing the source to the class library. I'll also probably be releasing a fully
functional trainer with source for AoM that uses this soon. Just want to add a few more cool options I'm working on first :)

later
The Immortal Descendants

Level: Date:
Beginner Aug. 14, 2000
Training Arkanoid 2000 v1.5
The Immortal
by Muad'Dib muaddib(at)immortaldescendants(dot)org
Descendants

This is a very easy game to train and is great for the beginner. For this essay you will need Arkanoid
2000, Teraphy's Trainer Creation Kit, and MASM.

http://www.terminalstudio.com/files/arkinst.exe
http://unixfu.box.sk/files/tools/pc_tck41.zip
http://masm32.cjb.net/

For this trainer we'll be using Win Mem Search v1.0 (included in the TCK v4.1). Load up the game in
Win Mem Search and start a new game on any episode you want (easiest on Episode III).

As soon as you begin to play, notice that the score has 5 digits, seemingly a WORD for the score.
ALT+TAB out of the game and do a WORD search for 0 (or your current score) and then go back in.
Get a few points and note down the score and then ALT+TAB again. This time put in your current
score but do "Continue Search" in order to search through all of the previously obtained results. You
should only have a few results. If any at all show up in the list box, click memory patch, otherwise, if
some were found, repeat the process.

Alt+TAB back and note down your new score. Then go back to the memory searcher and find your
score as the far left value in the list box. This is the memory location for score. Why is this? Because
Win Mem Patch sets the values incrementally if it has a narrow enough array of search results. Now
we are going to do the same but with balls. Start a new game and note down how many balls you
have. Do a BYTE search this time (balls have 2 digits) and then continue to play. Each time you get a
new ball (a +1 icon falling when you hit a brick) continue the search. Once you have a narrow enough
array of results, do a memory patch and then go back and note how many balls you have. Then do the
same as you did with score to get a memory location. Here are the results I got:

BALLS - 444AAA - BYTE


SCORE - 442F1C - WORD

Now to make a trainer. I'd reccomend looking in your API guide for how to use the API functions I
use. Here is a source listing:
.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

MainDialog PROTO :DWORD,:DWORD,:DWORD,:DWORD


.data
OFFS_Points dd 442F1Ch
OFFS_Balls dd 444AAAh

ArkanoidWindow db "Arkanoid2000",0

Error_NoRun db "Arkanoid 2000 is not running...",0


Error_Write db "Error writing process memory!",0
Error db "ERROR:",0
About_Title db "About...",0
About db "Arkanoid 2000 v1.5 +2 Trainer by Muad'Dib/KNiFE",0dh,0ah,0dh
db "Greetings to OPTiCaL, Carpathia, CrackZ, sinn0r,",0dh,0ah
db "everyone in Pravus/Immortal Descendants and",0dh,0ah
db "everyone I know",0dh,0ah,0dh,0ah
db "-Muad'Dib / Aug. 4, 2000",0

.data?

hWnd_Arkanoid dd ?
pid_Arkanoid dd ?
process_Handle dd ?
number dd ?

hInst dd ?

.code

main:
invoke GetModuleHandle, 0
mov hInst, eax
invoke DialogBoxParam, hInst, 1, 0, OFFSET MainDialog, 0

MainDialog PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD


.if uMsg == WM_INITDIALOG
invoke FindWindow, 0, OFFSET ArkanoidWindow
.if eax == 0
invoke MessageBox, 0, OFFSET Error_NoRun, OFFSET Error, 0
invoke EndDialog, hWnd, 0
ret
.endif
mov hWnd_Arkanoid, eax

invoke GetWindowThreadProcessId, hWnd_Arkanoid, OFFSET pid_Arkanoid

invoke OpenProcess, PROCESS_ALL_ACCESS, 0, dword ptr [pid_Arkanoid]


mov process_Handle, eax
.elseif uMsg == WM_COMMAND
mov eax, wParam
.if eax == 100
invoke GetDlgItemInt, hWnd, 300, 0, 0
mov number, eax
invoke WriteProcessMemory, process_Handle, OFFS_Balls, OFFSET number
.if eax == 0
invoke MessageBox, 0, OFFSET Error_Write, OFFSET Error, 0
invoke EndDialog, hWnd, 0
ret
.endif
.elseif ax == 101
invoke GetDlgItemInt, hWnd, 301, 0, 0
mov number, eax
invoke WriteProcessMemory, process_Handle, OFFS_Points, OFFSET numbe
.if eax == 0
invoke MessageBox, 0, OFFSET Error_Write, OFFSET Error, 0
invoke EndDialog, hWnd, 0
ret
.endif

.elseif ax == 102
invoke ExitProcess, 0
ret
.elseif ax == 103
invoke MessageBox, hWnd, OFFSET About, OFFSET About_Title, 0
.endif
.elseif uMsg == WM_CLOSE
invoke EndDialog, hWnd, 0
.endif

ret

MainDialog ENDP

end main

I hope you enjoyed this essay and learned something. This technique can be used in many games. I
hope to bring you an essay on savegame editors and more advanced training soon.

Muad'Dib / Aug. 14, 2000

muaddib(at)immortaldescendants(dot)org
~+---------------------------------------------------------------+~

| Title: How to Make Your Own Fog Removal Trainer |

| By: Max_Power ``` |

| Date: 6-30-2003 |

| Current Game Version: 1.4 |

| Approximate Amount of Time Needed: 45 Minutes |

~+---------------------------------------------------------------+~

NOTE: THIS TUTORIAL IS BATTLEFIELD 1942 SPECIFIC. IF YOU DO NOT HAVE BATTLEFIELD

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

Table of Contents.-.-.-.-.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

1. Introduction | . | |

2. Tools of the Trade | | | . . |

3. Skills Needed | |__|

4. Trainer Compatability | | | | ' '

5. Getting the Memory Address | | | | '.......'

6. Making the Trainer |

7. Closing Statements |

--------------------------------+

_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

1. Introduction.-.-.-.-.-.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

Lets get this out of the way now:


This tutorial contains role playing. Hypothetical situations and tasks are sugges

For best viewing: Non-Maximized Notepad Window --- 1024 * 768 Monitor Resolution.

I have done my best to make this tutorial incredibly throurough, easy to understa

_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

2. Tools of the Trade.-.-.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

TSearch 1.6

Download Url: http://dlh.net/getfile.php?55:/gamehacking/memfinders/tsearch_16.zi

Description: TSearch is a very very good easy to use memory searcher. It is used

Trainer Maker Kit 1.51

Download Url: http://dlh.net/getfile.php?55:/gamehacking/trainermakers/tmk_151.zi

Description: Trainer Maker Kit is an easy to use tool for making trainers. No pro

* I apologize if these links are dead, as of the date posted in the header they w

_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

3. Skills Needed.-.-.-.-.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

Basic Computer Skills

The Ability to Follow Directions

Patience
Light Typing Proficiency

_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

4. Trainer Compatability.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

This only applies to the trainer we are making in this tutorial.

Every Total Conversion

RTR

Vanilla Battlefield 1942

:) - Pure/Non-Pure Servers - :)

1.4 Patch and Lower

This trainer will work under pretty much any condition unless it is patched by EA

This trainer will only work on your machine. The fog memory address is known as a

I am currently working on a Fog Removal trainer that uses code injection techniqu

_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

5. Getting the Memory Address.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

Start TSearch

Start Battlefield 1942


Minimize Battlefield 1942 (Alt + Tab)

In TSearch Click Open Process

Click BF1942.exe

In BAttlefield 1942 On the Main Screen:

Click Options -> Video

=-=Verify That the View Distance iS Set to 100% <---

Minimize Battlefield 1942 (Alt + Tab)

In TSearch Click the Magnifying Glass Under the Open Process Button

+=+ A Window Named Search Will Pop-Up

=-=Verify Search: Exact Value <---

=-=Verify Type: 4 Bytes <---

Enter 100 In the Value Text Box

Click Ok

+=+ A Window With a Status Bar and Numbers Will Pop-Up

When the Status Bar is full click ok.

In Battlefield 1942 Set the View Distance to 75%

In TSearch Click the Magnifying Glass With the Ellipse (...) by it Under the Open

+=+ A Window Named Search Next Will Pop-Up

=-=Verify Search: Exact Value <---

=-=Verify Type: 4 Bytes <---

Enter 75 In the Value Text Box

Click Ok

+=+ A Window With a Status Bar and Numbers Will Pop-Up

When the Status Bar is full click ok

^^- You Will Now Have 1 Address This Address Will Appear Under the Magnify Glasse

Example Address: 1EF2238

Write the Address Down

Close TSearch

Close Battlefield 1942


_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

6. Making the Trainer.-.-.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

Start Trainer Maker Kit

+=+ A Window Name Project Option Will Pop-Up

Enter FogRemover in the Project Name Text Box

Click Create

Click the Splash Screen to Make it Disappear

Click Insert -> Button

+=+ A Button Will Appear on the Interface

Right Click the Button

On the Pop-Up Click Properties

+=+ A Window Named Propterties Will Appear

In the Styles Tab Enter Remove Fog in the Caption Text Box

In the Pos Tab Enter 14 in the X-Pos Text Box ~|-|~ Enter 10 in the Y-Pos Text Bo

In the Key Tab Click Shift ~|-|~ Enter F in the Hokey Text Box

Close the Properties Window

Right Click the Button Named Remove Fog

On the Pop-up Click Write Memory Actions

+=+ A Window Named Test Script From: FogRemover

Click the Wiz Button

-!-Action to Perform Drop Down Menu:

Select Add

-!-Type of Value Drop Down Menu:

Select Word

Enter the Memory Address You Found and Wrote Down in the Address Text Box
Enter 300 in the Value Text Box

Click Apply

Click Apply

Click Insert -> Button

+=+ A Button Will Appear on the Interface

Right Click the Button

On the Pop-Up Click Properties

+=+ A Window Named Propterties Will Appear

In the Styles Tab Enter Replace Fog in the Caption Text Box

In the Pos Tab Enter 105 in the X-Pos Text Box ~|-|~ Enter 10 in the Y-Pos Text B

In the Key Tab Click Shift ~|-|~ Enter R in the Hokey Text Box

Close the Properties Window

Right Click the Button Named Replace Fog

On the Pop-up Click Write Memory Actions

+=+ A Window Named Test Script From: FogRemover

Click the Wiz Button

-!-Action to Perform Drop Down Menu:

Select Subtract

-!-Type of Value Drop Down Menu:

Select Word

Enter the Memory Address You Found and Wrote Down in the Address Text Box

Enter 300 in the Value Text Box

Click Apply

Click Apply

Right Click the Trainer Interface

Click Properties on the Pop-Up

Enter Fog Remover in the Caption Text Box

Check the Minimize Box

Click the Bottom Right Corner of the Interface to Resize the Window.
Resize the Window So That it Looks Good With the Buttons Where They Are

Regarding the Trainer Maker Kit as a Whole:

Click the Build Settings Tab Near the Bottom Left Side of the Window

Double Click the Yellow Box Right Next to the Gray Box Thats Says Process Name

+=+ The Box Will Turn White and an Ibeam Will Appear

Enter BF1942.exe

Double Click the Yellow Box Right Next to the Gray Box Thats Says Exe Name

+=+ The Box Will Turn White and an Ibeam Will Appear

Enter Fog Remover

Double Click the Yellow Box Right Next to the Gray Box Thats Says Exe Type

Select Linked

Click File Save Project to Save the Project

Click Build -> Build Your Project

Close Trainer Make Kit

You're done, the trainer executlable file is now located in the Trainer Maker Too

Remember what you named it. Once you find it put it on your desktop or wherever i

_________________________________________________________________________________

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

7. Closing Statements.-.-.-.-.-.-

,.-'`'_.,.-'`'_.,.-'`'_.,.-'`'_.,

Congratulations you now have a fully functional fog remover that works under almo

By Clicking Remove Fog or pressing Shift + F in game you reduce the fog by 300% e

By clicking Replace Fog or pressing Shift + R in game you increase the fog by 300
This trainer is more effective then the average no fog hack. The reason is becaus

****WARNING=-=-!+!****WARNING=-=-!+!****WARNING=-=-!+!****WARNING=-=-!+!****WARNI

ONLY REPLACE THE FOG AS MANY TIMES AS YOU REMOVED IT OR YOUR GAME WILL CRASH CAUS

****WARNING=-=-!+!****WARNING=-=-!+!****WARNING=-=-!+!****WARNING=-=-!+!****WARNI

--------- _____ _____ ___

| | || | |\ | | |

| |___||___ _|_ |___ | \ | | |

| | || | | | \ | | |

| | ||_____ |_____ | \| |___|

.'.

. '.' .

.'. .'. .'.


Writing a Trainer for "Beavis And Butt-head" by defiler
As I got a lot of feedback about my other trainer tutorial and more and more people in
#cracking4newbies seem to be interested in creating trainers and finding the memory locations to
patch, I decided to write another (hopefully better) tutorial for another game. There are also too few
tutorials out, explaining the process of *finding*,*analyzing* and *patching* the code/data and
afterwards writing a "self made" trainer to release it for the "scene". I chose a demo game as it is
free, fully functional, windowed and pretty small for a Windows-game.

This time we don't search the memory locations with SoftICE, we will use a famous tool called
'GameHack' (http://www.gamehack.com/), but you will need SoftICE anyway, just to have a deeper
look at the process and the stuff that is going with the data/code you want to patch in memory. Now
let's begin, run the game and have a first look.

Patching the score and writing the trainer


I assume the game is still running, time to run GameHack. Start a new game (File->New Game),
choose Beavis as player (it doesn't really play a role which character you choose, but it's fact that
Beavis is smarter :P). Now, before starting to spit onto anything (look at the game), look at your
score. It says : 0/20. Switch back to GameHack. Now press on the icon on the upper left ("Select
process for hacking").

The process list will show up, look for the name of window of the process we want to train ("Beavis
and Butt-head Hock-a-Loogie"). Select it with your mouse and click the OK-Button. Start a new
search for an *Exact value*, a type of *4 Bytes* in *Decimal* base. As Value1 you take your current
score - remember we had a score of 0/20. So you take '0' and click the OK-Button. Wait until the
search has finished (it is rather slow, because it "mirrors" the process to a temporary file on your
hard disk). A message box will be shown saying "Too many addresses found, they wont't be shown" -
click the OK-Button, the addresses have been saved. Switch to the game and try to spit onto the
bicycle, your score will be 2/20. Back to GameHack you do a "next search" and feed the textbox with
your current score (yes, 2). After you made and drunk your coffee GameHack has found a few
addresses, mine has found 3 addresses, they all contain the value "2" of course.
But we need to go on until we have the exact location where Hock-a-Loogie stores the score. We
could test it by patching different values into each address, but we don't want to crash the game
(though I assume the score sleeps in 412F74). So spit another time onto a bicycle, you will have a
score of 4/20, so you can do a next search with the value "4". Most probably you now have the exact
address. For my session it was 412F74.

So this is where SoftICE comes into play. We want SoftICE to pop up when the game accesses this
memory address (412F74) by writing to it. This can be done with the SoftICE command "bpm". It
will break on access of a specified address. You can look it up in SoftICE with the help command "h"
- just type "h bpm" and SoftICE will display a short description of the bpm command:

Breakpoint on memory access BPM[size] address [R|W|RW|X] [debug register] [IF expression] [DO
bp-action]

[size] can be one of the following types:

"b" standing for byte


"w" standing for word ( = 2 bytes)
"d" standing for double ( = 4 bytes)

We need the "double" type; remember we were searching for 4 bytes? For the "address" parameter
we take the address GameHack found (412F74), the next parameter must be "W" for write access
only, so SoftICE will break if your score increases. What we have to do now is switching back to the
game and pressing CTRL-D to get into SoftICE. Be sure the active process is the game (in this case
you will see the string "Loogie" on the bottom of the SoftICE "window" at the very right). Then you
can bpm on our address (bpmd 412F74 W). Get back to the game (x^) and score ;) Sice pops up:
:00403320 CMP DWORD PTR [0041453C],0
:00403327 JNZ 00403334
:00403329 MOV ECX,[ESP+04]
:0040332D ADD [00412F74],ECX
:00403333 RET

SoftICE broke in at relative virtual address 403333. Look at the code above, especially at RVA
40332D. It adds the double stored inside ECX to address 412F74. Remember this address? Yeah,
this MUST be the location where the score is stored, as SoftICE broke in immediately after the code
at RVA 40332D (and... by the way.. it was the address we were talking of all the time). What else can
we get from the code? It must be static data, because the code adds ECX ALWAYS to [00412F74] -
and- I do not assume that we have a case of self modifying code.

What does all that mean for our trainer?. It means we can for sure add some score by writing into that
address directly - no patching of code or seeking for the address, as it is fixed. Now it's time to begin
coding the trainer. We will use a hotkey that will add some score. GetAsyncKeyState will be the
perfect API for it. So look it up in the Win32 Programmer's reference (win32.hlp) :-

The GetAsyncKeyState function determines whether a key is up or down at the time the function is
called, and whether the key was pressed after a previous call to GetAsyncKeyState.

SHORT GetAsyncKeyState ( int vKey // virtual-key code );

excellent... now the standard stuff for doing a trainer: WriteProcessMemory is the API that we have to
use to write to memory. WriteProcessMemory needs a handle to the process to patch.

BOOL WriteProcessMemory(

HANDLE hProcess, // handle to process whose memory is written to


LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // pointer to buffer to write data to
DWORD nSize, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written );

This handle can be retreived with OpenProcess, but OpenProcess needs a process identifier .

HANDLE OpenProcess(
DWORD dwDesiredAccess, // access flag
BOOL bInheritHandle, // handle inheritance flag
DWORD dwProcessId // process identifier );

This process identifier can be retreived with GetWindowThreadProcessId, and we finally need a
handle for the window to pass to GetWindowThreadProcessId.

DWORD GetWindowThreadProcessId(

HWND hWnd, // handle of window


LPDWORD lpdwProcessId // address of variable for process identifier );

FindWindowEx returns a handle to a window:

HWND FindWindowEx(
HWND hwndParent, // handle to parent window
HWND hwndChildAfter, // handle to a child window
LPCTSTR lpszClass, // pointer to class name
LPCTSTR lpszWindow // pointer to window name );

So we finally got the basic APIs for our trainer: FindWindowEx, GetWindowThreadProcessId,
OpenProcess, WriteProcessMemory and GetAsyncKeyState. Another API that we will have to use is
ReadProcessMemory to read the game's current score to a variable, then add the value we want and
finally write it back.

The ReadProcessMemory function reads memory in a specified process. The entire area to be read
must be accessible, or the operation fails. BOOL ReadProcessMemory(

HANDLE hProcess, // handle of the process whose memory is read


LPCVOID lpBaseAddress, // address to start reading
LPVOID lpBuffer, // address of buffer to place read data
DWORD nSize, // number of bytes to read
LPDWORD lpNumberOfBytesRead // address of number of bytes read );

The memory-patching routine will be triggered after we pressed the hotkey :-

invoke GetAsyncKeyState,VK_F12

.if eax == TRUE

invoke TrainProc

.endif

Writing the trainer


First of all you create a little dialog for the trainer. I used M$ VC++ resource editor, but you can use
any other, of course. You may get some on Kaparo's Programmers tools for example. This is how my
dialog looks :-
A simple dialog with a caption and some strings, you can add a picture and other stuff, but that's not
the point of this tutorial. Save the dialog as trainer.res. IDD_DIALOG1 is a constant value and 101 as
default for VC++ Res-edit. We will have to import this Id into the trainer's source to create the
dialog, here the complete source code.

Return to Trainers

© 1998, 1999, 2000 defiler, Hosted by CrackZ. 15th September 2000.


Break Through by Chafe

What this is: An arcanoid-clone game


What we're going to do: Find a way to cheat in the game (Hehe..)
What we need to anaylze it: W32Dasm, some knowledge of win32 API
What we need to patch it: Borland resource workshop, HIEW 6+

Start up this game, and look at it. To the right you see that you have six balls left to play with. Since I'm
not very good at arcanoid, I want to have some more. ;-) Make a copy of the main .exe-file and
disassemble it. Look in the string-references for "Balls left:". You'll see that the string is a resource, with the
ID 00027. Since the string is a resource, we could tell that when the program needs to use it, it has to call
LoadStringA, and that's useful to know. If you search for it in the disassembly, you'll find that W32Dasm
finds it at many different locations, but only one is followed by a call to LoadStringA, and that's the real one.
Take a look futher down. We see a reference to the string " %u ". Now I'm really convinced, and I
think that everybody who knows the syntax for the formatspecifiers for sprintf in C is too. And what do we
see right after that? Yep, a call to wsprintfA. We've come right! ;-) The syntax for wsprintfA is:

wsprintfA( DestinationBuffer, FormatSpecifier, ... )

"..." is the arguments that should be formatted according to the FormatSpecifier and be placed as a string
in DestinationBuffer. So what does this program pass to wsprintfA?

movsx eax,si 1
push eax 2
lea ecx, dword ptr [ebp+0ffffff00] 3
push 414110 4 This is the formatspecifier, "%u"
push ecx 5
call wsprintfA 6

Okey.. We'll find the most interesting thing on the top. In this case, ecx is set to point to DestinationBuffer
at line 3, and is pushed as the first argument on line 5. The formatspecifier is pushed as the second
argument at line 4. But the things we want to know, is where it gets the number of balls left. At line 2 eax is
pushed as argument #3 (...), so at that point eax holds the number of balls left. At line 1, eax gets its value
from si, and if we look a couple of rows up, we see that si gets its value from a fixed memoryaddress with
this code:

mov si, word ptr [00416700]

Bingo! From this we could tell that the address 416700 holds the number of balls left. From this point, we
have many different ways to patch this code, let's say that we found the location where it set the value to
6 and then patched it to give us 1000 balls to play with. Or we could find the location where it decreases
the value when you loose a ball and nop it out. But if we don't always want to be cheaters then? Wouldn't it
be nice to have a button to push every time you want to have more balls? I definitely think so.. Let's open
this program in Resource Workshop. You'll see that it has a couple of dialogboxes, most of them for the
leveleditor, but the last one is the About-box. Open that one in edit-mode and simply add a button, set the
text of it to "Cheat" and make sure to note the Control ID of it. Save the whole project, start the game
and open up the about-box. Hehe, there's our nice button, but nothing happens when it's clicked. Let's fix
that! Remeber from Resource Workshop that the dialog ID of the about-box was 114? Anyways, it is. 114
is equal to 72 in hex, and that's what we need to find the message-procedure of the about-box. Back to
W32Dasm, and click the Dlg-ref button. The second last in the box is "Dialog: DialogID_072", and that's the
one we're looking for. Doubleclick it to find that it is displayed with DialogBoxParamA. This is what win32.hlp
says about that API:

int DialogBoxParam(
HINSTANCE hInstance handle to application instance
LPCTSTR lpTemplateName identifies dialog box template
HWND hWndParent handle to owner window
DLGPROC lpDialogFunc pointer to dialog box procedure
LPARAM dwInitParam initialization value
);
So the fourth argument of this API is the offset of the message procedure. Look in your disassembly, and
see that the fourth argument in this one is 40192E. This is the first point we should patch this program at,
but not yet. Let's think of what we could do in this situation. We've got a button in the dialog, the offset of
the message procedure and we've got the location where the message procedure of the dialog is set. What
if we included some of our own code into the .exe, which would check if the messages sent to the
dialogbox is WM_COMMANDs from our button, and if it is, we do some cool things, if it's not, we just pass
t he message to the original procedure? Sounds like a good idea to me! ;-) Now, we've got another
problem. Where are we going to put our code? What would Win95.CIH do in this situation? Yes! It would fill
up one of the gaps that is present in almost every PE-executable and then just make a slight change in the
header of the file to make sure that enough memory is allocated when the game is loaded. Let's do the
same! Open the .exe in HIEW and go to disassembly mode. Press F8 to get info from the header and press
F6 to get the object-table. We'll see that the biggest object is .text, and that the PhysSize of it is 11E00
bytes, but the VirtSize is only 11C8C bytes. That means that the object has 372 unused bytes at the end
of it, and that should be more than enough for our code! To find out where the used code ends, just add
the VirtSize with the RVA and the imagebase (11C8C + 1000 + 400000 = 412C8C). This will be the offset
of our code, and therefore, we could now do our first patch. We change the fourth argument to
DialogBoxParamA from 40192E to 412C8C, and now we've redirected the messages to the spot where
we're going to put our code. The next step is to write the code at 412C8C, but first we need to list what
we're going to do.

1 Check if the message is WM_COMMAND, if not go to 5


2 Check if the control that sent the message was our button, if not go to 5
3 Put the amount of balls we want in [00416700]
4 Update the window that displays the amount of balls left
5 Jump to the original message procedure

This is how we will do it:

412C8C: 817C240811010000 cmp d,[esp][00008],000000111


412C94: 7522 jne 000412CB8 WM_COMMAND = 111h
412C96: 66817C240C2004 cmp w,[esp][0000C],0041F
412C9D: 7519 jne 000412CB8 The ID for the button is 1055 = 41Fh
412C9F: 66C70500674100FF7F mov w,[000416700],02710
412CA8: 6A00 push 000 This will give us 10000 balls
412CAA: 6A00 push 000
412CAC: A1F85D4100 mov eax,[000415DF8] [000415DF8] = The HWND of the statuswindow
412CB1: 50 push eax Update it
412CB2: FF159C154200 call InvalidateRect Jump to the original message procedure
412CB8: E971ECFEFF jmp 00040192E

Now there's only one thing left, to update the header. The last byte after our code is at 412CBD. To get
new VirtSize, subtract it by the imagebase and then by the RVA of the object (412CBD - 400000 - 1000 =
11CBD). Switch to hex-mode in HIEW and go to the beginning of the file. proceed a bit and you'll see the
.text-label. The VirtSize is specified 8 bytes after the label begins, and should look like this: 8C 1C 01 00,
since the old VirtSize was 11C8C. Change it to: BD 1C 01 00, and you should be ready to go! Exit HIEW
and start up the game. It should give you six balls to play with. Open the about-box and press the Cheat-
button, and you should have 10000 balls to play with!

Chafe / The Millenium Group

-* TMG *- Copyright © 00/2001 TMG. Credits: Automatization by flaket - Web. and Stats by Statman - Gfx and design by tHE EGOiSTE
Caesar III Demo Tutorial

Requirements: Caesar 3 Demo, Memory Editor (Gamehack 2.0), Softice (Softice 3.22.)

This tutorial assumes you have softice installed and a basic knowledge of it.

1. Run the game.

2. Click "Start new game".

3. Select name.

4. How much money do you have, I started with $6,500

5. Alt-tab to windows.

6. Open Gamehack 2.0 and click "Select process for hacking"

7. Click "Caesar III" and click ok.

8. Click the binoculars to begin a new search.

9. Choose Search: "Exact value", Value 1: 6500 , Type: 2 Bytes and click ok.

10. My search returned 6 values.

11. Return to the game and spend some money, I chose build housing. (note the amount of money you have after
spending)

12. Alt-tab to windows.

13. Click the binoculars with the arrow under it for next search.

14. Enter Value 1: 6490 and click ok.

15. I have two values left, both 6490.

16. Double click both values to put it in the edit area.

17. Double click the top value and change it to 10000.

18. Double click the bottom value and change to 30000.

19. Write down both values for reference.

20. Go into the game and spend some more money noting how much you have left after spending. (I chose house again)

21. Alt-tab to windows.

22. Go into gamehack and see which value matches your money. (mine is 29990)

23. That means that the bottom value is the real one so click the top value (click on description) and delete it.

24. Now write down the real value. (mine was 00574DB8)

25. Go back into the game.


26. <ctrl-d> to pop into softice. (also type "code on" to enable code)

27. Type "bpm 00574DB8 w" and hit enter, this sets a breakpoint on your address and it will break upon any write.

28. <ctrl-d> to leave softice.

29. Spend some money. (I chose house)

004B36AA 7502 JNZ 004B36AE


004B36AC EB42 JMP 004B36F0
004B36AE 8B5508 MOV EDX,[EBP+08]
004B36B1 69D22C450000 IMUL EDX,EDX, 0000452C
004B36B7 8B828C085700 MOV EAX,[EDX+0057088C]
004B36BD 2B450C SUB EAX,[EBP+0C]
004B36C0 8B4D08 MOV ECX,[EBP+08]
004B36C3 69C92C450000 IMUL ECX,ECX,0000452C
004B36C9 89818C085700 MOV [ECX+0057088C],EAX
è 004B36CF 8B5508 MOV EDX,[EBP+08]

30. Softice pops up and highlights the purple address.

31. Since the game is subtracting money we look for a "SUB" above the code softice landed on.

004B36AA 7502 JNZ 004B36AE


004B36AC EB42 JMP 004B36F0
004B36AE 8B5508 MOV EDX,[EBP+08]
004B36B1 69D22C450000 IMUL EDX,EDX, 0000452C
004B36B7 8B828C085700 MOV EAX,[EDX+0057088C]
è 004B36BD 2B450C SUB EAX,[EBP+0C]
004B36C0 8B4D08 MOV ECX,[EBP+08]
004B36C3 69C92C450000 IMUL ECX,ECX,0000452C
004B36C9 89818C085700 MOV [ECX+0057088C],EAX
004B36CF 8B5508 MOV EDX,[EBP+08]

32. The code in green is the "SUB" command we are looking for.

33. Double click the green code in softice, that sets a breakpoint at that address. (if any problems, type in "bpx
004B36BD")

34. Type "bl" and hit enter. (this lists all current breakpoints)

35. Type "bd 00". (this disables breakpoint 1)

36. <ctrl-d> to exit softice and spend some money.

37. Notice Softice pops up on the green address.

38. Type "a" and hit enter, type "nop" enter, "nop" enter, "nop" enter and hit <ctrl-d> to exit softice. (if any problems
you can manually nop the address by typing "a 004B36BD" and then the nops.) (the reason you nop 3 times is this, the
code is 2B450C so you nop once per 2 digits, 6 divided by 2 is 3)

39. <ctrl-d> to enter softice and type "bc *" to clear all breakpoints.

40. Note that you now have unlimited money.

41. Now you can create a trainer that nops address 004B36BD 3 times, or 90 90 90 which is nop in machine language.
42. Enjoy...

Written by Logician
Proud member of X²
TUT no2
~~~~~~~
Hacking Captain Claw - Advanced GameHacking

INTRO
~~~~~
Hello boys (and girls), fans of game-hacking!

This is my second tut, "HACKING IS BETTER THAN CHEATING !"

Well, in the following I'll show you (in case you already know) how to
hack a game using it's own cheats !

THIS TUT IS A GENERAL PROPOSE HACKING, BUT I'LL USE A SKELETON GAME TO BE
MORE CLEAR ! REMEMBER, IT'S NOT A SPECIFIC GAME!

IF YOU PLAN TO LEARN SOMETHING USEFUL ( OR REMEMBER SOMETHING YOU ALREADY KNOW ),
READ THE FOLLOWING WITH THE MIND, NOT THE EYES !

===========================V I C T I M================================

The game we want to cheat in is "Captain Claw", an adventure game like


Tarzan or Lion King !

===========================T O O L S================================

So, let's begin ! For demonstration we'll need:

1) SoftIce ; you probab


2) Game Trainer or TSearch or GameHack or any other mem. finder ; guess why
3) TMK [(Trainer Maker Kit) for newbies] or any programming language ; for the t

========================H A C K - T Y P E=============================

What we'll hack ? Oh, a good question ! I will not show you how to hack
the pistol ammo or grenades (because it'll be boring and too easy !) !

Let's try to have another hack... Ah ! I got it !

This game has it's own cheats, you know. It has some cheats for the ammo,
and some good cheats that will help you much more than some bullets !

One of these is "MPJORDAN" ! If you type this in the game, your cat will jump
higher (it's called "SUPER JUMP MODE") ! But if you type the cheat, the game
will not save your finished-level and you will be treated like a fuc*ing
cheater (i.e. : no high-score etc, etc) !

SO, I'll tell u how to make a trainer that fools the game -- you will be
using the SUPER JUMP MODE, but you will not be a cheater for the game
(your game will be saved as well as the high-score !) !

================H A C K - T Y P E - E X P L A N A T I O N==================

Explanation of the game routines (in general). This routine is not valid for
money/ ammo/ health/ resources cheats, as well as any other cheat that
affects the QUANTITY (with some exceptions)...
Most of games that have their own cheats think and act like this:

1) Gamer typed in a cheat ==>


modify var1 (see bellow at variables!)

2) Gamer wants to use the benefits of the cheat (walk through walls,etc)
or it does different actions in the game or he just plays the game:

check var1. If var1=on ==> wall_through-walking, jump higher, kill enemies


with one shot etc
else ==> continue with game without cheat_benefits
check var1 again. If (var1=on) and (var2=FALSE) ==> modify var2 to TRUE

3) Gamer finishes level, reach rally_point, accomplish the mission, reach the goa

check var2. If var2=FALSE ==> good gamer, save his score, give him another
mission etc
else ==> cheater, don't save his character or score,
or the most annoying thing: put the word "CHEATER"
in the front of the screen, wrote with hate (and
the red color). Man, I hate when someone calls me
a cheater (even if I really am one :)

variables:
- var1 that holds the curent state of the cheat (ON/OFF) -- this was initially
- var2 that holds the state of the gamer (FALSE/TRUE). At first this is OK for
the user (game is started with no cheat, and var2=FALSE ==> good gamer!)
but in the moment that he typed a cheat, or the game finds var1=ON,
var2 will be against him all the game (var2:=TRUE)! And this var will NO
modified again! This means that if the gamer deactivate the cheat, he
will remain a cheater for the game and will be treated like a cheater!
In short words: THIS VAR WILL BE CHECKED AT THE END OF THE LEVEL AND IF
GAMER CHEATED ==> NO HIGH-SCORE for him !

To resolve this, we have 2 choices:

1) Trap the var2 and set it to default (FALSE ==> the gamer is "clean") even if
he cheated

2) Use that part of program that makes the good thing in games (i.e. : jump highe
be invincible etc) CALLED from a different code than the original one
(original one = the one that it's being executed when we type a cheat) !

I'm a lazy bastard and I'll show you the SECOND method !

====================H A C K - B E G I N I N G==========================

Start:

STEP 1 :Enter the game and pause it (press [ESC]). Do ALT+TAB and start the
mem. finder (in my case is Game Trainer).
As process, select Claw.exe then click the dump button! Wait until it
finished dumping the mem.

STEP 2 :Go in the game and type MPJORDAN to ACTIVATE the cheat! Pause the game
again and ALT+TAB. In Game Trainer hit the Diff button ( the "var1"
changes ! it's the one we want ! )
STEP 3 :Go in the game and type MPJORDAN to DEACTIVATE the cheat! Pause the
game again and ALT+TAB. In Game Trainer hit the Diff button ( the
"var1" changes again! )

STEP 4 :Follow SETP 2 and STEP 3 until you have ONLY a few memory addresses
( a few <= 6, less or equal ! )

STEP 5 :Look at the memory addresses and grab the ones that holds 0 OR 1
( usually, 0=cheat disabled ; 1=cheat enabled ). If none of the mem.
addr. holds 0/1, you should use REPLACE AND TEST METHOD ( fill a mem.
addr. with diff. number and test it ! if nothing happens, go for the
next mem. addr. and change it ! Repeat this procedure until you end up
at the desired place ! if this fails, it means that you didn't find the
correct addr., OR the game has some in_game_checks, OR the number you
written is not corresponding to the game calculations etc, etc ! In thi
case you must "play" more with the found addr. ! ) ...
Fortunately, we have a memory addr. that holds 0/1 ! It's a static one,
and let's say it's 3021000 !

STEP 6 :OK ! Address found ! To check this is the right address, switch it
( 0:=1 or 1:=0 ) and go inside the game ! If you have the cheat ON, go
ahead and jump ! You'll notice that your jump will be normal (like when
the cheat is OFF) !

STEP 7 :Now comes the SoftIce part ! Let's put a breakpoint on that address ! But
what kind of breakpoint ? Let's think : If we put a write only breakpoi
SoftIce will pop only when we type a cheat ! We don't need that ! We wa
SoftIce to pop when the game checks if the cheat is ON\OFF. This means
game reads the addr., then do the check ! So, we'll put a read_only bre

BPM 3021000 R

STEP 8 :Jump inside the game to pop SoftIce ! SI popped, take the instruction's
address ! Press F5 again, take the instruction's address ! Mmmmm, we ha
2 different addresses... F5, SI popped at the previous address ! Wow !
F5 again, SI pop at the same address ! What the fuc* ? F5 UNTIL you are
back in the game ! You will notice that you will have ONLY 2 addresses
Why's that?

xxx:xxx:xxx cmp byte ptr [3021000],0


xxx:xxx:xxy jz ? ? ? (SI popped here at first time)
................................ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

yyy:yyy:yyy cmp byte ptr [3021000],0


yyy:yyy:yyz jz no_cheat_code_processing (SI popped here many times)
mov ecx,[~~~] ~~~~~~~~~~~~~~~~~~~~~~~~~~~
mov eax,[@@@]
add eax,ecx interesting...
................................ ~~~~~~~~~~~~~~

STEP 9 :SI kept popping at the second address. And the pops were during the
different altitudes the cat reached from the time you jump! This means
only one thing : WE HAVE FOUND THE CODE THAT MAKES YOU JUMP HIGHER WHEN
THE CHEAT IS ENABLE !
Game is checking the cheat state ! If the cheat is OFF, jump to the
non_cheating code (that lowers your jump) ! If the cheat is ON, process
the code for the SUPER JUMP MODE !
STEP 10 :If you want to build a trainer, all you have to do is to patch the memor
to change the conditional jump jz at yyy:yyy:yyz into a jnz (or 2 nops
But what about the first address where SI popped at the first time
(at xxx:xxx:xxx)? And what about that "add eax,ecx" ? Can this be the
calculation of the altitude (i bet it is :)? Strange questions, heh ?

========================T R A I N E R - C R E A T I O N============

I'll skip this part, I assume you already know how to use TMK !

NOTE : At this type of hacking, you mustn't poke in memory big numbers (of money,
resources, etc), you must patch the game's code in memory !

===========================L E G A L - S T U F F=====================

Nothing to say here, you can have this tut on your sites, you can change it if
you have better ideas or if I did some mistakes - correct me !

Questions, comments are welcomed !

Bye for now, see you soon !

Sorin ( Splinter@email.ro ).

2003

[BEST VIEWED WITH NOTEPAD 800X600]

eof
Tutorial Author: Razali Rambli @ Bie
Email: razali_bie@hotmail.com
Homepage: http;//bie.cjb.net

Tool:

Tsearch

Bie Code Cave tool (http://bie.cjb.net)

This is a not a tutorial on Tsearch, this is a tutorial on how to make God Mode and Instant Kill in Cold Zero Demo.
So it is required to you to know Tsearch to be able to follow this tutorial.

ColdZero v2.0.12 Demo


1. search for health value, simple, just use the 100% as pointer
2. found it, and put autohack on it break here in autohack

CODE
004998c3 895040 mov [eax+0x40],edx
004998c6 8B4DDC mov ecx,[ebp-0x24]
004998c9 C781FC01000001000000 mov dword ptr [ecx+0x1FC],0x1
004998d3 8B4DDC mov ecx,[ebp-0x24]
004998d6 E8F59BF6FF call 0x004034D0
004998db 85C0 test eax,eax

3. put r/w bpx on your health address, found this, look at register, yep... only our pointer... not
shared between human and ai.

CODE
004a51d4 837A4000 cmp dword ptr [edx+0x40],0x0
004a51d8 7F29 jg short 0x004A5203
004a51da 8B45E8 mov eax,[ebp-0x18]
004a51dd 8B8888030000 mov ecx,[eax+0x388]
004a51e3 E8B882F7FF call 0x0041D4A0

4. use my Code Cave tool on it, make code cave at address 40032F

my code cave 1st part:


CODE
0040032f 891521034000 mov [0x400321],edx
00400335 817A4000000000 cmp dword ptr [edx+0x40],0x0
0040033c 0F8FC14E0A00 jg 0x004A5203
00400342 E9934E0A00 jmp 0x004A51DA

my code cave 2nd part:


CODE
00400347 390521034000 cmp [0x400321],eax
0040034d 7407 je short 0x00400356
0040034f C7404000000000 mov dword ptr [eax+0x40],0x0
00400356 8B4DDC mov ecx,[ebp-0x24]
00400359 E96B950900 jmp 0x004998C9
jmp to my code cave 1st part:
CODE
004a51d4 E956B1F5FF jmp 0x0040032F
004a51d9 90 nop

jmp to my code cave 2nd part:


CODE
004998c3 E97F6AF6FF jmp 0x00400347
004998c8 90 nop

5. i test it, get hit or get shot, my life still 100%, get hit more than enough that should make my life
reach 0, but the life bar still show 100 and i still alive, try to hit all the enemy, they all die instantly...
huahahaha...

GOD MODE & INSTANT KILL trainer for Cold Zero Demo source code by ßié (if u use this, give proper
credit)
How to make instant build trainer Tutorial -- by Groza / May 2001

Target: Red Alert 2 version 1.004

I wrote this tutorial in order to show you how I made the instant build
option in my trainer for Red Alert 2. Because of a great demand I will
write how to make reveal map and skip mission options too. All the tutorials
will be available to download from my page http://grozatt.cjb.net so check
it out time to time.

WHAT WE NEED ?
--------------
- SoftIce ( the best tool, can't live without it )
- Winhack

To make an instant build trainer we have to find out the code that
cares(calculates) how long something will be building. There are many
possibilities how to find it out. I will explain just one of them, which
worked fine with me. Now if we think a little, there should be some parameter
in memory that is increasing or decreasing(depends on the game) during the
build. We are going to find it out.
So let's start building something. Now during building process we have to
find all the memory locations which are decreasing or increasing. First we
will try to find out those which are decreasing. In the game we start
building Barracks and as soon as it starts we pause the game(we press ESC),
ALT+TAB to WinHack choose the process of RedAlert 2(game.exe) and start
searching the locations. Then ALT+TAB back to the game, unpause and wait a
little. Back ALT+TAB to Winhack and use the -has decreased- option to search
only those memory locations which were decreased since the last search.
Then back to the game... we need to repeat doing this till we don't find only
one or few locations.
In Winhack we can also use other options like -has decreased by Less than %-
which can be very useful but I won't explain them here.

OK, everything should come well and we find the location(by me is 88FCEEC).
Let's check it out.

Back to the game and ALT+D to Softice. Be sure that we are in RA2(game.exe)
and not in some other process. Let's put a breakpoint on the address
bpmb 88FCEEC w and ALT+D to return to the game. SoftIce should pop up.

We should see something like this:

:004B9529 mov ecx, dword ptr [esi+68]


:004B952C push edi
:004B952D call 004E5470
:004B9532 mov eax, dword ptr [esi+5C]
:004B9535 mov [esi+58], 00
:004B9539 sub eax, edi <-this decrease our counter
:004B953B mov dword ptr [esi+5C], eax
:004B953E cmp dword ptr [esi+24], 00000036 <---interesting
:004B9542 jne 004B9574
Hm, let's patch it !!! Instead of sub eax, edi let's modify it by
sub eax,eax ! In this way we will decrease the counter so it should build
the thing instantly. Let's modify it, disable all breakpoints and back to
the game. What???#%&%#& Nothing happen. :(

But don't give up, let's check that cmp at the 004B953E. Seems it's comparing
the location pointed to [esi+24] with 36 hex. Let's check it out, disable
all breakpoints and put a bpmb [esi+24] w.

Back to the game and softice pop up here:

:004B94BF 8B4638 mov eax, dword ptr [esi+38]


:004B94C2 8B5624 mov edx, dword ptr [esi+24]
:004B94C5 03D0 add edx, eax
:004B94C7 895624 mov dword ptr [esi+24], edx
:004B94CA A15453A300 mov eax, dword ptr [00A35354]
:004B94CF 8B54240C mov edx, dword ptr [esp+0C]

Hm, we can see that here is some other counter, which increases something.
And when it reaches 0x36 it is done. OK, let's modify the code in this
way then:

mov edx, 36
nop //this 3 additional nops are because this instruction is
nop //shorter than that we've replaced
nop
mov dword ptr [esi+24], edx

OK, disable all breakpoints and let's go back to the game. YES, IT WORKS !!!!
We have the instant build. Now we only need to make a trainer that will
modify the code when we press a button.
And that's all that has to be done. Easy isn't it ?

Please check the tutorial section on my page to find out more about
writing a trainer...

Greetz to MICRaL from TekZ 8193 for trying to make my page better !

From the heart of the winter,


Groza

Email: grozatt@email.si
Web: http://grozatt.cjb.net
Tutorial Author: Razali Rambli @ Bie
Email: razali_bie@hotmail.com
Homepage: http://bie.cjb.net
Other known method to contact the author

http://www.gamehacking.com/ipb/index.php

http://www.devious.tsongkie.com

http://www.extalia.com

Introduction:
I have seen lots of trainer for this game and have try it all. They are great trainer with infinite money, power, speed build, etc.

But the bad thing is, all the trainer also give benefit to the AI (computer player) thus making it is more difficult than ever.

So, after I get a tips from The Lord Of The Gamehacking, [sheep] I manage to get speed build for Command and Conquer General Zero Hour.

I decided to created a tutorial on making one side speed build starting from Red Alert 2. I hope I have time to make tutorial for One Side speed
build for General Zero Hour.

**[Sheep] you are a great teacher, thank you. :D

So, let get started and enjoy the tutorial. Remember, this is not a tutorial on using the tool, this is a tutorial on making speed build option. Learn
to use the tool and read the method tutorial.

Razali Rambli @ Bie


Sarawak, Malaysia

Target

Red Alert v1.00

Tools

1. Tsearch http://membres.lycos.fr/tsearch/
2. Bie Code Cave Tool http://bie.cjb.net

Method

1. Code Injection, Code Cave and Staple Intersection http://www.sheeprec.cjb.net


2. Pointer http://www.voidofmind.com/eedok/index.php

Collecting Info

When we building something in Red Alert 2, we don't see a numeric value to give us a hint on our building progress. The only indicator are a
layer of translucent blue on top of the building we wish to build and it will move clock wise to show us the building progress.

Choosing the search method

Since we don't know how much is the value are, we can choose 3 type of search in Tsearch

1. Unknown, Increase
2. Unknown, Decrease
3. Unknown, Change, Not Change

Starting the search

Choose one of the search method above, for this tutorial, I choose the 1st method. Remember, different game have different method.

1. Build and pause


2. Do unknown search
3. Unpause and pause again
4. Search 1 byte increase
5. Repeat step 3 and 4 until you find your address.

Opcode

After you have found the address, we have to put a write breakpoint on it to get to the opcode that control the value.

In autohack, we will land here

Offset Hex Asm Detail


004b8e82 8B 56 24 mov edx,[esi+0x24] Move our value to edx register
004b8e85 03 D0 add edx,eax Add our value with value from eax register
We land here
004b8e87 89 56 24 mov [esi+0x24],edx
Move our new value back into our address

Write breakpoint on our address [write pointer]


So, from the opcode above, we know that our write pointer reside in esi register.

Then I let the game finish building and I look at my address, the value inside it show 54, so now I know that when our value reach 54, that
mean our building is complete.

So what we need to do it just make our value that is put inside the edx register with 54 and it will build instantly.

Since this address is share between human player and AI player, we need to find a staple intersection. So to find the staple intersection, we
have to put read breakpoint on our address.

1. Pause the building by right click on the building icon, don't pause the game, just alt+tab out
2. So in autohack, put a Read/Write breakpoint on our address.
3. Get back to game and don't do nothing, just alt+tab out again.

We will find a few breakpoint. But we only need only one that are not shared. In autohack, click the read breakpoint and register it one by one
one. At Register tab, just focus on register in the bracket [ ].

4. Get back to game and don't do nothing, just alt+tab out again.

Look at the register and compare it with our pointer, if the pointer show different address with our pointer, that is not our staple intersection. So,
after looking at all the read breakpoint, only 1 opcode is not shared between human player and AI player.

Offset Hex Asm Detail


We land here
004b9410 8B 41 24 mov eax,[ecx+0x24] Move our staple intersection to eax register. ecx is our pointer and are
not shared between us and AI.
004b9413 C3 ret Return back to call opcode

Read breakpoint on our address that are not shared [Staple Intersection]

Jump, Code Cave and compare pointer

We planned our injected code.

Jump from staple intersection opcode:


1. We jump to code cave, we choose 400314
2. We move our staple intersection pointer into one address, we choose 400370. Jump back

Jump from write opcode:


1. We jump to code cave, we choose 40031e
2. We then compare our staple intersection pointer with write pointer.
3. If equal, we put 54 [decimal] = 36 [heximal] inside our value [edx]
4. If not equal, add value with eax
5. Jump back to next write opcode.

Use Bie Code Cave Tools to open the 400300 address for code injection or use Tsearch easywrite. If you don't want to make code cave there,
just use SAS at http://www.sheeprec.cjb.net

Example of Code Cave and Jump

Code Cave
Offset Hex Asm Detail
00400314 8B4124 mov eax,[ecx+0x24] jump from staple intersection, original code
move staple intersection pointer to 400370 to be compare later. our
00400317 890D70034000 mov [0x400370],ecx
code
0040031d C3 retn get back to call opcode
0040031e 393570034000 cmp [0x400370],esi compare write pointer with our staple intersection pointer
00400324 740D je short 0x00400333 if equal go to 400333
00400326 8B5624 mov edx,[esi+0x24] if not equal, recreate original code
00400329 03D0 add edx,eax recreate original code
0040032b 895624 mov [esi+0x24],edx recreate original code
0040032e E9578B0B00 jmp 0x004B8E8A jump back to normal next write opcode
00400333 BA36000000 mov edx,0x36 move 36 (hex) = 54 (dec) into edx
00400338 EBF1 jmp short 0x0040032B go to 40032B

Jump from staple intersection


Offset Hex Asm Detail
004b9410 E9FF6EF4FF jmp 0x00400314 jump to code cave

Jump from write opcode


Offset Hex Asm Detail
004b8e82 E99774F4FF jmp 0x0040031E jump to code cave
004b8e87 90 nop no operation [destroyed code]
004b8e88 90 nop no operation [destroyed code]
Command & Conquer: Renegade

Infinite Ammo Hex Cheat:


This cheat is a little complex, but with this extremely detailed guide, I am conf
So let get to the point of infinite ammo for your weapons. Just follow these step

Step 1: Download “Hex Workshop 3” and install it.


Step 2: Play C&C: Renegade until you get the weapon you want and some ammo for it
Step 3: Save the game and write down the ammo in the gun that you want to modify
Step 4: Quit the game and go back to Windows.
Step 5: Access the save game folder in your Westwood folder. So if I installed th
Step 6: Find the file that is most recently modify by looking at the “Date Modify
Step 7: Write down the file name. It should be something.sav.
Step 8: Open “Hex Workshop 3”
Step 9: Using Hex Workshop, open the file name that you wrote down in step 7. You
Step 10: Click on Edit and click on Find.
Step 11: In the “Type” drop down box, select “32 Bit Singed Long” in the value bo
Step 12: In the “Type” drop down box, select “32 Bit Singed Long” in the value bo
Step 13: In the “Type” drop down box, select “Hex Values”.
Step 14: In the “Value” box type in the “Hex” number that you wrote down in Step
Step 15: Click OK. Something should be highlighted. If not then you got the wrong
Step 16: Replace everything in that highlight with “FFFFFFFF1304FFFFFFFF”.
Step 17: Save the file and go back to Renegade and load the save game. Now that g

In case anyone did not get this step-by-step guide, then here is an example. I ha
Advanced Game Training Techniques - Tutorial 1
C&C:Tibieran Sun and Dynamic Memory Allocation

What you will learn:


Once in a while there are some games that seem impossible to train using
the "find and freeze the value" approach. These games use a dynamic
(changes all the time) memory address to store their values or other
trickery. In this tutorial you will learn how to use Softice to find the
original code in the EXE that effect your value. I have tried to keep it really
simple so that any newbie can understand the techniques used here, without
a lot of nerdy asm code listings to bore you to death. Yet again, I will
stress, this is NOT the BEST way to do this, but it works just as good and I
was just using this as a GENERAL lesson on using softice, and not trying to
teach asm.

NOTE: C&C: Tiberian Sun was protected with SAFEDISK, which has
anti-softice code in it. This tutorial assumes you have the the unpacked
executable, mostlikely available from http://www.gamecopyworld.com/.

Also it is suggested that when you setup softice, choose the universal vga
driver if possible. Most other video drivers will cause games/your system
to freeze when popping into Softice.

Things you need:


- SoftIce 3.x - 4.01 for Win9x
- Unpacked Tiberian Sun EXE file
- GameHack 2.0 or Game Trainer 2.01 (the second is the best, fastest, and
free for this tutorial)
- Very basic knowledge of ASM (assembly)

Step 1: Finding the memory address(es)


Run tiberian sun. In this first step you will look for the memory value of the
credits. Start a new game. In GDI mission one you start out with $5000.
Pause the game, and Alt + Tab into Game Trainer 2.01 (will refer to it as
GT from now on). In the process list, select the tiberian sun exe. Now in the
value tab type in 5000 and make sure that Dword is selected. Go back into
the game and then build something so that your credits decrease. Pause the
game again after your credits have stopped decreasing and go back to GT.
Type in the new value and press SIEVE (this only checks the values you
have listed in your FOUND column, kind of like GameHack's Next Search).

If your are lucky, you should have found three values. 00712A04,
00712A08, and one other one. If you only found two, load up a different
mission or reload the game again. Continue until you get three values. I will
tell you right now that the third value is random every time, and it is the
TRUE value of how much money you have, while the other two values are
for the on screen display. Play around with ...04 and ...08, you will see that
04 holds the value which 08 has to count up or down to. If you freeze these
two values at 31337, your display will say 31337 with some fluctuation (it
will try to reset itself to its real value, but since you froze the values it will
stuggle between the two values). EFFECTING 04 and or 08 WILL NOT
GIVE YOU ANY MORE MONEY, it will say that it did, but in reality it
did not. You will run out eventually, check for yourself. You CAN however
freeze the third value, but since its random every time, there really isnt a
chance that you would write a trainer for it (without a lot of work, and this
solution is much easier and faster) and you would have to refind the new
third value every time you got to a new mission, but as i said before,
sometimes this third value can not be found. So now we begin...

Step 2: Softice and some ASM background


In this section I will not teach you to set up softice, there are plenty tutorials
on the web. Just search for "fravia" on any major search engine and his elite
page of reverse engineering.

Some basic softice commands:


BPX api.call.name.here (ie: BPX messageboxexa, bp stands for break
point)
BPM memory.address.here (ie: BPM 00712A08, [b]reak [p]oint [m]emory)
CODE ON will turn on the HEXADECIMAL representation of the ASM
instructions

some basic ASM op codes:


HEX: NAME: OPERATION:
90 NOP No OPeration, which means "DO NOTHING"
MOV 1,2 Moves the value of 1 into 2

Step 3: Let the fun begin...


Okay, first off all, this is not a "clean crack" as one would call it, but for
our general learning purposes this works quite well.

Get your third random everytime memory value (i will use 00431337) ,
now pop into softice with control + d, and now type in the following
(replace my value with yours!!!!)
:BPM 00431337

Now get out of softice, use either control + d or F5. Softice should pop up
immediatley with the following:

:004B4BD0 56 PUSH ESI


:004B4BD1 8B742408 MOV ESI,[ESP+08]
:004B4BD5 8D8E80010000 LEA ECX, [ESI+00000180]
:004B4BDB E8C0C11300 CALL 005F0DA0
:004B4BE0 8B8E90010000 MOV ECX,[ESI+00000190]
:004B4BE6 5E POP ESI (<-- POPS HERE)
:004B4BE7 03C1 ADD EAX,ECX
:004B4BE9 C2D400 RET 0004

When softice poped up, it is because your memory address that you BPM'd
was accessed at this point in the code. So.. now the best general advice i
can give is to NOP the closest MOV to where SI popped. In this case it
would be the one at the address 004B4BE0. So just replace
8B8E90010000 with 909090909090, this means that it will do nothing at
this point. This can be done by typing the following at the softice prompt:
:E 004B4BE0

Another window should pop up in softice, this one called the edit window,
here you can change values in memory (like a trainer does), change those
values above with the following 909090909090, then hit enter.

Now at the si prompt type


:BC *

This will erase all the breakpoints you have set. If you do not, Softice will
continue popping up until you remove the breakpoints.

Since we effected the program at SOURCE CODE LEVEL, when the


mission is reloaded or when you go onto the next mission, no matter where
that third REAL memory value is, you will have infinity money. But wait!
What is this, the counter is sky rocketing up and up and up.. Gee.. a side
effect of not NOPing the right instructions, but rather then spend a lot more
time on this, we will now attack the on screen display counter to get rid of
that annoying constant incrementing.

STEP 4: Cosmetic Flaws...


Okay, the second that counter didn't stop, it started to annoy me. What is
happening is the value in 00712a08 is trying to catch up the the value of
00712a04. So, what you do now is
:BPM 00712a08

NOTE: YOU MIGHT HAVE TO DO THIS BEFORE STEP 3.

Okay softice pops up .. below..

:0046DEF2 8B0E MOV ECX,[ESI]


Okay all you do now is NOP it with a 9090, and it will stop the counter
from continiously counting up. Infact it will zero out the counter but due to
step 3 you will have unlimited $.

CONCLUSION:
Okay, I got bored towards the end too..but i really hope that this tutorial has
helped you understand the basics of using softice to edit memory. I
REALLY suggest you learn ASSEMBLY if you really want do do some
profesional, clean, trainers for games that use dynamic memory allocation
or other trickery.

IN GENERAL:

-search until you only have the true memory location left.
-BPM on the address
-enter the game
-do something that would effect the value (build something)
-Softice should pop up
-you will see something in the style of mov [addy], eax or sub [addy], 1 or
dec [addy], 1 ..anything in that style (LEARN ASM!@#!@#)
-now all you have to do is nop the instruction, closest to where si poped
usually works well

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques - Tutorial 1 PART II
C&C:Tibieran Sun and Dynamic Memory Allocation

What you will learn:


Once in a while there are some games that seem impossible to train using
the "find and freeze the value" approach. These games use a dynamic
(changes all the time) memory address to store their values or other
trickery. In this tutorial you will learn how to use Softice to find the
original code in the EXE that effect your value. I have tried to keep it really
simple so that any newbie can understand the techniques used here, without
a lot of nerdy asm code listings to bore you to death. This is the better way
to do the same thing, without having to worry about that on screen display
counter going crazy.

NOTE: C&C: Tiberian Sun was protected with SAFEDISK, which has
anti-softice code in it. This tutorial assumes you have the the unpacked
executable, mostlikely available from http://www.gamecopyworld.com/.

Also it is suggested that when you setup softice, choose the universal vga
driver if possible. Most other video drivers will cause games/your system
to freeze when popping into Softice.

Things you need:


- SoftIce 3.x - 4.01 for Win9x
- Unpacked Tiberian Sun EXE file
- GameHack 2.0 or Game Trainer 2.01 (the second is the best, fastest, and
free for this tutorial)
- Very basic knowledge of ASM (assembly)

Step 1: Finding the memory address(es)


Run tiberian sun. In this first step you will look for the memory value of the
credits. Start a new game. In GDI mission one you start out with $5000.
Pause the game, and Alt + Tab into Game Trainer 2.01 (will refer to it as
GT from now on). In the process list, select the tiberian sun exe. Now in the
value tab type in 5000 and make sure that Dword is selected. Go back into
the game and then build something so that your credits decrease. Pause the
game again after your credits have stopped decreasing and go back to GT.
Type in the new value and press SIEVE (this only checks the values you
have listed in your FOUND column, kind of like GameHack's Next Search).

If your are lucky, you should have found three values. 00712A04,
00712A08, and one other one. If you only found two, load up a different
mission or reload the game again. Continue until you get three values. I will
tell you right now that the third value is random every time, and it is the
TRUE value of how much money you have, while the other two values are
for the on screen display. Play around with ...04 and ...08, you will see that
04 holds the value which 08 has to count up or down to. If you freeze these
two values at 31337, your display will say 31337 with some fluctuation (it
will try to reset itself to its real value, but since you froze the values it will
stuggle between the two values). EFFECTING 04 and or 08 WILL NOT
GIVE YOU ANY MORE MONEY, it will say that it did, but in reality it
did not. You will run out eventually, check for yourself. You CAN however
freeze the third value, but since its random every time, there really isnt a
chance that you would write a trainer for it (without a lot of work, and this
solution is much easier and faster) and you would have to refind the new
third value every time you got to a new mission, but as i said before,
sometimes this third value can not be found. So now we begin...

Step 2: Softice and some ASM background


In this section I will not teach you to set up softice, there are plenty tutorials
on the web. Just search for "fravia" on any major search engine and his elite
page of reverse engineering.

Some basic softice commands:

Step 3: Let the fun begin...again...


Okay, here is the "clean crack" version of the original tutorial.

Get your third 'random everytime' memory value (i will use 00431337) ,
now pop into softice with control + d, and now type in the following
(replace my value with yours!!!!)
:BPMD 00431337 W

Now for a a little explination if you did not understand that screen shot
above. BPM is the standard command, the D represents Dword (a 4 byte
value). The W means WRITE. So, when the memory address is accessed
and WRITTEN TO softice will pop up.

Now get out of softice, use either control + d or F5. Softice should NOT
pop up immediatley this time, if it did you forgot the W. In order to trigger
SI this time, you must build something. Okay, NOW SI popped up with the
following:

:MEMORY :HEX :ASM


:004B7126 2BC3 SUB EAX, EBX
:004B7128 895C2420 MOV [ESP+20], EBX
:004B712C 8987A4010000 MOV [EDI + 000001A4], EAX
:004B7132 EB40 JMP 004B7181

Okay, what exactly has happened here? Well Tiberian Sun accessed and
WROTE to our memory address so softice poped up just after. So we know
somewhere around here, in the memory, in the code, something has
decreased our value. If you scroll up 3 lines you will see a sub eax, ebx
command. This is out target, EAX is the a value of our counter and ebx is
the value of our unit. So to get rid of this command, back in softice.

:ew 004B7126 9090


(the w stands for WORD, since we are overwriting 2 bytes, and two bytes
is equal to a word)

Now at the si prompt type


:BC *

Since we effected the program at SOURCE CODE LEVEL, when the


mission is reloaded or when you go onto the next mission, no matter where
that third REAL memory value is, you will have infinity money. No side
effects this time.

CONCLUSION:
I REALLY suggest you learn ASSEMBLY if you really want do do some
profesional, clean, trainers for games that use dynamic memory allocation
or other trickery. This was the clean crack version of the tutorial.

IN GENERAL:

-search until you only have the true memory location left.
-BPM[type{b,w,d}] ADDRESS W on the address
-enter the game
-do something that would effect the value (build something)
-Softice should pop up
-you will see something in the style of mov [addy], eax or sub [addy], 1 or
dec [addy], 1 ..anything in that style (LEARN ASM!@#!@#)
-now all you have to do is nop the instruction, closest to where si poped
usually works well

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques - Tutorial 1 PART III
C&C:Tibieran Sun and Dynamic Memory Allocation

What you will learn:


This is really a continuation of PART II. In here you will learn another approach,
besides NOP'ing. In this tutorial I will teach you how to change operations, so
basically I will be teaching you some very basic ASM. Also we will learn how to
patch a program permanently, so you don't have to run a trainer every time.

NOTE: C&C: Tiberian Sun was protected with SAFEDISK, which has anti-
softice code in it. This tutorial assumes you have the the unpacked executable,
most likely available from http://www.gamecopyworld.com/.

Also it is suggested that when you setup softice, choose the universal VGA driver
if possible. Most other video drivers will cause games/your system to freeze when
popping into Softice.

Things you need:


- SoftIce 3.x - 4.01 for Win9x
- Unpacked Tiberian Sun EXE file
- GameHack 2.0 or Game Trainer 2.01 (the second is the best, fastest, and free for
this tutorial)
- Hiew (hex editor that can decode to ASM, not necessary but useful)
- Very basic knowledge of ASM (assembly)

Step 1: Remembering PART II:


Open your command and conquer: ts executable inside of hiew (for this example I
will use HIEW 6.04, because it can decode to ASM source).
If you do not know where these values (below) came from, go read part II of this
series of tutorials. As you remember this is the program at source code level,
meaning that this is the actual code inside the exe.

From our memory hacking..


:MEMORY :HEX :ASM
:004B7126 2BC3 SUB EAX, EBX
:004B7128 895C2420 MOV [ESP+20], EBX
:004B712C 8987A4010000 MOV [EDI + 000001A4], EAX
:004B7132 EB40 JMP 004B7181

Be sure to remember that the MEMORY ADDRESS (where something is stored in


run time ..ie:004B7126) and the FILE OFFSET (when you open the file for hex
editing) for the code location are not the same. So don't try to located the code by
GOTO'ing to 004b7126, you will end up in the wrong place, or no where at all.
STEP 2: HIEW:
Okay, run HIEW. Press ALT+f2 to switch drives if you need to, locate the TS
executable. Now press F4 to change mode. You have TEXT, HEX, and DECODE.
Go into HEX mode first, press F7 to search, make sure to TAB into the HEX
Search part of the dialog, not the ASCII. Type in 2BC3895C24208987A, this is
the HEX representation of the code up above. We search for more then just the hex
of SUB EAX, EBX because that command is very common in asm so its bound to
be used a lot through out the exe. If you search for your hex and then some of the
hex right after it you are bound to get just one result.

Okay, hiew found it (well it should of). Now press F4 again and select DECODE.
This will turn all of your code into the ASM representation of it.

(I already edited the byte)

Now Press F3 to get into EDIT MODE. Move your cursor to line 004b7126, then
hit F2 (which is now labeled ASM). A dialog will pop up called ASSEMBLER.
Right now it has SUB eax, ebx written in there. In asm there are a variety
commands to subtract and add. The addition ones are: ADD & INC, and then you
might see some variations of it like FADD, but their functions are the same. Next,
the subtraction ones are SUB and DEC.

So lets think for a minute now. In the last tutorial we erased the whole SUB
routine, so that when we clicked to build a unit, no money would decrease. Now
we are going to change the SUB to an ADD, what this will do is, if you click to
build a unit, it will ADD cost of the unit to your total money, so the more you
spend, the more you earn. If you had just NOP'd it, you would have to rely on
gaining money by collecting it through your harvester.

Anyway, back to the Assembler dialog. Move your cursor under the SUB, now
type in ADD (so it looks like add eax, ebx) , then hit ENTER, and then escape to
close the dialog. To save the changes to your file, hit F9, which will update the
exe. Then you can exit with F10.

You now have a permanently patched exe file so that every time you build a unit, it
will deposit its cost into your bank account. However if you just want to write a
trainer for it, follow the part two tutorial and rather then writing 90 90 to memory,
you have to write 03 into memory in the same memory address for the first 90.
You do not need to modify the 0C (which is the second 90 in part II) because the
ADD function needs to know what values to add together.

FINAL CONCLUSION:
Here ends the series of the C&C:TS money tutorials. Possibly some more will
follow on how to make a reveal map, power, and fast build. The whole intention
was to teach you how to deal with dynamic memory allocation. I have taught you
several ways to track down the commands you need to find and how to effectively
patch them.

Why is patching the sub eax, ebx routine better then writing a trainer that writes to
that memory address every 1/10th of a second? Well first off all, with TS that isn't
possible because of dynamic memory allocation. The real bank account value is
moved around every time you play a level. Next, you only have to write to
memory 1 time, meaning that your trainer will not be a CPU hog. If you write the
value to memory every 1/10th of a second, you will use a lot of spare CPU. It is
best to patch the code in memory, and not write to it every second.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
1. Required :

a) Commandos : Behind Enemy Lines


b) GameHack v2.0 (for searching)
c) Trainer Maker Kit (for the trainer creation)

2. Finding the value

> start Commandos


> load a level or start a new game
> in the game type the cheat for *godmode* - 1982GONZO
> press now CTRL+i to activate the cheat (see top left the 'I')
> now press P to pause the game so that it not crashes when u press ALT+TAB
> press ALT+TAB to switch to the desktop
> start GameHack 2.0
> press the first button on top left (to select the process)
> select COMANDOS.EXE
> now press the 4th button (Search) from left to right and type in the value "1"
> it will say that there are many values which it won't show
> now switch to the game (ALT+TAB)
> press P again to unpause
> press CTRL+i to deactivate the cheat and then switch to GameHack again...
> now press the 5th button (Continue Search...) and type "0", 'cause u disabled t
> it would say again it found many values...
> repeat the last 2 steps till u find 3 or 4 values then switch to the game and p
> returning to GameHack u will see that one value changed according to what u did
> and use Trainer Maker Kit to create yer own trainer...
> remember to always press P to pause the game everytime u want to ALT+TAB, other

3. Stuff

If you don't manage to use this tutorial right please mail me... ==> mdk
If ya don't know how to use Trainer Maker Kit or GameHack please go to... ==> htt
Also check out my trainers and other members' at TekZ, which ya can find in the *

Wish ya luck and pls read the next releases I make... C ya...

T-RaiNeR
GAMEHACKING ... COMMANDOS 2
The tool used: TSearch.

Max ammunition for pistol = 120, rifle = 15, machine gun = 150; bazooka = 6.

PISTOL / RIFLE / MACHINE GUN / BAZOOKA Ammunition; Exact Value Search + 4 bytes +
Write

Tsearch pops up at 86752d:


0086752d FF4E04 dec dword ptr [esi+0x4]
1st option: NOP the DEC instruction so the ammunition value doesn't decrease; 909090 at 86752d.
2nd option: change from DEC to INC the instruction so the ammunition value will increase each
time you fire instead of decreasing; FF4604 at 86752d: inc dword ptr [esi+0x4].
This option can be used to help increase the ammunition value to the maximum (don't increase to a
value above the maximum).
It's enough to have 1 ammunition left for both options to work.

Max ammunition for sniper rifle = 25.

SNIPER RIFLE Ammunition; Exact Value Search + 4 bytes + Write


Tsearch pops up at 5a362f:
005a362e 49 dec ecx
005a362f 894804 mov [eax+0x4],ecx
1st option: NOP the MOV instruction so the ammunition value doesn't decrease; 909090 at 5a362f.
2nd option: change from DEC to INC the instruction so the ammunition value will increase each
time you fire instead of decreasing; 41 at 5a362e: inc ecx.
This option can be used to help increase the ammunition value to the maximum (don't increase to a
value above the maximum).
It's enough to have 1 ammunition left for both options to work.

Max ammunition for flamethower doesn't exist.

FLAMETHROWER Ammunition; Exact Value Search + 4 bytes + Write


Tsearch pops up at 81d34c:
0081d34b 48 dec eax
0081d34c 894500 mov [ebp],eax
1st option: NOP the MOV instruction so the ammunition value doesn't decrease; 90 at 81d34c.
2nd option: change from DEC to INC the instruction so the ammunition value will increase each
time you fire instead of decreasing; 40 at 81d34b: inc eax.
This option can be used to help increase the ammunition value.
It's enough to have 1 ammunition left for both options to work.

Max ammunition for syringe = 20.

SYRINGE Ammunition; Exact Value Search + 4 bytes + Write


Tsearch pops up at 8283b1:
008283b1 FF08 dec dword ptr [eax]
1st option: NOP the DEC instruction so the ammunition value doesn't decrease; 9090 at 8283b1.
2nd option: change from DEC to INC the instruction so the ammunition value will increase each
time you fire instead of decreasing; FF00 at 8283b1: inc dword ptr [eax].
This option can be used to help increase the ammunition value to the maximum (don't increase to a
value above the maximum).
It's enough to have 1 ammunition left for both options to work.

Max ammunition for blow torch doesn't exist.

BLOW TORCH Ammunition; Exact Value Search + 4 bytes + Write


Tsearch pops up at 81c543:
0081c543 FF08 dec dword ptr [eax]
1st option: NOP the DEC instruction so the ammunition value doesn't decrease; 9090 at 81c543.
2nd option: change from DEC to INC the instruction so the ammunition value will increase each
time you fire instead of decreasing; FF00 at 81c543: inc dword ptr [eax].
This option can be used to help increase the ammunition value.
You must have at least 2 ammunition left for both options to work because the game doesn't let you
use the blow torch as a weapon if you only have 1 ammunition left.

Max number for grenades = 10.

Number of GRENADES; Exact Value Search + 4 bytes + Write


Tsearch pops up at 80fc60:
0080fc5f 4A dec edx
0080fc60 8911 mov [ecx],edx
1st option: NOP the MOV instruction so the number of grenades doesn't decrease; 9090 at 80fc60.
2nd option: change from DEC to INC the instruction so the number of grenades will increase each
time you use one instead of decreasing; 42 at 80fc5f: inc edx.
This option can be used to help increase the number of grenades to the maximum (don't increase to a
value above the maximum).
For the 1st option you must have at least 2 grenades, for the 2nd option you must have at least 1
grenade.

Max number for gas grenades = 10.

Number of GAS GRENADES; Exact Value Search + 4 bytes + Write


Tsearch pops up at 80fc93:
0080fc92 4A dec edx
0080fc93 8911 mov [ecx],edx
1st option: NOP the MOV instruction so the number of gas grenades doesn't decrease; 9090 at
80fc93.
2nd option: change from DEC to INC the instruction so the number of gas grenades will increase
each time you use one instead of decreasing; 42 at 80fc92: inc edx.
This option can be used to help increase the number of gas grenades to the maximum (don't increase
to a value above the maximum).
For the 1st option you must have at least 2 gas grenades, for the 2nd option you must have at least 1
gas grenade.

Max number for smoke grenades = 10.

Number of SMOKE GRENADES; Exact Value Search + 4 bytes + Write


Tsearch pops up at 810535:
00810534 49 dec ecx
00810535 8908 mov [eax],ecx
1st option: NOP the MOV instruction so the number of smoke grenades doesn't decrease; 9090 at
810535.
2nd option: change from DEC to INC the instruction so the number of smoke grenades will increase
each time you use one instead of decreasing; 41 at 810534: inc ecx.
This option can be used to help increase the number of smoke grenades the maximum (don't
increase to a value above the maximum).
For the 1st option you must have at least 2 smoke grenades, for the 2nd option you must have at
least 1 smoke grenade.

Max number for molotov cocktails = 10.

Number of MOLOTOV COCKTAILS; Exact Value Search + 4 bytes + Write


Tsearch pops up at 80fce7:
0080fce6 4A dec edx
0080fce7 8911 mov [ecx],edx
1st option: NOP the MOV instruction so the number of molotov cocktails doesn't decrease; 9090 at
80fce7.
2nd option: change from DEC to INC the instruction so the number of molotov cocktails will
increase each time you use instead of decreasing; 42 at 80fce6: inc eax.
This option can be used to help increase the number of molotov cocktails to the maximum (don't
increase to a value above the maximum).
For the 1st option you must have at least 2 molotov cocktails, for the 2nd option you must have at
least 1 molotov cocktail.

Max number of sleeping pills for each bottle doesn't exist.

Number of SLEEPING PILLS; Exact Value Search + 4 bytes + Write


Tsearch pops up at 847c1f:
00847c1f FF0B dec dword ptr [ebx]
1st option: NOP the DEC instruction so the ammunition value doesn't decrease; 9090 at 847c1f.
2nd option: change from DEC to INC the instruction so the number of sleeping pills in the bottle
will increase each time you use it instead of decreasing; FF03 at 847c1f: dec dword ptr [ebx].
For the both you must have at least 2 sleeping pills because the game doesn't let you use the
sleeping pill bottle when it only has 1 left in it.

Max number for mines = 10, anti-tank mines = 10.

Number of MINES / ANTI-TANK MINES; Exact Value Search + 4 bytes + Write


Tsearch pops up at 825c2e:
00825c2d 48 dec eax
00825c2e 894108 mov [ecx+0x8],eax
1st option: NOP the MOV instruction so the number for mines doesn't decrease; 909090 at 825c2e.
2nd option: change from DEC to INC the instruction so the number for mines will increase each
time you use one instead of decreasing; 40 at 825c2d: inc eax.
This option can be used to help increase the number of mines to the maximum (don't increase to a
value above the maximum).
For the both options you must have at least 2 mines or anti-tank mines

Max number for packs cigarettes = 10.

Number of CIGARETTES PACKS; Exact Value Search + 4 bytes + Write


Tsearch pops up at 5caf3f:
005caf3e 49 dec ecx
005caf3f 894E04 mov [esi+0x4],ecx
1st option: NOP the MOV instruction so the ammunition value doesn't decrease; 909090 at 5caf3f.
2nd option: change from DEC to INC the instruction so the number for packs cigarettes will
increase each time you use one instead of decreasing; 41 at 5caf3e: inc ecx.
This option can be used to help increase the number of packs cigarettes to the maximum (don't
increase to a value above the maximum).
For the both options you must have at least 2 packs of cigarettes.

Max number for first aid kits = 10.

FIRST AID KIT stock; Exact Value Search + 4 bytes + Write


Tsearch pops up at 7991df:
007991de 48 dec eax
007991df 89410C mov [ecx+0xC],eax
1st option: NOP the MOV instruction so the number for first aid kits doesn`t decrease; 909090 at
7991df.
2nd option: change from DEC to INC the instruction so the number for first aid kits will increase
each time you use one instead of decreasing; 40 at 007991de: inc eax.
This option can be used to help increase the number for first aid kits to the maximum (don't increase
to a value above the maximum).
It's enough to have 1 first aid kit for both options to work.

Max number for tinned food = 10.

Number of TINNED FOOD; Exact Value Search + 4 bytes + Write


Tsearch pops up at 6b83f1:
006b83f0 49 dec ecx
006b83f1 8908 mov [eax],ecx
1st option: NOP the MOV instruction so the number for tinned food doesn`t decrease; 909090 at
6b83f1.
2nd option: change from DEC to INC the instruction so the number for tinned food will increase
each time you use one instead of decreasing; 41 at 6b83f0: inc ecx.
This option can be used to help increase the number of tinned food to the maximum (don't increase
to a value above the maximum).
For the 1st option you must have at least 2 tinned food, for the 2nd option you must have at least 1
tinned food for the 2nd option to work.

Endurance

Unknow Value Search, Has Changed, Has Not Changed + 4 bytes + Write
Tsearch pops up at 6b357e:
006b3578 D825740BAE00 fsub dword ptr [0xAE0B74]
006b357e D99E1C020000 fstp dword ptr [esi+0x21C]
1st option: NOP the FSUB instruction so the Endurance bar won't decrease; 909090909090 at
6b3578.

Underwater Air

Unknow Value Search, Has Changed, Has Not Changed + 4 bytes + Write
Tsearch pops up at 6b338c:
006b3386 D825740BAE00 fsub dword ptr [0xAE0B74]
006b338c D99618020000 fst dword ptr [esi+0x218]
1st option: NOP the FSUB instruction so the Underwater Air bar won't decrease; 909090909090 at
6b3386.

Cold

Unknow Value Search, Has Changed, Has Not Changed + 4 bytes + Write
Tsearch pops up at 6b36dd:
006b36d7 D825740BAE00 fsub dword ptr [0xAE0B74]
006b36dd D99624020000 fst dword ptr [esi+0x224]
1st option: NOP the FSUB instruction so the Cold bar won't decrease; 909090909090 at 6b36d7.

Invisibility

By using the cheat code ==> 144C303: 1 byte: 1=On, 0=Off.

Invulnerability (+max Endurance bar + max Underwater Air bar +max Cold bar +no ammunition
decrease)

By using the cheat code ==> 144C303: 1 byte: 1=On, 0=Off.

Enemy with blank ammunition

By trying to change the memory addreses around 144C303 ==>144C302: 1 byte: 1=On, 0=Off.

Victor D. "Wolverine"
From Porto, Portugal, Europe

victordwolverine@yahoo.com

victordwolverine@gamehacking.com

www.geocities.com/victordwolverine

members.fortunecity.com/victordwolverine

Copyright © 1996 - 2002 The World Of Game Hacking. All Rights Reserved.
Regulations, Trademarks and Privacy Statement are property of The World of Game Hacking.
Copyright © 1997 - 2002 The C.E.S Game Hacking Team (Cogito Ergo Sum).
Users of this site agree to be bound by the terms of the International Internet Web Site Rules and
Regulations.

This tutorial have been modify to maintain the size of this book. For tutorial + picture, please go to
http://www.gamehacking.com/
Making a Mass Kill

Target:
Crimsonland version 1.9.8
http://www.crimsonland.com

Tools:
-Softice
-Tsearch 1.6b (http://fly.to/mtc/)
-Code Cave Chaos (http://www.s-i-n.com/chaos/)

Objectives:
With One hit kill hacks being all the rage these days, we will take it a step
further and turn a one hit kill into a kill all mass killer.

Begin:
The first step is that we have to find the routine that deals with the enemy
health. A good idea would be to get the DOCTOR perk (0x48E6C0 = 1),
which allows you to see enemy health by holding your mouse cursor over
them. The problem at the beginning of the game is that enemies die off too
quickly to be able to search for health, so wait until level 1.5 ( Alien Dens )
and shoot at those big red white enemy spawners.

Doing the standard dec / inc search you should have come up with
something in the 499xxx range, then put a breakpoint (bpm w) / autohack it.

You should pop up at the monster health routine:

:004200DD D99E34944900 fstp dword ptr [esi+0x499434]

--- side note ---


The fst and fstp instructions copy the value on the top of the floating point
register stack to another floating point register or to a 32, 64, or 80 bit
memory variable. When copying data to a 32 or 64 bit memory variable, the
80 bit extended precision value on the top of stack is rounded to the smaller
format as specified by the rounding control bits in the FPU control register.
The fstp instruction pops the value off the top of stack when moving it to the
destination location. It does this by incrementing the top of stack pointer in
the status register after accessing the data in st(0). If the destination operand
is a floating point register, the FPU stores the value at the specified register
number before popping the data off the top of the stack.

Executing an fstp st(0) instruction effectively pops the data off the top of
stack with no data transfer. Examples:
fst mem_32
fstp mem_64
fstp mem_64[ebx*8]
fst mem_80
fst st(2)
fstp st(1)

The command at 004200DD is just basically storing a number from the


stack at the address of esi+0x499434.
--- end side note ---

Take a look at the registers and jot down some notes. F5 out of Softice and
attack a different monster. Try to understand what is going on in those
registers when you get popped back into SI due to attacking the monsters.
You will also see at the far right that DS: holds the memory address of what
you are currently attacking, then the number after the equal sign is the value
of their health in hex.

--- side note ---


If you want to convert it to
a dec type:

? xxxxxxxx ; where xxxxxxxx is the number after the equal sign. You will
notice that it is a large value like 1140457472, this is because it is in
DWord (4 bytes) format. To get the float version of it, either change it from
4 Bytes to Float in TSearch or divide it by 2280914.944
--- end side note ---

You will see the following pattern as you go through a bunch of times:
EDI ESI
00 00
01 98
02 130
03 1c8
04 260
05 2f8
06 390

It can be inferred that when monsters spawn, they are assigned an ID


number based on the order in which they were spawned. Also each Monster
struct is 0x98 bytes apart in memory.

--- side note ---


A struct (structure) is simply a way of grouping several variables under one
name like below:

struct Monster
{
float xposition;
float yposition;
float health;
float speed;
};

//example usage Monster.health=100;


--- end side note ---

Now that we know what is going on at

:004200DD D99E34944900 fstp dword ptr [esi+0x499434]

we want full control of what happens in this function. So now it is time to


jump to a code cave and rewrite the function to fit our needs.

Use Code Cave Chaos to find an empty code cave.

For this project I chose to put my stuff @ 0x46cb58.

Load up TSearch and open up the Easy Script section, its time for some
coding fun. Make sure you have the latest version of TSearch which
supports labels inside of EasyScript.

//-- code start ---


// first we must create the jump to our code so do the following:

offset 004200dd
//jumps to my function
jmp @myfunction
//gets rid of the extra byte that was left over from
//destroying the original fstp dword...
nop
//creates a label to jump back to.
@home:

//next we must create @myfunction

offset 46cb58
//create a label to jump to by name rather then offset
@myfunction:
//recreates the instruction that we destoryed
fstp dword ptr [esi+0x499434]
//jumps back home to the instruction after our created jmp
jmp @home

//-- code end ---

So with that code above we created a jump to our code cave, which just
recreated the original fstp instruction. At this point nothing has changed
except that when you attack a monster, the game now goes through our
function before returning back to the games own code.

So now let us add some code that will cause the current monster's life to be
set to 0 when it passes through our function.

!GREEN COLOR INDICATES NEW CODE THIS TIME AROUND!


!BLUE COLOR INDICATES STUFF THAT WAS DEACTIVATED OR
DELETED!
!NEW COMMENTS ARE THIS COLOR!

//-- code start ---


// first we must create the jump to our code so do the following:

offset 004200dd
//jumps to my function
jmp @myfunction
//gets rid of the extra byte that was left over from
//destroying the original fstp dword...
nop
//creates a label to jump back to.
@home:

//next we must create @myfunction

offset 46cb58
//create a label to jump to by name rather then offset
@myfunction:
//recreates the instruction that we destoryed
//we are going to replace this with a mov instruction
//fstp dword ptr [esi+0x499434]
//move the value of 0 into the pointer, thus killing current monster
mov dword ptr [esi+0x499434], 0x0
//jumps back home to the instruction after our created jmp
jmp @home

//-- code end ---

Okay, there you have it. When a monster is attacked, its health will be
replaced with 0 and it will die. However this is not good enough, we
would like to be able to kill all monsters at once. The monster's health
pointer is [esi+0x499434], so if we were able to go through the whole list
of created monsters and replace their health with 0, then they all would die
when one was attacked.

Remember how I made you pay attention to those two registers? EDI &
ESI? Now we are going to use them in a loop to help point to the proper
memory address of the monster's health and then we will write a 0 into it to
kill them.

//-- code start ---


// first we must create the jump to our code so do the following:

offset 004200dd
//jumps to my function
jmp @myfunction
//gets rid of the extra byte that was left over from
//destroying the original fstp dword...
nop
//creates a label to jump back to.
@home:

//next we must create @myfunction

offset 46cb58
//create a label to jump to by name rather then offset
@myfunction:
//pushes all registers so that they are backed up
//on the stack so we can pop them back later so that we have no
//adverse effects on the game
pushad
//set esi to 0
xor esi, esi
//set edi to 0
xor edi, edi

//creates a label so that we can jump back to it by name


//when we need to loop back through our little function again
@loop:

//move the value of 0 into the pointer, thus killing current monster
mov dword ptr [esi+0x499434], 0x0

//Since ESI*EDI*0x98+0x499434 = current monster's hp


//load effective address is the most efficient way of doing this.
//ESI now equals esi+0x98
lea esi, dword ptr [esi+0x98]
//increases EDI by 1, thus pointing to the next monster
inc edi
//compares edi and 300, which is how many times it should loop
//this accounts for all the monsters that could ever spawn in the
//game at once. I choose 300 cause 500 crashed the game =P
cmp edi, 0x12c
//if edi is not yet at its 300th run through the loop then go to the
//code at the label @loop: (LOOK UP!).
jne @loop

//pop all registers so that they are at the value they were at right before
//we started messing with them.
popad
//jumps back home to the instruction after our created jmp
jmp @home

//-- code end ---

So this time around we backed up the registers so that we could reuse them
at the end of our function, just incase we modified any of them during our
code.

Then we created a loop that looped 300 times, increasing the value of EDI
until it reached 300 - all the while writing 0 to the health address of each
creature as it goes through the loop.

Conclusion:
For the most part games store players and enemies an arrays of structs so
once you find a pointer for health you can do some math and go through
memory and write new values there.
In the case here, EDI (0,1,2,...) * ESI (0x98) + 0x499434 pointed to the
health of the current monster. We modified it so that it would go through
and write 0 to each Monster.health address. When a monster is attacked by
the player, the game jumps to our code and writes 0 to all currently
spawned monsters - killing them all for one. The only glitch is you only get
exp for what you kill with your bullet, but that's a story for another time.

DOWNLOAD COMPILED VERSION OF CODE


DOWNLOAD EASYSCRIPT VERSION OF CODE

//--FINAL CODE BELOW--//

offset 004200dd
jmp @myfunction
nop
@home:

offset 46cb58
@myfunction:
pushad
xor esi, esi
xor edi, edi
@loop:
mov dword ptr [esi+0x499434], 0x0
lea esi, dword ptr [esi+0x98]
inc edi
cmp edi, 0x12c
jne @loop
popad

jmp @home

^chaos^
idxchaos@hotmail.com
http://www.s-i-n.com/chaos/

^chaos^
November 15th, 2003

chaos world (c) 2003


Do not distribute as your own
:: Delta Force Series :: Crosshair Spread ::

For this option you will need to host a game;


Go to "Host options" and put Crosshair Spread off;
In the game, there will be no crosshair spread;
Alt & Tab out of the game to TSearch and search "Unknow Value";
Exit the game and go back to "Host Options";
Put crosshair spread on and go in game;
In the game, there will be crosshair spread;
Alt & Tab out of the game to TSearch and search "Has Increased";
Exit the game and go back to "Host Options";
Put crosshair spread off and go in game;
In the game, there will be no crosshair spread;
Alt & Tab out of the game to TSearch and search "Has Decreased";
Keep on doing this until you have found the addie.

:: Delta Force Series :: Fog ::

For this option, you will need to host the games;


You will need to make about 4/5 maps (the more, the better);
Each map should have 1 more building than the other;
"Map1" has a fog value of 1;
"Map2" has a fog value of 2;
"Map3" has a fog value of 3;
"Map4" has a fog value of 4;
"Map5" has a fog value of 5;
Go and host "Map1";
Alt & Tab out of the game to TSearch and search "Exact Value" 1;
Go back into game and Exit;
Host "Map2";
Alt & Tab out of the game to TSearch and search "Exact Value" 2;
Go back into game and Exit;
Host "Map3";
Alt & Tab out of the game to TSearch and search "Exact Value" 3;
Go back into game and Exit;
Host "Map4";
Alt & Tab out of the game to TSearch and search "Exact Value" 4;
Go back into game and Exit;
Host "Map5";
Alt & Tab out of the game to TSearch and search "Exact Value" 5;
Go back into game and Exit;
Keep on doing this method until you have found the addie to remove the fog.

:: Delta Force Series :: GPS ::

For this option you will need to host a game;


In the "Host Options", select "Show Nothing" and host the game;
Alt & Tab out of the game and search "Unknow Value" on TSearch;
Go back on the the game and Exit back to the "Host Options";
In the "Host Options", select "Show Everything" and host the game;
Alt & Tab out of the game and search "Has Increased" on TSearch;
Go back on the the game and Exit back to the "Host Options";
In the "Host Options", select "Show Nothing" and host the game;
Alt & Tab out of the game and search "Has Decreased" on TSearch;
Keep on doing the repeatedly until you find the addie.

Here is what you need to search once you have selected either Show Nothing, Show Friendly or Show Everything:
:: Show Nothing to Show Friendly = Has Increased
:: Show Nothing to Show Everything = Has Increased
:: Show Friendly to Show Everything = Has Increased
:: Show Friendly to Show Nothing = Has Decreased
:: Show Everything to Show Nothing = Has Decreased
:: Show Everything to Show Friendly = Has Decreased

For it to show everything on the game you will need the value for it, in which will be shown if you have a game with "Show
Everything" on. Then apply this addie to the game for it to work.

:: Delta Force Series :: Medic Timer ::

First off, you wil need to start a multiplayer team game;


Alt & Tab out of the game to TSearch and search "Unknow Value";
Go back into the game and kill yourself;
Alt & Tab out of the game to TSearch and search "Has Increased";
Go back into the game and revive yourself;
Alt & Tab out of the game to TSearch and search "Has Decreased";
Repeat this method over and over again and you will eventually find the addie for the Medic Timer.

:: Delta Force Series :: Recoil ::

For this option you will need to host a game;


Go to "Host options" and put Recoil off;
In the game, there will be no recoil;
Alt & Tab out of the game to TSearch and search "Unknow Value";
Exit the game and go back to "Host Options";
Put recoil on and go in game;
In the game, there will be recoil;
Alt & Tab out of the game to TSearch and search "Has Increased";
Exit the game and go back to "Host Options";
Put recoil off and go in game;
In the game, there will be no recoil;
Alt & Tab out of the game to TSearch and search "Has Decreased";
Keep on doing this until you have found the addie.

:: Delta Force Series :: Remove Buildings ::

For this option, you will need to host the games;


You will need to make about 4/5 maps (the more, the better);
Each map should have 1 more building than the other;
"Map1" has one building in it;
"Map2" has two buildings in it;
"Map3" has three buildings in it;
"Map4" has four buildings in it;
"Map5" has five buildings in it;
Go and host "Map1";
Alt & Tab out of the game to TSearch and search "Exact Value" 1;
Go back into game and Exit;
Host "Map2";
Alt & Tab out of the game to TSearch and search "Exact Value" 2;
Go back into game and Exit;
Host "Map3";
Alt & Tab out of the game to TSearch and search "Exact Value" 3;
Go back into game and Exit;
Host "Map4";
Alt & Tab out of the game to TSearch and search "Exact Value" 4;
Go back into game and Exit;
Host "Map5";
Alt & Tab out of the game to TSearch and search "Exact Value" 5;
Go back into game and Exit;
Keep on doing this method until you have found the addie to remove buildings.

:: Delta Force Series :: Scope Drift ::

For this option you will need to host a game;


Go to "Host options" and put Scope Drift off;
In the game, there will be no scope drift;
Alt & Tab out of the game to TSearch and search "Unknow Value";
Exit the game and go back to "Host Options";
Put scope drift on and go in game;
In the game, there will be scope drift;
Alt & Tab out of the game to TSearch and search "Has Increased";
Exit the game and go back to "Host Options";
Put scope drift off and go in game;
In the game, there will be no scope drift;
Alt & Tab out of the game to TSearch and search "Has Decreased";
Keep on doing this until you have found the addie.

:: Delta Force Series :: Speed Hack ::

Go into a game;
Alt & Tab out to TSearch and search "Unknow Value";
Go back into the game and put Auto Run on (Scroll Lock);
Alt & Tab out to TSearch and search "Has Increased";
Go back into the game and put Auto Run off (Scroll Lock);
Alt & Tab out to TSearch and search "Has Decreased";
Repeat this until you have found the addie.

:: Delta Force Series :: Start Delay ::

For this option, you will need to host your own games;
Host your first game with no start delay;
Alt & Tab to TSearch and search "Unknow Value";
Go back to the game;
Exit the map and go to "Host Options" and host a game with a long enough start delay to give you time to search;
Host the game;
Alt & Tab to TSearch and search "Has Increased";
Go back to the game;
Exit the map and go to "Host Options" and host a game without the start delay;
Alt & Tab to TSearch and search "Has Decreased";
Keep on doing that until you have found the addie for start delay.

:: Delta Force Series :: Wind ::

Before you search for this addie, you will need to make about 2 or 3 maps in the mission editor;
Set the wind speed as 1 for the first map, and save it as eg, "wind1";
Set the wind speed as 2 for the second map, and save its as eg, "wind2";
Set the wind speed as 3 for the third map, and save it as eg, "wind3";
Go onto the first map you made (wind1);
Alt & Tab out of the game and search in Tsearch for "Exact Value" 1;
Go back to the game and Exit;
The go onto the second map you made (wind2);
Alt & Tab out of the game and search in Tsearch for "Exact Value" 2;
Go back to the game and Exit;
The go onto the third map you made (wind3);
Alt & Tab out of the game and search in Tsearch for "Exact Value" 3;
Now keep on going through these maps until you have found the remaining addie;
To remove the wind, you will have to set the value of the addie to "0".

:: Delta Force Series :: Wall Hack ::

Go into a game and and get infront of a wall;


Alt & Tab out of the game and search "Unknow Value" in TSearch;
Go back into the game and go to the other side of the wall;
Alt & Tab out of the game and search "Has Decreased" in TSearch;
Go back into the game and go back to the other side of the wall;
Alt & Tab out of the game and search "Has Increased" in TSearch;
Keep on doing this until you have found your addie.

:: Delta Force Series :: Scope Zoom ::

Go into a game and get a weapon with a scope;


Set the scope zoom as, eg "8";
Alt & tab out of the game and get on TSearch, and search for exact value "8";
Go back into the game and change the scope zoom to "9";
Alt & tab out of the game and get on TSearch, and search for exact value "9";
Repeat this until you have 1 addie (you can use any value);
Add the addie you have left to the right side of the TSearch programme by using the [+] button above the found addies, then
highlight the addie;
Select the "Autohack Window" which can be found at the top of TSearch and click on "Enable Debugger";
Right click on the addie you have and select "Autohack";
Go back onto the game and change the scope zoom to "10";
Now go back onto TSearch and and look at the "Autohack Window" and click on the "TMK" button;
You will then be shown a patched (on) and unpatched (off) addie;
If nothing appeared in the "Autohack Window", then go back into the game and change the scope zoom a few more times
until it does appear;
Go on to TMK (or any other trainer maker program) and input the patched script into the "Memory Actions" and the original
addie you found, in which has the value of the scope zoom;
Eg:
Poke ***** 90 90 90 90 90 90
ADD BYTE 02
This will add 2 to the value of your scope zoom.

Poke ***** 90 90 90 90 90 90
SUB BYTE 02
This will subtract 2 from the value of your scope zoom.

Poke ***** 90 90 90 90 90 90
poke ***** 06
This will set your scope zoom to 6.

:: Copyright © 2003-2004 :: http://www.gamehack.net/ :: All Rights Reserved ::


:Hacking Different Options in Delta Force:
by InvadeR
for release with Devious.
:Info:
Certain Methods below will only work for Certain DF games.
----------------------------------

Auto Weapons:
Auto Weapons will also make Auto Knife.
Ok enter a game get a Pistol go into TSearch and search UNKNOWN VALUE.
Return to the game and get a weapon that is Auto like a Saw or FN MAG.
Go into TSearch and search HAS INCREASED. Return to the game and get your
pistol again and search HAS DECREASD. Continue gettin a pistol and saw and
search in HAS INCREASED for the SAW and HAS DECREASED for the Pistol.
You should find a addie which will increase with the saw and decrease with the pi
Take that addie and freeze it when u have a saw on and then change to different
weapons and those weapons should now shoot at the speed of the saw.
There are other methods of finding autoweapons but i find this to be one of the e
---------------------------------------
Jump:
This jump will work for Host and if u find the rest of the addies for Join.
Go into a Game that has a lader. Get on the lader and search for UNKNOWN VALUE.
Go back to the game and go up the lader a little and search HAS INCREASED.
Return to the game and go back down or up the lader and
search HAS INCREASED for when u go UP and HAS DECREASED for when you go DOWN.
And you should find one addie that when you poke it or inject a Higher number wi
you as high as the Value u up in. Now for this to work on Join what you must do
Jump address for Every SLOT. Most DF Games there are a Maximum of 50 Slots.
There is one good way to find them. This is a hard way but the way to start. go i
and Find jump for Slot 1. Then find it for Slot 2. and find out how much the dif
between Slot 1 and 2 then count up 50 times. That way is hard but if u find the
for the first few slots and figure out how much it is between each Addie for a Sl
up or down and find all 50 of them. This is proboly one of the easier ways to fi
But theres always another way.
----------------------------------------
GPS:
By hosting we have 2 options: Show Friendly and Show Nothing.
By single player we have 3 options: Show Default, Show Friendly, and Show Everyth

Show Nothing to Show Friendly = Has Increased


Show Nothing to Show Everything = Has Increased
Show Friendly to Show Everything = Has Increased
Show Friendly to Show Nothing = Has Decreased
Show Everything to Show Nothing = Has Decreased
Show Everything to Show Friendly = Has Decreased

So on to finding GPS. There are two addresses you need to find:


The address that controls GPS, and the address that controls whether or
not you are in a Multiplayer game or a Singleplayer game. First, we are going to
find the address that controls GPS. We are going to find it using the Decreased
and Increased Facts listed above.

Host a game with the GPS setting show nothing. Go to TSearch and start an
unknown value search. Go back into DF and exit your current game, then host
a new game with the GPS setting show friendly. Since show nothing to show
friendly is increasing the GPS value, click search next and then choose "Has Incr
Now exit your current game and then start a single player game with the GPS sett
show everything. Since show friendly to show everything is increasing the GPS val
click search next and choose has increased. Now exit your current game and host
game with the GPS setting show friendly and since show everything to show friend
decreasing we click search next and then choose "Has Decreased". Exit your curre
game and host a new one with the GPS setting show nothing and since show friendl
show nothing is decreasing, click search next and choose has decreased again. Re
above steps until you find the GPS address.

Now to find the address that controls whether your playing Multi or Single Player
Host a Multiplayer game and do an unknown value search. Now exit your game, start
Singleplayer game, and click search next, then choose "Has Decreased".
Then host a Multiplayer game and do has increased. Repeat these steps until you f
address that controls whether your in a Multiplayer or Singleplayer game.
-------------------------------------
Raise or Lower Buildings.
Ok for this u will need to make 3 or 4 maps. Each map needs to have a few buildin
1st map: Make all buildins at 0 height. 2nd map: all building need to be in the s
as the first one,but the height of the buildings needs to be higher.
make the next 2 in the same way. Each one needs to have higher buildings then bef
But the buildings HAVE to be in the SAME place.
Now start the first map and search UNKNOWN VALUE.
Now go to the next map and search HAS INCREASED.
go on to the next map and search HAS INCREASED.
now continue on in that manner until u find the correct addresses.
-----------------------------------------------
Fog,Water,Day ON/OFF:
Now for this one u have to make maps. u need to make 4 or 5 maps each map
needs to have a higher Fog level then the next one. eg-1st Map: Level 1,
2nd Map: level 2. Now start the first map and search EXACT VALUE and the Value i
Now go to the next map which should be Fog at Level 2.And seach INCREASED BY and
Continue searching that way until u find the correct addie. Now if searching by
INCREASED BY or EXACT VALUE doesnt give u the correct Addie.
Try instead the first map searching for UNKNOWN VALUE and the next map HAS INCREA
When u find the correct Addie simply put 0 in it and u should have no Fog.
If the fog doesn cut off right away((like in DFLW)) Freeze the addie at 0 and go
the next map and the Fog should be gone.

You can also apply the same method for finding Water On/OFF and Day/Night.
Just make it with diff levels of whatever u are wanting to hack and then search a
-----------------------------
Ammo:

Ok so u want to hack ammo for any DF game..or any game for that matter heres what

Go into a game. Get the weapon u want to hack the ammo on up. Look at the value((
of ammo u have remember that. Open TSearch select the process for the game u wan
Now go to the first search and under EXACT VALUE put the value in that box and b
Now when its done go back to the game. Now shot 2 or 3 shots, go back to TSearch
DECREASED BY from the SEARCH NEXT and put the amount of shots u shot off in ther
((if u shot 3 put 3 in that buton)).Now search. Continue going in the game and sh
searchin DECREASED BY or HAS DECREASED until u come to about 3 to 10 addies.
Now go through all those addies and put new Values in and see if the ammount of a
in the game changes. If so then u have found the correct Addie. Now games that us
you will need to do is. After u find that addie. Enable the AUTOHACK option on th
to the game a shot and then return and it should have the Root Addie.
------------------------------------------
Weapons:
If u want to find the Addies that control what weapon is on what slot.
Go into a game get a weapon up. Already have TSearch ready. Do an UNKNOWN VALUE s
Return to the game and change the weapon that is on that slot. Go back to TSearch
HAS CHANGED search. Return back to the game when done and change the weapon on t
again and do a HAS CHANGED search again. Continue changing the weapon on that sl
searchin HAS CHANGED and u should find the addies u are looking for. You can use
to find what addie controls what weapon is on what slot.

You can use the weapons method to also find weapons like Autonade,.50 Caliber Mou
All u have to do is either get into and Autonade or .50 caliber mount and look at
Or
Start putting values from 1 up and see whatr weapons u find.
-------------------------------------------
Tracers:
Go to SETTINGS in DF and find where Tracers is set and select ON. Go into a game
UNKNOWN VALUE search.Once its done leave the game and go back to SETTINGS and se
Go back to a game and search HAS CHANGED. Continue cutting Tracers ON and OFF and
HAS CHANGED until u find the correct Addie.
-------------------------------------------
LW-TFD-BHD Only
Crosshairspread/ScopeDrift/No recoil:
All work in the same way, there are many other ways to find these, but this is th

Set your multiplayer settings to Crosshairspread On. Then start a game and search
Leave the game and set it to Crosshairspread Off. Then start another game and sea
Leave and set it to Crosshairspread On. Start another game and search has increas
address's. You can use the same method for ScopeDrift/Norecoil.
------------------------------------------
LW-TFD-BHD Only
Speed:
Get into a game and press Scroll Lock. Leave and search Unknown value. Come back
Then search Has Decreased. Turn Scroll Lock back on and then search Has Increased
what you are looking for.

-----------------
A few words
-----------------
The tutorial was a general refrence to Delta Force. The many tuts on hacking diff
in most every game. And these aren't the only ways they can be found. Every optio

---------------------------------------------------------
DEVIOUS - http://devious.tsongkie.com
TCB - www.tcb-hacks.com
CES - www.gamehacking.com
CC - www.cheat-core.com
---------------------------------------------------------
Greetz fly out to all DEVIOUS & TCB
---------------------------------------------------------
Date: 7th Of July, 2003
---------------------------------------------------------
Best viewed in Arial, Regular, 9
Bie comment:
This info is taken from http://www.gamehacking.com forum

Tutorial Author: eVoByte


Email: Unknown
Homepage: http://www.evobyte.net/
Other known method to contact the author

Unknown

Namehack in BHD
---------------

Author : eVoByte-h4x-

Date : 16th March 2004

Music : Fat Joe and P.Diddy ft.Dre - Girl, I'm A Bad Boy
The Roots ft. Musiq - Break you off

Tools I Used : T-Search - www.evobyte.net


Artmoney - www.evobyte.net
Visual Basic 6.0 - Kazaa

Description : Namehack = the ability to change the name you type under, as to appear to be other
player / use hexed letters while talking in game. Note that the name on the kill list is not changed
when name hack is used, only the one you type under.

Right, before we start I wanna get 1 thing clear. Incase anyone has the wrong idea here, this tutorial
is only for host mode. I'm not writing a tutorial so that everyone can copy the code at the bottom
and say they made a name hack, thats not the point. However, if you learn the information in this
tutorial, the same methods can be applied to make a name hack for join.

So, heres how I did it, keep track :


First thing to do is host a map. It doesn't matter what map or anything like that, its your name your
hacking, and thats the same no matter what. Ok, now I wasn't sure of the name I typed under so I
just typed a quick message to check :

evo: fucknut

Right, so the names evo for me. Now, minimize the game and open up artmoney. Select BHD as the
process, and search for exact value, type as text and enter your name, in my case "evo"; for me 28
addresses were found.

To narrow these down I edited each one so that they had a different letter after them, e.g.

address 1 = evoa
address 2 = evob
...etc

After you've changed the name of each, go back in game and type a message. I typed under the
name evon. So, go back to Artmoney and find the address which holds the name you typed under.
Mine was :

0943005C

Ok, load up T-Search, select BHD as the process, and go to Autohack>Enable Debugger, then
Autohack>Autohack window. Just to note, I havent bothered rebooting the game to see if it has
DMA, I'm just guessing it does, and for tutorials sake I'd do it this way whether it did or not. This idea
of this bit is to be able to find the address each time you press the button/hotkey on your trainer, as
its the best way to defeat DMA on namehack.

Ok, so now your in the autohack window, goto Edit>Set Breakpoint, and type your address in, leave
the bytes as 1, and select Read/Write. What this means is, whenever your address ( in my case
0943005C ) is read, or written to, then the code which does it will be listed here. Ok, I got 5 entries
and you should too :

CODE
5C7087: cmp [eax],al
5C73DA: movsx eax, byte ptr [esi]
4AC88D: mov edi,edx
4Ac8C2: mov edx,[ebp+0x8]
4Ac8D4: rep movs dword ptr es:[edi],dword ptr [esi]

Ok, just because I'm used to looking at this code, I prefer to look into the following ones :

CODE
4AC88D: mov edi,edx ; copy the value edx holds into edi
4Ac8C2: mov edx,[ebp+0x8] ; copy the value which the address in ebp+0x8 holds to edx

NOTE : When you see things in [ and ], what it means is the value in the address it holds. E.G., in this
case, if ebp+0x8 holds 123456, it moves the value which 123456 holds into edx. Another thing to
note is mov does not really mean move...it means copy. After 'mov edi,edx' is completed, the value
will be in both registers.

Ok, next step? We need to see what goes on at these addresses so we know if we are safe to inject
code at them. For example, we dont want to split up a comparison and a conditional jump. Ok, so i
want to see whats around 'mov edi,edx', so in the autohack window goto Edit>Disassemble and
type in '4AC880'. We dont type in the exact address as the idea is we want to see what goes on
before it as well. After you have done this, click on Disassembler at the bottom of autohack window,
near debug event, thread and register.
Ok, heres the code around the area :

CODE
004AC880 Push ebp
004AC881 mov ebp,esp
004AC883 mov edx,[ebp+0xC]
004AC886 push esi
004AC887 push edi
004AC888 or ecx,0xFFFFFFFF
004AC88B xor eax,eax
004AC88D mov edi,edx ; where breakpoint put us
004AC88F repne scas byte ptr es:[edi]
004AC891 not ecx
004AC893 dec ecx

Ok, well, breakpoint put us on the mov edi,edx line, so one of these held the address for our
name...and being as it is being copied, its safe to say that after this line both will contain it. Xor
eax,eax is safe to put in a code cave, it just clears the eax register, and repne scas is also ok...so
thats where I will write.

Ok, one thing you might not know is a jmp takes up 5 bytes, 1 for the jmp opcode and 4 for the
address. We will be rewriting this over the xor line, so we will overwrite that, overwrite the next line,
and half overwrite the repne scas line with our jump.

The main rule of code injection is replace game code which you overwrite, and make sure the byte
numbers add up, heres why:
Say we overwrote where we said, and jumped back on 004AC891, then a byte from the repne scas
line would be blank. What would happen is all the code below would shift up 1 byte to fill the gap, and
there for all jumps in the entire code which jump after the line 004AC88F would jump 1 byte too far,
and cause the game to crash. To stop this, we put in a nop, which fills the space but does fuck all so
the game isn't screwed.

I found a huge group of blank codes which is the same in LW, TFD and BHD. From about 00400360
up until about 00400FF0. So, I'v decided I'm going to write my code to 00400370 and store the
address in 004003C0.

You're probably wondering whats going on here, so I'll finally explain. What we are doing, is making it
so we can find the address out easily each time.We are going to copy edi or edx after the line
004AC88D, as they contain the new address for our name, and then put it somewhere else in
memory. Then, in our trainer, we will use ReadProcessMemory to get this address, and then we can
write our name to it.

So, I'll write the code then explain it. By the way, this is wrote into EasyWrite in TFD which converts it
to Pokes:
CODE
Offset 004AC88B
jmp 00400370;jump to code cave
nop;to fill the blank space

Offset 00400370
xor eax,eax; replace code we overwrote
mov edi,edx; replace code we overwrote
mov [4003C0],edi;put our names address in 4003C0
repne scas byte ptr es:[edi];replace code we overwrote
jmp 004AC891; jump back to code

So, lets have a look in more detail than shitty comments :


--
CODE
Offset 004AC88B
jmp 00400370;jump to code cave
nop;to fill the blank space

This code replaces the original code to jump to our code cave, where we are storing the code to
store our address.
--
--
CODE
Offset 00400370
xor eax,eax; replace code we overwrote
mov edi,edx; replace code we overwrote

This just replaces the code we overwrote with the jump command
--
--
CODE
mov [4003C0],edi;put our names address in 4003C0

This stores the address for our name into 004003C0. In our trainer we will use readprocessmemory
on this address, and the value will be the address of our name.
--
--
CODE
repne scas byte ptr es:[edi];replace code we overwrote

More code we overwrote with out jump


--
--
CODE
jmp 004AC891; jump back to code

Jump back to the line after the bytes we overwrote, its important not to miss any lines out, which
we havent :-)
--

So, now we have all the code we need to store our address for us. To get this into a form where we
can write it easily, press TMK and then press CHECK ( the button, not the check box ). This will give u
pokes on the right hand side. If you don't know how to convert these TMK pokes to your
programming language, stop reading this tut, walk near a wall and face it, lean back, wrap your right
hand around the back of your head and push very hard.

Well, if you've managed to get upto here without knocking yourself unconcious on a wall, then I'm
guessing you have a brain cell, so I'm not going to write the source code for the trainer out for
n00bs to copy.

Heres the basic things your trainer needs to do:


WriteProcessMemory all the converted TMK code to make name addie store in 4003C0
ReadProcessMemory on 4003C0 to get address, this will be in decimal
WriteProcessMemory to the address you got from 4003C0. To get the address to work use the
following as your address:
val("&H" & hex(returned))
Thats if your ReadProcessMemory put your value into a variable named "returned".

Well, finally, thats the end of a long, shit tutorial on Name Hack for BHD. We covered the following
topics:
Simple Hacking to get first name address
Basic Debugging
Beating DMA
Code Injection
Trainer Using Read/Writeprocessmemory

By the way, you can easily adapt this for join, and the whole Delta Force series...infact, any game,
any option.

Shoutouts : Zehcnas, Just M3, i.Brid, jb, OxY, Diablo, Demented, Bie, Predator
- No Order, just cool people -
www.evobyte.net
www.df-hacks.com
www.toxic-cell.net
www.btcsquad.com
www.gamehack.net
www.gamehacking.com

Tutorial by [mdk] / eVoByte / Rookie / [oz] / GTi / ...so many other fucking names. :-)
ADVANCED GAMEHACKING TUTORIAL

TARGET: DIABLO
~~~~~~~~~~~~~~
WRITTEN BY: Sorin ( Splinter@email.ro )
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TOOLS NEEDED: SoftIce, TSearch(or other mem finder), HexWorkshop, ProcDump
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE OF MEMORY THAT THE GAME USES: STATIC MEMORY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WHAT WILL BE THE HACK: all spells, automap reveal, spell casting in town
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
REMARKS: You'll need some brain, too :(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

_______
INTRO:|
~~~~~~~

Hello again dear game lovers! If u stay with me for a moment, i'll show you some
techniques in gamehacking. But first I must tell you that sometimes a good ga
MUST BE a good game-player! Don't forget this !

So, let's first try the "all spells" hack.

******************** PART I - HACKING THE SPELLS ********************************

For this your character must have the following:


- 1 book in the inventory, that holds a spell that he hadn't learnt yet
ex: if you didn't learn the "healing" spell yet, find 1 "healing book" and put
inventory!
if your char. had already learnt the healing spell, find (or buy) 1 book o
that he don't know...

- 3-4 books of a spell that your char. already know


ex: if u play with the sorceror, you have the "firebolt spell" from the beginn
and find other 4 books of firebolt and put them in your inventory.
(as i told you, you must be a good gamer, too!)

- at least 2-3 spells known

Now, in Diablo see what level is the spell you have that 3-4 in inventory. Let's
firebolt. See what level is. Press [ESC] to pause Diablo, then do ALT+TAB.

OK. Open TSearch, and select Diablo as process. Now search for the level your fir
is. Let's say it's 3. Search for 3 (BYTE search!). Now, go back in the game,
the level of your firebolt spell by right-clicking on one of the 3-4 books th
to find.

Your firebolt level should now increase to 4. Pause Diablo, and in TSearch click
and enter 4 as value (BYTE search).

You must repeat this steps until you have ONLY 1 address! (for me that was 53317A
differs from version to version (game version) ).

After you found the address, modify it to see if it's the right one. Make your fi
be 8 (within TSearch, of course)! Go back in the game and voila! You have lev
spell!
But what about the other spells? We don't want to do this for every spell!

Ok.... Now comes the explanation:

Most of the games hold your data in memory locations CLOSE one from another.
ex: If your life is at address 15, then your bullets will be (in most of cases)
address around 15 (let's say the bullets are at addr. 20). And your miner
at address 12! Get the trick? The addr. are one around other! (around mea
far).

%%%%%%%%%%%%%%% This method is the mother of gamehacking!!! Don't forget it!!! %%

=================================================================================
So, we have the starting address (mine was 53317A). Let's dump the memory around
then modify something in the game, then dump again the memory around that add
compare the results and try to figure out where is holding the "key"!
=================================================================================

%%%%%%%%%%%%%%% This method is the mother of gamehacking!!! Don't forget it!!! %%

For this we'll use TSearch again. In the "Misc" menu, select "memory dump -> save
The begin address should be the one you found, and the end address should be
found+200 (or 300, or 1000, etc - this is the range). I suggest to set this r
between 200-300. If you don't find anything, increase the range! ALSO, this w
dumping the memory AFTER the known address. If you can't find what you want,
memory BEFORE the known addr, by setting (in TSearch) the start addr to known
addr-(minus)range, and the end addr to known addr! It seems a little bit comp
but it's a kid's play!

But enough with explanation, let's dump!

~~~~~~~~~~~~~~~~~~~~~~~~~ |
~ start address: 53317A ~ |> in TSearch
~ end address: 53337A ~ |
~~~~~~~~~~~~~~~~~~~~~~~~~

Ugh, the dump was fast wasn't it?

Now, in Diablo learn a NEW magic spell (by right clicking on a book in your inven
IT'S VITAL THAT YOU DON'T DO ANYTHING ELSE IN THE GAME !(not even move !). Pause,
ALT+TAB & your back in TSearch.

All you have to do is to dump the memory again (don't change the start/end addres

Now, you have 2 files with a part of diablo's memory. To find out the differences
HexWorkshop and compare the 2 files...

In HexWorkshop, delete the first 12 (twelve) bytes from BOTH dump files. They are
signature and we don't need them.

If you did EXACTLY what I told you, you should have 3 differences. First is the s
(that changed from 0 to 1). The second difference is the spell enabler and th
diff. is not important to us. I guess that those addresses 53317a,53317b,5331
the levels for all your spells. Let's modify some of them (not in HexWorkshop
and set them to 8! Go back in the game, and what you see? ONLY the spells you
their level. That's because difference no.2 from above. The byte at that diff
the spell you have just learnt! Change that byte (also in TSearch & not in He
(the biggest). Go back in the game, and you have some new spells, but not all
That's because we changed only one byte, and not a DWORD! So, change the dword at
at the second diff. to FF FF FF FF (in TSearch). Go back in the game and voil
(of course some of them are level 0 because you just enabled them and you did
their level).

PS: This hack will not enable the "Bone Spirit", "Blood Star" & "Heal Others-mult
spells. These are treat separately by the game. If you want to hack them, f
books & repeat the hack as above!

Man, I hope you understand me. :)

*********************************** PART II - MINIMAP HACKING *******************

Ok, now that we know how to hack the spells, let's practice a little more the "du
We have already a starting address: 53317A (the firebolt level from above). S
the memory again, but with a bigger range (let's say 20000).

Again we'll use TSearch. But first go into the dungeon in a level that you didn't
all the map. Pause Diablo, ALT+TAB in TSearch!

~~~~~~~~~~~~~~~~~~~~~~~~~ |
~ start address: 53317A ~ |> in TSearch
~ end address: 55317A ~ |
~~~~~~~~~~~~~~~~~~~~~~~~~

I must tell you again that we're dumping the memory ONLY AFTER the known addr.(53
we can't find anything, we'll dump the memory BEFORE known addr.

Now, go in that level & discover a new part of map. Pause the game, dump the memo
the SAME ADDRESSES!

And again you have 2 files containing a part of game's memory! Let's compare them
<Don't forget to delete TSearch signature from both files!>

Uuuh, now we have not only replacements, but insertions & delections! But we are
only in replacements (differences). If you follow carefully every replacement
land in some bytes like : ... 01 00 01 01 01 01 00 00 00 00 01 00 01 01 00 00
01 00 01 00 01 01 00 00 01 01 01 01 00 01 01 01 00 01 01 00 01 01 (a lot of t

In this bytes, HexWorkshop found not only differences, but matches, too! And thes
bytes are in BIG NUMBER! Isn't this possible to be a map skeleton? Let's chan
40-50) 01 bytes to 00's (within TSearch). Now, go back in the game and look a
minimap? Is it changed? Of course it is! You see that the map you had discove
it's "hidden" again!

So, we got lucky! Also, I must tell you that this map_memoring is the oldest in t
Diablo uses byte 0 where your character hadn't been before and ,of course, di
the map, and byte 1 where he discovered the map. And if you want to see all t
replace the 00's to 01's! But be careful not to overwrite other game's data !

And the minimap hack is complete...

PS: of couse you could hack the map by finding a shrine (in the game) that reveal
save your game before you click on it, then click on it, dump the memory, loa
dump the memory, see the differences. But this takes alot of time before you
shrine, and you must save your game every time you find one(because you don't
the beginning what it'll do *hehehe*). And this is not so professional like t
above!

**************************** PART III - SPELLCASTING IN TOWN ********************

We'll use the same mem. dump trick on this one, too!

But first, let's set some hotkeys in Diablo! Set F6 to be your hotkey for firebol
healing.

Explanation:
Diablo let us cast healing in town, but not firebolt. So we'll need to know when
reads your current spell. Then the game must compare something with the "heal
If they match, then your spell is healing and you can cast it in town. If the
then you must go in the dungeon to cast! :) Our solution is to find out what
"healing's key", and trick the game to believe that our firebolt is allowed i
giving to firebolt the healing's key). Easy huh?

Go in town, F7 to change to healing, pause Diablo, dump the mem. in TSearch.

But this time dumping the memory after the known address won't work! (you can try
don't believe me!). So we'll need to dump the mem. BEFORE 53317A. The length

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ start address: 532F7A -> we're dumping backwards and 53317A-200=532F7A ~
~ end address: 53317A ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Back in the game, F6 (switch to firebolt), pause, dump again!

Next, like always, compare the files (don't forget to erase the signature!).

And we have this time only one difference. To be more precisely, a byte differenc
located at address 53316C (532F7A-> start addr + 167 -> hexworkshop addr = 53

Now comes the SoftIce part :). But first change your spell to healing.

Put a

bpm 53316c

in SI. And right click to use your healing spell. SoftIce breaks:

41B611: MOV EDX, [EDI+53316C]


CMP EDX, -1 -> edx holds our spell id
JNZ 41B650 -> here both firebolt & healing jump
..........CODE....CODE....
41B650: CMP BYTE PTR [621CB4], 0
JNZ 41B69B -> firebolt & healing don't jump
MOV EAX, EDX -> eax gets the spell id
IMUL EAX, EAX, 38 -> make the "key"
CMP DWORD PTR [EAX+49A2A0], 0 -> cmp the byte at our spell key with
ALLOWED in town)
JNZ 41B69B -> if it's not 0 then you can cast it

That "jnz 41b69B" was taken by the healing, but the firebolt didn't take it (didn
So we need to change the 0 held by the byte at [eax+49a2a0] to another number
our firebolt will jump over the "firebolt not allowed", and our character ca
spell in town.

Use this method for the others spells. Their "key" is one after another!

********************************* END OF TUTORIAL *****************************

Huh, another one finished!

Like always, I hope you understood something from this. If anything is unclear, c

WHY I WROTE THIS TUTORIAL:


~~~~~~~~~~~~~~~~~~~~~~~~~~

Because I LOVE old games (diablo,starcraft,dark colony etc) and because i saw ove
thousands of diablo trainers, but not even 1 tutorial on how to hack it! Mayb
searched enough, or maybe there really aren't any others...

FUTURE PLANS:
~~~~~~~~~~~~~

I want to release a FULL-HACK tutorial on diablo. So if you are a skilled gamehac


want to help me, plz sent me your tips & ideas (hacking different things). Yo
FULL CREDITED, and you will not only have my respect, but you'll have the res
your readers!

Also, I'm looking for different methods of map-hacking, not in diablo, but in str
If you know something and you want to share your knowledge with the others, s
tips. Again, you will be full credited! If you don't trust me, write your own
spread them over the net. I'm satisfied with BOTH options :)

CHEERS & GREETS (order doesn't matter) :


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ParaBytes (my cracking teacher)
- Groza (thnx for your hosting)
- All GHU members & those who help us
- ALL in GameHacking's forum (hi guys - can't wait to "see" you again)
- Johnny Bravo :)
- all tutorial writers! (keep going writing until every newbie will be a PRO)
- JUVENTUS TORINO - THE BEST FOOTBALL TEAM IN THE HISTORY OF SPORT
- You for reading this piece of s..
- Romanian:
*********************************************************************************
* Aceasta zi (10 sept. 2003) este una foarte trista pt romani. Echipa nationala a
* calificarea la EURO 2004, remizand in meciul cu Danemarca. Sa speram ca vor ven
* zile mai * bune si sa auzim numai de bine. Traiasca Romania!
*********************************************************************************

Dont forget to visit our page: http://www.sorinspage.cjb.net/


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[best viewed with notepad at 800 X 600]

Sorin ( Splinter@email.ro )

eof
Author: Bie @ Razali Rambli
Email: razali_bie@hotmail.com
Website: http://bie.cjb.net
Demonstar
http://www.mking.com

Tools: Tsearch

Ghost Ship
Collecting information & Explanation:
We try to create an 'advanced' cheat, by making our ship invulnerable to anything.
But how we going to do that? What value to look for? Is this even possible?
Yes, it is easy actually. Don't believe me? Read more.

If we are hit by enemy fire or hit by enemy ship, we will die.


Then if we still have life, a new ship will comes out. But when the ship
comes out, it goes right pass everything and does no damage to you.
But this happy time don't last forever. It is just for a few second only
and your ship will turn to it normal state and you will die if you are
hit with enemy fire or enemy ship.

So, what we have here? Yep... timer. I illustrate below:

1. We die.
2. Timer start, as long as the timer haven't reach it limit, we can go pass everything without any damage.
3. Timer stop, our ship turn to normal again.

Searching:
1. Search Unknown 1 Byte
2. Die and let the new ship load and Pause [Press P]
3. Search Next Has Increase
4. Unpause and Pause again
5. Search Next Has Decrease
6. If the ship still flashing, repeat step 4-5. If the ship have return to normal, repeat step 2-5
7. You will found one address.

Testing:
1. Add the address to Cheat table
2. Change the value between 1-255
3. Freeze the address
4. If your ship keep flashing, and doesn't get damage at all. Yep, you have found it.

TMK & GTS


Poke Address FF

Make sure you turn on the freeze option.

Conclusion:
Not so advanced cheat right? Ok, next time I'll show you how to make a cleaner way to handle this like what I have done inside my trainer.
Sample of this cheat in action can be download at my homepage at http://bie.cjb.net

Next time it will involve code injection, you wont have to make your trainer keep poking at that address & your ship will not flashing.
Advanced Game Training Techniques
Diablo 2: Money On Character

What you will learn:


How to find the value for the money that your character currently has. If you
are a BLIZZARD LACKEY, and think that "hacking diablo 2 is gay" please
visit our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better becuase its faster
for "exact value searches")

STEP 1:
Your character should at least have 1 piece of gold, if you do not have,
attain it. The value for money is stored in 4 bytes (dword) in "exact value"
format, meaning that the value that you see on screen is the one that you
want to search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter how much gold you have and hit the
FIND button. This may take a few seconds to a few minutes depending on
how fast your CPU is because d2 seems to be a memory whore. Hop back
into Diablo 2 and change the amount of gold you are holding. Now alt + tab
back to GT and enter your new gold value in the GT edit box, but this time
hit the SIEVE button. This will only look at the addresses which matched
your first search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value. Hop back into Diablo 2, the value of your
money will still be the same until you change it by buying an item or
dropping some gold. The value I had was 00d19530, this address is static
in memory and will never change. So it will work every time you start up
Diablo 2.

Conclusion:
Enjoy your new found fortune.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: Money On Character

What you will learn:


How to find the value for the money that your character currently has in his
STASH BOX. If you are a BLIZZARD LACKEY, and think that "hacking
diablo 2 is gay" please visit our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better becuase its faster
for "exact value searches")

STEP 1:
Your character should at least have 1 piece of gold, if you do not have,
attain it. The value for money is stored in 4 bytes (dword) in "exact value"
format, meaning that the value that you see on screen is the one that you
want to search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter how much gold you have in the
STASH BOX and hit the FIND button. This may take a few seconds to a
few minutes depending on how fast your CPU is because d2 seems to be a
memory whore. Hop back into Diablo 2 and change the amount of gold in
your STASH BOX. Now alt + tab back to GT and enter your new gold
value in the GT edit box, but this time hit the SIEVE button. This will only
look at the addresses which matched your first search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value. Hop back into Diablo 2, the value of your
money will still be the same until you change it by buying an item or
dropping some gold. The value I had was 00d72cc8, this address is static
in memory and will never change. So it will work every time you start up
Diablo 2.

Conclusion:
Enjoy your new found fortune.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: Character Attributes

What you will learn:


How to find and modify your ATTRIBUTES: strength, dexterity, vitality,
and energy. If you are a BLIZZARD LACKEY, and think that "hacking
diablo 2 is gay" please visit our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better because its faster
for "exact value searches")

STEP 1:
This is really 4 easy tutorials in one. Your character should at least have 2
or 3 STAT UPGRADE POINTS that you can distribute, if you do not have,
attain it by LEVELING UP, OR CHEAT using the previous tutorial. The
value for ATTRIBUTE POINTS is stored in 4 bytes (dword) in "exact
value" format, meaning that the value that you see on screen is the one that
you want to search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter how much your STRENGTH
currently is and hit the FIND button. This may take a few seconds to a few
minutes depending on how fast your CPU is because d2 seems to be a
memory whore. Hop back into Diablo 2 and use one of the STAT
UPGRADE POINTS on STRENGTH so that the value for STRENGTH
goes up 1. Now alt + tab back to GT and enter your new value of your
STRENGTH ready to distribute in the GT edit box, but this time hit the
SIEVE button. This will only look at the addresses which matched your
first search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value, increase it for best results. Hop back into
Diablo 2, the value of your STRENGTH will match whatever value you
entered. The values I had were: STRENGTH: 00d194c0, DEXTERITY:
00d194d0, VITALITY: 00d194d8, ENERGY: 00d194c8, these addresses
are static in memory and will never change. So it will work every time you
start up Diablo 2.

STEP 3:
Now repeat the steps over to find the other values for DEXTERITY,
VITALITY, and ENERGY.

Conclusion:
Enjoy playing with your attributes. Remember that if you just modify
VITALITY/ENERGY to a high value you will NOT get 2 life/mana per
point, so its best to invest actual upgrade points into these two values. Also
don't forget that you can set these stats back to 0 and upgrade them again
and again.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: Stat Upgrade Points

What you will learn:


How to find and modify your total STAT UPGRADE POINTS. If you are a
BLIZZARD LACKEY, and think that "hacking diablo 2 is gay" please visit
our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better becuase its faster
for "exact value searches")

STEP 1:
Your character should at least have 2 or 3 STAT UPGRADE POINTS that
you can distribute, if you do not have, attain it by LEVELING UP. The
value for STAT UPGRADE POINTS is stored in 4 bytes (dword) in "exact
value" format, meaning that the value that you see on screen is the one that
you want to search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter how many STAT UPGRADE
POINTS you currently can distribute and hit the FIND button. This may take
a few seconds to a few minutes depending on how fast your CPU is because
d2 seems to be a memory whore. Hop back into Diablo 2 and use one of the
STAT UPGRADE POINTS on a stat such as strenght so that the value for
STAT UPGRADE POINTS drops 1. Now alt + tab back to GT and enter
your new value of your STAT UPGRADE POINTS ready to distribute in
the GT edit box, but this time hit the SIEVE button. This will only look at
the addresses which matched your first search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value, increase it for best results. Hop back into
Diablo 2, the value of your STAT UPGRADE POINTS will match
whatever value you entered. The value I had was 00d194e0, this address is
static in memory and will never change. So it will work every time you
start up Diablo 2.

Conclusion:
Enjoy playing with the stat upgrade points and creating an ultimate
character. Remember that you must have at least 1 STAT UPGRADE
POINT to distribute so that the [+] icon is enabled. Otherwise you will not
be able to distribute your points, but you will still have them for later use.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: Experiance

What you will learn:


How to find and modify your LEVEL. If you are a BLIZZARD LACKEY,
and think that "hacking diablo 2 is gay" please visit our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better because its faster
for "exact value searches")

STEP 1:
The value for CHARACTER LEVEL is stored in 4 bytes (dword) in "exact
value" format, meaning that the value that you see on screen is the one that
you want to search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter what CHARACTER LEVEL you
currently are and hit the FIND button. This may take a few seconds to a few
minutes depending on how fast your CPU is because d2 seems to be a
memory whore. Hop back into Diablo 2 and kill some more enemies until
you level up and gaint a CHARACTER LEVEL. Now alt + tab back to GT
and enter your new value of your EXPERIANCE in the GT edit box, but
this time hit the SIEVE button. This will only look at the addresses which
matched your first search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value, increase it for best results. Hop back into
Diablo 2, the value of your CHARACTER LEVEL will NOT match
whatever value you entered, it is ONLY AFTER YOU SAVE & EXIT will
the results be apparent. The value I had was 00d19520 addresses are static
in memory and will never change. So it will work every time you start up
Diablo 2.

Conclusion:
Change your level and then, SAVE AND EXIT, do not check your
Character screen because it might set your level back to the original.

^chaos^
chaos world (c) 1999
Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: STAMINA

What you will learn:


How to find and modify your STAMINA. If you are a BLIZZARD
LACKEY, and think that "hacking diablo 2 is gay" please visit our
complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0

STEP 1:
The value for the STAMINA BAR is stored in 4 bytes (dword) in a "bar"
format meaning that you can't see the value, OKAY I know you can see it
but I am tired of doing exact searches and its always good to know another
method of searching. So start up GAME HACK, select GAME.EXE or
DIABLO II from the process window (press the left most button).

In Diablo 2 make sure that your stamina bar is filled to the top. Next click
on the BINOCULARS and select ADVANCED from the drop down list
under the SEARCH header. This will take the current state of memory.

Back in Diablo 2 make sure you have RUN enabled (hit R). Run around till
the bar decreases a bit. Pause the game with ESC, and get into Game Hack.
Now select the BINOCULARS ICON that has a small arrow under it (the
one that is next to the BIG binoculars). Under the search select DECREASE
and hit OKAY.

After Game Hack stops, go back into Diablo 2, run some more. Do the
Decrease Search yet again.

Now go back into Diablo 2 and let your stamina bar fill up 100%. Now in
game hack rather then a DECREASE search, do an INCREASE search.

Continue this cycle until you get as few values as possible, 8 of them:

00d1950e <-real
00d1950f <-real
00d19510 <-real
00d19511 <-real
043a3efe <-just for show
043a3eff <-just for show
043a3f00 <-just for show
043a3f01 <-just for show
The first four values are the real values, I know this because if I froze these
values I could run forever, however the next four values if I froze, they did
nothing and my stamina still went down.

So for the easy solution, just FREEZE only ONE of these four values (to
SAVE some CPU cycles since freezing a value pushes it into memory every
so often), 00d19511 preferred, and you can run forever.

Conclusion:
The freeze solution takes some cpu cycles. Another solution would be to
find a STAMINA SHRINE and see how that works via the ADVANCED
search + increase/decrease and then freeze that.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: MANA

What you will learn:


How to find and modify your MANA so that it never decreases. If you are a
BLIZZARD LACKEY, and think that "hacking diablo 2 is gay" please visit
our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0

STEP 1:
Use a spell caster for best results, I used the Necromancer. The value for
the MANA ORB is stored in 4 bytes (dword) in a "bar" format meaning that
you can't see the value. So start up GAME HACK, select GAME.EXE or
DIABLO II from the process window (press the left most button).

In Diablo 2 make sure that your MANA ORB is filled to the top. Next click
on the BINOCULARS and select ADVANCED from the drop down list
under the SEARCH header. This will take the current state of memory.

Back in Diablo 2 use a spell till the bar (orb) decreases a bit. Pause the
game with ESC, and get into Game Hack. Now select the BINOCULARS
ICON that has a small arrow under it (the one that is next to the BIG
binoculars). Under the search select DECREASE and hit OKAY.

After Game Hack stops, go back into Diablo 2, run some more. Do the
Decrease Search yet again.

Now go back into Diablo 2 and let your mana orb fill up 100% by waiting
or just use a potion of mana. Now in game hack rather then a DECREASE
search, do an INCREASE search.

Continue this cycle until you get as few values as possible, 8 of them:

00d194fe <-real
00d194ff <-real
00d19400 <-real
00d19401 <-real
043a3ef6 <-just for show
043a3ef7 <-just for show
043a3ef8 <-just for show
043a3ef9 <-just for show
The first four values are the real values, I know this because if I froze these
values I could use bone armor or raise skeletons as many times as i wanted,
however the next four values if I froze, they did nothing and my mana still
went down.

So for the easy solution, just FREEZE only ONE of these four values (to
SAVE some CPU cycles since freezing a value pushes it into memory every
so often), 00d19401 preferred, and you can run forever.

Conclusion:
The freeze solution takes a some cpu cycles. Enjoy your spells.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: HEALTH

What you will learn:


How to find and modify your MANA so that it never decreases. If you are a
BLIZZARD LACKEY, and think that "hacking diablo 2 is gay" please visit
our complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0

STEP 1:
The value for the HEALTH ORB is stored in 4 bytes (dword) in a "bar"
format meaning that you can't see the value. So start up GAME HACK,
select GAME.EXE or DIABLO II from the process window (press the left
most button).

In Diablo 2 make sure that your HEALTH ORB is filled to the top. Next
click on the BINOCULARS and select ADVANCED from the drop down
list under the SEARCH header. This will take the current state of memory.

Back in Diablo 2 use a spell till the bar (orb) decreases a bit. Pause the
game with ESC, and get into Game Hack. Now select the BINOCULARS
ICON that has a small arrow under it (the one that is next to the BIG
binoculars). Under the search select DECREASE and hit OKAY.

After Game Hack stops, go back into Diablo 2, loose some health. Do the
Decrease Search yet again.

Now go back into Diablo 2 and let your health orb fill up 100% by waiting
or just use a potion of health. Now in game hack rather then a DECREASE
search, do an INCREASE search.

Continue this cycle until you get as few values as possible, 8 of them:

00d194ee <-real
00d194ef <-real
00d194f0 <-real
00d194f1 <-real
043a3eee <-just for show
043a3eef <-just for show
043a3ef0 <-just for show
043a3ef1 <-just for show
The first four values are the real values, I know this because if I froze these
values I could get hit as many times as I wanted, however the next four
values if I froze, they did nothing and my health still went down.

So for the easy solution, just FREEZE only ONE of these four values (to
SAVE some CPU cycles since freezing a value pushes it into memory every
so often), 00d194f1 preferred, and you can run forever.

Conclusion:
The freeze solution takes a some cpu cycles. Enjoy your longevity.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: SKILL POINTS

What you will learn:


How to find and modify your SKILL POINTS. If you are a BLIZZARD
LACKEY, and think that "hacking diablo 2 is gay" please visit our
complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better becuase its faster
for "exact value searches")

STEP 1:
Your character should at least have 2 or 3 SKILL POINTS that you can
distribute, if you do not have, attain it by LEVELING UP. The value for
SKILL POINTS is stored in 4 bytes (dword) in "exact value" format,
meaning that the value that you see on screen is the one that you want to
search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter how many SKILL POINTS you
currently can distribute and hit the FIND button. This may take a few
seconds to a few minutes depending on how fast your CPU is because d2
seems to be a memory whore. Hop back into Diablo 2 and use one of the
SKILL POINTS on a skill so that the value for SKILL POINTS drops 1.
Now alt + tab back to GT and enter your new value of your SKILL POINTS
ready to distribute in the GT edit box, but this time hit the SIEVE button.
This will only look at the addresses which matched your first search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value, increase it for best results. Hop back into
Diablo 2, the value of your SKILL POINTS will match whatever value you
entered. The value I had was 00d194e8, this address is static in memory
and will never change. So it will work every time you start up Diablo 2.

Conclusion:
Enjoy playing with the skill points and creating an ultimate character.
Remember that you must have at least 1 SKILL POINT to distribute so that
the [+] icon is enabled. Otherwise you will not be able to distribute your
points, but you will still have them.
^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques
Diablo 2: Experiance

What you will learn:


How to find and modify your EXPERIANCE. If you are a BLIZZARD
LACKEY, and think that "hacking diablo 2 is gay" please visit our
complaint board.

Things you need:


- Diablo2 version 1.2 Standard Edition
- GameHack 2.0 or Game Trainer 2.01 (the later is better because its faster
for "exact value searches")

STEP 1:
Your character should at least have 1 experience point, if you do not have
some experiance, GO KILL SHIT! The value for EXPERIENCE is stored
in 4 bytes (dword) in "exact value" format, meaning that the value that you
see on screen is the one that you want to search for.

Start up Game Trainer (GT from now on), select GAME.EXE under the
PROCESS: heading. Under TYPE: make sure that DWORD is selected, it
is the default. Now in the edit box enter how much your EXPERIENCE
currently is and hit the FIND button. This may take a few seconds to a few
minutes depending on how fast your CPU is because d2 seems to be a
memory whore. Hop back into Diablo 2 and kill some more enemies so that
your experiance goes up. Now alt + tab back to GT and enter your new
value of your EXPERIANCE in the GT edit box, but this time hit the SIEVE
button. This will only look at the addresses which matched your first
search.

STEP 2:
You should have only a few values, 1 - 3, add them to the list by clicking
the >> button. In your new list of matches, double click under the VALUE
header and modify the value, increase it for best results. Hop back into
Diablo 2, the value of your EXPERIENCE will match whatever value you
entered ONLY AFTER YOU KILL ANOTHER ENEMY. The value I had
was 00d19528 addresses are static in memory and will never change. So it
will work every time you start up Diablo 2.

Conclusion:
Don't put your experience to high, as having a level 99 character would
probably lead people to suspect that you cheated.

^chaos^
chaos world (c) 1999
Do not distribute as your own
please link here
TUT no1:
~~~~~~~~
Hacking Disciples: Sacred Lands - Advanced Game-Hacking

INTRO
~~~~~

OK! In the following, I'll teach you how to find the instruction that decrease
your money in DISCIPLES: SACRED LANDS. I must tell you that it uses DMA and
has an unusual (at least for me) method to dec your money!

Start the game,and choose to PLAY A QUEST(not saga) and take a look at the money.
Write the value down on a piece of paper, then press alt+tab. Now, start
GameTrainer or any other memory finding/editing tool (Gamehack,Tsearch,etc.)
and search for that value [if you don't know how to do that, i'll explain to
you but only for GameTrainer.

GameTrainer: <- JUST for newbies and those who don't know(yet) how
~~~~~~~~~~~~ to use a memory finder

----------------------------------------------------------------------
STEP 1: As "Process", select the game(---in my case disciple.exe);

STEP 2: In the "Value" box, type the amount of money you have;

STEP 3: In the "Type" drop-down menu select dword(means DoubleWord);

STEP 4: Press the "Find" button...

STEP 5: Now, down the "Find" button, it's the address list. Here you'll look
to see the money address. But after the search, this should contain
many addresses. That's because not only one memory address holds the
number you typed, but many more (in most of the cases). But you need
just the money address.To get that, go back in the game and spend some
money (ie: hire a unit, or build something). Now, you have less money -
remember the value or write it down.

STEP 6: Alt+tab and go back to GameTrainer.


In the "Value" box, type the new amount of money;
Press the "Sieve" button...

STEP 7: Look at the address list. If there are more than 3-4 addresses, you must
lose (or gain) some money in the game and start a new search by typing
new amount of money in the "Value" box, and always use the "Sieve" butt

STEP 8: Repeat this until you'll have only 3-4 addresses (in our case just one if
you play a quest). Very good...]
-----------------------------------------------------------------------

The Hack: <- FOR EVERYBODY


~~~~~~~~~

Well, we have the money addr. In my case is: 03B00A20. Since this game uses
DMA (dynamic memory allocation) your address WILL BE DIFFERENT. But that's
doesn't matter...

And, as you probably know, the classic method is this:


BPM 03B00A20 W --------------|
or |> in SoftIce
BPR 03B00A20 03B00A30 W------|

but in this case doesn't work.

This is what i got in SoftIce after putting a BPR 03B00A20 03B00A30 W

============================from here==================================
mov dx,[ecx]
mov [eax],dx
mov dx,[ecx+02]
mov [eax+02],dx
mov dx,[ecx+04]
mov [eax+04],dx
mov dx,[ecx+06]
mov [eax+06],dx
mov cx,[ecx+08]
mov [eax+08],cx --->>>here i land in SoftIce
ret 0004
===========================till here===================================

Well, eax+08 holds our money. But eax+08 is 03B00A20 (in my case, in your case
is the address you found with GameTrainer). If you don't believe me, type:

? eax+08

in SoftIce. Got it?

We can't overwrite this instruction, because it's used NOT only by the money_rout
but by others as well (i.e.: when you hire a unit, this instruction MUST be e
Otherwise, the unit can't be hired!). We can't set another breakpoint on eax+
because we already have one. MMmmmm... What to do???

I'll tell what to do in the following...

IF YOU KNOW A DIFFERENT METHOD, PLEASE LET ME KNOW!!!


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Let's put a breakpoint on 03B00A20 (in my case). But this time the breakpoint
should be rw(READ/WRITE) not only w(WRITE). So, in SoftIce type:

bpm 03B00A20 rw

OK...
Let's test it. Inside the game lose some money. SoftIce will break, and you'll be

mov [eax+08],cx like in the beginning.

But this time eax+8 will not be 03B00A20(my case). It'll be a different value.

Now the things are like this:

When you lose some money, the game uses different addresses to hold your money
FROM WHERE IT DEC THE AMOUNT. Then it stores the new amount (after you lose s
in 03B00A20 (in my case). Let's say that you lose some money. The game saves
money you had (before losing) in a temp. address, it does the operations (dec
this temp. address, then stores then new value in 03B00A20 (in my case). That
how the game works (in my opinion). Now, we only need to trap this tmp. addre
BEFORE THE GAME WILL DEC THE AMOUNT. This means we must trap it when the game
to put in it the money you have BEFORE the game will dec the amount. That's w
a read/write breakpoint. When SoftIce popped the second time, eax+08 stores t
address. So, put a breakpoint on it:

bpm eax+8 w

We'll use a write-only breakpoint because the game will now modify that amount.

Now,F5 to exit SoftIce, and you'll be again in SoftIce. But guess where? Exactly
instruction that dec your money!!!:

===============================from here===============================
mov dx,[ecx]
sub [eax],dx
mov dx,[ecx+02]
sub [eax+02],dx
mov dx,[ecx+04]
sub [eax+04],dx
mov dx,[ex+06]
sub [eax+0],dx
mov cx,[ecx+08]
sub [eax+08],cx *** what can this be ?!?!?! hehehe...***
mov cx,[eax] <-- here I land in SoftIce
test cx,cx
=============================till here=================================

So looking at the code, I figure it out that the "sub [eax+08],cx" is the nasty
instruction that dec our money. Now all you have to do is to nop or change o
do whatever you wanna do with that instruction! You can also make a trainer
modify the .exe ...

Well my job here is done. But there is another question: what are the rest of the
"sub"-instructions do there? I'll let you figure it out what they do! (you m
play the game if you wish to know)...

HUH!
~~~~

This was my first tutorial about gamehacking. I hope you learnt something useful.
I'm glad I can share my knowledge with all of you, and remember : If you kno
something useful, don't keep it just for you! Because you are not the only o
knows it, and sooner or later, it'll be clear like the sunlight for EVERYBOD
it took a long time for you to discover that, but the happyness of teaching
others will be huge !

License, legal stuff, etc etc


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You are free to do whatever you wanna do with this tutorial. But if you think tha
is good and people will learn something from it, spread it!!!

NOTE : This tutorial is dedicated to the wonderful people in the GameHacking foru
~~~~~~ ~~~~~~~~~

mail-me! ( Splinter@email.ro )
Sorin greets you!

2003

[BEST VIEWED WITH NOTEPAD 800X600]

eof
Advanced Game Training Techniques - Tutorial 2 PART I
Drakan and Dynamic Memory Allocation

What you will learn:


This is just another example of attacking DMA with a different game. We
will stop health from decreasing, and then we will learn how to stop the air
meter from decreasing permanently. It is recommended right now that you
go read the tutorial 1 before you go onto this one.

NOTE: Drakan was protected with some kind of exe protection, which has
anti-softice code in it. This tutorial assumes you have the the unpacked
executable, most likely available from http://www.gamecopyworld.com/.

Also it is suggested that when you setup softice, choose the universal VGA
driver if possible. Most other video drivers will cause games/your system
to freeze when popping into Softice.

Things you need:


- softice 3.x - 4.01 for Win9x
- Unpacked Drakan EXE file
- GameHack 2.0
- Very basic knowledge of ASM (assembly)

Step 1: Your health..:


Okay, you start out the game (and what a great game it is) and you see you
have a red ball that is your health counter. So use game hack's
ADVANCED search for an unknown value. I will let you know right now
that if you search for a byte you will come up with only one value, but when
you search for 2bytes you will get two values. So lets explain, you will get
0117a988 and then a random value which would be similar to 03447e30
(that's what I got). If you play around with the values you will see that the
first value in fact is just the on screen representation of the real value
(second mem addy). Remember, this second memory address will be
different every time you load a level or a savegame. So here we are,
another game trying to use dynamic memory allocation to stop people from
cheating.

If you play around with these values, and you freeze the 0117a988, you will
see that the ball is fluctuating if the two values do not match. Since that
second address is different every time you can't just make your trainer
freeze that memory address because it will not work. So now lets load up
Softice, type (USE YOUR SECOND RANDOM EVERY TIME MEMORY
ADDRESS):
:bpm 03447e30 w
Now go find an enemy, when the enemy hits you, softice should pop up.

:memory :hex :asm


010824de 895104 mov [ecx+04],edx
010824e1 7e03 jle 010824e6 ---------
010824e3 894104 mov [ecx+04],eax -
010824e6 5f pop edi <--------
010824e6 5e pop esi
010824e6 5d pop ebp
010824e6 5b pop ebx
010824ea c20400 ret 0004

NOTE: you can use the softice command BPX (break point on execution) to
get to 010824e1 the next time you need to for whatever reason without
having to find that random value again (that is if you died in the process of
figuring this tutorial out). Just type:
:bpx 010824e1
Also be sure to clear all breakpoints when you are done with BC *

Okay, some really quick asm before we move on, please learn asm !
JLE = jump if less or equal, the arrow I drew shows where this jump hops
to

A value inside the [ ] means that it is really a memory address

RET = return to the spot right after the last CALL, a CALL calls a function

In softice, if you look around where SI popped up, you will NOT see any
kind of ASM code like DEC or SUB. You could possibly take out one of
the MOV instructions but you might take out something important and make
the program crash. So now in SI press F10 (to go to the next instruction)
until you get to the RET 0004, or press F12, which brings you to the
instruction right after the last CALL (which happens after you exit the
function using the ret). Please consult your softice documentation if you do
not understand. Every call has a RET inside of it to signal the end of the
call. So I pressed F12, this lead me to the following code:

:memory :hex :asm


010824fe 2bc2 sub eax,edx
010824500 50 push eax
010824501 e88af3ffff CALL 01082390
010824506 5e pop esi
010824507 c20400 ret 0004

When you pressed f12, the current highlighted line in SI is the one right
after that call (in red). If you scroll up just a bit you will see a SUB EAX,
EDX. So you know you can NOP this with two 9090 or you can change the
SUB to an ADD by changing the 2b to 03. A quick explanation of this is that
damage (edx) is subtracted from life (eax), and then its pushed back into
EAX (kept for later reference) and then in the CALL it is used to determine
how much health you have.

I know this part of the tutorial was very messy, I was trying to teach too
many things at once. ASM, how to use softice..etc. Hopefully you
understood it. Now we will tackle the air supply meter.

Step 2: The air supply meter..:


Go in the water, do another advanced search with GameHack. Now dive
under water wait for your air meter to decrease. Pause the game, go to GH
and do continue search for 2 BYTES. Now go up for air, research. Do this
until you get one or two values. I got two values, 0363F278 and
036401AC. Now freeze one value at a time. If you freeze the first one, you
will see that you can stay under water forever. If you freeze the second
value (unfreeze the first),you will notice that the second value is junk, so
get rid of it.

Do the following:
:bpm 0363f278 w (I think the value is random so use your own)

Once you go underwater SI should pop with:

:memory :hex :asm


010740ed a198ae1701 mov eax, [0117ae98]
010740f2 d8481c fmul real4 ptr [eax+1c]
010740f5 d8ae56080000 fsubr real4 ptr [esi+ 00000856]
010740fb d99656080000 fst real4 ptr [esi+00000856]

Okay we found where its doing the subtracting. But take this into account, if
your NOP that red line, you will really be multiplying (fmul) some value
with 0 (what you nop'd) the next time it passed through this function, which
ultimately would be 0. Because any value multiplied by 0 = 0. This WILL
give you infinite air, but your counter will always zero out the second you
get underwater. If you scroll up you can't find another DEC or SUB in sight,
but right above it is a MOV eax, [0117ae98]. By NOPing that line the air
meter will no longer decrease. AND it won't zero out.

This part is unnecessary. If you press f12, and then scroll up you will see
that there is one CALL function before the one you just RETurned out of.
Above that is a SUB instruction. So it looks something like this:

SUB EAX,EDX
.....
04000000 CALL 00123123 ( I made these numbers up!!! )
.....
0400fefe CALL 04930293
0400feff pop esi

That SUB is very far away, Eax is probably not even the air supply value at
this time. So if you NOP'd that SUB you might get rid of something
important causing the game to crash or freeze. EAX is manipulated in the
first CALL, which could do a number of things. Eax becomes the air supply
value some where in the CALL 04930293.

You could BPX 0400fefe (this is NOT the right value, I made it up!), and
then you could trace into the call with F8 in softice.

Conclusion:
Yes, I know this tutorial was pretty sloppy. I am trying to educate the
newbie too, not just the SI/ASM expert. This "hack" would transfer over to
multiplayer, so do not cheat in multiplayer even though its lagged as hell
already.

Please read your softice manual, SI is a great tool only if you know how to
use it. Next, I'd suggest learning some ASM. Your best resource would be
"the art of asm", you could probably find it in .pdf format on most search
engines. If you have any questions, feel free to ask.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Game Training Techniques - Tutorial 4
Dune 2000: Level Skip

What you will learn:


In this lesson you will learn how to make a level skipper. A level skipper
lets you complete the current mission instantly. This is usually stored in a
flag or sometimes multiple flags for each objective. A flag is usually a 0
(off) or 1 (on) but not always.

Things you need:


- Dune 2000
- GameHack 2.0

Step 1: Finding the memory address:


First off, be sure to select the right D2k process. Dune2000.exe is just a
pre-loader for the real file which is Dune2000.dat. Now with that out of the
way, start the first single player mission, to collect 2500 credits. Play the
mission till you have about 2400 credits and save the game. You may have
noticed that when you alt + tab out of the game, it plays on, you have to hit
escape to get to the options menu in order to pause the game.

Alt + tab out of D2k. Start up Game Hack. Select Dune2000.dat as the
process. In most flag related cases we are looking for a 0 (not complete
yet) or a 1 (mission objectives complete). Below I try to find the value as if
I did not know it was a 0 or a 1, it could be two different values instead.

1. In game hack click on start search (binoculars) and select ADVANCED


under the search drop down box.
2. Now go back to the game and collect more spice and deposit it until you
have over 2500 credits. You should hear a sound saying 'mission
accomplished'.
3. Alt + tab out of the game and select Next Search. Select increase and hit
okay.
4. Now load the saved game and go to Next Search and do a decrease
search. 5. Collect some more credits till you accomplish the mission. Now
do an increase search.
6. Continue this steps 2 - 5 till you have as little hits as possible, for me it
was around 175 hits and I couldn't get it any lower.
7. Add all your hits with the [>] button.

Step 2: Some guess work:


If you haven't already, reload the save game. You will notice that a
majority, if not all, of the values in GH are 0. Go into the game, move your
harvester into the refinery and alt + tab out of the game (DO NOT HIT
ESCAPE TO PAUSE THE GAME). Maximize your GH window so you
can see as many values as possible. When you get 2500 credits (you are
still watching GH at this point) you will hear "mission accomplished" (yes,
even though you are not in the game you will still hear it), so we can deduce
that the flag was set a millisecond before you heard the "mission
accomplished". If you watched carefully you would have noticed which
values turned to 1 as the sound happened, and which values turned to 1 way
before/after the sound. Now its just down to a few values, so reload the
saved game and in GH change the value from 0 to 1. If you change the right
one you will hear mission accomplished. The address is 006B0DD4 in the
retail release (v1.02), it changed to 1 a millisecond, almost at the same time
as the "mission accomplished" sound started to play.

Conclusion:
There we go, when you push the value 1 into 006B0DD4 your mission is
accomplished. You have to remember that a flag may not always 0 or a 1, it
could be any two different values one meaning true and the other false. In
some games you might notice that the flag values are reversed, 0 might
mean true and 1 means false sometimes.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Game Training Techniques - Tutorial 5
Dune 2000: Map Reveal

What you will learn:


In this lesson you will learn how to make a map revealer, which will reveal
the minimap & all the fog on the battle field using a 'dead listing' approach.

Some interesting things:


In all Westwood Real Time Strategy games, they include something called
crates. Crates give special power-ups to the unit that picks it up such as
money, invisibility, and sometimes it will reveal the whole map/minimap.

A ptr is a pointer. A pointer is used in programming to point to a memory


address. As seen on 004503eb: mov al, byte ptr [0078e074], this pushes the
value in address 0078e074 into al. However sometimes there might be an
instruction like mov al, byte ptr [esp+13], that is dynamic memory.

Things you need:


- WinDasm 8.xx or later
- GameHack 2.0
- Dune2000.dat (download this file if you don't have d2k but still want to
try the tutorial 412KB)

Step 1:
As you may have read in tutorial 4, Dune2000.exe is just a pre-loader for
the real game Dune2000.dat. So open up Dune2000.dat with WinDasm.
This is referred to as 'dead listing' because you will soon have the read out
of the games assembly instructions at your disposal to browse as you
please, this is not a 'live' approach because we are not going to search with
game hack for a increase or a decrease in values while playing the game.

Now that you have the listing of the game go to the string references
(second to last icon on the tool bar). At this point you would look for any
reference to what you were looking for, in this case anything to do with map
or reveal. The reference I found was 'Ex_CrateReveal', so using my
previous knowledge that there were crates that reveal the map I assumed
this is what I was looking for. So double click on the Ex_CrateReveal
reference, it should take you to the spot pictured below. This
Ex_CrateReveal function would be called if you picked up a crate in the
game that revealed the map for you.

click on picture for bigger version


* Possible StringData Ref from Data Obj ->"EX_CrateReveal"
|
:004503d9 685cf54d00 push 004df55c
:004503de 52 push edx
:004503df e8cc890600 call 004b8db0
:004503e4 83c408 add esp, 00000008
:004503e7 85c0 test eax, eax <- tests what kind of crate
crate it is.
:004503e9 750f jne 004503fa <- If it is not a reveal
crate it goes to :004503fa
to further determine what
kind of crate it is.
:004503eb a074e07800 mov al, byte ptr [0078e074]
:004503f0 a24dec6c00 mov byte ptr [006cec4d], al
:004503f5 e9b2020000 jmp 004506ac <- the crate that you picked
up was a reveal crate so
now you jump to :004506ac
Double click on this line
highlight it, and then
hit the 9th from the left
button "Jump to".

click on image for bigger version

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:


.. <-- these numbers (in the picture) show who caused a jump to :004506ac
..
..
:004506ac 8a442413 mov al, byte ptr [esp+13]
:004506b0 3c01 cmp al, 01 <- compares value in al with 1
:004506b2 0f85c1010000 jne 00450879 <- jump if not equal to 1
:004506b8 a0d46c4e00 mov al, byte ptr [004e6cd4] <- looks kind
of suspicious
so plug this
address in to
Game Hack and
change the
value from one
to zero.
:004506bd 84c0 test al, al
:004506bf 0f859c010000 jne 00450861
:004506c5 837c241c28 cmp dword ptr [esp+1c], 0000028
:004506ca 7612 jbe 004506de
Conclusion:
It ended up working, so I guess I would call this luck just because I found a
reference to Ex_CrateReveal. Using WinDasm is good a way to find values
you are looking for without actually searching through the processes
memory. The live approach would be easier in retrospect so here goes:

A way to find the same value in 'live' mode would be to play the 'practice'
mode with crates ON, play until you find a crate but save it just before you
pick up the crate. The contents of the crates are not random, they are the
same every time so reloading the save game won't give you something
different the next time. So if its a map reveal crate then your in luck,
otherwise keep on playing till you find another crate and save it again
before you get it. You save the game before you pick up the crate because
is_map_revealed = 1 (1 = false this time around), and after the you get the
crate is_map_revealed = 0 (true). You would figure this out through trial
and error. This approach will work in all Westwood games as they include
crates in all of them. As you can see there are two ways to solve this: a
dead and a live approach, do whichever one you deem easier.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Game Training Techniques - Tutorial 6
Dune 2000: Fast Build

What you will learn:


In this lesson you will learn how to make an instant build for Dune 2000,
this means that units and buildings and everything will pop out instantly.

Things you need:


- Dune 2000
- GameHack 2.0

Step 1: Finding the memory address:


This is trial and error, but with this game the 'Current % Done' value is
stored in two bytes (word) and counts up from zero.

1. Start a practice game, I played Harkonen, the address for each of the
three sides is different incase you wanted to know.
2. Deploy your MCV.
3. Click on the Wind Trap and start building it, wait a second and right
click to make it go "on hold".
4. Start Game Hack and do the Advanced search.
5. Back in D2k left click on the picture of the building so that it builds a
little bit more and then once again put it on hold.
6. In game hack do Next Search, select 2 Bytes (word) and select
"increase" under the search type.
7. Repeat steps 5 and 6 until you get as little values as possible, I came out
with like 5. Add those values to Game Hack with the [>] button.
8. Back in D2k left click on the picture of the building so that it builds.
9. Since the game does not pause them you Alt + Tab, go watch the values
in GH and see which ones increase incrementally.
10. You will see that 007BAA36 (this is a static address) holds the 'Current
% Done' value, it counts from 0 to 23040

You will have to repeat this cycle for the right slider as well. This will
work for infantry, vehicles, and super weapon.

007BAA4A break down (FAST BUILDING


INFANTRY/VEHICLES/SUPER WEAPON)

Barraks just placed down : 0 <-- no value assigned yet


unit start building 11% : 540 <-- started building
unit building still 65% : 14760 <-- still building
unit done building : 23040 <-- unit finished building
no units building : 23040 <-- it keeps the old value
unit started building : 360 <-- counter returns to 0 after you
click to build.

There is a problem however, when you get a super weapon. It will always
be "READY" so when you try to build a infantry or a vehicle they will go at
a normal build rate.
Since you can build a vehicle and a infantry at the same time we can infer
that there are some secondary counters, one for infantry and the other for
vehicles, just search the same way as above.

007BAA36 <- buildings


007BAA4A <- everything on the right bar UNTIL you get a super weapon,
at that point this value only makes super weapon instantly build.
007BAA5E <- vehicle fast build secondary value
007BAA72 <- units fast build secondary value

Conclusion:
That is how to make a fast build, just push the the value 23040 into the
addresses every couple seconds.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Advanced Game Training Techniques - Tutorial 7
Dune 2000: Unlimited Power

What you will learn:


In this lesson you will learn how to get unlimited power.

Things you need:


- Dune 2000
- GameHack 2.0
- SoftIce

Step 1: Finding the memory address:


If you put your mouse over the green bar on the sidebar that represents your
power, after a few seconds it will give you a number representation. Use
game hack and find the values (they are both word), I came up with two
values: 007b8ac8 and 007b8acc. The first value was the real value, but if
you tried to freeze it, it would go back to the original value. So lets
eliminate that.

In softice do: bmp 007b8ac8 w and go back to the game.

Wow it popped back into SI with a hit. This must mean that something was
writing the real value into 007b8ac8. (The yellow is where the SI highlight
is when you pop back into SI, however as you should know the line
ABOVE the highlight is the one that affected your value)

0167:00455927 85ff test edi, edi


0167:00455929 c781a8450200000000 mov dword ptr [ecx + 000245a8],
00000000
0167:00455933 c781ac450200000000 mov dword ptr [ecx + 000245ac],
00000000
0167:0045593d c781b0450200000000 mov dword ptr [ecx + 000245b0],
00000000
0167:00455947 0f84bf000000 jz 00455a0c
0167:0045594d 8a4734 mov al, [edi+34]

If you look above and below (go until you see the RET's), this function
checks how much energy you have and writes it back to memory. There are
no sub or add or anything like that, so hit F12 to go to to the RET(urn).

0167:004328ce e84d300200 call 00455920 <-- this call checks


power
0167:004328d3 46 inc esi

If you NOP 004328ce then the game will never check how much power you
have and try to set it back to its real value. So in softice do:

e 004328ce 90 90 90 90 90 and then hit enter.

Conclusion:
Now if you build a wind trap your power will not go up or if you
sell/destroy your current wind traps your power will not down. Now that
the game never modifies the power value, feel free to push 999 into
007b8ac8.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Bie comment:
This info is taken from http://www.codeproject.com/script/Articles/list_articles.asp?userid=172641
This article have to be edited to maintain this GHA size, please visit the link above for complete tutorial

Tutorial Author: arikp


Email: Unknown
Homepage: Unknown
Other known method to contact the author

Unknown
Introduction

Yep, again. For those of you who liked my first article "Minesweeper, Behind the scenes" I present here his natural sequel. The idea came when a friend of mine read the former article and joked
me about it, "now do hearts.." he said, so I did and this article is the final result. At this point I would like to thank some friends who helped me, Itay Langer, Michael Kuperstein and Yoav Sion (in
alphabetical order).

Two weeks ago, when I wrote the first article, I've explained the use of API functions with C# (using P/Invoke) to read another process memory. Also I've written an example for using this class
library in order to read the Minesweeper mines map. In that article I've claimed and I still claim that the goal of the article was not how to hack Minesweeper. The goal of that article was to provide
the reader a simple class library in C# that will allow them to read another process memory. To my surprise, many people who read the article was very interested in the example I've brought.
Because of that I cant really claim that the goal of this article is to learn how to use some new API functions in order to have functionality unsupported by C#. The goal of this article is to see what
is happening behind the scenes of the two Microsoft card games: FreeCell and Hearts. In spite of this goal my conscience cannot let me publish an article with no new coding feature, So I've
enhanced the library and now it supports also writing into another process memory. I've even done a use of this function in one of the examples.
Main Goals

1. FreeCell behind the scenes and developing a cool app that uses this knowledge.

2. Hearts behind the scenes and developing a very cool app that uses this knowledge.

3. Write to another process memory using the WriteProcessMemory API function.

Note: The first two sections are using a debugger to investigate the games, my personal favorite debugger is Olly Debugger v1.08 but any debugger will do.
Section 1: FreeCell, How does it work?

I imagine you ask yourself what is to crack in FreeCell? you already see all the cards! Well the point is to understand what it does and how it gets these cards. Also suppose you can read the cards,
you can write a program that plays Freecell by herself.. but you must have a way to read the freecell memory.

The first step, like always, is opening the file in the debugger. In this case we need the freecell.exe file which is found in the windows\system32 folder. After opening the file we need to find an
interesting starting point. When you look at the beginning of the file you see a list of functions imported from dll's as follows:

01001188 DD USER32.GetDlgItemInt
0100118C DD USER32.SetWindowTextW
01001190 DD USER32.wsprintfW
01001194 DD USER32.GetSysColor
01001198 DD USER32.GetWindowDC
0100119C DD USER32.IsIconic
010011A0 DD 00000000
010011A4 DD msvcrt._except_handler3
010011A8 DD msvcrt._controlfp
010011AC DD msvcrt.__set_app_type
010011B0 DD msvcrt.__p__fmode
010011B4 DD msvcrt.__p__commode
010011B8 DD OFFSET msvcrt._adjust_fdiv
010011BC DD msvcrt.__setusermatherr
010011C0 DD msvcrt._initterm
010011C4 DD msvcrt.__getmainargs
010011C8 DD OFFSET msvcrt._acmdln
010011CC DD msvcrt.exit
010011D0 DD msvcrt._cexit
010011D4 DD msvcrt._XcptFilter
010011D8 DD msvcrt._exit
010011DC DD msvcrt._c_exit
010011E0 DD msvcrt.isdigit
010011E4 DD msvcrt.time
010011E8 DD msvcrt.srand
010011EC DD msvcrt.rand

This is only the final part of the list, but If you look carefully you see that the last imported function listed is the function rand from the msvcrt dll, which is off course the randomize function from
the microsoft visual c runtime dll. So I've decided to search where this function is being used.

I've found two places where this function is being used. Then I put a breakpoint on both places and run the program. After I've started a new game the program stopped on the first breakpoint
once and 52 times on the second breakpoint. Here is the part where the brain needs to kick in, mine said that the first breakpoint randomize the game number and the second breakpoint
randomize the position of each card (or the card of each position) (remember you got 52 cards..).

So, I did a little test to prove me theory. I ran the program till the first breakpoint, then step over the rand function and look at the eax register, the value of this register was 0x00006A26, then I
continue to run the program, the game number (displayed in the caption) was 25254.. bingo, 0x6A26 = 25254. So now I knew I was right I needed to find where freecell stores this value and the
cards values, so I could read them later with my program. I started a new game and now I've investigated the second breakpoint. A few instructions before the breakpoint I've found a very
interesting piss of code. The code I've found store a value in a specific place in the memory, and then formatted the string "FreeCell Game #%d" with this same number, so THIS is where it stores
the game number.. The code is presented here:

010031D0 MOV DWORD PTR DS:[100834C],EAX


010031D5 PUSH ESI
010031D6 PUSH EDI
010031D7 PUSH 80 ; /Count = 80 (128.)
010031DC MOV ESI,freecell.01007880 ; |
010031E1 PUSH ESI ; |Buffer => freecell.01007880
010031E2 PUSH 12F ; |RsrcID = STRING "FreeCell Game #%d"
010031E7 PUSH DWORD PTR DS:[1007860] ; |hInst = 01000000
010031ED CALL DWORD PTR DS:[<&USER32.LoadStringW>>; \LoadStringW
010031F3 PUSH DWORD PTR DS:[100834C]
010031F9 PUSH ESI ; |Format => ""
010031FA MOV ESI,freecell.01007820 ; |UNICODE "Cards Left: %u"
010031FF PUSH ESI ; |s => freecell.01007820
01003200 CALL DWORD PTR DS:[<&USER32.wsprintfW>] ; \wsprintfW
01003206 ADD ESP,0C
01003209 PUSH ESI ; /Text
0100320A PUSH DWORD PTR SS:[EBP+78] ; |hWnd
0100320D CALL DWORD PTR DS:[<&USER32.SetWindowTex>; \SetWindowTextW

As you can see, the first line store the eax register value (which is the randomized number from the first breakpoint) in the specific memory address 0x0100834C. By the way, there is no way you
can tell from the code what the value of eax is, But when you actually use the debugger, at runtime, you can see this is the same value you got from the first rand function.

Back to the second breakpoint. As I said earlier the second breakpoint is being heat 52 times which is exactly the number of cards we have. So what's now interest me is where this code stores the
randomize cards. So lets look at the relevant code:

010032D3 PUSH EAX ; seed


010032D4 CALL DWORD PTR DS:[<&msvcrt.srand>] ; [srand]
010032DA POP ECX ; ebx = 52 (from earlier)
010032DB XOR ESI,ESI ; esi = 0
010032DD /CALL DWORD PTR DS:[<&msvcrt.rand>] ; [rand]: eax = randNumber
010032E3 |XOR EDX,EDX ; edx = 0
010032E5 |DIV EBX ; edx = randNumber % ebx
010032E7 |MOV ECX,ESI ; ecx = iteration #
010032E9 |AND ECX,7 ; ecx = ecx AND 7
010032EC |IMUL ECX,ECX,15 ; ecx = ecx * 21
010032EF |DEC EBX ; decrease iteration #
010032F0 |LEA EAX,DWORD PTR SS:[EBP+EDX*4-60]
010032F4 |MOV EDX,ESI ; edx = esi
010032F6 |SHR EDX,3 ; edx = edx / 8
010032F9 |ADD ECX,EDX ; ecx = ecx + edx
010032FB |MOV EDX,DWORD PTR DS:[EAX] ; load randCardNum
010032FD |MOV DWORD PTR DS:[ECX*4+1007554],EDX ; save in memory
01003304 |MOV ECX,DWORD PTR SS:[EBP+EBX*4-60]
01003308 |INC ESI ; esi = esi +1
01003309 |CMP ESI,34 ; check loop iterations
0100330C |MOV DWORD PTR DS:[EAX],ECX
0100330E \JB SHORT freecell.010032DD ; go to start of the loop

So, what we see in this code is calling the srand function with the seed as the game number randomize earlier. this is an important part to note. freecell has game numbers, and you can select a
specific game, so how is that possible that the game is randomized but if you select over and over the same game number, you get the same cards? well, the answer lies in the first two lines of
code, the "randomized" cards are randomized with the game number as a seed number to the randomize function. If the rand function is initialized with the same seed in the srand function, the
randomized number it will creates will be the same.

Line number 5 is a beginning of a loop, this loops iterate 52 times, and in each iteration, randomize a card number, and puts it on the next location in the memory. The line 010032FD is where the
randomized card number is saved in the memory. After tracing with the debugger a few timer on these addresses I can tell you this, there is 8 arrays of cards, the first iteration put the card number
as the first item in the first array, the following iteration puts the card number in the first item of the second array, and so forth. when it gets to card number 9 it starts over, putting the card
number as the second item in the first array..

So what's the point with these 8 array? Well, the reason we got 8 array is because freecell has 8 columns of cards. so each array is a column of cards. Again, after tracing the loop a few times I've
discovered that the formula for the address where the card is saved is: CardAddress = BaseAddress + 0x54*I + 4*J, where BaseAddress is 0x1007554 (mentioned in line 010032FD), I is the
column number (0..7) and J is the row number.

So, now that we got the addresses we can go on and make the Freecell Memory Reader app. The form contains 8 listbox controls, one for each column. The first thing we do is checking which
operating system are we on, the freecell I've checked was on XP, I've also searched the addresses for win2K, but I couldn't test the program, so if it doesn't work on win2K, please leave a
comment and I'll fix it. Anyway, I check the operating system and according to it I set the addresses I'm going to use later. Then I search the process of freecell using the static method
Process.GetProcessesByName() and then I open a new instance of my ProcessMemoryReader class. This class was introduced in my previous article so check it for details explanation on the use of
this class. After opening the process I read the game number from the game number address. then I loop over the cards array and for each place in the array I read its memory, convert the card
number to a normal card number and place it on the proper listview (according to its column).

"Convert the card number"? Well, here I need to explain how the card is stored in memory. The number that was randomized earlier was a number between 1..52, so I need to convert it to the
card's number (1..13) and the card's kind (1..4). At first I thought that the conversion is simple, I thought that it was organized like this:

Kind | Number | original number

1 1 1
1 2 2
1 3 3
1 4 4
...
2 1 14
2 2 15
...
4 12 51
4 13 52

Well, it turns out that is not the case.. instead of specifying all the cards from one kind and them the next kind and so forth (1..13,1..13,1..13,1..13) they decided to specify the sets of card
numbers. (1..4,1..4,1..4, 13 times), like this:

Kind | Number | original number

1 1 1
2 1 2
3 1 3
4 1 4
1 2 5
2 2 6
...
3 13 51
4 13 52

I hope its clear now, That's why a conversion is needed. One Last thing to mention is that when I read the game number from the memory I get a 4 bytes array and I need to convert it to an
Int32, there are better ways to do it then how I did but I kept my way for simplicity. So the code is as follow:

IntPtr GameNumAddress;
IntPtr CardsAddress;

// check if version is win2k or winXP


if (Environment.OSVersion.Version.Major == 5)
{
if (Environment.OSVersion.Version.Minor == 0) // win2K
{
GameNumAddress = (IntPtr)0x010071F8;
CardsAddress = (IntPtr)0x01007f74;
}
else // winXP
{
GameNumAddress = (IntPtr)0x0100834C;
CardsAddress = (IntPtr)0x01007554;
}
}
else
{
MessageBox.Show("Sorry, only winXP and win2K are supported!");
return;
}

// Search the Hearts Process


Process[] pArray = Process.GetProcessesByName("freecell");
if (pArray.Length == 0)
{
MessageBox.Show("No Freecell process!");
return;
}

// Create memory reader


ProcessMemoryReaderLib.ProcessMemoryReader pReader = new ProcessMemoryReaderLib.ProcessMemoryReader();

// Take the first process found


pReader.ReadProcess = pArray[0];

pReader.OpenProcess();

for(int i=0 ; i<8 ; i++)


listArray[i].Items.Clear();

int iGameNum;
int readBytes;
byte[] buffer;
int CardNum, CardKind;
string ItemString = "";
bool bAddCard;

buffer = pReader.ReadProcessMemory(GameNumAddress,4,out readBytes);


iGameNum = buffer[0] + 256*buffer[1] + 256*256*buffer[2] + 256*256*256*buffer[3];
txtGameNum.Text = iGameNum.ToString();

for (int i=0 ; i<8 ; i++)


{
for (int j=0 ; j<21 ; j++)
{
buffer = pReader.ReadProcessMemory((IntPtr)((int)CardsAddress + 0x54*i + 4*j),4,out readBytes);
CardNum = (buffer[0] / 4) + 1;
CardKind = (buffer[0] % 4) + 1;
bAddCard = true;

switch (CardNum)
{
case 11:
ItemString = "J";
break;
case 12:
ItemString = "Q";
break;
case 13:
ItemString = "K";
break;
case 64:
bAddCard = false;
break;
default:
ItemString = CardNum.ToString();
break;
}

if (bAddCard)
listArray[i].Items.Add(ItemString ,CardKind -1);
}
}

pReader.CloseHandle();

On to the next game..


Section 2: Hearts, How does it work?

This game was far more difficult to debug from the rest, because of the complex ways the cards are stored in the memory. Also the example works only on XP, cause I couldn't find Hearts on a
win2K system, so I couldn't search for the parallel addresses. Because of its complexity I'll will keep my explanations nice an simple, and I won't get into details.

So, how many of you knows how do I start? That's right, we open the program in the debugger (mshearts.exe) and search the file for the famous rand() function. We will find to places, and we
will put a breakpoint on each place. Then we will run the program. As soon as we start a game, the first breakpoint will pop once and the second breakpoint will pop 52 times.. I think we have
found the interesting part.. So as always we will look at the code and search for the memory addresses where the values are being stored. Brought to you here is the code of the second
breakpoint:

01007FB6 /CALL DWORD PTR DS:[<&msvcrt.rand>]


01007FBC |CDQ
01007FBD |IDIV DWORD PTR SS:[EBP-18]
01007FC0 |MOV EAX,DWORD PTR SS:[EBP-14]
01007FC3 |PUSH 0D
01007FC5 |POP EDI
01007FC6 |PUSH 4
01007FC8 |POP EBX
01007FC9 |MOV ECX,EDX
01007FCB |CDQ
01007FCC |IDIV EDI
01007FCE |SUB EAX,DWORD PTR DS:[ESI+140]
01007FD4 |MOV EDI,EDX
01007FD6 |ADD EAX,4
01007FD9 |CDQ
01007FDA |IDIV EBX
01007FDC |LEA EAX,DWORD PTR SS:[EBP+ECX*4-110]
01007FE3 |MOV EBX,DWORD PTR DS:[EAX]
01007FE5 |SHL EDI,4
01007FE8 |LEA ECX,DWORD PTR DS:[ESI+EDX*4+130]
01007FEF |MOV EDX,DWORD PTR DS:[ECX]
01007FF1 |MOV DWORD PTR DS:[EDI+EDX+1C],EBX
01007FF5 |MOV ECX,DWORD PTR DS:[ECX]
01007FF7 |XOR EBX,EBX
01007FF9 |DEC DWORD PTR SS:[EBP-18]
01007FFC |INC DWORD PTR SS:[EBP-14]
01007FFF |CMP DWORD PTR SS:[EBP-14],34
01008003 |MOV DWORD PTR DS:[EDI+ECX+28],EBX
01008007 |MOV ECX,DWORD PTR SS:[EBP-18]
0100800A |MOV ECX,DWORD PTR SS:[EBP+ECX*4-110]
01008011 |MOV DWORD PTR DS:[EAX],ECX
01008013 \JL SHORT mshearts.01007FB6

Yea, I know, lots of ugly code.. But I've bolded the parts that interest us, the first line is where we set out breakpoint, the rand() function is being called. The second bolded line (01007FF1) is the
line where the randomized value is stored in the memory. note that this is the first operation of the kind: MOV <memory address>,<value> ,So I've check carefully what is happening in this
command. After tracing it a few times I've found some logic in what address are being used to store the values. The first 13 iterations of this loop (by the way, the code brought here is a loop) are
accessing a zone in the memory, we will call it zone A, the next 13 iterations access a different zone in the memory, zone B, and also the next 13 iterations and the last 13 iterations. so what do
we got here. 52 iterations, each 13 we change to a different zone in the memory. Also I've found that the difference between the memory addresses in each set is equal to 16.

So, you see, we have 4 main base addresses, each one is an array, so the first item is in ZoneA + 0, the second is in ZoneA + 16 and so forth. According to the picture the 4 base addresses are
stored in an array, this is correct. I've discovered that there is an array of 4 addresses, each item of that array is a pointer to another array of 13 items. All this is very nice, but I still have a
problem, all of the addresses involved in this structure are dynamic, meaning they changed from run to run. I need to find an address that every time the program starts, it will always be a static
pointer to the base address (the Base address is the address of the 4 pointers array). How do I know this kind of static pointer does exist? well, this involves explanations on what happens when
you create a variable on the stack, and what happens when you create a variable on the heap (I'm talking about unmanaged code off course). So when you create a variable on the stack, its
address is written to the file and so cannot change when you run different instances, but if you create a variable dynamically, his address is not known at design time and so cannot be written to
the file. now suppose you got a pointer to an array, so the array can be in every size you want, and you cant create it dynamically and so on, BUT the pointer itself IS static and declared on the
stack so there is always a need for at least a static pointer that holds the structure, and this static pointer has always the same address. So now I know it exists, how do I find it? Well, I've just did
a search. I ran an instance of the program, and saw what was my Base address (the address of the array of addresses) and then I've did a search on the memory to find where is this base address
is stored on the memory, and I've found only one such address. bingo. Now, the trick is to know in which region of memory to look for, cause how can you tell if the memory you are looking on is
the dynamic memory or static memory? Well, the region of memory that is between 0x0100D000 and 0x0100E000. This is only for this specific file. Each file has its own .data section, and this is
the section where all the static memory is stored.

If you didn't understand all the details it is not important, all you need to know is that we got a Static address = 0x0100d514, this static address is a pointer to another pointer we will call
PointerArrayAddress, the PointerArrayAddress is a pointer to an array of 4 pointers. Each pointer in the array is a pointer to an array of 13 items. each item contains a card number. each array of
cards is a player. and now all I need to do is read this structure and display it on the screen.

So what does out code do? First we find the Hearts process, then we read the static pointer, then we read the 4 pointers of the arrays, and then we read the 52 items out of the arrays, for each
item we convert its card number into a normal representation. if you remember from the previous section the conversion to the cards, here it's the same. and finally we add it to the proper list on
the screen (we got 4 lists). The code is as follows:

// Search the Hearts Process


Process[] pArray = Process.GetProcessesByName("mshearts");
if (pArray.Length == 0)
return;

// Create memory reader


ProcessMemoryReaderLib.ProcessMemoryReader pReader = new ProcessMemoryReaderLib.ProcessMemoryReader();

// Take the first process found


pReader.ReadProcess = pArray[0];

pReader.OpenProcess();

int i;
int readBytes;
byte[] buffer;

IntPtr StaticAddress = (IntPtr)0x0100d514;


buffer = pReader.ReadProcessMemory(StaticAddress,4,out readBytes);
IntPtr PointerArrayAddress = (IntPtr)(
buffer[0] +
256*buffer[1] +
256*256*buffer[2] +
256*256*256*buffer[3] + 0x130);

IntPtr[] aArray = new IntPtr[4];


buffer = pReader.ReadProcessMemory((IntPtr)PointerArrayAddress,16,out readBytes);
for (i=0 ; i<4 ; i++)
aArray[i] = (IntPtr)(
buffer[4*i] +
256*buffer[4*i + 1] +
256*256*buffer[4*i + 2] +
256*256*256*buffer[4*i + 3] + 0x1c);

for (i=0 ; i<4 ; i++)


listArray[i].Clear();

int CardNum, CardKind;


string ItemString = "";
bool bAddCard;

for (int j=0; j<13 ; j++)


{
for (i=0 ; i<4 ; i++)
{
buffer = pReader.ReadProcessMemory((IntPtr)((int)aArray[i] + (16 * j)),1,out readBytes);
CardNum = (buffer[0] / 4) + 1;
CardKind = (buffer[0] % 4) + 1;
bAddCard = true;

switch (CardNum)
{
case 11:
ItemString = "J";
break;
case 12:
ItemString = "Q";
break;
case 13:
ItemString = "K";
break;
case 64:
bAddCard = false;
break;
default:
ItemString = CardNum.ToString();
break;
}

if (bAddCard)
listArray[i].Items.Add(ItemString ,CardKind -1);
}
}
pReader.CloseHandle();

In the next section I will give an example of writing to a process memory using in the Hearts game.
Section 3: WriteProcessMemory bonus

As I've said in the beginning, I could not write an article with no new feature presented so I've enhanced the functionality of the class library so now it can also write into another process memory.
This is done using the API WriteProcessMemory. This function excepts a byte array, an address and a process and writes the byte array to the address of the process. Simple as that. Its normal
header looks like this:

BOOL WriteProcessMemory(
HANDLE hProcess, // handle to process
LPVOID lpBaseAddress, // base of memory area
LPCVOID lpBuffer, // data buffer
SIZE_T nSize, // count of bytes to write
SIZE_T * lpNumberOfBytesWritten // count of bytes written
);

So its C# equivalent is:

[DllImport("kernel32.dll")]
public static extern Int32 WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[In, Out] byte[] buffer,
UInt32 size,
out IntPtr lpNumberOfBytesWritten);

For this function to work, you need to first open the process with the access permissions PROCESS_VM_WRITE and PROCESS_VM_OPERATION.

Brought to you here is an example of using this function, the example opens the Hearts process again, only this time the goal is to write me a good game. Here is the code:

// Search the Hearts Process


Process[] pArray = Process.GetProcessesByName("mshearts");
if (pArray.Length == 0)
return;

// Create memory reader


ProcessMemoryReaderLib.ProcessMemoryReader pReader = new ProcessMemoryReaderLib.ProcessMemoryReader();

// Take the first process found


pReader.ReadProcess = pArray[0];

pReader.OpenProcess();

int i;
int readBytes;
byte[] buffer;

IntPtr StaticAddress = (IntPtr)0x0100d514;


buffer = pReader.ReadProcessMemory(StaticAddress,4,out readBytes);
IntPtr PointerArrayAddress = (IntPtr)(
buffer[0] +
256*buffer[1] +
256*256*buffer[2] +
256*256*256*buffer[3] + 0x130);

IntPtr[] aArray = new IntPtr[4];


buffer = pReader.ReadProcessMemory((IntPtr)PointerArrayAddress,16,out readBytes);
for (i=0 ; i<4 ; i++)
aArray[i] = (IntPtr)(
buffer[4*i] +
256*buffer[4*i + 1] +
256*256*buffer[4*i + 2] +
256*256*256*buffer[4*i + 3] + 0x1c);

int writtenBytes;
buffer = new byte[1];

for (i=0 ; i<4 ; i++)


{
for (int j=0; j<13 ; j++)
{
buffer[0] = (byte)(j*4 + i);
pReader.WriteProcessMemory((IntPtr)((int)aArray[i] + (16 * j)),buffer,out writtenBytes);
}
}
pReader.CloseHandle();

btnReadMemory_Click(sender,null);

Note: the game might not be as much fun now..

That's it.
Code Caves and Code Injection
By Tsongkie / CES 2003
www.gamehacking.com

I. Introduction

Code caves are series of 00 and/or 90 hex bytes located in the process memory of our games. We
can use these code caves as a place wherein we can write our own code/routine/function.

II Needed Tools

1. SoftIce/Tsearch (I prefer SoftIce) www.gamehacking.com


2. Your favorite Memory Searcher (I use ArtMoney) www.gamehacking.com
3. Tsongkie’s Code Cave Tool ? www.tsongkie.com
4 Game (I used Gangsters 2 v1.0.5)
5. Few Brain cells ?

III Hacking the Game

I have searched the game as normal and found the value 010BAFDC for money. I also noticed that
the money is being updated when the time returns to 00 (e.g. 10:00, 11:00). Also, 010BAFDC is a
COUNTER Address, changing it wont have any effect with the real value.

For SoftIce Users be sure that the you enabled the following in SoftIce:

Dump Window: wd [return]


Register Window: wr [return]
Hex Codes: code on [return]

What we need is to put a breakpoint at 010BAFDC… so…

Press ctrl+d
Type bpmd 010BAFDC w
X
And wait for SoftIce to Pop when time reaches 00…

When SoftIce pops up, I get the following code:

0177:005650E6 85C0 TEST EAX,EAX


0177:005650E8 75CA JNZ 005650F4
0177:005650EA 8A8658040000 MOV AL,[ESI+00000458]
0177:005650F0 84C0 TEST AL,AL
0177:005650F2 7570 JNZ 00565164
0177:005650F4 57 PUSH EDI
0177:005650F5 8B7C240C MOV EDI,[ESP+0C] ? Notice here
0177:005650F9 85FF TEST EDI,EDI ? SoftIce Pops Here
0177:005650FB 7D0B JGE 00565108

type d [ESP+0C]
BINGO! [ESP+0C] is equal to 010BAFDC, our money address ?. If we simply NOP this, the money
wouldn’t change…It wouldn’t either increase nor decrease… the answer to this problem is code
injection…

What we need is change MOV EDI,[ESP+0C] to:


MOV EDI,00FFFFFF which gives us $99,999,999…

IV Code injection

First, Get TCCT (Tsongkie’s Code Cave Tool… Yeah ? ) and search Gangsters2 Window for code
caves. Look at the results and select one… I chose 00400319. In SoftIce type:

D 400319 [return]

Scroll down some more just to be safe…Look at 00400342…Again type

U 00400342

It is a series of code caves… Write down the address in a piece of paper.

For our own injected function

Now we need to assemble 00400342, so type:

A 00400342 [return]

0028:400342 MOV EDI,00FFFFFF [RETURN]


0028:400347 TEST EDI,EDI
0028:400349 RET

Again type: U 400342 [return]

It should look like this:

0028:00400342 BFFFFFFF00 MOV EDI,00FFFFFF


0028:00400347 85FF TEST EDI,EDI
0028:00400349 C3 RET

What we have just written is our own function ?.

1) The instruction at 0028:00400342 is the code that we need to have $9,999,999.

2) The instruction at 0028:00400342 is the same code at 0177:005650F9. We rewrote this because
we are going to overwrite the instruction at 0177:005650F9 when we call our own function.

3) All functions/procedures end with a RET (instruction at 0028:00400349)

The only thing we need to do is call our function…

Calling Our Function/Procedure

Lets look at the game’s code again:


0177:005650F2 7570 JNZ 00565164
0177:005650F4 57 PUSH EDI
0177:005650F5 8B7C240C MOV EDI,[ESP+0C] ? Notice here
0177:005650F9 85FF TEST EDI,EDI
0177:005650FB 7D0B JGE 00565108

What we need is to overwrite the code at 0177:005650F5 and 0177:005650F9 with a CALL
Instruction. Lets assemble and overwrite the said codes.

Now type:

A 005650F5 [return]

0177:005650F5 CALL 00400342


0177:005650FA NOP ? NOP this because the next instruction starts at: 005650FB
0177:005650FB [RETURN] ? Next Instruction starts here

Type again:

U 005650F5 [RETURN]

It should look like this:

0177:005650F2 7570 JNZ 00565164


0177:005650F4 57 PUSH EDI
0177:005650F5 E848B2E9FF CALL 00400342
0177:005650FA 90 NOP
0177:005650FB 7D0B JGE 00565108
There, we are done. ? Clear all our breakpoints and check if it works. It should.

V. Our Trainer

You just need to write…

Address New Bytes

00400342 BF FF FF FF 00 85 FF C3
005650F5 E8 48 B2 E9 FF 90

VI. FINAL WORDS

For questions/suggestions/comments, e-mail me at root@tsongkie.com. For further help, go to


www.gamehacking.com forums.
--=== Debugging GJPacmanV3X ===--

Author : Snaky[GHU]

Tools that u'll need : SoftIce, pen & paper

Remarks : You'll need a drink too if you're in Africa or Egypt

--===Let's begin===--

1. Start GJPacmanV3X.exe included in this .zip file.


Your options in the game are : StartNewGame/EnterPassword/
Quit

2. Play the first level until you find the password for level2.
That will be : RASP482

3. Leave the current game (Press F2). In the game options choose Password.
Enter RASP482 and in SoftIce type "bpx Getdlgitemtexta" without
(") mark. This tells SiftIce to break when the game reads the
password. Exit SoftIce and press the OK button.

4. SoftIce should break. F12 to return to the calling routine in


our target. Follow the code with F10. You should see a call to
USER32.EndDialog, then you will find yourself in kernel32's code...

5. To return at our target's code, hit F12 several times.


When you're done, we're ready to trace! (You're done when you
are in PACMAN's code. Look below the code-window in SoftIce,
it should say something like this : GJPACKMANV3X - if u hadn't
changed the exe's name)

6. If you type "d edi" you should see the code you entered (RASP482)
Now trace with F10 until you reach this piece of code:

40314D: cmp [43eb74],ebx ->ebx holds our level (second level is ebx=7
jz 40316f third is ebx=8 etc)
mov eax,[4eeaa4] ->mov the level map in eax
mov eax,[ebx*4+eax] ->localize the password's level on the map
test eax,eax ->if no level for where ebx is pointing
jz 40316f ->jump to search a new level for entered pass.
push edi ->else (a level matched with our pass.)
push eax ->then check to see if it's the real
call ->pass. for that level inside this call
add esp,8 ->this is for stack, unimportant
test eax,eax ->if eax=0 then all is ok
jz 40317a ->and we jump to the beginning of that level
40316F inc ebx ->inc the level pointer
cmp [43ea78],ebx ->had it exceeded the value in 43ea78 (48) ?
jg 40314d ->if not, then search the next level

7. Trace until you are (in SoftIce) on the "push edi" instruction.
Type "d eax" and you'll find the codes for all levels! Don't forget to
type "d eax+10" or "d eax+N" (0<N<300) to scroll the codes in SoftIce's display!

8. I give you some cool pass. : PARADISE - for SUPER BONUS LEVEL-u'll love it
COOLGUY - for the last level
9. BTW: TO PLAY THE CHRISTMAS-LEVELS DO THE FOLLOWING :
i) when you are in pacman's code put a "bpx 402bbe"
ii) go to the password dialog and enter a random incorrect pass.
iii) when SoftIce breaks, type "r fl z" and hit [ENTER]
iv) when you'll see "GAME OVER" screen, hit [SPACE]
v) then hit [SPACE] again to play CHRISTMAS LEVELS (you'll love this ones to

--===Regards and Salutations go to===--

Sorin (he made me what I am)


Biciuila (ne intalnim la 10, da?)
J.J. the Reaper (NO COMMENT FOR LAST NIGHT)
Grannie & Mr. Fantastic (sunteti de treaba !)
T-RaiNeR (esti un super gfx-er/web designer !)

In one phrase,
"Long live GHU"

Snaky[GHU]

"We hack ONLY what we like".

GHU ( http://www.ghu.as.ro/ ).

eof
Multi-Tools tutorial with ... HomeWorld, HomeWorld Raider Retreat, HomeWorld Cataclysm

Tool used to find the memory addresses: GameHack 2.0 and Winhack 2.0.
Tools used to set the BreakPoints: SoftIce & TSearch.
Tool used to take a look at the code: W32Dasm & TSearch; screenshots taken from W32Dasm.
All of them available here at http://www.gamehacking.com/ .

Since there are many game versions and cracked exes in this tutorial I will use as example the
HomeWorld and the HomeWorld Cataclysm demos available in FILEPLANET as reference.

RU in HomeWorld & HomeWorld Raider Retreat

SEARCH: 4 BYTES EXACT VALUE


RU & SU in HomeWorld Cataclysm

SEARCH: 4 BYTES EXACT VALUE


RU CURRENT SU MAXIMUM SU
HW 8A2290 --- ---
HW C 9152E4 9152F0 9152EC

UNLIMITED RU (RESOURCES UNITS) - 2 WAYS


:005817B9 2BC2 sub eax, edx
:005817BB 8B1588228A00 mov edx, dword ptr [008A2288]
HW
:005817C1 894204 mov dword ptr [edx+04], eax
:005817C4 A188228A00 mov eax, dword ptr [008A2288]
:0044EC69 2B0DE8C47D00 sub ecx, dword ptr [007DC4E8]
:0044EC6F 8B15DC529100 mov edx, dword ptr [009152DC]
HWC :0044EC75 894A04 mov dword ptr [edx+04], ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:..|:0044EC5F(C)
:0044EC78 A1DC529100 mov eax, dword ptr [009152DC]
After getting the "RU memory address" set the BPM in SOFTICE: bpmd "RU memory address" w,
and then build something.
By NOPping the SUB you build and it costs 0 RU´s.
CHANGE
SOFTICE FROM TO
IN
HW 5817C4 5817B9 2BC2 9090
HW C 44EC78 44EC69 2B0DE8C47D00 909090909090
After getting the "RU memory address" set the BPM in TSEARCH AUTOHACK: "RU memory
address" BPM SIZE 4 WRITE, and then build a ship.
By NOPing the MOV you get in TSearch when you build it will 0/1 RU.
CHANGE
TSEARCH FROM TO
IN
HW 5817C1 5817C1 894204 909090
HW C 44EC75 44EC75 894A04 909090

UNLIMITED SU (SUPPORT UNITS) => UNLIMITED SHIPS in HomeWorld Cataclysm


:00453956 015110 add dword ptr [ecx+10], edx
:00453959 F680CC01000008 test byte ptr [eax+000001CC], 08

:004539A8 295110 sub dword ptr [ecx+10], edx


:004539AB F780CC01000000000010 test dword ptr [ebx+000001CC], 10000000
Or increase the Maximum SU to 10000 or stop the Current SU from changing:
After getting the "CURRENT SU memory address" TSEARCH AUTOHACK "CURRENT SU
memory address" BPM SIZE 4 WRITE, and then build and retire a ship so the SU neither increase
till the limit or decrease to a negative value.
By NOPing the ADD and the SUB you get in TSearch you can build/retire/loose ships and the
current su units doesn't change.
CHANGE
SOFTICE TSEARCH FROM TO
IN
453959 453956 453956 015110 909090
HW C
4539AB 4539A8 4539A8 295110 909090
The trick is to NOP the Add and the Sub.

INSTANT SHIP BUILDING

:00581839 8B400C mov eax, dword ptr [eax+0C]


:0058183C 48 dec eax
:0058183D 8B15F4227E00 mov edx, dword ptr [007E22F4]
HW
:00581843 89420C mov dword ptr [edx+0C], eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:..|:0058178F(C)..|
:00581846 A1F4227E00 mov eax, dword ptr [007E22F
:0044ED18 83EA01 sub edx, 00000001
:0044ED1B A1DCC47D00 mov eax, dword ptr [007DC4DC]
:0044ED20 89500C mov dword ptr [eax+0C], edx
HWC
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:..|:0044EC3B(C),
:0044ED0D(U)..|
:0044ED23 8B0DDCC47D00 mov ecx, dword ptr [007DC4DC]
The memory address of the ship building bar is DMA (it´s different for each item in each mission in
each time you play the game); the type of search is a 2 bytes search; as the item is builded the value
of the ship building bar decreases; the value of the ship building bar is decreasing to 0.
After getting the "SHIP BUILDING BAR memory address" set the BPM in:
* SOFTICE: bpmd "SHIP FUEL BAR memory address" w.
* TSEARCH AUTOHACK: "SHIP BUILDING BAR memory address" BPM SIZE 4 WRITE
By NOPping the at 581843 and/or the DEC at 58133C
In HW/HWRR the trick is replace the MOV X, DWORD PTR [X+0C] at 581839 with a XOR X, X
being in this case EAX and NOPing the DEC EAX, so the amount built at one time unit is all that is
left to build.
In HW/HWRR the trick is replace the SUB X, 00000001 at 44ED18 with a XOR X, X being in this
case EDX, so the amount built at one time unit is all that is left to build. Replacing SUB X,
00000001 with SUB X, 000000FF would make that instead of building 1 each time unit with would
build 255 each time unit.
SOFTICE TSEARCH CHANGE IN FROM TO
581839 &
HW 581846 581843 89420C 48 33C090 90
58183c
HW C 44ED23 44ED20 44ED18 83EA01 33D290

UNLIMITED SHIPS in HW and HWRR

:00582BE4 741B je 00582C01


:00582BE6 B801000000 mov eax, 00000001
:00582BEB 8945F8 mov dword ptr [ebp-08], eax
:00582BEE 8B443E1C mov eax, dword ptr [esi+edi+1C]
:00582BF2 85C0 test eax, eax
:00582BF4 7E65 jle 00582C5B
:00582BF6 FF443E18 inc [esi+edi+18]
:00582BFA 40 inc eax
:00582BFB 89443E1C mov dword ptr [esi+edi+1C], eax
:00582BFF EB15 jmp 00582C16
* Referenced by a (U)nconditional or (C)onditional Jump at Address:..|:00582BE4(C)
:00582C01 8B45F4 mov eax, dword ptr [ebp-0C]
:00582C04 8B15C4117E00 mov edx, dword ptr [007E11C4]
:00582C0A 66A310237E00 mov word ptr [007E2310], ax
:00582C10 891514237E00 mov dword ptr [007E2314], edx
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:..|:00582BFF(U),
:00582C63(U)..|
:00582C16 A100F08700 mov eax, dword ptr [0087F000]
:00582C1B 83C4F8 add esp, FFFFFFF8
:00582C1E 8B44180C mov eax, dword ptr [eax+ebx+0C]
:00582C22 8B8094010000 mov eax, dword ptr [eax+00000194]
:00582C28 890424 mov dword ptr [esp], eax
:00582C2B E8D00F0C00 call 00643C00
:00582C30 A100F08700 mov eax, dword ptr [0087F000]
:00582C35 8B55F8 mov edx, dword ptr [ebp-08]
:00582C38 8B44180C mov eax, dword ptr [eax+ebx+0C]
:00582C3C 83C408 add esp, 00000008
:00582C3F 8B8094010000 mov eax, dword ptr [eax+00000194]
:00582C45 A3F4C67B00 mov dword ptr [007BC6F4], eax
:00582C4A 8BC2 mov eax, edx
:00582C4C 8B1C24 mov ebx, dword ptr [esp]
:00582C4F 8B742404 mov esi, dword ptr [esp+04]
:00582C53 8B7C2408 mov edi, dword ptr [esp+08]
:00582C57 8BE5 mov esp, ebp..:00582C59 5D pop ebp
:00582C5A C3 ret
.* Referenced by a (U)nconditional or (C)onditional Jump at Address:..|:00582BF4(C)..|
:00582C5B A100F08700 mov eax, dword ptr [0087F000]
:00582C60 FF0418 inc dword ptr [eax+ebx]
:00582C63 EBB1 jmp 00582C16
Search for the "number of Scouts in queue", with a 4 Bytes Exact Value Search, the memory address
is 7BBF30 and it ain't DMA.
You can bypass the limit of ships to build if you have the memory address by changing the number
of ships to build even if you can only build 80 you can change to 100 and build all the 100.
* SOFTICE: bpmd "number of Scouts in queue memory address" w
* TSEARCH AUTOHACK: "number of Scouts in queue memory address" BPM SIZE 4 WRITE
Above the memory addresses SoftIce and Tsearch suggest is the reference to a JUMP at 582BF4, go
there, messing with the JLE isn't the right approach (NOPing it or changing from JLE to JA) but
NOPing the JE above 582BF4 at 582BE4 is.
SOFTICE TSEARCH CHANGE IN FROM TO

HW 582C63 582C60 582BE4 741B 9090

INSTANT RESEARCHING

:006237C5 D95F18 fstp dword ptr [edi+18]


HW :006237C8 9E sahf
:006237C9 7705 ja 006237D0
:004E9F35 D95B14 fstp dword ptr [ebx+14]
:004E9F38 D94314 fld dword ptr [ebx+14]
HWC :004E9F3B D81D30C46300 fcomp dword ptr [0063C430]
:004E9F41 DFE0 fstsw ax..:004E9F43 F6C401 test ah, 01
:004E9F46 0F848C020000 je 004EA1D8
The memory address of the research bar is DMA (it's different for each item in each mission in
each time you play the game); the type of search is a 2 bytes search; as the item is researched the
value of the research bar decreases.
After getting the "RESEARCH BAR memory address" set the BPM in:
* SOFTICE: bpmw "RESEARCH BAR memory address" w
* TSEARCH AUTOHACK: "RESEARCH BAR memory address" BPM SIZE 2 WRITE
In HW NOPing the FSTP or the SAHF doesn't make the research become instant; just change from
JA (JUMP ABOVE) ">" to JBE (JUMP BELOW OR EQUAL) "< =".
In HWC the trick is to change from JE (JUMP EQUAL) to JNE (JUMP NOT EQUAL).
SOFTICE TSEARCH CHANGE IN FROM TO
HW 6237C8 6237C5 6237C9 7705 7605
HW C 4E9F38 4E9F35 4E9F46 0F848C020000 0F858C020000

UNLIMITED FUEL in HW

:0054BE09 D998C8020000 fstp dword ptr [eax+000002C8]


:0054BE0F EB39 jmp 0054BE4A
* Referenced by a (U)nconditional or (C)onditional Jump at Address:..|:0054BDD4(C)..|
:0054BE11 83EC0C sub esp, 0000000C
:0054BE14 8BCC mov ecx, esp
:0054BE16 8B55BC mov edx, dword ptr [ebp-44]
:0054BE19 8911 mov dword ptr [ecx], edx
:0054BE1B 8B45C0 mov eax, dword ptr [ebp-40]
:0054BE1E 894104 mov dword ptr [ecx+04], eax
:0054BE21 8B55C4 mov edx, dword ptr [ebp-3C]
:0054BE24 895108 mov dword ptr [ecx+08], edx
:0054BE27 E824C8FFFF call 00548650
:0054BE2C 83C40C add esp, 0000000C
:0054BE2F 8B4594 mov eax, dword ptr [ebp-6C]
:0054BE32 D88808020000 fmul dword ptr [eax+00000208]
:0054BE38 8B4D08 mov ecx, dword ptr [ebp+08]
:0054BE3B D8A9C8020000 fsubr dword ptr [ecx+000002C8]
:0054BE41 8B5508 mov edx, dword ptr [ebp+08]
0054BE44 D99AC8020000 fstp dword ptr [edx+000002C8]
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:..|:0054BDC2(C),
:0054BE0F(U)..|
:0054BE4A 8B4508 mov eax, dword ptr [ebp+08]
The memory address of the ship fuel bar (blue bar) is DMA (it's different for each item in each
mission in each time you play the game); the type of search is a 4 bytes search; as the fuel decreases
the value of the ship fuel bar decreases.

After getting the "SHIP FUEL BAR memory address" set the BPM in:
* SOFTICE: bpmd "SHIP FUEL BAR memory address" w
* TSEARCH AUTOHACK: "SHIP FUEL BAR memory address" BPM SIZE 4 WRITE
Fly to decrease the fuel and dock to refill the fuel; in TSearch you get 3 FSTP and 1 FST, if you
NOP them the results aren't the expected.
The solution to this problem is from MegaBajt/Origin's Homeworld 1.03 +5 trainer.
Replace the code between [ ] with a dword memory address elsewhere so the fuel variation that
was been calculated in the code replaced doesn't affect the current amount of fuel.
In the MegaBajt/Origin's Homeworld 1.03 +5 trainer the change was from FSTP DWORD PTR
[EAX +000002C8] & FSTP DWORD PTR [EDX+000002C8] to FSTP DWORD PTR
[00958F00].
We change the code to D91D 00 8F 95 00 - with the memory address reversed (00 95 8F 00 =>00
8F 95 00).

SOFTICE TSEARCH CHANGE IN FROM TO


54BE0F 54BE09 54BE09 D998C8020000 D91DF06F9500
HW
54BE4A 54BE44 54BE44 D998C8020000 D91DF06F9500

All versions data below.

Versions of HOMEWORLD detailed


#A DEMO as available in FILEPLANET
#B 1.00 CD UNCRACK
1.00 CD CRACKED
#C Homeworld v1.0 - cracked exe. backup CD. no CD in MEGAGAMES
Homeworld v1.0 [US] No-CD 05-10-1999 Lord Kihra in GAMECOPYWORLD
#D 1.01 RIPPED
#E 1.03 CD UNCRACK
1.03 CD CRACKED
#F
Homeworld v1.03 [US] Update 08-10-1999 Itchy in GAMECOPYWORLD
#G 1.04 CD UNCRACK
1.04 CD CRACKED UK
#H Homeworld v1.04 UK - cracked exe. no CD in MEGAGAMES
Homeworld v1.04 [UK] No-CD #1 13-12-1999 Fuzzy in GAMECOPYWORLD
#I 1.05 CD UNCRACK

Versions of HOMEWORLD RAIDER RETREAT detailed


##A HWU LIGHT as available in HOMEWORLD UNIVERSE
##B HWU FULL as available in HOMEWORLD UNIVERSE
##C CD

Versions of HOMEWORLD CATACLYSM detailed


###A DEMO 1.00 as available in FILEPLANET
###B CD 1.00 UNCRAKED
CD 1.00 CRACKED ENGLISH
###C Homeworld: Cataclysm v1.0 ENG - no CD in MEGAGAMES.
Cataclysm v1.0 [ENGLISH] No-CD/Fixed EXE 11-09-2000 ? in GAMECOPYWORLD.
###D CD 1.00 ISO CRACKED ENGLISH
###E CD 1.01 UNCRACKED US & UK PATCHES
CD 1.01 CRACKED US
###F Homeworld: Cataclysm v1.0.0.1 US [FDX] - backup CD in MEGAGAMES
Cataclysm v1.0.0.1 [US] Fixed EXE 19-02-2001 FDX in GAMECOPYWORLD

RU CURRENT SU MAXIMUM SU
#A 8A2290 --- ---
#B #C 8A4B10 --- ---
#D 85D8B8 --- ---
#E #F 8A4B10 --- ---
#G #H 8BC630 --- ---
#I 8BB650 --- ---
##A ##B ##C 8BB5F0 --- ---
###A 9152E4 9152F0 9152EC
###B ###C ###D A0C884 A0C890 A0C88C
###E ###F B67504 B67510 B6750C

UNLIMITED RU (RESOURCES UNITS) - 2 OPTIONS


CHANGE
SOFTICE FROM TO
IN
#A 5817C4 5817B9 2BC2 9090
#B #C 582FB4 582FA9 2BC2 9090
#D 55B9BF 55B9B4 2BC2 9090
#E #F 582F94 582F89 2BC2 9090
#G #H 5883B9 5883AE 2BC2 9090
#I 5883F9 5883EE 2BC2 9090
##A ##B
587239 58722E 2BC2 9090
##C
###A 44EC78 44EC69 2B0DE8C47D00 909090909090
###B ###C 4503A8 450399 2B0D883A8D00 909090909090
###D
###E ###F 454BB4 454BA5 2B0DD8DBA200 909090909090
CHANGE
TSEARCH FROM TO
IN
#A 5817C1 5817C1 894204 909090
#B #C 582FB1 582FB1 894204 909090
#D 55B9BC 55B9BC 894204 909090
#E #F 582F91 582F91 894204 909090
#G #H 5883B6 5883B6 894204 909090
#I 5883F6 5883F6 894204 909090
##A ##B
587236 587236 894204 909090
##C
###A 44EC75 44EC75 894A04 909090
###B ###C
4503A5 4503A5 894A04 909090
###D
###E ###F 454BB1 454BB1 894A04 909090

INSTANT SHIP BUILDING


CHANGE
SOFTICE TSEARCH FROM TO
IN
#A 581846 581843 581839 8B400C48 33C09090
#B #C 583036 583033 583029 8B400C48 33C09090
#D 55BA60 55BA5D 55BA53 8B400C48 33C09090
#E #F 583016 583013 583009 8B400C48 33C09090
#G #H 588444 588441 588437 8B400C48 33C09090
#I 588484 588481 588477 8B400C48 33C09090
##A ##B ##C 5872C4 5872C1 5872B7 8B400C48 33C09090
###A 44ED23 44ED20 44ED18 83EA01 33D290
###B ###C
450453 450450 450448 83EA01 33D290
###D
###E ###F 454C5F 454C5C 454C54 83EA01 33D290

UNLIMITED SHIPS
SOFTICE TSEARCH CHANGE FROM TO
IN
#A 582C63 582C60 582BE4 741B 9090
#B #C 584453 584450 5843D4 741B 9090
#D 55CDFD 55CDFA 55CD94 741B 9090
#E #F 584433 584430 5843B4 741B 9090
#G #H 5892D5 5899D2 5898F5 0F8479000000 909090909090
#I 589A15 589A12 589934 0F8479000000 909090909090
##A ##B
588855 588852 588774 0F8479000000 909090909090
##C
UNLIMITED SU (SUPPORT UNITS) => UNLIMITED SHIPS
CHANGE
SOFTICE TSEARCH FROM TO
IN
453959 453956 453956 015110 909090
###A
4539AB 4539A8 4539A8 295110 909090
###B ###C 455049 455046 455046 015110 909090
###D 45509B 455098 455098 295110 909090
459AB9 459AB6 459AB6 015110 909090
###E ###F
459B0B 459B08 459B08 295110 909090

INSTANT RESEARCHING
CHANGE
SOFTICE TSEARCH FROM TO
IN
#A 6237C8 6237C5 6237C9 7705 7605
#B #C 625278 625275 625279 7705 7605
#D 5F5CE8 5F5CE5 5F5CE9 7705 7605
#E #F 625258 625255 625259 7705 7605
#G #H 62C2E8 62C2E5 62C6E9 7705 7605
#I 62C308 62C305 62C309 7705 7605
##A ##B
62AEE8 62AEE5 62AEE9 7705 7605
##C
###A 4E9F38 4E9F35 4E9F46 0F848C020000 0F858C020000
###B ###C
4EDE68 4EDE65 4EDE76 0F848C020000 0F858C020000
###D
###E ###F 4F2AC5 4F2AC5 4F2AD6 0F848C020000 0F858C020000
UNLIMITED FUEL (HW & HWRR only)
SOFTICE TSEARCH CHANGE IN FROM TO
54BE0F 54BE09 54BE09 D998C8020000 D91DF06F9500
#A and/or and/or
54BE4A 54BE44 54BE44 D99AC8020000 D91DF06F9500
54D5BF 54D5B9 54D5B9 D998C8020000 D91D008F9500
#B #C and/or and/or
54D5FA 54D5F4 54D5F4 D99AC8020000 D91D008F9500
52967A 529674 529674 D99ABC020000 D91D008F9500
#D and/or and/or
5296B5 5296AF 5296AF D999BC020000 D91D008F9500
54D59F 54D599 54D599 D998C8020000 D91D008F9500
#E #F and/or and/or
54D5DA 54D5D4 54D5D4 D99AC8020000 D91D008F9500
5515FF 5515F9 5515F9 D998C8020000 D91D008F9500
#G #H and/or and/or
55163A 551634 551634 D99AC8020000 D91D008F9500
5515FF 5515F9 5515F9 D998C8020000 D91D008F9500
#I and/or and/or
55163A 551634 551634 D99AC8020000 D91D008F9500
55043F 550439 550439 D998C8020000 D91D008F9500
##A ##B
and/or and/or
##C 550474 D99AC8020000 D91D008F9500
55047A 550474

Victor D. "Wolverine"

From Porto, Portugal, Europe

victordwolverine@yahoo.com

victordwolverine@gamehacking.com

www.geocities.com/victordwolverine

members.fortunecity.com/victordwolverine

Copyright © 1996 - 2002 The World Of Game Hacking. All Rights Reserved.
Regulations, Trademarks and Privacy Statement are property of The World of Game Hacking.
Copyright © 1997 - 2002 The C.E.S Game Hacking Team (Cogito Ergo Sum).
Users of this site agree to be bound by the terms of the International Internet Web Site Rules and
Regulations.
.________. .________.
\ | ___///__ ._________ .__///____ | \_
::::::| ____|___ ____|__ |_| /_| / .____|_____ |:::::::
:: | | __/___| | ____/| ____/ | | ::
:: | |____ \_ | | _|_|______._|___|____. | ::
:: | | | | | | | __///___| ::
:: | | | | | | | | ::
:: |_. | |_____|\_____///________|__________| | ::
:: \___///________| |[sheep] |_ | ::::::::::::
:: \__________| |_______| :: :: ::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::
Gamehacking Tutorial Collection.. :: ::
::::::::::::

(best viewed in 1024x768)

TIME/DATE: 11:23pm, 09, October 2003


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SUBJECT: INSTANT BUILD FOR PLAYER ONLY - Advanced Options Gamehacking.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Once again I feel its time to unleash another tutorial onto the world of
gamehacking freaks, this one is a little shorter than most.. Hope you all
get something from it though.

RANTS!
------
I notice a lot of fucking idiots around the trainer community that seem
to think bashing out the same shit day after day is helping the community
in some way, people sitting on forums talking about how to make a trainer
engine for the last 2 years need to get a fucking life..

The REAL!! trainer scene which is part of the WAREZ RLS scene with groups such
as MYTH, CLASS, DIVINE, DEVIANCE, FAIRLIGHT etc.. seems to have gone to shit
these days, its infested with lame ass groups rlsing substandard trainers to
gain rls numbers. Lets hope these lame fucks read my tutorials and educate them
selves so that the standard of trainers can at least raise a little.

I feel better now :)

ON WITH THE SHOW!


-----------------
With the increase of RTS games on the PC market lots of trainers are being
created for them but unfortunately not many are created correctly. The
main problem with these BAD trainers are that when the trainer maker
manipulates the code in an RTS 99% of the time the same code is used for
the computer player as well, ergo.. we get an invalid option because the
computer will use that option to a greater advantage than u ever could,
especially if its instant build.. u can generally tell if u are using
a BAD trainer because u will most likely get ur ass kicked when
enabling the options.

TOOLS NEEDED: Softice, Search Engine (Tsearch or Artmoney).


WORK SUBJECT: HOMEWORLD 2

locations...

SOFTICE.........................LOOK FOR IT!!! ITS ON THE WEB!!


SEARCH ENGINE...................LOOK FOR IT!!! ITS ON THE WEB!!
HOMEWORLD 2.....................BUY IT! :)

SOFTICE SETUP
*************

When you press CTRL-D to pop softice you should see the following windows..

REGISTER WINDOW - this window is always at the very top of the softice window
(WR [return]) and displays the contents of all the registers..

DUMP WINDOW - generally situated close to the top of the softice window
(WD [return]) contains a split screen display.. one side is ascii the
other is hex.
CODE WINDOW - this is the main window.. sits just under the DUMP WINDOW
(WC [return]) contains the code of whatever process maybe running when
u pop softice.. the code is represented in ASSEMBLY LANGUAGE
instructions..

The comments in the brackets are what you need to type to turn the different windows on..
you also need to type CODE ON.. this will bring up the OPCODES which are a set of numbers
displayed to the left of each ASM instruction and to the right of every memory location
in the CODE WINDOW..

LESSON START
************
Ok, as stated above the game we will be working on is HOMEWORLD 2 without any updates
installed. Im choosing this game because Ive just created a HOMEWORLD 2 trainer and the
options are fresh in my mind. I suppose even if u dont have the game u can still learn
from the actual theory.

THEORY
******

One thing that we all can assume for ourselves is that the computer doesnt need a
graphical representation of the game unlike humans who need the graphical
stimulus to work and even play the game (moronic humans:)) ) anyway all that babble
actually means that the computer will never use ANY routines that are associated
with the DISPLAY. I can tell the little cogs in ur head are turning now eh? hmm
perhaps not :) well, our task is to find somewhere within the game that our 2
pointers collide, this is called a STAPLE INTERSECTION it means 2 beneficial pointers
or code sections are in the same area. You will find many of these STAPLE INTERSECTIONS
within the game but tracking them down can sometimes be tricky. Im now going to
give u an example of a STAPLE INTERSECTION just to make sure u understand what I
mean.

STAPLE INETERSECTION EXAMPLE


============================

This is totally made up code but shows u the point Im trying to make...

Game Screen
|
.===============.
||
| (-0-) | <-- space ships.. hehe
| (-0-) |
||
||
| Progress 46%| <-- Players Build Progress, 100% = Unit is built.
'===============' ( I know that most of the time build progress
is shown in a BAR but to make it so people
understand more clearly Ive used numbers
to represent the build progress.)

Ok, so at this present time the screen is being updated with the value
46, this will be somewhere in the data section and very easy to find
with a search engine such as tsearch.

The progress value in memory is at some stage converted from data into a graphical
representation of what we see on the screen. This is where we will find our
STAPLE INTERSECTION.

STAPLE INTERSECTION CODE


========================

(this code is not real)

Graphical Conversion Routine.

mov edx, [ecx+456*4+456] <-- Move Build Progress value into edx (46)
lea eax, [ebp-130h]
push eax
push dword ptr [ebp+8]
lea eax, [ebp-234h]
push offset bb55
push edx
call 456333 <-- Convert 46 (value) into 46% ON SCREEN.
add esp, 10h

The above routine is a perfect example of a STAPLE INTERSECTION, we have


2 pointers or code sections that are INTERSECTING with each other.. first
we have the REAL!! value in memory (46) and then we have the routine that
is converting it into a graphical representation..CALL 456333. The reason
we need both crossing at 1 point is because we need something from both
elements..

ELEMENT 1 - mov edx, [ecx+456*4+456] <--- this gives us access to


our real value.(46)

ELEMENT 2 - call 456333 <--- This gives us a place that the computer
never uses because its a SCREEN ROUTINE!

ELEMENT 1 + ELEMENT 2 = STAPLE INTERSECTION which in turn means we now


have a place to inject code, update our value and we are assured that
the computer will never get the benefit.

Im going to go 1 step further just in case u guys still dont get it.. below
is what will probably happen when a UNIT is built within an RTS.
COMPUTER PLAYER BUILD ROUTINE
=============================

1 Check Money Amount (make sure the computer has enough to build the unit)

2 Start Building

3 Update Build Progress

4 Check Build Status (is it at 100%?)

Ok, there are more than likely a lot more steps but this shows u the basics..
now we look at the HUMAN PLAYER.

HUMAN PLAYER BUILD ROUTINE


==========================

1 Check Money Amount (same as above)

2 Start Building

3 Update Build Progress

4 Update Screen Progress <-- STAPLE INTERSECTION!

5 Check Build Status (same as above)

6 Check if Player Quit Unit Production <-- STAPLE INTERSECTION!

As u can see there are more steps included in the human players routine because
humans need to SEE the game (4) and humans also change their mind (6) both are
valid STAPLE INTERSECTIONS but the screen update is the cleanest and best way
of the two.

So now I hope u all at least know the REASONS why we are using STAPLE INTERSECTIONS
and how they are very beneficial when it comes to cutting the computer out of any
cheat benefits.
PRACTICAL
*********

This is the part of the show where I take HOMEWORLD 2 (our chosen target) and enlighten
u all on how to actually obtain the instant build option using a STAPLE INTERESECTION.

1.Finding the build progress data location


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

(As this is supposed to be an advanced tutorial this will be a brief description.)

i) START BUILDING A UNIT (space craft etc.)


ii) SWITCH TO TSEARCH (or whatever search engine u are using) and do an unknown search.
iii) FINAL SEARCH (This game uses a DWORD to store the progress of the build, it also
decreases as the bar goes up so make sure u do a DECREASED search
rather than INCREASE. If u use the pause build button u can also
add a NOT CHANGED search which will shorten ur search a LOT)

oki, this is what I found.

108E030C: 001046BA <-- this value is what remained of my build progress.

Once u have ur value, (ur value will be different btw.. ) then u need to
freeze all building progress with the PAUSE BUILD button.. its just on the
right of the actual progress bar, this will stop our breakpoint from picking
up and of the progression code.

Now we have this done we need to set an OPEN breakpoint on the progress value
we just searched for.. so in softice do this..

type.. BPM <address> (return)

mine looks like this..

BMP 108e030c (return)

An OPEN BREAKPOINT just means that it will pick up any code that either READS or WRITES to
the
value we breakpoint.
If u have done this correctly softice should constantly break at the code below..

We know that this is indeed the onscreen display routine because if we change
the JNZ at location 51cff5 to a JMP then we get no progress bar at all on the
screen.

.text:0051CFF3 cmp edx, [ecx]


.text:0051CFF5 jnz short loc_51D016
.text:0051CFF7 mov ecx, [ebp+var_C]
.text:0051CFFA mov ecx, [ecx+1Ch]
.text:0051CFFD mov eax, [eax+0Ch] <-- our build progress value is placed in eax.
.text:0051D000 mov [ebp+var_1C], ecx <-- softice breaks here
.text:0051D003 sar eax, 0Ah <-- our build progress value is converted.
.text:0051D006 sub ecx, eax <-- ecx = build to go, eax = build already done
.text:0051D008 mov [ebp+var_4], ecx

The code here just determines the percentage of the screen it has to fill with the color
yellow, this represents the build progress..

So now we have tracked down our STAPLE INTERSECTION that will NEVER be used by the
computer
yet it has a direct link to the values we need to change.. oh happy day!! :) We are ready to
inject a little bit of code to make an instant build for PLAYER ONLY..

So.. first thing we do is determine what we need to inject.. well, I suggest the best way to
tackle this problem is by moving 0 into the (LEFT TO BUILD) progress value which is
situated at offset EAX+0Ch, u need to be very careful though because as u may have noticed
the pointer EAX+0Ch is actually being placed into EAX which will destroy our pointer
to the value we need.. so this is where we shall jump out..

.text:0051CFF3 cmp edx, [ecx]


.text:0051CFF5 jnz short loc_51D016
.text:0051CFF7 mov ecx, [ebp+var_C]
.text:0051CFFA mov ecx, [ecx+1Ch]
.text:0051CFFD mov eax, [eax+0Ch] <-- jmp out here --.
.text:0051D000 mov [ebp+var_1C], ecx |
.text:0051D003 sar eax, 0Ah |
.text:0051D006 sub ecx, eax |
.text:0051D008 mov [ebp+var_4], ecx |
|
|
|
CODE CAVE |
|
.data:008b9E00 <---to here--------'
.data:........
.data:........
.data:........

final code looks something like this..

.text:0051CFF3 cmp edx, [ecx]


.text:0051CFF5 jnz short loc_51D016
.text:0051CFF7 mov ecx, [ebp+var_C]
.text:0051CFFA mov ecx, [ecx+1Ch]
.text:0051CFFD jmp 8b9e00 <-- jmp out here(1)--.
.text:0051D000 nop #-- back to here(2)--. |
.text:0051D003 sar eax, 0Ah | |
.text:0051D006 sub ecx, eax | |
.text:0051D008 mov [ebp+var_4], ecx | |
||
||
||
CODE CAVE | |
||
.data:008b9E00 mov dword ptr [eax+0c],0 #---to here(1)-----'
.data:........ mov eax, [eax+0Ch] |
.data:........ mov [ebp+var_1C], ecx |
.data:........ jmp 51d000 <---jmp back from here(2) -----'

Most of the time I recreate the destroyed instructions first, but because the instruction
destroys the pointer then I had to re-create it after we have placed 0 into the build
progress value.

Once this is all done u can press F5 to let softice run the game and ur instant build will
be complete..

IMPORTANT NOTE: its very important that u always re-create the instructions u destroy when
using CODE CAVES, at worst u will crash the game and at best u will kill gfx onscreen which
I always think is an ugly option.

ADDITION: I forgot to add this in, The theory used here can be applied to any options really,
money etc.. anything that has a screen value.. try it next time u come across a game that
uses the SAME routines for health as u and the enemy.. works 100%.. thanks to SKYNET for
reminding me to add this.. :)

FINAL WORDS
-----------

Once again we find ourselves at the end of another show.. time just flies when ur reading
massive amounts of shite! :)) seriously I hope u all get something from this tutorial, I
dont spend my time writing them for nothing u know :)

until next time dudes..

******************************************************************************************
******************************************************************************************

If u have any questions or comments then email me at... sh33pr3c@hotmail.com

visit my site for more tutorials.. http://WWW.SHEEPREC.CJB.NET

I would just like to greet some people that support and inspire me....

Odin, MiraMax, KeyboardJunky, Calligula, Orr, DarkLighter, Kilby, Tuna,


MiNiSTER, [NTSC], [Drone], Rizzah, [Etrigan], tko..

No order.. just GREAT people..

PLEASE FEEL FREE TO SPREAD THIS DOCUMENT TO ANY SITES!!!!!


Simple In-game Trainer Menus
----------------------------
Author: Orr

NOTE!
This tutorial is _Definetly_ NOT for newbies. Best read with NOTEPAD.

Introduction
------------
Say you made a trainer with 10 or more options. The game you trained uses routine
protect against Alt+Tabbing outside the game. Say that the gamer using your train
forgot what are the trainers options, or he forgot what keys to use. He can do tw
things now. Quit the game, or try to press all the keys and see how it affects hi
Is there a solution for this kind of situation? Well, There is!

The method I will suggest in this tutorial was not invented by me. As far as I kn
it was already done in the old DOS days. That method is called Ingame Trainer Men
The purpose, is to show the trainer option menu, inside the game, when the user h
a hotkey.

What I will show in the tutorial, is how to make a trainer with one hotkey, that
pressed, will pop up a Message Box from inside my favorite target game: (pam pam
"The House of the Dead 2".

The tools I will be using are SoftICE, IDA, HIEW, and Visual C++ (not a must).

Theory
------
Basically the idea I will suggest works like that:

1. The user presses the menu hotkey.


2. The Trainer injects some code to a free space in the game's memory.
3. The Trainer overwrites a place in the gameloop.
4. The code injected will be run (the code is a messagebox) by the game.
5. The Trainer fixes the place it overwritten in the gameloop.

In case you don't know how to perform in-mem code injections, I suggest you go re
alittle about it in [SHEEP]'s tutorial, or keep reading on, as I will explain som
fundumentals of injections.

Finding a Game Loop


-------------------
A Problem arises with what we want to do. We want to inject code to the game, and
the game run it by itself. Injecting the code isn't much of a problem, it is actu
quite easy. But how do we make the GAME run OUR code?

The solution is quite simple.

If we find a place that is getting executed ALL the time (like, in a huge loop :)
could locate a good place to patch there, and inject our code to am empty space.
question is, how do we find a place, a loop that runs all the time?

Basically, what I did was, whiile playing that game alittle, I poped SoftICE for
times, until I saw I am in the correct process (look in the bottom-right corner o
for the CLSID), in my case it is HOD2. I poped SoftICE in times that I wasn't doi
so I would see what code is executed even when I am IDLE.

After poping up in a place that looked OK, I began tracing alot. Some cases I did
manually, and some cases I did it using the T command (T 100 will trace 100 instr
After a while, I saw that some loop is being executed alot of times, so I wanted
it out. I disassembled the file with IDA, and got to that location. I am terribly
to tell you I really forgot what location it was... What I did though, was seeing
function that location was, and then seeing who calls it... for example:

.text:004A4EA0 sub_4A4EA0 proc near ; CODE XREF: sub_4A41C0+142p


.text:004A4EA0 push ebx
.text:004A4EA1 push ebp
:
:
:
.text:004A4F47 test ah, 41h ; Say, this location :)
:
:
:
.text:004A4FDA pop ebp
.text:004A4FDB pop ebx
.text:004A4FDC retn
.text:004A4FDC sub_4A4EA0 endp

This function is called from the location sub_4A41C0. So I went there. and there
I found a cool place that executed many API's. Anyway, I chose this location:

.text:004A5967 push ecx ; lpMsg


.text:004A5968 call ds:GetMessageA
.text:004A596E test eax, eax

Why? Because GetMessage is a Windows API that gets executed all the time. I check
for my suspicion by simply setting a breakpoint at that location, and I saw that
I couldn't even play for one sec, because SoftICE kept popping after I pressed F1

Also, I am a fan of overwriting API calls. Why?


a) They have a sufficient amount of OPCodes (6, in many cases).
b) They can be executed later on from anywhere in the program, with the same opco
c) Because Micro$oft coders did them (and because I couldn't find another reason

OK, So we found a place to overwrite with our jump... now we actually need a plac
to jump to!

To summarize:
You can do 2 things in order to find a place that is getting executed all the tim

- Find a place that loops alot manually, by simply stopping the game in an IDLE
point, and trace from there. Tracing can be done manually, or it can be done
using the T command in SoftICE.

- Breakpoint on known API's that are likely to get executed all the time:
GetMessage, GetTickCount.

Finding a Place to Inject


-------------------------
OK, This is my favorite part.

Windows EXE's are based on the PE (Portable Executable) file format. The PE forma
supports sectioning of the file. Every section of the file has a different job.
There are Code/Data/Resource/Import/Export/etc sections. Most sections are differ
in size, so they all must be aligned. Because of that nice feature compilers leav
us, there are often alot of 'dead' NULL bytes, that are simply wasted just to ali
the section size. There is a difference between those code caves, because these a
mapped to memory, while there may be cases you will see empty places, but they wo
be mapped into memory, thus you cannot jump to them.

There are few ways to find the alignments in the exe:

1. You simply scroll through the entire EXE looking for those alignments. Once yo
see empty spaces, you check if they are indeed code caves (later on how to check)

2. In a hex editor, look for a binary string that contains nothing but 00's. It w
you to many odd places, but eventually to a cave.

3. You do the "proffesional" way. In IDA (or any other PE editor), we get some in
about the sections. We go to the beginning of the code (generally on top), and we

.text:00401000 ; File Name : D:\Games\THoTD2\Hod2.exe


.text:00401000 ; Format : Portable executable for IBM PC (PE)
.text:00401000 ! ; Section 1. (virtual address 00001000)
.text:00401000 ! ; Virtual size : 000C1940 ( 792896.)
.text:00401000 ; Section size in file : 000C2000 ( 794624.)
.text:00401000 ; Offset to raw data for section: 00001000
.text:00401000 ; Flags 60000020: Text Executable Readable
.text:00401000 ; Alignment : 16 bytes ?
.text:00401000 ; OS type : MS Windows
.text:00401000 ; Application type: Executable 32bit

You see that the Virtual Address is 1000, and that the Virtual Size is C1940?
You add those up together, and you get C2940. You go to that OFFSET in the file,
will see a nice and clean code cave. :)

In order to check if this is indeed a CODE cave, and not just a dead cave, in HIE
notice if there is a dot (.) before the address of not. The address will be 4C294
see this: .004C2940, then this is code... if you see just 004C2940 then it won't
Trust me on this one, I spent a lot of hours figuring why it didn't work on some
I was working on a while ago.

What to Inject?
---------------
OK, So we know where to jump from, and where to jump to. But all of this is usele
we inject something! In this tutorial, I will show how to inject a simple Message

A standard MessageBoxA call looks like that:

push Style
push Caption
push Text
push WindowHandle
call MessageBoxA
But remember, that we have overwritten an API... so we need to execute it again,
to the location we came from (actually we jump to the instruction after the API c

call GetMessage
jmp 4A596E

After that, we need to actually inject the text for MessageBox caption and text.
location 4C2970 for the caption, and 4C2980 for the actual text. The style will b
So we have this code now:

push 0
push 4C2970
push 4C2980
push 0
call MessageBoxA
call GetMessage
jmp 4A596E

But this code won't work... because we push 0 as the window handle. If we use 0 a
handle, then the MessageBox will be shown OUTSIDE the game, and sometimes cause i
crash. So how do we solve this? We need to find the window handle, and push it. B
the Window Handle is saved in a variable after the window was created. So we go b
IDA, and we track down the CreateWindowExA function. We see where it is reference
and we find this location:

.text:004A5885 call ds:CreateWindowExA


.text:004A588B test eax, eax
.text:004A588D mov dword_7DC8AC, eax

So we see that the hWnd is saved in a global variable which is located inside the
memory address 7DC8AC. So now, we have to get that value, and push it, instead of

push 0
push 4C2970
push 4C2980
mov eax, [7DC8AC]
push eax
call MessageBoxA
call GetMessage
jmp 4A596E

OK, now we get a little practical and summarize what we have:

1. A place to jump from : 4A5968


2. A place to jump to : 4C2949 (not 4C2940, because I want to leave some space
3. A place to put strings: 4C2970
4. A place to return to : 4A596E

Make a copy of hod2.exe, and name if hod2_.exe or whatever. We will be doing all
changes to this one. Open up HIEW, select HOD2_.exe, and then press F4 and go to
mode. Press F5, and type ".4A5968" (Without quotes ofcourse). Now you are in this

.text:004A5968 call ds:GetMessageA

Press F3 (to be in EDIT mode), and then press F2 (to be in ASSEMBLE mode), and ty
jmp 4C2949 [Enter]
nop [Enter]
[Escape]

Press F9 to update.

now go to the cave (.4C2949), and assemble the code block we wanted to add (see a
For API's you cannot assemble, so you will have to leave 6 nop's for each API. ho
add an API? Simply. Do you remember that I told you that it can be executed from
in the program, and also with the same opcodes all the time? Simply go to a locat
that calls GetMessage (4A5968), and a location that calls MessageBoxA (49E148), a
the opcodes (FF 15 xx xx xx xx).

After that go to add the strings (F3 and then TAB), and simply write them. Rememb
In order to separate strings there has to be a 00 between them:

.004C2970: 54 72 61 69-6E 65 72 20-4F 70 74 69-6F 6E 73 00 Trainer Options


.004C2980: 48 69 21 Hi!

OK, I believe we are all set.

The Trainer
-----------

This is how the source of the trainer looks like:

#include <windows.h>
#include "resource.h"

// Define sizes for writing into memory.


#define OPT1 6
#define OPT2 58

char wname[]="The House of the Dead 2"; // Window Name


BYTE opt1[OPT1]={0x90,0xE9,0xDC,0xCF,0x01,0x00}; // Jump my_injectio
BYTE opt1_off[OPT1]={0xFF,0x15,0x34,0x32,0x4C,0x00}; // Call GetMessage(

// The rest of the


BYTE opt2[OPT2]={0x90,0x6A,0x00,0x68,0x70,0x29,0x4C,0x00,0x68,0x80,0x29,0x4C,0
0xA1,0xAC,0xC8,0x7D,0x00,0x50,0xFF,0x15,0xFC,0x31,0x4C,0x00,0
0x15,0x34,0x32,0x4C,0x00,0xE9,0x01,0x30,0xFE,0xFF,0x00,0x00,0
0x54,0x72,0x61,0x69,0x6E,0x65,0x72,0x20,0x4F,0x70,0x74,0x69,0
0x6E,0x73,0x00,0x48,0x69,0x21};

LRESULT CALLBACK main (HWND, UINT, WPARAM, LPARAM);


HINSTANCE hInst;
HWND g;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin


{
// Basic Windows API main entry

hInst = hInstance;
DialogBox(hInst, MAKEINTRESOURCE( IDD_DIALOG1 ), 0, (DLGPROC)main);
return(0);
}

int Write(char windowname[], long address, BYTE *writearr, long sizeofarr)


{

// My WRITE engine

HWND hwnd;
HANDLE phandle;
DWORD pid,bytesw;

hwnd = FindWindow(0, windowname);


if (hwnd == 0) {
SetDlgItemText(g, ID_EDIT1, "Error: Cannot Find Game Window!");
goto quit;
}

GetWindowThreadProcessId(hwnd, (unsigned long *)&pid);

phandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);


if (phandle == 0) {
SetDlgItemText(g, ID_EDIT1, "Error: Cannot Open Game Process!");
goto quit;
}

WriteProcessMemory(phandle, (void *)(address), &writearr[0],sizeofarr, &bytesw);


return(1);

quit:
return(0);
}

BOOL GetKeyPress(int key)


{
// HotKey handling routine
return ((GetAsyncKeyState(key) & 1)==1);
}

VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
// This is the actual thing!
{
if (GetKeyPress(VK_F4)) { // If F4 was pressed
Write(wname, 0x4C2949, opt2, OPT2); // Write The injection
Write(wname, 0x4A5968, opt1, OPT1); // Patch the call
Sleep(2000); // Wait a little (2 seconds)
Write(wname, 0x4A5968, opt1_off, OPT1); // Change back the call
}
}

LRESULT CALLBACK main(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

// Main Message function


g = hDlg;
switch (uMsg)
{
case WM_INITDIALOG:
SetTimer(hDlg,0, 100, TimerProc);
break;

case WM_COMMAND:
if (wParam == ID_QUIT) ExitProcess(0x31337);
break;

default : return(FALSE);
}

return(TRUE);
}

Explanation:
What I did, was writing all the injected bytes into memory. First I wrote the inj
then I Patched the place to jump from, then waited for 2 seconds, and then patche
back again. I didn't bother to Zero out all the injection, because it won't get e
anyway.

Ending
------
Phew! That was a lot to write! I have been working 2 days on this menu + another
actually WRITING this. Looking back, it wasn't very tough, I just had to reboot a
due to blue screens and other sorts of page faults and weird exceptions.

What you have to keep in mind while doing an ingame menu, is:

1. Finding a place that runs all the time.


2. Finding a code cave.
3. Adding your code, followed by doing the instructions you overwritten.
4. Finally jumping back to the place.

There can be many problems and diffuculties that can occur. For example, what hap
if you don't find a global variable that contains the Window Handle? For that cas
can simply use FindWindow(0,"Window Name"). But what happens if you don't have Fi
imported in the EXE? You can import it like this:

push offset "User32.dll" ; Find the address of User32.DLL in memory


call GetModuleHandle ; eax contains the address

push offset "FindWindowA" ; Function to find


push eax ; what DLL? (the one we found eariler)
call GetProcAddress ; eax contains the address of the function

push offset "Window Name" ; What window name?


push 0 ; What CLSID?
call eax ; call FindWindowA

Finally, my little advice, BE CREATIVE. Think of more ideas, like adding DIALOG B
many more options, or perhaps even injecting the ENTIRE trainer to the game, so y
even have to use an external program besides a memory patcher.

Attached to this package is the trainer source, and a nice pic hehe :)

Thanks:
[SHEEP]: Encouragement, and for telling me the Window Handle thing
Duelist: For telling me where to find that Window Handle thing :)

Greets:
iCARUS, Have_No_Mercy, calligula, jmp_fce4, Keyboard Junky, ddh, MacDeath, Dang,
and all the other dudes in #gamehacking which I forgot to add. Please bitch
me if I forgot :)

Orr in July 2002.


OrrAghion@hotmail.com

LONG LIVE ISRAEL!

/\
____/__\____
\ / \ /
\/ \/
/\ /\
/__\____/__\
\ /
\/
TUT NO. 5
~~~~~~~~~~

(BEST VIEW WITH NOTEPAD 800/600)

============================I N T R O==================================

Salve a tutti ! (Hello everybody !) (Hai noroc si la mai mare!)

Here's another piece of work ;)

In this tut i'll show you how to make a *FULL AND TOTAL* hack on a game. I choose
Lamentation Sword (i like it very much).

DETAILS about the game:


-it's a RPG game, like Diablo or Rage of Mages
-u have 3 characters to play with (all 3 at the same time !!!)
-weapons,armors,swords,potions,monsters,quests... *all the comfort* hehehe :))

=============================T O O L S U S E D======================

Like always, you will need:

SoftIce :}
GameTrainer (or any other mem. finder). It must have a dump memory option!
Hex-Workshop (i prefer HIEW, but we'll need Hex-Workshop!!!)
W32Dasm (to show u a cracking approach :))
a little time to read this...

============================H A C K T Y P E==============================

Now, i want to show u how a game can be hacked...

PART 1:

Hacking the money, potions, gems, balls (fire and ice balls, not what u have in m

PART 2:

Hacking the time u must spend before u learn a magic-spell

PART 3:

Hacking the STAT-POINTS

PART 4:

Hacking the Experience-points

PART 5:

Hacking the weapons durability

PART 6:

Hacking the life & mana points

PART 7:
Hacking the weapons properties

PART 8:

Cracking the game when needed ;)

******** With the hope that u'll learn something from this, LET'S BEGIN !!! *****

=============================T H E P A R T S (the hacking in other words)=======

Before going any further, i must tell u one thing: the game uses DMA (and u don't
to pee your pants, trust me :] )

__________________________________________________________
PART 1: (money,potions, all u need to finish a game :)) |
(The money are stored as a DWORD) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ok! Start the game, kill some monsters, find some money. Note the amount on a pie
paper!

Pause the game, ALT+TAB and start your mem. finder! Search for the money value. G
in the game, inc\dec your amount and search again the new value with the mem.

Repeat that until u have only one addr!

Ok, addr found! Now change the amount within the mem. finder to know if that is t
addr!

Yes, it is! Good...

Now, put a breakpoint in SoftIce on that addr! (my addr was 865998, but yours wil
different, because of the DMA !)

bpm 865998 w -------> in SoftIce

Now, kill some monsters to find money! SoftIce popped! You should see this:

.............code code code.............

xxxx:aaaaaaaa mov eax,[esp+04] ------->the amount of money you find (money1)


xxxx:bbbbbbbb mov edx,[ecx+58] ------->the amount of money you had before addin
xxxx:cccccccc add edx,eax ------->perform the add operation (money2:=money
xxxx:dddddddd mov eax,[ecx+44] -------| unimportant
xxxx:eeeeeeee cmp eax,31 -------| instructions
xxxx:ffffffff mov [ex+58],edx ------->update the amount of money in the memory
You will land in SI after the above instruction

.............code code................

I think it's clear for everyone: the game stores the old value of money in edx, t
to add in eax, then add operation is performed, then updates the old value of
with the new one!
Now, let's loose some money to see what's happening... Go to a merchant and buy s

SoftIce popped... !@#$@$@$@#$ What the fu*k ?!?!?!?

We land in the code above, where the game incs our money! But we loose some money

Now, put a bpx on the addr xxxx:aaaaaaaa

bpx aaaaaaaa -----> where aaaaaaaa is the addr


i.e: 0167:00123456 mov eax,[esp+04] ---> bpx 123456

Loose some money again! SI popped at aaaaaaaa! F10, then type "? eax" in SI! WTF
ugly number? Oh, it's a negative one. So the add operation in this case will
afterall...

i.e: 123+(-3)=123-3=120
123+(+3)=123+3=126

Get the idea? Good...

Now what can we do? We can nop the add instruction, but when we find some money,
will not increase anymore, and when we buy something, the amount will not dec
well! But we don't want not to inc our money, right?

Now the technique will use it's simple: we must check for the value to see if it
or positive. If it's negative, then we will not add it on the amount. If it's
we'll add it!

To do this, we must write some code hehehe :)))


NOTE : this will be more clear to u if u read sheep's tuts! (very good ones !)

To inject our code we must:


- find a place to inject (usually where are a lot of 0's)
- jump to that place
- write there the code
- jump back

Now, i wont tell u how to find the place to inject the code (read sheep's or mail
have problems). I'll just tell u what to inject:

eax=money to add/sub
edx=your amount
cmp eax,0 -> check if we loose money
jl back -> if so, then don't dec the sum and jump to the game code
add edx,eax -> if we find money, inc the sum
jmp back -> jump to the game code

Now, to understand this, READ SHEEP'S TUTS !!!

BTW, the add\sub method is the same for potions,ice_balls etc ! So u don't need t
other code!

______________________________________
PART 2 (learn magic in a sec. !!!) |
(The time u need is stored as a WORD)|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now, take one of the 3 characters (i like Kusa) to a witch. Choose him a magic_sp
learn. Oh, no... He must wait some time until he will learn the spell (it's t
concentration time :)
And the higher is the level of the magic u want to learn, the bigger is the time!
This must be fixed somehow...

Pause the game while he is learning. Note the amount of time left down on a piece

Search the value with your mem.finder until u have 2 addresses. One of them is fo
screen output and one of them is the real one. U can check this by modifying
(one by one) within your mem.finder, then go back in the game to see if it's

Put a breakpoint on that addr (mine was 1E63D30)

bpm 1E63D30 w --------> in SoftIce

SI popped! You should see the code:

....................code code code......................


mov ecx,[esi+730] ------->the remaining time before u learn the spell
dec ecx ------->dec it by 1
mov eax,ecx ------->save the new time to eax
mov [esi+730],ecx ------->update the old time with the new one
cmp eax,ebp ------->all the time had elapsed ? (ebp is always 0)
jg u_must_wait ------->if no, then u must wait until it does
.....................code............................

From the above code u see this: The game dec the timer one by one until it is 0.
it's 0, then your character have learnt the spell.

All u have to do is to nop down that "jg u_must_wait" !!! If u don't execute that
instruction, then your character will INSTANTLY learn the spell !!!

Isn't this great, or what? hehehe...

_______________________________________
PART 3: (the well-known STAT-POINTS) |
(They are stored as WORD) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Well, nothing much to say here, just the same old method: Wait until u make a "le
to gain some stat-points. Then search the quantity with your mem.finder...
You should see something like this:

..................code...........................
dec dword ptr [ecx+7f8]
..................code...........................

You know what you have to do... If you want, you can nop the instruction! In this
you will have infinity stat-points!
____________________________
PART 4: (EXPERIENCE points)|
(It's stored as DWORD) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here is best to cheat using your mem.finder! So, after finding the correct addr.,
to a huge number (u know, something like 99999999 :)). After that, back in th
each time u hit a monster, you will level-up your character!!! kooll...

__________________________________
PART 5: (the weapons durability) |
(You must dump your memory!) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ok, so we want to find where the game changes the durability of our equipment...
some tries, i figure it out that if your sword has it's durability 20, in mem
stored as 20.
So, we must dump the memory!

After this, dec your sword durability by one, pause, ALT+TAB, and in your mem.fin
the option that search the dumped memory for changed values (in GameTrainer t
button called "Diff"). Do this until u have only one addr!

Now put a bpm (breakpoint on memory access) on that addr in SoftIce --> mine

bpm 86551C w --> in SI

Back to the game. Play a little (kill something) and SI should pop!

.........................code code..........................
mov eax,[esp+04] ------->here will be 1 encrypted
mov edx,[ecx+5C] ------->here will be weapon's old durability, also
sub edx,eax ------->substract 1 from the dur.
xor eax,eax ------->unimportant instruction
mov [ecx+5C],edx ------->update the new durability of the weapon, al
You will land in SI after the above instruction
.........................code code.........................

To clear this out: The game takes the durability of the weapon (let's say it's 20
it (20 will be transformed into 179, for example), then takes 1 and encrypt i
say the encryption of 1 will be 17). After this perform operation with encryp
(substracts 17 from 179, in our example) then it updates the memory address w
new encrypted value.
Simple, heh...

And because the encryption, the game don't use "dec edx", but "sub edx,eax" to su
from our dur.

You can't change the durability of your weapon within your mem.finder (because it
encrypted value ;))

All you have to do is to nop out the sub instruction that dec your weapon's dur.
_______________________________________________________
PART 6: (life & mana, where would we be without them ?|
(Again you must DUMP !!!) |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ah, the life and the mana! The essence of every RPG ! We want to freeze them, cor
Then follow me ! hehehe... :)

Let's play with the life points, first!

Dump the memory, change your life points (ask a monster to hit you :)), search th
memory for changed values! Repeat this until u have only one addr!

Put a bpm in SI ---> my addr was 1E635BC

bpm 1E635BC w

Now, go to a monster to hit u! SI popped! You should see this:

............code....................
mov edi,eax ------>move the "damage" to edi
................code...............
mov eax,[esi+810] ------>move your life to eax
push 3C ------>unimportant
sub eax,edi ------>substract damage from life
mov DWORD PTR [ESP+28],1 ------>unimportant
mov [esi+810],eax ------>update the new life in the addr
You will land after the above instruction in SI
..................code.............

What this code does: takes the amount of damage you receive from a monster and su
it from your current life!

To become invincible, you must nop out that "sub eax,edi" that is eating your lif

For the mana, u must use the same dump procedure!

Here's the snippet:

..................code code....................
mov cl,[eax*4+493D96] ------>mov the cost of the spell in cl
mov eax,[esi+80C] ------>mov in eax your mana points
sub eax,ecx ------>sub the cost from your mana
mov [esi+80C],eax ------>update the new mana
You will land in SI after the above instruction
.......................code code code............

I think it's clear for everybody: The game substracts the cost of the spell u cas
your mana points!

To prevent this & to have infinity mana & to cast spell after spell upon your ene
NOP that sub instruction !!!
_________________________________
PART 7: (hacking the properties)|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Unlike Diablo2, that when (for example) u find an item with enhanced damage, the
enhance your damage by a random number, Lamentation Sword have fixed weapon p

i.e:
in Diablo 2 : Long Sword may have damage 13
Long Sword may have damage 15
Long Sword may have damage 17

in Lam.Sword: Long Sword always have damage 13


Long Sword always have damage 13
Long Sword always have damage 13

See what i mean?

So, this means that the game keeps this values in a file. And that file is non ot
Sword.exe (the game's .exe!).

Fire up Hex-Workshop and take a look in Sword.exe. Waw...

You'll find there all the weapons' names (u can change them too!), and above the
are the properties :))

Now, for example search for Devil's Bow who has Magic+5 and Sight+3 as special pr

Found! And now search up for 5 or 3 (Magic+5 and Sight+3), but the search must be
32_bit_signed_long type! (thanks Hex-Workshop!)

Found, modify, play, test, cheers!!! hehehe...

________________________________________
PART 8: (Hacking using cracking skills)|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I like this game very much! Since u have 3 characters to play with at the same ti
go to kill monsters with all 3, or u can leave in town (or in other region) t
"hurt_ones", and go and play with only one char.

But here comes the tricky part: if u find a good sword with one of your warriors
to give it to any of the other 2, they must be in the same region! If not, th
u that "Not in the same region". Mmmmm... It seems to me like a bug! Let's fi

Fire up W32Dasm and disassemble the Sword.exe. Now search that message (Not in th
region). Found!

Scroll up in W32Dasm until u find a je\jne\cmp\test... In our case is :

...........code..........

cmp eax,ecx
je it_seems_like_they_are_in_the_same_region
...........code...........

* Possible StringData Ref From Data Obj -> "Not in the same region"

...........code...........

That's what u should see in W32Dasm! I think u guess what u have to do, eh?

Simple: Change the je (jump if equal) to jmp (jump always), and this way u'll pre
seeing that ugly message, and u should be able to exchange the weapons an
between your characters!

Of course u know that\how u can change the jump within Hex-Workshop! ;)

==========================================F I N A L W O R D S===============

Huh, i think that this was the biggest document i ever wrote!

Hope u learnt something useful from this, and u didn't fall asleep :))

=================================G R E E T S & C H E E R S +===================

groza (always from now on ;) )


all members in New2Cracking (especially ParaBytes)
all members in the GameHacking's forum
YOU, for loosing your time with this piece of sh... :)) Better go outside & play
JUVE (hope Nedved will win the Golden-Ball this year)
to all people in Romania:
*************************************************************************
* Va salut pe toti si sper ca intr-o buna zi veti avea tot ce va doriti!*
* Sa auzim numai de bine! *
* Cautati-ma !!! *
*************************************************************************

Sorin (Splinter@email.ro)

the beginning of 2003's summer holydays !

BTW: I think i'll be out in this beautiful summer

EOF
Game Hacking - Tutorial v1.0Tutorial with picture available online here
http://www.ghu.as.ro/ghtuts/omega1.htm

About:

This is the 1st real tutorial I've made the others have been small simple things just so I know what to do, in the future.
This definately isn't the last tutorial I'll make, but I just have to find time.
Well I hope this tutorial is helpful to all you GameHackers out there.

Before you say it MiCRaL I know i could have used jmp but i wrote this tutorial before you told me and have edited it just to
write this in
I've tested it with jmp and it uses the same amount of bytes so i didn't see the point in changing the tutorial
I hope to get a new version out VERY soon, with Source-Code etc.

This Tutorial explains how to:

Search Memory.
Code Inject
Use EasyWrite
Use AutoHack
Make a trainer with Trainer Maker Kit 1.51

Comes with TMK 1.51 Project File.

Future:

In this Tutorial I want to add:

Alot more info on Code Injection as not many people know what this is, and how to do certain things, so I'll add everything I
learn to this tutorial.
Making a trainer in VB, Delphi, ASM, and C++
One HTML page for each Section, when it gets bigger. ie. SearchMemory.html, CodeInject.html etc.

And alot of other stuff.

Gr33tz goes to....

Hype
MiCRaL
Raven
Curt
Artanis
Elissaios
Famore
Raiko
Johno
Ste J
Apoc
Ckob
ddh

Needed Tools:

TSearch v1.6
Trainer Maker Kit v1.51
Minesweeper - I'm hacking XP Version so values will be different on another OS etc.

Hacking:

Start WinMine.exe, then play a new game, so the timer counts up, then minimize the WinMine.exe window (to pause the
game)

Load up TSearch, and click the big Open Process Button at the top.double click on winmine.exe

Next click the "Init New Search" (1st One), button under the open process button.
"Value:" = Time Amount
"Type:" = 1 Byte (Value shouldn't be over 255 for now.)
Then click ok.

Once TSearch has found all the addresses, go back to winmine.exe, and let the time increase, minimize again and
then click the "Search Next" (2nd One), button under the open process button.
"Value:" = New Time Amount
"Type:" = 1 Byte

Click ok, then once search is complete, you should end up with 1 address, if not just repeat, the search next part.

Double click the address in the results table.


To add it to the cheat list.
Give it a descriptions I'll use Time
Change the Type: to 4 bytes.

NOTE:
When I edited the time, I never realised It was stored in 4 bytes, because I didn't realise the time went to 999, I don't play
winmine.exe
I start memory searching for 1 Bytes, you'll have more addresses to scan but more chance of hitting the right one if under
255.

Also, the addresses I use in this tutorial MAY be different it all depends on what Version of Windows you have and
Minesweeper.

Click "AutoHack" / "Enable Debugger"

Now, click "AutoHack" / "AutoHack window"

We will see the "AutoHack" Window, in the bottom text box you will see:
CREATE_PROCESS At Address
LOAD_DLL : "DLL NAME" At Address
BREAKPOINT AT : Address

Go Back to TSearch
Click "Time" (with the right button) and click "AutoHack"

Then go to winmine, increase the counter, and then minimize and go back to "AutoHack" window.

You should see a screen like the screenshot above, "1002FF5" and "0x100579C" will be different if you use a different
winmine (win98/ME etc).
Now at the bottom you'll see the "Disassembler" Tab, Click it, then click on the Code above. 1002FF5 etc (Or vice-versa)

01002ff5 = The Current Memory Address


FF059C570001 = Bytes In Current Memory Address
inc dword ptr [0x100579C] = ASM Code to increase counter.

Now you can either do 2 things.


Change the Code to Decrease the counter instead of increase, or nop the address, so it doesn't do anything.

Decrease Counter:

Now right click the 01002ff5 line, and click "Assemble"

Change from: inc dword ptr [0x100579C] Change To: dec dword ptr [0x100579C]

Once changed click Assemble.


And now your counter should be decreasing instead of increasing.
This isn't v/gud in this game as the counter is still decreasing even when gets to 0 but it doesn't show it on winmine.exe but
in memory searcher it is.
But in other games it might prove useful.

TMK Code:
DECREASE: Poke 1002FF5 FF 0D 9C 57 00 01
INCREASE: Poke 1002FF5 FF 05 9C 57 00 01

I got these, by reading what it said in the AutoHack Window before editing and after, take a look and you'll see what I mean.

NOP Counter:

Now left click the 01002ff5 line, and icons on the toolbar above will be enabled.

Click the Patch to NOP the address (Make It No-Operation - Do Nothing)


Click the unPatch to remove the nops and restore original code.

Then on the menu at the top, click "Tmk" / "Button Script"


And there you have the code for your trainer.

DMA:

If you you this method on a address that is DMA, all you have to do is nop the Game Code, 01002ff5 was the game code in
this instance, the game code is the code that changes the DMA address, so for money decreasing just nop the dec command,
autohack finds.

I'll go into more detail with this in the next version. (Screenshots etc)

EasyWrite:

Click the new button.

You will then see:

Taken from TSearch Help File:


"hex" write hex chain into memory ex: hex 9050c3
"offset" set offset where the code will be writen into memory

Description: = Decrease

Top TextBox:
offset 0x1002ff5
dec dword ptr [0x100579C]

Bottom TextBox:
offset 0x1002ff5
inc dword ptr [0x100579C]

Explaination on what we did above:

Top TextBox:
We take the 1002ff5 from AutoHack and write "offset 0x1002ff5"
We want to decrease when checked, and the code before was inc (Increase) so we write "dec dword ptr [0x100579C]"

Bottom TextBox:
We take the 1002ff5 from AutoHack and write "offset 0x1002ff5"
We want to increase when unchecked and the origiinal code was inc (Increase) so we write "inc dword ptr [0x100579C]"

Click ok and you should see its been added to the EasyWrite box.
If the checkbox doesn't appear then you've got an error in the code, RE-CHECK.

If its fine check the box next to it, and the counter should Decrease instead of Increase, and uncheck it and it should
return to normal.

Click new again.

Description: = NOP

Top TextBox:
offset 0x1002ff5
hex 909090909090

Bottom TextBox:
offset 0x1002ff5
hex FF059C570001

Explaination on what we did above:

Top TextBox:
We take the 1002ff5 from AutoHack and write "offset 0x1002ff5"
We want to patch when checked, and the code before was inc (Increase) so we write "hex 909090909090"

Bottom TextBox:
We take the 1002ff5 from AutoHack and write "offset 0x1002ff5"
We want to unpatch when unchecked and the original code was inc (Increase) so we write "hex FF059C570001" or "inc
dword ptr [0x100579C]"

Click ok and you should see its been added to the EasyWrite box.
If the checkbox doesn't appear then you've got an error in the code, RE-CHECK.

If its fine check the box next to it, and the counter should Freeze instead of Increasing, and uncheck it and it should
return to normal.
All you have to do now is make a trainer, for the codes you just found:
Quick Help on making a trainer in TMK at bottom.

Click here for the TMK Project File (Trainer SourceCode).

TMK Code:
Poke 1002FF5 FF 0D 9C 57 00
DECREASE
01
Poke 1002FF5 FF 05 9C 57 00
INCREASE
01
Poke 1002FF5 90 90 90 90 90
PATCH
90
Poke 1002FF5 FF 05 9C 57 00
UNPATCH
01

Also:

If you go back a few memory addresses by 15 (HEX), you'll notice:

ADDRESS MEMORY BYTES ASM CODE: DESCRIPTION


cmp dword ptr Compares an address to 0,
01002fe0 833D6451000100
[0x1005164],0x0 interesting.
If 0x1005164 = 0 then Jump to
01002fe7 741E je short 0x01003007
Exit Function
cmp dword ptr
01002fe9 813D9C570001E7030000 if 0x100579C = 999
[0x100579C],0x3E7
if 0x100579C = 999 then Jump to
01002ff3 7D12 jge short 0x01003007
Exit Function
01002ff5 FF059C570001 inc dword ptr [0x100579C] Else Increase 0x100579C By 1
01002ffb E8B5F8FFFF call 0x010028B5
01003000 6A01 push 0x1
01003002 E8E6080000 call 0x010038ED
01003007 C3 retn Exit Function

01002ff3 compares, the address for the Time to 3E7 (HEX) / 999 (DEC) which is the max amount of time you can have.
If then time equals 999 then it jumps past the increase, to address 0x1003007 which Exits The Function.

Another address to look at is 01002FE0, it compares 0x01005164 to 0, so I checked this out, when your alive this = 1,
when your dead it = 0.
Poke this address to 0 and the timer stops, poke to one and it starts.

Decrease:
If you use this method, then you notice the counter messes up as it tries to minus 0 there's a script in there if it equals zero
then jump out but it didn't work all the time.
So if you do a bit more code injection you'll be able to get it to work right.

In The Top TextBox on EasyWrite, Type:

Offset 0x10011b5
cmp dword ptr [0x100579C],0x0
je LONG 0x01003007
dec dword ptr [0x100579C]
ret

offset 0x1002ff5
call 0x10011b5
nop

In The Bottom TextBox on EasyWrite, Type:

offset 0x1002ff5
inc dword ptr [0x100579C]

Simple Explaination Of Above Code:

Code To Patch Counter:

In The Bottom TextBox on EasyWrite, Type:


Go to offset (Code Cave) where we are going to write
Offset 0x10011b5 code.
(I'll explain more about code caves in next version)
cmp dword ptr
Compare Address 0x100579C to 0
[0x100579C],0x0
je LONG 0x01003007 Jump to Address 0x1003007 (Jumps if 100579c = 0)
dec counter (If 0x100579C isn't 0 then decrease
dec dword ptr [0x100579C]
0x100579C)
ret return to the main program function
offset 0x1002ff5 Go To Offset we want to replace.
call 0x10011b5 Call the Code Cave where our injection is going.
Extra NOP, so game doesn't crash (Call is shorter than
nop
increase)

So:
If 0x100579C = 0 then
Get out of function
Else
Decrease counter

To make this work in TMK you need to use:

TMK Code:
Poke 10011B5 83 3D 9C 57 00 01 00 0F 84 45
1E
PATCH
Poke 10011C0 00 00 FF 0D 9C 57 00 01 C3
Poke 1002FF5 E8 BB E1 FF FF 90
UNPATCH Poke 1002FF5 FF 05 9C 57 00 01

Just by AutoHacking one code you MIGHT find other ways of hacking that code or other codes.
I know your proberly thinking Whoopy Doo, Its Minesweeper, I'm only using minesweeper as an example, cuz everyone has
Minesweeper, and its easy to hack, so beginners should find this tutorial easy to follow.

So we've covered Memory Searching, Using AutoHack and Writing Easy Write code.
Hopefully in the next release I will clear this file up making it easier to read, understand, etc.
Add a few more things.

Ok thats about it.


You can use this type of method for ANY game.

I don't know if you've noticed but in the last 2 week my knowlage of Code Injection has improved Greatly.
I'm hoping to get alot more knowlage to, and I am learning ASM while hacking. FUN :D

OMEGA = Elite.
Well not really but I'm getting there, slowly but I'm definately getting there.

Please remember I do NOT have SoftIce/Driver Studio, which is why I'm using TSearch.
I want it but i can get it :(

Trainer Maker Kit:

Start a new project and add 4 buttons.

Right-Click in a Button and click in "Write memory actions"


You'll then see the "Code-Editor"
Now, get your code (in my case it's Poke 1002FF5 FF 0D 9C 57 00 01) and paste it into the "Code-Editor"

Repeat these steps for Increase, Patch And UnPatch, and then Save the Project and Compile.

Phew, this has been alot of typing for one day.

>> Tutorial By Omega <<


Hacking Minesweeper with Omni Trainer v 1.0

Hi there guys it's me again and this time with an tutorial on hacking Minesweeper

Needed Tools :
» Any Game (i'll use Minesweeper)
» The OMNI TRAINER v 1.0 - get in www.omnitrainer.cjb.net
» Some Coke, Fanta or Coofe (hmm... I like coke, he he he....)
» Some music , of course....like Rock or Eletronic Music :)
» Do u have a brain, right?

Ok, let's start rocking ! :)

Step 1 : Finding the address

1. Open Minesweeper.

2. Open the Minesweeper process in Omni Trainer. You can do this by using the Pro

3. Create a New Location.


You can do this by using the Location \ New Location menu command.

4. Search for the Seconds Address. Click the Search button. To find the second ad
5. Check the Address. You should make sure that the seconds address you found is

6. Set the Modify Value and the Refresh Time. Since you want to get the lowest ti

7. Personalize the Location with a Label and Info. You may want to label this loc

8. Enable the Location. Double-click the location you just created to enable it.

9. Saving your Location List. To save your newly created location list use the Lo

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

Tutorial by [D.N.A]
eXtalia (c) 2003
contact : dna.netz@ig.com.br or dna@extalia.com
web: www.extalia
italy 19-1o-2oo3
Minesweeper Reversing
A simple exercize
written by ZaiRoN

Introduction:
Minesweeper is one of the millions M$ games and in this tutorial I will explain you how to add a new feature
on the game. The new feature will give you the ability to view where the bombs are.
Literature:
http://www.woodmann.net/fravia/menusspa.htm
http://www.woodmann.net/fravia/TracePlus_MenuPatch.html
http://www.woodmann.net/fravia/kayaker_RegmonPlus.htm
http://www.codeguru.com/mfc/comments/50642.shtml
Target:
MineSweeper (English version for WinXP/W2k)

Program description:
Don't you ever played with this game in your boring days? I can't believe you :-p
Tools:
- a debugger (Ollydbg)
- a disassembler (Ida)
- a resource editor (Resource Hacker)
- Spy++
- c and asm compiler (lcc, masm)
music: Black Sabbath - Black Sabbath

Included file (containing files and resources mentioned in this tut):


zaiwinmine.zip

Preamble
We will show where the bombs are as a *mouse-over* effect as the cursor moves over each grid
square. We will add all the modifications inside a dll and we will write a loader to patch the
program in memory. This is not only a reversing exercize but also a programming exercize because
you will have to code a dll, work with GDI and finally write a little loader. This tutorial is a resume
(with some differences) of a project at the RCE board, you can find the thread here.
We start finding all the places where we will have to put a jump to our code; after that we will write
the code to add to the program, we will write the dll and finally a little loader.
Find the point where to add the new menu item
We should be able to pass from normal to cheat mode (and viceversa) therefore the best way is to use
a new menu item. I will add the new item inside 'Game' menu, after the 'New' item.
We can use a resource editor but remembering that we need to patch the file in memory, we have to
think in a different way. How can I add a new item into an existing menu? We can use the function
InsertMenuItem. This function will be placed into a cave with all the other modifications needed by
the program. We will see later how to use this function, for the moment you only have to know that
InsertMenuITem will be called in the initialization part of the program, exactly after the menu has
been loaded (because it needs the menu handle...).
Now, we should find the place where to insert the jump to the new cave. The program uses LoadMenu
to load the menu:
:010014B9 push 1F4h <------- lpMenuName
:010014BE push hInstance <-- hInstance
:010014C4 call ds:LoadMenuW
:010014CA push 1F5h <------- lpTableName
:010014CF mov hMenu, eax
:010014D4 push hInstance <-- hInstance
:010014DA call ds:LoadAcceleratorsW
:010014E0 mov [ebp+hAccTable], eax
:010014E3 call sub_10023DB
:010014E8 mov eax, dword_10052A4
:010014ED mov ecx, yBottom

When the menu has been loaded you can insert the new item, I decided to put a jump to the code that will
call the InsertMenuItem directly at 10014E8. I did choose this particular address only because it has the
same number of bytes of the new jump instruction...
Find the point where the program checks whether a menu item has been pressed
This task is useful because we need to add/manage the new menu item, the special mode option. If you
check the 'special mode' item, the game will show you the bomb, otherwise the game will remain the
same.
There are many ways to solve this second point.
- You can use Spy++, a little application that gives you a view of many informations about a process that is
running on your system.
Run Minesweeper and then run Spy++. You will see a list of the running processes, find Minesweeper
process and double click on it. A dialog will show you some informations about the game, one of them is
the window procedure.
- Another way to locate the window procedure is to use Ida.
This is more or less the way explained by +Spath in his tutorial. Load the file into ida and press ctrl-p; a
dialog appears. This dialog contains the functions used by the program and, we are interested in WinMain
function, the one used to define the window class. This is useful because from here you can understand
where the window procedure is. The program uses RegisterClassW function to register the window class:

ATOM RegisterClass(
CONST WNDCLASS *lpWndClass // address of structure with class data
);

and:

typedef struct _WNDCLASS {


UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;

This structure contains the window attributes; we are interested in lpfnWndProc because it points to the
window procedure. Look at the disasm Ida gave you and take the address we were looking for:
:01001472 mov [ebp+WndClass.style], edi <----------------------- style param
:01001475 mov [ebp+WndClass.lpfnWndProc], offset sub_100180A <-- lpfnWndProc param, our
address is 100180A
:0100147C mov [ebp+WndClass.cbClsExtra], edi <------------------ cbClsExtra param
:0100147F mov [ebp+WndClass.cbWndExtra], edi <------------------ cbWndExtra param
:01001482 mov [ebp+WndClass.hInstance], ecx <------------------- hInstance param
:01001485 mov [ebp+WndClass.hIcon], eax <----------------------- hIcon param
:01001488 call ds:LoadCursorW
:0100148E push ebx ; int
:0100148F mov [ebp+WndClass.hCursor], eax <--------------------- hCursor param
:01001492 call ds:GetStockObject
:01001498 mov [ebp+WndClass.hbrBackground], eax <--------------- hbrBackground param
:0100149B lea eax, [ebp+WndClass]
:0100149E mov esi, offset AppName
:010014A3 push eax ; lpWndClass
:010014A4 mov [ebp+WndClass.lpszMenuName], edi <---------------- lpszMenuName param
:010014A7 mov [ebp+WndClass.lpszClassName], esi <--------------- lpszClassName param
:010014AA call ds:RegisterClassW <------------------------------ RegisterClassW

Ok, now that we know where the window procedure is, it's time to use a debugger, Ollydbg.
Load the program and jump to the window procedure, we need to set a breakpoint. Remembering that we
are trying to find the part of the procedure which check whether a menu item is clicked, we need to break if
and only if a menu item is clicked. When an item is clicked, a specific WM_COMMAND message is sent to
the procedure. This specific message contains the menu item identifier (the one you have clicked on) in the
loworder word of the wParam parameter.
Take a look at the first part of the window procedure:

:0100180A PUSH EBP


:0100180B MOV EBP,ESP
:0100180D SUB ESP,40
:01001810 MOV ECX,DWORD PTR SS:[EBP+C] <-- ecx is the message (i.e. WM_COMMAND)
:01001813 PUSH EBX

If we want to catch the click over one of the menu item we need to set a conditional breakpoint (Shift+F2)
at 1001810. The condition I have used is:
[EBP+0Ch]==111H && [EBP+10H]==209H
where '[EBP+0Ch]==111H' checks for the WM_COMMAND message and '[EBP+10H]==209H' checks
whether the 'Beginner' menu item is been clicked (you can use your preferred menu item :-)). Run the
program and click on the chosen item, Olly breaks. Steps a little and you will surely find the place where the
program checks which menu items is been pressed:
:010018B7 MOV EAX,111
:010018BC CMP ECX,EAX <-------------------- Is WM_COMMAND received?
:010018BE JA winmine.01001B3F
:010018C4 JE winmine.010019AD <------------ We jump if a WM_COMMAND has been received
...
:010019AD MOV ECX,DWORD PTR SS:[EBP+10] <-- ecx is the wParam
:010019B0 MOVZX EAX,CX <------------------- eax is the item identifier
:010019B3 CMP EAX,20B <-------------------- Is "Expert" item clicked?
:010019B8 JG SHORT winmine.01001A30
:010019BA CMP EAX,209 <-------------------- Is "Beginner" item clicked?
:010019BF JGE SHORT winmine.010019EE
This piece of code is what we were looking for; since we will have to check whether the new menu item
has been clicked, we will change the jump at 10018C4 into a new jump. We will see later how the code will
look like.

Find the point where the program checks whether a WM_MOUSEMOVE has been received
This is necessary because from here we will jump to the dll function that shows a possible bomb. In
order to find the place where the program checks for WM_MOUSEMOVE message we will change
the conditional breakpoint; the new condition will be: [EBP+0Ch]==200H
:01001B3F MOV EAX,DWORD PTR SS:[EBP+C] <-- the received message
:01001B42 MOV ESI,200 <------------------- 200h = WM_MOUSEMOVE
:01001B47 PUSH 1
:01001B49 XOR EDI,EDI
:01001B4B CMP EAX,ESI <------------------- is WM_MOUSEMOVE received?
:01001B4D POP EBX
:01001B4E JA SHORT winmine.01001BB4
:01001B50 JE winmine.01001DD5 <----------- yes, WM_MOUSEMOVE received

Stepping a little you will see that this type of message is not so useful for the original program therefore we
will change the jump at 1001B50.
How to modify the Minesweeper process
First of all we have to find a place where we will go to insert the new code; there are many caves
inside the file, you must only choose one of them. I will add the new code starting from 10049A5h.
What does this new code is supposed to do? It adds the new item menu and then it simply calls a
function from our dll.
InsertMenuItem is not imported by the program and so we will have to use the combination of
LoadLibrary/GetProcAddress functions. To use these two functions is pretty easy.
LoadLibrary: it's the first function to use and it maps the dll module into the address space of the
calling process. The function returns a handle that can be used in GetProcAddress to get the address
of a dll function.
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName // address of the string that names the executable module
);
GetProcAddress: returns the address of the exported dll function.
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module (the value returned by LoadLibrary)
LPCSTR lpProcName // address of the string that names the function
);
Now that you know how to call InsertMenuItem we can see how this function looks like:
BOOL WINAPI InsertMenuItem(
HMENU hMenu, // Handle to the menu in which the new menu item is inserted
UINT uItem, // Identifier or position of the menu item before which to
insert the new item
BOOL fByPosition, // If FALSE, uItem is a menu item identifier. Otherwise, it is
a menu item position
LPMENUITEMINFO lpmii // Pointer to a MENUITEMINFO structure that contains
information about the new menu item
);
and:
typedef struct tagMENUITEMINFO {
UINT cbSize; // Size of structure, in bytes
UINT fMask; // Members to retrieve or set
UINT fType; // Menu item type
UINT fState; // Menu item state
UINT wID; // Application-defined 16-bit value that identifies the menu
item
HMENU hSubMenu; // Handle to the drop-down menu or submenu associated with
the menu item
HBITMAP hbmpChecked; // Handle to the bitmap to display next to the item if it is
checked
HBITMAP hbmpUnchecked; // Handle to the bitmap to display next to the item if it is
not checked
DWORD dwItemData; // Application-defined value associated with the menu item
LPTSTR dwTypeData; // Content of the menu item
UINT cch; // Length of the menu item text
} MENUITEMINFO, FAR *LPMENUITEMINFO;
Even if there are alot of parameters, the use of this function is pretty easy.
This is the code you have to inject into the Minesweeper program:

:010049A5 ; Initial address of the cave I chose


:010049A5 dword_10049A5 dd 0 ; specialMode=08h if specialMode is
enable otherwise specialMode=00h
:010049A6 aZaiwinmine_dll db 'zaiWinmine.dll',0 ; The name of the new DLL
:010049B5 aUser32_dll db 'User32.dll',0 ; InsertMenuItem is inside USer32.dll
; The name of the 2 exported functions:
:010049C0 aChangeitemstat db 'changeItemStatus',0 ; Changes the status of the itemmenu
:010049D1 aRevealcell db 'revealCell',0 ; Reveals a bomb under a cell
:010049DC dword_10049DC dd 0 ; Stores the address of
changeItemStatus function
:010049E0 dword_10049E0 dd 0 ; Stores the address of revealCell
function
:010049E4 aInsertmenuitem db 'InsertMenuItemA',0
:010049F4 aSpecialMode db 'Special Mode',0 ; Text to be place in the new menu item
; MENUITEMINFO structure:
:01004A01 dd 2Ch ; Size of structure: 11 dwords = 2Ch bytes
:01004A05 dd 42h ; MIIM_ID + MIIM_STRING
:01004A09 dd 0 ; MFT_STRING, displays the menu item using a text string
:01004A0D dd 0 ; Default state
:01004A11 dd 212h ; Id of the new item
:01004A15 dd 0 ; NULL because the item does not open a drop-down menu or submenu
:01004A19 dd 0 ; NULL, default check mark
:01004A1D dd 0 ; NULL
:01004A21 dd 0 ; NULL
:01004A25 dd 10049F4h ; The pointer to a null-terminated string that defines the text of
the new item
:01004A29 dd 4 ; The length of the string
:01004A2D ; From initialization (10014E8): we add the new item and save the address of
changeItemStatus and revealCell
:01004A2D push offset loc_10014ED ; Address from where to return to
:01004A32 pusha
:01004A33 push offset aUser32_dll ; "User32.dll"
:01004A38 call ds:LoadLibraryA ; Maps User32.dll
:01004A3E push offset aInsertmenuitem ; "InsertMenuItemA"
:01004A43 push eax ; Handle to dll module
:01004A44 call ds:GetProcAddress ; Get the address of the function
:01004A4A mov ebx, offset hMenu
:01004A4F push offset dword_1004A01 ; Pointer to a MENUITEMINFO structure
:01004A54 push 0 ; FALSE
:01004A56 push 0 ; The position of the item
:01004A58 push dword ptr [ebx] ; Handle to the menu
:01004A5A call eax ; call InsertMenuItem
:01004A5C push offset aZaiwinmine_dll ; "zaiWinmine.dll", the name of the dll
:01004A61 call ds:LoadLibraryA
:01004A67 mov esi, eax
:01004A69 push offset aChangeitemstat ; "changeItemStatus"
:01004A6E push esi
:01004A6F call ds:GetProcAddress
:01004A75 mov ds:dword_10049DC, eax ; Stores the address of changeItemStatus
:01004A7A push offset aRevealcell ; "revealCell"
:01004A7F push esi
:01004A80 call ds:GetProcAddress
:01004A86 mov ds:dword_10049E0, eax ; Stores the address of revealCell
:01004A8B popa
:01004A8C mov eax, dword_10052A4
:01004A91 retn ; Jump to the original code
:01004A92 ; From 'specialMode' item clicked (10018C4): we call changeItemStatus
:01004A92 push offset loc_10019AD ; Address from where to return to
:01004A97 pusha
:01004A98 call ds:dword_10049DC ; call changeItemStatus
:01004A9E jmp short loc_1004AB6
:01004AA0 ; From WM_MOUSEMOVE event (1001B50): we call revealCell
:01004AA0 push offset loc_1001DD5 ; Address from where to return to
:01004AA5 cmp ds:byte_10049A5, 0 ; Is the special mode enable?
:01004AAC jnz short loc_1004AAF ; Yes, jump down
:01004AAE retn ; specialMode is disable, no need to show the bomb,
jump back to the original code
:01004AAF pusha
:01004AB0 call ds:dword_10049E0 ; call revealCell
:01004AB6 popa
:01004AB7 retn ; Jump back to the original code

Now, we have to modify the instructions at 10014E8, 10018C4 and at 1001B50 because they have to
jump to the new code:

:010014E8 jmp loc_1004A2D


:010018C4 jz loc_1004A92
:01001B50 jz loc_1004AA0
DLL functions
We have seen all the modifications we will have to add to the program; from now on, we will see how to
write the 2 dll functions:
- changeItemStatus, this function will check/uncheck the menuitem enabling or disabling the special mode.
- revealCell, this function reveals a bomb under a cell.
changeItemStatus
To check/uncheck the item I will use CheckMenuItem function:

DWORD CheckMenuItem(
HMENU hmenu, // handle to menu
UINT uIDCheckItem, // menu item to check or uncheck
UINT uCheck // menu item flags
);

An easy function to use. It needs:


1. the handle of the menu. We don't have the handle but since the function is imported and since some of
the items of the menu could be checked/unchecked, the easiest way to retrieve the handle is to put a
breakpoint on this function and hit one of the checked items, for example the 'sound' item. Perfect, Olly will
break showing us where the handle is stored.
2. the id of the menu. It's the number we gave to our new item.
3. we are interested in two values:
MF_CHECKED (08h): sets the check-mark attribute to the checked state.
MF_UNCHECKED (00h): sets the check-mark attribute to the unchecked state.

I did write the dll in asm but no one will stop you from writing it in other languages. Here is the first
function:
; Change the status of the new item
changeItemStatus proc
.IF word ptr [ebp+10h] == 212h ; 212h is the id I used for the new item
mov ebx, 10049A2h ; byte [10049A2] stores the state of the menu item
xor byte ptr [ebx], 08h
movzx eax, byte ptr [ebx]
mov ebx, 10052BCh ; address where the menu handle is stored
invoke CheckMenuItem, dword ptr [ebx], 212h, eax
.ENDIF
ret
changeItemStatus endp

The only thing that requires an explanation is the value stored at 10049A2. This byte is:
00h if the item is unchecked
08h if the item is checked
Why not 00h and 01h? That is because I use this address for store both the state of the item and the menu
item flag.
revealCell
Before writing the function we must understand where the bombs are stored.
We need to find a way to break when a cell is clicked. Exploiting the work we have done before, I will use
another conditional breakpoint at 1001810; the idea is to break when the left mouse button is pressed
(and then released). When this button is released, a WM_LBUTTONUP (202h) message is posted and so,
the new condition will be: [ebp+0Ch]==202h
Set the new breakpoint and click on a cell; Olly breaks, steps a little until Olly will tell you that you have
found the place:

01001C30 XOR EDI,EDI ; Cases 202 (WM_LBUTTONUP) <-- thx to


Olly :-D
01001C32 CMP DWORD PTR DS:[1005160],EDI
01001C38 JE winmine.01001D4C
01001C3E MOV DWORD PTR DS:[1005160],EDI
01001C44 CALL DWORD PTR DS:[<&USER32.ReleaseCaptu> ; ReleaseCapture
01001C4A TEST BYTE PTR DS:[1005010],BL
01001C50 JE SHORT winmine.01001C5C
01001C52 CALL winmine.0100373E ; hmmm...
01001C57 JMP winmine.01001D4C ; jump at the end of the procedure
This is the code that manages the WM_LBUTTONUP command; as you can see there is a call to
ReleaseCapture, a jump at the end of the procedure and a suspicious call. Maybe it's the call that will show
us where the bombs are. Enter the call and take a glance at it:
010037F2 MOV EDX,ECX ; ecx stores the number of the row of the clicked cell, eax stores
the column
010037F4 SHL EDX,5
010037F7 MOV DL,BYTE PTR DS:[EDX+EAX+1005700] ; dl = value stores in the clicked cell
As you can see the first row is stored starting from 1005721 and it ends with the character with double
value 0x10. Doing some tryes you will sooner understand which is the value that identify the bomb, it's
0x8F.
Now that we know almost everything about the program, we have to show these damned bombs. I will try
to explain you how to show them when the mouse pass over a cell; the bombs will remain showed until
the end of the game. We can write the other function of the dll, the one I called revealCell. What this
function is supposed to do? Remembering that the function will be called on every single movement of the
mouse (and let's suppose specialMode is enable), we have this scheme:

1. Is the pointer inside the grid?


No: quit from the function
Yes: jump to 2

2. Is the cell hiding a bomb?


No: quit from the function
Yes: reveal the bomb

The point number 1 is necessary because the bombs can not be outside the grid while the point number 2 is
the final check. The first cell (upper left corner) starts from coordinates 0x0C,0x37 and each cell is
0x10,0x10. Now that we know this information, we are able to implement the point number 1: a simple 'if'
based on the coordinates of the point where the mouse has been pressed. How did you know the x and
the y coordinates where the mouse has been pressed? WM_MOUSEMOVE will tell you; infact:
WM_MOUSEMOVE
fwKeys = wParam; // key flags
xPos = LOWORD(lParam); // horizontal position of cursor
yPos = HIWORD(lParam); // vertical position of cursor
Here is all that you need :-D

Point number 2: first of all, we have to check whether a cell hides a bomb; this is not a problem because
we know where the program stores the grid in memory and, we will easily perform this check but... how
can I reveal a bomb under a cell? The answer is inside Graphics Device Interface (GDI) library; in this specific
case we will use GDI to display a bitmap. My new version of the game displays the image that has the
bomb on the red background (open the program with a resource editor, you will find the image I am talking
about under "Bitmap-410-1033"). You can display the image you prefer taken from the proggie or created
by you. To display this image I use these functions: GetDC, BitBlt, ReleaseDC.
GetDC: retrieves a handle of a display Device Context (DC) for the client area of the specified window.
HDC GetDC(
HWND hWnd // handle of window
);

This is the first function we have to call and it takes a single parameter. How do we know the handle of the
window? Simple, these 3 functions are used by MineSweeper and so, the best way to understand how to
use them is to bpx them and to look how they are used. This time, put a bpx on GetDC and run again the
program. Ollydbg will surely break and the only thing you have to do is to take note of the address that
contains the handle...
BitBlt: it clips an image from a source DC to a destination DC.

BOOL BitBlt(
HDC hdcDest, // handle to destination DC, the GetDC returned address
int nXDest, // x-coordinate of destination rectangle's upper-left corner
int nYDest, // y-coordinate of destination rectangle's upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
HDC hdcSrc, // handle to source device context
int nXSrc, // x-coordinate of source rectangle's upper-left corner
int nYSrc, // y-coordinate of source rectangle's upper-left corner
DWORD dwRop // raster operation code
);

Easy. As before, the best way for to understand how to use the function is to bpx it on Ollydbg. If you want
to display another image you have to change the 6° parameter: hdcSrc.

ReleaseDC: the ReleaseDC function releases a device context


int ReleaseDC(
HWND hWnd, // handle of window
HDC hDC // handle of device context
);

Ok, it's time to past the source of the revealCell procedure:

.data
oldRow db "0100499D"
oldColumn db "010049A1"
; Display the image under a cell
revealCell proc
pushad
; Is the mouse pointer inside the grid ?
.IF word ptr [ebp+14h] < 0Ch || word ptr [ebp+16h] < 37h
jmp @exitRevealCell
.endif

xor eax, eax


mov ax, word ptr [ebp+14h] ; The x-coord of the mouse
sub eax, 0Ch
shr eax, 4
add eax, 1 ; The number of the column -inside the grid- where the
mouse is pressed
xor ebx, ebx
mov bx, word ptr [ebp+16h] ; The y-coord of the mouse
sub ebx, 37h
shr ebx, 4
add ebx, 1 ; The number of the row where the mouse is pressed

mov edi, 100499Dh


.IF ax == word ptr [edi] && bx == word ptr [edi+4]
; It's in the same cell than before, no need to display the same image again
jmp @exitRevealCell
.ENDIF

mov ecx, ebx


mov edx, ecx
shl edx, 5
mov ebx, 1005700h
add ebx, eax
add ebx,edx
; Reveal the cell if and only if there is an hidden bomb
.IF byte ptr [ebx] == 8Fh
mov edi, 100499Dh
mov dword ptr [edi], eax ; Save the column
mov dword ptr [edi+4], ecx ; Save the row
push eax
push ecx
mov esi, 10052A8h ; Pointer to handle of window
push [esi] ; Handle of window
call GetDC
mov esi, eax
pop ecx
pop eax
shl ecx, 4
add ecx, 27h
shl eax, 4
sub eax, 4
mov ebx, 1005AE0h
push 0CC0020h ; SRCCOPY flag
push 0
push 0
push [ebx+48] ; Source DC, the image to display
push 10h ; Height of the rectangle
push 10h ; Width of the rectangle
push ecx ; y coord
push eax ; x coord
push esi ; Handle to destination DC
call BitBlt
mov ebx, 10052A8h
push esi ; Handle of DC
push dword ptr [ebx] ; Handle of window
call ReleaseDC
.ELSE
mov dword ptr [edi], 0
mov dword ptr [edi+4], 0
.ENDIF

@exitRevealCell:
popad
ret
revealCell endp

Postamble: conclusion.
The tutorial ends here, you only have to write a loader which will load the program and add the new
functionality in memory. I will not tell how to write a simple loader, you will find all the sources
inside the attached file.
Playing with the new version of the game I have discovered a weird fact; set the special mode feature
and make the first click over a bomb. Nothing happens, the bomb disappears; is there something
wrong in our work? Eheh, no. Where the bomb has gone? (Hint: it is a specific characteristic of the
program.. :-))
Greetings and thanks.
all the UIC members. As usual, feel free to
I would like to thank all the friends at RCE messageboard and
mail me for comments, suggestions, bug reports and/or whatever you want...

ciao,

ZaiRoN
zaironcrk(at)hotmail.com

Disclaimer
All the information given are for educational purposes only.
Bie comment:
This info is taken from http://www.codeproject.com/script/Articles/list_articles.asp?userid=172641

Tutorial Author: arikp


Email: Unknown
Homepage: Unknown
Other known method to contact the author

Unknown
Introduction

Ever wanted to know what is happening in the Minesweeper game behind the scenes?
Well, I did, and I decided to investigate it. This article is the result of my research, brought here just for you.
Main Concepts

1. Using P/Invoke to invoke Win32 API's.

2. Direct reading another process memory.

NOTE: the first part of this article involves some assembly code, if there something you don't understand it's NOT important to the goal of this article. you CAN skip it. Nevertheless, if you want to
ask me about it, you're more then welcome to mail me your question.

NOTE 2: The program was tested on Windows XP, so if you got some other system it might not work.. if you got some other system, and it did worked, comment this article with your system info
so we all could enjoy that knowledge.

Update to NOTE 2: the code is now fixed in order to work on Windows 2000 as well. thanks goes to Ryan Schreiber for finding the addresses in Win2K.
Step 1 - Investigate winmine.exe

If you're not an assembly fan, you might want to skip to the end of this step, to the conclusions..

So, in order to know better what is happening behind the scenes of Minesweeper I've started by opening the file in a debugger. My personally favorite debugger is Olly Debugger v1.08, this is a
very simple and intuitive debugger. Anyway, I've open winmine.exe in the debugger and looked a bit on the file. I've found in the Import section (a section that lists all the dll functions that are
used in the program) the following entry:

010011B0 8D52C377 DD msvcrt.rand

which means that the Minesweeper uses the randomize function of the MicroSoft Visual C RunTime dll, So I thought it might help me. I've search the file to find where the rand() function is being
called, I've found only one such place:

01003940 FF15 B0110001 CALL DWORD PTR DS:[<&msvcrt.rand>]

Then I've put a breakpoint on this single call and ran the program. I've discovered that every time you click the smiley a new mines map is generated. the mines map is created as follows:

1. Allocate a block of memory for the mines map and set all the memory bytes to 0x0F, which means that there is no mine in that "cell".
2. second, loop over the number of mines and for each mine:
2.1. randomize x position (1 .. width).
2.2. randomize y position (1 .. height).
2.3. set the correct cell in the memory block to 0x8F, which represents a mine in this cell.

here is the original code, I've added some remarks, and bolded the important parts:

010036A7 MOV DWORD PTR DS:[1005334],EAX ; [0x1005334] = Width


010036AC MOV DWORD PTR DS:[1005338],ECX ; [0x1005338] = Height
010036B2 CALL winmine.01002ED5 ; Generate empty block of memory and clears it
010036B7 MOV EAX,DWORD PTR DS:[10056A4]
010036BC MOV DWORD PTR DS:[1005160],EDI
010036C2 MOV DWORD PTR DS:[1005330],EAX ; [0x1005330] = number of mines
; loop over the number of mines
010036C7 PUSH DWORD PTR DS:[1005334] ; push Max Width into the stack
010036CD CALL winmine.01003940 ; Mine_Width = randomize x position (0 .. max width-1)
010036D2 PUSH DWORD PTR DS:[1005338] ; push Max Height into the stack
010036D8 MOV ESI,EAX
010036DA INC ESI ; Mine_Width = Mine_Width + 1
010036DB CALL winmine.01003940 ; Mine_Height = randomize y position
; (0 .. max height-1)
010036E0 INC EAX ; Mine_Height = Mine_Height +1
010036E1 MOV ECX,EAX ; calculate the address of the cell in the memory block
; (the map)
010036E3 SHL ECX,5 ; the calculation goes:
; cell_memory_address = 0x1005340 + 32 * height + width
010036E6 TEST BYTE PTR DS:[ECX+ESI+1005340],80 ; [cell_memory_address] == is already mine?
010036EE JNZ SHORT winmine.010036C7 ; if already mine start over this iteration
010036F0 SHL EAX,5 ; otherwise, set this cell as mine
010036F3 LEA EAX,DWORD PTR DS:[EAX+ESI+1005340]
010036FA OR BYTE PTR DS:[EAX],80
010036FD DEC DWORD PTR DS:[1005330]
01003703 JNZ SHORT winmine.010036C7 ; go to next iteration

As you can see from the code I've discovered 4 important things:

1. Reading the memory in address [0x1005334] gives me the Width of the map.

2. Reading the memory in address [0x1005338] gives me the Height of the map.

3. Reading the memory in address [0x1005330] gives me the number of mines in the map.

4. Given x,y that represents a cell in the map, in column x, row y, the address [0x1005340 + 32 * y + x] gives me the cell value.

Which brings us to the next step..


Step 2 - Design a solution

You might wonder, what kind of solution am I talking about? Well, after discovering that all the mine information is available for me, and all I need to do is read the data from the memory I've
decided to write a small app that reads this information and present it for you. It can even draw a map of its own, with a picture of a mine wherever I find one..

So, what is to design about that? all I need to do is put the address into a pointer (yes, they exist even in C#) and read the pointed data, right? well, not exactly, the reason why this is not the
case is that the memory where this data is stored is not in my application. You see, each process has its own address space so it could not access "by accident" memory that belongs to another
program, so in order to read this data I need to find a way to read the memory of another process, in this case, its the Minesweeper process.

I've decided to write a small class library, that will receive a process and will give me the functionality of reading a memory address from this process. the reason I've decided to make it a class
library is because there is allot of cases you might want to use it so why develop it again and again? That way, you could easily take the class and use it in your own application, and you are free
to do so. An example for where this class can help is if you write a debugger. All the debuggers I know have the ability to read memory of the debugged application..

So, how do we read another process memory? the answer resides in an API called ReadProcessMemory. this API actually let you read a process memory at a specific address. Only before you do it
you must open the process in a special read mode and when you finish you must close the process handle, to avoid resource leaks. The following operations are performed with the help of two
more API called OpenProcess and CloseHandle.

In order to use API's with C# you must use the P/Invoke, meaning you need to declare the API you're going to use, which is basically quite simple, but you need to do it in the .NET way, which is
not that simple sometimes.. I've found the API declarations in the MSDN:

HANDLE OpenProcess(
DWORD dwDesiredAccess, // access flag
BOOL bInheritHandle, // handle inheritance option
DWORD dwProcessId // process identifier
);

BOOL ReadProcessMemory(
HANDLE hProcess, // handle to the process
LPCVOID lpBaseAddress, // base of memory area
LPVOID lpBuffer, // data buffer
SIZE_T nSize, // number of bytes to read
SIZE_T * lpNumberOfBytesRead // number of bytes read
);

BOOL CloseHandle(
HANDLE hObject // handle to object
);

Well this declaration transformed to the following C# declarations:

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

[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[In, Out] byte[] buffer,
UInt32 size,
out IntPtr lpNumberOfBytesRead
);

[DllImport("kernel32.dll")] public static extern Int32 CloseHandle(


IntPtr hObject
);

If you want to know more information on the types conversions between c++ and c#, I suggest you searched msdn.microsoft.com for the topics: "Marshaling Data with Platform Invoke". Basically,
if you put there what is logically true, it will work. sometimes, a bit tuning is requested.

After I have these functions declared, all I need to do is wrap them with a simple class and use it. I've put the declarations in a separate class called ProcessMemoryReaderApi, only to be more
organized. The main utility class is called ProcessMemoryReader. This class has a property named ReadProcess, this property is from the type System.Diagnostics.Process, this is where you
put the process you want to read its memory.

The class has a method which opens the process in the read memory mode:

public void OpenProcess()

{
m_hProcess = ProcessMemoryReaderApi.OpenProcess(
ProcessMemoryReaderApi.PROCESS_VM_READ, 1,
(uint)m_ReadProcess.Id);

The PROCESS_VM_READ constant tell the system to open the process in read mode, and the m_ReadProcess.Id states what process do I want to open.

The most important method in the class is the one that reads the memory from the process:

public byte[] ReadProcessMemory(IntPtr MemoryAddress, uint bytesToRead,


out int bytesReaded)
{
byte[] buffer = new byte[bytesToRead];

IntPtr ptrBytesReaded;
ProcessMemoryReaderApi.ReadProcessMemory(m_hProcess,MemoryAddress,buffer,
bytesToRead,out ptrBytesReaded);
bytesReaded = ptrBytesReaded.ToInt32();

return buffer;

This function declares a byte array in the requested size and read the memory with the API. Simple as that.

And finally, the method that close it all:

public void CloseHandle()

{
int iRetValue;
iRetValue = ProcessMemoryReaderApi.CloseHandle(m_hProcess);
if (iRetValue == 0)
throw new Exception("CloseHandle failed");

}
Step 3 - Using the class

Well, here comes the fun part. Using the class in order to read Minesweeper memory and reveal the map. In order to use the class you must first instantiate it:

ProcessMemoryReaderLib.ProcessMemoryReader pReader
= new ProcessMemoryReaderLib.ProcessMemoryReader();

then, you need to set the process you want to read its memory, here is an example of how to get the Minesweeper progress, once it is loaded, and set it as the ReadProcess property:

System.Diagnostics.Process[] myProcesses
= System.Diagnostics.Process.GetProcessesByName("winmine");
pReader.ReadProcess = myProcesses[0];

and all we need to do now is Open the process, read the memory, and close it when we finish. Again, here is an example of how its been done. Here I read the memory address that represent the
Width of the map.

pReader.OpenProcess();

int iWidth;
byte[] memory;
memory = pReader.ReadProcessMemory((IntPtr)0x1005334,1,out bytesReaded);
iWidth = memory[0];

pReader.CloseHandle();

that simple!

In conclusion I present you the full code that reveals the map of mines. Don't forget, all the memory places I'm accessing are places found in the first section of this article..

// resource manager for the picture of the mine


System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));

ProcessMemoryReaderLib.ProcessMemoryReader pReader
= new ProcessMemoryReaderLib.ProcessMemoryReader();

System.Diagnostics.Process[] myProcesses
= System.Diagnostics.Process.GetProcessesByName("winmine");

// take first instance of minesweeper you find


if (myProcesses.Length == 0)
{
MessageBox.Show("No MineSweeper process found!");
return;
}
pReader.ReadProcess = myProcesses[0];

// open process in read memory mode


pReader.OpenProcess();

int bytesReaded;
int iWidth, iHeight, iMines;
int iIsMine;
int iCellAddress;
byte[] memory;

memory = pReader.ReadProcessMemory((IntPtr)0x1005334,1,out bytesReaded);


iWidth = memory[0];
txtWidth.Text = iWidth.ToString();

memory = pReader.ReadProcessMemory((IntPtr)0x1005338,1,out bytesReaded);


iHeight = memory[0];
txtHeight.Text = iHeight.ToString();

memory = pReader.ReadProcessMemory((IntPtr)0x1005330,1,out bytesReaded);


iMines = memory[0];
txtMines.Text = iMines.ToString();

// delete the previous button array


this.Controls.Clear();
this.Controls.AddRange(MainControls);

// create new button array, for drawing the mine map


ButtonArray = new System.Windows.Forms.Button[iWidth,iHeight];

int x,y;
for (y=0 ; y<iHeight ; y++)
for (x=0 ; x<iWidth ; x++)
{
ButtonArray[x,y] = new System.Windows.Forms.Button();
ButtonArray[x,y].Location = new System.Drawing.Point(20 + x*16, 70 + y*16);
ButtonArray[x,y].Name = "";
ButtonArray[x,y].Size = new System.Drawing.Size(16,16);

iCellAddress = (0x1005340) + (32 * (y+1)) + (x+1);


memory = pReader.ReadProcessMemory((IntPtr)iCellAddress,1,out bytesReaded);
iIsMine = memory[0];

if (iIsMine == 0x8f)
ButtonArray[x,y].Image = ((System.Drawing.Bitmap)
(resources.GetObject("button1.Image")));

this.Controls.Add(ButtonArray[x,y]);
}

// close process handle


pReader.CloseHandle();
That's it. Hope you leaned something new.
Using GameHack 2.0 to hack Monopoly Tycoon

I- Table of contents:

I- Table of contents :)
II- Thanks
III- Needed Tools
IV- Basic about Game Hacking
V- Finding Address with GameHack (GH)

II- Greetz goes to....

MiCRaL
Shaikh Adeel
Tsongkie
Vivien Abner
MacDeath ťť Thanks for fixing errors with my english...

III- Needed Tools:

First of all, you'll need a brain :)


Little knowledge about Memory Finder
Little GameHacking knowledge
GameHack 2.0 (I'll call it "GH") - This tool is fast, but is shareware.

IV- Basic about GameHacking:

Before you make a trainer, you'll need:


1- Your Brain - It's very important
2- Patience - It's important too.
3- Tools
4- Address of value.
5- Knowledge in any language or you can use TMK.

V- Finding Address with GameHack (GH)

Start Monopoly Tycoon and select a new game. Look for the money value, ALT+TAB and start GameHack 2.0.
Click the first icon to select Monopoly Tycoon.

In the process list double click in Monopoly Tycoon to select it:

Then start a new search:

Do an "Exact Value" search, "Float" type, for the value.


Return to Monopoly Tycoon (ALT+TAB) and build any item.
Return to GameHack (ALT+TAB) and continue the search.

"Exact value" and your new value:

The same for the value 3, 4, etc. You'll need to test all address, because only one is the real address. This game
use DMA.
Get others tutorials about it.

ťť Tutorial by [D.N.A] ŤŤ
tekz (c) 2002
do not use without permission our plz

contact : dna.netz@ig.com.br
Using Game Trainer to hack Monopoly Tyccon

I- Table of contents:

I- Table of contents :)
II- Thanks
III- Needed Tools
IV- Basic about Game Hacking
V- Finding Address with GameTrainer (GT)

II- Greetz goes to....

MiCRaL
Shaikh Adeel
Tsongkie
Vivien Abner
MacDeath ťť Thanks for fixing errors with my english...

III- Needed Tools:

First of all, you'll need a brain :)


Little knowledge about Memory Finder
Little GameHacking knowledge
GameTrainer 2.01 (I'll call it "GT") - This tool is fast and free. I like it.

IV- Basic about GameHacking:

Before you make a trainer, you'll need:


1- Your Brain - It's very important
2- Patience - It's important too.
3- Tools
4- Address of value.
5- Knowledge in any language or you can use TMK.

V- Finding Address with GameTrainer (GT)

Run game Monopoly Tycoon first, and then open up the GameTrainer program.
Look for a Process combo box, and select "mc.exe" from the list. Look at the image below.

Now, we're going to hack the money value in Monopoly Tycoon


Look for the value in game and type "the value" (without quotes) into the value edit box in GameTrainer, select
BYTE from the Type list,
and then click Find.
P.S.: If the value is 31430.23, don't use 23. Type 31430 only!

Wait a few seconds. Then you will hear a small beep and GameTrainer will report that several thousand addresses
were found. This is
way too much! I have found 47 addresses.
Now, go back to the game and build any item. Look for the new value and back to the GT. Type the new value
and click Sieve.

Wait a bit and you should find only 4 addresses now. That is the address you need! Double click on the address to
add it to the Target
List. Now you have control over this address. You can double click on the Value field to change its value. Try it!
You need to test all
addresses, because only one is the "real address". This game uses DMA. Get others tutorial about it"

ťť Tutorial by [D.N.A] ŤŤ
tekz (c) 2002
do not use without permission our plz

contact : dna.netz@ig.com.br
Using TSearch 1.4a to hack Monopoly Tycoon
I- Table of contents:

I- Table of contents :)
II- Thanks
III- Needed Tools
IV- Basic about Game Hacking
VII- Finding Address with TSearch (TS1.4a)

II- Greetz goes to....

MiCRaL
Shaikh Adeel
Tsongkie
Vivien Abner
MacDeath ťť Thanks for fixing errors with my english...

III- Needed Tools:

First of all, you'll need a brain :)


Little knowledge about Memory Finder
Little GameHacking knowledge
TSearch 1.4a (I'll call it TS1.4a) - This tool is fast and free....I like it.

IV- Basic about GameHacking:

Before you make a trainer, you'll need:

1- Your Brain - It's very important


2- Patience - It's important too.
3- Tools
4- Address of value.
5- Knowledge in any language or you can use TMK.

V- Finding Address with TSearch (TS1.4a)

Start Monopoly Tycoon and select a new game... Look for the money value, ALT+TAB and start TSearch 1.4a
You have two options to select Monopoly Tycoon:

First option

f
Click the first icon to select Monopoly Tycoon.

Click "Open Process" and you'll see the "Select process"


screen. In "Select process", you need select MC.exe
(Monopoly Tycoon icon)

Second option

Click the "Second" icon to select Monopoly Tycoon.

Its faster for you to use the "Select process list" little screen.
Now, you need select MC.exe (exe of Monopoly Tycoon)
Then start a new search:

Do a "Exact Value" search, "Float" type, for your value.

Return to Monopoly Tycoon (ALT+TAB) and build any item.


Return to TSearch (ALT+TAB) and continue the search.

"Exact value" and your new value:


The same for the value 3, 4, etc. You'll need to test all addresses, because only one is the real
address. This game uses DMA.
Get others tutorials about it.

ť Tutorial by [D.N.A] ŤŤ
tekz (c) 2002
do not use without permission our plz

contact : dna.netz@ig.com.br
In-Game Menu:
-------------
Written by Omega

Game:
-----
Mortal Combat 4 *Rip* (12-13meg on kazaa)

Explanation:
------------
In-Game menu's are good for if you have a game with alt-tab protection
or if you have alot of hotkeys, and lazy users.

What you need to do is:


1. Find a gameloop (command thats called all the time) "GetMessage, GetTickCount"
2. Find a code cave.
3. overwrite the api that loops wiv a gateway to your code.
4. poke your code into the codecave.
5. jump back to orginal location (code after the api call)

This method is the NONE SICE Method :)

So lets get started:

as i stated above GetMessage And GetTickCount are 2 of a few API calls that are a
and this game, uses GetMessage, so i'm just gonna get straight to it.

Open up W32Dasm and load up the EXE.


Click Imported Functions

Then scroll down to "USER32.GetMessageA" and double click it

it should go to the address 0x4C52D8

* Reference to: USER32.GetMessageA, 0rd:0115h

:004C52D8 FF15C8214d00 Call dword ptr [004d21c8]


:004C52D8 85C0 Test eax,eax
:004C52E0 7505 jne 004C52E7
:004C52E2 E889F5FFFF call 004c4870

We need to replace line 004C52D8 with our jump to our codecave. i'll do that in a
for now.

Now we need to sort out the code for MessageBox

A MessageBox is called like:

push Style
push Caption
push Text
push WindowHandle
call MessageBoxA

We need to call the MessageBox


So go back to W32Dasm Click "Imported Functions" Again
Then find "USER32.MessageBoxA" double click it.
it should go to the address 0x4C493E

* Reference To: USER32.MessageBoxA, 0rd:0195h

:004C493E FF1514224d00 Call dword ptr [004D2214]

So Call MessageBoxA Becomes Call 004D2214

So we need to put that into the game as well as the GetMessage we replaced.

I chose:
"0x4D1b90" For The Caption
"0x4D1b9f" For The Text
"0x4D1c1f" For The Injected Code.

push 0
push 4D1b90
push 4D1b9f
push 0

// MessageBoxA
call [4D2214]

// GetMessageA
call [4d21c8]
jmp 004C52D8

But because were pushing 0 as the WindowHandle then this won't work.
and the messagebox will be displayed outside of the game, and could crash the gam
we need to find a way of getting the games window handle.

Thankfully the game stores the WindowHandle in memory when it window is created (
So go back to W32Dasm Click "Imported Functions" Again
Then find "USER32.CreateWindowExA" double click it.

it should go to the address 0x4c5189

* Reference To: USER32.CreateWindowExA, 0rd:0055h

:004C5189 FF15E8214D00 Call dword ptr [004D21E8]


:004C518F 85C0 test eax, eax
:004C5191 A3C0F7F900 mov dword ptr [00F9F7C0], eax
:004C5196 7512 jne 004C51AA

As you should see at 004C5191 it puts the WindowHandle into 0xF9F7C0

So now we have to push that value.

So we need to add:

mov eax, [00F9F7C0]


push eax
to our code.

push 0
push 4D1b90
push 4D1b9f
mov eax, [00F9F7C0]
push eax
// MessageBoxA
call [4D2214]
// GetMessageA
call [4d21c8]
jmp 004C52D8

so now it should look like that..

Now we need to write it into EasyWrite in TSearch:

Including The Text And Caption Of MessageBox.

Key:
====
ASC = Write Text
Hex = Write Hex
Hex 0a = New Line
Hex 0a0a = 2 New lines
Hex 00 = End Of Message

Top Window:
===========

offset 0x4D1b90
asc "Title"

offset 0x4D1b9f
asc "InGame Menu"
hex 0a
asc "========="
hex 0a
asc "Created by Omega"
hex 00

offset 0x4D1c1f
push 0
push 4D1b90
push 4D1b9f
mov eax, [00F9F7C0]
push eax
//MessageBoxA
call [4D2214]
//GetMessageA
call [4D21C8]
jmp 4c52de

// Code To Replace API GetMessage NOP To Even code out.


offset 4c52d8
jmp 0x4D1c1f
nop

Bottom Window:
==============
offset 0x4c52d8
call [0x4D21C8]
We don't need to remove our injected code as it won't be called.

Now all you need to do it make it poke all the bytes, then wait a few seconds the

Because we replaced GetMessage, and it gets called near enough all the time the g

I found the code cave, by Using TSearch's Hex Editor, and searching fora lot of
you'll come to alot of places, but eventually you'll find a cave, just load into

If the game crashes then it isn't if it works, then whey hey :)


theres different ways but i can't be bothered to explain it all right now.

This is just oneway of injecting stuff you can inject dll's, trainers, etc etc.

"With code injection the sky is the limit."

Thanks:
Orr: For his amazing tutorial helping me to write this one.
Quake2 wallhack tutorial - cppdude

This fairly advanced tutorial is going to teach you how to make a wallhack for Qu

Ok lets go. Look in you Quake2 dir. Youll find a ref_gl.dll dll file. This file i

Our wallhack will have 2 modes. The first will be a wireframe mode, where we will

DrawMode(Lines)
Drawworld()
DrawMode(Fill)
return //to game code

Pretty easy that. DrawMode will force all drawwing after that call to be done wit

Ok now you understand the theory of our first wallhack mode, lets put it into pra

You will find a string ref to r_drawworld:

* Possible StringData Ref from Data Obj ->"r_drawworld"


|
:1000914F 68BCE40210 push 1002E4BC

The address of the string ref is being pushed as a parameter to a function. What

r_drawworld 0

The function then returns a pointer to a variable. Functions return values by sav

mov dword ptr [10056908], eax

So now at location 10056908, we have a pointer to the r_drawworld variable. We no

* Referenced by a CALL at Address:


|:10008EC6
|
:1000C080 A108690510 mov eax, dword ptr [10056908]
:1000C085 83EC48 sub esp, 00000048
:1000C088 D94014 fld dword ptr [eax+14]
:1000C08B D81D74730210 fcomp dword ptr [10027374]
:1000C091 DFE0 fstsw ax
:1000C093 F6C440 test ah, 40
:1000C096 0F8543010000 jne 1000C1DF
:1000C09C F6050467051002 test byte ptr [10056704], 02
:1000C0A3 0F8536010000 jne 1000C1DF
...

Great. Youve now found the function that draws the world. You can see that the po

:10008EB2 E889F9FFFF call 10008840


:10008EB7 E874F8FFFF call 10008730
:10008EBC E80FFCFFFF call 10008AD0
:10008EC1 E82A330000 call 1000C1F0
:10008EC6 E8B5310000 call 1000C080 //call to drawworld
:10008ECB E8A0F2FFFF call 10008170
:10008ED0 E83BAFFFFF call 10003E10
:10008ED5 E8D6F5FFFF call 100084B0
:10008EDA E811250000 call 1000B3F0
:10008EDF E82CFFFFFF call 10008E10

We have now found out where the drawworld function is called. Hooray! We can now

This is where we start using TSearch; to make asm scripts. Read the TSearch help

offset 1002644B ;define the start of our code section

We now need to make a call to the DrawMode function. The OpenGL api we will use f

glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

So now we need to make a call to the function glPolygonMode, and we need to find

* Possible StringData Ref from Data Obj ->"glPolygonMode"


|
:10011108 6830000310 push 10030030
:1001110D 50 push eax
:1001110E FFD6 call esi ;call GetProcAddress
:10011110 8B0DD4600510 mov ecx, dword ptr [100560D4]

* Possible StringData Ref from Data Obj ->"glPolygonOffset"


|
:10011116 6820000310 push 10030020
:1001111B 51 push ecx
:1001111C A334510510 mov dword ptr [10055134], eax ;glPolygonMode a
:10011121 A3C45C0510 mov dword ptr [10055CC4], eax
...

Here the address of the string ref "glPolygonMode" is being pushed as a function

The address is saved in two places. Do a search for one of these addresses and yo

call dword ptr [10055CC4]

You now know how to call glPolygonMode. Soon you can add it to your TSearch asm s

//define the start of our code section


offset 1002644B
//push GL_LINE
push 1B01

Now we need to push GL_FRONT_AND_BACK which is defined as 0x0408. Then you call g

//define the start of our code section


offset 1002644B
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]

Now that all following polygons are drawn in line mode, we can call drawworld. We

//define the start of our code section


offset 1002644B
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]
//call drawworld
call 1000C080
//push GL_FILL
push 1B02
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]
//return to game code
ret

Great. We now have our code section defined. We now need to make a call to it, by

//define the start of our code section


offset 1002644B
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]
//call drawworld
call 1000C080
//push GL_FILL
push 1B02
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]
//return to game code
ret

//make call to our code


offset 10008EC6
//by replacing existing call to drawworld function
call 1002644b

Save this script and run it on quake2.

Disaster!!! Quake2 now looks a mess. Every frame that Quake2 draws is being drawn

glClear(GL_COLOR_BUFFER_BIT);

but Quake2 already has a cvar to do this so i would rather hack that. The Quake2

* Referenced by a (U)nconditional or (C)onditional Jump at Address:


|:10008D43(C)
|
:10008DA6 8B1574620510 mov edx, dword ptr [10056274]
:10008DAC D94214 fld dword ptr [edx+14]
:10008DAF D81DD0720210 fcomp dword ptr [100272D0]
:10008DB5 DFE0 fstsw ax
:10008DB7 F6C440 test ah, 40
:10008DBA 7507 jne 10008DC3
:10008DBC 6800410000 push 00004100
:10008DC1 EB05 jmp 10008DC8

* Referenced by a (U)nconditional or (C)onditional Jump at Address:


|:10008DBA(C)
|
:10008DC3 6800010000 push 00000100

You can see that 0x4100 is being pushed. If this is used as the paramater to glCl

So now your TSearch asm script will now look like this:

//define the start of our code section


offset 1002644B
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]
//call drawworld
call 1000C080
//push GL_FILL
push 1B02
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [10055CC4]
//return to game code
ret

//make call to our code


offset 10008EC6
//by replacing existing call to drawworld function
call 1002644b

//nop jne to make sure GL_COLOR_BUFFER_BIT is also passed to glClear


offset 10008DBA
hex 9090

If you run this you will have a fully working wallhack for Quake2. If you want to

You are probably thinking: how can i remove that gay pink as the clear color? Joh

glClearColor(0.0f, 0.5f, 0.75f, 1.0f);

for a nice calm blue. The first 3 params are RGB, and the 4th is an alpha value w

I cant be bothered to explain exactly how i do the second wallhack mode, because

glDisable(GL_DEPTH_TEST);
drawentities();
glEnable(GL_DEPTH_TEST);
return;

GL_DEPTH_TEST is defined as 0x0B71. One other thing you should know, you must dra
:10008EB2 E889F9FFFF call 10008840
:10008EB7 E874F8FFFF call 10008730
:10008EBC E80FFCFFFF call 10008AD0
:10008EC1 E82A330000 call 1000C1F0
:10008EC6 E8B5310000 call 1000C080//drawworld
:10008ECB E8A0F2FFFF call 10008170//drawentities
:10008ED0 E83BAFFFFF call 10003E10
:10008ED5 E8D6F5FFFF call 100084B0
:10008EDA E811250000 call 1000B3F0
:10008EDF E82CFFFFFF call 10008E10

Drawentities is also called there. When i made my depth test hack I made that dra

That sums up my Quake2 wallhack tutorial. The methods here can be applied to any

You may be wondering why i made this tutorial using Quake2 instead of Quake3. Wel

Also, i like to get the bytes generated by TSearch and put them into a C++ progra

Have fun and go rage some servers =)


cppdude
Quake 3 wallhack tutorial by ^chaos^
####### VERSION 0.9 @@2@@@
most of this tutorial is a plagiarized version of cppdude's quake 2 tutorial
forgive me in advance cppdude.

This fairly advanced tutorial is going to teach you how to make a wallhack for Qu

Ok lets go. Look in you Quake3 dir. Youll find a quake3.exe file. Unlike quake 3,

Our wallhack will have 2 modes. The first will be a wireframe mode, where we will

DrawMode(Lines)
Drawworld()
DrawMode(Fill)
return //to game code

Pretty easy that. DrawMode will force all drawwing after that call to be done wit

Ok now you understand the theory of our first wallhack mode, lets put it into pra

* Possible StringData Ref from Data Obj ->"r_drawworld"

:449b19 push 4c339c ;pushes the text "r_drawworld"


:449b1e mov dword ptr [007cb250], eax ;[7cb250] = 6993280 dec = 006AB580 hex. [
;which seems to be the CVAR before r_drawworld
:449b23 call dword ptr [007be364] ;[007be364] = 4312496 dec = 0041CDB0 hex
:449b29 push 00000000 ;pushes 0
* Possible StringData Ref from Data Obj ->"0"
:449b2b push 4b55bc ;pushes the text "0"
:449b30 mov dword ptr [007cb340], eax ;[7cb340] = 6993320 dec = [006AB5A8] hex=

The address of the string ref is being pushed as a parameter to a function. What

r_drawworld 0

The function then returns a pointer to a variable. Functions return values by sav

mov dword ptr [007cb340], eax

So now at location 007cb340, we have a pointer to the r_drawworld variable. We no

* Referenced by a CALL at Addresses:


|:0044BFAE , :0044C760 , :0044C90E
|
:00466D90 51 push ecx
:00466D91 A140B37C00 mov eax, dword ptr [007CB340] <----
:00466D96 8B4820 mov ecx, dword ptr [eax+20]
:00466D99 53 push ebx
:00466D9A 33DB xor ebx, ebx
:00466D9C 3BCB cmp ecx, ebx
:00466D9E 0F8470020000 je 00467014
:00466DA4 F6058CEB7B0001 test byte ptr [007BEB8C], 01
:00466DAB 0F8563020000 jne 00467014
:00466DB1 8B0D44B37C00 mov ecx, dword ptr [007CB344]
:00466DB7 55 push ebp
:00466DB8 C705C0E87B00FE030000 mov dword ptr [007BE8C0], 000003FE
:00466DC2 C705C4E87B0000E03F00 mov dword ptr [007BE8C4], 003FE000
:00466DCC 395920 cmp dword ptr [ecx+20], ebx
:00466DCF 56 push esi
:00466DD0 57 push edi
:00466DD1 0F85F3010000 jne 00466FCA
:00466DD7 8B35C0E37B00 mov esi, dword ptr [007BE3C0]
:00466DDD 3BF3 cmp esi, ebx
:00466DDF 7516 jne 00466DF7
...

Great. You've now found the function that draws the world. All three of them this

:0044BFA4 E8A7F0FFFF call 0044B050


:0044BFA9 E832F4FFFF call 0044B3E0
:0044BFAE E8DDAD0100 call 00466D90 <-- //call to drawworld
:0044BFB3 E8F8590100 call 004619B0
:0044BFB8 E833F2FFFF call 0044B1F0
:0044BFBD E84E050000 call 0044C510

...

:0044C760 E82BA60100 call 00466D90 <-- //call to drawworld


:0044C765 E846520100 call 004619B0
:0044C76A E881EAFFFF call 0044B1F0
:0044C76F E99CFDFFFF jmp 0044C510

...

:0044C904 E847E7FFFF call 0044B050


:0044C909 E8D2EAFFFF call 0044B3E0
:0044C90E E87DA40100 call 00466D90 <-- //call to drawworld
:0044C913 E898500100 call 004619B0 //i draw shadows at the feet
:0044C918 E8D3E8FFFF call 0044B1F0
:0044C91D E8EEFBFFFF call 0044C510

We have now found out where the drawworld function is called. Hooray! We can now

This is where we start using TSearch; to make asm scripts. Read the TSearch help

offset 400000 ; define the start of our code section

We now need to make a call to the DrawMode function. The OpenGL api we will use f

glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

So now we need to make a call to the function glPolygonMode, and we need to find

* Possible StringData Ref from Data Obj ->"glPolygonMode"


|
:0044E563 6828464C00 push 004C4628 ;text gets pu
:0044E568 52 push edx
:0044E569 A3F0A65C00 mov dword ptr [005CA6F0], eax
:0044E56E A3ECE07B00 mov dword ptr [007BE0EC], eax
:0044E573 FFD6 call esi
:0044E575 A394A75C00 mov dword ptr [005CA794], eax
:0044E57A A388DF7B00 mov dword ptr [007BDF88], eax ;[007bdf88] =
;in Opengl32.dll
:0044E57F A1ECD77B00 mov eax, dword ptr [007BD7EC]

Here the address of the string ref "glPolygonMode" is being pushed as a function
The address is saved in a couple places. Do a search for one of these addresses a

call dword ptr [007BDF88]

You now know how to call glPolygonMode. Soon you can add it to your TSearch asm s

//define the start of our code section


offset 400000
//push GL_LINE
push 1B01

Now we need to push GL_FRONT_AND_BACK which is defined as 0x0408. Then you call g

//define the start of our code section


offset 400000
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [007BDF88]

Now that all following polygons are drawn in line mode, we can call drawworld. We

//define the start of our code section


offset 4000000
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [007BDF88]
//call drawworld
call 466d90

//return to game code


ret

Great. We now have our code section defined. We now need to make a call to it, by

0044bfae - seems to control REFLECTIONS? like mirrors and such


0044c760 - don't know. I couldn't tell what this did.
0044c90e - draws the main world

So we add a call to our code section in our asm script so that it now looks like

//define the start of our code section


offset 400000
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [007BDF88]
//call drawworld
call 466d90
//return to game code
ret

//make call to our code


offset 0044C90E
//by replacing existing call to drawworld function
call 400000

Save this script and run it on quake3.

Disaster!!! Quake2 now looks a mess. Every frame that Quake2 draws is being drawn

glClear(GL_COLOR_BUFFER_BIT);

but Quake3 already has a cvar to do this so i would rather hack that. The Quake3

* Possible StringData Ref from Data Obj ->"r_clear"


|
:00449D78 6878324C00 push 004C3278 ;pushe
:00449D7D A368A17C00 mov dword ptr [007CA168], eax
:00449D82 FF1564E37B00 call dword ptr [007BE364]
:00449D88 6800020000 push 00000200

* Possible StringData Ref from Data Obj ->"-1"


|
:00449D8D 68F4164C00 push 004C16F4

* Possible StringData Ref from Data Obj ->"r_offsetfactor"


|
:00449D92 6868324C00 push 004C3268
:00449D97 A398A17C00 mov dword ptr [007CA198], eax ;[007C
:00449D9C FF1564E37B00 call dword ptr [007BE364]
:00449DA2 6800020000 push 00000200

...

Search for where that pointer (007CA198) is being referenced like you did before
:0045A1C9 FF15A4E17B00 call dword ptr [007BE1A4] ;[007BE1A4
:0045A1CF 8B0D98A17C00 mov ecx, dword ptr [007CA198] ;[007CA198
:0045A1D5 8B4120 mov eax, dword ptr [ecx+20]
:0045A1D8 85C0 test eax, eax
:0045A1DA 7422 je 0045A1FE
:0045A1DC 680000803F push 3F800000 ;float val
:0045A1E1 680000003F push 3F000000 ;float val
:0045A1E6 6A00 push 00000000 ;float val
:0045A1E8 680000803F push 3F800000 ;float val
:0045A1ED FF1500E27B00 call dword ptr [007BE200] ;[007BE200
:0045A1F3 6800410000 push 00004100
:0045A1F8 FF15CCE07B00 call dword ptr [007BE0CC] ;[007BE0CC

...

:0045A715 FF15A4E17B00 call dword ptr [007BE1A4]


:0045A71B 8B1598A17C00 mov edx, dword ptr [007CA198]
:0045A721 8B4220 mov eax, dword ptr [edx+20]
:0045A724 85C0 test eax, eax
:0045A726 7422 je 0045A74A
:0045A728 680000803F push 3F800000
:0045A72D 680000003F push 3F000000
:0045A732 6A00 push 00000000
:0045A734 680000803F push 3F800000
:0045A739 FF1500E27B00 call dword ptr [007BE200]
:0045A73F 6800410000 push 00004100
:0045A744 FF15CCE07B00 call dword ptr [007BE0CC]

...

:0045A8A5 FF15A4E17B00 call dword ptr [007BE1A4]


:0045A8AB 8B1598A17C00 mov edx, dword ptr [007CA198]
:0045A8B1 396A20 cmp dword ptr [edx+20], ebp
:0045A8B4 7421 je 0045A8D7
:0045A8B6 680000803F push 3F800000
:0045A8BB 680000003F push 3F000000
:0045A8C0 55 push ebp
:0045A8C1 680000803F push 3F800000
:0045A8C6 FF1500E27B00 call dword ptr [007BE200]
:0045A8CC 6800410000 push 00004100
:0045A8D1 FF15CCE07B00 call dword ptr [007BE0CC]

You can see that 0x4100 is being pushed. If this is used as the paramater to glCl

//define the start of our code section


offset 400000
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [007BDF88]
//call drawworld
call 466d90
//return to game code
ret

//make call to our code


offset 0044C90E
//by replacing existing call to drawworld function
call 400000

//nop 3 x jne to make sure GL_COLOR_BUFFER_BIT is also passed to glClear

offset 0045A1DA
//je 0045A1FE
hex 9090

offset 0045A726
//je 0045A74A
hex 9090

offset 0045A8B4
//je 0045A8D7
hex 9090

If you run this you will have a fully working wallhack for Quake3. If you want to

You are probably thinking: how can i remove that gay pink as the clear color? Joh
glClearColor(0.0f, 0.5f, 0.75f, 1.0f);

If you noticed earlier at offset :0045A1ED :0045A739 :0045A8C6 these are all call

add this to the bottom of your script.

offset 45a728
hex 9090909090
hex 9090909090
hex 9090
hex 9090909090
hex 909090909090

offset 45a1dc
hex 9090909090
hex 9090909090
hex 9090
hex 9090909090
hex 909090909090

offset 45a8b6
hex 9090909090
hex 9090909090
hex 90
hex 9090909090
hex 909090909090

for a nice gray. The first 3 params are RGB, and the 4th is an alpha value which

Your script so far:

//define the start of our code section


offset 400000
//push GL_LINE
push 1B01
//push GL_FRONT_AND_BACK
push 408
//call glPolygonMode
call dword ptr [007BDF88]

push 3f800000
push 3F000000
push 3F000000
push 3F000000
//call glClearColor values are set to light gray
call dword ptr [007BE200]

//call drawworld
call 466d90

//return to game code


ret

//make call to our code


offset 0044C90E
//by replacing existing call to drawworld function
call 400000

//nop 3 x jne to make sure GL_COLOR_BUFFER_BIT is also passed to glClear

offset 0045A1DA
//je 0045A1FE
hex 9090

offset 0045A726
//je 0045A74A
hex 9090

offset 0045A8B4
//je 0045A8D7
hex 9090

// gets rid of calls to glClearColor


offset 45a728
hex 9090909090
hex 9090909090
hex 9090
hex 9090909090
hex 909090909090

offset 45a1dc
hex 9090909090
hex 9090909090
hex 9090
hex 9090909090
hex 909090909090

offset 45a8b6
hex 9090909090
hex 9090909090
hex 90
hex 9090909090
hex 909090909090

That sums up my Quake3 wallhack tutorial. The methods here can be applied to any

special thanks to cppdude for writting his original tutorial...


so that i could plagiarize it =)
^chaos^
Yo sup,i was bored and thou i would write a tutorial on how to find unlimited gue
I call it " RCT " !

Start RCT.

Choose a game u want to make ur park in.

Now you should be in ur park "DO NOT BUILD ANYTHING!" and have " 0 " guests right

Open Tsearch ( or the gamehacking tool you use ) !

Make A Exaxt Value Search For " 0 "

now you should get one heck of codes..

Get back in the game,Open your park so guest can visite it,let some guests in 3 e

Get back to Tsearch search for 3 ( or the value of guest u let come in to the par

Now you should have ONE address if you have done this right.

Double click on it,then on the window the the right you should see it,double clic

You have now Found RCT Guests Cheat..

Written By X-Undead

I'll make a .html format of it next time with Pictures and more text,was just to

Later/
UnDeaD
X² Tutorials

Sim City 3000 Unlimited Tutorial

Requirements: Sim City 3000 Unlimited, Memory Editor (Gamehack


2.0), Softice (Softice 3.22), Cracked sc3U.exe
(www.gamecopyworld.com). If you own the original game, get
Frogsice to bypass the Softice protection in the game.

This tutorial assumes you have softice installed and a basic knowledge
of it.

1. Run the game with the fixed executable SC3U_crk.exe

2. Click "Start new city".

3. Select game options.

4. How much money do you have, I started with $50,000

5. Alt-tab to windows.

6. Open Gamehack 2.0 and click "Select process for hacking"

7. Click "SimCity 3000" and click ok.

8. Click the binoculars to begin a new search.

9. Choose Search: "Exact value", Value 1: 50000 , Type: 4 Bytes and


click ok.

10. My search returned 9 values.

11. Return to the game and spend some money, I chose landscape
and plant trees. (note the amount of money you have after spending)

12. Alt-tab to windows.


13. Click the binoculars with the arrow under it for next search.

14. Enter Value 1: 49997 and click ok.

15. I have two values left, both 49997.

16. Double click both values to put it in the edit area.

17. Double click the top value and change it to 60000.

18. Double click the bottom value and change to 30000.

19. Write down both values for reference.

20. Go into the game and spend some more money noting how much
you have left after spending. (I chose trees again)

21. Alt-tab to windows.

22. Go into gamehack and see which value matches your money.
(mine is 59997)

23. That means that the top value is the real one so click the bottom
value (click on description) and delete it.

24. Now write down the real value. (mine was 02ABB6D4 but yours
will be different, it changes each time you play the game, this is known
as dynamic memory)

25. Go back into the game.

26. <ctrl-d> to pop into softice. (also type "code on" to enable code)

27. Type "bpm 02abb6d4 w" and hit enter, this sets a breakpoint on
your address and it will break upon any write.

28. <ctrl-d> to leave softice.

29. Spend some money. (I chose trees)

0132895A 57 PUSH EDI

0132895B 33FF XOR EDI, EDI


0132895D 2B4508 SUB EAX, [EBP+08]

01328960 1BD7 SBB EDX, EDI

01328962 5F POP EDI

01328963 783C JS 013289A1

01328965 7F04 JG 0132896B

01328967 3BC6 CMP EAX, ESI

01328969 7236 JB 013289A1

0132896B 894138 MOV [ECX+38], EAX

==> 0132896E 89513C MOV [ECX+3C], EDX


DS:02ABB6D8=0000000

30. Softice pops up and highlights the purple address.

31. Since the game is subtracting money we look for a "SUB" above
the code softice landed on.

0132895A 57 PUSH EDI

0132895B 33FF XOR EDI, EDI

===> 0132895D 2B4508 SUB EAX, [EBP+08]

01328960 1BD7 SBB EDX, EDI

01328962 5F POP EDI

01328963 783C JS 013289A1

01328965 7F04 JG 0132896B

01328967 3BC6 CMP EAX, ESI

01328969 7236 JB 013289A1

0132896B 894138 MOV [ECX+38], EAX


0132896E 89513C MOV [ECX+3C], EDX DS:02ABB6D8=0000000

32. The code in green is the "SUB" command we are looking for.

33. Double click the green code in softice, that sets a breakpoint at
that address. (if any problems, type in "bpx 0132895d")

34. Type "bl" and hit enter. (this lists all current breakpoints)

35. Type "bd 00". (this disables breakpoint 1)

36. <ctrl-d> to exit softice and spend some money.

37. Notice Softice pops up on the green address.

38. Type "a" and hit enter, type "nop" enter, "nop" enter, "nop"
enter and hit <ctrl-d> to exit softice. (if any problems you can
manually nop the address by typing "a 0132895d" and then the nops.)
(the reason you nop 3 times is this, the code is 2B4508 so you nop
once per 2 digits, 6 divided by 2 is 3)

39. <ctrl-d> to enter softice and type "bc *" to clear all breakpoints.

40. Note that you now have unlimited money.

41. Now you can create a trainer that nops address 0132895D 3 times,
or 90 90 90 which is nop in machine language.

42. Enjoy...

Written by Logician

Proud member of X²
TUT NO. 4
~~~~~~~~~~

OK. In the following, i'll teach (in case u don't know) how to hack Solitaire! Be
not that simple, and u can't do almost anything with a mem finder!

So, let's begin!

To hack Solitaire you need some experience! It isn't a hack that you go for trapp
when it dec the timer! It uses some Windows fuc*ing .dlls to do it's job (i t
it's useless to change the memory because the .dlls are changing\using it ins
game and if u do that ==> program crash (kernel or solitaire or your mem. fin
I tried with a mem finder, but found nothing! Maybe u will be more lucky !! ;}

BTW, it's code is on 16 bit... Fu*king Bullshit !!!!

To avoid this i recommend u another method (a cracking approach). Yes, this metho
more used when crack !

Go and grab W32Dasm if u haven't done it by now (u can use any other disassembler
is the best! ). Make a copy of Solitaire and disassemble-it !

But first i must tell u this : games like Solitaire uses the user32.dll's SetTime
(to manage the time-elapsing). So our task is to look in the Solitaire.exe fo
function. That's why u need a disassembler!

Now, in W32Dasm click on the Imported_function button, and double-click on USER.S


Dbl-click once more to be sure there's no other occurrence of this function!
isn't! Perfect!

Now above the SetTimer there are some pushes. Those are needed for the function t
properly. Check the SetTimer function's parameters below:

============cut from win32 programmer's reference=====================

The SetTimer function creates a timer with the specified time-out value.

UINT SetTimer(

HWND hWnd, // handle of window for timer messages


UINT nIDEvent, // timer identifier
UINT uElapse, // time-out value
TIMERPROC lpTimerFunc // address of timer procedure
);

Parameters

hWnd

Identifies the window to be associated with the timer. This window must be owned
calling thread. If this parameter is NULL, no window is associated with the t
the nIDEvent parameter is ignored.

nIDEvent

Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this paramet
ignored.
uElapse

Specifies the time-out value, in milliseconds.

lpTimerFunc

Points to the function to be notified when the time-out value elapses. For more i
about the function, see TimerProc.
If lpTimerFunc is NULL, the system posts a WM_TIMER message to the application qu
hwnd member of the message's MSG structure contains the value of the hWnd par

============================end cut===================================

But the pushes are being pushed backwards! So, first on the stack is pushed the l
then uElapse followed by nIDEvent and hWnd!

So at this point we know that we must get the "uElapse" value. The pushes are:

in solitaire: | in general:
|
push word ptr [01F0] | pTimerFunc
push 029A00FA | uElapse
push dx | nIDEvent
push word ptr [01F2] | hWnd

So, the "push 029A00FA" is the elapsing time! I don't know how the game processes
to make a delay of ~1sec. I modify this number typing some random numbers (e.
029A0000 instead of 029A00FA) and the time flew very fast!

So, to make the timer run very slow, u need to change the "push 029A00FA" to "pus
How to do that? SIMPLE!

Grab any hex-editor, go to the push's offset, and modify the beast! (u can wiew t
offset in W32Dasm, by putting the gray line over the "push 029A00FA", and loo
bottom of W32Dasm's window. There should be 950 in the Sol.exe that i include
.zip)

Now, that we are done with this, let's make a full "hack", by trapping the code t
pts when undo\restart_poket. But u know how to do that ! No? WTF...

Grab a mem finder (GameTrainer) and search for the pts.


After u have only 1-2 addr, bpm in SI, SI popped, code found, hack completed!

Well, i think u understood something from this...

Sorin ( Splinter@email.ro ).
Tutorial: Starcraft Screen Messages
Author: Drakken
Date: 4/24/03
Site: http://www.GameThreat.com
Game: Starcraft/Broodwar version 1.10
_____________________________________

Intro:
In this tutorial I'm going to show you a way to send client side messages to the
_____________________________________

What you will need:


Softice - I highly reccomend you get softice. It is the BEST and most valuable to

Memory Searcher/Editor - I use Winhack. It's decent and easy to use but it is sha

W32Dasm - This is a disassembler. You can also use IDA which is more advanced but

You should be able to find these tools pretty easily on the net. Search on google

Some knowledge of assembly will really be helpful but not totally necessary. Hope

_____________________________________

Let's begin:
Start up starcraft and load a game. Do not start a single player campaign game be

First we want to find where starcraft stores the text that is displayed on screen

Open the text box and type "Drakken is my hero" and press enter. hehe ;). Now ope

Now go through and find all eleven offsets for the screen text. Write a different

When finished you should have found these eleven offsets:


650CA8
650D82
650E5C
650F36
651010
6510EA
6511C4
65129E
651378
651452
65152C

Now we've got all eleven offsets. (there's actually a couple more but don't worry

Why don't we just search for the timer value?


Because we have no idea what that value might be and since the messages only stay

Why do we want to find where it writes the null byte?


Because shortly before it writes the null byte starcraft will check the timer to

We will have to set a breakpoint in softice on one of the offsets to find where s

BPM 650CA8
Press enter to set the breakpoint. Then press ctrl-D to exit softice. Softice wil

Now let's look at the disassembly so we can see what's going on at 46B825. Open W

When it's done you can click disassembler and save the disassembly to a project f

Now click Goto, then Goto Code Location. In the code offset box enter the offset

ASM Code:
:0046B812 Call dword ptr [004E61A0]
:0046B818 mov edi, eax
:0046B81A xor esi, esi

:0046B81C lea eax, dword ptr [esi+2*esi]


:0046B81F lea eax, dword ptr [eax+8*eax]
:0046B822 lea eax, dword ptr [esi+4*eax]
:0046B825 mov cl, byte ptr [2*eax+00650CA8]
:0046B82C test cl, cl
:0046B82E je 0046B8D9
:0046B834 mov edx, dword ptr [4*esi+006517BC]
:0046B83B mov ecx, edi
:0046B83D sub ecx, edx
:0046B83F js 0046B8D9
:0046B845 cmp esi, 0000000C
:0046B848 mov byte ptr [2*eax+00650CA8], 00
:0046B850 jne 0046B86C

Comments:
:0046B812 calls GetTickCount (result ends up in eax)
:0046B818 moves the tick count from eax to edi for use below
:0046B81A clears esi

:0046B81C sets up eax for the pointer to the message offset


:0046B81F " "
:0046B822 " "
:0046B825 moves the first byte of the message offset into cl
:0046B82C tests cl against itself
:0046B82E if cl is null (00) it jumps to 46B8D9
:0046B834 moves the message timer value into edx
:0046B83B moves the current tick count from edi into ecx
:0046B83D subtracts the message timer from the current tick count
:0046B83F depending on the result it will jump to 46B8D9
:0046B845 compares esi to 0C
:0046B848 writes the null byte to the message offset
:0046B850 jumps to 46B86C if esi isn't 0C

You may still be confused by all that. I'll try to sum it up. First it calls GetT

Now we know that it's using GetTickCount to check the message timer. So we also k

Message - Timer
650CA8 - 6517BC
650D82 - 6517C0
650E5C - 6517C4
650F36 - 6517C8
651010 - 6517CC
6510EA - 6517D0
6511C4 - 6517D4
65129E - 6517D8
651378 - 6517DC
651452 - 6517E0
65152C - 6517E4

Now that you know the timers for each message offset you can write a timer value

6517BC 0F 0F 0F 0F
650CA8 44 72 61 6B 6B 65 6E 20 72 75 6C 65 73 21 00

Neat eh? But there are two problems. That message will stay on screen for a reall

To solve the timer problem, in your program make a call to GetTickCount. To deter

Now let's figure out how to tell which message offset is the bottom one. Look bac

:0046B825 mov cl, byte ptr [2*eax+00650CA8]


:0046B834 mov edx, dword ptr [4*esi+006517BC]
:0046B848 mov byte ptr [2*eax+00650CA8], 00

Now look down just below these offsets and you'll see another offset sticking out

:0046B852 mov edx, dword ptr [006517F4]

Hrm what could this be? Let's take a look. First notice that it's pointing to a d

Text spot pointer


6517F0

Spot Message Timer


01 - 650CA8 - 6517BC
02 - 650D82 - 6517C0
03 - 650E5C - 6517C4
04 - 650F36 - 6517C8
05 - 651010 - 6517CC
06 - 6510EA - 6517D0
07 - 6511C4 - 6517D4
08 - 65129E - 6517D8
09 - 651378 - 6517DC
0A - 651452 - 6517E0
00 - 65152C - 6517E4

Now we have all the info we need.

_____________________________________

Summary:
Now to put all this info to good use in your program. First you want to use ReadP

Update:
Use these hex bytes in your messages to add colors.
0x02 default White/dull blue
0x03 Yellow
0x04 Bright White
0x05 Grey
0x06 Red
0x07 Green

_____________________________________

Conclusion:
Remember that these are client side messages only. No one else will see them but

I'm sure some of you are going to want to go and make an ally detector program ri

I hope you learned something new from this tutorial. If not, at least you know ho

Feel free to post this tutorial on your own site as long as it remains unmodified
_____________________________________

Drakken
©GameThreat.com 2003
Hacking StarCraft with Cheatzzz...

Hi ppl....new one by me again....and this time with a tutorial on hacking


StarCraft v1.09...it's not BroodWar :)...it's for newbies in GH...

Needed Tools :
» StarCraft v1.09
» TSearch 1.6 (the new version)
» Music again, of course....I listen to Patience/November Rain (Guns 'n
Roses)
» Get them at TekZ 8193 (tekz8193.com)

Step 1 : Finding the address

1. Open StarCraft(SC) and TSearch (TS).

2. Open the SC process in TS. You can do this by using the Open Process
menu. Select StarCraft in "Select Process" window.

3. Start new game...I like Protoss :)...Pause the game and go to TS.

4. Search by "Unknown Value". When it stops go back to SC.

5. Unpause game (hehehe) and press [ENTER] to type the cheat: I use "modify
the phase variance" (its ability to build anything). Pause again and go TS.

6. Now use "Search next", select "Has changed" (Search), and "1 Byte"
(Type)

7. It comes up with a lot of them. Repeat the steps 5 and 6 again and again
....until u get 3 or 4 of them.

8. Write all values on a sheet of paper....change the all values to "0"...go to SC


and enable the cheat again....back TS and type the values see if it's the same
value.

9. Go back to SC and disable all cheats. Go to TS and test all values, and then
go back to game and see if it works....:)

P.S.: A lot of games use diferent addresses to "write a cheat", but SC uses one
address for cheats....example: my address for the cheat is "52568D" (1Byte).
When this cheat (only the modify the phase variance cheat) is enabled, my
value is 32. When I use the "war aint what it used to be" (Disables Fog of
War. Only this cheat is on), my value is 63....but when I enable the 2 cheats,
my value is: 96....

Cya guys...
* Thx to JoeIsMy Name *
* and MacDeath *

Tutorial by [D.N.A]
The East KidZ © 2002
Contact: dna.netz@ig.com.br or dna@tsongkie.com
web: www.vngamecenter.com
Tutorial: Making a Starcraft Name Spoofer
Author: Dragon484
Date: 9/0/03
Site: http://www.GameThreat.com
Game: Startcraft/Broodwar
(This tutorial was modeled around drakkens
Startcraft screen messages tutorial)
___________________________________________

Intro:
Making a Name Spoofer for starcraft is
acutally very simple, if your having
trouble getting started then use this
tutorial and learn something.
___________________________________________

Tools:
A Memory editor, i use tsearch.
Starcraft Broodwar, updated to version 1.10
___________________________________________

Making a Name Spoofer:


Alright load up starcraft broodwar
and connect to bnet. Remember your acct name,
to make this tutorial easy please type your
name "youracctname". Once you have entered your
name in the quotes. Click edit->replace
Find What: "youracctname"
Replace With: yourname!.
Click Replace All.
Example for you slow people :)
Findwhat: "youracctname"
Replace with: Dragon484
Now that the hard part is over lets move on
to the easy stuff. Ok log onto bnet.
Load up your memory editor and select the
starcraft bw process.(In tsearch, click open
process then select starcraft.exe) Now you
need to search for your account name.
Click hex Editor(Third Button from the left.)
A window should of poped up that says HView.
We want to find text, so click the first
search button, its a magnifying glass.
If you dont have tsearch then there should
be an Ascii search of some sort. Type in
"youracctname" and click search. There will be
several different "youracctname". Now we are
ready to find the name spoofer offset. What
I did when i was first attempting to make
a name spoofer is Replace each of the names
with a number. And log the offsets
Example:
1ragon484 - B0700B4
2ragon484 - 19033310
3ragon484 - 190335A8
and so on..
When you enter the game, notice the number
mine happened to be 2ragon484. So I know
that the 19033310 is the offset for spoofing.
Now we need to check to make sure the offset
is static(does not change from game to game).
Enter a game say something, and leave, check
the offset, you will notice that your name
has been restored back to "youracctname". If
you wanted to test this offset further you
would restart bw, but it is in deed static.
(If you come apawn an offset that is not static
read the tutorial on dynamic to static under
the download section at www.gamethreat.com)
Anyway that is how to create a basic name
spoofer.

___________________________________________

Colors:
Adding colors is always fun but it gives
your self and others a temp ban from bnet.
Anyway adding colors is very easy once you
have found the spoofer offset. All you need
to do is changethe first byte of your name
to a color code.
Example:
Memory Ascii
44 72 61 67 6F 6E 34 38 34 Dragon484
*Now Change the first byte to a color code"
03 44 72 61 67 6F 6E 34 38 34 .Dragon484
___________________________________________

List of Colors Provided by Drakken:


0x02 default White/dull blue
0x03 Yellow
0x04 Bright White
0x05 Grey
0x06 Red
0x07 Green
___________________________________________

The Tricky Part:


Preventing temp bans and or a disconnect on
your record. Now this is not as easy as
making the spoofer. The concept here is to
change your name back after you have entered
the pregame lobby or after the game has
started. Im not going to go into detail
in this tutorial but i might at a later
time if people request help. Anyway you need
to set your name back, make sure you get them
ALL set back, setting back the spoofed offset
wont do it, good luck :D.
___________________________________________

Other Sc Tutorials:
Softice for beginngers - Drakken
Single player mineral hack tutorial - lordlardo
**code injection - Dma to static Address - drakken
Starcraft Screen Messages - Drakken
(www.gamethreat.com-> fourms->downloads->tutorials)
___________________________________________

Please Use this tutorial to the fullest and


leave it unmodded if your going to post this
tutorial. Any questions/suggestions please
goto www.gamethreat.com, enter the fourms
and either pm me or post a topic and state your
question/suggestion.

-Dragon484
(This Tutorial was orginally posted @ www.gamethreat.com)
HACKING STARCRAFT(BROODWAR)

Well, I will spend a little time to teach you how to hack Starcraft.

What will we hack? - THE INSTANT BUILD -

Yes, that's right. Instant build lets you build structures & units
IMMEDIATELY...

Tools needed:
~~~~~~~~~~~~~
-SoftIce
-Mem. finder (i use TSearch for this example)
-a little time to listen :)

Level:
~~~~~~
-Advanced

NOTE: This tutorial is dedicated to T-RaiNeR :) "sper sa-ti placa si


~~~~~ sa te ajute. Un mic antrenament cu SoftIce :)"

Let's BEGIN
~~~~~~~~~~~

Ok, Fire up BroodWar & enter a single player game. Choose to play custom
and not campaigns... I choosed map challenger & I played with zergs - but
this doesn't matter...

Now, since we wanna make INSTANT BUILD hack, we want to build something
(to see how it modifies the memory). & to build, we need minerals. Just type
[ENTER] Show me the money [ENTER] in SC, to have the cash :)

After that, put your "probe" to build something... After the probe started to
build, pause SC (hit F10), ALT+TAB, enter TSearch and search for "unknown val
in Starcraft's memory. After TSearch finished it's job, enter in SC, unpause
the game for a sec or 2. The building hit-points will increase. Pause the gam
again, and in TSearch choose the option "has decreased" (thnx Groza for
your tut). This means that we're searching the values that have decreased.
If we don't find anything this way, next time we'll search the values that
have increased. Get the point? But i assure you that "has decreased" is for
Starcraft :). After TSearch finish it's job, go back in the game, unpause for
a sec or 2 (to inc the hit-points of the building), then in TSearch choose ag
"has decreased". Repeat these steps until you will find about 6-7 addresses i
TSearch. Now we must find the correct one by taking each of them (IN ORDER) a
modify it, then back in the game to see what happend. I'll make your job easi
and i'll tell you the address. It's the first one (in TSearch) that starts wi
634XXX (mine was 6342C4 - i'm using SC version 1.12, yours could be different

So, we got the address (i found this address by putting 0 into it. Since SC dec.
the timer until you building is finished, 0 will probably be the finish of ou
construction). DON'T PUT 0 (YET) AT THAT ADDRESS BECAUSE WE CAN'T TRAP IT WIT
WHEN IT'S BEING DECREASED !!!

In SoftIce type:
bpm the_address w (the_address=found address)

Go back in the game, unpause it, and SI should break:

..........code.....code...... eax stores the time remaining it's *encrypted*


XXXX:XXXXXX DEC EAX -> dec the remaining time
XXXX:XXXXXX MOV [ECX+AC],AX -> update it in our found address
XXXX:XXXXXX XOR EAX,EAX -> here you land in SI
XXXX:XXXXXX RET
..........code....code.......

After you can see, the time remaining is decreased one by one...

Let's put a breakpoint (bpx) on the ret instruction for later use.

So, let's make our PC an easier life and put a 0 in eax :) To do so, find a code
then overwrite the "mov [ecx+ac],ax" instruction with "jump code_cave".
In the code cave: "xor eax,eax","mov [ecx+ac],ax","jmp back" to write 0 in our ad

NOTE: If you don't know what code cave is, read some more tuts, then come back! :
This tut is not for Newbies!!!

And now let's test our patch by simply exiting SI(F5).

Voila... Hey, the structure is build, but it's hit-points remained the same!

That's because we modified only the state of the building in the building
process. When we had set the time_remaining to 0, the game thought that it's
hit-points were also increased to maximum (the building is ready WHEN it's
hit-points are maximum - in case you're not attacked :).

That's why i told u to put a bpx on the ret. To see what's happening next!

Go and build something else...

SI should break at the ret. Trace with F8 until you see a comparation like jle,
jl,jge,jg. Game uses those often to compare the current_building_hit_points w
building_is_finished_hit_points.

After trace, you should come to this piece of code (this is inside a call, that's
why you had to trace with F8)

........code.....code.............
XXX:XXXXXX MOV ECX,[ESI+8] ->mov in ecx the current_hit_points *encrypted*
XXX:XXXXXX MOV EAX,[ESI+64] ->mov in eax a hit_point *encrypted*
XXX:XXXXXX ADD ECX,EAX ->increase building hit_points
XXX:XXXXXX MOV [ESI+8],ECX ->update an address
XXX:XXXXXX MOV EAX,[EAX*4+6A9BA8] ->mov in eax the_maximum_building_HP *encrypted
XXX:XXXXXX CMP ECX,EAX ->IS building finished?
XXX:XXXXXX JLE building_not_ready ->if no, then jump
XXX:XXXXXX MOV [ESI+8],EAX ->if yes, put in address the maximum_HP *encrypted*
.............code.......code......

It's easy to figure out what you should do... NOP the jle instruction to make the
always update the addr with the maximum_HP...

Also, notice that this hack will make your units INVULNERABLE because the game us
same routine to manage units' health. Another notice is that YOU HAVE to jump
when i showed you the first piece of code (and not just xor eax,eax, update a
otherwise the game crashes when "operation cwal" cheat is on!

FINAL WORDS:
~~~~~~~~~~~~

It seems that we shoot 2 rabbits from one shot (instant-build & invulnerability).
And the instant_build hack works FASTER than the game's cheat code.

CHEERS & GREETS (order doesn't matter):


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-Groza (what happend to you, dude?)


-ParaBytes :)
-All in GameHacking's forums
-ALL GHU members
-JUVE
-YOU
romanian:
*******************************
* Salutari celor din Romania! *
*******************************

-And specially greets goes to T-RaiNer (timem legatura! )

Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


GHU ( http://www.ghu.as.ro/ ).

eof
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|_|_|_|_|_| |_|_|_|_|_| |_|_ _|_| |_|_|_|_|_|
|_| |_| |_| |_|_|_|_|_| |_|
|_| |_| |_| |_| |_| |_| |_|
|_| _ _ _ |_|_ _ _|_| |_| |_| |_|_|_|
|_| |_|_|_| |_|_|_|_|_| |_| |_| |_|
|_| |_| |_| |_| |_| |_| |_|
|_|_ _ _|_| |_| |_| |_| |_| |_|_ _ _ _
|_|_|_|_|_| |_| |_| |_| |_| |_|_|_|_|_|
H H AAAAAA CCCCCC K K I N N GGGGGG
H H A A C K K I NN N G
HHHHHH AAAAAA C KK I N N N G GGG
H H A A C K K I N N N G G
H H A A C K K I N NN G G
H H A A CCCCCC K K I N N GGGGGG

( harmony between Cracking and Game-Hacking )

Target : StarCraft-BroodWar
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Description : An example to show you that Game-Hacking is Cracking's brother


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Tools Needed : SoftIce


~~~~~~~~~~~~~~~~~~~~~~

Level : Intermediate(-Advanced)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LET'S START
~~~~~~~~~~~

Back to work again, eh ? After a few days of playing CS (man, I LOVE this game...
I decided to "hack" BroodWar... No, not the minerals, but the cheat codes !

If you had read my previous tut (about Worms2), you should know what I'm trying t
do... If you didn't (you naughty boy!), then I'll explain once more...

So, we want to intercept StarCraft when it reads the cheat_codes. (Windows progra
often use GetDlgItemText(A) or GetWindowText(A) to read the text inside an
edit_box. But we don't have such thing (edit_box) in StarCraft :( .

Then maybe we can catch a call to Kernel's HMEMCPY. This HMEMCPY is another way
to see where a program reads text inside an edit_box (and not only!). The
applications doesn't call this function, but Windows works with it when
something goes to memory (i.e. when you type something in NOTEPAD).
Also, Delphi programs doesn't call GetDlgItemText(A) or GetWindowText(A) to
read the text inside edit_boxes...
(Delphi progies are often debugged with a bpx on HMEMCPY :) ).
Got the idea ?

Now, let's try this on StraCraft. Enter the game, and in SoftIce type:
bpx hmemcpy

And now (in StarCraft), type in your name instead of a cheat...

???!?!?!? NOTHING HAPPENED ?!?!???!?!?! But... how... UFFF !!!!!

Is there any solution to break in ? OF COURSE IT IS ! :))))))))

As my good_old pal ParaBytes told me : "The games have their own HMEMCPY" !

And so it is, dear reader, so it is...

But how ? Here's the explanation : Games have their own functions to read the tex
that you type in. That function is PROBABLY hidden in a .DLL file of the gam
It can be, of course, inside the .exe, but in most of the cases, IT'S IN A .
And our target uses a function inside STORM.DLL to do it's "dirty" job...
Why storm ? Oh, come on ! We all know how Blizzard works, right ?
BTW : in storm.dll is the CD-check security_scheme as well, but we don't wan
that ! We payed for our StarCraft copy, right ? ;)

Now, all we have to do :

- make SoftIce load the exports from Storm.dll (use SoftIce's loader. You can
them durind the SoftIce-load <when you start your PC> , or dinamicaly, at r
Use SoftIce's Symbol Loader ! )

- put a bpx on all functions exported by Storm.dll. Then delete the unnecessa
i.e. : If you put a bpx on "func1", and SoftIce pops up when you move your
then delete that bpx on "func1". Because we need the function used t
read the text we type in, not the function that moves your probe !
Get the idea ? :)))
To do this the good way, do the following : put a bpx on the first 1
functions. Play a little. If SI pops, delete the bpx on that functio
that SI popped on. If SI don't break, try to type a fake_password.
If SI pops, than that function could be the right one. If SI didn't
pop when you entered the fake cheat, then delete all bpx on all func
and put some new bpx on the next 10 functions ! Repeat the steps abo
If you finished checking all functions and SI didn't pop when you ty
a fake_cheat in, then YOU DID SOMETHING WRONG OR THAT .DLL ISN'T THE
WE NEED !

- after you found the function, read bellow :)))

OK, OK ! I tell you the function, you lazy jackass (uuuuh, what does "jackass" me
anyway ?) :)

It's "ORD_1F5" function inside storm.dll. So bpx this function like this :

bpx storm!ord_1f5

Now, disable this breakpoint, and in the game type a fake_password ! Enable now t
breakpoint. And you should be in SI again. That's because the game wants to
the typed text even if you haven't pressed [ENTER] to send it to the game.
It's like this : When the "enter_password" part have the FOCUS (i.e. : you w
type in a cheat_code), then BroodWar keeps calling ord_1f5.

Here you must be fast and press [ENTER] for cheat_validation inside the game...
In other words : You must press [ENTER] (to let game read what you've entere
cheat) inside BroodWar between the pops of SI !
Example :
________________________
| |
| Game Screen |
| |
| |
|Message:FAKE CHEAT |
|________________________|

After you wrote "FAKE CHEAT", enable the breakpoint on ord_1f5 ! You'll see that
will pop very often. You must press [ENTER] in the game between SI's pops to
the game that you have finish writing the "cheat_code".

If you did this correctly, SI should pop at the beginning of ord_1f5. Press F12 a
should be here :

4DB9BA : call storm!ord_1f5


ret

Execute the "ret" instruction and you will be here :

call 4DB9B0 -> the call which we returned from


4B5DDD : mov eax, [51B0B0] -> here we land
lea edx, [esp+10]
lea ecx, [esp+14] -> after this instr. ecx will hold the address of
mov [esp+10], eax typed text (type "d ecx" in SI to see your tex
.................

Now that we have found where our string is stored, we put a bpm to see where the
is accessing it ... So when you are on "mov [esp+10], eax" type in SI :

bpm ecx

Press F5 to exit SI, and SI pops immediately with this piece of code :

40793E : repnz scasb -> here we land; edi=addr_of_string, ecx=fffffffe, esi=


not ecx -> negate ecx (i.e. : if ecx=9, then ecx=-9)
dec ecx -> decrease ecx

After you can see, that code calculates the length of the entered_text :
repnz scasb will search the entered_text (edi) for the NULL terminati
(esi) while ecx<>0. Ecx=ffffffff the first time, then it will be decr
if NULL char isn't reached. Then ecx is negated and dec-ed to obtain
string_length.

Trace down through the code until you will be here :

407962 : movsx eax, [ebx+esi] -> place in eax string chars one by one <--
push eax
call 4c5090 -> if that char is uppercased, then make it
add esp, 4
mov [esi], al -> save lowercased char back to string
dec ebp -> ebp=length_string
jnz 407962 -> if that wasn't the last char, jump to nex
So BroodWar searches our entered string to check for uppercased letters. If it fi
then it lowercases them...

Trace down the code... You will see how your entered_string is ENCRYPTED. Then yo
see this :

4079F3 : mov ecx, 8 -> encrypted cheat_codes have a length of 8


mov edi, 4e45a0 -> first encrypted cheat_code
lea esi, [esp+10] -> our encrypted string
xor edx, edx
repz cmpsb -> compare our encrypted_string with encryp
jnz 407a22 -> if they don't match, jump to compare wit
...cheat 1 matched.... -> they matched, so activate cheat1
....................
407a22 : mov ecx, 8 -> encrypted cheat_codes have a length of 8
mov edi, 4e4538 -> second encrypted cheat_code
lea esi, [esp+10] -> our encrypted string
xor eax, eax
repz cmpsb -> compare our encrypted_string with encryp
jnz 407a4f -> if they don't match, jump to compare wit
...cheat 2 matched.... -> they matched, so activate cheat2
....................

After you can see, the game compares our entered_string with all cheat_codes one
If there was a match, then activate the respective cheat (i.e. : invulnerab
they didn't match, then compare our_string with the next cheat_code. And so
until there is a match or there's no more cheat_code to be compared with.

So that's how BroodWar works... It takes our string, encrypts it and compares it
encrypted cheat_codes...

Well, we could also decrypt them, but that was too hard for me to reverse, write
explain (and for you to understand). :((((((

< I counted up to 18 possible cheat codes :) >

FINAL WORDS
~~~~~~~~~~~

Looks like my job here is done... I wish you all the good things !

BTW: If you like a game, then first finish it without any cheats/memory_hacking..
you won't feel it's FEELING ! After you finished it many times and it's play
be boring, then HACK it until your eyes will be as big as a potato ! hehehe.

CHEERS & GREETS (order doesn't matter, chaos is the problem :) hehehe )
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Groza (great dude - check http://www.grozatt.cjb.net/ for more of this stuff...


- Snaky (cel mai "nebun" nebun)
- T-RaiNeR (long time - no see)
- ParaBytes (my cracking teacher - a BIG THANKS)
- All in GameHacking's forum
- All GHU members (GHU=tseB) hehehe...
- JUVENTUS (I love JUVE !)
- All crackers in the world ! (you opened a beautiful book for us)
- YOU
romanian:
*******************************
* Salutari celor din Romania! *
* Fiti si voi mai fericiti !! *
*******************************

Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


GHU ( http://www.ghu.as.ro/ ).

2003

eof
Game-Hacking Tutorial

Target : StarCraft-BroodWar
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Description : Unit Spying


~~~~~~~~~~~~~~~~~~~~~~~~~

Tools Needed :
~~~~~~~~~~~~~~

- SoftIce
- A memory finder (GameTrainer, TSearch, ArtMoney -> you decide)
- Some programming skills ('cause we're gonna make a "unit detector" trainer)

Level : Intermediate(-Advanced)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

INTRO
~~~~~

Hello there, friends!

I'm preparing for winter holidays, and I haven't so much time to write :(((

But in my very rare internet_surfings I found a tut about Screen Msg in StarCraft
written by Drakken (Cheers!). It's indeed a good one, but that isn't our
subject for today. Our subject is how to make a unit-detector for StarCraft (
the end of his tut, Drakken mentioned about this kind of hack, so that gave
me the idea to write down this one. So, thanks Drakken for the idea :) )...

Eh, looks like we have set our objective, so let's "don't just play... HACK !"

IMPORTANT NOTE : I'm hacking StarCraft v1.04, so if you have a diff. version,
the offsets are different. Don't worry, 'cause the instruction
may be the same. (and forgive my laziness, cause I'm using
v1.04 when there is v1.10 on the web... -> I'm in a hurry ;) )

Let's Begin
~~~~~~~~~~~

Fire up StarCraft, enter a custom game and play with 7 computers. Choose "PROTOSS
as your race, and for the computers, choose "PROTOSS", too.

Before we continue, I must tell u something : let the computers play a little whi
you are doing nothing. That's because we don't want them to have the same num
of units (probes) that we have. Let them play as they like ;).
PS : turn the map cheat on ("black sheep wall").

Now, while you're in game, count the number of your probes (should be 4). Write i
(or keep it in your mind :) ), and then pause StarCraft (F10). Now ALT+TAB an
up your mem. finder (I use TSearch). Select StarCraft as a process, then sear
the number of your probes (type_of_search=DWORD ... Yeah, StarCraft stores th
unit_numbers as a DWORD). Then go back in the game and modify the number of y
probes (you can either build another probe or kill one). Then pause again SC,
go back in mem. finder, and search_next for the new number of probes. Repeat
steps until you'll have only a few addresses (3 or 4 addies). Now modify the
stored AT these addies (one at a time) within the mem. finder and see how aff

ex: let's say you found those addresses:

aaaaaa hold a value=6


bbbbbb hold a value=6
cccccc hold a value=6
dddddd hold a value=6

Now, replace the value (6) held by first address (aaaaaa) with a new one (7) - in
your mem. finder. Go back in the game and build one probe. Return to the mem.
and look at the value of that addie (aaaaaa). If it's 8 (7+1 - you had 7 prob
you build another one in the game), then it's probably the address we are loo
If the value isn't 8, then delete this address (aaaaaa) and do the same with
one. If this isn't the right one, delete it and skip to the next one... Get t

Following this technique I found my address. It's 504A84. (yours could be differe

What to do next ? Well, the classic method : let's put a breakpoint on this addre
the help of our beloved SoftIce :

bpm 504A84

(be sure you are in StarCraft memory when you put breakpoints. To check this look
right corner in SoftIce. If you are not in SC memory, go back in the game, un
and enter again in SoftIce until you're in SC mem. )

Ok... we have set the trap... This bpm means : I command SoftIce to pop whenever
address (504A84) is being read/written.

Exit SoftIce and go back in the game. Build a probe. When it's ready, SoftIce sho
with the following code:

Registers are: eax=40; ecx=1; esi=40

a: mov eax, [esp+14] -> moves in eax a number


b: lea edx, [esi*2+esi] -> "moves" in edx a number
c: and eax, FF -> eax will have the value of al (for me it'
d: lea ebp, [edx*4+eax] -> "moves" in ebp a number
e: mov edx, [ebp*4+503E7C] -> edx will hold our probes number
f: add edx, ecx -> add to edx one (the probe we have build)
g: mov [ebp*4+503E7C], edx -> update with our new number of probes
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

What is this piece of code doing here ? Mmmm... I have no ideea :((((

Let's put a breakpoint on "mov eax, [esp+14]" instruction


bpx a
where "a" is the offset of "mov eax, [esp+14]" instruction (you can see it in Sof

Exit SoftIce, an let's build something else in the game... Let's say a pylon (hop
enough money :) ). IF SI pops and your pylon isn't build yet, ignore that pop
That's because the same routine is used for computer players, too. (the compu
build or lost a unit).
When your pylon is build, SI pops where we put our breakpoint :

Registers are: eax=9C; ecx=1; esi=9C

a: mov eax, [esp+14] -> moves in eax a number


b: lea edx, [esi*2+esi] -> "moves" in edx a number
c: and eax, FF -> eax will have the value of al (for me it'
d: lea ebp, [edx*4+eax] -> "moves" in ebp a number
e: mov edx, [ebp*4+503E7C] -> edx will hold our pylons number
f: add edx, ecx -> add to edx one (the pylon we have build)
g: mov [ebp*4+503E7C], edx -> update with our new number of pylons
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

What the hack does it means ? ( LOOK AT THE REGISTERS !!! )

Exit SoftIce and let the computers play a little... When their units number chang
should pop again:

Registers are: eax=41; ecx=-1; esi=41

a: mov eax, [esp+14] -> moves in eax a number


b: lea edx, [esi*2+esi] -> "moves" in edx a number
c: and eax, FF -> eax will have the value of al (this time
d: lea ebp, [edx*4+eax] -> "moves" in ebp a number
e: mov edx, [ebp*4+503E7C] -> edx will hold computer's zealot number
f: add edx, ecx -> add to edx -1 (a zealot had been killed)
g: mov [ebp*4+503E7C], edx -> update with computer's new number of zeal
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

( The above code is what I saw when the red_colored computer lost a zealot )

Registers are: eax=A3; ecx=1; esi=A3

a: mov eax, [esp+14] -> moves in eax a number


b: lea edx, [esi*2+esi] -> "moves" in edx a number
c: and eax, FF -> eax will have the value of al (this time
d: lea ebp, [edx*4+eax] -> "moves" in ebp a number
e: mov edx, [ebp*4+503E7C] -> edx will hold computer's citadel_of_adun
f: add edx, ecx -> add to edx 1 (a citadel_of_adun had been
g: mov [ebp*4+503E7C], edx -> update with computer's new number of cita
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

( The above code is what I saw when the yellow_colored computer build a citadel_o
Registers are: eax=48; ecx=1; esi=48

a: mov eax, [esp+14] -> moves in eax a number


b: lea edx, [esi*2+esi] -> "moves" in edx a number
c: and eax, FF -> eax will have the value of al (this time
d: lea ebp, [edx*4+eax] -> "moves" in ebp a number
e: mov edx, [ebp*4+503E7C] -> edx will hold computer's carriers number
f: add edx, ecx -> add to edx 1 (a carrier had been build)
g: mov [ebp*4+503E7C], edx -> update with computer's new number of carr
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

( The above code is what I saw when the yellow_colored computer build a carrier )

Registers are: eax=48; ecx=1; esi=48

a: mov eax, [esp+14] -> moves in eax a number


b: lea edx, [esi*2+esi] -> "moves" in edx a number
c: and eax, FF -> eax will have the value of al (this time
d: lea ebp, [edx*4+eax] -> "moves" in ebp a number
e: mov edx, [ebp*4+503E7C] -> edx will hold computer's carriers number
f: add edx, ecx -> add to edx 1 (a carrier had been build)
g: mov [ebp*4+503E7C], edx -> update with computer's new number of carr
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

( The above code is what I saw when the purple_colored computer build a carrier )

???? DO YOU FEEL WHAT'S GOING ON ????

Let me tell you what's going on...

After you can see, the game uses the SAME routine to upate the number of units fo
and your computer_opponents. If you looked carefuly the registers, you saw th

I) ECX could hold only 2 values : FFFFFFFF (-1) when a unit was killed
1 when a unit was build

II) ESI & EAX held different numbers when DIFFERENT units had been build or kil
i.e. : when a carrier had been builed, ESI & EAX held 48
when a pylon had been builed, ESI & EAX held 9C
when a probe had been builed, ESI & EAX held 40

III) And another change was at instruction "and eax, FF", which changed eax:
i.e. : when purple_colored computer build something, eax held 7
when yellow_colored computer build something, eax held 3
when I build something, eax held 2
when red_colored computer build something, eax held 5

So, with this information, we determined EXACTLY what that piece of code does:
Registers are: eax=coded_byte_for_units; ecx=1 or -1; esi=eax=coded_byte_for_un

a: mov eax, [esp+14] -> moves in eax a number containing current


number in al
b: lea edx, [esi*2+esi] -> edx will hold esi*2+esi (some calculation
coded_byte_for_units)
c: and eax, FF -> eax will hold the effective number of cur
(that builds or looses a unit)
d: lea ebp, [edx*4+eax] -> ebp will hold edx*4+eax (some calculation
coded_byte_for_units and current player number)
e: mov edx, [ebp*4+503E7C] -> edx will hold current player's number of
unit (carriers, drones pylons etc)
f: add edx, ecx -> perform operations with that number (incr
it by one if current player builds someth
decrease it by one if current player loos
g: mov [ebp*4+503E7C], edx -> update with current player's new number o
unit
h: xor edx, edx -> unimportant... (makes edx=0)
.......code code.......

Here's some more information for you guys that didn't understood : when a player
builds/looses a unit (or structure), the game uses his number (player's numbe
4,5,6,7,8) and the coded_byte for that unit to reach the effective number of
unit and perform operations on it (inc if he builds the unit / dec if he loos
unit).

SOME REMARKS : eax that holds player number, can hold this values:
0=player 1
1=player 2
2=player 3
..........
7=player 8

So, when 2 is in eax, we know it's NOT about player 2 BUT player 3 !

I was telling you about some "coded_byte_for_units"... This means that every unit
specific byte (stored in ESI register) !
i.e. :
carrier=48
pylon =9C
probe =40
zealot =41

Look around the address of your probes... Don't you see something suspicious ? Ye
The game stores the number of units_type (probes, marines) for each player li

i.e. for probes :

504A7C : 04 00 00 00 0B 00 00 00 02 00 00 00 1C 00 00 00
504A8C : 10 00 00 00 15 00 00 00 0E 00 00 00 12 00 00 00

player 1 has 4 probes


player 2 has 11 probes (0B in hex)
player 3 has 2 probes
.....................
player 8 has 18 probes (12 in hex)

i.e. for zealots :

504AAC : 01 00 00 00 03 00 00 00 00 00 00 00 01 00 00 00
504ABC : 09 00 00 00 22 00 00 00 07 00 00 00 04 00 00 00

player 1 has 1 zealot


player 2 has 3 zealots
player 3 has 0 zealots
.....................
player 8 has 4 zealots

So, the units number is stored as a DWORD, and the unit numbers are stored one af
another for each player (starting from player 1 and ending with player 8)
NOTE : you could figure this out with some math, too ( having the players number
unit_coded_byte... you know, with the above piece of asm code... ;) )

Now, like a hard-working-lamer that I am, I'll give you the list of all units & s
for TERRANS, ZERGS and PROTOSS with their respective coded_byte... ( I deserv
beer ! :)))) )

TERRAN
coded_byte | unit
~~~~~~~~~~~~~~~~~~
0 = Marine
1 = Ghost
2 = Vulture
3 = Goliath
5 = Siege Tank (Tank mode)
7 = SCV
8 = Vraith
9 = Science Vessel
B = Dropship
C = Battlecruiser
D = Spider Mine
E = Nuclear Lounch
1E = Siege Tank (Siege Mode)
20 = Firebat
21 = Vision (casted from Scanner Sweep)
22 = Medic
3A = Valkyrie
6A = Command Center
6B = Comsat Station
6C = Nuclear Silo
6D = Suply Depot
6E = Rafinery
6F = Barracks
70 = Academy
71 = Factory
72 = Starport
73 = Control Tower
74 = Science Facility
75 = Covert Ops
76 = Physics Lab
78 = Machine Shop
7A = Engineering Bay
7C = Turret
7D = Bunker

ZERG
coded_byte | unit
~~~~~~~~~~~~~~~~~~
23 = Larva
25 = Zergling
26 = Hidralisk
27 = Ultralisk
28 = Broodling
29 = Drone
2A = Overlord
2B = Mutalisk
2C = Guardian
2D = Queen
2E = Defiler
2F = Scourge
32 = Infested Terran
3E = Devourer
67 = Lurker
82 = Infested Command Center
83 = Hatchery
84 = Lair
85 = Hive
86 = Nydus Canal
87 = Hydralisk Den
88 = Defiler Mound
89 = Greater Spire
8A = Queen's Nest
8B = Evolution Chamber
8C = Ultralisk Cavern
8D = Spire
8E = Spawning Pool
8F = Creep Colony
90 = Spore Colony
92 = Sunken Colony
95 = Extractor

PROTOSS
coded_byte | unit
~~~~~~~~~~~~~~~~~~
3C = Corsair
3D = Dark Templar
3F = Dark Archon
40 = Probe
41 = Zealot
42 = Dragoon
43 = High Templar
44 = Archon
45 = Shuttle
46 = Scout
47 = Arbiter
48 = Carrier
49 = Interceptor
53 = Reaver
54 = Observer
55 = Scarab
9A = Nexus
9B = Robotics Facility
9C = Pylon
9D = Assimilator
9F = Observatory
A0 = Gateway
A2 = Photon Cannon
A3 = Citadel of Adun
A4 = Cybernetics Core
A5 = Templar Archives
A6 = Forge
A7 = Stargate
A9 = Fleet Beacon
AA = Arbiter Tribunal
AB = Robotics Support Bay
AC = Shield Battery

NEUTRAL
coded_byte | unit
~~~~~~~~~~~~~~~~~~
5F = Ragnasaur
B2 = Mineral Field
BC = Unoccupied Vespene Geyser
( the player number for neutral is B )

Yeah, actualy there are more neutral units, but this list is by far ENOUGH !

How did I get this list ? Simple : I managed to play alone a game (with every rac
time), then I set that bpx on "mov eax, [esp+14]" instruction, then I build e
structure & unit that race have, looking at ESI register... And to tell you t
it was very UNcool, especialy when there are 7-8 electricity failures in your
neighbordhood... :(((((((((

OK, OK..... Now let's think a bit on what can we do with these informations...

DO NOT DO THIS :
The first thing I did was the code-injection... I jump from the "mov eax, [esp+14
instruction to a code cave. Then, in that code-cave I wrote a unit filter...
You know, player checks, unit checks, and many-many more features... But sudd
I realized that if the trainer was started after the players build-up their c
(for example), the trainer wasn't able to read the carriers number ( because
that the trainer wrote in that code-cave is called ONLY if a carrier is build
- we jump there ONLY from that routine that starts with "mov eax, [esp+14]").

DO THIS !!!! :
Then I came up with the correct idea : Why to inject code when we can read the un
numbers with some simple math calculations... More over, StarCraft don't use
that storing...

Let's see how the game reaches the address of probes, for example :

lea edx, [esi*2+esi] (esi is the coded byte for probes, in this case esi=40)
lea ebp, [edx*4+eax] (edx from above; eax is the player's number i.e.: 0,1,.
mov edx, [ebp*4+503E7C] (ebp from above; 503E7C is a static address;
here edx gets the effective number of probes for pl

So, our task is very simple :

- calculate the address of the unit that we want it's number


- use API ReadProcessMemory to read the value from that address

Now for that you can either choose the player you want to spy on, or make a cycle
goes through all 8 players. You decide ! I'll show you both ways :)

SPYING CARRIERS' NUMBER OF PLAYER 4

phandle:DWORD ; you get this by calling OpenProcess for StarCraft


carrier_numba:DWORD ; a variable in which you store the number of carriers

mov eax, 3 ( player 4 = 3 in eax, remember ? )


mov esi, 48h ( coded_byte for carrier )
lea edx, [esi*2+esi]
lea ebp, [edx*4+eax]
lea edx, [ebp*4+503e7ch]
Invoke ReadProcessMemory, phandle, edx, addr carrier_numba, 4, NULL

SPYING CARRIERS' NUMBER OF ALL PLAYERS

player_iteration:DWORD ; stores player's number (0,1,2..7)


unit_buffer dd 8 dup(0) ; a buffer of dwords to store the carrier number for ea

mov player_iteration, 0
.while player_iteration <= 7
mov eax, player_iteration
mov esi, 48h
lea edx, [esi*2+esi]
lea ebp, [edx*4+eax]
lea edx, [ebp*4+503e7ch]
Invoke ReadProcessMemory, phandle, edx, addr carrier_numba, 4, NULL
mov eax, numba
mov ecx, player_iteration
mov unit_buffer[ecx], eax
inc player_iteration
.endw

FINAL WORDS
~~~~~~~~~~~

Ough! Another *great* :) tut finished... And it was a lot of typing... But I thin
worth it !
And I think this kind of hack should work without any problem in Multiplayer game
:)))))))

'Till next time, I wish you a happy... life !

CHEERS & GREETS (order doesn't matter)


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Groza (great dude - check http://www.grozatt.cjb.net/ for more of this stuff...


- Snaky (Snaky is a looser :), Snaky is a looser :) hehehe)
- T-RaiNeR (long time - no see)
- ParaBytes (my cracking teacher - a BIG THANKS ; like above, long time - no see
- All GHU members (GHU=tseB) hehehe...
- JUVENTUS (I love JUVE ! OH NO > JUVE-INTER 1:3 < OH NO )
- YOU
romanian:
*******************************
* Salutari celor din Romania! *
* Fiti si voi mai fericiti !! *
*******************************
PS : Acest document a fost scris pe 1 decembrie 2003 -> Ziua Romaniei
(Bineînteles dupã ce m-am întors de la defilare :::)))))) )
TRAIASCA ROMANIA
Specialy Thanks goes to Drakken for his "StarCraft Screen Messages" tut and unit

Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


GHU ( http://www.ghu.as.ro/ ).

2003

eof
Bie comment:

This info is taken from http://www.gamehacking.com forum. The info didn't mention the patch is for which version of Starcraft. Omega have

explaining the format of the info in 3 categories, Offset, Original and Patch.

Informer: JohnTheBaptist

Email: Unknown

Homepage: Unknown

Other known method to contact the author

none

Maphack Public Offset:

Offset Original Patch


46c517 74 eb
46c532 01 11
4105cf 8a 4e 0c 84 c8 bd fe 00 00 00
4c458b f0 00
4c4fa2 ed 00
46e6f8 32 00
46e702 75 eb
46d2fe 74 11 84 75 19 85
46d302 6ce3 3040
46d308 a1 70 e3 65 00 85 c0 ff 0d 08 2f 65 00 90
46d310 06 08
46e47f 32 00
46e489 75 eb
46e81f 32 00
46e829 75 eb

The Public Offsets. Originally found by the Korean guy. These will let you maphack in a multiplayer game, yeah. You don't "hack" them though,

you poke them.

Bie comment:

Below is some more info Eedok. Eedok can be contact thru http://www.gamehacking.com forum.

More Info: By Eedok:

we can try to translate those offsets up there to asm and see what they get changed to, maybe that'll help us out, cept I can't find a program

to translate hex into asm..

Anyways here's the easywrite script for the unpatched values

offset 0x46C517

je 0x46C521

offset 0x46C531

mov byte ptr [ecx], al

offset 0x4105CF

mov cl, byte ptr [esi+0C]

test al,cl

offset 0x4C4589

je 0x4C467F
offset 0x4C4FA0

je 0x4C5093

offset 0x46E6F7

je 0x46E72B

offset 0x46E702

jne 0x46E726

offset 0x46D2FE

je 0x46D311

offset 0x46D300

test byte ptr [0065E36C], al

offset 0x46D308

mov eax, dword ptr [0065E370]

offset 0x46D30F

jmp 0x46D317

offset 0x46E47E

je 0x46E4B2

offset 0x46E489

jne 0x46E4AD

offset 0x46E81E

je 0x46E852

offset 0x46E829

jne 0x46E84D

try to figure out what to change to make them work..(hint:use the TMK button and compare with public offsets)

Sorin Question:

i tried to do changed/not changed but i have found 1 addr that if i modify, nothing will happen

Eedok Answer:

try searching 2 byte instead of 4, or maybe it's 1 byte I can't remember but I think it's 2 bytes and the on value is 0F and the off value is

1F(convert these out of hex to get them to work) plus changing these only changes 1 little square.. maybe the one you're modifying is off the

map..

Bie comment:

JohnTheBaptist also explain how to find the hack, but did not say if this method is for offline or online games but Eedok said it would. I let the

instruction in it original state as JohnTheBaptist post it in the gamehacking.com forum. User who read the instruction below must have already

know to use memory searcher example Tsearch or Artmoney. 'Black Sheep Wall' mean to be type in Starcraft chat screen while playing the

game.

Using Starcraft Cheat to find the address and value

Search unknown offsets

Black Sheep Wall


Bie comment:

This info is taken from http://www.angelfire.com/games5/storagebin/ . The info is for Starcraft v1.10

Tutorial Author: Fish Beans

Email: Unknown

Homepage: Unknown

Other known method to contact the author

none

This page is dedicated to the hacks that are not possible for the current version of Starcraft, 1.10. I will attempt to explain to you why these

hacks are impossible, and hopefully teach you a bit about how Starcraft works.

The Basics

The way Starcraft's online mode works is like this. When you start a new game of Starcraft, the map file determines how many

minerals/gas/units you have. It initializes these values for each player. After this point, whenever a player does something (tells a unit to move,

attack, makes a new unit) only the commands are sent to each computer. This way every computer knows exactly what's happening on each

other computer. There are periodic checks for changes (I believe it's every 174 milliseconds, but I could be wrong) to check to see if something

has changed unexpectedly. If it has, the computer(s) that detected the anomoly breaks their connection(s) with you, ending your game of

Starcraft. This is how the disconnect hack works, and is often referred to as a desync.

Resource Hacks

Now let's examine all the possible methods of making a mineral hack, and I'll explain why none of them will work. As stated earlier, from the

start of the game, each computer knows how many minerals each other computer has.

Trying to change the value that you start with will cause an immediate desync because the other computers still think you have a different

amount.

If you attempt to change how much units/buildings cost, you will get desynced when you build something. Your computer sends the command

that you are building a unit/structure at a certain location, then it subtracts the amount of mineras/gas it cost from your total. When the other

computers recieve the command, they in turn subtract the cost of the unit/structure from the running total kept on their computer. Since your

change to the cost of the unit/structure did not affect their computer in any way, the values go out of sync and you get dropped.

Changing the code that subtracts the amount from your resources to add it instead (which is quite possible to do) will cause a desync when you

spend any resources. Once again, the other computers register a normal change and your computer has an abnormal change.

Changing to code that determines if you have enough resources to spend to always think you do will cause a desync when you spend your

resources past 0. When you attempt to spend your resources past 0, two things happen. The value rolls back all the way to 4,294,967,296 and

starts counting down. The other computers then detect that you didn't have enough resources to perform the selected action and break the

connection with you.

Attempting to change the number of minerals an SCV/Drone/Probe is carrying also desyncs because these values are monitored as well.
There have been other proposed mineral hack ideas, but I can't think of them off the top of my head. I'll add to the list and explain why they

don't work over time. If you wish to argue this with me, feel free to contact me at the forums at www.gamethreat.com, just prepare to be

flamed by the Gamethreat Network collectively for doing so.

Energy Hack

This hack is impossible for the same reasons a mineral hack is impossible. Each other computer knows how much energy each of your units has,

changing that value will cause you to desync. I have seen people ask if you could make it regenerate faster, the answer is no. The other

computers have their own regeneration speeds, and if yours regenerates faster, it will cause the values to be unmatched and you will desync.

Upgrade Hack

A hack that allowed you to upgrade farther than level three was possible in previous versions of Starcraft and Warcraft II, however this is no

longer possible. Now, each computer monitors what level your upgrades are at. If at any time the value is greater than three, you get

desynced.

Fastbuild Hack

This hack is rarely asked about, but I thought I'd add it anyway. When a map file is read from to initialize a game, the build speeds are also

initialized, leaving the possibility to change those build speeds and thus gain an advantage over your opponents. This is not possible however.

Since the other computers know what speed things should be built at, attempting to build something at a greater rate will cause a desync

because your computer only sent the command to build the structure with X unit at coordinates x,y. When production does not match up (yes,

the other computers keep track of production percentages too), you get desynced. Simply changing your production speed will not cause a

desync immediately, only when you build a unit/structure.

Allied Message Monitor

There is no way in which to see the messages sent to other players. These packets are sent directly to the other computers, and your computer

never even knows they exist.

At the moment those are the only hacks I can think of that are asked about fequently. As more hacks are proposed, I will continue to add them

to this page.

See Also:
Game Training Techniques - Tutorial 5
The Sims: Dead Listing

What you will learn:


You don't always have to search memory to find addresses, we will use
WinDasm to dead list THE SIMS. Be sure to grab an unpacked executable
file before attempting this. I provide the one I used, its from the CD release.
You could probably find one at http://www.gamecopyworld.com/

Things you need:


- WinDasm 8.xx or later
- GameHack 2.0
- sims.exe (download this file if you don't have the sims but still want to try
the tutorial 1MB)

Step 1:
Load sims.exe in WinDasm and wait for it to disassemble the file. When it
is open go to the STRING REFERENCES, which is the second to last
button on the tool bar, and start browsing.

SIDE NOTE: As I've talked about before any address that has brackets
around it is pointing to the value inside of that memory address. The read
out is usually something like this:
mov ecx, dword ptr [0060747c].
The previous instruction moves the value inside 0060747c and puts it in
ecx.

One of the first string references I found by scrolling through the list was:
hunger decrement ratio. Well since I can read, this looks like this reference
is talking about a SET value at which your hunger bar decreases. Double
click on "hunger decrement ratio" in the String Reference Window, it will
jump to:

* Possible StringData Ref From Data Obj ->"hunger decrement ratio"


|
:00414abd 6848925e00 push 005e9248
:00414ac2 e83b79ffff call 0040c402
:00414ac7 d91d886f6000 fstp dword ptr [00606f88]
:00414acd d90594565b00 fld dword ptr [005b5794]
:00414ad3 56 push esi
:00414ad4 51 push ecx
:00414ad5 8d4ddc lea ecx, dword ptr [edp-24]
:00414ad8 d91c24 fstp dword ptr [esp]

If you look in the value in those addresses you will see that they are some
crazy high number, that is the decrement ratio at which you starve. If you
change the first value to zero then you will never starve. If you change that
value to a higher number you will starve faster.

Sometimes you have to test which value does what, its probably best to set
both of them to zero. In the case with other values (contained in the file
below) its best to test them out yourself.

The only other one I tested was 'money for new family', with this you have
to set the second value from 20,000 (default) to whatever you want your $
to be. The first memory address is garbage, and THEN (after you set the
new value) you have to create a new family.

All the addresses and names of stats for version 1.0 are in this FILE and the
addresses and stats for version 1.1 are in this FILE. Change them at your
own risk, I included everything I saw, but only certain things are worth
changing like the hunger decrement ratio.

Conclusion:
I assume the values were read into memory from a file when the game
started up (all that garbage scrolling at the botton of the screen on start up),
and stored in memory and never again verified with the original files. Its
always a good idea to check out the game with WinDasm first.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
Code Injection

What is code injection?


Right now there are some games which can’t be trained via the normal ways are searching for the
static address for e.g. on The Sims When you find the money value changing it won’t do shit to your
money on screen. Now to get round this we use code injection. There are also a variety of things that
we also use it for things such as when you get a value that the computer uses as well for e.g. you find
the health address you freeze it and you’ve got infinite life but then the computer does as well. Well
these sort of problems can be solved with code injection so read on.

Tools:
Memory Searcher I suggest T-search but any will do.
Softice – A definite needed tool for any true game hacker.
The Sims v1.1 for the practical

Now just to make this a little bit easier before the practical. I’ll explain exactly how code injection
works. First you must find a code cave. A place in the game where we can write our own code we
then jump from the game code which is affecting say health to our codecave where we have written
our own code we then jump from here back to the game code. This is just totally made up code from
softice but should give you a slight idea of what we want to do.

-Game Code-
0010:558975 5F2014 Sub EAX,30 We Jump out here to our code
0011:558978 5078 Mov EAX,[ESI+30] We nop this address
0012:558980 50 Add EBX,EAX We jump back here

-Code Cave-
0055 Add EAX,30 This is just made up code this is our code cave.
0056 Mov EAX,[ESI+30]
0078 Jmp 558980 We Then jump back to our game code.

Also there is one thing you will need to know a little bit about asm to fully understand this tutorial. So
don’t mail me if your having problems understanding this tutorial if you don’t know shit about asm.

Now for this example I will be using The Sims. We are going to hack the money value which uses
DMA, address changes every level or any time we restart the game Also changing the static address
won’t do anything also nopping the address won’t do shit. So we are going to use code injection to
hack this game.

Finding Code Caves


Now there are several ways of doing this but the easiest which I have found is to use T-Songkie’s
Code Cave tool and then with the address you have use SI commands to locate your codecave. So
first go and get TCCT from gamehacking.com or from the Devious homepage. Also this is only one of
the ways to do this and because I’m lazy and can’t be bothered explaining all the ways of finding
codecaves.
Now run The Sims and go back to the desktop and open TCCT and put the window name ‘The Sims’
into the textbox and press search. Then in the results window you will see hex addresses pick one lets
say 10ABF. Now run softice and type d 10ABF and you will have a list on addresses so scroll down
I’ve picked 10ADF. So then type in SI type u 10ADF and this should take you to the location of the
address and bingo we’ve found our code cave. Now codecaves look like this:-

0010:10ADF ADD [EAX],AL

So write this address down on a piece of paper which we will use later in the tutorial.

Now we must find our money address. So open your memory searcher and search for the amount of
money you have. Go back to the game decrease your money go back to your memory searcher and
search for the decreased value. After doing this a couple of times you should get it. I got 180BECA
now changing this or nopping it won’t do anything to the actual amount of money on your screen
because all this address does is read the amount of money you’ve got.

Now we must place a breakpoint on this is SI so back to the game and press ctrl+d then in SI type

BPMD 180BECA W

After doing this go to the game and loose a bit of money and SI should pop up with something that
looks like this:-

0008:00447F80 MOV EAX,[ECX+50] Moves Money into EAX


0008:00447F83 ADD EAX,[ECX+54] SI Pops Here
0008:00447F86 Push Eax

447F80 This is the pointer we want to edit ECX+50 being our amount of money which is placed into
eax and then further down in the code EAX is placed into our on screen display. So this is where we
want to make our jump. So in SI type

a 447f80 Enter
jmp 10ADF Enter
nop Enter

and then enter again to drop out of assembly mode. Now it should look like this

0008:00447F80 JMP 10ADF


0008:00447F83 NOP
0008:00447F86 Push Eax

Now I haven’t included the op codes because their not needed just yet. Now by editing address
447F80 to jump to our code cave after doing this it fucks up the game code but if we right a single nop
to the address underneath it will even it out.

Now for our codecave so type a 10ADF

And then type the following and pressing enter after each line

MOV DWORD PTR [ECX+50],98967FH


MOV DWORD PTR EAX,[ECX+50]
ADD EAX,[ECX+54]
JMP 447F86

Then hit enter twice to drop out of assembly mode. Now to explain a bit more on what we have just
done.

MOV DWORD PTR [ECX+50],98967FH - Move 9999999 in hex into [ECX+50]


MOV DWORD PTR EAX,[ECX+50] - Then we move ecx+50 into eax
ADD EAX,[ECX+54] - recreate the code we nopped earlier
JMP 447F86 - jumps back to the game code.

Now exit SI and buy or sell something and bingo!!! We’ve done it our money is now 9999999
simoleons.

Now to put this into a trainer you just poke the address where you made your gateway with the op
codes and then the first address of your code cave with all their op codes.

To display the op codes type code on. After doing this you should have some extra numbers in the
code window these are called op codes.

Example

Gateway
448789 1B 5F 8E Jmp to code cave

CODE CAVE
10ABF 1A F1 45 88
10AC3 58 99 88 77
10AC7 45 9E 55 88 JUMP BACK

So here we would poke

Poke 448789 1B 5F 8E
Poke 10ABF 1A F1 45 88 58 99 88 77 45 9E 55 88

And there you have it.


Now this is just one of the things you can do with code injection buy the possibilities are endless. So
hopefully after reading this tutorial you should have a better idea of code injection. By reading this
you won’t learn fully but do this tutorial a couple of times also read some of the other tutorials
floating around on the internet. I have also tried to explain things in this tutorial as simple as I can but
if you have any problems understanding something or feel I have missed something then give us an
email on

Shinero_uk@yahoo.co.uk

Greetz Fly out to Sheep Tsongkie, Vulmer, Futal, Micral, Raven, Digital Vigilante, CES Devious and
all extalia members.

Well Enjoy

Tutorial by Shinero
HACKING THE SIMS : HOT DATE TUTORIAL

Hi there ppl it's me i'm back again and this time with an exclusive tutorial
on hacking The Sims Hot Date ! Some of you might have noticed that there
aren't many hacks for the sims out there apart from the money and
personalities hacks but it's not that hard at all. So to all of you who is
wondering how i made my ultimate sims trainer, here's the essay !

First of all here's a list of necessary stuff :


- The Sims Hot Date - of course :)
- A disassembler - in this tut i will use WDASM 8.9
- Any memory ultility - i use TSearch which is the best in this field
- Some assembly knowledge... well not really a must cuz i will explain
everything later in the tut
All these stuff can be downloaded at TekZ :
http://www.vngamecenter.com/

Ok, let's start rocking ! :)

Step 1 : Finding the addies


1. Open Wdasm and select to disassemble the main exe file of the game.
2. When it finished disassembling click "String Data References" (2nd from
the right on the toolbar). This will show all the string references.
3. Now scroll down slowly and look for "hunger decrement ratio", double
click on the text when you found it.
4. WDasm will take you to the code that should looks like this :

* Possible StringData Ref from Data Obj ->"hunger decrement ratio"

00417A70 6878486300 push 00634878


00417A75 E86668FFFF call 0040E2E0
00417A7A D91D00506500 fstp dword ptr [00655000]
00417A80 D905CCC75F00 fld dword ptr [005FC7CC]
00417A86 56 push esi
00417A87 51 push ecx
00417A88 8D4DDC lea ecx, dword ptr [ebp-24]
00417A8B D91C24 fstp dword ptr [esp]

Ok i assume that you don't know any assembly so i will explain it as simple
as i could. All addies that is put inside a bracket i.e [00655000] is a
memory address. The difference between [00655000] and 00655000 can
be shown in this example :

mov eax,00655000 -> eax = 00655000


mov eax,dword ptr [0065000] -> eax = the value stored in 00655000

Look at the highlighted line. Basically it's an interesting addie and you
should check it out.

Step 2 : Experimenting with the addie


1. Now run the sims hotdate.
2. Alt-tab out and run TSearch.
3. Choose the sims process and click add new cheat in the Cheat list
window. Type in the address you found.
4. You should see some crazy big number in the Value field
5. Hey do you remember the opcode ? It was fstp dword ptr [00655000]
that mean it is a FLOAT operation.
6. So click the Type combo box and choose Float. You should see a
number like 10 or so.
7. Hmm this is really interesting... hunger decrement ratio = 10... you
probably have guessed... if we put a negative number here the game will
increase the hunger bar instead of decreasing it.
8. Let's try it ! Type -100 in the value field and return to the game.
9. Wow ! My sim's hunger bar is going up like crazy ! :) We did it !

Other stuff
This is just an example of how values in the sims can be hacked. You
should look around a bit, there are many interesting string references that
you can play with. Some examples : "energy span", "wake hours", "comfort
decrement active", etc. Check them out yourself.

@^~'essay done by micral'~^@


tekz (c) 2002
do not use without permission plz

contact : micral@phreaker.net
Tutorial On Getting ALL WEAPONS in Tomb Raider II

( By Shaikh Adeel )

Web : http://www.vngamecenter.com/

About :

Hi All …….. I was playing Tomb Raider 2 some time ago. After playing a little, I
So that is why I decided to make my own that really worked. And I did….. now Im
This game uses the most different and interesting process of finding all guns …….
U can get that by reading tutorials on different Memory Finders …. Which u can fi

Audience : Game hackers who have been hacking for some time ..... This tutorial

Abbreviations Used In This Tutorial :

1) TS ====> T-Search , our memory Find

2) TMK ====> Trainer Maker Kit 1.5, our tr

3) Min. the game. ====> Minimize the game by press

4) TR2 ====> Tomb Raider II, the game we r

5) Save Game # 1 ====> Saved game with Lesser weapo

6) Save Game # 2 ====> Saved Game with All weapon

What U Need :

1) Basic knowledge of memory finding. J

2) T-Search ( Read a tutorial on TSearch ) J

3) Tomb Raider II J

4) TMK 1.5 ( for Checking the addresses ) J

Back Ground :

Well we will use the cheat codes for getting the weapon
take one step forward (hold down "shift" while pressing up arrow), then take one
in code, Instead, we shall search for change in offsets for guns. Coz this game
Lets Get Those Damn Guns :

So lets begin guys …..

1. Open up T-Search.

2. Start Tomb Raider II. Start a new game. At this time Lara Croft has the simp

3. Save the game. <--- This is Save Game # 1

4. Now from here, put in the Cheat Code so that ur Lara has all weapons.

5. Save the game here, but under the previous saved game. <--- This is Saved Ga

6. Load the Saved Game # 1.

7. Min the game ..... into windows. Bring up TS.

8. Select the process to hack= TOMB2.EXE.

9. Press the Big magnifying glass ( Start Search ). It searches for some time an

10. Now go into TR2. Load the Saved Game # 2 in which Lara has all the weapons.

11. Min the game again. Bring up TS.

12. This time press the smaller Magnifying Glass. Select Type = 2 Bytes and selec

13. Go back into TR2. Load the Saved Game # 1 which has lesser weapons.

14. Min the game.

15. Repeat steps no. 9-12 .... But press the small magnifying glass only ...... U
Now the addresses dont lessen .... U keep on doing steps 9-12 but u keep getting

16. Trial And Error Method : Load the Save Game # 2 ( wid all weapons ). Min the
U might be lucky if some of the weapons have changed ..... like .... in place of

17. Check the addresses u had frozen for the address that changed the weapon in t

18. Repeat step # 17 until u get 5 values which change the weapons in the invento

19. But the problem is that the weapons only change in place of some other weapon

Theory :

Now time for some theory ...... I mean ... Before getting u to get All Weapons I
That means there r only 6 Slots for items. When Cheat is On, there r 11 items, so

20. Now if u look at the address in the Left hand portion of Tsearch ... where al

21. Unfreeze all the values, if u have frozen any. Load game # 2. U have all weap

22. Min the game , come into TSearch.

23. U have found 6 addresses up till now. Freeze them at their current values now

24. Go in the game and load Game # 1. Check the inventory. U will have all weapon
EXPLANATION :

In case u dont know what we have dun uptil now ...... Here is the Explanation. Wh
there r 11 slots ...... so the thing at number 6 lot night go to slot # 11 when t
because the weapons have increased but there r not enough slots 2 put them into.

25. Check TSearch ....... Check the values at which u get all guns.

26. To check the addies. In TMK poke these addresses wid their respective values
the Slots number is changed to 11 and the respective slot of the items is also ch

NOTE :

U r welcome to ask questions and give critic's view on this tutorial so that I ca
|
· ·-------=+=---· ·
ÜÜÜÜÜÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ|
Û²²²²²²²²²²²Û±± Û²²²²²²²²²²²Û±± Û²²²²²²²²²²²²²²Û±± ÛÛÛÛÛÛÛ±±
Û²²²ÛÛÛÛÛ²²²Û±±°° Û²²ÛÛÛÛÛÛÛ²²Û±±°° ßßßßßßßÛ²²²²²²Û±±°° ±±±±±±±±±°°
Û²²²²²²²²²²²Û±±°° Û²²²²²²²²²²²Û±±°° Û²²²²²²Û±±°° °°°°°°°°°°°
ÛßßßßßßßßßßßßÛ±±°° ÛßßßßßßßÛßßßß±±°° Û²²²²²²Û±±°° ÜÜÜÜÜÜÜ
Û²²²²²²²²²²²²Û±±°° Û²²²²²²²²Û±±°° Û²²²²²²Û±±°° Û²²²²²Û±±
Û²²²ÛÛÛÛÛÛ²²²Û±±°° Û²²²Û²²²²²Û±±°° Û²²²²²²Û±±°° Û²²²²²Û±±°°
Û²²²ßßßßßß²²²Û±±°° Û²²²ÛÛÛ²²²²Û±±°° Û²²²²²²ßßßßßßÛ±± Û²²²²²Û±±°°
Û²²²²²²²²²²²²Û±±°° Û²²²ÛÛÛÛ²²²²Û±±°° Û²²²²²²²²²²²²²Û±±°° Û²²²²²Û±±°°
ßßßßßßßßßßßßßß±±°° ßßßßßßßßßßßßß±±°° ßßßßßßßßßßßßßßßß±±°° ßßßßßßß±±°°
±±±±±±±±±±±±±±±±°° ±±±±±±±±±±±±±±±°° ±±±±±±±±±±±±±±±±±±°° ±±±±±±±±±°°
°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°°°°° °°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°

Tutorial on Code Injection - Part 2 by brzi*


********************************************
brzi@devious.tsongkie.com*
**************************
RELEASED UNDER DEViOUS (http://devious.tsongkie.com)*
*****************************************************

Well after a week or two or maybe more of doing nothing just standing in front of
looking at the screen and drinking i have decided to write another tutorial on co
I hope you liked my first one :). But in that i have told you how to do the stand
injection method which is boring. In this tutorial i'm going to show you how to i
functions. Well as my first tutorial of this kind i'm going to show you how to in
Message Box. In my next tutorials i'll show you some more stuff (if i have time t
tutorials because the school year has just began. So lets start our little tutori
Tsongkie's Code Cave Tool for searching a code cave and we will inject our Messag
mean we will inject the messagebox into Tsongkie's Code Cave Tool. Wait u'll see

TOOLS NEEDED
************

Windows Disassembler - W32Dsm89 - www.gamehacking.com


Tsongkie's Code Cave Tool - www.tsongkie.com
TSearch v1.6 - www.gamehacking.com
API Reference
Pen and a Piece of Paper

LESSON START
************

Explanation of the MessageBox API taken from the API reference:

The MessageBox function creates, displays, and operates a message box. The messag
an application-defined message and title, plus any combination of predefined icon
buttons.

int MessageBox(

HWND hWnd, // handle of owner window


LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);
Parameters

hWnd

Identifies the owner window of the message box to be created. If this parameter i
the message box has no owner window.

lpText

Points to a null-terminated string containing the message to be displayed.

lpCaption

Points to a null-terminated string used for the dialog box title. If this paramet
the default title Error is used.

uType

Specifies the contents and behavior of the dialog box.

*NOTE: Unlike other programming languages in ASM parameters are pushed into the s
In ASM you have to push the caption first, then the main text, followed by the wi
and then the call the MessageBoxA.

Ok now open W32Dsm89 and disassemble Tsongkie's Code Cave Tool. After the Disasse
click on the StrnRef button on the toolbar. Now double click on the string in the
says "Tsongkie's Code Cave Tool v1.0". I have this code:

* Possible StringData Ref from Data Obj ->"About Tsongkie's Code Cave Tool"
|
:00401089 6849304000 push 00403049 <- pushes the location of the c

* Possible StringData Ref from Data Obj ->"Tsongkie's Code Cave Tool v1.0"
|
:0040108E 6869604000 push 00403069 <- pushes the location of the m
:00401093 FF3558324000 push dword ptr [00403258] <- push the WndHandl

* Reference To: USER32.MessageBoxA, Ord:01BBh


|
:00401099 E85E010000 Call 004011FC <- Calls MessageBoxA
:0040109E EB1A jmp 004010BA |
........... |
........... |
|
* Reference to: USER32.MessageBoxA, Ord:01BBh |________
| |
:004011FC FF2524204000 Jmp dword ptr [00402024] <-

Now we know everything that we need. Lets do some testing :)


Open TSearch and click on EasyWrite.

// Begin TSearch script

offset 00401089
//jmp to our code cave
jmp 0040DC17
offset 0040DC17
//Recreate all the stuff
//push the caption of the msgbox
push 00403049
//push the main text of the msgbox
push 00403069
//push the window handle
push dword ptr [00403258]
//call the MessageBoxA API
call 004011FC
//jmp back after the call or the program will crash
jmp 0040109E

// End TSearch script

Now if you run Tsongkie's Code Cave Tool and enable the script and then press the
it will display you the standard Message "Tsongkie's Code Cave Tool ....". It mea
injection is succesfull and everything is fine.
Now the other part - our strings (the caption, main text). I have marked the new
|NEW| .

// Begin TSearch script

//First we will write our strings

//|NEW| Our caption


offset 0040DCA7
asc "brzi's CI tut2"
hex 00
//hex 00 is a null terminator needed for all strings

//|NEW| Our Text //I couldn't think of anything good for the text so let it be "
offset 0040DCBB
asc "Hello !"
hex 00

offset 00401089
//jmp to our code cave
jmp 0040DC17

offset 0040DC17
//Recreate all the stuff
//|NEW| Change the original caption "About Tsongkie's Code .." to our "brzi's CI
push 0040DCA7

//|NEW| Chande the original text "Tsongkie's Code Cave..." to our simple "Hello !
push 0040DCBB

//push the window handle


push dword ptr [00403258]

//call the MessageBoxA API


call 004011FC

//jmp back after the call or the program will crash.


jmp 0040109E

//End TSearch script


Now if you press the about button a message saying "Hello !" will be displayed.
Congratulations ! You have injected your first Message Box!

Well that's it for now, i hope you understood how this thing works so you may try
something by your self. Until next time CYA.

GREETS:
*******
Stoner,Tsongkie,Omega,Micral,EEDOK,InvadeR,Bie,VBTrainer and everybody else that
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@
@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@
@@! @@@ @@! @@@ @@@ @@!!@
!@! @!@ !@! @!@ @!@ !@ @!
@!@!!@! @!@!!@! !!@! @@@!!
!!@!@!!! !!@!@! !!@ !!!!!
!!: !!! !!: :!! !!!::!!! !!::!
:!: !:! :!: !:! !:!:!::! :!:!!
:!!:::!! :: ::: ::!: :::!
::!!:!! : : : : ::
:::
:

Tutorial on Code Injection - Part 3 - Injecting a ShellExecute API by brzi


¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Released under DEViOUS (http://www.devious.tsongkie.com)
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
brzi@devious.tsongkie.com
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Best viewed in WordPad, font Courier New, Regular, 10

TABLE OF CONTENTS
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1. Introduction
2. Tools Needed
3. API Explanation
4. The Injection
5. Final Words
6. Greets

1.INTRODUCTION - a short one :)


**************

Well here i'm again, in front of my PC writting another tutorial as I


promised in my previous tutorial. In this one i'll show you how to inject
a very useful API function called ShellExecute. It is used for many things
as opening documents, executable files, webpages and so on. Again i'll use
Tsongkie's Code Cave Tool because:
1. It's a very good and useful program.
2. It has a lot of functions that we can use.
3. Because Tsongkie is the author and he's a good friend of mine and he
wont be angry if we play with his progie as long as it used for learning
or will you Tsongkie??? I know that this is not a real "introduction"
but who gives a f**k... Let's continue..

2.TOOLS NEEDED
**************

-> TSearch - www.gamehacking.com


-> Tsongkie's Code Cave Tool - www.tsongkie.com
-> W32Dasm89 - Windows Disassembler - www.gamehacking.com
-> API reference - i had a link for this but i forgot it, sorry :)
-> Piece of paper

3. API EXPLANATION
******************
As i sad well use ShellExecute Api for this tutorial. The explanation is a
little long but it's very good. Here it is ..

The ShellExecute function opens or prints a specified file. The file can be
an executable file or a document file. See

HINSTANCE ShellExecute(

HWND hwnd, // handle to parent window


LPCTSTR lpOperation, // pointer to string that specifies operation to perfor
LPCTSTR lpFile, // pointer to filename string
LPTSTR lpParameters, // pointer to string that specifies executable-file par
LPCTSTR lpDirectory, // pointer to string that specifies default directory
INT nShowCmd // whether file is shown when opened
);
Parameters

hwnd

Specifies a parent window. This window receives any message boxes that an
application produces. For example, an application may report an error by
producing a message box.

lpOperation

Pointer to a null-terminated string that specifies the operation to perform.


The following operation strings are valid:

String Meaning

"open" The function opens the file specified by lpFile. The file can be
an executable file or a document file.

"print" The function prints the file specified by lpFile. The file
should be a document file. If the file is an executable file, the function
opens the file, as if "open" had been specified.

The lpOperation parameter can be NULL. In that case, the function opens the
file specified by lpFile.

lpFile

Pointer to a null-terminated string that specifies the file to open or


print. The function can open an executable file or a document file.
The function can print a document file.

lpParameters

If lpFile specifies an executable file, lpParameters is a pointer to a


null-terminated string that specifies parameters to be passed to the
application.
If lpFile specifies a document file, lpParameters should be NULL.

lpDirectory

Pointer to a null-terminated string that specifies the default directory.

nShowCmd
If lpFile specifies an executable file, nShowCmd specifies how the
application is to be shown when it is opened. This parameter can be one of
the following values:

Value Meaning

SW_HIDE Hides the window and activates another window.


SW_MAXIMIZE Maximizes the specified window.
SW_MINIMIZE Minimizes the specified window and activates the next top-level
window in the Z order.
SW_RESTORE Activates and displays the window. If the window is minimized or
maximized, Windows restores it to its original size and position.
An application should specify this flag when restoring a minimized window.
SW_SHOW Activates the window and displays it in its current size and position.
SW_SHOWDEFAULT Sets the show state based on the SW_ flag specified in
the STARTUPINFO structure passed to the CreateProcess function by the
program that started the application. An application should call ShowWindow
with this flag to set the initial show state of its main window.
SW_SHOWMAXIMIZED Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE Displays the window as a minimized window.
The active window remains active.
SW_SHOWNA Displays the window in its current state. The active window
remains active.
SW_SHOWNOACTIVATE Displays a window in its most recent size and position.
The active window remains active.
SW_SHOWNORMAL Activates and displays a window. If the window is
minimized or maximized, Windows restores it to its original size and
position. An application should specify this flag when displaying the
window for the first time.
If lpFile specifies a document file, nShowCmd should be zero.

Return Value

If the function succeeds, the return value is the instance handle of the
application that was run, or the handle of a dynamic data exchange (DDE)
server application.
If the function fails, the return value is an error value that is less than
or equal to 32. The following table lists these error values:

Value Meaning
0 The operating system is out of memory or resources.
ERROR_FILE_NOT_FOUND The specified file was not found.
ERROR_PATH_NOT_FOUND The specified path was not found.
ERROR_BAD_FORMAT The .EXE file is invalid (non-Win32 .EXE or error in .EXE
image).
SE_ERR_ACCESSDENIED Windows 95 only: The operating system denied access
to the specified file.
SE_ERR_ASSOCINCOMPLETE The filename association is incomplete or invalid.
SE_ERR_DDEBUSY The DDE transaction could not be completed because other
DDE transactions were being processed.
SE_ERR_DDEFAIL The DDE transaction failed.
SE_ERR_DDETIMEOUT The DDE transaction could not be completed because the
request timed out.
SE_ERR_DLLNOTFOUND Windows 95 only: The specified dynamic-link library
was not found.
SE_ERR_FNF Windows 95 only: The specified file was not found.
SE_ERR_NOASSOC There is no application associated with the given filename
extension.
SE_ERR_OOM Windows 95 only: There was not enough memory to complete the
operation.
SE_ERR_PNF Windows 95 only: The specified path was not found.
SE_ERR_SHARE A sharing violation occurred.

4. THE INJECTION
****************

First let's explore Tsongkie's Code Cave Tool a little. If you run it you
will see that it has:
1. A logo -> This does nothing
2. A listbox -> Display Code Cave's found in the specified process
3. An EditBox -> You type the Window Name here
4. And three buttons:
* Search -> Searches and opens a process with the Wnd Name given
* Help -> Runs the Readme.txt file <- this btn is useful for this tut
* About -> Displays information about who coded the program

So if you press the help button it will open the Readme.txt which can be
found in the program directory or if the file does not exist it will open
your Windows Readme File. Now we will inject the ShellExecute function so
it will open another file or executable. Let's make a little MSGBOX program
that we will use for opening. The first example is in mASM and the second in
Visual Basic. You can use any program you like, this is just an example.

-> MASM - don't type this :)

.386
.model flat, stdcall
option casemap: none

include \masm32\windows.inc
include \masm32\user32.inc
include \masm32\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
MsgText db "Brzi's Code Injection Tut #3",0
MsgCap db "Info",0

.code
start:
invoke MessageBox,NULL,addr MsgText,addr MsgCap,MB_OK
invoke ExitProcess,NULL
end start

Well i think that it is something like this :)


In VB remove the Form1 form and add a module and type this in it

Sub Main()
MsgBox "Brzi's Code Injection Tut #3", "Info", vbOkOnly
End Sub
Compile it.

Ok now let's disassemble the file with W32Dsm89. Click on the ImpFn button
on the toolbar and then double click on the ShellExecuteA function.
I have this code:

:0040106A 6A03 push 00000003 <- whether file is show when open
:0040106C 6A00 push 00000000 <- pointer to string that specifi
:0040106E 6A00 push 00000000 <- pointer to string that specifi

* Possible StringData Ref from Data Obj ->"README.TXT"


|
:00401070 683E304000 push 0040303E <- pointer to filename string
:00401075 6A00 push 00000000 <- pointer to string that specifi
:00401077 6A00 push 00000000 <- handle to parent window

* Reference To: SHELL32.ShellExecuteA, Ord:006Eh


|
:00401079 E890010000 Call 0040120E <- call ShellExecute
:0040107E EB3A jmp 004010BA <- we jmp back here

So now we know everything that we need so run TSearch and open EasyWrite.
I found some code caves so you don't have to bother to search for them.

//[BEGIN TSEARCH SCRIPT - ShellExecute]

//First we will write our .exe name


offset 0040125C
asc "MsgBox.exe"
//change the MsgBox.exe to whatever program you want to run
//NOTE: If you specify only the .exe name then you will have to copy the exe
//to TCCT directory or you will need to specify the whole path but that will
//use lots of bytes

//this is null terminator needed for all string


hex 00

//Now we will write the operation


offset 0040126C

//this is the operation that will be performed


asc "open"
//null terminator
hex 00

//Now we will inject the most important things


//Here we will land when we jump from the main code
offset 0040127C

//whether the file is show when opened


push 00000003

//push pointer to string that specifies default directory


push 00000000

//push pointer to string that specifies executable-file parameters


push 00000000
//push the name of the file to be opened
//this was 0040303E
push 0040125C

//push the operation that will be performed


push 0040126C

//push the handle of window


push 00000000

//call ShellExecute
Call 0040120E

//jump back
jmp 0040107E

//Now we will jmp from the main code to our code


offset 0040106A
jmp 0040127C

//[END TSEARCH SCRIPT - ShellExecute]

This is how to code looks without the explanation

Our Code:

push 00000003
push 00000000
push 00000000
push 0040125C
push 0040126C
push 00000000
Call 0040120E
jmp 0040107E

The game code (replaced):

jmp 0040127C
push .....
..........

Well add a hotkey to the script and try it. It opened our program!
Interesting stuff eh.. Or you can replace the MsgBox.exe with TCCT and that
way when you press the help button it will open Tcct.exe.
Until next time cya... Take care :)

5.FINAL WORDS
*************

Always when you do code injection, always poke your code first then the main
code because the game/program will crash in some cases and it is save and
better. And i need a favor - will somebody make me a good ascii logo cuz
mine sucks - please!. For any suggestions/questions, crittics are welcome
mail me at brzi@devious.tsongkie.com
And one other thing.. I think that these tutorials can help you how to learn
to code in ASM ->Tasm. This is how the code will look in TASM way. Just the
function. I'm not saying that i know how to code in TASM, but i know how to
do some stuff so..

push 3
push 0
push 0
push 0040125C
push 0040126C
push 0
Call ShellExecute

->brzi

'at the end of days, at the end of time...


when the sun burns out,will any of this matter?
who will be there to remember who we were..
who will know that any of this had meaning for us...'

6.GREETS
********

+ Stoner + Omega + Tsongkie + EEDOK + Bie + Micral + Invader + VBTrainer +


+ PCP + [sheep] + snow + ddh + rat + SubZero and everybody else..
-> Greets in no special order ...
..::[ Comprehensive Tutorial On Game Hack 2.0 ]::..
Basic Rules For Memory Hacking:
These r the basic rules for memory hacking in games. Almost all tools work on these principles. Here they R :
1. First of all the target game and the Memory Searcher should be ON.
2. In the start .... first Select the process of the target game.
3. For the first search ... all tools have a button. Press it to start the search.
4. All tools have another button for the secondary search like : next search , Sieve , Next etc.
5. To change the value of an address double click on the value and change it.

Well here is another tutorial. This time about GameHack 2.0. It is a very useful game hacking tool with the
ADVANCED search option which is used for searching unknown values. Like energy bars. We will hack the health
in Beans Trainer Tester, Level-1. And We shall also hack the Money and Lives.

Beans Trainer Tester:


A cool tool with the help of which u can test ur experience in game hacking. Open TESTER. Press Pause. And
then press Restart. This will pause the TESTER programme at the beginning. The Level 1 goals r : (1) 1,000,000 cash,
and (2) 10 lives. Although the health is not needed but we can practice on hacking energy bars.

Hacking Health (Advanced Search):


1. First of all ..... start GAMEHACK.
2. Press the first button in the GH window with the picture of two wheels. Another window appears.
Choose the process or window of the game .... In case of Beans trainer Tester choose Trainer::Trainer.
3. Now press the buttons with the bigger binoculars. Another small window appears. Choose the search type
to Advanced. Now press OK. GH will search. When it stops, go back to Tester.Press Unpause. After some
time Your energy decreases. Press PAUSE to stop the tester coz pausing the game before searching is VERY
important. So that our Required values dont change.
4. Come to GH. Press the smaller binoculars. DO NOT CHOOSE THE PROCESS THIS TIME. Now choose DECREASE,
because the energy in the tester has decreased. And choose the TYPE to 2 Bytes (WORD) because the address
for energy is very often stored in WORD(2 Bytes). Press OK. GH will search for some time and then stop saying
that it has found a lotta addresses.
5. No problems. Go in the tester and press Unpause. Again the energy decreases. Press Pause to stop the tester.
6. Now!! We gotta use our upper storey which stores something called a brain. So we saw that the health had decreased.
Press the smaller binoculars again. Just choose DECREASE. Press OK. It searches again . It has again got alot of addresses.
7. Repeat this step again until u get many addresses. I got 16 addresses. The number of these addresses will remain
16 so all these addresses r for health.
8. I used "0040C1D0. And changed the value to 100. My health got full. This address is static in memory ...
This means it will remain same everytime you start a game.

Hacking Money and Lives (Normal Search):


1. Well .. now we need to achieve the actual goals of the Tester. Money and Lives. Press Restart. It will start
the Tester again from 0 time.
2. Look at the cash. Its 100,000. I hope u remember the basic steps of Memory hacking. No. 2 Choose the process of the
game u want to hack in this case Tester. Choose the process in GH. Its Trainer::Trainer.
3. Press the Big Binocular. In the Search method, select Exact Value. In the value tab write the amount u wanna hack.
In our case. The money 100000. In the Type , select 4 bytes. Press OK. It will search and come up with 3 addresses.
Now to know which addresses is the address for money we apply the TRIAL AND ERROR method.
4. TRIAL AND ERROR: We have 3 addies and one of them is the real one. So change the value of one pf them to 1000, change
the second to 2000 and third to 3000. Go to TESTER and unpause it. The value of money will change to one of the above
mentioned numbers. And that address will be the address for the money. The addie I found is : 0040C1D8. Change its value
to 1000000 and u will have accomplished ur goal.
5. I want u to hack the Lives and timer urself.

If u have any problem .... Contact me. I am there 2 Help :o)


Website : www.Extalia.com
The target: Beans' Trainer Tester 1.1
Difficulty Level: 1
Target: Make the money >= 1000000 and make the lives >= 10.
Tools: GameHack 2.0

Essay

This is the first level of the tester, and thus it is the easiest. This is a very simple
and yet common type of "protection". The addresses are in static memory, means that they
do not change from time to time. The address will be the same address each time you load
the game. Static Memory is pretty good for us game hackers, because a trainer can easily
be coded. If it was a dynamic memory type of trainer, a process patcher or a loader would
have been required in order to complete the task.

First Part: The Money


1. Open up GameHack, and select the "Trainer::Trainer" prcoess from the process list.
(The first button of the menu is "Select Process for hacking"). You now have 100000
dollars. Note that number. Click pause at the tester, and switch to GameHack. Click the
binoculars (4th button from the left), and run a search with these values:

Search: Exact Value


Value1: 100000
Type: 4 Bytes

You should have gotten 2 addresses. If you got more than 2 then Un-pause the tester
and wait for the money to be changed. Then click on the "Next Search" button, and do
the same, only with the new value.

2. If you did everything right, you should have 2 addresses left: 40C1D4 and 40C1D8.
One of the two addresses is a false address, that is in charge of the screen display
of the value. Move the 2 addresses to the lower list, and Poke one of them. When I
say POKE, I mean - change the value of the address. How to Poke? Simply click on the
address and change its value to something bigger than 1,000,000. After you have poked
the first address (40C1D4), un-pause the tester and see if the value in the money box
is changed. Did it? Nope.

3. Do the same with the second address. Did the value change? It did. Good, we found
the correct address for the money. In order to "Freeze" the address (meaning that the
value will not change), only click on the little box besides the address' name. if a
green smiley appeard than you did it right.

Second Part: The Lives

1. Look at the Health bar. Whenever it reaches the end, the life amount decrease.
In order to successfully hack the Lives, we first have to hack the Health Bar. Pause
the Tester and go to GameHack. In Search options, search with the "Advanced" option.
Unpause the tester, and let the Health decrease alittle bit. After that, click on the
search again button and with these options:

Search: Decrease
Type: 2 Bytes

Do the same until you got these addresses left: 0040C1D0 and 0052001C. Again, one of
them is "fake". Do the same as step 2 in above to know which one isn't fake.

2. Set the value of the health bar to 0 and freeze it. Now the Lives will decrease
really fast. If you want, you can restart this level in order to have 5 lives. Pause
the tester. Let's say that you have 4 lives now, do this search:

Search: Exact Value


Value1: 4
Type: 1 Byte

Un-pause the tester, and let the lives go down by one, and the pause it again. Do the
same search again, until you have only one address left: 0040C1D2. Poke it to a value
higher than 10, and freeze it, and then un-freeze the Health.

3. Click on "Test", and if you did everything correct, you will get a "Congratulations"
message.

Final Words

The aim of this short tutorial was to introduce the newbies of game hacking into this
world, by the use of a very common training example. The main idea behind this was the
"offset search" method. You search alot of times, and each time the number of correct
addresses decreases, until you find the correct one. As for the number of bytes. If you
are wondering how did I know the correct amount of bytes to seek, well, all I can tell
you is that I did it out of Trial N' Error, and tried all the possibilites until I
had reached to the correct one - a pretty messy job.

Orr

OrrAghion@hotmail.com
=======
Level 2
=======

Programs needed:
Game Trainer

Trainer Goals:

Money at $2,000,000 or over


Lives at 15 or over
Freeze Health at 90% or over

=====
Money
=====

You need to decide on what type you're going to search. Let's say your current mo

So the money is $100000 and the game is paused. So start a search and type 10000

What's that? Found 0? Too bad, it happens sometimes with games. So what next? Wel

=====
Lives
=====

Let's say that you have 5 lives. It's a small number so you use Byte. So change t

Hmm, 0 addresses found. Sometimes, values that are shown are actually different,

======
Health
======

The health is an unknown value so you'll be using the advanced search method agai

I got 2 codes so you might as well add both of them, but don't freeze them yet be

Click on Test and you should've completed level 2 successfully. If any of the cod

Written by ROWE.
The target: Beans' Trainer Tester 1.1
Difficulty Level: 3

Programs needed:
Game Trainer

Trainer Goals:

Freeze Timer
Freeze Money at $1234.56
Freeze Lives at 10
Freeze health over 90%

=====
Timer
=====

I'm persuming that you've read the other tutorials first. So to save you time, yo

=====
Money
=====

Restart the game but pause it straight away. Let's say your money is $5000.00. Be

=====
Lives
=====

Again, the bytes have been reversed. So start the game. You start with 5 lives, s

======
Health
======

You have to be slightly careful with this because the health is sectioned into 3

It's not over yet though. There is another address to find, the one which control

Click on Test and you should've completed level 3 successfully.

Written by ROWE
The target: Beans' Trainer Tester 1.1
Difficulty Level: 4

Tools needed
------------
Softice

INFO
After been asked to do the tut for lvl4 also here i am again ;)
I`ll try and make it as easy to follow as possible but this lvl
is a bit trickier cause it uses floating pointers and registers
to store the values so we`ll c how it ends up.

The Crack/Patch
---------------
First of all you have to have winice loaded.
Then start tester.exe and go to lvl4 and press pause.
Now you can just try to search for all possible combinations for the money
byte,word,dword,float double,asci,asciz. But to save you some time :).. don`t bot
doing that cause we can find all the rutines by just finding the address for the
This might sounds a bit strange to some but what i`m going to do in this tutorial
that i`ll search for the timer address and then break on the timer increase(float
Then trace through a bit of code and then put some new code into the program. The
why we`re going to trace from the timeraddy is that it`ll save us...well you alot
and when you have read this tutorial then you might come up with some other idéa
patch/crack lvl4.

Well enough talking now and let`s get on with the real deal ;)

Let the timer go up to 1, search for 1(float, i used gametrainer), then un-pause
for the next value and continue until you only got 1 addy (it should be 0040D08C)
Now put a breakpoint on memory access on that address (bpm 0040D08C w).
Un-pause and bang..softice comes up then you should land here.

0177:0040CE94 42700000 7C403EC3 E72B4559 E85AEB71 ..pB.>@|YE+.q.Z.


the reason i show the line abowe is that it`s on a function that has to do with t
we land and 42700000 is our health. Well heh i know that we don`t have to do anyt
the health to complete our goals so lets continue ;)
016F:00401A9C D91D8CD04000 FSTP REAL4 PTR [0040D08C] <--timer address
016F:00401AA2 D90594CE4000 FLD REAL4 PTR [0040CE94] <--landing point(h
016F:00401AA8 D80538A14000 FADD REAL4 PTR [0040A138]
016F:00401AAE 57 PUSH EDI
016F:00401AAF C744241000000000 MOV DWORD PTR [ESP+10],00000000
016F:00401AB7 D91D94CE4000 FSTP REAL4 PTR [0040CE94]
016F:00401ABD 0F8418010000 JZ 00401BDB

The first thing we`re going to do is to make the money stay at 1234.
So if we trace until we get to this code snippet

016F:00401C0F 85D2 TEST EDX,EDX


016F:00401C11 751F JNZ 00401C32
016F:00401C13 E8B2150000 CALL 004031CA
016F:00401C18 99 CDQ
016F:00401C19 B9B80B0000 MOV ECX,00000BB8
016F:00401C1E 6A01 PUSH 01
016F:00401C20 F7F9 IDIV ECX
016F:00401C22 8D841724FAFFFF LEA EAX,[EDX+EDI+FFFFFA24] <--- here the
money gets moved into the register.

So basically all we have to do is to change that LEA EAX,[EDX+EDI+FFFFFA24] to


a mov eax,000004D2 (1234) so the 8D841724FAFFFF becomes B8D20400009090 and now
we`re finished with the money goal. So next thing upp is the lifes.

Continue to trace until you reach this code.

These to first rows compares your present health with the health that the present
has to reach before gaining one life. erhmm that sounded a bit strange so i`ll tr
explain it a bit more.
Lets say you have A=10 and B=100 and when A==B you gain a life.
So the FCOMP basically checks if A==B and if so you gain one life and then
the health is resetted and it starts over again. And if A==B a flag is set (AH to

016F:00401C3E D90594CE4000 FLD REAL4 PTR [0040CE94] <- shown health


016F:00401C44 D81D24A14000 FCOMP REAL4 PTR [0040A124] <- compare heal
016F:00401C4A 8BC8 MOV ECX,EAX move X lifes into ECX

016F:00401C4C DFE0 FSTSW AX


016F:00401C4E F6C441 TEST AH,41 this checks AH if we may
and gain another life ;)

016F:00401C51 7516 JNZ 00401C69 if not then jump.


016F:00401C53 41 INC ECX increase lifes by 1
016F:00401C54 6A00 PUSH 00
016F:00401C56 51 PUSH ECX
016F:00401C57 68EB030000 PUSH 000003EB
016F:00401C5C 56 PUSH ESI
016F:00401C5D C70594CE400000004842MOV DWORD PTR [0040CE94],42480000 rese
016F:00401C67 FFD5 CALL EBP
016F:00401C69 5F POP EDI
016F:00401C6A 5E POP ESI
016F:00401C6B 5D POP EBP
016F:00401C6C 5B POP EBX
016F:00401C6D 81C4CC000000 ADD ESP,000000CC
016F:00401C73 C3 RET

Ok so now we know where the lifes increase so to make this crack/patch as easy as
possible i wont insert any new code. Just alter the excisting a tiny bit ;).

check out these 2 rows


016F:00401C4A 8BC8 MOV ECX,EAX move X lifes into ECX
as i said this fucntion moves the lifes into ecx. And on the row below ecx is inc
by 1 after going through the check. so if we always have 0 lifes when we get to t
it will appear as if we have 1 ;).
016F:00401C53 41 INC ECX increase lifes by 1
So what we will do know is that we will change the MOV ECX,EAX to xor ecx,ecx(8BC
And that complete´s the second goal also ;)

Now one problem with this is that you will have to wait for the life to go one ro
that it reaches the xor code and we get our Life=1.

Feel free to send me a mail if you have comments or questions about the tutorial
just send it to xdariuzx@hotmail.com
This tutorial is dedicated to all newbies and/or anyone who just thought that thi
tutorial would help them out...

Well bye for know..maybe i`ll come back with some more tuts...who knows ;) !!!

-----------
© 2001 DudE
-----------
Advanced Game Training Techniques
The Trainer Tester 1.0 coded by Beans
LEVEL 5

What you will learn:


Beans of CES released a great little utility to help people test their skills of
game hacking. It is packed with a file packer called CodeSafe, so you will
not be able to find all the addresses with WinDasm.

NOTE: If you have trouble getting Softice to pop when trying to BPM
on the values in Tester.exe do the following:
1.) First make sure that you remove the semicolons (;) from winice.dat in
your SI install folder under the exports section, so it looks like this:
EXP=c:\windows\system\kernel32.dll
EXP=c:\windows\system\user32.dll
EXP=c:\windows\system\gdi32.dll
2.) You need to only do this once if you haven't done this before. Now
reboot. This now will let you BPX (break point on execution) on all
Windows API.
3.) Go into SI with control+d and type: BPX hmemcpy, now in Tester.exe
select a level and hit the TEST button. SI to pop (You will notice in the
right hand bottom corner it will tell you that it is in tester.exe). From this
point on you can set any BPM that you have, and the exit SI.

Difficulty Level 5:

THE TIMER:
The timer value is stored in a 2 byte word, and it increases. It is stored in
memory the same way you see it, so if you see 13, search for 13. Pause
Trainer Tester. Once you have the right address, pop into SI and type BPX
hmemcpy, now exit SI. Unpause the Trainer Tester and let the timer value
increase, SI should pop due to HMEMCPY. Do a bc *, this will clear all
break points, now do a BPM on the address of the timer that you got, for me
it was 00664BEA. Below is what SI poped on (yellow is the line SI is
currently highlighted on, we all know that it is the line ABOVE the highlight
that wrote something into our address):

:00401d5d 41 inc ecx ;increase value in ecx


:00401d5e 8908 mov [eax], ecx ;move ecx into address in [eax]
:00401d60 8b0df8d34000 mov ecx,[0040d3f8] ;replaces ecx with some
new #

The requirement is to freeze the timer, so if we NOP (hex:90) the inc ecx
(hex:41) in 00401d5d, that will make the timer value never increase.
THE HEALTH BAR:
The health bar is stored in a 4 byte dword, and it decreases. There are two
values, one is the real one (dynamic), and the other is the one screen
display. Pause Trainer Tester. Pop into SI, set a BPX hmemcpy and exit SI.
Unpause Trainer Tester, SI should pop due to hmemcpy. Do a BC *. BPM
on the real address, for me it was 66ea01. Exit SI. Wow, SI popped on the
following:

:00401d98 48 dec eax ;in SI type: ? eax, you will see your value
:00401d9c 8901 mov [ecx],eax ;? ecx results in the dynamic address.
:00401d9c eb39 jmp 39093939 ; i forgot to write this down, its some jmp

To freeze the health meter, NOP (hex:90) the dec eax (48) instruction.

^chaos^

chaos world (c) 1999


Do not distribute as your own
please link here
The target: Beans' Trainer Tester 1.1
Difficulty Level: 6
Target: The Lives meter decreases when the Health reaches 0. We have to make it i
Tools: GameHack 2.0 and SoftICE 3.2x or higher

Essay
I think that basic Assembly language is required in this task. I will, however, g
background on the commands i will use in this tutorial (skip this if you know asm

MOV:
Used to copy data from register to register.
Example:
Mov AX, 12h ;copy 12h into AX
Mov AX, BX ;copy the value inside BX to AX

INC:
Used to increase the value of the register in 1.
it is similar to the ++ command in OOP languages.
Example:
INC DL ;if DL was 1, then now it is 2

DEC:
Used to decrease the value of the register in 1.
Similar to the -- command in OOP languages.
Example:
DEC DL ;if DL was 2, then now it is 1

1. Load the program and select level 6. Open GameHack and select the process "Tra
Pause the program and search in GameHack with the option: Search: ADVANCED. Click

2. Unpause the program, let health meter decrease alittle, and then click on "Nex
with this option: Search: Decrease.

3. Do this few times until you get 2 same values which are less than 100. One of
is incorrect. In order to know which value is correct try to change each one at t
and the one the changes the health meter is the correct one. Delete the other val
of no use.

4. Now the address I got is 67177F, which is probably NOT the same as yours, sinc
dynamic value. Click "Pause" in the program, and type CTRL+D to get into SoftICE.
breakpoint over "hmemcpy" (bpx hmemcpy) and then exit by typing "X".

5. Unpause the program, and SoftICE will break. Clear all breakpoints (BC *), and
breakpoint on memory access over the value you found in GameHack (bpm yourvalue),
get out of SoftICE.

6. The application will break, and you should see something like this:

0177:0040241B 85C0 TEST EAX, EAX ;You land here


0177:0040241D 7E0D JLE 0040242C
0177:0040241F 48 DEC EAX ;Decrease Health meter by 1
0177:00402420 5F POP EDI
0177:00402421 5E POP ESI
0177:00402421 8901 MOV [ECX], EAX ;Copy value of eax into memory ad
0177:00402424 5D POP EBP
0177:00402425 81C4C8000000 ADD ESP, 000000C8
0177:0040242B C3 RET
0177:0040242C A1BCD24000 MOV EAX, [0040D2BC]
0177:00402431 8B08 MOV ECX, [EAX] ;Copy value of memory address [EA
0177:00402433 48 DEC EAX ;Decrease Life counter

In case you don't see the following code snippt, try pressing F11 few times until

7. If you read the beginning then you should probably know what to do. All you ha
change the DEC instruction into an INC instruction at the 00402433 memory locatio
In SoftICE type "A 402433", Enter, "INC EAX", Enter, Esc.

If you did all the above like I did, then you probably seen that the lives are'nt

Last Words
I only learnt about dynamic memory address yesterday, and had a success in this o
operate SoftICE and becase I have Assembly knowledge. If you want to succeed in t
to learn ASM. It is interesting and fun, because otherwise, you have nothing to d

I hope you enjoyed reading this tutorial as much as I did.


feedback, comments, questions, money and hate-letters: OrrAghion@hotmail.com

Signing off,
Orr
The target: Beans' Trainer Tester 1.1
Difficulty Level: 7

Tools needed
------------
Softice only .. :P

INFO
Well after the topic on beans tester i decided to make a little tutorial on it..
so here it is.. It should be quite easy to follow i hope.. ;)

The Crack/Patch
---------------
First of all you have to have winice loaded..what a surprise huh ..oh well
Then start tester.exe and go to lvl7 and press pause.
Now search for the money value(DWORD, you should only get one hit)
And then go into softice and do an bpm on that value (bpm xxxxxxxx w)
now exit softice and press the un-pause button and bang you should be right back
you should land on this code snippet..

016F:00402B85 90 NOP
016F:00402B86 90 NOP
016F:00402B87 90 NOP
016F:00402B88 90 NOP
016F:00402B89 90 NOP
016F:00402B8A 90 NOP
016F:00402B8B 90 NOP
016F:00402B8C 90 NOP
016F:00402B8D 90 NOP
016F:00402B8E 90 NOP
016F:00402B8F 90 NOP
016F:00402B90 8B442404 MOV EAX,[ESP+04]
016F:00402B94 8B4C2408 MOV ECX,[ESP+08]
016F:00402B98 0108 ADD [EAX],ECX
016F:00402B9A C3 RET
016F:00402B9B 90 NOP
016F:00402B9C 90 NOP
016F:00402B9D 90 NOP
016F:00402B9E 90 NOP
016F:00402B9F 90 NOP

ain`t 100% sure that the addresses are the same but that doesn`t matter as you sh
now hhmm you c that the code ADD [EAX],ECX must be the code that does something h
your value/s... so your first try might be just to nope this function and then th
on this function (you would have noticed that the timer doesn`t increase if you n
so what we have to do here is take a look at what the registers look like when th
NOTE
EAX=0066D9CB EBX=00000000 ECX=00000001 EDX=00000001 ESI=0040D2D4
EDI=00000007 EBP=0064FC50 ESP=0064FB40 EIP=00402B9A o d I s z a P c
CS=016F DS=0177 SS=0177 ES=0177 FS=111F GS=0000

ok so what do we have here...hhmm ..c the ECX,, !! and remember ADD [EAX],ECX the
that that value ECX holds increases the timer so what we have to do know is this.

we will change the ADD [EAX],ECX to a CMP ECX,01 just c below...

016F:00402B85 0108 ADD [EAX],ECX


016F:00402B87 C3 RET
016F:00402B88 90 NOP
016F:00402B89 90 NOP
016F:00402B8A 90 NOP
016F:00402B8B 90 NOP
016F:00402B8C 90 NOP
016F:00402B8D 90 NOP
016F:00402B8E 90 NOP
016F:00402B8F 90 NOP
016F:00402B90 8B442404 MOV EAX,[ESP+04]
016F:00402B94 8B4C2408 MOV ECX,[ESP+08]
016F:00402B98 83F901 CMP ECX,01
016F:00402B9B 74E8 JZ 00402B85
016F:00402B9D C3 RET
016F:00402B9E 90 NOP
016F:00402B9F 90 NOP

ok so know you c that i have put that cmp there and if ECX=1 jump to 00402b85
if not return (cause we do not wan`t the money to increase now do we ;)
then we just put the code ADD [EAX],ECX in the address we jump to and then retu
And now just press test and tada the timer increases but the money stands still j
as we wanted it.. ;)

with this crack the life does not decrease any longer either cause ECX holds -1 w
decreasing the lifes so if the tester would want the life decrease to work you wo
to make another compare to -1 .. but that wasn`t needed here so who cares really

As I said before..this was only one way of cracking it..


There are certainly other ways to deal with it by using other other jumps
therefore i have also included some here .. :|

here under are som usefull jumps that can be good to know about ..

JA Jump Above (unsigned)


JAE Jump Above or Equal (unsigned)
JB Jump Below (unsigned)
JBE Jump Below or Equal (unsigned)
JC Jump Carry
JCXZ Jump if CX is Zero
JE Jump if Equal
JZ Jump if Zero (Equal)
JG Jump if Greater (signed)
JGE Jump if Greater or Equal (signed)
JL Jump if Less (signed)
JLE Jump if Less or Equal (signed)
JNA Jump if not Above (unsigned)
JNAE Jump if not Above or Equal (unsigned) (same as JB)
JNB Jump if not Below (unsigned)
JNBE Jump if not Below or Equal (unsigned)
JNC Jump if not Carry
JNE Jump if not Equal
JNG Jump if not Greater (signed)
JNGE Jump if not Greater or Equal (signed)
JNL Jump if not Less (signed)
JNLE Jump if not Less or Equal (signed)
JNO Jump if not Overflow
JNP Jump if not Parity
JNS Jump if not Signed
JNZ Jump if not Zero (Equal)
JO Jump if Overflow
JP Jump if Parity
JPE Jump if Parity Even (PF=1)
JPO Jump if Party Odd (PF=0)
JS Jump if Signed
JZ Jump if Zero (Equal)

You can catch me on the gamehacking forum!!


Also feel free to send me a mail if you have comments or questions about the tuto
just send it to xdariuzx@hotmail.com

Now my greetingz :)
Greetz to: everyone on the gamehacking forum i guess..

This tutorial is dedicated to all newbies and/or anyone who just thought that thi
tutorial would help them out...

Well bye for know..!!

-----------
© 2001 DudE
-----------
Razali Rambli a.k.a Bie Solution For
DEViOUS Trainme Level 1
Download at http://devious.tsongkie.com

******************************************************************************
My Trainer for DEViOUS Trainme Level 1
Hotkeys
=======

F11 = Enable Cheat

Requirement
===========
Both Full Bar = OK
50000 Money = OK
10 Life = OK
No NOP = YES, I use only mov & jmp
EXTRA = When click test, original message change to

'Bie was here to make it easy for you!'

******************************************************************************

This tutorial will show you how to use Tsearch & all it feature
example Calculator, Autohack [Assemble, Register] & explanation
about reading assembly code in game & defeating DMA.

We Must have This


===================
1. Both Full Bar
2. 50000 Money
3. 10 Life
4. No Nopping

Tools Use
=========
TSearch

We Begin!
-------------------------------------------------------------------------------
Money
-------------------------------------------------------------------------------
Search 4 bytes
Found only 1 address
example C7F010, your could be dif because this is dma value
use autohack & we get here

004011d6 B805000000 mov eax,0x5 <--- if we backward, we see this


004011db 294604 sub [esi+0x4],eax <--- we land here

explanation
----------
mov eax,0x5 <--- put value 5 into register eax
sub [esi+0x4],eax <--- subtract value inside dma with 5,
in this case, the value is money
solution
--------
change value at 004011d6 from 5 to 50000
use Calculator
in Dec, type 50000
now click Hex & value turn to C350
so on autohack, right click on 004011d6 & assemble
type this

mov eax,0xC350 <--- put value 50000 into register eax

instead of subtract the value, we just move the value


so on autohack, right click on 004011db & assemble
type this

mov [esi+0x4],eax <--- put value 50000 into dma

this mean, the value inside dma is always 50000

the result
-----------
004011D6 B850C30000 mov eax,0xC350
004011db 894604 mov [esi+0x4],eax

Trainer Maker Kit Code


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

Poke 4011D6 B8 50 C3 00 00 89 46 04

-------------------------------------------------------------------------------
First Bar
-------------------------------------------------------------------------------
Remember money opcode? yes this

004011d6 B805000000 mov eax,0x5


004011db 294604 sub [esi+0x4],eax <-- decrease money
004011de B805000000 mov eax,0x5
004011e3 294608 sub [esi+0x8],eax <-- decrease someth

at 4011e3 decrease something, hmm... let found what inside esi+0x8


right click on 4011e3 & choose register
click register tab & enabled the left box, if enabled, it turn red
at register table, change EAX into ESI
now unpause trainme
then pause it again & look at register>original value.
for me, original value for ESI is d7f00c, now let add ESI with 8.
why? because esi+0x8.
i got D7F014
now we go back to tsearch & add new cheat with address we found.
poke it & u will see the top bar wont decrease.

explanation
-----------
mov eax,0x5 <--- put value 5 into register eax
sub [esi+0x8],eax <--- subtract value inside dma with 5,
in this case, the value is top bar

solution
--------
change value at 4011de from 5 to 100
use Calculator
in Dec, type 100
now click Hex & value turn to 64
so on autohack, right click on 004011de & assemble
type this

mov eax,0x64 <--- put value 100 into register eax

instead of subtract the value, we just move the value


so on autohack, right click on 4011e3 & assemble
type this

mov [esi+0x8],eax <--- put value 100 into dma

this mean, the value inside dma is always 100

the result
-----------
004011DE B864000000 mov eax,0x64
004011E3 894608 mov [esi+0x8],eax

Trainer Maker Kit Code


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

Poke 4011DE B8 64 00 00 00 89 46 08

-------------------------------------------------------------------------------
Life
-------------------------------------------------------------------------------
For life, you can search using the money method, but that method, even a little
kid can do that, we use the better way. that is to understand the game code.
just like we did for First Bar value.

understanding & explanation


---------------------------
004011d6 B805000000 mov eax,0x5 <-- put 5 into eax
004011db 294604 sub [esi+0x4],eax <-- decrease money by 5
004011de B805000000 mov eax,0x5 <-- put 5 into eax
004011e3 294608 sub [esi+0x8],eax <-- decrease top bar by 5
004011e6 8B4608 mov eax,[esi+0x8] <-- put top bar value inside eax
004011e9 0BC0 or eax,eax <-- if either return true
004011eb 7532 jnz short 0x0040121F <-- go to 40121f
004011ed B864000000 mov eax,0x64 <-- if not, fill 100 inside eax
004011f2 894608 mov [esi+0x8],eax <-- put 100 inside top bar
004011f5 8B460C mov eax,[esi+0xC] <-- hmm... interesting
004011f8 0BC0 or eax,eax <-- if either return true
004011fa 751B jnz short 0x00401217 <-- go to 401217
004011fc 6A00 push 0x0 <-- if not clear
004011fe 6800304000 push 0x403000 <-- show 'Game Over' title
00401203 680A304000 push 0x40300A <-- show message 'You suck...
00401208 FF7508 push dword ptr [ebp+0x8]<--
0040120b E874010000 call 0x00401384 all to exit trainme
00401210 6A00 push 0x0
00401212 E873010000 call 0x0040138A <--
00401217 B801000000 mov eax,0x1 <-- put 1 into eax
jump from 4011fa
that compare if top bar reach
0, decrease life by 1
0040121c 29460C sub [esi+0xC],eax <-- decrease life by 1

First solution
----------
so now, we dont want the jump at 4011eb
the simple method is just nop the jump
but the trainme requirement specificly said no noping
so what we can do?
easy, we use jump
we destroy unuse code at

004011e9 0BC0 or eax,eax

& change it to jump past 4011eb directly to 4011ed

so on autohack, right click on 4011e9 & assemble


type this

jmp 4011ed

Second solution
-----------
this step is necessary because we have to get more than 10 life, but we only have
5 life. so using the same method as money value & top bar value, we change

00401217 B801000000 mov eax,0x1 <-- put 1 into eax


0040121c 29460C sub [esi+0xC],eax <-- decrease life by 1

into this

;00401217 B80A000000 mov eax,0xA <-- put 10 into eax


;0040121c 0089460C mov [esi+0xC],eax <-- put 10 into dma

Trainer Maker Kit Code


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

Poke 4011E9 EB 02
Poke 401217 B8 0A 00 00 00 00 89 46 0C

-------------------------------------------------------------------------------
Second Bar
-------------------------------------------------------------------------------
The final requirement. we put what we have learn before for testing

understanding & explanation


---------------------------
004011d6 B805000000 mov eax,0x5 <-- put 5 into eax
004011db 294604 sub [esi+0x4],eax <-- decrease money by 5
004011de B805000000 mov eax,0x5 <-- put 5 into eax
004011e3 294608 sub [esi+0x8],eax <-- decrease top bar by 5
004011e6 8B4608 mov eax,[esi+0x8] <-- put top bar value inside eax
004011e9 0BC0 or eax,eax <-- if either return true
004011eb 7532 jnz short 0x0040121F <-- go to 40121f
004011ed B864000000 mov eax,0x64 <-- if not, fill 100 inside eax
004011f2 894608 mov [esi+0x8],eax <-- put 100 inside top bar
004011f5 8B460C mov eax,[esi+0xC] <-- hmm... interesting
004011f8 0BC0 or eax,eax <-- if either return true
004011fa 751B jnz short 0x00401217 <-- go to 401217
004011fc 6A00 push 0x0 <-- if not, clear
004011fe 6800304000 push 0x403000 <-- show 'Game Over' title
00401203 680A304000 push 0x40300A <-- show message 'You suck...
00401208 FF7508 push dword ptr [ebp+0x8]<--
0040120b E874010000 call 0x00401384 all to exit trainme
00401210 6A00 push 0x0
00401212 E873010000 call 0x0040138A <--
00401217 B801000000 mov eax,0x1 <-- put 1 into eax
jump from 4011fa
that compare if top bar reach
0, decrease life by 1
0040121c 29460C sub [esi+0xC],eax <-- decrease life by 1
0040121f B801000000 mov eax,0x1 <-- put 1 into eax
jump from 4011eb
that compare if top bar reach
0, decrease bar by 1
00401224 294610 sub [esi+0x10],eax <-- decrease bar by 1

Solution
--------
simple enough

0040121f B801000000 mov eax,0x1 <-- put 1 into eax


00401224 294610 sub [esi+0x10],eax <-- decrease bar by 1

change to

0040121f B864000000 mov eax,0x64 <-- put 100 into eax


00401224 894610 mov [esi+0x10],eax <-- put 100 into dma

Trainer Maker Kit Code


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

Poke 40121f B8 64 00 00 00 89 46 10
-------------------------------------------------------------------------------
THE END
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
FOR ADVANCED USER
-------------------------------------------------------------------------------
In other word, more simple & easy to understand for advanced user

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Money >
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;004011d6 B805000000 mov eax,0x5


;004011db 294604 sub [esi+0x4],eax

;Reset Money to 50000


;--------------------
;004011D6 B850C30000 mov eax,0xC350
;004011db 894604 mov [esi+0x4],eax

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; First Bar >
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;004011de B805000000 mov eax,0x5


;004011e3 294608 sub [esi+0x8],eax

;Reset bar to 100


;----------------
;004011de B864000000 mov eax,0x64
;004011e3 894608 mov [esi+0x8],eax

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Life >
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;004011E9 0BC0 or eax,eax


;00401217 B801000000 mov eax,0x1
;0040121c 29460C sub [esi+0xC],eax

;Reset to 10
;-----------
;004011E9 EB02 jmp 0x04011ED
;00401217 B80A000000 mov eax,0xA
;0040121c 0089460C mov [esi+0xC],eax

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Second Bar >
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;0040121f B801000000 mov eax,0x1


;00401224 294610 sub [esi+0x10],eax

;Reset to 100
;------------
;0040121f B864000000 mov eax,0x64
;00401224 894610 mov [esi+0x10],eax

-------------------------------------------------------------------------------
Trainer Maker Kit
-------------------------------------------------------------------------------
For newbie who want to try this inside Trainer Maker Kit, below is the code

Poke 4011D6 B8 50 C3 00 00 89 46 04 B8 64 00 00 00 89 46 08
Poke 4011E9 EB 02
Poke 401217 B8 0A 00 00 00 00 89 46 0C B8 64 00 00 00 89 46 10

-------------------------
I hope this will help you
Razali Rambli aka Bie
http://bie.cjb.net
razali_bie@hotmail.com
I'm gonna try to do my best to explain this...

Tools: Tsearch, W32DSM98

1. open up tsearch...
2. open up ghme1lvl1.exe
3. press the "pause" buton in the GTM program
4. click on open process in Tsearch and choose GHME1LVL1.exe
5. goto the menu Autohack and choose enabled debugger in tsearch
6. now we have to do a memory search for the life bars
7. do a new search
8. choose unknown search and click on OK
9. click on pause in the GTM level1 program
10. wait until the progress bar on the bottom decrease..
12. click on search next
13. choose "has decrease" and 1 byte for the type
14. repeat 10 and 11 until you get the results
15. you should get the address two address 530044 and 76F01C
16. right double click on the addresses
17. right click on both address and choose autohack
18. goto to the autohack menu and choose autohack window
19. press pause and make sure the bar is running
20. press pause agian to make it stop
21. go back to the auto hack window and you should see 401224 sub [esi+0x10], eax
22. look at the botton of the Autohack window for dissembler and click on it
23. go back on the top and click on 401224 sub [esi+0x10], eax]
24. now go to the window that has 00401224 294610 sub [esi+0x10], eax] and right
25. choose backwords in the menu scroll down until you see
00401217 b801000000 mov eax, 0x1 </===set how much it will subtract
0040121c 29460C sub [esi+0xC], eax
0040121f b801000000 mov eax, 0x1 </===set how much it will subtract

26. right click on 00401217 b801000000 mov eax, 0x1 and choose Assemble from the
27. change mov eax,0x1 to mov eax, 0x0
28. right click on 0040121f b801000000 mov eax, 0x1 and choose Assemble from the
29. change mov eax,0x1 to mov eax, 0x0
30. now you must do this from the other bar

31. do a new search


32. choose unknown search and click on OK
33. click on pause in the GTM level1 program
34. wait until the progress bar on the top decrease..
35. click on search next
36. choose "has decrease" and 1 byte for the type
37. repeat 10 and 11 until you get the results
38. you should get the address two address 76F014 and 53001C
39. right double click on the addresses
40. right click on both address and choose autohack
41. goto to the autohack menu and choose autohack window
42. press pause and make sure the bar is running
43. press pause agian to make it stop
44. go back to the auto hack window and you should see 4011E3 sub [esi+0x8], eax]
45. look at the botton of the Autohack window for dissembler and click on it
46. go back on the top and click on 4011E3 sub [esi+0x8], eax]
47. now go to the window that has 004011e3 294608 sub [esi+0x8], eax] and right c
48. choose backwords in the menu scroll down until you see
004011db b805000000 mov eax, 0x5 </===set how much it will subtract
004011de 29460C sub [esi+0xC], eax
004011e3 b805000000 mov eax, 0x1 </===set how much it will subtract

49. right click on 004011db b805000000 mov eax, 0x5 and choose Assemble from the
50. change mov eax,0x5 to mov eax, 0x0
51. right click on 004011db b805000000 mov eax, 0x5 and choose Assemble from the
52. change mov eax,0x5 to mov eax, 0x0
53. now we need to figure out so open W32DSM98 and load ghme1lvl1.exe
54. ok the money starts with 5000 which is 1388 in hex
55. now go to search menu and choose find text
56. type 1388
57. you should get 004012FC B888130000 mov eax, 00001388
58. 004012FC is the mov eax instruction so 004012FD is the value
59. go back to tsearch and click on the paper to add a new cheat
60. type 004012FD and choose 4 byte and click on OK
61. Change the change the 5000 to 50000
62. go back to the top in W32DSM98
55. now go to search menu and choose find text
56. type 00000005
57. click on find next 3 times in till you get 0040130c B805000000 mov eax, 00000
59. go back to tsearch and click on the paper to add a new cheat
60. type 0040130D and choose 1 byte and click on OK
61. change the value from 5 to 10
62. now goto back GTM level 1 program and click on restart then click on test

-piccahoe
How to beat GTM Level 1 in 5 or less minutes.
---------------------------------------------
What you'll need:
Windasm

Open up Win32Dasm and look at the string references, you may notice an interestin

Detailed steps of what I just said


------------
Open WinDasm
Press Open File to Disassemble
Choose Trainme
Click Strn Ref button
double click Failed message
Look for conditional jump above the function(looks like this):
:004010FD 7718 ja 00401117
Note down the jump address
Repeat for the 2nd reference for it(looks something like this):
:0040111D 7718 ja 00401137
Note and repeat again
:0040113D 7718 ja 00401157
Note and repeat again
:0040115D 7718 ja 00401177
Search and find out there's no more, so you're all done here.
Now Write a single EB to all these jumps to force them.

Now put all this into a trainer.


_______________________________________________________________
|===============================================================|
|TUTORIAL FOR SORINS SECOND TRAINME |
|===============================================================|
|URL:http://www.ghu.as.ro/downloads/Train-me2.zip |
|AUTHOR: GlomYar |
|DATE: 28.12.2003 22:54 |
|TUTORIAL VERSION: 1.1.2 |
|DIFFICULTY LEVEL: Rated Beginner-Intermediate by Sorin |
|_______________________________________________________________|
|===============================================================|
|TOOLS USED |
|===============================================================|
|IDA Pro v4.3 (or W32Dasm v8.93 w/BratPatch v3) |
|SoftIce (would simplify things alot.. if I actually had it) |
|ResHacker v3.4 |
|TSearch v1.6b |
|Win32API reference |
|_______________________________________________________________|
|===============================================================|
|ASSUMES THAT THE READER HAS KNOWLEDGE OF |
|===============================================================|
|How to find CodeCaves |
|How to do Code Injection |
|How to use TSearch |
|At least a bit of assembly |
|_______________________________________________________________|

-[INTRODUCTION]-
I wrote this tutorial per request from Swatto.
It's my first atempt at writeing one so don't expect too much
It does contain some spoilers..so if you're just looking for clues, be aware.
When I used debuggers such as OllyDbg or W32Dasm later on, an error related to NT
would occur when setting any breakpoint causeing the TrainMe to crash. (ERROR_INV
I haven't investigated as to why this happens.
So I dont know wether it's related to bad programming or done on purpose.
There might(in fact I expect there to be) be typos. So no garanties :p

-[WHAT NEEDS TO BE DONE IN ORDER TO SOLVE THE TRAINME]-


1. Ammo for pistol needs to be maxed (240 bullets)
2. Ammo for machinegun needs to be maxed (999 bullets)
3. Ammo for sniper rifle needs to be maxed (15 bullets)
4. (SPOILER) Hidden requirement

-[LET'S BEGIN...]-
We could go about finding the required memory address's in the most common way.
By useing TSearch fireashot-search-fireashot-search method..
But that's no fun and it will potentionally give you less results.
If you got the benefit of access to a debugger, you could do a breakpoint on 'Get
But since I don't, I opened the file in IDA and got a reference to it from the im
(You actually could use TSearch for this, but it's kind of the hard way to do it.
I traced until I got the one involved with the button '1' (change to pistol)
After a little more traceing I landed here..
.text:0040141F mov al, ds:byte_405629 ;Pistol Ammo
.text:00401424 movzx ax, al
.text:00401428 push ax ; uValue
.text:0040142A push 8B9h ; DialogID inside .rsrc s
.text:0040142F push [ebp+hWndParent] ; hDlg
.text:00401432 call SetDlgItemInt

I made a mental note of the intruction "mov al, byte ptr [0x405629]". Then I saw
SetDlgItemInt call. This told me that it would update some dialogitem on the scre
I opened the TrainMe in ResHacker and looked up the dialogID being pushed.(push 0
By useing ResHacker as a reference I worked out that 0x405629, had to be a pointe
and since this happens when you push the '1'button..
It's ergo the address for pistol ammo. The word 'deduction' comes to mind.

.text:00401437 push offset 0x40530D ;lpString "Pistol"


.text:0040143C push 8BBh ; DialogID inside .rsrc s
.text:00401441 push [ebp+hWndParent] ; hDlg
.text:00401444 call SetDlgItemTextA

Went about it the same way as before(useing ResHacker as reference),


but this time the call would update some text on the screen.
The string had to be "Pistol" and when I looked up the address I was
correct in my assumption. I made a note of the adress in case of doing a "weapon

.text:0040144D mov al, ds:byte_40560D ; Pistol Damage


.text:00401452 movzx ax, al
.text:00401456 push ax ; uValue
.text:00401458 push 8BCh ; DialogID inside .rsrc s
.text:0040145D push [ebp+hWndParent] ; hDlg
.text:00401460 call SetDlgItemInt

Same method again. This made me conclude it was the pointer for pistol damage.

.text:00401469 mov al, ds:byte_405626 ; Pistol MaxAmmo


.text:0040146E movzx ax, al
.text:00401472 push ax ; uValue MaxAmmo value
.text:00401474 push 8BDh ; dialogID inside .rsrc s
.text:00401479 push [ebp+hWndParent] ; hDlg
.text:0040147C call SetDlgItemInt ; update screen

Same method yet again. It turned out to be the pointer for the pistols maxammo.

.text:00401481 mov byte ptr [405326], 14h

I made a mental note of this pointer..


Then I repeated all of the above for the machinegun and sniperrifle..
I noticed that the value being pushed to 0x405326 were different for the machineg
This told me that 0x405326 contained info on what's the current weapon selected.
Nice to implement into a trainer..

What information do we currently possess?


Pistol---------------------------------------------------------------------------
.text:0040141F mov al, ds:byte_405629 ; Pistol Ammo
.text:00401437 push offset 0x40530D ; lpString pointer to "p
.text:0040144D mov al, ds:byte_40560D ; Pistol Damage
.text:00401469 mov al, ds:byte_405626 ; Pistol MaxAmmo
.text:00401481 mov byte ptr[0x405326], 14h ; 14h=Pistol
MachineGun-----------------------------------------------------------------------
.text:004014BE push small ds:uValue ; Machine Gun Ammo
.text:004014D2 push offset 0x0405314 ; lpString pointer to "m
.text:004014E8 mov al, ds:byte_40560E ; MachineGun Damage
.text:00401504 push small ds:word_405627 ; MachineGun MaxAmmo
.text:00401518 mov byte ptr[0x405326], 1Eh ; 1Eh=MachineGun

SniperRifle----------------------------------------------------------------------
.text:00401559 mov al, ds:byte_405481 ; Sniper Ammo
.text:00401571 push offset 0x40531F ; lpString pointer to "s
.text:00401587 mov al, ds:byte_40560F ; Sniper Damage
.text:004015A3 mov al, ds:byte_40562E ; SniperRifle MaxAmmo
.text:004015BB mov byte ptr[0x405326], 0FCh ; FCh=Sniper

In order to find a way to freeze the weapons ammo, we have two options.. Either
we could continue traceing the code useing the method above.. or we could use
TSearch and set a breakpoint on the address's. I originaly did do the trace, but
setting a breakpoint is much more efficient. So we do just that and TSearch
gives us the following address's.

401646 dec al :decrease Pistol Ammo


4016D2 dec ax ;decrease MachineGun Ammo
40175D dec al ;decrease SniperRifle Ammo

Nop'ing these will stop the ammo from decreasing.

-[WARNING SPOILER IMMINENT]-


We pushed our correct values for Pistol ammo, MachineGun ammo and SniperRifle
ammo and pressed the 'Test your trainer' button.. But, WTF?, you get an error
message telling you that it isn't working. Now prepare for the SPOILER. What
Sorin forgot to tell you, was that the value for grenades needs to be set to 100,
in order to complete the trainme. Those of you, who might have teared out all of
your hair(if any :p) attempting to figure this out..
I imagine you are loading your shotguns right about now. I sympatize.
I recon this was a strategy to force you into really study the code.
So a complete newbie couldn't just search for the address's and poke 'em and that
If you had access to a debugger, you would quickly notice why it didnt work as yo
could step through the code at runtime. But as said before, I didn't have that lu
Instead I looked at the import table for a reference to MessageBoxA.
Or maybe I just crossreferenced with the error string.( Don't remember).

.text:00401B2D push offset byte_40410E ;where to store the v


.text:00401B32 push hFile ;hFile
.text:00401B38 call ReadFile
.text:00401B3D cmp ds:dword_405666, 0
.text:00401B44 jg short loc_401B91
.text:00401B46 mov al, ds:byte_405611 ;Grenade pointer
.text:00401B4B cmp al, 64h ;do we have 100grenades?
.text:00401B4D jnz short loc_401B91 ;if not give error messa
.text:00401B4F cmp dword ptr ds:unk_40562A, 0
.text:00401B56 jg short loc_401B91
.text:00401B58 cmp al, byte_40410E ;value we got from ghu.tm
.text:00401B5E jnz short loc_401B91 ;If not then give the er

What it basicaly does is to first check if we have 100 grenades. Then if we do,
compares it against the value from ghu.tmp. You're not allowed to crack the
protection, and thats why I suggested that patching the code is the only way to
go. Since your value will be checked against ghu.tmp anyway.

To find the address for grenades I used the same method as before (GetAsyncKeySta

.text:00401799 push 54h ; vKey=T


.text:0040179B call GetAsyncKeyState
.text:004017A0 or eax, eax
.text:004017A2 jz short loc_4017E3 ;if its not our key, jum
.text:004017A4 cmp ds:dword_405479, 1 ;
.text:004017AB jnz short loc_4017E3
.text:004017AD inc ds:byte_405610 ;Dummy pointer?
.text:004017B3 movzx eax, ds:byte_405611 ;address for grenades
.text:004017BA dec eax ;decrease grenades
.text:004017BB push ebx
.text:004017BC push eax ;then push the value onto the stack
.text:004017BD call sub_401E59 ;call anti-cheat sub
.text:004017C2 mov ds:byte_405611, al ;push value onto memory

Now here's the interesting part of the trainme. Inside the "anti-cheater" sub it
first reads a value from a file(c:\windows\ghu.tmp), then compares it to our
grenade value. Then if AOK it writes our decremented value of grenades back into
the file. Then sets certain memory address's involved with the scheme to zero.
So no matter what you poke into 0x405611 the software will know you have cheated
the correct value from ghu.tmp. The only solutions to overcome this protection,
which I can think of, is to patch the code.

Inside Grenades Anti-Cheat Sub---------------------------------------------------


.text:00401EBF pop eax ; pop the decreased grenades back int
.text:00401EC0 cmp byte_40410E, 0 ; Did we have Zero grenades
.text:00401EC7 jz short loc_401F36 ; If we did then jump
.text:00401EC9 dec byte_40410E ; Decrement grenades value fro
.text:00401ECF cmp al, byte_40410E ; Is the value in memory
.text:00401ED5 ______ jz short loc_401F0F ; If it is equal, then ju
.text:00401ED7 | mov al, byte_40410E ; move the value of grenad
.text:00401EDC | mov byte_404120, al ; move value of grenades f
.text:00401EE1 | push 0 ; lpOverlapped
.text:00401EE3 | push offset NumberOfBytesWritten ; lpNumberOfB
.text:00401EE8 | push 1 ; nNumberOfBytesToWrite
.text:00401EEA | push offset byte_404120 ; What to write
.text:00401EEF | push hFile ; hFile
.text:00401EF5 | call WriteFile ; write value at 0x404120 to g
.text:00401EFA | mov al, byte_404120 ; move value in memory i
.text:00401EFF | mov byte_404120, 0 ; zero memory
.text:00401F06 | mov byte_40410E, 0 ; zero memory
.text:00401F0D ___|_____ jmp short locret_401F32 ; jump to return
.text:00401F0F ; ---|--|---------------------------------------------------------
.text:00401F0F | |----> mov byte_40410F, al ; Move value in register
.text:00401F14 | push 0 ; lpOverlapped
.text:00401F16 | push offset NumberOfBytesWritten ; lpNumberOfB
.text:00401F1B | push 1 ; nNumberOfBytesToWrite
.text:00401F1D | push offset byte_40410F ; What to write
.text:00401F22 | push hFile ; hFile
.text:00401F28 | call WriteFile ; Write to ghu.tmp
.text:00401F2D | mov al, byte_40410F ; move value at 0x40410F
|----->Return from call at 0x4017BD
.text:004017CB mov al, ds:byte_405611 ; move value at 0x40561
.text:004017D0 movzx ax, al ; move lower bits into higer bits
.text:004017D4 push ax ; Move value in register
.text:004017D6 push 8BAh ; Move dialogID onto sta
.text:004017DB push [ebp+hWndParent] ; hWnd
.text:004017DE call SetDlgItemInt ; Update screen with new va

How to overcome this obstacle? We could:


1)Code a "loader" which would patch the call "CreateFile" to create the file
ghu.tmp with Read+Write(3h) SecurityAttributes. Thus enableing you to read and wr
to the file outside of the trainme.

2)Code a "loader" which would patch the initial values for grenades to 100
poke 0x40561B 64h ; This would only be helpfull when you start the TrainMe
poke 0x405611 64h ; Not a solution really

3)..or we could do it in the way that would actually work:


<<<<<<<<<<<<<<<<<<<<<EasyWriteScript:BEGIN>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//Find a CodeCave somewhere..
offset 0xCODECAVE
@CODECAVE:
mov byte ptr [0x404120],0x64
ret

//Patch some code inside the grenades "anti-cheat" sub, so it writes our value t
offset 0x401EDC
call @CODECAVE

//Poke correct value into memory, equal to the value written to ghu.tmp
offset 0x405611
hex 64
<<<<<<<<<<<<<<<<<<<<<EasyWriteScript:END>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

After you have done this, you have press 'T' while the trainme has focus in order
Then the our new value for grenades will be written to file too. This will make o

To stop grenades from decreasing NOP these locations


.text:004017BA dec eax ;Decrease Grenade value from memory
.text:00401EC9 dec byte ptr [0x40410E] ;Decrease Grenade val

-[THE SOLVE]-
<<<<<<<<<<<<<<<<<<<<<EasyWriteScript:BEGIN>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//Make Pistol Ammo 240
offset 0x405629
hex F0

//Make MachineGun Ammo 999


offset 0x&40566E
hex E703

//Make SniperRifle Ammo 15


offset 0x405481
hex 0F

//Make Grenades 100


offset 0x405611
hex 64

//Setup CODECAVE
offset 0xCODECAVE
@CODECAVE:
mov byte ptr [0x404120],0x64
ret

//Create call to our codecave


offset 0x401EDC
call @CODECAVE
<<<<<<<<<<<<<<<<<<<<<EasyWriteScript:END>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

After you've done this you've got to change weapons?(shouldn't be nessesary?) and
screen updates and write our new grenades value to ghu.tmp.
An alternative solution to the grenades part of our hack,
would be to create a timer (patching code, redirected to our codecave).
Which, when elapsed, would write our value to ghu.tmp and poke the grenade pointe
(and weapons ammo too if you want).

To give you an idea of how timer works...


Timer Event Check----------------------------------------------------------------
.text:004019AC cmp [ebp+arg_8], 0CDh ; Did the Sniper timer e
.text:004019B3 jnz short loc_4019D2 ; If not move on to next
.text:004019B5 mov ds:dword_405670, 1 ; It did elapse, set "S
.text:004019BF push dword_40411C ; uIDEvent
.text:004019C5 push [ebp+hWndParent] ; hWnd
.text:004019C8 call KillTimer ; Destroy the timer
.text:004019CD jmp loc_401C0A ; jump to end of line

End of line----------------------------------------------------------------------
.text:00401C0A mov eax, 1 ;We have processed all events, En
.text:00401C0F pop edx
.text:00401C10 leave
.text:00401C11 retn 10h

SniperRifle Sub------------------------------------------------------------------
.text:004016F7 cmp al, 0FCh ;Is it the sniper?
.text:004016F9 jnz TrowGrenade ;If not then jump to ThrowGre
.text:004016FF cmp ds:dword_405670, 1 ;Did the timer elapse?
.text:00401706 jnz TrowGrenade ;If it hasn't then jump
.text:0040170C mov ds:dword_405670, 0 ;If the timer did elaps

We could patch location 0x401C0A to call our codecave, it has just enough bytes f
<<<<<<<<<<<<<<<<<<<<<EasyWriteScript:BEGIN>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//Setup codecave
offset 0xCODECAVE ; Find a large enough codecave
@CODECAVE:
cmp [@BOOL],0x1 ; Is the timerset?
je @TimerSet ; if it is then jump
push 0 ; lpTimerFunc
push 1F40h ; Interval
push 0xCF ; nIDEvent
push [ebp+0x8] ; hWnd
Call [0x004030A4] ; Call SetTimer
mov [@uIDEvent], eax
@TimerSet:
cmp [ebp+0x10], 0xCF ; Is it our uniqeTimerId?
jnz @notOurtimer ; if it isn't our timer, then continue onto next
push ebp
mov ebp, esp
cmp byte ptr 0x405625, 0xCB
jnz @OPEN
push 0 ; hTemplateFile
push 80h ; dwFlagsAndAttributes
push 4 ; dwCreationDisposition
push 0 ; lpSecurityAttributes, make this 3h for Read+Write acc
push 3 ; dwShareMode
push 0C0000000h ; dwDesiredAccess
push 0x40406C ; lpFileName
Call [0x40303C] ; Call CreateFileA
@OPEN:
push 0 ; dwMoveMethod
push 0 ; lpDistanceToMoveHigh
push 0 ; lDistanceToMove
push 0x40410A ; hFile
Call 0x40201E ; Call SetFilePointer
push [ebp+0x8]
push 0 ; lpOverlapped
push [0x404106] ; lpNumberOfBytesWritten
push 1 ; nNumberOfBytesToWrite
push [@Grenades] ; lpBuffer, what to write
push 0x40410A ; hFile
Call 0x402024 ; Call WriteFile
mov al, byte ptr [@Grenades]; move grenades into register
mov byte ptr [0x405611],al ; poke grenades into memory

//If we want to stop the timer uncomment this


//push @uIDEvent ; push our timerID onto stack
//push [ebp+0x8] ; push handle to window
//Call [0x0040306C] ; call killtimer

//Recreate destroyed code


@notOurtimer:
mov eax, 0x1
ret

//Setup a place to hold our Data


@uIDEvent:
hex 00000000
@Grenades:
hex 64
@BOOL:
hex 00

//Patch the code


offset 0x401C0A
call @CODECAVE
<<<<<<<<<<<<<<<<<<<<<EasyWriteScript:END>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

PS: I haven't verifyed that this actually works


-[CREATING A WEAPONHACK]-
Earlier we found locations which house the value for MaxAmmo, Damage, strFireRate
What we can accomplish with this intel is, for an example, changeing the ReloadTi
Thus makeing the weapon fire quicker(or slower). But if we simply poke the new va
the "FireRate" text will still be the same.
Here's where the address's for strFireRate comes in..
If we wanted only the option of "Very Fast", "Medium" and "Slow" then it would be

Pistol: poke 0x401817 XX ;36h="Very Fast"


;2Fh="Medium"
;40h="Slow"

MachineGun: poke 0x4014D5 XX ;36h="Very Fast"


;2Fh="Medium"
;40h="Slow"

SniperRifle: poke 0x40184D XX ;36h="Very Fast"


;2Fh="Medium"
;40h="Slow"

But we want the option to change FireRate to "Fast" and "Very Slow" too.
The solution is to find yet another codecave, and put the strings there (remember
Now you only have to change the address's being pushed, to reflect the correct st
The MachineGun lacks a timer which makes it harder to do a ReloadTime hack.
A workaround is to create this timer like we did in the alternate grenade solutio
You also need to create the missing code for the MachineGun, so it will check for

You could create a new weapon too if you wanted.


*You would have to create the code for checking if your button (eks: '4') was pre
*Create the missing code for your weapon (eks: what happens if u press 'Fire'?)
*Create the "Screen Update" code. Pushing correct values to correct dialogitem.
*Create timers
*Create memory space to store the data for our new weapon (ammo, maxammo, damage,

-[LAST WORDS]-
This is what I can remember for now. I hope this tutorial helped you in some way.
That it gave you some new ideas and you've learned something from it.
If something is unclear, I made a mistake somewhere, I use an expression incorrec
or if you've got suggestions on how to further improve this tutorial..
You can find the contact information at the bottom.

-[GREETINGS]-
Archead, Legba, Wyerm, TIC, Zyrtech
..to the people at the www.gamehacking.com forum.
..and everyone else i know :)

>>>>>>>>>>>>>>>>>>>>>>>>>
|CopyRight© GlomYar |
|http://glomyar.cjb.net|
|mail:glomyar@c2i.net |
<<<<<<<<<<<<<<<<<<<<<<<<<
[Target: Extalia Trainme 1.0 coded by MiCRaL]
[URL: http://www.s-i-n.com/chaos/exttrainme.exe]
[Objective: Hax0ring timers + Code Injection]

(best viewed at 1024x768)

[PREFACE]
Well it seems that everyone and their mother has a tutorial on code injection, ex
In this tutorial I will show you how to defeat TIMERS in a way in which you are p
have not thought of.

[TOOLS]
WinDasm 8.9
TSearch / Softice

[API CALL REFERENCE]

The SetTimer function creates a timer with the specified time-out value.

Syntax

UINT_PTR SetTimer( HWND hWnd,


UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);

Parameters

hWnd
[in] Handle to the window to be associated with the timer. This window must
be owned by the calling thread. If this parameter is NULL, no window is
associated with the timer and the nIDEvent parameter is ignored.
nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL,
this parameter is ignored. If the hWnd parameter is not NULL and the window
specified by hWnd already has a timer with the value nIDEvent, then the
existing timer is replaced by the new timer. When SetTimer replaces a timer,
the timer is reset. Therefore, a message will be sent after the current
time-out value elapses, but the previously set time-out value is ignored.
uElapse
[in] Specifies the time-out value, in milliseconds.
lpTimerFunc
[in] Pointer to the function to be notified when the time-out value elapses. Fo
information about the function, see TimerProc. If lpTimerFunc is NULL, the system
a WM_TIMER message to the application queue. The hwnd member of the message
structure contains the value of the hWnd parameter.

The KillTimer function destroys the specified timer.

Syntax

BOOL KillTimer( HWND hWnd,


UINT_PTR uIDEvent
);

Parameters
hWnd
[in] Handle to the window associated with the specified timer. This value
must be the same as the hWnd value passed to the SetTimer function that
created the timer.
uIDEvent
[in] Specifies the timer to be destroyed. If the window handle passed to
SetTimer is valid, this parameter must be the same as the nIDEvent value
passed to SetTimer. If the application calls SetTimer with hWnd set to
NULL, this parameter must be the timer identifier returned by SetTimer.

The MessageBoxEx function creates, displays, and operates a message box.


The message box contains an application-defined message and title, plus
any combination of predefined icons and push buttons. The buttons are in
the language of the system user interface.

Currently MessageBoxEx and MessageBox work the same way.

Syntax

int MessageBoxEx( HWND hWnd,


LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType,
WORD wLanguageId
);
Parameters

hWnd
[in] Handle to the owner window of the message box to be created. If this paramet
is NULL, the message box has no owner window.
lpText
[in] Pointer to a null-terminated string that contains the message to be display
lpCaption
[in] Pointer to a null-terminated string that contains the dialog b
title. If this parameter is NULL, the default title Error is use
uType
[in] Specifies the contents and behavior of the dialog box. This paramet
can be a combination of flags from the following groups of flag
wLanguageId
[in] Reserved.

[PART I]
The first thing that we must do is examine MiCRaL's train me program. If
you run exttrainme.exe, you will see that it consists of 4 things:

the dialog :the main window that holds the other objects
a progress bar :this represents the value we want to hack
exit button :this exits the program
info button :this pops up a message box that tells us what
we must do

In most cases you would find the value which is increased by the timer and
put a BPM on it, then you would NOP the instructions that modify the value.
Thats fine and dandy, everyone knows how to do it and its boring. The timer
changes the value of the variable every time that the timer increments.
Here I will teach you another method, we will inject the KillTimer() function
into the program to stop the timer. We will do this by injecting code into
the program that is called by the INFO button. So how does one go about this?
Well I will tell you, but first let me side track for a second to describe
how calling MessageBoxA works.

In VC++ you would type in:


MessageBoxA(HWND, "Extalia Trainme coded by MiCRaL", "Information", MB_OK | MB_IC

The HWND is the windows handle, it tells who owns the window that is ab
be created. Then we have the main text that is to be displayed, you coul
a variable here rather then a string. Next is the caption that goes at the
the message box. Next are the icon and what buttons are to be placed on the messa

One method is to open up WinDasm, click on the IMPORTS, and locate USER32.Mes
double clicking on it will lead you to the part of the code where the MessageBoxA
is called. The other method is to BPX MessageBoxA in softice, both will lead y
same place.

* Possible StringData Ref from Code Obj ->"Information"


|
:004011D9 68CB114000 push 004011CB :pushes the lo
"Information"

* Possible StringData Ref from Data Obj ->"Extalia Trainme"


|
:004011DE 6829304000 push 00403029 :pushes the lo
"Extalia Trai
:004011E3 FF7508 push [ebp+08] :pushes the wi

* Reference To: USER32.MessageBoxA, Ord:01BBh


|
:004011E6 E8F3010000 Call 004013DE ------- :calls Message
:004011EB E98C010000 jmp 0040137C |
|
.. |
.. |
|
* Reference To: USER32.MessageBoxA, Ord:01BBh |
| |
:004013DE FF2528204000 Jmp dword ptr [00402028] <------ :[00402028] c
MessageBoxA

So when we click on the INFO button, it eventually makes it to this routine whe
followed by the main text, then the windows handle, and finally it calls th
chose to JMP to my routine from :004011DE because a) its 5 bytes, same as a
a MessageBox to the user telling him that the timer is enabled / disabled, but I
5 extra bytes of code by pushing the caption information again in my routines. I
EASY SCRIPT to do my code injection since its nice and friendly.

REMEMBER THAT UNLIKE OTHER PROGRAMMING LANGUAGES, PARAMETERS IN ASM ARE PUSHE
IN ASM YOU HAVE TO PUSH THE CAPTION FIRST, FOLLOWED BY THE MAIN TEXT, FOLLOWED
THEN THE CALL TO MESSAGEBOXA. Although in our case we are not going to push the c
in the original code to save some bytes later.

[BEGIN TSEARCH EASY SCRIPT]


offset 004011DE
//this is the location of our new function, its just a
//bunch of 00's that i found so i could over write it
jmp 40142c

offset 40142c
//Lets recreate all the stuff for now
//push the main text of the message
push 00403029
//push the windows handle
push [ebp+08]
//call MessageBoxA
Call 004013DE
//Jump back to AFTER the call to MessageBoxA since we already called it
//if we didn't the program would crash since it would have no parameters
//pushed anymore
jmp 004011EB

[END TSERACH EASY SCRIPT]

So here is what happens when we inject that code:

//the code we replaced//


:004011DE E949020000 jmp 0040142C :jump to my fu

//my new function here//


:0040142C 6829304000 push 00403029 :pushes the lo
"Extalia Trai
:00401431 FF7508 push [ebp+08] :pushes the wi
|
:00401434 E8F3010000 Call 004013DE :calls Message
:00401439 E9ADFDFFFF jmp 004011EB ;jump back hom

If we run the program and turn on the Easy Script, we see that if we press the IN
work normally. Congratulations, you have injected code into the program that redi
then we recreated the pushing of the main text and the handle and then the cal
Great. Next lets store some strings in memory so we can call them later when we
the timer was enabled or it was disabled.

[BEGIN TSEARCH EASY SCRIPT]

offset 40148a
asc "disabled"
hex 00
//hex 00 is a null terminator needed for all strings

offset 401493
asc "enabled"
hex 00

[END TSERACH EASY SCRIPT]

Okay. Before we proceed I must teach you how the SetTimer() and the KillTimer() f
to better understand as to what you are looking for.

Usage: SetTimer(HWnd, RESOURCE_ID, 80, NULL);


Usage: KillTimer(hWnd, 1);
So find the SetTimer function in the trainme.exe, same as you found the MessageBo

:00401259 6A00 push 00000000 :pointer to t


set to null
:0040125B 6A50 push 00000050 :pushes the m
:0040125D 6A02 push 00000002 :pushes the R
:0040125F FF7508 push [ebp+08] :pushes the w

* Reference To: USER32.SetTimer, Ord:024Dh


|
:00401262 E88F010000 Call 004013F6 :Calls SetTim

..
Now find the KillTimer function in the trainme.exe
..

:0040135E FF35A0314000 push dword ptr [004031A0] :pushes timer


:00401364 FF7508 push [ebp+08] :pushes the w

* Reference To: USER32.KillTimer, Ord:0192h


|
:00401367 E860000000 Call 004013CC :Calls KillTi

Okay well now at this point of the tutorial we are going to add that KillTimer Ro
that we created earlier. I added *NEW* to all the lines that are new this time ar

[BEGIN TSEARCH EASY SCRIPT]

offset 40142c
//Lets recreate all the stuff for now
//push the main text of the message

//*NEW* we change the text from MiCRaL's original text to our "disabled" text. *N
push 40148A
//push the windows handle
push [ebp+08]
//call MessageBoxA
Call 004013DE

//*NEW* the KillTimer() routine *NEW*


push dword ptr [004031a0]
push [ebp+08]
call 4013cc

//Jump back to AFTER the call to MessageBoxA since we already called it


//if we didn't the program would crash since it would have no parameters
//pushed anymore
jmp 004011EB

[END TSERACH EASY SCRIPT]

Okay if you want, you are done. If you click on the INFO button it will display a
you click OK the timer will be stopped, so the progress bar will not change any
that the timer affected.

[PART II]
In this part we will add a variable that tells us if the timer is enabled or disa
enable or disable the timer. I have chosen an empty byte at 4014b1 to be my IsTim

your code to date should look like the following:

[BEGIN TSEARCH EASY SCRIPT]

offset 40148a
asc "disabled"
hex 00

offset 401493
asc "enabled"
hex 00

offset 004011DE
//this is the location of our new function, its just a
//bunch of 00's that i found so i could over write it
jmp 40142c

offset 40142c
//Lets recreate all the stuff for now

//push the main text of the message


//we change the text from MiCRaL's original text to our "disabled" text.
push 40148A
//push the windows handle
push [ebp+08]
//call MessageBoxA
Call 004013DE

//the KillTimer() routine


push dword ptr [004031a0]
push [ebp+08]
call 4013cc

//Jump back to AFTER the call to MessageBoxA since we already called it


//if we didn't the program would crash since it would have no parameters
//pushed anymore
jmp 004011EB

[END TSEARCH EASY SCRIPT]

So now what we need to do is add a CMP that will compare the value in our IsTimer
I have marked all new lines with *NEW*

[BEGIN SEARCH EASY SCRIPT]

offset 40142c
//*NEW* check if timer is off
cmp byte [4014b1], 01
//*NEW* jump to our function holding the SetTimer Function
je 401462

//redo the message box call push disabled


push 40148a
push [ebp+08]
call 004013de
//call KillTimer()
push dword ptr [004031a0]
push [ebp+08]
call 4013cc
//*NEW* is timer running flag SET FLAG TO 1, MEANING THAT THE TIMER IS NOW OFF. 1
mov byte ptr [4014b1], 01
jmp 4011eb

//*NEW* our function with the new SetTimer() function in it


offset 401462
//message box changed to "enabled"
push 401493
push [ebp+08]
call 004013de

//set IsTimerRunning flag to yes. 0 = true.


mov byte ptr [4014b1], 00

//recreate the SetTimer() call


push 00000000
push 00000050
push 00000002
push [ebp+08]
call 4013f6
//jump back home
jmp 4011eb

[END TSEARCH EASY SCRIPT]

[FINAL SOLUTION SCRIPT: http://www.s-i-n.com/chaos/extaliatrainme.esy]

[CONCLUSION]
Well thats it, now when you click on INFO it will tell alternate between enabled
We could have also jumped to the ORIGNAL SetTimer and KillTimer in code, but ther
was followed by an exit from the program - the program would quit. So its best th
enjoyed this little code injection tutorial and now you will be able to defeat
This inclues the ones that are so clever as change values rapidly but do not incl

Also if you do not feel like injecting all of this code, it is possible to slow d
SetTimer which is below:

:0040125B 6A50 push 00000050 :pushes the m

Since the timer is usually initialized right when the dialog loads, you would hav
or you could just whip out your trust hex editor and modify it from there so that

P.S.
If you are writing a trainme, there is ABSOLUTLEY NO REASON to pack it. It just m
know how to unpack it and rebuild the PE header to have a working exe. If your
be no reason to hide it with lame anti-debugging techniques/packing it. Leave tha

^chaos^
idxchaos@hotmail.com
www.s-i-n.com/chaos/trainerology.htm

<~~greets~~>
[sheep], MiCRaL, Archmage, MrNOP, Visual Perfection, MiraMax, cppdude.
the people of #gamehacking on efnet
_._____
\ | ____
| | |____|
| |______ ________ _ _______ | \_
| ._ \ ._ \_._ /__|\| |
| |/ / |/ | / | |
_ __| | /_ | | | |_ __ _
__ _ _______________| |____________|_______________
____________________ | | _brzi_________________________
__ |_ | __
|___________________ \____| ___________________________|

[Subject: Killing Timers With Code Injection]


[Target: EEDOK's HackMe 1.1]
[URL: http://devious.tsongkie.com]
[Written by: [brzi] / http://www.brzi.cjb.net / brzi@devious.tsongkie.com]
[23.11.2003 - 9:35 PM]

--------------
[Introduction]
--------------

The reason that i'm writting this tutorial is to help all of those n00b's who ar
get in DEViOUS and in general, how to defeat timers (in a more advanced way). Sin
in they need to defeat EEDOK's HackMe. I haven't seen anyone of them to do that,
help for them. We all like to help these guys who are trying to learn something..
Well yeah until the start to ask too stupid questions like: "What's SoftICE and w
debugger?".. But there's forgivness for everything :)))
Anywayz, this tutorials assumes that u have at least basic knowledge of ASM and u
a simple code injection, since we are going to beat timers with code injection. I
that u should check my previous code injection tutorials and [sheep]'s tutorials.
a good understanding of how things work. Ok, since we're ready let's start...

------------------------------
[Tools and Where to Find Them]
------------------------------

[EEDOK's HackMe]-[http://devious.tsongkie.com]
[TSearch 1.6]-[http://www.gamehacking.com]
[W32Dasm 8.9]-[http://www.gamehacking.com]
[API Reference]-[http://www.win32asm.cjb.net]

-------------------
[Windows API Calls]
-------------------

The KillTimer function destroys the specified timer. The system searches the mess
any pending WM_TIMER messages associated with the timer and removes them.

BOOL KillTimer(

HWND hWnd, // handle of window that installed timer


UINT uIDEvent // timer identifier
);
Parameters

hWnd
Identifies the window associated with the specified timer. This value must be the
hWnd value passed to the SetTimer function that created the timer.

uIDEvent

Specifies the timer to be destroyed. If the window handle passed to SetTimer is v


parameter must be the same as the uIDEvent value passed to SetTimer. If the appli
SetTimer with hWnd set to NULL, this parameter must be the timer identifier retur

The SetTimer function creates a timer with the specified time-out value.

UINT SetTimer(

HWND hwnd, // handle of window for timer messages


UINT idTimer, // timer identifier
UINT uTimeout, // time-out value
TIMERPROC tmprc // address of timer procedure
);
Parameters

hwnd

Identifies the window to be associated with the timer. If this parameter is NULL,
associated with the timer and the idTimer parameter is ignored.

idTimer

Specifies a nonzero timer identifier. If the hwnd parameter is NULL, this paramet

uTimeout

Specifies the time-out value, in milliseconds.

tmprc

Points to the function to be notified when the time-out value elapses. For more i
about the function, see the TimerProc callback function.
If tmprc is NULL, the system posts a WM_TIMER message to the application queue. T
of the message's MSG structure contains the value of the hwnd parameter.

--------------
[Lesson Start]
--------------

Ok, as a standard routine, u would find the value which is increased/decreased b


put a BPM on it and then NOP the instructions that modify that value. Well that's
and it's a n00b way to do it. But we don't have a Pause or a Stop button that wil
from decreasing.. How are u going to do that with the standard searching methods?
Here's what we will do: We will inject the KillTimer function so that when u clic
"Instructions" button the timer will stop and the won't decrease anymore. Btw we
MessageBox to inform us about the timer, but we are goind to save some bytes, so
the standart message.

Open W32Dasm 8.9 and Disassemble EEDOK's HackME and click on ImpFnc button on th
From the list double click on user32.SetTimer function. I have this code..
..............
..............

:004011C3 6A00 push 00000000 <- pointer to timerproc - this i


not used
* Possible Reference to Dialog: DialogID_03E8
|
:004011C5 68E8030000 push 000003E8 <- pushes the miliseconds (3E8 h
1000 dec = 1 second
:004011CA 6A08 push 00000008 <- pushes the resource id
:004011CC FF7508 push [ebp+08] <- pushes the window handle (hWn

* Reference To: user32.SetTimer, Ord:0217h


|
:004011CF E876070000 Call 0040194A <- calls SetTimer

..............
..............

Now double click on user32.KillTimer function.

..............
..............

:004011F0 6A08 push 00000008 <- pushes timer id (this is the


of SetTimer
:004011F2 FF3568314000 push dword ptr [00403168] <- pushes the window

* Reference To: user32.KillTimer, Ord:017Bh


|
:004011F8 E823070000 Call 00401920

And finaly double click on the user32.MessageBox function.

..............
..............

* Possible StringData Ref from Data Obj ->"Trainme"


|
:00401580 6807304000 push 00403007 <- pushes the msgbox caption

* Possible StringData Ref from Data Obj ->"Hack this bitch as many ways as "
->"you can."
|
:00401585 68EC304000 push 004030EC <- pushes the msgbox text
:0040158A FF7508 push [ebp+08] <- pushes the window handle (hWnd

* Reference To: user32.MessageBoxA, Ord:019Dh


|
:0040158D E8A6030000 Call 00401938 <- call MessageBox
:00401592 EB14 jmp 004015A8 <== We will jump back here <==

So, we sad that when the "Instructions" button is clicked, the usual MsgBox will
and our KillTimer code will be executed. So we must jump from somewhere to our co
Ofcourse we will jump from the msgbox caption to our code cave :)
Open up TSearch and start EasyWrite...

// BEGIN TSEARCH SCRIPT - [KILL TIMER] //


//First we recreate all the stuff of the message
//and then we create the KillTimer function

//I found a code cave so won't have to bother

//CODE CAVE CODE


offset 00401D1A

//push the caption of the msgbox


push 00403007

//push the text of the msgbox


push 004030EC

//push the window hanlde (hWnd)


push [ebp+08]

//call MessageBox
call 00401938

//Now the KillTimer stuff

//push the timer id - the id of the timer that is created so we can destroy that
push 00000008

//push the window handle (hWnd)


push dword ptr [00403168]

//Call KillTimer
Call 00401920

//Jump back - remmember the "<==We will jump back here <==" offset
jmp 00401592

//Now we replace the main code with a jmp function that will jump to our code cav
//Remember we jmp from the msgbox caption
offset 00401580

//Jump to our code cave


jmp 00401D1A

// END TSEARCH SCRIPT - [KILL TIMER] //

Ok, now add a hotkey to the script and try it out.. Does it work?? NO!!!!! Yeah
confused me too.. But i found the solution.. What's the problem here...

When the parameters of the SetTimer and MessageBox are pushed the window handle
pushed is "push [ebp+08]", but this is not the same for the KillTimer function..
that i just replaced the window handle that is pushed before the call to the Kill
"push dword ptr [00403168]" to "push [ebp+08]" the same for SetTimer and MessageB
result is: "WORKS!!!!". So here the final TSearch script:

// BEGIN TSEARCH SCRIPT - [KILL TIMER] //

//First we recreate all the stuff of the message


//and then we create the KillTimer function
//I found a code cave so won't have to bother

//CODE CAVE CODE


offset 00401D1A

//push the caption of the msgbox


push 00403007

//push the text of the msgbox


push 004030EC

//push the window hanlde (hWnd)


push [ebp+08]

//call MessageBox
call 00401938

//Now the KillTimer stuff

//push the timer id - the id of the timer that is created so we can destroy that
push 00000008

//push the window handle (hWnd)


push dword ptr [ebp+08]

//Call KillTimer
Call 00401920

//Jump back - remmember the "<==We will jump back here <==" offset
jmp 00401592

//Now we replace the main code with a jmp function that will jump to our code cav
//Remember we jmp from the msgbox caption
offset 00401580

//Jump to our code cave


jmp 00401D1A

// END TSEARCH SCRIPT - [KILL TIMER] //

-------------
[Final Words]
-------------

I don't know what to say, i just hope u learned something from this because it is
Also i would recomend the tutorial from ^chaos^, he has a good tutorial on timers
tutorials on other subjects. http://www.s-i-n.com/chaos is the link to his site.
For more tutorials visit my site. Thank u for reading this tutorial.
Now turn off ur PC and goto bed. U deserve a little sleep :)

--------
[Greets]
--------

Greets in no special order...

[sheep] # Stoner # Synbios # EEDOK # Bie # VBTrainer # Omega # Future666 # ddh #


Omaster (hope u'll forgive me:)) # and everybody on DEViOUS and CES forums # and
--------------------------------
[Copyright© VisualSoft® by brzi]
[http://www.brzi.cjb.net]
[brzi@devious.tsongkie.com]
--------------------------------
‡ Tutorial on ”Code Injection“ by brzi ‡
****************************************
‡ August - 21 - 2003 ‡
****************************************
‡ E-Mail...¦ brzi@devious.tsongkie.com ‡
‡--------------------------------------‡
‡ Team.....¦ DEViOUS™ ‡
‡--------------------------------------‡
‡ Web Site.¦ www.deviousonline.tk ‡
‡--------------------------------------‡
‡ Greets...¦ Tsongkie ¤ Stoner ¤ Omega ‡
‡ Micral ¤ Mini^Me ¤ EEDOK ¤ InvadeR ¤ ‡
‡ snow and everyone that i know :) ‡
****************************************

‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡
‡Dedicated to ..:Omega:.. - MISS YA BRO‡
‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡

****************************************
‡ Tools Needed ‡
‡--------------------------------------‡
‡ SoftIce ‡
‡--------------------------------------‡
‡ Memory Searcher ‡
‡--------------------------------------‡
‡ A PIECE OF PAPER ‡
****************************************

****************************************
‡Links To The Tools ‡
‡--------------------------------------‡
‡SoftIce - I am giving you the latest ‡
‡version of SI - ver. 4.5 ‡
‡www.newhua.com/down/si405w9x.zip ‡
‡Serial #: 4001-2345FB-BF ‡
‡--------------------------------------‡
‡Memory searcher - your choice ‡
‡www.gamehacking.com ‡
‡--------------------------------------‡
****************************************

*** Excuse my English ***


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

‡ Lesson Start ‡
****************

‡ Why learn Code Injection ‡


****************************

ONE: Well if you learn Code Injection you can give yourself a bigger rank
in the gamehacking community,but.. the main reason is that if you know
how to do Code Injection and you have enough ASM knowledge the there is
nothing that can stop you from doing something BAD!! to the game - ofcourse
this is limited by your knowledge of the game and your knowledge of the ASM Langu
TWO: Your are playing your game, ok, you have found your ... lets say health
address... You NOP that address and you have an infinite health.
But you pass the level or you go on the next stage and it doesnt work anymore.
You say: WHAT THE HELL!? Well HELLO !!!! This is DMA!!! It causes your memory
addresses to change everytime you run/restart the game or when you change the
level/stage/map. Well this is fucking annoying, you can stop it by finding the
instruction that decreases your health and by NOP-ing it but what if you want
something more, what if you want something BAD! to the game. Well that can be
accomplished with Code Injection. All you need is included in the Tools and
you have to be willing to learn.
IF KNOWLEDGE IS CRIME, THEN MAY GOD HELP ME. - Remember this sentence.
*NOTE: This is my opinion.

‡ Code Injection Theory ‡


*************************

Code Injection is a method that is used by gamehackers


(advanced gamehackers) to do/achieve something that it cannot be done
with the normal training methods. The main goal of code injection is to
create a path from the Game loop to your own code and after the code has
beed executed you jump back to the Game loop again. I told ya you are only
limited by your knowledge of the game and your ASM knowledge.

‡This is how code injection works:‡


***********************************
1. We find our address.
2. We find a code cave.
3. We modify the instruction at our address to jump to the code cave
where we have written our code.
4. We write our code to the code cave.
5. After the code is executed we jump back to the instruction below the
NOP - if we have to write NOP.
- Try to understand ME :)
*************************

I this tutorial i will use the Programme test by Oliviver.

We will hack the numbers.


Well you open favorite memory searcher and search.
After a little search you should end with only one address.
My address was 41D090.
Put a breakpoint on that address using SoftIce (bpm 41D090 w)
Press the button once.SoftIce should pop.
I have this code:

Code ...

Address OPCODES ASM Instructions

00401384 A390D04100 mov [0x41D090],eax <-move the value of eax into ON SCREEN v
00401389 C644241100 mov byte ptr [esp+0x11],0x0 <- SI pops here
00401385 E86D0D0000 call 0x00402100
........ ........ ...............

Let's say that we want the number to be at 100 so we first


search for a code cave where we will put our code. You can
use SI commands for this or Tsongkie's Code Cave Tool. www.tsongkie.com

‡ What is a Code Cave? ‡


***********************************************************************
‡Code Caves are 00's and 90's in the program code where we ‡
‡can inject our code without infecting the main code. ‡
***********************************************************************

‡How to find a Code Cave using Tsongkie' Code Cave Tool, SoftIce‡
*****************************************************************
The Easy way is Tsongkie's Code Cave Tool:
Start TCCT.
Type the window name of the program/game. In our case type prog test.
Press on Search.
TCCT will find a lots of addresses and display them in the Result Box.
But we wont select any address from this, we will use that old SI way
and then select an address.
---------------------------
The SoftIce way:
In SI type:
TASK
You should see this:
--------------------

TaskName SS:SP StackTop StackBot StackLow TaskDB hQueue

Programm * 0000:0000 0065E000 00660000 0B26 0B87 000


Wordpad 0000:0000 0066D000 00670000 0A9E 0A5F 0000
Explorer 0000:0000 0066C000 00670000 1F9E 1F3F 0000
........ ......... ........ ........ .... ....

---------------------------------------------------------------------------------
NOW Type:
MAP32 Programme test <- here you type the name of the game eg. GTA2
You should see this:
--------------------

Owner Obj Name Obj# Address Size Type


PROGRAME .text 0001 0137:00401000 0001697A CODE RO
PROGRAME .rdata 0002 013F:00418000 000042C8 IDATA RO
PROGRAME .data 0003 013F:0041D000 00007B68 IDATA RW
PROGRAME .idata 0004 013F:00425000 00001BA2 IDATA RW
PROGRAME .rsrc 0005 013F:00427000 00004540 IDATA RW
------------------------------------------------------------------

Now lets check the address that is in the .rsrc line (00427000)
In SI type:
U 00427000 - Press Enter
Now you will be at code location 00427000.
Scroll the window up by pressing Ctrl+Up key and you'll see lots of
addresses like this:

Address OPCODES Asm Intructions

xxxxxxxxx 0000 ADD [EAX],AL


xxxxxxxxx 0000 ADD [EAX],AL
xxxxxxxxx 0000 ADD [EAX],AL

This addresses are called "Code Caves".


Lets pick 00426F80.
This is where we are goind to inject our code.
First we need to replace the function at address 00401384 with a jump
that will jump to our code. So we do this

In SI type:

a 00401384 <enter>
Type jmp 00426f80
Press Esc or Enter

Now we type:

u 00401384 <enter>

Now the address will change from

Address OPCODES ASM Instructions

00401384 A390D04100 mov [0x41D090],eax


00401389 C644241100 mov byte ptr [esp+0x11],0x0
00401385 E86D0D0000 call 0x00402100
........ .......... .................

to

Address OPCODES ASM Instructions

00401384 E9F75B0200 jmp 00426F80 <- jump to our code


00401389 C644241100 mov byte ptr [esp+0x11],0x0
00401385 E86D0D0000 call 0x00402100
........ .......... ...............

At address 00401384 we jump to our code.


By usual we need to write a single NOP but in this case that's not needed.
Why we should write a NOP? - well it this case we dont need but in other
cases here's why:
After we write our jump or call we write a single NOP to even to code.
example
We have this code:

MOV [EDI],AX
MOV EAX,[EDI+14]
MOV ECX,[EAX+50]

Now after we write our jump without the NOP to even the code the code will
look like this:

JMP 000000000 <- some address here


ADD BX, EC <- we jump back here
JE 000000 <- some address here

And when our code is executed and jmp back to the game loop the game/program
will crash . But if we write NOP to even the code it should be like this:

JMP 000000000 <- some address


NOP
MOV EAX,[EDI+14] <- we jump back here - the function that is below the MOV [EDI],
You see that after we have written the NOP the code comes back to normal
and everything will work fine. OK return to the main subject.
OK.. next we need to write our code at the address 00426F80

In SI we type:
u 00426f80 <enter> - this will bring you to the address
a 00426f80 <enter>
type MOV EAX,064h <enter>
type MOV [0041d090],EAX <enter>
type JMP 00401389 <enter>
Press Esc or Enter

Now check. In SI we type:

u 00426f80

and it should be like this:

Address Opcodes ASM

00426F80 B864000000 MOV EAX,00000064 <- now eax has the value of 100 Dec - 64 H
00426F85 66A390D04100 MOV [0041D090],AX <- mov the value of eax into ON SCREEN v
00426F80 E9F9A3FdFF JMP 00401389 <- jmp back to the game code

Now lets check if our Code Injection works. First clear the break points
in SI type bc * <enter> and exit by pressing Ctrl+D. Look at the program.
What !? The value is the same, but wait the program increases the value
everytime you press the button.So press the button few times and you will
see what happens. The value will be 101 cuz the program add one to the value.
If the program crashes then you have wrote something wrong. Check if you have
wrote everything like i told ya.If yes then congratulations you have made
your first Code Injection.

Write the opcodes on a piece of paper. We need the opcodes for later when
we will poke this address with the trainer.

You see that code injection is easy, you just need to practice and everything
will be just fine.Remeber that i told you that you can do some BAD things
with Code Injection.

‡Making the Trainer‡


********************

You just need to poke the addresses like this


Address Bytes2Write
00401384 E9 F7 5B 02 00
Address Bytes2Write
00426F80 B8 64 00 00 00 66 A3 90 D0 41 00 E9 F9 A3 FD FF

‡To Better Understand Code Injection‡


Main Code
00401384 E9F75B0200 --- JMP 00426F80 <- jump to our code
00401389 C644241100 | MOV BYTE PTR [ESP+11],00<-|
| |
Our Code | |
00426F80 MOV EAX,00000064 <-| |
00426F85 MOV [0041D090],AX |
00426F8B JMP 00401389 ------------------------------------- <- jump back
‡Final Words‡
*************

And finaly this tutorial is over. THANKS GOD for that. Now i can get to my
normal life again. IS THERE IS ONE :)

‡Greets:‡
*********

To Sheep for releasing his wonderfull tutorials - check them out www.sheeprec.cjb
To All Members of the DEViOUS Team and everybody that i know.
How to create a trainer for energy bars using GameHack and Master Cheater
I'm using Virtua Fighter to demonstrate how the creation works but I think it can

First of all you should start Virtua Fighter, then ALT-TAB to your desktop and lo
Now select the process you wanna cheat (in that case 'Virtua Fighter PC') by clic
Done ? Allright, let's continue.

Get back to the game (I think you know how to do that...). It's much easier to fi
Once inside the game ALT-TAB (or CTRL-F12) to GameHack. Press that binoculars- bu
Click on OK and return to your game.

As the second player hit player 1 one time and go back to GameHack.
Click on 'Next search andsearch for a 'decreased' value now. GameHack finds a lot
It can be that a lot of adresses are left at the end, so use the 'Trial-and-error

I think those negative values are complete bulls**t, so (in my case) 008E3710 is

Try to enter '255' as the value and go back to the game. Whew, the energy bar loo
Type in '200' and get back to VF. Allright ... everything's normal and click on t
Try to hit player 1 in the game ... the energy fills up everytime he's hit.

GREAT ! Now let's create the trainer using Master Cheater !

STAY INSIDE OF THE GAME, IT WILL MAKE THE PROCESS HANDLE EASIER LATER !! Umm ...
Enter that C8 (Beware ! This is for Virtua Fighter ! This value may not work on o
The program creates a file called vfenergy.mct in its directory which is importan
The BUTTONS TITLE should be 'Energy P1' so that the end user knows what'll happen
Type TMBUILD into the input field and choose the options that will fulfill your n
Start it, minimise it, press CTRL-T inside the game, freeze your energy bar and t

Umm ... that should be it ! :)

If anything goes wrong, you can email me.

And don't forget: 'The world is a beautiful book, for those who can read it.'

Tutorial Written By Space Marine


World of Game Hacking
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|_|_|_|_|_| |_|_|_|_|_| |_|_ _|_| |_|_|_|_|_|
|_| |_| |_| |_|_|_|_|_| |_|
|_| |_| |_| |_| |_| |_| |_|
|_| _ _ _ |_|_ _ _|_| |_| |_| |_|_|_|
|_| |_|_|_| |_|_|_|_|_| |_| |_| |_|
|_| |_| |_| |_| |_| |_| |_|
|_|_ _ _|_| |_| |_| |_| |_| |_|_ _ _ _
|_|_|_|_|_| |_| |_| |_| |_| |_|_|_|_|_|

H H AAAAAA CCCCCC K K I N N GGGGGG


H H A A C K K I NN N G
HHHHHH AAAAAA C KK I N N N G GGG
H H A A C K K I N N N G G
H H A A C K K I N NN G G
H H A A CCCCCC K K I N N GGGGGG

( harmony between Cracking and Game-Hacking )

Target : Worms 2
~~~~~~~~~~~~~~~~

Description : An example to show you that Game-Hacking is Cracking's brother


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Tools Needed : SoftIce ; Pen & Paper


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Level : Beginner(-Intermediate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LET'S START
~~~~~~~~~~~

OK. The purpose of our hack is to find the passwords for all levels of the
game...

So, open the password window, type in a bogus string, hit OK. The game didn't
do anything. It's time to find out its secrets...

We observed that Worms 2 uses a dialog/window where we could type the password.
Open SoftIce (CTRL+D). Let's try to bpx on Windows' API GetWindowTextA and
GetDlgItemTextA. These API are often used by programs for getting the data
inside edit_boxes. So in SoftIce type :

bpx getwindowtexta
bpx getdlgitemtexta

Tip : That "a" in the end of those API stands for 32-bit code. On 16 bit code,
you don't need that "a".

Exit SoftIce (CTRL+D or F5 or type X and hit [ENTER]). Return now in the game's
menu, and go again to the password window. This time, type in the edit-box
your name, for example, or a familiar word. Press OK.

You're now back in SoftIce, at the begining of USER32's GetWindowTextA. Press


F12 once in SoftIce to return to the Worms2 code. You should see this:

CALL [USER32!GETWINDOWTEXTA] -> the API from where we returned


mov ecx, [ebp+10] -> Mmmmmm... (u land here)
push FF -> a parameter to
call 4c09b7 -> call something
jmp 4cf36c -> jump somewhere
.....code....code.......

From above code, we observe this : After API was called, something SUSPICIOUS
is moved in ecx. So, when you're on "push FF" in SoftIce, type

d ecx

Oh, no ! We don't see anything good for us... HEY, but wait a sec ! Look at the
first 4 bytes displayed in SoftIce's display_window! They are :

9C 58 4A 01

Mmmmm... Maybe it's a pointer to something... Let's find out ! Type this:

d 014A589C

You see, we inversed the bytes from right to left. That's how the computers deals
with them...

And in display_window we see the string you typed in the password-box ! It's a le
You can also type :

d *ecx

That "*" in front of ecx tells SoftIce that it's about a pointer, so display the
memory that is NOT in ecx's address, BUT in address pointed by the first 4 byt
stored in ecx! In both ways, you'll get the same result : your string !

Yeah, but what can we do with this ? SIMPLE : since we know where it stored our
string, we set a breakpoint to see when the game compares our string with the
levels' passwords ! To do this, type (in SoftIce, of course) :

bpm *ecx

OR

bpm 014A589C (our find address)

Tip : "bpm" is a breakpoint on memory access. It tells SoftIce to pop when that p
of memory is beeing read from or write to.

If you are in kernel32's code, press F5 until you will be in Worms2 code!
We are in Worms' code. Good! We see something like this :

.........code...code......

49BBA0: mov al, [esi] -> move in al a byte from good_password


49BBA2: inc esi -> go to next char in good_password
49BBA3: mov ah, [edi] -> move in ah a byte from our_entered_string
49BBA5: inc edi -> go to next char in our_entered_string (u l
49BBA6: CMP AH,AL -> comapre the byte from good_pass with the b
49BBA8: jz 49BB9C -> if they are the same, then jump and compar
next bytes.

........code..code....

Now, We landed on "inc edi" instruction, so press CTRL+UP to see the above code.
We know that esi points to the real passwords, and edi to our string. All we
have to do is :

d esi-1

(We dec esi because it has been inc-ed at address 49BBA2 - check above! )
We see the password for first level, that is "ONCEUPONA" !

Yeah, but we need all passwords! To get them, put a

bpx 49BBA0 DO "d esi"

This breakpoint will tell SoftIce to pop when breakpoint is reached and to displa
the memory pointed by esi. (esi was the register for correct password, remembe

All you have to do right now is to sit back in your chair and press F5, then writ
down the password, press F5, write down the password... Got the ideea ?

Very GOOD !
FINAL WORDS AND REMARKS
~~~~~~~~~~~~~~~~~~~~~~~

I start writting this tut when I had a contradiction with the people in GameHacki
forum... I told them that cracking and gamehacking are like 2 brothers, but th
didn't listen... I hope this tut will PUSH in their minds that, and they never
POP it !!!
CHEERS AND GREETS (order doesn't matter)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Groza (BEST publisher :) - I'm still waiting that tut on C&C map_hack :) )
- Snaky (te-am cam copiat putin! hehehe... Ne vedem la un suc :))))
- T-RaiNeR (cum mai e cu facultatea ?)
- ParaBytes (my cracking teacher - a BIG THANKS)
- All in GameHacking's forum (what to say... you are incredible :)
- All GHU members (Suntem de belea, eh ?)
- JUVENTUS AND ALL JUVE FANS & PLAYERS (you make me happy when I'm sad. I love JU
- All crackers in the world ! (you opened a beautiful book for us)
- YOU
romanian:
*******************************
* Salutari celor din Romania! *
*******************************

Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


GHU ( http://www.ghu.as.ro/ ).

2003

eof
OllyDbg Tutorial

Tools Needed :
~~~~~~~~~~~~~~

- Hmm... First we need a hammer, some nails, and of course OllyDbg


- (can your spare_time be considered a tool ?)

Level : "Level 7, Chapter 3 : Escape from Monkey Island"


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

INTRO
~~~~~

".... Centuries ago, in time of darkness...


... by fighting for their lives, by fighting for their honor,
by fighting for their realm... In a tournament called...."
'<<Catch the rat who's eating my breakfast>>'

Lately, more and more people asked me to marry them and to write some Olly tuts.
I see no connection between these 2, but here goes :
- I don't use OllyDbg in gamehacking;
- I am married with Yogi Bear (or Scooby Doo, I don't remember exactly :(

But you know those words : "The newbie is always right". So, I decided to write s
Olly stuff. But like I said, Olly isn't so good in gh like SoftIce, so I'll s
you how to use it in other 'domains', too. Also, some people spamed me and ma
head huge with Olly requests. Here you are, mo' fo's ! Hope you'll like it !

Let's Begin
~~~~~~~~~~~

Let's take a look at Olly's main window, first. To do that, chose a program and o
it inside Olly. I've chosen Mortal Kombat 4. Here's what I've got :
You have 4 BIG windows :

- The Disassembler Window. Here you can see program's code in asm language, a
can comment every line of code.
- The Registers Window. The home of eax, ebx, edi etc. The flags are here, to
like SoftIce's top 'window'.
- The Dump Window. Here you can view/edit in hex or ascii the memory of the p
you want to debug. You can see here what you can see in SotIce after 'd
- The Stack Window - not important to what we'll do.

Also there's something below the Disassembler window : The Tip Window. It's not i
but I call it that way :). When you are at a code line (with the debugging),
you details about that code line. If you're on "mov eax, dword ptr [123]" for
shows you what number is stored at [123]. And many more helpful hints.

Well, that's the 'overview'. You'll learn more while we're debugging some targets
a kind of "learning through doing".

Ok... "Choose your destiny !" :

- Cracking Mortal Kombat 4 (no cd crack) - This is the starting point (READ!)
- Cracking Nightmare Creatures (no cd crack) - Practice what you've already l
- Hacking Mortal Kombat 4 (hitter takes damage) - Olly in gamehacking
CHEERS & GREETS (order doesn't matter)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Groza & NanoBot (- check http://www.grozatt.cjb.net/ & http://www.nanobot2k.org


- Snaky, Biciuila, The_Android, T-RaiNeR, Gran, Mr. Fanta$tic~ (The GHU Team)
- ParaBytes (my cracking teacher - a BIG THANKS)
- All in GameHacking forum
- JUVENTUS (maybe next year...)
- YOU
- and all who publish my work -> I'm thinking of 'retirement'. Maybe I'll write
no more :(
romanian:
*************************************************
* Salutări celor din România! *
* Odihniţi-vă ziua ca să puteţi dormi noaptea ! *
*************************************************
Special Thanks goes to Mr. Fanta$tic~ ! You are a real supplier !

Prof. Dr. Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


"We care about YOU".
GHU ( http://www.ghu.as.ro/ ).

2004

eof

!!! Here we go !!!

Alrighty, then ! Let's hack !

You know how to find health addr. in MK, right ? If not, then maybe this tut
is not for you... (have you heard of mem. finders ? - read some other
beginner tuts, then come back !).

I've found the health addr. (I'm a good boy :) ). They are :
53865C - the health of Player1
535EAC - the health of Player2

Since we want a "hitter takes damage" hack, we need the health addr.

Now... Load MK in Olly, then let it run (F9). Start a 2 player game, and
play a little (hit with both chars.). After this, set in Olly a mem.
breakpoint on player 2's health address. You should now how to do this
from MK no-cd tut. (CTRL+G in Dump Window, insert the health addr., then
select it's first 2 bytes (a word) and right-click on them, then choose
"Breakpoint"->"Memory, on write"). And after this, hit player 2 with
player 1. Olly should pop here :
What is all this crap ? Where are the ASM instructions ? We know this code
is to be executed, but we don't see the instructions !

Well, Olly is not a perfect program. When the target is loaded into Olly,
an analyze of code is started (to give the user useful hints and comments).
And Olly's display is based on the analyze. So our problem could be this
analyze that Olly had some problems with it. Let's remove the analyze to
see if this is the problem. To remove this analyze right-click in
Disassembler Window, then choose "Analysis"->"Remove analysis", like in
the pict. :

And here's the result we've been waiting for :


I commented the code a little :). (after I've done some tracing and checks
that I suggest you do them, too). I've started with this : If player2's
health is held in a STATIC addr., why the game uses pointers ( [eax*4] ) to
work with the health ? With this question in my mind, I decreased
the health of player1 this time, and saw that the same line of code is
executed. But this time [eax*4] holds the player1's health addr. Then
I realize is about flags/registers :) Here I could elaborate a kind of theory

Theory : If you find your wanted addr. NOT being a dynamic addr. and the
game access it with the help of pointers, then the line(s) of
code that's messing with your addr. is used in other actions
by the game, too. Also, if so, the flags/registers are the answer.

I know it sounds logic, but it may help you find some other things done by
the game, things that you might forget to look at...

So, in our example, the same routine is used to decrease the health of both
players. But from where does the game now it's about playerX and not
playerY ? It gotta check something, right ? And this 'something' have
to be executed above the code-line that's modifying the health.

And again I traced and debug until I wrote all that comment.

I've found out that "cmp eax, ecx" at 48E00B is the decision instruction.
If eax=ecx, then player2 hit. Else, player1 hit.

But you want to see it for yourself, right ? OK... Let's set a breakpoint
at 48E00B. But this time a CONDITIONAL breakpoint. Here's how it's done :
(but first remove that mem. breakpoint on player2 health ! you should
know how to remove it from MK no-cd tut !)
Nothing easier : to set a conditional breakpoint at a code-line, you
click it, then right-click it and choose "Breakpoint"->"Conditional".
(or click on it and press SHIFT+F2). After this, a dialog will appear
asking for the condition (conditional breakpoints act like this :
if the condition is met, tell Olly to pop ! hehe :) ). The dialog
is like in the pict :

We'll set the condition to "pop if eax = ecx". In the dialog you must write
"eax == ecx", without any 'if' or something. Also take notice that you
must use assembly code ("==" for equal). After you did this, press OK.
The address on which you've set a conditional breakpoint got 'pink'. Here's
a pict :

And now, let's test to see if I was right about that "eax=ecx if player 2 hit".
Go back in the game and hit with player2. (when I say hit with playerX,
I mean hit with playerX playerY, and not hit with playerX the air). Olly
should pop. Let's look at the registers :

See ? Olly pop when the condition was met. eax=ecx=14893C.

F9 to run the game and hit with player1 this time. WHAT ? Olly don't pop ?
Hit again ! Still no popping ? That's because even if the game executes
that cmp instruction, Olly don't pop 'cause the condition is not met (eax
is NOT equal to ecx). So I was right !!! Eax=ecx ONLY when player 2 hits !

If you still don't believe me, let's remove the conditional breakpoint (with F2)
and put an execution breakpoint in it's place. The execution breakpoint have
no condition, and will tell Olly to pop EVERY time the game executes the
respective instruction (the one on which we've set the breakpoint).

An execution breakpoint is set with the F2. The addr. should get 'red', right ?
Ok. Now back in the game and hit with player1. Olly should pop. Let's look
at the registers :

Wow ! eax=14895D and ecx=14893C. So I was definitely right.

Now, we'll try to do the "hitter takes damage" hack. For this we'll need a code-c
where we'll put our instructions. To find a code-cave, we must know how and
where is mapped the game's memory. And to find this out, we just press
ALT+M in Olly. Here's what we've got :

Usually we search for a code-cave (lots of 00s) at the end of the .data section.
In our example, end_of_.data = beginning_of_.rsrc = F9F000 address. We'll loo
for our code-cave just above F9F000. I think F9EE70 is a good place.

Now, set focus to the Disassembler Window, press CTRL+G (go to), and enter 0F9EE7
our code-cave address. (must start with 0 or Olly finds it invalid). Here's
what you should find :

See ? Lots of 00s. Now return to 48E00B (with CTRL+G, of course). We're going to
jump from 48E00B to 0F9EE70. At F9EE70 we'll inject our code, then we'll jump
back to an addr. below 48E00B. Here's the plan :
Ok. CTRL+G and go back to 0F9EE70. Double-click that line and assemble this code

cmp eax,ecx --\


mov dword ptr [53ffc8],eax \ these instructions are carried in the cave
mov dword ptr [54000c],edx --/ (they are unchanged, cut from game's routine)
jne 48e023 ----> the original instr. was a 'je', but we changed
it to 'jne' for our hack to take effect
jmp 48e01a ----> we jump back to first instruction that we hadn't
carried in the code-cave

Here's what you should have :

Now return to 48e00b. Double-click that line and assemble this :

jmp 0f9ee70

Here's what you should have :

And now all you have to do is to play ! (remove first all breakpoints you could
have).

Happy ?

Of course you could have done this hack by changing the 'je' at 48e018 into
'jne', without all this code-injection that practically do the same thing,
but you work 'harder'. BUT since this is a Olly tut, I wanted to show you
the code-cave hacking with Olly :) Satisfied ? ;)))

!!! Thanks !!!

- to Mr. Fanta$tic~ for supplying me this game.

Prof. Dr. Sorin ( Splinter@email.ro )

http://www.ghu.as.ro/
OllyDbg visual crash course - for gamehackingBy: EEDOK
Mr_eedok@hotmail.com

First off you would want to open Ollydbg before opening the game, then open the game through
Ollydbg like so:

Once Ollydbg is opened you would hit the C (which is outlined with orange and has an arrow
pointing towards it) to bring up the main CPU screen, which would look something like this:

Once at this point you would want to hit F9 until the game you are playing is running normally, and
whip out your favorite memory searcher to find the address which you want to set a breakpoint on.
Once you have found the address you wish to hack in your memory searcher you would alt+tab back
to Ollydbg and click on the CPU - main thread window and hit Ctrl+G, a window such as this would
pop up:

In the combo box of the window that comes up(where it says 41D090 in the example) is where you
would want to put the address on which you would want to set a breakpoint on. Upon entering your
address, it should take you to your address under the dump(bottom left side of CPU - main thread
window), from here you would right click your address to bring up this menu:
The 2 different breakpoints are as follows:

Memory, on access - Makes the program break whenever the address is read.
Memory, on write - Makes the program break when the address is written to (Tsearch Default).

Shouts to:

Devious: Stonerifik, Tsongkie, Omega, Synbios, Micral, Mini^Me, brzi, Invader, Sn0w

renzo, bie, ddh, Vortexion, routine_error, [Ginger], Ultimate, Zekk

Web sites:
Devious
Mine
################################################
# [Artmoney Explained by InvadeR ] part 1 #
################################################
# #
################## #
#[ Info About Tutorial ]# #
################## #
#This tutorial is designed to explainArtmoney and what it can#
#do and how it works to beginners. #
################################################
# Contents of part 1: #
#Buttons explained, Searches explained. #
#################################

##############
[ Select Process ]
##############
This is the first thing you do when memory scanning. You want to select the proce
you are going to memory scan.

########
[ Buttons ]
########

###[ Search Button ]###

After you have chosen the process/program you are going to memory scan you can op
window and choose how you want to search. The options for searching and what they
as follows:
--#[Search]#--

-Exact Value is for when you know the exact number you are searching for.
####
-Sequence Of Values is for when you are searching for a group of address's that c
what you are looking for but you don't know which has it.
####
-Range is for when you know the general area of the number but you don't know exa
where it is.
####
-Unknown Value is for when you have no clue what your value is or your just searc
anything.
####
-Coded Value is for when the value is unknown and likely coded unusually.
####

--#[Value]#--

Is of course where you enter the value you are searching for unless you have sele
an Unknown or Coded search.

--#[Type]#--

This is where you choose what type of search your are preforming.
####
-Custom is where you can define all the points of the search criteria.
####
-Integer is what your going to use fo ra typical Decimal(Number) search.
####
-Float is used for values between -1.2E-38 and 3.4E38.
####
-Text is for when you are searching for ASCII/Text(Letters or Words),
####

###[ Sieve Button ]###

After you have completed you first search and are ready to search again you use S
It will narrow down the results of the last search to a lesser number.

--#[Search]#--

-Exact Value is for when you know the exact number you are searching for.
####
-Sequence Of Values is for when you are searching for a group of address's that c
what you are looking for but you don't know which has it.
####
-Range is for when you know the general area of the number but you don't know exa
where it is.
####
-Unknown Value is for when you have no clue what your value is or your just searc
anything.
####
-Coded Value is for when the value is unknown and likely coded unusually.
####

--#[Value]#--

If you have chosen Unknown or Coded value you will not have to enter a value, oth
you enter the value depending on the chosen Search type.
-For an Exact Value you enter the exact number you are searching for.
####
-For a Sequence Of Values search you enter the sequences of numbers you are searc
for.
####
-For a Range search you enter the lowest number you think what you are searching
could be and the highest number that you think it could be.
####
-For Unknown Value search you choose one of the following for your Value:

--Was Changed - The number has changed since you last searched.
--Was Not Changed - The number is the same since the last search.
--Was Increased - The number has gone up since last search.
--Was Decreased - The number has gone down since last search.
--Was Increased By - You know exactally what it has increased by, but not to what
it has increased to.
--Was Decreased By - You know exactally what it has decreased by but not to what
it has decreased to.
####
-For a Coded search you choose one of the following for your value:

--Was Changed - The coded number has changed since you last searched.
--Was Not Changed - The coded number is the same since the last search.
####
--#[Type]#--
This is where you choose what type of search your are preforming.
####
-Custom is where you can define all the points of the search criteria.
####
-Integer is what your going to use fo ra typical Decimal(Number) search.
####
-Float is used for values between -1.2E-38 and 3.4E38.
####
-Text is for when you are searching for ASCII/Text(Letters or Words),
####

###[ Options Button ]###

The options window is used to edit options within Artmoney and to change
how things work on it. Below is a list of tabs and what operations you can edit:

--#[General]#--

-Show Process is where you define what type of processes to show, here's what eac
####
--ALL is every process running on the system, even those that are hidden from vie
####
--Visible are those that you can see on the main screen or in the task bar.
####
--With Windows are programs running within windows.
####

-Game Type is where you define what type of game you are playing, here's what eac
####
--ALL will search as if the game is Win16/32 or Dos.
####
--AUTO will detect what type of game you are playing and change the search to mat
####
--Win32 will set search settings to search like the game is Win32.
####
--Win16 will set search settings to search like the game is Win16.
####

-Search In Address Range will allow you to specify from what address to what addr
wish to search through for the info you are looking for.(Example: You know that b
update the address was 478ED4 but that it has changed, so you can specify to sear
470000 and 480000.)

-Economize Disk Space is used to keep the about of memory you use down, for peopl
slower computers and don't want this to crash it.

-Undo/Redo Sieving will allow you to undo/redo searches after you have already pr

-Scan Priority will allow you to set how sensitive the scan is. The higher you se
(meaning it will mostlikely find more results) it will be.

--#[Additional]#--

-Byte's order will the define how the bytes are displayed. They are fairly self e

-Integer View will allow you how to view bytes. Either Signed or UnSigned.
-Refresh Time defines how often Artmoney refreshes the values of the address's.

-Freeze Time defines how fast Artmoney keeps the address's value frozen where it

-Show Addresses defines how many addresses will show up in the search box.

-Decimal Format defines how many decimals it will display. (Example: If set to 2
like this 23.00, if set to 3 it will display like this 23.000)

-Hexidecimal view will allow you to view all values in the hexidecimal format ins

--#[Personal]#--

This tab allows you to enter infomation about yourself and some comments.

--#[Interface]#--

-Language allows you to choose, thats right, you guessed it, what language everyt
Which I don't believe has been setup on most versions, so it's basically useless.

-Charset is where you define what the text on Artmoney looks like.

-Main Font is where you define the Font you wish to use on the main program.

-Table Font is where you define the Font you wish to use on the tables.

-Main Background Color is where you define the background color for the hole prog

-Input Background Color is where you define the background color for the input bo

-Button Color is where you define what color the front of the buttons are.

-Elipse Buttons will convert all Square and Graphical buttons into Eliptical butt

--#[Hotkeys]#--
-Hotkeys Is Enabled is of course where you define if the hotkeys are on or off.

-Popup Hotkey is where you define what hotkey will make Artmoney the window In-Fo

-Select Current Process is where you define what hotkey will select the current p
that is In-Focus(the window you are viewing) as the process you are going to memo
scan.

-Freeze/Unfreeze is where you define what hotkey will Freeze/Unfreeze the current
you have selected in the cheats list(where addresses are sent after moved from se

-Set Value is where you you define what hotkey will Set the value in the Input Bo
of the current address you have selected.

-Add To The Value is where you define what hotkey will Add the value in the Input
value of the current address you have selected.

You can set the Hotkey for Freeze/Unfreeze,Set Value, and Add To The Value by cli
to the left of them where it displays the hotkey and then pressing the key you wi
hotkey and once you have the one you wish displayed in the box press ok to set it
### [ Help Button ]###

Help will give you some information about Artmoney. You can recieve more help by
to the Artmoney folder and going to the Help folder and it has help files with mo
and pictures about Artmoney and some of its Operations.

###[ About Button ]###

About gives information about the maker of Artmoney and the such.
Not really any help here needed..but what the flick. :)

###[ Benchmark Button ]###

Benchmark will test your system's speed and then display it on the chart against
the other systems.

###[ Clear Button ]###

Clear will clear the entirecheats list box of addresses and everything.

###[ Load Button ]###

Load will load a saved cheat list table(.amt) from the Artmoney Tables directory

###[ Save Button ]###

Will save all of the addresses and values and any comments in the cheats list
box into a .amt(Artmoney Table) for later use.

###[ Info Button ]###

Is where you will input any information about the current table of addresses and
that are to be saved.

################################
DEVIOUS - http://devious.tsongkie.com
TCB - www.tcb-hacks.com
CES - www.gamehacking.com
CC - www.cheat-core.com
################################
Greetz fly out to all DEVIOUS & TCB
################################
Date: 7th Of July, 2003
################################
Best viewed in Arial, Regular, 9
Using SoftICE for Game Training
Author: Orr

Preface
-------
Most of the game trainers out there relax when they figure out that the
game they have been training is not using DMA (Dynamic Memory Allocation), in ord
to store the values it needs for the gameplay. Once they are sure it is Static
(that is, the address never changes), they go on and code their trainer. In this
tutorial I will show how to use SoftICE in order to create a trainer, even if the
address is static. I usually can't care less if the game is 'static' or 'dynamic'
I use SoftICE, and I have more control over the game.

Pre-Requisits:
- Basic Knowledge of Game Hacking (using a memory seeker).
- Basic Knowledge of Assembly commands (I will review some).
- Basic Knowledge of SoftICE.

The target game for this tutorial is "The House of the Dead 2". I chose it becaus
it is using Static Memory Allocation, and because it is quite easy game for begin
There are 2 main items in this game; The Bullets, and the Life. The second is a b
more tough than the first one, so I will teach how to hack the both of them here.

Bullets
-------
Start playing alittle, and you will notice then you have 6 bullets. Shoot them al
up and you get this nasty message "RELOAD". Basically you reload with the right m
button. In the first "House of the Dead" game there was an auto-reload option, bu
they 'forgot' to add it in this version... playing without auto-reload is harder.
uhm, I say we should ReCREATE this option, and show the coders of the game how to
it properly! hahaha! ok. I will calm down now.

Open up your favorite memory seeker, and search for the value "6" (make sure that
indeed you have 6 bullets). After the search is done, shoot away one bullet, and
search for 5 now. Perform this usual drill until you have ONE memory address.
It should be 009A3EFC. If you will poke any value you want to this address, it WI
affect the bullet number, but we want to freeze it don't we?

Get back into the game, and load SoftICE (Control+D). Now we will set a Breakpoin
on Memory Address (BPM). When you set a BPM, SoftICE will break whenever the memo
address that we specified was ACCESSED. For example:

BPM[SIZE] ADDRESS [R|W|RW|X]

Size: There are 3 types of sizes:


B - Byte
W - Word (2 bytes)
D - Double Word (4 bytes)

Why do we need to specify sizes? Well, I usally don't specify size, BUT it may ge
useful. Say we have the address 111, and it holds our money, which is in many cas
a big value. If this value is a DWORD (4 bytes), then the address will be 'spread
on 4 bytes, that is: 111, 112, 113, 114. So if we BPMD (BPM Dword) on 111, it wil
detect any access to one of the four addresses specified.
We also have BPM Permissions:
R - Break if the address was READ
W - Break if something was WRITTEN into the address
RW - Break if both Read and Write access happend on the address.
X - Break if the address was executed (Eqivalent to BPX)

So let's figure out what we need. We don't know whether this address is B/W/D so
will use plain BPM, BUT, we know that we need WRITE permission (whenever this add
gets updated with the correct value), so enter this command in SoftICE:

BPM 9A3EFC W

Get out of SoftICE (Control+D) again, and shoot another time. SoftICE should now
and you should see this code:

00414AC3 48 dec eax ; EAX stores num of bull


; and it is now decrease
00414AC4 6689461C mov word ptr [esi+1C], ax ; Move updated bullet nu
; to the mem address ESI
00414AC8 66837E1C00 cmp word ptr [esi+1C], 0000 ; You will land here

If you don't see this, then scroll up a bit (Control+UP).


For those of you who don't remember or don't know the basic Assembly commands, I
review some of the relevant ones.

MOV DEST, SRC - Moves a value to a register or memory address


ADD DEST, SRC - Adds a value to a reg or mem address
SUB DEST, SRC - Subtracts a value from a reg or mem address
INC DEST - Increases a value
DEC DEST - Decreases a value
NOP - No OPeration. Doesnt do anything, moves to the next instruction.

(DEST = Destination; SRC = Source.)

So, from observing the code, we see that the number of bullets is DECresed by one
and then it is being written again to the address.

So, what can we do in order to freeze the bullets? Remember that neat little comm
called NOP? We can replace that DEC with NOP! This way, whenever the processor wi
reach this line, he will simply move to the next command, without decreasing anyt

We see that the memory LOCATION of the DEC EAX is in 00414AC3. So, in order to pa
it, simply type in SoftICE the following command:

A 414AC3 <ENTER>
NOP <ENTER>
<ESCAPE>

You will see that the DEC changes into a NOP, and that 48 is changed into 90. Tho
are the HEXADECIMAL Representations of the instructions and those are called OPCO
I think that it is a short name for OPeration-Codes.
Clear all your Breakpoints (BC *), and get back into the game (Control+D). Shoot
bullets, and you will that it doesn't decrease anymore! Nice eh?

By the way, I always like to seek other solutions to the same problem, so lets se
we can find any other ways to patch the game, so it will freeze the bullets.
After the number of bullets was decreased, we see this command:
00414AC4 66 89 46 1C mov word ptr [esi+1C], ax

This is the actual instruction that writes the value back into the address. as yo
see, it is 4 opcodes long (which means it is 4 bytes long), so we can replace tho
four opcodes with 4 NOPs. Also, a nice idea would be to write a fixed value into
address. What do you mean fixed value? What if we will replace that line of code
this line of code:
mov BYTE ptr [esi+1C], 6
^^^^ ^
It will always write the value 6 into the bullet address, no matter what operatio
were performed on it!

There are many nice solutions available! Be creative... just study the flow of th
code, and you will see how many possibilities you have in store.

Life
----
OK, I won't explain this thing again, so just find the value of life the way we
found the value of bullets. If you did everything alright, you should have found
the address 9A3EE8. Now, Poke some value into it (say, 8), and get back to the
game. Nothing happens. The poking did not affect the value of lives... why?

In order to find out, we must set a breakpoint again, and study the code... so
the breakpoint should be:

BPM 9A3EE8 W

Go back to the game and SoftICE should pop again,


and you should be in this location:

0041404B 668B4606 mov ax, word ptr [esi+06] ; AX = What's in [ESI+6]


0041404F 83C404 add esp, 00000004 ; *not important*
00414052 66894608 mov word ptr [esi+08], ax ; Write back AX to [ESI+
00414056 57 push edi ; You will land here

So, from examining the code, we can see that the address that the actual memory
address that holds the value of the life is [ESI+6].
In SoftICE, do this:
? ESI+8 <ENTER>
And you will get this:
009A3EE8 0010108648 "š>è"

ESI+8 is the address that we found! So, let's see what's inside ESI+6:

D ESI+6 <ENTER>
you will see this, in the data window:

019F:009A3EE6 03 00 03 00 00 00 C0 03-00 00 00 00 00 00 00 00 ................


019F:009A3EF6 00 00 00 00 00 00 04 00-00 00 12 00 00 00 26 00 ..............&.

OK, I figured it out... The game takes the value in 9A3EE6, and then puts
it again inside 9A3EE8. So in order to find the decrementing routine, we
should set a BPM on 9A3EE6. Clear all breakpoints (BC *), and set a new one:
BPM 9A3EE6 W

Get out of SoftICE, and get hit once. You will be in this location:
00415429 66FF8AE63E9A00 dec word ptr [edx+009A3EE6]
00415430 8D82E63E9A00 lea eax, dword ptr [edx+009A3EE6] ; You land here

Wow! Did you see this! We found the DEC instruction that controls the value
of lives! OK, we see it takes 7 bytes, so we just put 7 nops instead of this
instruction. In SoftICE do this:

A 415429 <ENTER>
NOP <ENTER>
NOP <ENTER>
NOP <ENTER>
NOP <ENTER>
NOP <ENTER>
NOP <ENTER>
NOP <ENTER>
<ESCAPE>

Clear all Breakpoints (BC*), and get back to the game... get hit again by one
of those dead people, and BOOM! The lives did NOT DECREASE! Success!

End
---

Whew... I enjoyed writing this text... I hope everything was clear for you.
In case it wasn't, don't hesitate mailing me, or coming to the EFNet IRC channel
#gamehacking, join us and IDLE :)

Greetz:
[SHEEP], calligula, Keyboard Junky, jmp_fce4, MacDeath, and all the other people
from #gamehacking, and all the people I forgot, sorry... :(

Orr in May 2002.


OrrAghion@hotmail.com

LONG LIVE ISRAEL!

/\
____/__\____
\ / \ /
\/ \/
/\ /\
/__\____/__\
\ /
\/
when you find 1 of the codes such as X Spred or Speed for them to work in stats a
go into a game with your code such as speed we will use speed for this tut , 1st
code , go to Auto Hack at the top click and hit "enable debugger" ok now go to au
again and click "auto hack window"now the window is open right click on your code
auto hack now go into your game and turn speed on and use it for a sec , notice i
hack window the code is thier now highlight it and click "tmk" at the top and cho
script it will tell u what to put in TMK to make the code work

See Part 2 for setting break points


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

|Mini-Tutorial - Configuring TSearch to Maximize Search Speed

|Written By Max_Power (11-13-03) Accept No Substitutes

|This is really fast. Read in peace.

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

Introduction:

This mini-tutorial contains information to maximize the speed of your TSearch sea

Configuration:

Click View -> Options

Click the Search Tab.

Using the Search Priority slider set the Priority to critical.

Set the Max Address Show value to 100 (Learned from Mace/Sliderz)

Check the Fast Search and Freeze game during search check boxes.

Click the Cheat List tab.

Using the Refresh Rate slider set the refresh rate to about 1/4. Ex:

|||||||\/|||||||||||||||||||||||||||||||

Tips/Tricks:

A. Set TSearch hotkeys so you do not have to minimize from the game constantly.

In TSearch click View -> Options

Click the scroll right arrow in the top right corner until you see the hotkey tab

On the Search frame click the icon that looks like a white piece of paper to crea

Self explanatory from there .


B. Set you game to open in windowed mode.

BATTLEFIELD 1942 SPECIFIC: Use console command (I highly recommend Saida's consol

Or

Navigate to: C:\Program Files\EA GAMES\Battlefield 1942\Mods\bf1942\Settings

Open the VideoDefault.con

Change: renderer.setFullScreen 1 to renderer.setFullScreen 0

C. Lower your game graphic settings.

D. You can run t-search with networking option. This enables you to run your game

Live long and prosper.


This continueing on how to auto hack and set break points.

part 2

Setting a Break point .

if the code still doesnt work try setting a break point by useing auto hack
and clicking at the top where it says "edit" (this is in the auto hack
window) and click set break point now a window will pop up just type in the
code and press ok thats it you just set a break point
NOTE: This quick and easy tutorial will show you how to defeat basic DMA using TS

TSearch Basic Search

- Open Process
- Init new search (magnifying glass)
- Select type of search
- Type value your searching for
- Select size (byte, float, double)
- Click ok

TSearch AutoHack

Once you find the value you were looking for click the address in the table on th

Now that you have the address in the table on the right, select the menu item Aut

Right click on the address in the table on the right and select AutoHack from the

TSearch is now watching the address you AutoHacked for any changes.

Now go back to the game and do something that would change the value at the addre

For instance if you AutoHacked the address for Ammo, shoot the gun a few times.

Now that you have changed the value at the address you AutoHacked, you can go bac

If you shot a bullet, TSearch prolly found the decreaser. If you got ammo or relo

If you simply want to NOP (No operation) the found addy(s) in the AutoHack window

Whatever you selected is now patched or NOP. If you patched the decreaser your am

If you want to know what to put in TMK, select the addy in the AutoHack window, a
-TSearch tutorial by XaZ/GorgnutHi, all this is my first tutorial.

It directs it self on guys/girls who is new to gamehacking.


However a brain is needed to understand it. Oh, one more thing before we start, X

First start TSearch :)


Then start the game you want to hack.
Now in your game start a new game or something so you get"into" the game.
When your done with that, you can look around a bit on the things you want to hac

Lets say you have 100 health in a game. Remember that, or write it down.
Now, switch to TSearch using ALT-TAB in game. In Tsearch, click the "Open Process

Now you will see a list of allthe process (programs, games etc etc).
Now double click on your games process (i.e sof2.exe, starcraft.exe etc etc).
Now your process is loaded in TSearch. Now remember the value of your Life/gold/a
Click the search buttonbelow the "Open Process" button (the button looks like a b
Now, write in the value of that you wrote down. Thenfrom the list select "Exact V
Now TSearch is finding all the memory adresses with the value youentered.
It can find up to some millions of memory adresses with that value.

So how do we know which one of these memory adress is ours? Hold on and i will te
Now go back into the game and fire a bullet or loose some life or build something
Do somthing that effect your value!When you done that, switch back to TSearch and
Now from the list where you choosed "Exact Value" select Has Decreased or Has Inc
Now click ok.
Now it will searchfor all values that where decreased from last time you searched
Now do thisprocess a couple of times untill you only have like 2-3 results.
Good, you have the 2-3 results now? Then read on... Select the adress that was fo
This will add the adresses to an other list, just beside theother one.
Now to freeze this value, click in the little box on adress that you want to free
Go back to the game andVoila!
Your ammo/gold/life should be freezed!Thats all for now!
If you got any problem, want to give me feedback etc etc,
please e-mail me at gorgnuts@extalia.com
Tune in for my other tutorial "Hacking DMA with TSearch" which i will do soon :)
Until then have fun and hack on :)
Hacking Minesweeper with Omni Trainer v 1.0

Hi there guys it's me again and this time with an tutorial on hacking
Minesweeper of Win 98! I know...its easy, but i like this game 'cause i'll
show how to use Omni Trainer and its a new tool ;)

Needed Tools :
» Any Game (i'll use Minesweeper)
» The OMNI TRAINER v 1.0 - get in www.omnitrainer.cjb.net
» Some Coke, Fanta or Coofe (hmm... I like coke, he he he....)
» Some music , of course....like Rock or Eletronic Music :)
» Do u have a brain, right?

Ok, let's start rocking ! :)

Step 1 : Finding the address

1. Open Minesweeper.

2. Open the Minesweeper process in Omni Trainer. You can do this by using
the Process / Open Process menu command. Now, scroll down until you find
a process with the window title "Minesweeper". Select it and then click
OK.

3. Create a New Location.


You can do this by using the Location \ New Location menu command.

4. Search for the Seconds Address. Click the Search button. To find the
second address we perform a single out search; we will continue to search
for the seconds value until we have found a single address (the address of
the seconds value). Since the timer can range from 0 to 999 we should be
safe by searching for the DWord data type since most game use the DWord
data type for all their numeric data. Select DWord in the Type combo box. A
Forward-Normal search will work just fine. The seconds value in
Minesweeper should currently be zero, so type "0" in the search text box and
click search. Omni Trainer indicates that a search for zero is not
recommended. An initial search for zero usually returns too many values and
can lead to errors. Click No and change the seconds value to a number other
than zero by playing Minesweeper and losing. Back at the search dialog,
enter the seconds value that is currently shown in Minesweeper, and click
Search. A large number of values will appear in the Addresses Found List,
but we want only one. In the Search Again field, retype the seconds value
and click Search Again. Notice that the number of addresses found either
changed very little, or not at all. This is because some values may not
change in a program unless the user activly using the program. Play
minesweeper again and lose at a different time than before. Enter the new
second value in the Search Again text box and click Search Again. The
number of addresses found should reduce significantly. Continue this until
only one value is in the Addresses Found list. Note: If you encounter
problems just restart your search. Double-click the one address to select it
so that it appears in the Addresses Selected list, then click OK.

5. Check the Address. You should make sure that the seconds address you
found is correct by returning to Minesweeper, starting a new game (but do
not click anything) and then returning to Omni Trainer and pressing the
Update button on the New Location dialog. The current value text box
should read "0". If not, go back and repeat the search.

6. Set the Modify Value and the Refresh Time. Since you want to get the
lowest time possible in Minesweeper, type "0" into the Modify Value field.
However, if you use a refresh time of zero, you would have to keep enabling
the location to a low seconds value since a Refresh time of zero only writes
the location once. Therefore, you will want to change the Refresh field. The
refresh rate is measured in milliseconds, so change the value to "1000" to
make it refresh every second.

7. Personalize the Location with a Label and Info. You may want to label
this location for quick reference. Change the Label field to "Seconds". Then,
add a more detailed description in the Info field and click OK.

8. Enable the Location. Double-click the location you just created to enable
it. Play Minesweeper, and notice that your time remains at one. This
demonstrates that when you change a value, it is not immediately noticeable
because values are only shown when they are updated in the application.
The time, for example, is only updated when it is incremented. Since Omni
Trainer modifies it to zero, its first update occurs when Minesweeper
increments the value to 1. Therefore 1 is shown.

9. Saving your Location List. To save your newly created location list use
the LocationèSave Location List menu command. This displays the Save
Location List dialog. First, type "Minesweeper Tutorual" in to the Location
List field. Some programs have different versions, while others only work
on specific operating systems. For Minesweeper, type your Operating
System name in the Version Info text box. Then, pat yourself on the back.
You have just completed the Omni Trainer Basic Tutorial!

Tutorial by [D.N.A]
The East KidZ (c) 2002
contact : dna.netz@ig.com.br or dna@tsongkie.com
web: www.vngamecenter.com
transparent trainer using game trainer studio

tools:
gts
any photo editor (i'm using adobe photoshop)

okay, this tuts will explain how to make a transparent trainer using GTS.

draw trainer's bitmap

first of all, open up your photo editor and draw your trainer bitmap.

please make sure that your bitmap's background color are different from any other color on your trainer bitmap.
i'm using white as background color. you might ask "why?" :) i'll explain it later. when you done with your bitmap,
save it as *.bmp
format file. i named it as trpic.bmp.

make a transparent trainer

okay, we're here. now, open up your GTS and make a new trainer project.
now, right click on the trainer dialog, choose trainer setting. trainer setting box will open up. go to bitmap tab.

now you'll be here.


use the number on picture above as a guide.

1 - choose your bitmap. remember our bitmap name? yes, its trpic.bmp. click on 'choose bitmap',
find where our bitmap is and choose it.

2 - now, we will create RGN file for our trainer. click on 'create rgn file' and you'll be here.

okay. click on 'browse' and choose our bitmap, trpic.bmp and open. now click on 'pick' and right click on white
area.
that why i told you to use a different background color for our trainer bitmap. rgn meant 'region' and in this
case,
white is a our trainer region. click ok. then click on 'create', give your rgn file a name. i'm using trrgn.rgn

3 - now you'll choose the rgn file you've make, trrgn.rgn. click on 'choose rgn file', find your rgn file and click open.

then click on 'apply'. congratulation, you've done!

greets
Bie, a_jaxxx, divine shadow, all gamehacker around the world - you know who you are.

tutorial witten by
hotfloppy
hotfloppy@malaysia.com
hotfloppy.cjb.net
- do not eat -
|- TUTORIAL BEGIN HERE -|

First of all, change your font to terminal...now! hehehe :p

In this tutorial, i'll use:


- Tester v1.1 by Beans [Get it in www.gamehacking.com]
- TSearch v1.6 [fly.to/mtc]
- Princess Sandy 1.0 by AgentData [http://www.the-eminence.com]

Lesson one - Looking for DMA (Cool to patch!) addresses


So, u see, i wanna hack one dma value, why? It's simple! When you
use a T-Search to hack a dma address, the AutoHack show a special
thing for you, it's show the "Patch-code"...and your brain, u can
make a cool patch instead a trainer!

Lesson two - Find the "patch-code"


Start your Tester in level 5 and pause it. Open your TS and find
find the value, it's 1Bytes (Timer)...i've found only one address
Click in Auto-Hack menu and "Enable Debugger", now u need to open
the "Auto-Hack window", this option is in Auto-Hack menu...wait, i
will drink coke...i'm back :p...Right click in the address you've
found and click in "AutoHack" option, go to Tester and unpause it.
Go to "AutoHack window", u'll see: "401E4E: mov[eax],ecx"...hehehe
Select it, click in "TMK" menu and select "Button script", you'll
see the "Patch-code", something like this:

# Patched script: Poke 401E4E 90 90


# UnPatched script: Poke 401E4E 89 08

What it mean? It mean: UnPatchad script="Original data", and the


other (Patched script)="Patch data", well this is all you need to
make this path!

Lesson three - Using the Princess Sandy to make ur loader


Well, simply enter in Princess Sandym select "Tester.exe" when it
ask...Now, click in "Add Item", in Address, write: "00401E4E", in
Original Data, write "8908" and in Patch data, write "9090"....and
now, click in build...Select the folder to save it.....BINGO!!!!
your Loader was successful created! Now, copy the Loader to Tester
folder and run it, what the fuck? Nothing new to me! Ok, let's see
it, select level 5 and click in Test, wait the time and look: u've
Success with the timer hack!!! lol...

Lesson four - Homework


Hey man, now u know how to make a loader, make a loader to Health!

Cya,
[D.N.A]
WIN32 - Inside Debug API
------------------------
(Things you need to know: the mysterious CONTEXT structure)

by Iceman, 20 March 1998

I'm very proud that my previous work "Tweaking with memory in Windows 95" was go
enough to open a new section ,"+HCU's PAPERS", at Reverser's.That's very stimulat
back! I hope that will be many other contributors to this section.Let's bring lig
shadows!
BTW, Reverser ,I really like the picture for your new section.I'm with you boys,
and forever!And one more thing:for now one I will send you my essays in .htm for
plain text files!
In this document I will focus on Debug API functions.I think that it is an
interesting chapter,who worth a closer lock.
Note:In order to use those functions in Windows NT your user must have debug
privileges access right granted.I don't know for sure but it seems that NT does n
this for default to administrators.
I have started to work on part two of "Tweaking with memory in Windows 95" this
time I want to present a VxD aprroach.It's nice to write self-modifying code usin
trick(Make code section read-write at link time).But wouldn't be nicer to relay o
to tweak with memory leaving that damned section write protected and without ANY
calls to functions like VirtualProtect? The target will be this time the virtual
itself.Anyone out there who could HELP?.

The document has the following structure:

Chapter1:Functions and structures.


Chapter2:Debug events.
Chapter3:Creating or attaching a process for being debugged.
Chapter4:The main loop: WaitForDebugEvent - ContinueDebugEvent.
Chapter5.Handling debug events.
Chapter6:GetThreadContext & Set ThreadContext(Advanced stuff)
6.1 Thread Contexts explained
6.2 Injecting code in another process.
Chapter7:Notes

=================================================================================

Chapter1:Functions and structures


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

A good WIN32 API reference for future reference is OK.I don't explain here all
the parameters those functions take, nor all structures.But for now,let's see the

ContinueDebugEvent
DebugActiveProcess
DebugBreak
FatalExit
FlushInstructionCache
GetThreadContext
GetThreadSelectorEntry
IsDebuggerPresent
OutputDebugString
ReadProcessMemory
IsDebuggerPresent
SetThreadContext
WaitForDebugEvent
WriteProcessMemory

As we can see , two old friends:WriteProcessMemory & ReadProcessMemory.We all kn


them very well,so let's go further.
FlushInstructionCache ,IsDebuggerPresent,OutputDebugString? Self-explanatory.

DebugActiveProcess
------------------

This function allows a debugger to attach to an active process.

BOOL DebugActiveProcess(
DWORD dwProcessId
);
Parameters:

DWORD dwProcessId: PID of process to attach

WaitForDebugEvent
-----------------

This function allow the debugger to wait until a debug event heapens
in target process.

BOOL WaitForDebugEvent(
LPDEBUG_EVENT lpDebugEvent,
DWORD dwMilliseconds
);
Parameters:
LPDEBUG_EVENT lpDebugEvent: Pointer to a DEBUG_EVENT type structure.
This struct will receive info about the
debug event trapped.
DWORD dwMilliseconds: Number of ms. to wait.Could be INFINITE.
If it is INFINITE WaitForDebugEvent does
not return until a debug event occurs.
ContinueDebugEvent
------------------

This function allow the debugger to resume a thread that previously raised a
debug event.

BOOL ContinueDebugEvent(
DWORD dwProcessId,
DWORD dwThreadId,
DWORD dwContinueStatus
);
Parameters:

DWORD dwProcessId: PID of process beeing debugged


DWORD dwThreadId: TID of thread to be resumed
DWORD dwContinueStatus : DWORD that specify how the thread will
continue.Two values defined:
DBG_CONTINUE & DBG_EXCEPTION_NOT_HANDLED.

Debug Break
----------
This function causes a breakpoint in current process.

VOID DebugBreak(VOID);

FatalExit
---------
This function force the exit of caller process,transferring execution to debugg

VOID FatalExit(
int ExitCode
);
Parameters:
int ExitCode : Exit code

GetThreadContext & Set Thread context


-------------------------------------
Those functions are used to retrieve & set the context of a thread.See chapter

BOOL GetThreadContext(
HANDLE hThread,
LPCONTEXT lpContext
);

BOOL SetThreadContext(
HANDLE hThread,
CONST CONTEXT *lpContext
);
Parameters:
HANDLE hThread: A handle to thread whose context is being read
or set.
LPCONTEXT lpContext: Pointer to a CONTEXT structure to receive /set
context info.

GetThreadSelectorEntry
----------------------
The GetThreadSelectorEntry function retrieves a descriptor table entry for
the specified selector and thread.
BOOL GetThreadSelectorEntry(
HANDLE hThread,
DWORD dwSelector,
LPLDT_ENTRY lpSelectorEntry
);
Parameters:
HANDLE hThread: A handle to thread containing specified
selector.
DWORD dwSelector: Selector Number
LPLDT_ENTRY lpSelectorEntry Pointer to a structure that receiv
descriptor table.

=================================================================================

Chapter2:Debug events.
----------------------

From Debug API functions point of view a debug events is an object used to commu
with the debugger.When a debug event occurs in target process the OS inform the d
this.The debugger use WaitForDebugEvent to retrieve info about the event that occ
process(See chapter 5).Following debug events exists:
1.CREATE_PROCESS_DEBUG_EVENT & EXIT_PROCESS_DEBUG_EVENT raised every time than a
process is created/destroyd by the process being debugged.
2.CREATE_THREAD_DEBUG_EVENT & EXIT_CREATE_THREAD_DEBUG_EVENT raised whenever a n
thread object is created/destroyed by the process being debugged.
3.LOAD_DLL_DEBUG_EVENT & UNLOAD_DLL_DEBUG_EVENT generated whenever the target lo
unloads a dll.
4.OUTPUT_DEBUG_STRING_EVENT generated than target calls OutputDebugString.
5.EXCEPTION_DEBUG_EVENT generated when an exception occurs in target process.Thi
include breakpoint instructions such INT 3 , DivideOverflow .....
6.RIP_DEBUG_EVENT generated when a RIP exception occurs.
WaitForDebugEvent receives the debug event and returns information about the eve
in a DEBUG_EVENT structure.This structure is defined as below in WIN32 AP:

typedef struct _DEBUG_EVENT {


DWORD dwDebugEventCode;
DWORD dwProcessId;
DWORD dwThreadId;
union {
EXCEPTION_DEBUG_INFO Exception;
CREATE_THREAD_DEBUG_INFO CreateThread;
CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
EXIT_THREAD_DEBUG_INFO ExitThread;
EXIT_PROCESS_DEBUG_INFO ExitProcess;
LOAD_DLL_DEBUG_INFO LoadDll;
UNLOAD_DLL_DEBUG_INFO UnloadDll;
OUTPUT_DEBUG_STRING_INFO DebugString;
RIP_INFO RipInfo;
} u;
} DEBUG_EVENT;
The member dwDebugEventCode contains a value indicating which kind of debug eve
was ocureed.The dwProcessId member contain the PID of process in which the debug
The union u member is a classic C/C++ union.It is reflected in a structure whose
determined by DWORD dwDebugEventCode.This structure contains extended information
event that ocurred.I don't list all of them here because it's pointless.
Also note that a CREATE_PROCESS_DEBUG_EVENT is generated than a debugger attach
target process.

=================================================================================

Chapter3:Creating or attaching a process for being debugged


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

In this short chapter I present you how to create a process for being debugged,o
how to attach to an already running process.

3.1:Creating a process for being debugged


Use CreateProcess to create the process being debugged.Call this function
with dwCreationFlags parameter with one of following values DEBUG_PROCESS or
DEBUG_ONLY_THIS_PROCESS.If target process is created with DEBUG_PROCESS creat
flag than the debugger will receive events from all processes crated by targe
process.If dwCreationFlags=DEBUG_ONLY_THIS_PROCESS than the debugger will rec
debug events only from target process ignoring child processes.As usually you
can use PROCESS_INFORMATION structure to ret rive handles to both the created
process and it's primary thread as well as the PID an TID(for primary thread)

3.2:Attaching to an already running process


Use DebugActiveProcess function.If this function returns successfully you
are attached to target as if you called CreateProcess with DEBUG_ONLY_THIS_P
flag.

Note that in WindowsNT DebugActiveProcess can easily fail if we try to attach to


process that was created with a security descriptor that denies requested access.
the only thing you have to worry is to pas a valid PID to DebugActiveProcess.That
NT has better security.
Attaching to a process is an elegant method but sometimes the loader method is t
only solution.It's up to you what method to use.For a simple game trainer it's OK
but if you really want to do cool things...,better use the loader method.It gives
control over the target process and it's threads.

=================================================================================

Chapter4:The main loop: WaitForDebugEvent - ContinueDebugEvent


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

A minimum skeleton for using Debug API function is easy to implement.All you hav
do is to create a process for being debugged and the implement code to watch for
I call the part responsible with watching debug events "The Main Loop".Why?Becaus
simple to implement as a While loop.The functions you have to use for this are
WaitForDebugEvent - ContinueDebugEvent. As we have seen before WaitForDebugEvent
certain amount of time for a debug event to occur in target process.If a debug ev
occur in this time the function times-out and return FALSE. If a debug events occ
this function return TRUE,fill a DEBUG_EVENT type structure with info about even
freeze the thread in witch the debug event ocurred.The programmer is responsible
event type checking and take appropriate meassures.After the specific code for ha
event is executed we have to use ContinueDebugEvent to resume thread execution an
other events to occure.Another thing to worry: the only thread witch is allowed t
WaitForDebugEvent is the thread who created or attached to target process.So let'
code:

PROCESS_INFORMATION pi;
STARTUP_INFO si;
DEBUG_EVENT devent;
if(CreateProcess( 0 , "target.exe" , 0 , 0 ,FALSE ,DEBUG_ONLY_THIS_PROCESS , 0 ,
&si , &pi))
while(TRUE)
{
{
if (WaitForDebugEvent( &devent , 150)) // wait 150 ms for debug event
{
switch(devent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
// your handler here
break;
case EXIT_PROCESS_DEBUG_EVENT:
// your handler here
break;
case EXCEPTION_DEBUG_EVENT:
// your handler here
break;

}
ContinueDebugEvent(devent.dwProcessId , devent.dwThreadId , DBG_CONTINUE);

else
{
// other operations
}

}
} // while end here
else
{
MessageBox(0,"Unexpected load error","Fatal Error" ,MB_OK);
}
=================================================================================

Chapter5.Handling debug events


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

In previous example we can see that how we can trap debug events and take approp
actions using case/switch C /C++ statements.Each debug event has a personal handl
gets executed when corresponding debug event occurs.More information about the de
can be found in union u member of DEBUG_EVENT.As a example let's the structure co
to EXCEPTION_DEBUG_EVENT.I choose this because encountering breakpoints and traci
code generates an exception debug event.See a API reference for other events.

typedef struct _EXCEPTION_DEBUG_INFO


{
EXCEPTION_RECORD ExceptionRecord;
DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO;

In this case we have to retrieve data we need from another structure,member of


EXCEPTION_DEBUG_INFO structure.This is EXCEPTION_RECORD structure in which , fin
we can find all data we need about trapped exception.Let's see:

typedef struct _EXCEPTION_RECORD


{
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;

DWORD ExceptionCode: Specifyes the type of exception


ExceptionFlags : 0 if exception is a continuable exception
EXCEPTION_NONCONTINUABLE if exception is not continuable.
ExceptionRecord : Pointer to an associated EXCEPTION_RECORD structure
PVOID ExceptionAddress: Pointer to the address where exception occurred
DWORD NumberParameters: Number of parameters defined in ExceptionInformation
ExceptionInformation: Additional 32 bit array.For most exception is undefined.

Using the information from those structures we can find all we need.We can retri
the thread there exception occurred , type of exception , if we can continue exec
the address where exception occurred and others.
Note that trying to continue a EXCEPTION_NONCONTINUABLE exception type will
generate a EXCEPTION_NONCONTINUABLE_EXCEPTION exception.
Currently used exceptions are EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP.The
first exception is raised on a breakpoint hit, the seconds signalizes that trace
signals that one instruction has been executed.
Using a similar mechanism you can gather information about threads , dll's used
by running process and other things.

=================================================================================

Chapter6:GetThreadContext & Set ThreadContext(Advanced stuff)


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

6.1 Thread Contexts explained


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

I really enjoyed writing this chapter.All others are things easy to figure out.D
scare it not really difficult to understand what's going on in this chapter.Befor
those two functions and their use I want to remember some basic things about proc
threads.
In WIN32 philosophy a process is a object who has an private address space , cod
data , and a primary thread.Each process has at the very beginning only one threa
primary thread we can later create other threads which run in the same address sp
to the popularly belief a process does NOT execute any kind of code.The threads a
who executes the code.The thread objects share the same address space and resourc
have individual contexts.What means that? Windows95 and WindowsNT are multitaskin
multithread operating systems.The OS seems to run all threads in the same time ,
not true. Every individual thread is scheduled for execution for a short time , a
OS save the thread state in a structure called CONTEXT structure and goes for the
The information saved in this structure represents the thread context and is form
- threads machine registers (CPU registers)
- the kernel stack and the user stack address
- thread environment block address.
The the OS encounter again our thread it restores it's context info from associa
structures and resume execution like nothing happened.
Ok,so let's see the CONTEXT structure.Unfortunately seems that Microsoft does no
include info about this structure API help files. The structure is documented at
in winnt.h header file in Watcom compilers(can be elsewhere in others.Keep lookin
mind that this structure is hardware dependent so expect different implementation
x86 , Alpha...

typedef struct _CONTEXT {


DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs;
DWORD EFlags;
DWORD Esp;
DWORD SegSs;

} CONTEXT;

typedef struct _FLOATING_SAVE_AREA {


DWORD ControlWord;
DWORD StatusWord;
DWORD TagWord;
DWORD ErrorOffset;
DWORD ErrorSelector;
DWORD DataOffset;
DWORD DataSelector;
BYTE RegisterArea[SIZE_OF_80387_REGISTERS];
DWORD Cr0NpxState;
} FLOATING_SAVE_AREA;

typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA;

DWORD ContextFlags: the folowing values are defined:

CONTEXT_CONTROL // SS:SP, CS:IP, FLAGS, BP


CONTEXT_INTEGER // AX, BX, CX, DX, SI, DI
CONTEXT_SEGMENTS // DS, ES, FS, GS
CONTEXT_FLOATING_POINT // 387 state
CONTEXT_DEBUG_REGISTERS // DB 0-3,6,7

CONTEXT_FULL=(CONTEXT_CONTROL | CONTEXT_INTEGER > CONTEXT_SEGMENTS)

Watch out CONTEXT_FULL does not include CONTEXT_DEBUG_REGISTERS and


CONTEXT_FLOATING_POINT.You must specify them independently.It's huge and ugly, is
Ok we know now how a CONTEX structure is looking.Now let's see what can we do wi
this monster.First let's talk a little about GetThreadContext & SetThreadContext.
The function GetThreadContext is used to get a thread context.
BOOL GetThreadContext(
HANDLE hThread,
LPCONTEXT lpContext
);
hThread is the handle of thread whose context is to be retrieved.
LPCONTEXT lpContext is a pointer to a CONTEXT structure.

PRIOR TO USE GetThreadContext you MUST initialize ContextFlags member with


the appropriate flag.Use This to set the amount of info to retrieve.For example i
you specify CONTEXT_CONTROL value for ContextFlags only SS:SP, CS:IP, FLAGS, BP
will be saved.
The function SetThreadContext is used to set the thread context.
BOOL SetThreadContext(
HANDLE hThread,
CONST CONTEXT *lpContext
);
Like before hThread is a handle to destination thread and CONST CONTEXT
*lpContext is a pointer to a CONTEXT structure.The amount of information restored
is determined by ContextFlags member.
You may want to consider another thing.NEVER try to set a thread context
while the thread is running.I consider this "one way ticket to the hell".Use
SuspendThread to stop a running thread.Later after you set the context you
can use ResumeThread function.Warning: using ResumeThread does not guarantee
that the target thread will indeed resume executions.Why?Every thread have an
thread suspend count.When the thread is running the counter is 0.Every time when
we use SuspendThread this counter is incremented by one.So we call SuspendThread.
The counter will be updated to 1.But W_95 and W_NT are multithread enviroments
so another thread can call too SuspendThread on our thread.Now the counter
is 2.Calling ResumeThread once will have only one effect.The counter is again 1.
Thread execution is not resumed until the thread suspend count is 0.(ResumeThread
decrements the suspend counter ).So how can we be sure that the thread resumed ex
Simple.Examine the return value. If it's 0 then the thread was not suspended.If
1 the thread was suspended but resumed execution.If it's greater than 1 the threa
counter was decremented but the thread was not resumed.A value of 0xffffffff mean
ResumeThread failed.

6.2 Injecting code in another process.


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

Now let's take a deep breath.We are almost through.As usually I want to present
you an interesting trick.Let's inject some code into another process address spac
how,but first let's talk about a little impediment.We need some committed memory
our brand new code.A VirtualAllocEx function was not provided in WIN95 API.It see
this one along with it's companion VirtualFreeEx exists under NT.
If our code is very little we can use the space provided by our compilers: The MS
the PE files,copyright strings or even unnecessary data strings(I dont care too m
About the program says that it was developed by "!^$##@*^$f76").Another method is
save a code page of target process , overwrite with new code , execute new code ,
code page.Let's see this step by step.

1. Use CreateProcess to create a process for being debugged.


2. Build the "Main Loop" WaitForDebugEvent - ContinueDebugEvent
3. Stop the target thread. Use SuspendThread.
4. Use VirtualProtectEx to set a read-write permission to target page
5. Use ReadProcessMemory to save the target page.
6. Use GetThreadContext to save the thread context.
7. Use WriteProcessMemory to write new code page.
8 Make sure that the last instruction in the new code is a INT 3.We need this t
take control when our code finished.The INT 3 will be trapped by our little
debugger-like application EXCEPTION_DEBUG_EVENT.Make sure that is a
EXCEPTION_BREAKPOINT and has occurred at the address there our INT 3 resides
9. Make a temporary copy of saved CONTEXT structure.
10. Set the new eip in the temporary CONTEXT structure (You now what is ei
you?
11.Resume execution of the thread.Watch it executing our new code.When INT
executed our little loader will trap it.The target thread is stopped.
12.Restore the original code page using WriteProcessMemory.
13.Restore the protection attributes on target page.
14.Use SetThreadContext to set thread context from the first CONTEXT struc
15.Resume thread.

If we need that our resides in target process address space at the same tim
original code,and our code is BIG we have to commit some memory in the target pro
space.The code to call VirtuallAlloc is very small,so use previous method to call
in the context of the target process.This will commit memory in target's address
return a pointer to it.Several kb should be more than enough,so don't be a fool a
to commit cosmic values like 10 Mb.I wonder if there is another method to impleme
VirtualAllocEx under WIN95.I keep looking.Anyone now if VirtualAllocEx is impleme
in Memphis(future Windows 98)?.
If you ever need to convert a segment relative address in linear virtual ad
can use GetThreadSelectorEntry.
Final words: !!WATCH!! the stack.DON'T mess IT.If you do , you will be sorr

=================================================================================

Chapter7.Notes
--------------

1.Any corrections and additions are wellcomed.Please append them at the end of t
document and also include your name (or your nickname ).Slightly editing minor mi
typos is admitted in-place and without notice.
melted MeltICE
(SoftIce 3.xx detection and another lesson for shareware programmers)

by Frog's Print

(22 August 1997, slightly edited by Fravia)


With an important addition by Kox! (27 August 1997)
--------------------------------------------------------------------------------

Well, Frog's Print finding are indeed interesting. I'm pretty sure that we are go

Note that since the programmers keep programming in "high" languages, all this ca
1) Use Visual Basic made protections;
2) Use ready-made third party protections (if the people selling them
would put their money where their mouths are you would see many more
working demos of their protections on the net, btw);
3) Use Visual C++ made protections;
Write your own small protections routines in assembler using some forgotten dos c
Well here you go: Meltice melted away under the touch of Frog's Print...

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

MeltICE
(SoftIce 3.xx detection)

by Frog's Print

I found today at http://www.window95.com a file named MeltICE. This is an updated


version of "ICEcream" whose only purpose was to detect if a version of SoftIce wa
loaded and "to make shareware developers a little bit easier about the safety of
their software" as it's author (David Eriksson) wrote.
The file contains a source code that (lazy) protectionists can add to their progr
MelICE was written specially for the new versions of SoftIce: v3.0 and 3.01 (Win

How it works:
The program will open the VxD driver named SICE (Windows 95) or NTICE (for Window
with CreateFile. It will then check the file's Handle (in EAX) in order to see if
SoftIce Win95 or WinNT is loaded or not.

Below are the source code of MeltICE and a disassembly listing that I did with W3
of an .exe file compiled with this code:

MeltICE - SoftICE '95 version 3 detection - Made by David Eriksson

#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

// See if SoftICE version 3.x for Windows 95 is loaded


BOOL IsSoftIce95Loaded()
{
HANDLE hFile;

hFile = CreateFile( "\\\\.\\SICE",


GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if( hFile != INVALID_HANDLE_VALUE )


{
CloseHandle(hFile);
return TRUE;
}
return FALSE;
}

// See if SoftICE version 3.x for Windows NT is loaded

BOOL IsSoftIceNTLoaded()
{
HANDLE hFile;

hFile = CreateFile( "\\\\.\\NTICE",


GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if( hFile != INVALID_HANDLE_VALUE )


{
CloseHandle(hFile);
return TRUE;
}
return FALSE;
}

// Example code for calling these functions

int main(void)
{
if( IsSoftIce95Loaded() )
printf("SoftICE for Windows 95 is active!\n");
else if( IsSoftIceNTLoaded() )
printf("SoftICE for Windows NT is active!\n");
else
printf("Can't find SoftICE with this method!\n");

return 0;
} And now, the Dead Listing of an .exe file using that code:

* Referenced by a CALL at Address :004011DE


:00401080 E87BFFFFFF call 00401000 ; first, check for S-Ice Win95
:00401085 85C0 test eax, eax ; check if loaded...
:00401087 7410 je 00401099 ; No, jump to check_NT, if yes:
:00401089 6894604000 push 00406094 ;->"SoftICE for Windows 95 is active!"
:0040108E E83D000000 call 004010D0
:00401093 83C404 add esp, 4
:00401096 33C0 xor eax, eax
:00401098 C3 ret ; S-Ice Win95 detected. Bye_bye.
:Check_NT
:00401099 E8A2FFFFFF call 00401040 ; Now, check for S-Ice WinNT
:0040109E 85C0 test eax, eax ; check if loaded...
:004010A0 7410 je 004010B2 ; jump if NOT loaded to can't_find, el
:004010A2 6870604000 push 00406070 ;->"SoftICE for Windows NT is active!"
:004010A7 E824000000 call 004010D0
:004010AC 83C404 add esp, 4
:004010AF 33C0 xor eax, eax
:004010B1 C3 ret ; S-Ice WinNT detected. Bye_bye.
:can't_find
:004010B2 6848604000 push 00406048 ;->"Can't find SoftICE with this metho
:004010B7 E814000000 call 004010D0
:004010BC 83C404 add esp, 4
:004010BF 33C0 xor eax, eax
:004010C1 C3 ret ; S-Ice not found.

********************************End of detection********************************

The detection/CreateFileA routine for S-Ice Win95:

:00401000 6A00 push 00000000 ; CreateFileA parameters


:00401002 6880000000 push 00000080 ; ...
:00401007 6A03 push 00000003 ; ...
:00401009 6A00 push 00000000 ; ...
:0040100B 6A03 push 00000003 ; ...
:0040100D 68000000C0 push C0000000 ; ...

* Possible StringData Ref from Data Obj ->"\\.\SICE" ; VxD driver for S-Ice Win95
:00401012 6830604000 push 00406030

* Reference To: KERNEL32.CreateFileA, Ord:0031h


:00401017 FF15BCA04000 Call dword ptr [0040A0BC] ; CreateFileA
:0040101D 83F8FF cmp eax, FFFFFFFF ; Handle= -1 ?
:00401020 740D je 0040102F ; Yes, jump otherwise...
:00401022 50 push eax ; SoftIce Win95 IS loaded!

* Reference To: KERNEL32.CloseHandle, Ord:0018h


:00401023 FF15F8A04000 Call dword ptr [0040A0F8] ; Close file's handle
:00401029 B801000000 mov eax, 00000001 ; Eax:=1
:0040102E C3 ret !
; Back to the caller

* Referenced by a (C)onditional Jump at Address :00401020


:0040102F 33C0 xor eax, eax ; Eax:=0 (not loaded)
:00401031 C3 ret !
; Back to the caller
...
The detection/CreateFileA routine for S-Ice WinNT:
...
* Referenced by a CALL at Address :00401099
:00401040 6A00 push 00000000 ; CreateFileA parameters
:00401042 6880000000 push 00000080 ; ...
:00401047 6A03 push 00000003 ; ...
:00401049 6A00 push 00000000 ; ...
:0040104B 6A03 push 00000003 ; ...
:0040104D 68000000C0 push C0000000 ; ...

* Possible StringData Ref from Data Obj ->"\\.\NTICE"; VxD driver for S-Ice WinNT
:00401052 683C604000 push 0040603C

* Reference To: KERNEL32.CreateFileA, Ord:0031h


:00401057 FF15BCA04000 Call dword ptr [0040A0BC] ; CreateFileA
:0040105D 83F8FF cmp eax, FFFFFFFF ; Handle= -1 ?
:00401060 740D je 0040106F ; Yes, jump otherwise...
:00401062 50 push eax ; SoftIse WinNT IS loaded!

* Reference To: KERNEL32.CloseHandle, Ord:0018h


:00401063 FF15F8A04000 Call dword ptr [0040A0F8] ; Close file's handle
:00401069 B801000000 mov eax, 00000001 ; Eax:=1
:0040106E C3 ret !
; Back to the caller

* Referenced by a (C)onditional Jump at Address :00401060


:0040106F 33C0 xor eax, eax ; Eax:=0 (not loaded)
:00401071 C3 ret !
; Back to the caller

OK, we see that this new simple and 'ready-to-use' protection will probably pleas
a huge amount of unexperimented shareware programmers. Since it is available at
Windows95.com, I assume we may have to face it very soon.

But is S-T-U-P-I-D because we now will be able to check if any program is detecti
Soft-Ice even before it will have the time to do so: just with a BPX CreateFile(A

Anyway, this will make shareware crackers a little bit easier about the safety of
the software they want to reverse engineer too.

(c) Frog's print 1997. All rights reserved


--------------------------------------------------------------------------------
Here is the important addition by Kox (27 August 1997):
Defeating MeltedICE for good in 10 Seconds.

They sure can't be serious for publishing such MeltedICE.


You can never rely on a constant string comparison to detect SoftICE.

Here is how to defeat it in 10 seconds:


(I guess everybody knows this, but just in case someone didn't think of it..)

Just replace the string "SICE" with "KICE" (or whatever you want) in the files
"Winice.exe" and "nmtrans.dll"

(Please do not use "KICE" ,just use a unique string... cause those MeltedICE
people may update it by checking for "KICE" too :)

And gone is the check for VxD name "SICE".

You can check the VxD names with many tools.. (Infospy for example)

This goes for win95 version and i guess would work for NT too..
(although for NT you have to recalculate the checksums as in +HCU Project 2)

This way of detecting SoftICE is the same one used


in the "nmtrans.dll" Function "DevIO_ConnectToSoftICE" so i guess they
reversed engineer that function.. (You see the pun,they do reverse engineer
too,
i guess no one can just live without Reverse Engineering :-) well,except for
zombies ..

Later

Kox
Anti-Debugging & Software Protection Advice
Detecting SoftICE - Protecting your Software

As an author you can clearly see that virtually every serious cracker/reverse engineer will use a
debugger or disassembler of sorts to break your application, of those tools out there I'll wager a
substantial amount that SoftICE is the "debugger of choice". Modern day programmers have still not
really caught up with "crackers", maybe they just consider it a wasted cause?, or perhaps their desire
to roll out their latest software overrides any desire to protect. At any rate, with the progression of
commercial wrapper schemes e.g. VBox, I think a list of the most common tricks encountered by
reversers would be useful for both communities.

Most of these tricks require implementation in Assembly language, evidently that isn't a problem if
you are familiar with in-line ASM coding in your compiler environment (sadly many HLL
programmers are not). Most of these examples are designed to thwart SoftICE users (virtually all of
the existing documents on the web describe tricks which would have been useful in the days of DOS
Debug/Turbo Debug but are happily traced by SoftICE).

Bear in mind that the use of these techniques will only add time to a crackers progress if he/she
doesn't actually realise the debugger has been detected (use at least 2 techniques to make sure you
aren't penalising legitamate users and don't show friendly message boxes like VBox's "Debugger
Detected, please remove me screen"). Hidden detection can work very well if used in shareware key
generation schemes, set a discrete flag and then send the would-be cracker to a routine that requires
hours of analysis time for no result, eventually time is money for the best reverse engineers.

1. - Using the API function CreateFileA to check for the presence of the SoftICE vxd/sys device
(//./SICE, //./SIWDEBUG, //./NTICE in Windows NT). This method is now very well known,
although you could try using _lread() instead (ASProtect).

Bypass by bpx CreateFileA (change API result) or HEX edit the strings from the detection or patch
your nmtrans.dll / Winice.exe against them. (Seen in Advanced Disk Catalog v1.16, MeltICE,
Hardlock/HASP envelope).

2. - INT 41h Debugger Notification.


PUSH EDI
PUSH 0000004F
PUSH 002A002A
CALL Kernel32_1 <-- ORD_1 or VxdCall.
SUB AX,F386
POP EDI
JZ SoftICE_is_running

This detection pushes 002A002A as a parameter, the high 2A means we are calling VWIN_32 vxd,
the low 2A the INT 41 dispatch service. Bypass with bpint 30 if ax==0xF386 and clear AX,
described in Matt Pietrek's legendary book.
3. - Issue commands to SoftICE. This was one detection I uncovered whilst running an installation
program protected by a Hardlock dongle (HASP wrappers also use it). I had inadvertently enabled
INT 3's with SoftICE's I3HERE toggle.

:? 4647
00004647 0000017991 "FG" <-- Magic Val. 1.
:? 4A4D
00004A4D 0000019021 "JM" <-- Magic Val. 2.

28F1:0092 MOV SI,4647


28F1:0095 MOV DI,4A4D
28F1:0098 PUSH CS
28F1:0099 POP DS
28F1:009A MOV AX,0911h <-- Function 0911.
28F1:009D MOV DX,000Eh <-- Points at null-terminated command (in this case
HBOOT).
28F1:00A0 INT 3 <-- Call Interrupt.

Evidently there are several easy ways to beat this, changing SoftICE's magic values is one option (as
described by The_Owl), another would be editing DI/SI or modifying the string at DX, you could also
just NOP the INT 3 altogether, this detection routine works with varying levels of success. Other
subfunctions exist (0912h, 0913h & 0914h) which can be used to manipulate SoftICE breakpoints.

Another set of magic values are also known ('BCHK'), this is the documented BoundsChecker
interface, if you place BCHK into EBP and set EAX=4 calling INT 3 will return AL=0 in the
presence of Winice (works in Windows).
MOV EBP, 04243484Bh <-- 'BCHK'.
MOV AX, 4h
INT 3 <-- Trap debugger.
CMP AL, 4
JNZ SoftICE_is_here

4. - Using NuMega's own functions. This requires the use of nmtrans.dll but may well appeal to HLL
programmers who aren't keen on using in-line ASM. The idea is to call DevIO_ConnectToSoftICE
and verify the functions return value before taking appropriate action. Sadly this method is based
heavily on CreateFileA (although a small amount of work could change that), hence in its current form
it could easily be found. Looking through some of the other exports from nmtrans.dll I reckon a sneaky
programmer could use some of the other exports.

5. - ICECream detection (Windows 95).

Get the Interrupt Descriptor Table (IDT) with the SIDT command.
Get the address of Interrupt gate 1.
Move 16 bytes back.
Check if byte is 1Eh - if so SoftICE is running.
SIDT FWORD PTR opIDT <-- Store IDT.
MOV EAX, DWORD PTR [opIDT+2] <-- EAX=IDT.
ADD EAX, 8h <-- EAX has INT 1 vector.
MOV EBX, [EAX] <-- EBX=INT 1 vector.
ADD EAX, 16h <-- EAX points at INT 3 vector.
MOV EAX, [EAX] <-- Get EAX=INT 3 vector.
AND EAX, 0FFFFh
AND EBX, 0FFFFh <-- Remove selectors.
SUB EAX, EBX <-- Find displacement.
CMP EAX, 01Eh
JZ SoftICE_3.0_is_running

6. - Detect SoftICE VxD or SoftICE GFX VxD (obviously ineffective under NT).

XOR DI,DI <-- Clear DI.


MOV ES,DI
MOV AX, 1684h
MOV BX, 0202h <-- VxD ID for SoftICE.
INT 2Fh
MOV AX, ES <-- VxD Entry Point.
ADD AX, DI
TEST AX,AX
JNZ SoftICE_is_here

The GFX id code is identical to that shown above except AX=1684h & BX=7A5Fh.

7. - Detect WinICE handler using INT 68h (V86).


MOV AH, 43h
INT 68h
CMP AX, 0F386h <-- Will be set by all system debuggers.
JZ SoftICE_is_here

8. - Detect and crash SoftICE with an illegal form of the instruction CMPXCHG8B (LOCK prefix) -
opcode: F0 0F C7 C8.

9. - Searching for names installed by SoftICE in low-memory, "WINICE.BR", "SOFTICE1" + others


(described in Stone's code below).

10. - Using the control or debug registers - I remember reading somewhere (perhaps in a fairly old
Anti-debugging FAQ) that SoftICE doesn't handle the control or debug registers very well or not at all
in the case of CR4, try DR4 and above too - a little something for you to play with me thinks :-).

11. - Dongle protection (used by dongle SSI Win32 Aegis).


xxxx: xxxx
EB01: JMP $+1
E8: DB E8h
xxxx: xxxx

SoftICE View:
xxxx: xxxx
EB01: JMP $+1
E8xxxxxxxx: CALL bad
TRW (not affected):

xxxx: xxxx
EB01E8: NOP
xxxx: xxxx

12. Calling the Windows function IsDebuggerPresent() (exported from kernel32.dll), returns non-zero
in the presence of a debugger, implemented only under NT so not a great trick on its own. A few
reversers have already patched their kernel32's against this one.

13. Querying the registry for keys installed by SoftICE,


[HKEY_LOCAL_MACHINE/SOFTWARE/NuMega] and subkeys. Far too easy to beat, mine are
removed already and the key was NU-MEGA in older versions.

14. Using a timer to check the execution speed of a routine can be an effective way of detecting
debuggers, under single step analysis the routine will run much slower, how you choose to react of
course is down to your own ingenuity.

15. Check if a potential cracker has set breakpoints on key API functions :-
LEA ESI, GetDlgItemTextA
CALL CheckForSoftICEBP
CMP EAX, "xxxx" <-- Substitute for your own identifier.
JE SoftICEBPIsSet <-- Send bad cracker to some really horrid routine.
CALL ESI

CheckForSoftICEBP:

PUSH ESI
PUSH DS
PUSH CS
POP DS
MOV ESI, [ESI+2] <-- Get dll function jmp address.
MOV ESI, [ESI] <-- Get dll function real address.
MOV EAX, ESI <-- Get first dword of dll function.
AND EAX, 0FFh <-- Use only first byte.
CMP AL, 0CCh <-- INT 3 ?.
MOV EAX, 'xxxx' <-- Your identifier.
JE BPXSet
XOR EAX, EAX <-- No BPX.

BPXSet:

POP DS
POP ESI
RET

This sadly won't detect the clever cracker who routinely sets breakpoints such as 'bpmb
GetDlgItemTextA x'.

16. Exploit a W32Dasm bug (this probably won't keep IDA users out but will at least stop the real
StringRef crackers which make up the majority).
00401000 JMP 00401005
.
.
.
.
00401005 JMP 00401000

It seems that if this code is placed in a zone that doesn't mess with code flow, it will put W32Dasm in
a memory-consuming -> crashing loop.

Other Resources

BPX Detection & Tricking Series - Detecting breakpoints by duelist - (55k).


FrogsICE - by Frogs Print, anti-SoftICE detection via vxd.
SoftICE Detection - by Stone (includes ASM source code) - (5k).
Top Protection Tips for Software Authors
I'm sure many authors who stumble across reverse engineering sites regard them as little more than
'how to crack' repositories, and with software piracy costing most authors a significant proportion of
their potential revenue, I do sympathise with this point of view. In the real world of computer
software there is probably very little you as an author can do to prevent the really determined pirate
from breaking your protection, even the ultimate protection can potentially be compromised by a
legitamate user doing some research.

Preventing the wide scale distribution of cracks for your program can actually be a worthwhile
exercise, use a search string such as "warez + crack + your application name" in AltaVista and
several of the other engines and you'll probably be able to find out if and where a crack exists for
your software. Remember that most 'crack' sites are operated by bored teenagers and hosted on
anonymous free space providers, most of these have Piracy@ e-mail addresses that will remove the
offending site within a day or 2, just devise your own 'piracy e-mail letter' and send them off at the
click of a button.

Below you'll find a collection of protection tips, these won't make your program bullet proof but
should waste a crackers time if nothing else, if you want more details regarding implementation drop
me an e-mail.

Top Protection Tips


1. Virtually all serious crackers will use SoftICE to break your protection, use the undocumented INT
3 interface between SoftICE and BoundsChecker to detect its presence (or other routines) thus halting
the system, better still detect and issue a HBOOT to SoftICE. Use a parity checking routine to ensure
that this detection is not tampered with and maybe set a discrete flag each time the parity routine is
required, don't tell the cracker what you are doing with helpful message boxes.

2. When writing your protections functions try to avoid using very obvious names like these that I've
seen - (Auth_Check(), FindDK47(), IsValidSerialNumber() ). Instead frustrate crackers by using less
intuitive even misleading names, further minor irritation can be achieved by using very long names
with @ symbols, and never place your entire protection inside a single dll.

3. Avoid issuing helpful message boxes period, and avoid "Thanks for registering" ones as well, most
legitimate users will type their serial numbers correctly first time, as an example, I give you the latest
version of 3D Studio Max, very expensive software, and reverse engineered by me in under 5 minutes
because of a message box.

4. If you must track registered status using the registry use several keys and don't use names like
"MySoftwareKey', instead use some sort of encryption to decode them. If you decide to use a file
based protection, avoid using *.ini and *.reg, use something like *.sys and *.vxd and make sure they
are of credible length and name.

5. Avoid commercial *wrapper* protection schemes e.g. PreviewSoftware's TimeLock, VBox,


ZipLock, Release Software Corporation's SalesAgent, Ken Nesbitt's ShareLock like the proverbial
plague. All of these protections have been generically cracked, you might as well give your software
away.

6. Forget about protecting using runtime-limits or 30 day trials, these are too easy to crack, cmp eax,
1E - jg times_up. If you must use this means have the program disable itself completely perhaps
by deleting critical files.

7. Many crackers struggle with applications written in Visual Basic and Delphi, primarily because
the run-time dll's are a mass of spaghetti code which makes isolating your protection more difficult, in
some cases it can make patching virtually impossible. If you must use these languages, make several
checks and don't use __VbaStrCmp, hyphenated serial numbers like xxx-xxx-xxx-xxx-xxx make for
painful reversing. FPU maths (FCOS, FSIN) are also effective. If you use VB always compile your
final product to p-code.

8. Bore potential crackers to death with fake routines using lots of maths and fake checks. Force them
to work back through your mass of maths (all to no avail). Mix your flags, in function 1 use return 1
for good and then in function 2 use return 0 as good, this will prevent crackers from heuristically
reversing jumps.

9. Save disabling your target?, don't just grey the menu item, take out the code completely and don't
provide helpful documents detailing the precise specification of the file format.

10. Use encryption of any description, even just simple sliding XOR can add hours to a crackers
progress. Consider using arrays of random characters for code calculation routines.

11. Use CRC checks to ensure that key sections of your program have not been modified, its not a
good idea to CRC the entire file for performance and vulnerability reasons, when you find a CRC
error be aware this could be due to virus tampering.

12. ...And finally, invest the money and buy a copy of SoftICE, then attempt to reverse engineer your
own software or ask web crackers to try their hands. Make changes at ASM level if necessary and
strengthen your protection. The longer it takes you to protect, the longer it will take a cracker to de-
protect.

Whilst no protection will ever be completely cracker proof, treat software protecting like you treat
your car (or any other prized possession), if you can implement enough deterrents most thieves will
find an easier target.

I'd really like to add more advice, so if you want to post me a small text file I'll certainly add it here.

Š 1998, 1999 CrackZ. 22nd December 1999.


Debugging
Assembly Language in a Nutshell
By Synbios
8/7/03
Revision 1 – 9/9/03
Revision 2 – 10/2/03

* Official CES Release *


Greets: EEDOK, Tsongkie, Stoner, SubZero, Drakken, DEViOUS, and
of course CES

www.gamehacking.com

Introduction
In the recent days where assembly language is becoming obsolete in
means of application development, it is hard to find decent
references and tutorials on assembly language. Out of the very few
documents and books you will find on assembly language these days,
most of them focus on assemblers and programming. In contrast, this
document will focus on debugging.

If you are interested in assembly programming here are some places


to start:

Art of Assembly - http://webster.cs.ucr.edu/


Icezelion - http://win32asm.cjb.net/
Mad Wizard - http://www.madwizard.org/

This document is mainly centered towards reverse engineers and


game hackers, although if you are coming from any programming
background you should be able to follow along easily. The assembly
language used throughout this paper is 32bit Intel x86.

This paper is already long enough as is, if I added every little detail I
could make this an entire book. I suggest you buy a book on assembly
language programming or find an online reference. You won’t need it
to read this tutorial, but after you finish this you should go back to all
the places where I said “consult reference” and read about the
details I missed with your reference. Although Art of Assembly
focuses on programming, I highly suggest that you use this for your
reference. I also suggest the book: “Computer Organization and
Assembly Language Programming” by Michael Thorne

Tool Box
Like any other task, certain tools are required to get the job done.
We will not discuss how to use any of these tools, there are far too
many tutorials floating around the net for that. Here are some of the
programs that most reversers use:

My Recommended Debugger: SoftICE by Numega


Alternatives: OllyDbg, Interactive Disassembler Pro (IDA) by
DataRescue, W32Dasm by URSoftware

My Recommended Disassembler: Interactive Disassembler Pro (IDA)


by DataRescue
Alternatives: W32Dasm by URSoftware, OllyDbg

Debuggers are used to deal with applications at runtime, they evaluate


RAM and processes. Disassemblers are used to look at the assembly
of a binary file, where source code cannot be accessed, ie: a closed
source program.

Registers
Registers are places in the CPU where bits can be stored and
manipulated. Registers are divided into two different sections,
General Purpose Registers and Pointer (Index) Registers. GPRs can
each hold a 32bit value, while PIRs can hold a 16bit value. Only nine
registers are listed here, consult reference for more detailed
descriptions and for the rest of the registers.

The 32bit General Purpose Registers:


EAX: The Accumulator register. EAX is primarily used for I/O
operations, arithmetic, and calling services.
EBX: The Base register is often used as a pointer to a base address.
ECX: The Count register is used during loop and repetition
operations.
EDX: The Data register is used in arithmetic and I/O operations.

The 16bit Pointer (Index) Registers:


ESP: The Stack pointer always points to the top of the processor’s
stack.
EBP: The Base pointer usually addresses variables stored inside the
stack.
ESI & EDI: Source index and Destination index. Both indexes are
commonly referred to as string registers and typically process byte
strings.
EIP: The Instruction pointer specifies the next code instruction to
be executed. When you control the instruction pointer, you control the
entire process.

The GPR registers can also be used as a 16bit register; to do this you
just take away the E.
For example:
32bit EAX can become 16bit AX

A 16bit GPR register can also be divided into two 8bit registers.
For example:
16bit AX becomes 8bit AH and 8bit AL

You can use the same rules for the other GPR registers; just replace
the A with the appropriate letter of the register.
EBX à BX à BH & BL
ECX à CX à CH & CL
EDX à DX à DH & DL

Flags
Like registers, flags also store values, but flags are slightly
different. They can only hold a BOOLEAN value, or a true/false value,
1 or 0. There are nine flags maybe more or less depending on what
version of x86 processor you have. Each has its own purpose. These
are the eight used in SoftICE; instead of boringly listing each and
giving a description, I will just list them. Consult reference for
descriptions and other flags.

Carry Flag
Parity Flag
Auxiliary Carry Flag
Zero Flag
Sign Flag
Interrupt Flag
Direction Flag
Flag

Basic Opcodes
Opcodes are the actual instructions that your processor carries out.
They can be anything from simply adding, to jumping to different
addresses in memory.

The first Opcode we will look at is ADD. You are probably blowing
your brain thinking of what it does…

Let’s look at an example:

ADD EAX, EBX

In this particular operation, the values stored in EAX and EBX are
added, and the result is stored in EAX. When dealing with Opcodes,
destination is always first, and source is second.

The following Opcodes are used in the same syntax, but perform
different operations between their operands, what they do is self
explanatory if you are past kindergarten.

SUB
DIV
MUL

Here are some other basic Opcodes:

MOV: Move a value into a register, or copy the values of one register in the other.
Remember, when dealing with Opcodes, destination is ALWAYS first, and source is
second. The first example here moves the value 4 into EBX. The second example
copies the value of EBX into EAX, at the end of this particular operation; both of
these registers contain the same value.
Ex. MOV EBX, 4
Ex. MOV EAX, EBX

INC: Increment a value. If you know C++, it’s the same as ++, it adds
one.
Ex. INC EAX

DEC: Decrement a value (subtracts one)


Ex. DEC EAX

Some Advanced Opcodes


Here are some other Opcodes that you will see once in a while, a
basic description is provided. Consult a reference for the MANY
other Opcodes or examples for these ones.

LEA: Load Effective Address, same syntax as MOV, difference is


that the source can be an address or a variable.
CMP: Compares the content of one register with another. It stores
the result in specific flags.
XOR: Logical Exclusive OR
OR: Logical OR
TEST: Test bits
SHR: Shift right
SHL: Shift left
CALL: used to call functions or procedures
RET: Return from a procedure
The Stack & PUSH/POP Opcodes
The stack is a special segment of memory used for three main
purposes:

To store the return addresses of functions


To store register values
To store variables

The common metaphor for the stack is a pile of plates. It uses a last
in, first off logic, often referred to as LIFO. To add something to
the stack, the PUSH Opcode is used, to remove something, the POP
Opcode.

When a function is called, register values, function parameters, and


variables, along with the return address, are pushed onto the stack.
As memory is allocated on the stack and situated before the return
address, you may reach outside the bounds of the allocated memory
and overwrite the value of the return address and return to any
location; doing so creates a buffer overflow. Buffer overflows are
extremely important when dealing with vulnerabilities and exploits; we
will talk about them in a later section.

The Jump Opcodes


Jump Opcodes jump to a particular address in memory. For all you
code injection junkies, jumps are what you will be using. There are
many Opcodes for all the different kinds of jumps. There is one
unconditional jump:

JMP
Ex. JMP H######

JMP will jump to a particular address unconditionally, or no matter


what. Of course, the address should be specified in Hex.

Here are the basic and common conditional jumps:


JZ: Jump if last arithmetic instruction was Zero
JNZ: Jump if last arithmetic instruction was Not Zero

These are some other conditional jumps; they are somewhat


complicated and not used frequently. I’ll just list them so if you see
one you will know that it is a conditional jump. Consult a reference for
descriptions.

JA
JB
JAE
JBE
JNC
JG
JL
JGE
JLE
JO
JNO
JS
JNS
JPO
JPE
JCXZ

Buffer Overflows
Buffer Overflows are really beyond the scope of this tutorial; they
are quite complicated and usually won’t have any significance when
game hacking. I decided to put this section in here anyhow, just for
fun or if you want an introduction to exploits. A buffer overflow
occurs when the amount of data being written to memory is larger
than the amount of memory reserved for the operation. When that
occurs, the data being written actually gets written to memory beyond
the reserved section.

Let’s look at a deliberate buffer overflow in C++:


void overflow(void)
{
char *name="HiIamMoreThanTenCharactersLong"
char buff[10];
strcopy(buff, name);
return;
}

If you are familiar with C++ you probably already see the problem in
this, if you don’t know C++ it is still easy to see. Let me explain. There
are two variables declared here, name and buff. Buff is only allotted
10 bytes, but name is a lot more than 10 bytes long. When the
command strcopy is used to copy name into buff, a buffer overflow
occurs because name is too big to be stored in buff.

Hackers look for places where they can cause buffer overflows in
memory so they can do specific things, for example gaining root
access on a remote machine. This is known as exploiting vulnerability.
Vulnerabilities are extremely difficult to find, let alone exploit.

Conclusion
This tutorial covered a lot of assembly, but there is still a lot more
out there. Go out now, read some other documents, and expand your
knowledge of what you learned.

If you have any more questions on assembly I would be glad to help at


the game hacking forums. My contact information can also be found
there.

Sources (can be found at a local book store):


“Computer Organization and Assembly Language Programming” by
Michael Thorne
“Web Hacking” by Stuart McClure, Saumil Shah and Shreeraj Shah
[Drawing Text To Screen a.k.a How to make a Stat Hack]

(best viewed at 1024x768)

[PREFACE]
This is more of a programming tutorial then anything else, it will teach you how
on another process' window.This is a common method used in creating Stat hacks, w
how many resources each player has, and how many units, or max population, ..etc
other methods of creating a stat hack, but they involve tracking down the games o
function and that may be hard to find.

-------------------
[Windows API Calls]
-------------------

The FindWindow function retrieves a handle to the top-level window whose class na
name match the specified strings. This function does not search child windows.
does not perform a case-sensitive search.

HWND FindWindow( LPCTSTR lpClassName,


LPCTSTR lpWindowName
);

The GetDC function retrieves a handle to a display device context (DC) for the cl
a specified window or for the entire screen. You can use the returned handle in s
functions to draw in the DC.

HDC GetDC(
HWND hWnd // handle to window
);

The SetBkMode function sets the background mix mode of the specified device conte
background mix mode is used with text, hatched brushes, and with non-solid pen

int SetBkMode(
HDC hdc,
int iBkMode
);

Parameters:
OPAQUE :Background is filled with the current background color before the te
hatched brush, or pen is drawn.

TRANSPARENT :Background remains untouched.

The SetTextColor function sets the text color for the specified device context to
specified color.

COLORREF SetTextColor(
HDC hdc, // handle to DC
COLORREF crColor // text color
);

The TextOut function writes a character string at the specified location, using t
selected font, background color, and text color.
BOOL TextOut(
HDC hdc, // handle to DC
int nXStart, // x-coordinate of starting position
int nYStart, // y-coordinate of starting position
LPCTSTR lpString, // character string
int cbString // number of characters
);

--------------
[The Function]
--------------

I've saved you the time in trying to do research and what not and gave you my Dra
Put it in a timer, and have the timer be very fast so that it can paint every f
prints RED text with a black drop shadow. You can change this by changing the
SetTextColor().

void DrawMyText(char *windowcaption, float x, float y, char *mybuffer, int howman


{
gamewindowhandle = FindWindow(NULL, windowcaption); //get the game hwnd
HDC hdc = GetDC(gamewindowhandle);

SetBkColor(hdc,RGB(255,255,255)); //WHITE BACKGROUND


SetBkMode(hdc, TRANSPARENT); //MAKES BACKGROUND TRANSPARE
//SO ALL YOU SEE IS T
//MAKE SHADOW FOR TEXT (BLACK) and offset it by 1 pixel
SetTextColor(hdc,RGB(0,0,0));
TextOut(hdc,x+1,y+1, mybuffer,howmany);

//MAKE SECOND SHADOW FOR TEXT (BLACK) and offset it by 2 pixels


TextOut(hdc,x+2,y+2, mybuffer,howmany);

//PRINTS MY TEXT OVER THE BLACK TEXT IN RED, GIVES IT A DROP SHADOW APPEARANCE.
SetTextColor(hdc,RGB(255,0,0));
TextOut(hdc,x,y, mybuffer,howmany);

UpdateWindow(gamewindowhandle);
ReleaseDC(gamewindowhandle,hdc);
}

-------
[Usage]
-------

char buff[255];

DrawMyText("Crimsonland",155,35,"Time: ",6);

or

DrawMyText("Crimsonland",155,35,buff,3);

First parameter is the games' name.


Second is the the position in X where you want to draw the text.

Third is the Y position where you want to draw the text.

Fourth is the buffer containing text, this could either be a string in between tw
a variable of type char.

Fifth is the length of the string/buffer.

[CONCLUSION]
I know I didn't really explain anything, all you need to know is that you need a
paint on a window. And you use TextOut to write text to a DC.

The only problem with this is that every frame that the game updates, it will o
and then you paint it again, so you will get a flickering effect. There is no wa
except to find the games own draw text routine. Alternatively, you could inject
value for gold in an address of your choice ( [0313370] for me ), and then if the
of text display (such as a score display board like in Age of Kings/Mythology)
locate the code and change it to PUSH the value inside of [0313370] rathe
of the score. Thus the game will display the value of gold in the place where the

^chaos^
idxchaos@hotmail.com
www.s-i-n.com/chaos/trainerology.htm

<~~greets~~>
[sheep], MiCRal, Archmage, MrNOP, Visual Perfection, MiraMax, cppdude.
#gamehacking on efnet
Razali Rambli a.k.a Bie Tutorial on
Disable Trainer Spy Protection in TMK Trainer Using Tsearch
Download at http://www.bie.cjb.net

Word of warning! This is a technique design by Razali Rambli @ Bie


& not base on other tutorial already made. Please don't claim it as
your own. 18/12/2003

******************************************************************************
This tutorial will show you how to use Tsearch to disable Trainer Spy
Protection in TMK Trainer.

Tools Use
=========
Tsearch
or
memory searcher of your choice.

We Begin!
-------------------------------------------------------------------------------
What is TMK?
-------------------------------------------------------------------------------
TMK or Trainer Maker Kit is a tool to create trainer without knowing any
programming language.

It can be download at http://fly.to/mtc


-------------------------------------------------------------------------------
What is Trainer Spy?
-------------------------------------------------------------------------------
Trainer Spy or TS is a tool to spy on other gamehacker trainer & show us what
& where the value have been writen in game memory by the trainer.

It can be download at http://fly.to/mtc

-------------------------------------------------------------------------------
What is Trainer Spy Protection?
-------------------------------------------------------------------------------
Trainer Spy Protection is a solution invented by Drakken to block Trainer Spy
for TMK made trainer.

How to use the protection:

Add this code in the beginning of each button

Poke 0 FF 52 19 FF XX

XX = how much addres to poke in a button

If the trainer have 2 poke address in a button

so XX = 02

The code for that button is

Poke 0 FF 52 19 FF 02

So if the user use TS on that trainer... TS wont show anything.


-------------------------------------------------------------------------------
Disable Trainer Spy Protection in TMK Trainer Using Memory Searcher
-------------------------------------------------------------------------------

1. Run Protected Trainer, for example, let say the trainer have only 1 button
2. Run Tsearch & open process of the Protected Trainer
3. What value to search?

For this example, let say the trainer block 2 address on 1 button

Remember the code to block Trainer Spy? Yes, it

Poke 0 FF 52 19 FF 02

From all the above code, we only need this

FF 52 19 FF

So if the trainer have this code, thats mean the trainer is protected

Hmmm... now we know we only need to search for that value.

But we cannot search for Hex value, we can only search Decimal value in

Tsearch. We mush convert the value from Hex to Dec

Use Tsearch calculator, in hex value type

FF1952FF

But why the above code is in reversed? because usually in memory, the

value are read in reversed. So convert hex to dec ("H" to "D")

you should get this value 4279849727

Now do a 4 byte exact value.

Let say u found 1 address for example, 95DAA8

Move it to table, now at address 95DAA8, value 4279849727, 4 byte

Now add 95DAA8 + 4 = 95DAAC

Change the address on the table to 95DAAC, 1 byte

You will see the value will be 2, because we use 2 address block

for our example.

4. Change the value to 0, now the trainer block 0 address, that's mean we can
use Trainer Spy on that button.

-------------------------------------------------------------------------------
The End
-------------------------------------------------------------------------------
I hope this will help you
Razali Rambli aka Bie
http://bie.cjb.net
razali_bie@hotmail.com
Razali Rambli a.k.a Bie Tutorial on
Disable Trainer Spy Protection in TMK Trainer Using Hex Edit
Download at http://www.bie.cjb.net

Word of warning! This is a technique design by Razali Rambli @ Bie


& not base on other tutorial already made. Please don't claim it as
your own. 18/12/2003

******************************************************************************
This tutorial will show you how to use Ultraedit to disable Trainer Spy
Protection in TMK Trainer.

Tools Use
=========
Ultraedit http://www.ultraedit.com [Shareware]
or
hex editor of your choice.

We Begin!
-------------------------------------------------------------------------------
What is TMK?
-------------------------------------------------------------------------------
TMK or Trainer Maker Kit is a tool to create trainer without knowing any
programming language.

It can be download at http://fly.to/mtc


-------------------------------------------------------------------------------
What is Trainer Spy?
-------------------------------------------------------------------------------
Trainer Spy or TS is a tool to spy on other gamehacker trainer & show us what
& where the value have been writen in game memory by the trainer.

It can be download at http://fly.to/mtc

-------------------------------------------------------------------------------
What is Trainer Spy Protection?
-------------------------------------------------------------------------------
Trainer Spy Protection is a solution invented by Drakken to block Trainer Spy
for TMK made trainer.

How to use the protection:

Add this code in the beginning of each button

Poke 0 FF 52 19 FF XX

XX = how much addres to poke in a button

If the trainer have 2 poke address in a button

so XX = 02

The code for that button is

Poke 0 FF 52 19 FF 02

So if the user use TS on that trainer... TS wont show anything.


-------------------------------------------------------------------------------
Disable Trainer Spy Protection in TMK Trainer Using Hex Edit
-------------------------------------------------------------------------------

1. Load/open Protected Trainer exe in Ultraedit


2. Search>Find this hex

FF 52 19 FF

3. After you find it, look at the value on the right of "FF 52 19 FF"
4. If the trainer protect 2 poke address, the value should be

FF 52 19 FF 02

5. So we should change the 02 --> 00


6. It should look like this

FF 52 19 FF 00

7. So although the trainer use the Protection, we just make it block 0 address
8. Thats mean Trainer Spy can show what & where the value is writen in memory

-------------------------------------------------------------------------------
The End
-------------------------------------------------------------------------------

I hope this will help you


Razali Rambli aka Bie
http://bie.cjb.net
razali_bie@hotmail.com
Programming Trainers: Trainer Spy Detection
Revision Date: 07/26/00

Contents
What Trainer Spy does.
Detecting if Trainer Spy is running
Protecting trainers against Trainer Spy

What Trainer Spy Does

Most Windows based trainers use a Windows API call named WriteProcessMemory to change values
in a target process. Trainer Spy monitors these calls and records the addresses and values used.

Having a tool like this can be useful when troubleshooting a newly programmed trainer. If the trainer
doesn’t work, or works incorrectly Trainer Spy will show exactly what address is being written to
and what value is being written there. It will show if either the address or value is wrong, or both,
making it easier to figure out what is going wrong.

Unfortunately while Trainer Spy allows trainer makers to easily debug their trainers, it also lets
anyone else monitor the same information. Any wannabee game hacker can ‘steal’ the addresses and
values from a trainer and release an identically working trainer claiming it as their own. While not
exactly a crisis, most people want to protect the addresses and values they spent so much time
obtaining.

Detecting if Trainer Spy is running

There are a couple of ways to prevent Trainer Spy from loading. One way is during trainer
initialization use the CreateFile API call to create a ‘dummy’ file in c:\windows called Traspy.vxd.
As you can imagine this could be easily defeated, and if the trainer was loaded after Trainer Spy it
would have no effect at all until Trainer Spy was restarted. The code would look like the following:

HANDLE temp = CreateFile("C:\\windows\\traspy.vxd", GENERIC_WRITE, 0, NULL,


CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
CloseHandle(temp);

A better scheme is to detect if Trainer Spy is currently running before each call to
WriteProcessMemory. There are several ways to do this.
1. The easiest way to detect if Trainer Spy is running is to use the FindWindow API call.

HWND hwnd = FindWindow( NULL, "Trainer Spy" );


if( hwnd != NULL ) {
// Trainer Spy is running, exit process or cancel write
return;
}

This method works and is relatively quick but is also very easily defeated.

2. A method that can’t be defeated easily is to use the EnumWindows callback. This involves
checking a offset in each running window’s process against a known value. Though hard to
defeat there is a performance penalty to pay, so it should be considered only as a last resort.
Check msdn or other Windows help files for more information on EnumWindows.
3. A third way to detect if Trainer Spy is running is to check the WriteProcessMemory call and see
if Trainer Spy has modified it. It turns out Trainer Spy replaces one byte (the first byte) of
WriteProcessMemory to allow it to intercept API calls. By checking this byte we can tell if
Trainer Spy is active and by replacing this byte to the original one we can prevent our addresses
from being intercepted. The detection can be done using the following code.

BOOL IsTrainerSpyActive()
{
BYTE byte;
DWORD addr;

HINSTANCE hKernel = LoadLibrary("Kernel32.dll");

if(hKernel) {
addr = (DWORD)GetProcAddress(hKernel, "WriteProcessMemory");
ReadProcessMemory(GetCurrentProcess(), (LPVOID)addr, &byte, 1, 0);
FreeLibrary(hKernel);

if(byte == 0xCC) return TRUE;


}

return FALSE;
}

There are other ways of detecting if Trainer Spy is running but this is enough to get you started. The
code is written in C but should be easy to convert to any other language.

Protecting trainers against Trainer Spy

Once you know Trainer Spy is running there are a couple of things you can do to prevent others from
reading your addresses. One way is to just skip your WriteProcessMemory calls while Trainer Spy is
running. Or you could give an error message and shut down the trainer. Along with any other action
let the cheater know what you think of him. Write to a dummy address a string containing your
message for him. The code below is one way to provide protection by detecting if Trainer Spy is
running (using method number 3 above) and if it is returning without writing to the target processes
addresses.

Here is code to do this in C:

void WriteMemory()
{
DWORD pid;
HWND hwnd = FindWindow(NULL, "Anti Trainer Spy");

GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

if(hProcess == NULL) return;

char str[100] = "I see your using Trainer Spy; well good luck.";

// See if Trainer Spy is running and if it is write dummy message


if(IsTrainerSpyActive()) WriteProcessMemory(hProcess, (LPVOID)0, str, strlen(str), 0);
else {
// Only executed if Trainer Spy isn’t running
DWORD val = 10;
WriteProcessMemory(hProcess, (LPVOID)0x401000, &val, 4, 0);
}
CloseHandle(hProcess);
}

And finally the complete code for a trainer in VB using the info above. (Sets the money to 2,000,000
on level 1 of the Trainer tester available from http://www.gamehacking.com/, version 1.1)

' Function declarations we need

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _


(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private Declare Function GetWindowThreadProcessId Lib "user32" _


(ByVal hwnd As Long, lpdwProcessId As Long) As Long

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess _


As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Private Declare Function WriteValue Lib "kernel32" Alias "WriteProcessMemory" _


(ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, _
ByVal nSize As Long, ByVal lpNumberOfBytesWritten As Long) As Long

Private Declare Function WriteString Lib "kernel32" Alias "WriteProcessMemory" _


(ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByVal lpBuffer As Any, _
ByVal nSize As Long, ByVal lpNumberOfBytesWritten As Long) As Long

Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess _


As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, _
lpNumberOfBytesWritten As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" _


(ByVal lpLibFileName As String) As Long

Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long

Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule _


As Long, ByVal lpProcName As String) As Long

Private Declare Function GetCurrentProcess Lib "kernel32" () As Long

' This function detects if Trainer Spy is running


' and returns True if it is

Private Function IsTrainerSpyActive() As Boolean


Dim value As Byte
Dim addr As Long
Dim hKernel As Long

IsTrainerSpyActive = False
hKernel = LoadLibrary("Kernel32.dll")
If hKernel <> 0 Then
addr = GetProcAddress(hKernel, "WriteProcessMemory")
ReadProcessMemory GetCurrentProcess, addr, value, 1, 0
FreeLibrary hKernel
If value = 204 Then IsTrainerSpyActive = True
End If
End Function

' This sub sets the money to $2,000,000. It gets called when the
' button SetMoney is clicked

Private Sub SetMoney_Click()


' Declare some variables we need
Dim hwnd As Long ' Holds the handle returned by FindWindow
Dim pid As Long ' Used to hold the Process Id
Dim pHandle As Long ' Holds the Process Handle
Dim Money As Long ' Holds the value to write to memory
Dim str As String ' Holds the string for the Trainer Spy user

' First get a handle to the "game" window


hwnd = FindWindow(vbNullString, "Trainer::Trainer")
If (hwnd = 0) Then
MsgBox "Window not found!"
Exit Sub
End If

' We can now get the Process Id


GetWindowThreadProcessId hwnd, pid

' Use the pid to get a Process Handle


pHandle = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
If (pHandle = 0) Then
MsgBox "Unable to open process!"
Exit Sub
End If

' Check if Trainer Spy is running


If IsTrainerSpyActive Then
' Trainer Spy is running so inform the user he's a lamer and skip normal addresses
str = "I see your using Trainer Spy, get a life."
WriteString pHandle, 0&, str, Len(str), 0&
Else
' Trainer Spy isn't running so set money to $2,000,000
' Two values control the money so set both of them
Money = 2000000
WriteValue pHandle, &H40C1D4, Money, 4, 0&
Money = 1999999
WriteValue pHandle, &H40C1D8, Money, 4, 0&
End If

' Close the Process Handle


CloseHandle hProcess
End Sub

This tutorial only covers a few of the possibilities. I encourage everyone interested in making trainers
to expand upon these ideas, experiment and come up with new ideas.
beans / techno
AN ALTERNATIVE TO TRAINER-SPY

More and more trainers are protected against TS nowadays... Maybe the trainers
don't like this programs (or have an allergy for this...)

So, now you wanna know how TS can be replaced... Well, SoftIce can do the job!

But first let's see how TrainerSpy works:

When TS is launched, it loads (dynamically) a VxD in memory. This Vxd is the key
of what TS means. It hooks API WriteProcessMemory, and when a trainer calls t
API, TS intercept the pushed parameters & shows them to us:

1) the address where the trainer writes data


2) the buffer containing the data to be written
3) the length of the above buffer

If you don't believe me, try this: bpx on a push before writeprocessmemory is exe
Then trace down with F8 inside the API. And soon, you will find yourself in t
traspy.vxd code. Of course traspy if you hadn't changed it (like i did :)

The job TS does can be replaced by 2 lines of code in SoftIce:

********************************************************
* macro Sorin = "? *(esp-10);? *(esp-8);d *(esp-c) l 10"
* bpx writeprocessmemory do "p ret;cls;Sorin"
********************************************************

What the hack does this piece of ...

Here's the explanation:

==========================================================================
BOOL WriteProcessMemory(

HANDLE hProcess, // handle to process whose memory is written to


LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // pointer to buffer to write data to
DWORD nSize, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);
==========================================================================

NOTE : When the push instruction is executed, the stack is DECREASED by 4 bytes,
and when the pop instruction is executed, the stack is INCREASED by 4 byte
Esp is the stack.

!The pushes are backwards!

ex:

Let's imagine that a trainer writes some data at 401000 in a game's process.
And let's say that the stack (esp) is 63FBC0.
So the trainer acts like this:
stack (esp)=63FEC0
push lpNumberOfBytesWritten ->stack is DECREASED by 4, so this means esp is now
push number_of_bytes_to_write ->stack is DEC. by 4, so (esp-4)-4=esp-8
push pointer_to_data_to_write ->stack is DEC. by 4, so (esp-8)-4=esp-c (it's hex
push address_where_to_write ->stack is DEC. by 4, so (esp-c)-4=esp-10
push game's_process'_handle ->stack is DEC. by 4, so (esp-10)-4=esp-14
call WriteProcessMemory

That's all you need to know for now. So, after API WriteProcessMemory is executed
easily determine what contained the pushed parameters...

If we do "? *(esp-4)" in SoftIce, we'll see the "actual number of bytes written"
parameter is usualy 0. By typing "? *(esp-8)" in SoftIce, we'll see how many
were written in the game's memory by the trainer. "d *(esp-c)" will show us t
buffer containing the bytes written (what the trainer wrote). NOTICE that her
typed "d" instead of "?", because we want to see the bytes at *(esp-c). And f
we get the most important thing (the address where the trainer writes data) b
"? *(esp-10)" in SoftIce.

That was the theory. (the above method can be used with ANY API).

So <BACK TO THE CODE IN SOFTICE>

macro Sorin = "? *(esp-10);? *(esp-8);d *(esp-c) l 10" is just a macro that displ
the address where the trainer writes data, the number of bytes that the train
and the bytes that the trainer writes at that address.

bpx writeprocessmemory do "p ret;cls;Sorin" - like you can see, sets a breakpoint
writeprocessmemory. If the API is called, then SoftIce will do a "p ret" taki
the trainer's code. Then the "cls" command is executed that clears the SI dis
window, and after that the macro Sorin is executed (see above)...

Clear, pure & simple!

You will see something like this (IN SOFTICE) when a trainer writes some data:

00401384 00004199300 -> the address where trainer writes (hex & dec)
00000002 00000000002 -> how many bytes the buffer with data is
016F:4030EC 90 90 A2 04 00 00 00 00 40 00 1F 0E 00 00 8C 04 ........@....... -
buffer. NOTE that in this example ONLY the first 2 bytes (90 90) are written at 4

It it was like this:

00401384 00004199300
00000002 00000000005
016F:4030EC 90 90 A2 04 00 00 00 00 40 00 1F 0E 00 00 8C 04 ........@.......

then the first 5 bytes (90 90 A2 04 00) were written at 401384

That's it for now, I hope you understood something useful from this...

& till next time, bye-bye!

Cheers & Greets (order doesn't matter) :

Groza (my publisher : thanks!)


ParaBytes (my cracking teacher)
All in GameHacking forums
All GHU members (hi dear friends!)
JUVE :)
You (you know why :)
All tut writers (the martians, too)
romanian:
**********************************************
* Daca vreti sa fiti membri GHU, cautati-ma! *
**********************************************

Cheers,
Sorin ( Splinter@email.ro ).

"We hack ONLY what we like"


GHU ( http://www.ghu.as.ro/ ).

eof
N Ways of protecting your trainer
PART I
Short Intro
~~~~~~~~~~~

So, here we are, thinking out how to defeat those "address stealers" and their
beloved Trainer Spy...

At first, I wrote anti-anti-trainer_spy code, but then I figure out that it


isn't right to let all lazy_thievs steal the work that took others hours of
searching, dumping, testing...

Also note this:

A part of the techniques are anti-cracking methods, gathered from experienced


crackers... (To protect, you must know how to crack). Of course there are meth
that are "copyright" to their respective "fathers". They will be credited...

The code will be converted to (M)ASM, so it can be more clear and can be
translated to any other programming language easily...

After all above have been told, let's

BEGIN
~~~~~

1. TRAINER-SPY WINDOW DETECTION method

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
window_name db "TRAINER SPY",0

.code
invoke FindWindow, 0, addr window_name
.IF eax!=0

; you will be here if Trainer Spy Window is detected


; so put here the defensive code (i.e.: don't poke any value and quit traine
; see the "DEFENSIVE" section
.ELSE

; you will be here if Trainer Spy Window wasn't detected


; so you can poke the values

.END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : This is a standard method. But it can give fake results if other
program (other than Trainer Spy) has the window caption "TRAINER SPY".

Explanation : We search for Trainer Spy's window name...

Protection Mark : 1/10

2. TRAINER-SPY CLASS DETECTION method

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
class_name db "#32770",0

.code
invoke FindWindow, addr class_name, 0
.IF eax!=0

; you will be here if Trainer Spy Class is detected


; so put here the defensive code (i.e.: don't poke any value and quit traine
; see the "DEFENSIVE" section

.ELSE

; you will be here if Trainer Spy Class wasn't detected


; so you can poke the values

.END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : This is a standard method. But it can give fake results if other
program (other than Trainer Spy) has the class name "#32770"

Explanation : Here we search for Trainer Spy's class name (main window is a dialo

Protection Mark : 1/10

3. TRAINER-SPY VXD DETECTION method

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
vxd_name db "\\.\TRASPY",0

.code
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push FILE_SHARE_READ+FILE_SHARE_WRITE
push GENERIC_READ+GENERIC_WRITE
push offset vxd_name
call CreateFile
.IF eax!=-1

; you will be here if Trainer Spy VXD was detected


; so put here the defensive code (i.e.: don't poke any value and quit traine
; see the "DEFENSIVE" section

.ELSE

; you will be here if Trainer Spy VXD wasn't detected


; so you can poke the values

.ENDIF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : Another standard method... Like the other ones, it's too known and easy
to bypass. But it's more "professional" than the first 2.
Explanation : Trainer Spy does its job by putting a breakpoint on WriteProcessMem
with the help of TRASPY.vxd (look for this file in Trainer Spy's
folder). The code above tries to open a VXD (in our case, TRASPY.vx
If the vxd exist in memory, then CreateFileA will return the handle
to the vxd, which means Trainer Spy is spying. If CreateFileA retur
-1 then it isn't a vxd with the specified name in memory, which mea
Trainer Spy is not active...

Protection Mark : 2/10

4. TRAINER-SPY LOGWMEMORY.BIN method(1)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
file_name db "c:\logwmemory.bin",0

.code
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push 0
push GENERIC_READ+GENERIC_WRITE
push OFFSET file_name
call CreateFile
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : Standard... Still, better than the first ones...


The above piece of code must be called right before poking values in me

Explanation : Trainer Spy saves in this file (c:\logwmemory.bin) the addresses, t


values and the name of the program that is calling WriteProcessMemo
(the trainer). With the code above we open the file (c:\logwmemory.
and restrict the access on the file, so that Trainer Spy will not b
able to write\read to\from this file.

Protection Mark : 2/10

5. TRAINER-SPY LOGWMEMORY.BIN method(2)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
file_name db "c:\logwmemory.bin",0

.code
invoke DeleteFile,addr file_name
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : Well, this one works too...


The above piece of code must be called right before poking values in me

Explanation : Like above, instead of restricting the access on this file, we simp
erase it.

Protection Mark : 2/10


6. TRAINER-SPY_IS_USELESS method

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.code
mov eax,WriteProcessMemory ; -> mov in eax the "jmp to WriteProcessMemo
mov eax,[eax+2] ; -> mov in eax the address of WPM
mov eax,[eax] ; -> mov in eax the address of first instr.
add eax,3 ; -> we jump over the first 2 instr. (3 byte
mov lll,eax ; -> we save this address to next instructio
push 0 ;----|
push how_many_bytes_to_write ; |
push offset data_buffer ; |> the WriteProcessMemory parameters
push lpAdress ; |
push phandle ;----|
mov ebp,_return_ ; -> we save the address where we want to re
push ebp ; -> first instruction in WPM
sub esp,4 ; -> we pushed before, so we must recalibrat
mov ebp,esp ; -> second instruction in WPM
call [lll] ; -> call WriteProcessMemory from the THIRD
_return_: ; -> a label where we will be after WPM was
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : BEST METHOD THAT WILL EVER BE


Trainer Spy, Soft Ice and all the debuggers will be tricked !
Explanation : This code executes the WriteProcessMemory (WPM) from the 3rd instru
We carry the first 2 instructions in our code, then call the WPR fr
it's 3rd instruction. That's because the debuggers (including Train
replace the first instruction in WPM with an "int 3" (0CCh). When w
WPM, first is executed the "int 3" that gives the control to the de
(Trainer Spy). When Trainer Spy has the control, it saves the param
of WPM and rewrite the first instruction (int 3) with the original
With the code above, we jump over this "int 3", without letting the
debugger know that we had been there.
The first 2 instructions in WPM are : "push ebp", "mov ebp,esp" (3
Trainer Spy replace the "push ebp" with "int 3".
We jump over those 2 (carrying them in our code) and we land on the
instruction. Then the WPM will do it's job, and Trainer Spy (and al
debuggers) will not know we called that API.

Protection Mark : 11/10 (yes, it's ELEVEN OUT OF TEN) - SUPER TECHNIQUE

7. ANTI-DEBUGGING method(1) (thnx to KurruPt - FiLe)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.code
pushf
pop ax
test ah,1
je no_debugger
jmp debugger_found
;.................
no_debugger:

; here you can continue. This means your code isn't debugged.

;.................
debugger_found
; you will be here if your code is debugged
; so put here the defensive code
; see the "DEFENSIVE" section

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Remarks : The above code has to be the first code after .code :)
Explanation : When a debugger is present, it sets some flags. So, we test this an
we find a debugger, you know what you have to do. Those few lines o
are VERY OFTEN used by the virii, kicking the ass of AntiVirus prog
(thnx KurruPt - FiLe again)

Protection Mark : 6-7/10

DEFENSIVE SECTION

Here will be presented some attitudes that you'll have to take if you find someth
inconvenient spying your code.

- don't poke any values and quit the trainer

- poke some random values at random addresses (my favorite :) )

- do this: mov al,0FEh - guess what


out 64h,al - this means :)

- make a gpf (general protection fault) : xor eax,eax


mov eax,[eax]

- kill trainer-spy (not recommended)

- make an infinite cycle (my favorite, too) : mov ecx,1234


.WHILE ecx!=0 do
; put here a lot of code
; never give ecx the 0 value
.ENDW

- do nothing

- try to attack the hardware components :))))

- erase some windows_filez and the erase your own trainer

- more to come in PART II


CHEERS
~~~~~~

Well, this rubric will not be as usual... I'll thank now the people who wrote
anti-X tutorials/materials or explained them which inspired me to write this

So A BIG THANKS TO:


- Micral, [Ntsc], Harlequin, Code_Inside, _Duelist, Pulsar, ParaBytes, JJ-Okocha,
Ken_Wright, +Orc, +Fravia, Gain_T, Invali_Opcode, KurruPt - FiLe (again ?!!!?!?
- and ALL I forgot ( I'm in a hurry )
Stay tuned for PART II
Sorin ( Splinter@email.ro ).

"We hack ONLY what we like".


GHU ( http://www.ghu.as.ro/ ).

2003

eof
======================== I N T R O=====================

Hello again, dear friends! (hope i'm not speaking to walls :) )

Well, i decided to write another essay, but what should i put in it?
I can't tell u how much i like cartoons, because this text would never end ;}

I searched the game-hacking sites (u should do this too ! (( grozatt.cjb.net ) -


koolest) and i saw a lot of tuts that teach u how to protect your trainers ag
Trainer-Spy... So i decided to write some on how u could defeat trainers prot
against Trainer-Spy ! Simple heh...

Now the good hackers (and the hard working ones ;) ) would fuc* my ass:
"Hey man! What the fu*k are u teaching the lamers how to steal our work?, u mothe

But here comes the tricky part: this tut is dedicated to the hard_working newbies
after hours and hours of hacking, couldn't find where the MineSweeper inc the
=> just joking, hehehe...

Seriously, i don't think that's a good idea to hide all your work (from the eyes
people that wants to learn something from u, after they tried and tried and t
any result! ).

And i don't think the lazy lamers would loosing their time coding in asm or C the
schemes!

Man, if i don't understand something or i have problems or difficulties, i go to


experienced in the domain, and i never step over the problem ( i write to par
5-6 mails asking him to teach me how polymorph code works ... And the answer
popped! thanks para! )

========================== A N T I - A N T I - T S (the essay)=======

Now, back to our business!

Let's study a little Micral's essay about the TS (trainer spy) protections! He di
into 3 parts:

1) The Beginner's Way (Search for TS's window, if found then don't train)
2) The Middle Way (Mess up with C:\logwmemory.bin, by setting it's access to read
3) The Good Way (Check if there is a breakpoint on WriteProcessMemory, and if it
or a debugger is active => no poking )

Now, let's analyse those one by one, finding the way to break in !!!

1) Now, this method is quite good (in my opinion), because the lamers don't want
around with anything, they just want to steal the offsets !
So, i think no lamer would try to change the TS's window text! Besides, they
"TRAINER SPY" string in the file :)

a) Changing the window of TS can be done very easily :

caption db "TRAINER SPY",0


caption_after db "put here a name",0
invoke FindWindow,NULL,addr caption
cmp eax,0
jz ts_isn't_loaded
invoke SetWindowText,eax,addr caption_after

This piece of code changes the TS's window text from TRAINER SPY to put here a na
this done, this protection is passed!!!
REMARKS: BEST WAY

b) Disassemble the "protected" trainer and look on where the API FindWindow is c
the pushed value points to "TRAINER SPY" string, this is it! Change the cmp
after.
REMARKS :This should work on non-encrypted\packed trainers. BTW, use W32Dasm for
disassembling part :)

2) The second method is a LAME !!! A LAME AND NOTHING ELSE !!!
In this method u should "protect" your trainer by setting readonly access on
called logwmemory.bin . HEHEHE... Let's see how can we bypass this...

a) MOVE the Traspy.vxd from your Windows dir (if the file exist) in the same dir
TS.exe.
Grab any hex-editor and change the logwmemory.bin into hehehehehe.bin (for
in TS.exe and in Traspy.vxd (be sure that the length IS LESS OR THE SAME ie
of logwmemory.bin=14, then your new name for the file must have the length
u choose <14, then fill the remaining 14-your_length with 00h).
REMARKS: BEST WAY

b) Trap the CreateFile function called from the "protected" trainer, nop-it or c
it's SecurityAttributes from 0 to 5 for example (the file won't be accessed
and TS will do it's job :) )
REMARKS: This should work on non-encrypted and non-packed trainers!

c) Go inside the trainer and change logwmemory.bin into pppppppppp.lol


(same length of course or if less, fill with 00h).
REMARKS: This should work on non-encrypted and non-packed trainers!

.....................
many many more !!!
.....................

With this done, the 2-nd protection is passed!

3) Ah! The good way... This is indeed a way to protect your trainers! But still c
defeated! Especially when u use API's ! (see LAST-WORDS).
Here the trainer will search for a breakpoint on the API WriteProcessMemory. If
a CCh in front of it, ==> no pokes (CCh=breakpoint).
The solutions ??? Here they are :

a) Find where the "protected" trainer compares the CCh with


the_byte_in_front_of_WriteProcessMemory and kill the bad_jump\change the cm
the whole code ;)
REMARKS: Should work on non-encrypted\packed trainers!

b) See where and how the "protected" trainer is fuc*ing with kernel32 (the owner
of WriteProcessMemory) and, you know, NOP!!! hehehe...
REMARKS: This method is quite risky!
Needs experience from u !
Should work on non-encrypted\packed trainers!

========================= L A S T W O R D S========================

Phew, another one finished!


Thus, i want to mention something (but this time for the trainer creators ) :

When u code your trainers, always try to avoid using many API's ! You see, there
of manuals on how the api's are processed, and you will find your code unsecu
i know that we are in window(s)' age, but there are methods! No matter how mu
your code, it still can be "deprotected". There are many commercial products
encrypt\pack your program, but there will be always the de-crypter\un-packer

A good example is this:


Try to count 1,2,3,4,5 ! Now if u want to see from where u have started to count,
reversing: 5,4,3,2,1 ! (of course u must know where to stop ;} )

=========================== G R E E T S and C H E E R S ;) ===========

groza
all members in gamehacking's forum
micral ( i hardly wait some other protections to "unprotect" heheh! hope u will n
on me for this essay! as i write, this is not for thievs -i am a lamer,
never be a thief !- )
all members in new2cracking (especially parabytes!)
YOU for loosing your time with this (better go outside and play ! :} )
JUVENTUS (like always)
romanian greetings:
**********************************************************************
* Salutari tuturor celor din Romania -crackeri,hackeri,zidari,macaragii,profesori
* Cautati-ma!!!
* (si aveti grija cu cine votati -hehehe...-)
* La Revedere!
**********************************************************************

Sorin ( Splinter@email.ro )

2003

eof
;********************************************************************************
;---------------------------------------------
; Protection-Suit Version 1.0 (c) by [NtSC]
;---------------------------------------------
;
; I prefer to implement this Sub-Routine in an Routine permanently called by your
; (not only once,at the init...)
;
;Contents (Trainer specified):
;-----------------------------
; - CheckBreakPoints (if BreakPoints on Read/Write will be found,Goodbye)
; - CheckTrainerSpy-Routine (if Window present,Goodbye)
; - CheckTrainerSpy-Routine (if CLass present,Goodbye)
; - Create TrainerSpy data file (c:\logwmemory.bin) + set specific File-Attribute

;********************************************************************************
; Still in development:
; - checksum routine for complete suit/Trainer main routine
; - cryption of Asciiz
; - check for breakpoints on Range

;--------------------------------------------------------------------------------
Thief db "TRAINER SPY",0 ; Trainer-Spy Window-Caption
ThiefClass db "#32770",0 ; Trainer-Spy Class
Kernel32 db "Kernel32",0 ; Base of our Api´s
ReadMemory db "ReadProcessMemory",0 ; Api´s to check
WriteMemory db "WriteProcessMemory",0 ; (most common used by trainers
Data db "c:\logwmemory.bin",0 ; TrainerSpy file (Info from vxd
;--------------------------------------------------------------------------------

CheckBreakPoints: ;Check Read/Write Api´s for Breakpoints


push offset Kernel32
call GetModuleHandleA
push offset ReadMemory
push eax
call GetProcAddress
cmp byte ptr [eax],0cch ;Breakpoint set on Function?
je LamerFound

push offset Kernel32


call GetModuleHandleA
push offset WriteMemory
push eax
call GetProcAddress
cmp byte ptr [eax],0cch ;Breakpoint set on Function?
je LamerFound

;--------------------------------------------------------------------------------

CheckTrainerSpyWindow:
call FindWindowExA,0,0,0,offset Thief ;TrainerSpy Window active? if yes,Go
cmp eax,0
je CheckTrainerSpyClass
jmp LamerFound

CheckTrainerSpyClass:
call FindWindowExA,0,0,offset ThiefClass,0 ;TrainerSpy Class found?..if yes,
cmp eax,0
je CreateAntiTrainerSpy
jmp LamerFound

CreateAntiTrainerSpy: ;create our vxd refered File with Attributes


push 0
push 1
push 2
push 0
push 1
push 40000000h
push offset Data
call CreateFileA
push eax
call CloseHandle
xor eax, eax

call SetFileAttributesA,offset Data,FILE_ATTRIBUTE_READONLY+FILE_ATTRIBUTE_

jmp WecontinuewithoutLamers

;********************************************************************************
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MM MMMMMMMMMMMMMMMMMMMMMMM DMMMMMMMMMMMM DMMM
MM MMMMMMMMMMMMMMMMMMMMMMM DMMMMMMMMMMMM DMMM
MM222+ 222MMMMMMMMMMMMMMMMMMMMMMM DMMMMMMMMMMMM22222 DMMM
MMMMMD MMMMMMMMMMMU2+ 22UMMMMMMMM DM222DMMMMMMMMMMM+ DMMMM
MMMMMD MMMMMMMMMM2 UMMMMMMM D2 +HMMMMMMMMMM+ DMMMMM
MMMMMD MMMMMMMMMH HMH MMMMMMM + +HMMMMMMMMMM2 DMMMMMM
MMMMMD MMMMMMMMMD 222 MMMMMMM +MMMMMMMMMM+ UMMMMMMM
MMMMMD MMMMMMMMMD 222222MMMMMMM DMMMMMMMM+ UMMMMMMMM
MMMMMD MMMMMMMMMH UMUUUDMMMMMMM 2D HMMMMMMD +22222UMMM
MMMMMD MMMMMMMMMM2 UMMMMMMM DM2 +MMMMMMD DMMM
MMMMMU222MMMMMMMMMMMD2+ +2HMMMMMMMM222UMH222HMMMMMU222222222UMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
8888 11 9999 3333
88 88 111 99 99 33 33
88 88 1111 99 99 33
88 88 1 11 99 99 333
8888 11 99 99 33
88 88 11 99999 33
88 88 11 99 33
88 88 11 99 9 33 33
8888 11 999 3333

+------------------------------------------------------------------------------+
[ n4m3 ] : ANTI-TRAINER SPY TUTORIAL
[ By ] : MiCRaL
[ c0nt4ct ] : ex_micral@yahoo.com
[ r3l34s3 tYp3 ] : essay
[ d4t3 ] : September 6th, 2001
[ URL ] : http://www.vngamecenter.com
+------------------------------------------------------------------------------+

Table of Contents :

1. INTRODUCTION
2. HOW TO DEFEAT TRAINER SPY
2.1 SIMPLEST WAY
2.2 NORMAL WAY
2.3 GOOD WAY
3. NOTES

+------------------------------------------------------------------------------+

================================================================================
1. I N T R O D U C T I O N
================================================================================

You know Trainer Spy do you ??? Well just in case you don't know, Trainer
Spy, as the name says, is a program that can monitor any chains written in the
memory, it is used to see what bytes and what address a trainer have written in
the game's memory. It was made for educational purpose, for newbie to learn by
looking at other's code. But if it is put in the wrong hand, it could be VERY
LAME to use TS to steal the addresses and claim it as the lamer's own.
This tutorial use Delphi for example because Pascal is one of the easiest
language out there, and you can easily convert the codes in this tut to another
language like C++ or ASM... Don't ask me for these sources, they're easy to
convert so do it yourself.
Actually, the methods in this tutorial are not the BEST ones as they can
still be defeated, but ones with enough knowledge to defeat 'em don't need the
steal the addresses anyway.
Lastly, I wrote this tutorial on request only, and myself I don't think
preventing TS is good. If you do that you've over-generalize anyone to be a
lamer. There are ones willing to learn and I would really like to help.
Now, for those who want to protect your code, here comes your solution!

================================================================================
2. H O W T O D E F E A T T R A I N E R S P Y
================================================================================

1. THE SIMPLEST WAY

Let's see... how do you identify a game when you program your trainer ?
It's FindWindow() API function right ? You could also use this function to
identify the Trainer Spy window, if it is found kill the trainer (or do anything
you like). Let's pass 'TRAINER SPY' as the parameter since it is the TS's window
caption. Here's the code :

if FindWindow(nil, 'TRAINER SPY') then


begin
//do anything you like here
//show a message, format his computer.. :)
ExitProcess(0); //quit the trainer
end;

This method is quick and easy to understand, but what if the caption wasn't
'TRAINER SPY' ? If it was changed ? (Yes this is possible but I won't mention
how to do that here...just in case... :-) Let's try other methods.

2. THE NORMAL WAY

One way is to create a dummy traspy.vxd in the Windows folder, so when TS


loads it can't load this file, and so no operations are done correctly. But,
this is too easy to defeat, what if the trainer started after Trainer Spy ?
Hmm there must be other ways. Let's look in the vxd file, you can see a
strange name that looks like "logwmemory.bin"... Hmm what the heck is this
strang thing ? Now open up Trainer Spy and then look in C:\ you will see a
hidden file called 'logwmemory.bin' hmm the name probably means this file is
where TS saves the addresses... What if I clear it out ? I will use
CreateFileA() API function here. And the code will look like this :

CreateFileA('C:\logwmemory.bin',$40000000,1,0,2,1,0);

Just put it at the beginning of your program, in the Form Create event or
such... you know how to do that ! If you don't, learn now.
This way Trainer Spy still run, the trainer won't exit, but TS has became
useless now, if you try to monitor some pokes you'll see that no addresses can
be found !
This is a better method, but, again, it can still be defeated... and again,
I won't mention how to do that here. :)
And in case this method fails, I think the below method is the most
efficient and easy to do one.

3. THE GOOD METHOD


Trainer Spy accomplish its task by setting a breakpoint on
WriteProcessMemory, so you can check if it is active or not by checking the
WriteProcessMemory function. You'll only have to check the first byte, if it is
0xCC (a breakpoint) this means Trainer Spy is monitoring your trainer... Let's
kill it ! Here's the code :

function IsTrainerSpyActive:bool;
var hProcess,hKernel:dword;
addr:pointer;
b:byte;
dummy:cardinal;
proc:pchar;
begin
//nothing done yet, result is false
result:=false;

//the procedure we want to check


//in this case is WriteProcessMemory
proc:='WriteProcessMemory';

//Get current process handle


hProcess:=GetCurrentProcess;

//load the kernel library


hKernel:=LoadLibrary('kernel32.dll');

//if loaded successfully


if hKernel<>0 then
begin
//get the procedure address
addr:=GetProcAddress(hKernel,proc);

//read the first byte from the address found


ReadProcessMemory(hProcess,addr,@b,1,dummy);

//free the library


FreeLibrary(hKernel);

//if the first byte is 0xCC then TS is found


if b=$CC then result:=true;
end;
end;

The codes are well commented and I think you could understand easily. This
code can be convert to any language easily too. This is a very efficient way and
it can be done quickly too.

================================================================================
3. N O T E S
================================================================================

You can get Trainer Spy from our site: http://www.vngamecenter.com


The methods in this tut are not perfect. Experienced hackers can still
defeat these unless you write anti-debugger code or use the EnumWindows
callback, but this method cost performance penalties and is not an easy way so I
won't mention it in this tut.
greetz fly to ... groza, freeman, MOP, all TekZ, CD, FGH and former iGH
members !
Thanx Groza (http://grozatt.cjb.net) for letting me post the tut on his
site ! Visit his site for some cool trainers and tut.

For all your game hacking needs, visit TekZ : http://www.vngamecenter.com


All comments, suggestions, corrections, questions, .... are welcome, you
can contact me at ex_micral@yahoo.com

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[EOF]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DETECTING TRAINER SPY

What you will learn:How to detect trainer spy (a.k.a TS, not Tiberian Sun)
and stop most kiddies from stealing your work.

Beggining:
A lot of us have been looking for a good way to prevent people from using
Trainer Spy. Sure its a good tool to help you learn, but a lot of people steal
the memory addresses and try to pass off the work as their own. It happened
to me a few times, someone took my addresses and even the wording from
my homeworld trainer and changed 2 words (credits into cash) and claimed
he made it.

How:
Since I come from a cracking background I watched how Trainer Spy
worked. It uses a file called traspy.vxd (virtual driver device - kind of like
a .dll) to capture things from memory anytime a process (program) opens
and writes to another programs memory. So naturally I opened up
TRASPY.VXD. Then by chance I found the following string
'logwmemory.bin' ...gee what could this be. Looks like Log Windows
Memory. So I did some investigation, I went to my c:\ but there was no file
named 'logwmemory.bin' there so I made an empty one just to make sure
that there really wasn't a file there. So I ran trainer spy and turned logging
on, and with Trainer 2.01 I modified some values, and TS was triggered.
Okay TS logged one hit, I hit the stop icon. I checked back in my c:\ and the
'logwmemory.bin' was gone. So I tried to make an empty 'logwmemory.bin'
again but to my surprise Windows popped up with a msgbox saying
"ERROR cannot create file, file already in use". So the file was hidden
(Even though I have Show All Files selected under Explorer) and write
protected. So I deduced that every address taken from memory got placed in
that file. I closed trainer spy, 'logwmemory.bin' no longer existed, so I
made a new 'logwmemory.bin' and I wrote protected it (in explorer select
the file hit alt+enter and check read-only). I again started up TS and played
around with Trainer 2.01 and TS had 5 hits recorded. I hit the stop button..
and what do I get? Nothing!

FROM | ADDRESS | HEXA CHAIN


blank 0000000 00

Solution:
The solution to finding if trainer spy is running, first check for
'logwmemory.bin' in the root dir with the FindFirstFile() api call. If its
there then TS is currently running & recording. If its not there then TS is not
running OR the user hex edited the 'traspy.vxd' & 'trainer spy.exe' and
changed the filename 'logwmemory.bin' to something else or just the drive
letter. Most not to bright lamers will just hex edit the title bar of Trainer
Spy from "Trainer Spy" to something else so the FindWindow() won't find
TS. The filename that is being used to store the captured addresses is stored
in the TS process at the following address: 00426247. So if you modify this
address and change it to lets just say 'stealing_is.gay', TS will never get
results.

Here lies the only problem, it might be hard to find which program is TS if
they change the title from Trainer Spy to something else. My only solution
is to use GetWindowClass() and open every Dialog (Window Class:
#32770) based process and write 'stealing_is.gay' into 0042647.

Another idea is to create a file called 'logwmemory.bin' in c:\ when your


trainer first runs (and deletes it on exit) and use SetFileAttributes() and set
it to be hidden and read only. This will prevent a user from logging your
trainers activities, assuming they start TS and hit the record button AFTER
they ran your trainer.

Conclusion:
I hope I gave you some new incite on how TS works and how to prevent
people from stealing your shit. Sure there are a lot of work arounds and
someone who really wants to get your addresses will, but this will hinder
them in their attempts. Anyone who hasn't read this won't really know how
to prevent us from preventing them from getting our addresses. And if you
plan on punishing someone for trying to use TS to get your shit, don't delete
their files, its lame and illegal (I am sure you are shaking in your boots), as
most people are only trying to learn how you did something.

^chaos^
June 26th, 2000

chaos world (c) 1999


Do not distribute as your own
please link here
Making a trainer in Masm - Level one:Part two Poking multiple addresses/values
Author:EEDOK
E-mail/MSN:Mr_eedok@hotmail.com
Webpage:http://eedok.simplehost.com/

First things first, I promise to not make this tutorial as lengthy as the previous one, if you're going in
order you most likely would not want another 12 page massacre, and if you don't you're in luck, for
now.. In this tutorial, I'll show you how to poke multiple values at once & poke multiple addresses.
This tutorial will attempt to take the same format as the previous tutorial.

Stuff you might want


Well it's the same as last time, cept you don't really need the API guide here. You should have the
finished design of the no dialog trainer from my previous tutorial which looks something like this

.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib

Poke proto :DWORD,:DWORD,:BYTE


.data
Caption db "Caption",0
Text db "Text",0
Value db 000h
wndName db 'prog test',0
.const
address equ 41D090h

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_YESNO
.if eax==IDYES
invoke Poke, address, addr Value, 1
.endif
invoke ExitProcess, NULL

Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE


LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start

Poking multiple values


----------------------
So you've made your killer easywrite script or just took the patch/unpatch TMK script generator from
Tsearch and you wanna put that into your uber trainer but it looks something like this. Poke 401384 90
90 90 90 90 (freeze numbers on Prog test)what you'll have to do is make multiple values and define
the number of bytes you will write to. Also it may be a good idea to rename it to describe it better.
Doing so looks something like this.
your .data section should look something like this
Poke proto :DWORD,:DWORD,:BYTE
.data
Caption db "Caption",0
Text db "Text",0
Freezeval db 090h
db 090h
db 090h
db 090h
db 090h
wndName db 'prog test',0
.const
Freezeadr equ 401384h
and invoke code looks something like this
invoke Poke, Freezeadr, addr Freezeval, 5
--Q&A--
Q:But what happens when there's more than one address?
A:You'll have to invoke another poke.
-------
So now you wanna invoke a poke on multiple addresses, because you either wanna do more than one
thing, or the TMK script that was generated is more than one address, or if you're doing code
injection. The thing you gotta remember is invoking a poke is like sex, and the address is like a male
orgasm and the values are like female orgasms. There can only be one address in a poke, and in order
to get another address you'll have to invoke another poke. Anyhow going back to our example say we
wanna make both the bars and numbers frozen on prog test, the TMK scripts would be Poke 401384
90 90 90 90 90 and Poke 4013EA 90 90 90 90 90. Firstly we gotta define these new addresses and
values in the .data section.
Poke proto :DWORD,:DWORD,:BYTE
.data
Caption db "Caption",0
Text db "Text",0
Freezeval db 090h
db 090h
db 090h
db 090h
db 090h
Barfrzval db 090h
db 090h
db 090h
db 090h
db 090h
wndName db 'prog test',0
.const
Freezeadr equ 401384h
Barfrz equ 4013EAh
next we gotta invoke both these addresses and define the number of bytes to patch.
invoke Poke, Freezeadr, addr Freezeval, 5
invoke Poke, Barfrz, addr Barfrzval, 5
after putting all this together we should have something like
.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib

Poke proto :DWORD,:DWORD,:BYTE


.data
Caption db "Caption",0
Text db "Text",0
Freezeval db 090h
db 090h
db 090h
db 090h
db 090h
Barfrzval db 090h
db 090h
db 090h
db 090h
db 090h
wndName db 'prog test',0
.const
Freezeadr equ 401384h
Barfrz equ 4013EAh

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_YESNO
.if eax==IDYES
invoke Poke, Freezeadr, addr Freezeval, 5
invoke Poke, Barfrz, addr Barfrzval, 5
.endif
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start
Final note
Well if you'll be able to continue waiting, my next tutorial should be the one you're waiting for how to
make a dialog in Masm, without 50 lines of code, with visuals

Summary(for the cheaters)

To poke multiple values:

1. Define the multiple values


2. Define the byte size in the poke proto

To poke multiple addresses:

1. Define the addresses


2. Define the values to be poked to these addresses
3. invoke a poke for each address
Making a trainer in Masm - Level 2 editing and linking your res file.
Author:EEDOK
E-mail/MSN:Mr_eedok@hotmail.com
Webpage:http://eedok.simplehost.com/

Well here goes my third tutorial, the one you've been waiting for, creating the dialog without knowing
a mass amount of asm. This tutorial requires picking up Reshacker and a .res file which I can provide
if you don't already have them.

Reshacker This is made to edit the res file to what you want.
Example res file The example res file used in this tutorial.
Starting off
First off open ResHacker, and set it to open .res files like so, and open the example.

The first thing we'll do upon opening Reshacker is changing the icon of our trainer. Click the icon on
the left side like so

Hit the open file with new icon button then choose which icon you want your trainer to have. Next
we'll start with editing the dialog. So we'll start by selecting the dialog like so.
right now the dialog should be just a quit button on a window. You can easily resize the window by
clicking and dragging the edges, and you can move or resize the quit button easily by moving it or
resizing it like the window. If you want to change the caption of the window you right click on it and
hit edit dialog. If you want to add a button you'll have to right click on the dialog and hit insert
control. The insert menu should look something like this.
The window should look something like this(minus the orange in the ID box.) To add a button hit the
button that says OK on it. From there put a Caption on the button, and don't forget to give it a unique id
number(in the box highlighted in orange above). After adding a few buttons we have our standard
trainer. Mine looked something like this.

Once we're finished all this we hit the compile script button at the top. Then go file->Save as and
save it in your bin directory.
The next step would be to link it to your obj file. The way we would do this is to open up Qeditor and
your asm file, reassemble it if necessary and hit the Command Prompt button(black windows beside
the printer button). After hitting that it should take you to a dos prompt in your bin directory, while in
your directory type in
link /subsystem:windows /libpath:C:\masm32\lib file.obj file .res
This should assemble the file and upon looking at your newly created file you'll notice the cool new
icon on it.
--Q&A--
Q:Where's my dialog????
A:Right where you left it, you gotta define it in your asm file for it to work.
-------
Defining the Dialog
Now we must make the dialog the main window much like they do in Iczelion's tut #10(the part 2
part). First we start off by defining the Dialog items above the .data.
Poke proto :DWORD,:DWORD,:BYTE

ID_DLG equ 100


ID_QUIT equ 101
ID_NUM equ 102
ID_BAR equ 103

.data
Then we define the dialog proto above the .data
DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
Poke proto :DWORD,:DWORD,:BYTE

ID_DLG equ 100


ID_QUIT equ 101
ID_NUM equ 102
ID_BAR equ 103

.data
Next would be to actually define the DlgProc proto.
DlgProc Proc hWin: DWORD, uMsg: DWORD, wParam:
DWORD, lParam: DWORD
xor eax,eax
ret
DlgProc endp
Now we should put in some actions.
DlgProc Proc hWin: DWORD, uMsg: DWORD, wParam:
DWORD, lParam: DWORD
.if uMsg==WM_COMMAND
.if wParam==ID_QUIT
invoke ExitProcess,0
.elseif wParam==ID_NUM
invoke Poke, Freezeadr, addr Freezeval, 5
.elseif wParam==ID_BAR
invoke Poke, Barfrz, addr Barfrzval, 5
.endif
.elseif uMsg==WM_CLOSE
invoke ExitProcess,0
.endif
xor eax,eax
ret
DlgProc endp
Then we gotta remove the old dialog(the messagebox) and put in our new one of the new dialog. We
do this by calling DialogBoxParamA and looking at the API guide we see that in order for it to work
it needs process instance, and in order to get that we need to use the GetModuleHandle API. The final
code looks something like this.
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParamA,hInstance,ID_DLG,0,addr
DlgProc,0
invoke ExitProcess, NULL
and to end it all off give it the variables it needs to identify itself to windows, we put this in a tag
under .data called .data? this is just like the .data tag except it's not too sure of itself so it doesn't do
anything till the program is running.
.const
Freezeadr equ 401384h
Barfrz equ 4013EAh

.data?
hInstance HINSTANCE ?
The final product should look something like this
.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib
DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
Poke proto :DWORD,:DWORD,:BYTE

ID_DLG equ 100


ID_QUIT equ 101
ID_NUM equ 102
ID_BAR equ 103

.data
Caption db "Caption",0
Text db "Text",0
Freezeval db 090h
db 090h
db 090h
db 090h
db 090h
Barfrzval db 090h
db 090h
db 090h
db 090h
db 090h
wndName db 'prog test',0
.const
Freezeadr equ 401384h
Barfrz equ 4013EAh

.data?
hInstance HINSTANCE ?

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParamA,hInstance,ID_DLG,0,addr
DlgProc,0
invoke ExitProcess, NULL

Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE


LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP

DlgProc Proc hWin: DWORD, uMsg: DWORD, wParam:


DWORD, lParam: DWORD
.if uMsg==WM_COMMAND
.if wParam==ID_QUIT
invoke ExitProcess,0
.elseif wParam==ID_NUM
invoke Poke, Freezeadr, addr Freezeval, 5
.elseif wParam==ID_BAR
invoke Poke, Barfrz, addr Barfrzval, 5
.endif
.elseif uMsg==WM_CLOSE
invoke ExitProcess,0
.endif
xor eax,eax
ret
DlgProc endp
end start
After this is all done you should assemble it as normal and link it the same way as above(link
/subsystem:WINDOWS /libpath:C:\masm32\lib file.obj file.res) and you should have your new Masm
trainer. Not too bad seeing how much real coding was involved.
Making a Trainer in Masm - Level one:Part one getting started

Author:EEDOK
E-mail/MSN:Mr_eedok@hotmail.com
Webpage:http://eedok.simplehost.com/
Version:1.00
Date:May 14,2003

This will be a quick tutorial on how to make a trainer in Masm, by using trial and error(many errors),
my no dialog Masm trainer skeleton will be the file I'll be making reference to(most the time). Getting
the uncommented version is recommended if you just want your own comments. This tutorial also
includes Q&A sections, which read your mind of the questions you were about to e-mail me to ask,
cause I'm psychic and I know exactly what you're going to ask.
Stuff you might want
Required
Masm Tells you how big of a dumbass you are and how much you shouldn't even be attempting to
compiler program, proving this wrong is your ultimate goal.
Text either notepad, Or Qeditor, I like Qeditor though cause it's more fun cause it wasn't made
editor by Microsoft. So for this I'm forcing you to use Qeditor.

Recommended
Programmers dictionary, trying to program without one of these is like trying to tell a
API guide
french person how to get to the theatre, but only knowing the very basic words
My trainer see the finished results, so once you get bored of this tutorial you can go ahead and
skeleton copy my code and cheat, you lousy cheater
Hex code for without this you'll be making a trainer that does nothing, which is about as useful as a
your trainer swiss condom(just think swiss cheese).

Starting off
well first you'll want all your required files. If you use Qeditor this is as easy as hitting a button, well
2 buttons, Script then ASM Model. Otherwise you'll have to go through all the work of copying and
pasting the code below.
---------------
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib

.data

.code

start:

end start
;----------Stop Copying and pasting here-----------

Well now that we got the required files, We'll want to create a dialog in which gives the user of the
trainer the option of using it. The simplest predefined type of dialog is a message box. The other thing
we'll need is the function to exit the program, cause as much as you want to send the user into an
eternal loop of your training damnation, the user most likely doesn't want to(either that or the
compiler forces you to have one). But how oh EEDOK, could we make such functions? Well for the
exit it's actually really easy. Just place this code under where it says .code, so it looks like this..

.code
start:
invoke ExitProcess,NULL
end start

--Q&A--
Q:What does that NULL mean?
A:hell if I know, it's in working order as it is, don't change it(unless you know what you're doing)
Q:What about the message box?
A:Oh yea, I'll get back to that now
-------

Time for the message box. How to make such a simple thing? well pulling up the API guide it says to
go invoke MessageBox, (put hWnd here), (put lpText here, which is really just gonna be a reference
to the data section), (put lpCaption here, which is gonna be another reference to the data section), (put
uType here, which we have a vast choice upon, but in this tut I'll stick to MB_OK and/or
MB_YESNO)
--Q&A--
Q:I don't understand that all looks like jibberish.
A:That's not a question, and just don't worry I'll do it all for you :)
-------
So lets make this easier for you, first thing I said looking at hWnd was wtf does that do? so I set it as
NULL. Next is lpText, which I'll simplify as Text, and I'll do the same with lpCaption. For the uType
We'll use MB_OK. So then the code looks like this..
under data put this
.data
Caption db "Caption",0
Text db "Text",0

Now for the code part, for the message box put in, invoke MessageBox, NULL,addr Text, addr
Caption, MB_OK as the code, now remember the code goes starting at the top down. So here's some
examples of what's wrong and right.

Wrong
.code
start:
invoke ExitProcess, NULL
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
end start
Right
.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke ExitProcess, NULL
end start
---funny tip----
copying the MessageBox code multiple times will make it so for every time you copied it the user
will have to hit OK, even though you had to hit the paste button that many times, annoying to you or
him?
-----------------

With all this in the code, all it does is makes a message box with the Caption and Text you defined.
Now quit saying "KW1CK lOoK @t MY leEt Tr@1Ner" realize it still has no training functions.
--Q&A--
Q:But how do I make my uber 1337 trainer work?
A:Well it's kinda complicated, but I'll continue on to how to figure it out..
-------
Well thinking what does a trainer do? If you answered that question with A.)Write new values to a
running program you'd be correct. If you answered B.)manipulates predefined addresses to overwrite
the existing values there to modify them to what the programmers set the values to, such to cause the
program to react in the way the programmer intended, Drink a beer, and repeat until your answer
changes to A.). If your answer changes to what is this 'trainer' you speak of? Then immediately stop.
Asking such questions is not healthy for you. Now once you've correctly answered this question, we
pull out the API guide and go line by line to find which API would properly do this, or we could
cheat and look at someone else's source code and find it, either way you'll find this API,
WriteProcessMemory. You can look at it how you like but I'm gonna define the parameters in this API
as phandle, aHack, nVal, iSize, NULL.

so putting it in the code would look like this

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
invoke ExitProcess, NULL
end start

Now we save it as something.asm, next we go to compile it, This is done in Qeditor by hitting
Project, then hit Assemble ASM file. This will come up with the compiler, which will promptly say
we have an idiot factor of 8. Taking a closer look at these errors they're saying our variables in
WriteProcessMemory aren't defined, and saying this 8 times. Pretty redundant eh?

--Q&A--
Q:How do we fix this recurring error?
A:Define the variables
-------

Now to define the variables. well there's aHack nVal and iSize, we should define them in the .data
part of the source.

so now .data should look like this

.data
Caption db "Caption",0
Text db "Text",0
nVal db 000h
iSize db 000h
.const
aHack equ 41D090h

(this is for MTC prog test, with these values it'll change the value of the number to 0)
--Q&A--
Q:What's with the .const thingy?
A:No idea, but it seems like ppl like it better putting the aHack there instead of under the .data part.
Silly people never explained why.. Lets keep it that way..(response from ddh:All data in your
program that doesn't change and will never need to should go under .const to help prevent bugs.)
-------

--Q&A--Again
Q:Hey that phandle variable still isn't defined!!!
A:Please ask that in question form from now on.. So I guess that's what we gotta do next..
-------

Defining the variable known as phandle.


--Q&A--Once again
Q:What exactly is phandle?
A:phandle will hold the process handle
-------
Well now you're prolly wondering how to get this mythical process handle. This is obtained through
the usage of the function OpenProcess. Opening up our handy API guide it tells us that we need to
define, how much access we want, whether to let other processes use the variable, and the process id.

I defined them as such, PROCESS_ALL_ACCESS(because we want super powers over our program
mwahahahah), 0(which means false, we don't need this stuff), pid(cause it sounds like piddle, j/k,
acronym for process id). The other thing we gotta do is define what type of variable phandle is. doing
so will look something like this.

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
LOCAL phandle:DWORD
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
invoke ExitProcess, NULL
end start

So now we go back and compile this once again.(Project>Assemble ASM file, remember to save
first.) This time it'll come with an error that looks like this PROC, MACRO, or macro repeat
directive must precede LOCAL. And that phandle still isn't defined, that and now there's a variable
known as pid that's not defined. So time to fix these errors.
--Q&A--
Q:How do I fix these errors?
A:Did you not just read my previous transitional phrase?
-------
Now to fix these errors we're gonna move all the write memory code into a PROTO. What PROTO
means is beyond me, but you won't need to know this, you'll just have to know how to use it. The first
step in think of what parts of write memory actions would we want to be user defined. Looking at the
current ones I'd say aHack, nVal and iSize. Next thing to think about is what type of values these
should be, what I say is when in doubt, use DWORD. So now onto defining the PROTO. Start by
naming it, I named mine Poke after a common way to greet people where I come from. Seeing how
we're gonna have 3 variables in the code we'll define them in the proto definition process(named so
by myself). I defined them as 2 Dwords and a byte, or someone else did and I just copied them(Most
likely Micral). So now for the defining part, for some odd reason this likes to be defined over the
.data instead of under it like other types of data, this is because Proto's are rebels and don't wanna
conform to the standard procedure. So now our data part would look something like this.

Poke proto :DWORD,:DWORD,:BYTE


.data
Caption db "Caption",0
Text db "Text",0
nVal db 000h
iSize db 000h
.const
aHack equ 41D090h

Now that it's defines we'll have to put it in the code section. That and we should define the variables
to use with it. Also we should move the phandle from where it was to it's new home. So our code
would look something like this now.

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
ret
Poke ENDP
end start

looks nice, on problem is, it's not doing anything as it is, so next we would relocate our code to this
location.
----Important note-------
now that aHack, nVal and iSize are in the Poke function we could rename them to easier to read
values so our .data could look something like this

Poke proto :DWORD,:DWORD,:BYTE


.data
Caption db "Caption",0
Text db "Text",0
Value db 000h
.const
address equ 41D090h

--Q&A--
Q:Where'd size go
A:It ran away cause you smell, either that or we'll be defining it in a different way
-------

Now to get on with relocating our code. we'll move all the non message box code into the Poke proto.
So now the code looks something like this.

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start

That looks nicer, now we attempt to compile again. now we get an undefined symbol : pid, and
another error caused by that undefined symbol.

--Q&A--
Q:How do I define this pid?
A:Read the next section
-------

Well the first thing we gotta do to define this pid is give it a value type, I give it a DWORD cause I'm
in doubt. I like keeping all my defining together at the beginning of the proto so I'll give it it's value
right by where I did it with phandle. So our code would look something like this

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start

Now that we got a variable type to it, we gotta use the API to find it, now we could go through line
through line of our API guide to find it, steal from someone else's source, but it'd be easier if I just
told you that it was the GetWindowThreadProcessId API. Now looking at our handy API guide
again(if you haven't deleted it because I'm telling what to do anyways) you'll see that we need to
define window handle and where to write the pid of the window handle to. I put them as windhand
and addr pid, so the code now looks like

start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start
Attempting to compile it at this time causes us to have the error that we have another undefined
variable, this time the one known as windhand.
--Q&A--
Q:How do I define this variable?
A:read on
-------

Now to define this variable, just as every other one, we need to give it it's Variable type and find the
API for defining this(FindWindow). for FindWindow you need to give a null terminated string to the
window you want to define(meaning you gotta put it in ur .data section), or use a process lister to find
the class of the window, but we won't do that quite yet. So with this addition to the data section,
would make it looks something like this.

Poke proto :DWORD,:DWORD,:BYTE


.data
Caption db "Caption",0
Text db "Text",0
Value db 000h
wndName db 'prog test',0
.const
address equ 41D090h

and the new code would look like this

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start
Compiling it now,Drum roll makes it come up with... a grand total of.. () 0 errors, now before you
start going hah in ur face compiler I pwned ur ass, you should realize that your trainer still does
nothing.
--Q&A--
Q:Why isn't my trainer doing anything?
A:You haven't got any commands to run it.
-------

The next step would be to call this process, The way we would do this is Invoke Poke, (what to put in
for aHack),(what to put in for nVal), (what to put for isize). We'll make it do this after clicking OK on
the message box. So the new code would look like this.

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_OK
invoke Poke, address, addr Value, 1
invoke ExitProcess, NULL
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start

compiling this we get no error, now to make this into an exe. We go up to where it says Project and
hit Link OBJ Object. After hitting this hit Project and run file, and we'll see that after hitting the OK
button on your program, it does change the value of the number to 0. But the only problem is you have
no choice but to change the value to 0. A good idea now would to be to give the user of choice, but
there's one problem with our current dialog, it only has one button. So now we're going to change the
MB_OK is the msgbox function to a MB_YESNO so then there'll be 2 buttons. Upon doing so will
cause the dialog to have 2 buttons, the only problem is they'll both do the same thing, so we must
define what each one will do.

--Q&A--
Q:How would we find out on how to make the program react differently to the 2 buttons?
A:Ask a gamehacking forum, but I've already done that, so now it's in this tutorial.
-------

The we tell what button the user hit is defined in the eax. If the eax=ID_YES the user hit yet if
eax=ID_NO then the user hit no. If you do not understand how this works I just have to ask you how
did you get this far into the tutorial?(lousy cheaters skipping the other sections) I made it so that it
would do the functions when the user hits yes, so after this change in code the .code section most
likely looks something like this

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_YESNO
.if eax==IDYES
invoke Poke, address, addr Value, 1
.endif
invoke ExitProcess, NULL

Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE


LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start

And now for the finished project, that looks something like this

.486
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib

Poke proto :DWORD,:DWORD,:BYTE


.data
Caption db "Caption",0
Text db "Text",0
Value db 000h
wndName db 'prog test',0
.const
address equ 41D090h

.code
start:
invoke MessageBox, NULL,addr Text, addr Caption,
MB_YESNO
.if eax==IDYES
invoke Poke, address, addr Value, 1
.endif
invoke ExitProcess, NULL

Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE


LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
end start
;---------------End finished code here----------------------------------------

------Final Q&A--------
Q: What do the mov windhand,eax, and mov phandle,eax do?
A: They move the results from the previous api to the defined variable(windhand or phandle).

Q: There's a problem with my trainer, what's wrong?


A: Umm make your question more specific, if you want to find the error just and if the API returns a
non-zero when successful, add this after the API you think the error is at.

.if eax==0
invoke MessageBox, NULL,addr Errortext, addr Caption,
MB_OK
ret
.endif

and remember to define Errortext under the .data section like so

.data
Errortext db "Error",0

Q:Can I copy your tutorial to my site?


A:You gotta ask me first, if you're too lazy to ask you're gonna have to link to here, and yes you can
directly link to this page
-----------------------

Summary(for the cheaters)

1. Put in your required information(includes and such)


2. Put in ExitProcess (invoke ExitProcess,NULL)
3. Put in MessageBox (invoke MessageBox, NULL,addr Text, addr Caption, MB_YESNO)
4. Define Variables for the messagebox(Caption db "Caption",0
Text db "Text",0)
5. Make the poke proto
Find the window to open
Get the Process ID
Write the values to the process
6. (optional)Add error checking
Adding to a value/freezing a value

Author:EEDOK
E-mail/MSN:Mr_eedok@hotmail.com
Webpage:http://eedok.simplehost.com/

This tutorial assumes you've read my previous tutorials and already have a grasp of where to put stuff
and add functions and the likes. If you don't understand where to put things, it is recommended you
read my previous tutorials.

Stuff you might want


Masm
Give yourself a bitchslap to your head if you didn't realize this.
compiler
actually I do like RadASM over this, but for the sake of this tutorial we're going to
QEditor
use Qeditor.
API guide ahh the good old programmers dictionary.

The ReadProcessMemory API


For each one of these actions(well maybe except freeze), you will need to read the original value in
order to any actions towards it. So what tool would we need in order to do such a thing as get the
original value. If you had read the title of the section or had figured it out, it's the
ReadProcessMemory API. Looking further on to this API you'll see that it's very similar to
WriteProcessMemory, except that instead of a Value to write, you need a buffer to get the values. The
buffer you define is dependant on how many bytes you want to write. You must put it into the .data?
section like so.
.data?
ReadVal db 4 dup(?)
Defining it like this will make the buffer capable of holding 4 bytes, change the 4 to how many bytes
we need to use.

Executing the ReadProcessMemory


seeing how the ReadProcessMemory uses nearly the same parameters as Writeprocessmemory there
is 2 options you have:
A) Add another definition into your current poke code and put it in your current poke code, or
B) Have a new proc for the ReadProcessMemory.
A looks something like this.
Change Poke at the top to:
Poke proto :DWORD,:DWORD,:BYTE,:BYTE
Change poke in the .code section to:
Poke PROC aHack:DWORD, nVal:DWORD, iSize:BYTE,
option:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
.if option==0
invoke WriteProcessMemory,phandle, aHack, nVal, iSize,
NULL
.elseif option==1
invoke ReadProcessMemory,phandle,aHack, nVal,
iSize,NULL

.endif
ret
Poke ENDP
And to invoke it, it looks something like this:
invoke Poke, Address, addr ReadVal, 4, 1
Remember if you use this method to change all your pokes that WriteProcess memory to
invoke Poke, Address, addr Value, 4, 0

B would look something like this.


Add this under your Poke proto:
Peek proto :DWORD, :DWORD, :BYTE
Add this into your .code section:
Peek PROC aHack:DWORD, nVal:DWORD, iSize:BYTE
LOCAL phandle:DWORD
LOCAL pid:DWORD
LOCAL windhand:DWORD
Invoke FindWindow, NULL, addr wndName
mov windhand,eax
Invoke GetWindowThreadProcessId, windhand, addr pid
Invoke OpenProcess,PROCESS_ALL_ACCESS, 0, pid
mov phandle,eax
invoke ReadProcessMemory,phandle, aHack, nVal, iSize,
NULL
ret
Poke ENDP
And invoke it like so:
invoke Peek, Address, addr ReadVal, 4

Putting it to use
One way to put ReadProcessMemory into use is to read the value then add to the value and Write the
value back into the program. I will use method B to show how this is done, because it's less typing for
me.
invoke Peek, Address, addr ReadVal, 4 add ReadVal,10
invoke Poke, Address, addr ReadVal, 4
When wanting to add negative numbers in order to make the total value a smaller value isn't an order
of adding negative number, but that of using a different function, one known as subtraction, which
looks something like this.
invoke Peek, Address, addr ReadVal, 4 sub ReadVal,10
invoke Poke, Address, addr ReadVal, 4

Freezing values
Ok so what you need to do it Read your Values you want to freeze, then chill them to 0 degrees
Celcius.. ok well maybe it doesn't quite work like that, it's more of a read to a value then constantly
write it back to the program.. To start all this off, We need to set up a timer, taking a quick look in our
handy API guide, we see that there's a nice function to do this. One known as SetTimer. Looking at
that function we see that you have to define, the hwnd, the Timer ID, How often the Timer functions
are done, and a Timer Proc for the functions. So lets start our defining, we shall start by defining the
SetTimer, the best place to do so(in my opinion for a small project like this) is right before creating
the dialog.
Change this:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParamA,hInstance,ID_DLG,0,addr
DlgProc,0
To this:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke SetTimer,hInstance,1,90,DoTimer invoke
DialogBoxParamA,hInstance,ID_DLG,0,addr DlgProc,0
now add this among your already existing proto's
DoTimer proto
and now add this proc under your .code section, before the end start.
DoTimer Proc

DoTimer endp
Now that you've got your timer set up, you're most likely wondering how to use it to freeze values..
Well first you'll need a flag to tell the timer either to poke the memory, or not to poke the memory. A
simple flag looks like this under your .data? section.
State db ?
Next you must add functions to a button to read the original value and toggle the flag.
invoke Peek, Address, addr ReadVal, 4 mov State,1
Then define the write memory actions into the timer.
DoTimer Proc
.if State ==1
invoke Poke, Address, addr ReadVal, 4
.endif
DoTimer endp
To Unfreeze the value simply change the flag to a different number, which goes something like this.
mov State,91
So there you have it, a few uses of the ReadProcessMemory API..
**********************************************************
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

An Enormous Tut on mASM: PART 1... A Little Background

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**********************************************************

INTRODUCTION
------------

On this series of tutorials, I *WILL* try and teach you how to program in
Win32ASM (mASM Specific). There is a great tutorial by rECLAIM in TASM, which
helped me in the process of learning. But 90% ASM programmers code in mASM
so its a good choice. If you got stuck in a code, you can get support easily.

WHY MASM?
---------

1. MASM improves the readability of your source code and makes learning ASM
a lot easier.

The traditional way of calling an API Function:

push param4
push param3
push param2
push param1
call API

While in MASM:

Invoke API, param1, param2, param3, param4

2. MASM supports comparison and loop construction.

These are:
.IF, .ELSEIF, .ELSE, .ENDIF
.REPEAT, .UNTIL
.WHILE, .ENDW, .BREAK
.CONTINUE

You dont have to mess with jumps anymore. :)


TOOLS TO USE
------------

1. MASM32 PACKAGE -- win32asm.cjb.net

Contains Text Editor, assembler, linker etc.

2. Resource Editor -- protools.cjb.net

Give yourself a break and dont write rc scripts. (ONLY USED BY PEOPLE
WHO VALUE THEIR TIME)

3. TEXT EDITOR --

MASM package includes a text editor (I dont use that though). Just use
a text editor with SYNTAX HIGHLITING *VERY USEFUL*. I use ULTRAEDIT.

4. API REFERENCE -- win32asm.cjb.net

A must have if you are serious in programming.

OPCODES
-------

OPCODES are the instructions for the Processor. Here are the OPCODES NEEDED.

OPCODE MEANS

1. mov 1, 2 moves the value of 2 into 1 (actually... copies)


2. add 1, 2 adds the value of 2 into 1
3. sub 1, 2 subtracts the value of 2 into 1
4. shr ax, 16 shift all the bits of ax 16 places to the right
5. push 1 and pop 2 push the value of 1 into the stack and pops into the mem

e.g. push eax


pop var1

REGISTERS
---------

works just like variables (GENERAL PURPOSE REGISTERS ONLY)

32bit lower 16bits highbyte lowbyte PURPOSE

eax ax ah al ACCUMULATOR
ebx bx bh bl BASE
ecx cx ch bl COUNTER
edx dx dh dl DATA

Although they have names, you can use them for anything.

WINAPI
------

These are the set of functions provided by the system. The heart of
Windows Programming.

Contact
-------

For questions and shit:


e-mail : tsongkie@gamefreaks.ph
**********************************************************
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

An Enormous Tut on mASM: PART 2... A Trainer Engine

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**********************************************************

Needed files : Download Here


(http://www.xcheater.com/tutorials/files/tsongkie_files.zip)

WHAT NOW?
---------

Ok... we're here to develop a trainer engine in MASM. If you haven't


read part 1 of this tutorial, READ IT FIRST G0D|)AM!T. But if you think
you can survive w/o it, then go on...

WHAT YA NEED
------------

1. All that is stated in part 1 PLUS


2. A game (I used prog test in MTC for testing purposes)
3. Basic ASM programming knowledge
3. A HELLUVA BRAIN

API's TO USE
------------

I won't go and explain each API. It takes space. Look them up in


your WINAPI REFERENCE. Here they aa you see it in the source.

1. GetModuleHandle
2. DialogBoxParam
3. SetTimer
4. LoadIcon
5. SendMessage
6. ExitProcess
7. MessageBox
8. GetAsyncKeyState
9. FindWindow
10. GetWindowThreadProcessId
11. OpenProcess
12. ReadProcessMemory
13. WriteProcessMemory
14. CloseHandle

TRAINER ROUTINE
---------------

1. Show the DialogBox


2. Check for Button Press Events
2.1 If clicked show command
3. Check for timer messages
3.1 If pressed call our trainer engine
4. exit

OUR TRAINER ENGINE


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

If you have seen the source you will see the TrainerEngine Procedure. I have mad
this procedure to make programming easier. It takes care of editing game values.
Very Useful if you have *MANY HOTKEYS*.

TrainerEngine PROC lpWindCap:DWORD, lpAdress:DWORD, lpNewValue:DWORD, nAdd:DWORD

If you want to change the value:


;call engine, window name, game adress, the bytes to write, NOT USED, NOT
Invoke TrainerEngine, offset WindCap, addie1, offset bytes2write, NULL, N

If you want to add a value:


;call engine, window name, game adress, NOT USED, the data to add, buffer for Re
Invoke TrainerEngine, offset WindCap, addie2, NULL, 5, offset buffer1

The SourceCode
--------------

.386 ;Dont Worry about this a bit


.model flat, stdcall ;
option casemap:none ;used so that windows.inc will function correctly

include /masm32/include/windows.inc ;Include all this libraries


include /masm32/include/user32.inc ; works just like header files
include /masm32/include/kernel32.inc

includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/user32.lib
DlgProc PROTO :DWORD, :DWORD, :DWORD, :DWORD ;Declare Procedures
TrainerEngine PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD

.data

ErrorCaption db 'ERROR', 0 ;CHANGE!!! the error caption (always teminated by 0


ErrorMessage db ' Game is not Running',0ah ;CHANGE!!! the message if
db ' You need to run the game',0ah
db 'So You can Use the trainer',0
AboutCaption db 'About',0 ;CHANGE!!! about caption
AboutMessage db ' Tsongkies Trainer Tut',0ah ;CHANGE!!! about message
db ' Modify Source Anyway You want',0ah
db ' hope this helps you',0
HelpCaption db 'Help',0 ;CHANGE!!! help caption
HelpMessage db 'Press F12 while in game or', 0ah ;CHANGE!!! help message
db 'Press F11 while in game',0
WindCap db 'prog test',0 ;CHANGE!!! the window name of game
bytes2write db 090h ;CHANGE!!! bytes to be written
db 090h

;the variables
buffer1 dd ? ; buffer to place read data
hInstance dd ? ; handle of our program
_hanicon dd ? ; handle of icon
windhand dd ? ; window handle
phandle dd ? ; process handle of game
pid dd ? ; process id of game

.const
DIALOG105 equ 105 ;
ICON106 equ 107 ;look at the resource file
ABOUTBUT equ 101 ;for these constants
HELPBUT equ 102 ;
addie1 equ 401384h ;CHANGE!!! your address to edit
addie2 equ 41D090h ;CHANGE!!! your address to edit (h means hexadecimal)

.code

c_mahal: ; doesn't matter what name you use this for

invoke GetModuleHandle, NULL ;Get the handle of our program


mov hInstance, eax ;move our handle to hInstance

; Call DialogBoxParam, handle of our prog, our dialog for trainer.res, NULL, adre
Invoke DialogBoxParam, hInstance, DIALOG105 , NULL, offset DlgProc, NULL

DlgProc PROC hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM ;Our Dialog B

.if uMsg == WM_INITDIALOG ;When our program is executed

pushad ;Saving registry is needed... the program will crash if you omit th

Invoke SetTimer,hwndDlg,0,90, 0 ; Set The Timer


Invoke LoadIcon, hInstance, ICON106 ; Load the Icon
mov _hanicon, eax ; save the handle of icon to eax

push eax ; Push eax


Invoke SendMessage, hwndDlg, WM_SETICON, FALSE, eax ; Set the small Icon
pop eax ; pop eax

ret ; return and start again

.elseif uMsg == WM_CLOSE ;Did the user close the Dialog Box?

Invoke ExitProcess, NULL ; Exit our Process

.elseif uMsg == WM_COMMAND ; Did the user press a button

mov eax, wParam ; mov wParam to eax

.if ax == ABOUTBUT ; check for the about button... was it clicked


shr eax,16
.if ax == BN_CLICKED ; if yes
Invoke MessageBox, hwndDlg, offset AboutMessage, offset AboutCaption, MB
.endif

.elseif ax == HELPBUT ; was the helpbutton clicked?


shr eax, 16
.if ax == BN_CLICKED ; if yes
Invoke MessageBox, hwndDlg, offset HelpMessage, offset HelpCaption, MB_O
.endif

.endif

.elseif uMsg == WM_TIMER

Invoke GetAsyncKeyState, VK_F12 ;was F12 pressed?


.if eax != 0 ;if yes
Invoke TrainerEngine, offset WindCap, addie1, offset bytes2write, NULL, N
.endif

Invoke GetAsyncKeyState, VK_F11 ;was F11 pressed?


.if eax != 0
Invoke TrainerEngine, offset WindCap, addie2, NULL, 5, offset buffer1 ;
.endif

.endif

ret ;return and start again

popad ;restore the registers

DlgProc ENDP
TrainerEngine PROC lpWindCap:DWORD, lpAdress:DWORD, lpNewValue:DWORD, nAdd:DWORD,

Invoke FindWindow, NULL, lpWindCap

.if eax == 0 ; If game is not running


Invoke MessageBox, hInstance, offset ErrorMessage, offset ErrorCaption, MB_OK

.else ;the game is running


mov windhand, eax ;move the handle to windhand

.endif

Invoke GetWindowThreadProcessId, windhand, offset pid ;Get the process ID a


Invoke OpenProcess, PROCESS_ALL_ACCESS,NULL, pid ;Open the process
mov phandle, eax ;move our process handle to phandle

.if nAdd == 5 ;Was the instruction to add?

Invoke ReadProcessMemory, phandle, lpAdress, lpBuffer, 2, NULL ;read the ad


mov ecx, nAdd ;move the value to add to ecx
mov ebx, dword ptr [lpBuffer] ;move the current value to ebx
add dword ptr[ebx], ecx ;add value of ecx to ebx
Invoke WriteProcessMemory, phandle, lpAdress, offset buffer1, 2, NULL ;write

.else ;Instruction is to NOP

Invoke WriteProcessMemory,phandle, lpAdress, lpNewValue, 2, NULL ;Write 9090

.endif

Invoke CloseHandle, phandle ;Close handle


ret ;return

TrainerEngine ENDP

end c_mahal

ASSEMBLING
----------

1. Put trainer.asm and trainer.res into c:\masm32\bin {default masm directory}


2. Open notepad and copy this:

@echo off
ml /c /coff /Cp trainer.asm
link /subsystem:windows /LIBPATH:c:\masm32\lib trainer.obj trainer.res
pause>nul

3. Save it as make.bat
4. Run make.bat
FINAL WORDS
-----------

You can modify the source in any way you want. If you have any questions
and shit... don't hesitate, e-mail me tsongkie@gamefreaks.ph
Archea Hacking - Trainers in MASM 1
[Written by Archea254]

Ok, in this tutorial we will be discussing advanced debugger techniques.


Keep in mind that although there are many ways to protect your programs
from debugging there are many more ways to defeat those protections.

All of the code examples used here are written in MASM, if you havn't
downloaded the example code you will need to download it now!

http://primal.framper.com/Downloads/antidebugmasm.zip

Although, I can guarantee that these techniques probly will atleast


protect you from 95% of the population ;).. It's the other 5% you
need to worry about. That is of course if they decide the want to
crack your program for some reason or another! And that is only
if they have the incentive and motivation! Otherwise you should be
realitively safe using these techniques...

What is a debugger? First let me describe import tables. Import tables


are basically this. According to the intel manuel.There are certain
instructions written into the cpu! Some of these instructions you are
probably already familiar with, like writeprocessmemory and readprocessmemory.
But that is besides the point. A debugger will patch an offset in one of
these import tables in such a way so that it can tell everything about
when and how a perticular instruction is used. It does it whenever a
program calls a perticular instruction. Let me give an example!

Say for example you press a button on a program and a messagebox pops up.
When you pressed that button, the program calls USER32.DLL and imports
what it needs to make the messagebox! Since USER32.DLL is an import.
If one wanted to find where the offset inside of the executable that calls
USER32.DLL is, they would type bpx messageboxa into softice or any other
similar debugger and the debugger could get the offset by patching the
MESSAGEBOXA offset within USER32.DLL.

Now that we know how a debugger works let's describe some ways to defeat
debuggers! :D

I guess I could put these protections into 2 categories!


direct and indirect protect techniques.. Basically, techniques
that target certain debuggers and techniques that target most
if not all types of debuggers!

In the direct category we will be learning how to detect:


Dos debuggers,softice, and trainer spy by corsica productions.

In the indirect category we will be learning the following techniques!:


Debugger breakpoint detection and exception handling checks.

Ok, let's get started! Let's discuss some of the more direct methods
of debugger detection!

Let's discuss some techniques used to protect against trainer spy!


First I will list optional ways to protect against trainer spy. I
say optional because these techniques can be easily defeated and
should not soley be used on their own. If you don't want to use these
than scan on down to the section where I discuss indirect protection
techniques! Otherwise happy reading! ;)

The first optional way to protect against trainer spy is to use


a timer to write logwmemory.bin consistently to drive c:\.
The reason for this is because the process will be used and
the user can not easily delete the file and if he does it
will be rewritten. When user tries to rip an offset with
trainer spy, it can not be logged because it can't overwrite
the fake logwmemory.bin in the main directory! Even a
Newbie can defeat this protection solely with a hex editor.
So like I said, don't use this trick alone. ;)

The second optional way would be to detect the trainer spy


window using findwindow.. Again, a newbie with a hexeditor
can defeat this!

tspytitle db "TRAINER SPY",0

invoke FindWindow,0,addr tspytitle


test eax,eax
jz continue1@@
jmp @@tspyfound
continue1@@:
;tspy not found and continues

The third way would be to detect the presence of Traspy.vxd


in memory! This is done by creating a dummy Traspy.vxd in
memory and then scanning for it's twin!

TSPYVXD db '\\.\TRASPY',0

invoke CreateFileA,offset TSPYVXD,0C0000000h,3,0,3,4000000h,0


cmp eax, 0ffffffffh
jnz @@tspyfound
;tspy not found and continues

This is a little more tricky, however a newbie


can still defeat this!

The fourth way would be to scan for the presence of logwmemory.bin


in drive c:\ and TRAINER SPY.ini in c:\windows\.. again a newbie
can defeat this!

That about it, there are a few other ways; but these are the most popular and
I don't feel like listing anymore...

Ok, now that we have established techniques trainer spy, let's go and talk about
and 16bit debuggers and direct ways to specifically detect them!...

The way you detect a 16bit debugger in masm is by using the IsDebuggerPresent.
It will return 1 if a dos debugger is present. Basically from my observations
it will only detect dos debuggers. So softice we will not be detected!

invoke IsDebuggerPresent
cmp eax,1
je @@16bit

There are a few ways to detect if softice is running or installed on the users
system. As we mentioned in the trainer spy section there is a bit of code that
can be used to detect the presence of certain vxds in memory. Softice actually
has 2 vxds.. SICE and SIWVID... using the same bit of code should work perfectly!

invoke CreateFileA,offset SIWVID,0C0000000h,3,0,3,4000000h,0


cmp eax, 0ffffffffh
jnz @@softice
invoke CreateFileA,offset SICE,0C0000000h,3,0,3,4000000h,0
cmp eax, 0ffffffffh
jnz @@softice

The next way is to check if there is an instance of softice in the registry.


Note: I didn't feel like rewritting this so I borrowed this bit of code from
another program...

.data

TitleMsg db 'SoftICE registry keys detector',0


FoundMsg db 'Found SoftICE registry key!',0
NotFoundMsg db 'registry keys not found!',0
hKey db 'HKEY_LOCAL_LACHINE',0
SubKey db 'Software\NuMega\SoftICE',0
pHkey dd 0

.code
Start:

lea eax, [pHkey]


invoke RegOpenKeyExA,80000002h,offset SubKey,0,00020019,eax
test eax,eax
jnz Quit
push eax
invoke RegCloseKey
invoke MessageBox,0,offset FoundMsg,offset TitleMsg,0
Quit:
push 0h
call ExitProcess
End Start

Argh! That was a lot of typing ;) That's about all I feel like listing for now!

Now that we have successfully digested the milk let's go right on to the meat!

Now we will be discussing the best ways [in this tutorial] to detect if a
debugger is present!

We will be discussing 2 techniques here! First let's discuss how to detect


if a debugger has a break on the writeprocessmemory api!

First things first! Get the process of KERNEL32.DLL by using GetModuleHandle.


Next, get the offset within KERNEL32.DLL where WriteProcessMemory resides.
We then get the offset in eax and compare it to 0CCh which is hex for int3.
If they both equal zero then we have a breakpoint on writeprocessmemory!
kernel db "kernel32.dll", 0
writepmem db "WriteProcessMemory",0
kernelh dd 0

invoke GetModuleHandle,ADDR kernel


invoke GetProcAddress, eax, ADDR writepmem
cmp byte ptr [eax],0cch
jz BPXWriteProcessmemoryfound

Pretty simple, huh? ;) This little trick will fool almost all newbies..
However, there are tricks that can fool this code into thinking everything
is all ok. It's fine for now untill you start studying anti-anti-debugger
tricks. But by then you should know enough on how to protect your programs! ;)

Now let's talk about the exceptions handler technique.. This is also a very simpl
and effective technique. It's very similar to the above code except it detects if
a debugger is patching any import table. If a debugger is not detected it then
calls a protocol, which in this case I have named startproc.

invoke SetUnhandledExceptionFilter,addr startproc


mov eax, 4
mov ebp, 'BCHK'
int 3

Below int 3 you should call a messagebox with an exitprocess or something along
that line, as it just continues on if the debugger is found...

Well, that's about all I feel about writting about now! You should know enough no
to keep most of your code safe as long as an intelligent, hardcoded, and dedicate
cracker doesn't want to take a peek at anything! ;) But if someone does get a pie
of your code don't blame me! After all, someone has to be within that 5% ;P
;*************************************
; NO NEED TO CHANGE THIS SECTION
;*************************************
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\shell32.inc
include \masm32\include\kernel32.inc
include \MASM32\INCLUDE\masm32.inc
include \MASM32\INCLUDE\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \MASM32\LIB\masm32.lib
includelib \MASM32\lib\user32.lib
includelib \MASM32\lib\shell32.lib

DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD


Poke proto :DWORD,:DWORD,:DWORD
Peek proto :DWORD, :DWORD, :DWORD

;*************************************
;*************************************

;*************************************
; REFERENCE TO DIALOG OBJECT (in res file)
;*************************************
;**Make sure the ID in the res files is the same as your ID here
;**If your 1st button = 101 in res, put your ID_ON = 101 too
ID_DLG equ 100 ;your dialog id
ID_ON equ 101 ;1st button id
ID_OFF equ 102 ;2nd button id
ID_QUIT equ 103 ;exit button id
;*************************************
;*************************************

.data ;No need to change this


gamenamehere db 'Ricochet',0 ;Insert the game windows name here
pokehere dd 049F613h ;Address where the value to poke
On dd 90h ;Value you want to poke at address
;to turn on the cheat
Off dd 48h ;Value you want to poke at address
;to turn off the cheat
Dummy dd 0 ;Just leave it 0
Buf dd 0 ;Just leave it 0

.data? ;No need to change this


hInstance HINSTANCE ? ;No need to change this
hProcess dd ? ;No need to change this

.code ;No need to change this


main: ;You can change it with ever name
;you want, but change also the last
;name too (see bottom)

invoke GetModuleHandleA, NULL ;No need to change this


mov hInstance,eax ;No need to change this
invoke DialogBoxParamA,hInstance,ID_DLG,0,addr DlgProc,0 ;Make dialog base on the
invoke ExitProcess,NULL ;If done making it, exit this process.
DlgProc Proc hWin: DWORD, uMsg: DWORD, wParam: DWORD, lParam: DWORD ;The beginnin
.if uMsg==WM_INITDIALOG ;If the dialog created
invoke SetTimer,hWin,1,90,NULL ;90 = set how many time this trainer poke/peek

.elseif uMsg==WM_COMMAND ;If button are push, check which button


.if wParam==ID_QUIT ;If button quit is push
invoke ExitProcess,0 ;exit trainer
.elseif wParam==ID_ON ;If button On is push
invoke Poke,pokehere,On,1 ;Poke, Address, On Value, how many byte
.elseif wParam==ID_OFF ;If button Off is push
invoke Poke,pokehere,Off,1 ;Poke, Address, Off Value, how many byte
.endif ;Close checking which button have been push

.elseif uMsg==WM_TIMER ;Check the timer


invoke GetAsyncKeyState,VK_F11 ;Check if keyboard key F11 is push
.if eax!=0 ;If yes
invoke Poke,pokehere,On,1 ;Poke, Address, On Value, how many byte
.endif ;If not, check other, then check it again base on
;how much we put on the WM_INITDIALOG

invoke GetAsyncKeyState,VK_F12 ;Check if keyboard key F12 is push


.if eax!=0 ;If yes
invoke Poke,pokehere,Off,1 ;Poke, Address, Off Value, how many byte
.endif ;If not, check other, then check it again base on
;how much we put on the WM_INITDIALOG

.elseif uMsg==WM_CLOSE ;If the "X" on the dialog is pressed


invoke KillTimer,hWin,1 ;close timer
invoke EndDialog,hWin,0 ;close dialog
.ENDIF ;Stop checking the dialog
xor eax,eax ;Erase all register
ret ;return
DlgProc endp ;the end

;*************************************
; NO NEED TO CHANGE THIS SECTION
;*************************************
;Write value to address specified
Poke Proc lpBaseAddress: DWORD, nValue: DWORD, bie: DWORD
invoke FindWindowExA,0,0,0,addr gamenamehere
invoke GetWindowThreadProcessId,eax,addr Dummy
invoke OpenProcess,PROCESS_ALL_ACCESS,0,Dummy
mov hProcess,eax
invoke VirtualProtectEx,hProcess,lpBaseAddress,bie,PAGE_EXECUTE_READWRITE,addr D
invoke WriteProcessMemory,hProcess,lpBaseAddress,addr nValue,bie,addr Dummy
invoke CloseHandle,hProcess
ret
Poke endp

;Read value from address specified


Peek proc lpBaseAddress: DWORD, nNumOfBytes: DWORD, lpReadBuffer: DWORD
invoke FindWindowExA,0,0,0,addr gamenamehere
invoke GetWindowThreadProcessId,eax,addr Dummy
invoke OpenProcess,PROCESS_ALL_ACCESS,0,Dummy
mov hProcess,eax
invoke ReadProcessMemory,hProcess,lpBaseAddress,lpReadBuffer,nNumOfBytes,NULL
invoke CloseHandle,hProcess
ret
Peek endp
;*************************************
;*************************************

end main ;Remember, if you change 'main' at the begining of this 'code' change th

*************************************
below this, you can write anything &
it wont be compile inside the trainer
Suitable for u to write note or something

When u use this, please remember to give


proper credits to me Razali Rambli and all
my gamehacking guru.

Razali Rambli
Malaysia
razali_bie@hotmail.com
http://bie.cjb.net

Greet to all my friend and gamegacking guru at:

Devious (http://www.devious.tsongkie.com)
CES (http://www.gamehacking.com)
Extalia (http://www.extalia.com)
UnknownCheat (http://www.unknowncheats.com)
XCheater.com
and all over the world, past, future, present.

History:

December 2003 - Initial Release


January 2004 - Added Virtualprotectex
*******************************************
From dse@pacific.net Sun Aug 21 16:22:28 1994
Newsgroups: alt.lang.asm
From: dse@pacific.net (DSE Software)
Subject: Anti-Anti-Debugging Code
Organization: Pacific Internet
Date: Sun, 21 Aug 1994 04:00:35 GMT

-> Anybody can tell me how to do a good anti-debugging routine


-> for protecting my asm programs from curious eyes? Also,
-> how can I fool Sourcer?

;;
;; Note by Uwe E. Schirm:
;; This refers to the 'Anti Debugging Tricks' by Inbar Raz
;; which is also found in the 80XXX Snippets as ANTIDBG.TXT
;;

Sun 24 Jan 93
By: Michael Forrest

Hi. Here's release 1 of the Anti-Anti Debugging Tricks article.

> In order to avoid tracing of a code, one usually disables the


> interrupt via the 8259 Interrupt Controller, addressed by
> read/write actions to port 21h.

This is completely ineffective against Soft-ICE, which will still break


in even when the KB interrupt is disabled. I've never seen a case where
SI won't break into the code without your program actually reaching out
and unplugging the keyboard.

> Just as a side notice, the keyboard may be also disabled by


> commanding the Programmable Peripheral Interface (PPI), port 61h.

That code doesn't seem to do anything at all, even to debug.

> This is quite an easy form of an anti-debugging trick.


> All you have to do is simply replace the vectors of interrupts
> debuggers use, or any other interrupt you will not be using or
> expecting to occur.

Any debugger that's worth anything these days works in a virtual


machine. That means that it keeps a separate interrupt table for
itself. If you try to get to it, you'll get a general protection fault
and you'll crash when running under QEMM, Windows, OS/2, or any other
protected mode system.

> This method involves manipulations of the interrupt vectors,


> mainly for proper activation of the algorithm. Such action, as
> exampled, may be used to decrypt a code (see also 2.1), using
> data stored ON the vectors.

Again, debuggers keep separate interrupt tables for themselves.

> This is a really nasty trick, and it should be used ONLY if you
> are ABSOLUTELY sure that your programs needs no more debugging.
It IS a really nasty trick against a real-mode debugger like Debug or
something else available 5-10 years ago, but completely useless against
Soft-ICE, TD386, or any other protected mode debugger.

> This method simply retains the value of the clock counter, updated
> by interrupt 08h, and waits in an infinite loop until the value
> changes. This method is usefull only against RUN actions, not
> TRACE/PROCEED ones.

That'll defeat DEBUG and not much else. Any other debugger has a key
that'll break into the code. At that point, one could go into trace
mode or just replace the JZ 0109 with a series of NOP instructions.

> This is a very nice technique, that works especially and only on
> those who use Turbo Debugger or its kind. What you should do is
> init a jump to a middle of an instruction, whereas the real address
> actually contains another opcode.

I'm not really sure what you're trying to accomplish here, but it
doesn't do much. A simple "U CS:IP" or its equivalent in any other
debugger will show the current instruction. Anyway, the code isn't
correct.

IN AL,21 IN AL,21h
MOV AL,FF MOV AL,0ffh
JMP 0108 JMP 108
MOV Byte Ptr [21E6],00 ---> MOV BYTE PTR [21e6h],0cdh
INT 20 ---> db 20h

You had an extra 00 in there.

> This is a nice trick, effective against almost any real mode
> debugger. What you should do is simply set the trace flag off
> somewhere in your program, and check for it later.

Isn't it sort of silly to be trying to defeat real-mode debuggers?


That's sort of like putting locks on your back door to make sure nobody
gets into your house while leaving the front door wide open.

> This is a technique that causes a debugger to stop the execution


> of a certain program. What you need to do is to put some INT 3
> instructions over the code, at random places, and any debugger
> trying to run will stop there.

Assembling a NOP over the int 3 will get rid of the break. Also, many
debuggers (like Soft-ICE) can be set to not break on an INT 3.

> This trick is based on the fact that debuggers don't usually use a
> stack space of their own, but rather the user program's stack space.

I'm not sure where you're getting this, but today's debuggers keep their
own stack safely hidden away in a protected segment where your program
can't corrupt it. This is also only effective against real-mode
debuggers if you intend to run your entire routine with interrupts
cleared, since most ISR's depend on your stack being there as well.

> This is a nice way to fool Turbo Debugger's V8086 module (TD386).
> It is based on the fact that TD386 does not use INT 00h to detect
> division by zero.

Did you actually try this? It doesn't seem to have much effect at all
on TD386. Soft-ICE traces through it quite happily too.

> Another way of messing TD386 is fooling it into an exception.


> Unfortunately, this exception will also be generated under any
> other program, running at V8086 mode.

Yes, and in a debugger it's _really_ easy to change the code while
you're tracing through it to jump right over the offending instruction.
All that you've done is eliminated compatibility with a lot of systems.

> The first category is simply a code, that has been encrypted,
> and has been added a decryption routine. The trick here is that
> when a debugger sets up a breakpoint, it simply places the opcode
> CCh (INT 03h) in the desired address, and once that interrupt is
> executed, the debugger regains control of things.

ANY decent debugger these days will let you use hardware breakpoints
which have nothing to do with INT 3 or any other instruction replacing
existing code. They'll let you set breakpoints wherever you'd like
without messing up encryption routines or self-modifying code.

> This is an example of a self-tracing self-modifying code,


> sometimes called 'The running line'. It was presented by Serge
> Pachkovsky.

This is really the only effective measure in this document. It defeated


every debugger I tried except for Soft-ICE. Even under Soft-ICE it was
hard to trace, since Soft-ICE has a quirk to it - it disables the trace
flag after each instruction. It also includes fkey macros though, so
once you realize what's going on, it's pretty easy to force it to turn
the trap flag back on before it executes the next instruction. With a
couple of additional macros, I had it set up to trace through the code
like nothing unusual was happening, except of course that the code I was
looking at kept changing, but that's another matter.

I had to change the routine you included since it doesn't handle multi-
byte instructions very well.

* DSE Online! * The Home of PB/VISION & PB/WORKSHOP for PowerBASIC 3.0

--
/\/ Daniel P. Stasinski /\/ Voice: +1-707-459-4358 /\/
/\/ DSE Software Publishing /\/ FAX/BBS: +1-707-459-4484 /\/
/\/ Post Office Box 96 /\/ Email: dse@pacific.net /\/
/\/ Willits, CA 95490-0096 /\/ FidoNet: 1:125/123 /\/
Tutorial 28: Win32 Debug API Part 1

In this tutorial, you'll learn what Win32 offers to developers regarding debugging primitives. You'll
know how to debug a process when you're finished with this tutorial.

Theory:
Win32 has several APIs that allow programmers to use some of the powers of a debugger. They are
called Win32 Debug APIs or primitives. With them, you can:

Load a program or attach to a running program for debugging


Obtain low-level information about the program you're debugging, such as process ID, address
of entrypoint, image base and so on.
Be notified of debugging-related events such as when a process/thread starts/exits, DLLs are
loaded/unloaded etc.
Modify the process/thread being debugged

In short, you can code a simple debugger with those APIs. Since this subject is vast, I divide it into
several managable parts: this tutorial being the first part. I'll explain the basic concepts and general
framework for using Win32 Debug APIs in this tutorial.
The steps in using Win32 Debug APIs are:

1. Create a process or attach your program to a running process. This is the first step in using
Win32 Debug APIs. Since your program will act as a debugger, you need a program to debug.
The program being debugged is called a debuggee. You can acquire a debuggee in two ways:
You can create the debuggee process yourself with CreateProcess. In order to create a
process for debugging, you must specify the DEBUG_PROCESS flag. This flag tells
Windows that we want to debug the process. Windows will send notifications of important
debugging-related events (debug events) that occur in the debuggee to your program. The
debuggee process will be immediately suspended until your program is ready. If the
debuggee also creates child processes, Windows will also send debug events that occur in
all those child processes to your program as well. This behavior is usually undesirable.
You can disable this behavior by specifying DEBUG_ONLY_THIS_PROCESS flag in
combination of DEBUG_PROCESS flag.
You can attach your program to a running process with DebugActiveProcess.
2. Wait for debugging events. After your program acquired a debuggee, the debuggee's primary
thread is suspended and will continue to be suspended until your program calls
WaitForDebugEvent. This function works like other WaitForXXX functions, ie. it blocks the
calling thread until the waited-for event occurs. In this case, it waits for debug events to be sent
by Windows. Let's see its definition:

WaitForDebugEvent proto lpDebugEvent:DWORD, dwMilliseconds:DWORD

lpDebugEvent is the address of a DEBUG_EVENT structure that will be filled with


information about the debug event that occurs within the debuggee.

dwMilliseconds is the length of time in milliseconds this function will wait for the debug event
to occur. If this period elapses and no debug event occurs, WaitForDebugEvent returns to the
caller. On the other hand, if you specify INFINITE constant in this argument, the function will
not return until a debug event occurs.

Now let's examine the DEBUG_EVENT structure in more detail.

DEBUG_EVENT STRUCT
dwDebugEventCode dd ?
dwProcessId dd ?
dwThreadId dd ?
u DEBUGSTRUCT <>
DEBUG_EVENT ENDS

dwDebugEventCode contains the value that specifies what type of debug event occurs. In short,
there can be many types of events, your program needs to check the value in this field so it
knows what type of event occurs and responds appropriately. The possible values are:

Value Meanings
A process is created. This event will be sent when
the debuggee process is just created (and not yet
CREATE_PROCESS_DEBUG_EVENT running) or when your program just attaches itself
to a running process with DebugActiveProcess.
This is the first event your program will receive.
EXIT_PROCESS_DEBUG_EVENT A process exits.
A new thread is created in the debuggee process or
when your program first attaches itself to a running
CREATE_THEAD_DEBUG_EVENT process. Note that you'll not receive this
notification when the primary thread of the
debuggee is created.
A thread in the debuggee process exits. Your
program will not receive this event for the primary
thread. In short, you can think of the primary thread
of the debuggee as the equivalent of the debuggee
EXIT_THREAD_DEBUG_EVENT process itself. Thus, when your program sees
CREATE_PROCESS_DEBUG_EVENT, it's
actually the
CREATE_THREAD_DEBUG_EVENT for the
primary thread.
The debuggee loads a DLL. You'll receive this
event when the PE loader first resolves the links to
LOAD_DLL_DEBUG_EVENT DLLs (you call CreateProcess to load the
debuggee) and when the debuggee calls
LoadLibrary.
UNLOAD_DLL_DEBUG_EVENT A DLL is unloaded from the debuggee process.
An exception occurs in the debuggee process.
Important: This event will occur once just before
the debuggee starts executing its first instruction.
The exception is actually a debug break (int 3h).
When you want to resume the debuggee, call
EXCEPTION_DEBUG_EVENT
ContinueDebugEvent with DBG_CONTINUE
flag. Don't use
DBG_EXCEPTION_NOT_HANDLED flag else
the debuggee will refuse to run under NT (on
Win98, it works fine).
This event is generated when the debuggee calls
OUTPUT_DEBUG_STRING_EVENT DebugOutputString function to send a message
string to your program.
RIP_EVENT System debugging error occurs

dwProcessId and dwThreadId are the process and thread Ids of the process that the debug event
occurs. You can use these values as identifiers of the process/thread you're interested in.
Remember that if you use CreateProcess to load the debuggee, you also get the process and
thread IDs of the debuggee in the PROCESS_INFO structure. You can use these values to
differentiate between the debug events occurring in the debuggee and its child processes (in case
you didn't specify DEBUG_ONLY_THIS_PROCESS flag).

u is a union that contains more information about the debug event. It can be one of the following
structures depending on the value of dwDebugEventCode above.

value in dwDebugEventCode Interpretation of u


A CREATE_PROCESS_DEBUG_INFO
CREATE_PROCESS_DEBUG_EVENT
structure named CreateProcessInfo
An EXIT_PROCESS_DEBUG_INFO structure
EXIT_PROCESS_DEBUG_EVENT
named ExitProcess
A CREATE_THREAD_DEBUG_INFO structure
CREATE_THREAD_DEBUG_EVENT
named CreateThread
An EXIT_THREAD_DEBUG_EVENT structure
EXIT_THREAD_DEBUG_EVENT
named ExitThread
A LOAD_DLL_DEBUG_INFO structure named
LOAD_DLL_DEBUG_EVENT
LoadDll
An UNLOAD_DLL_DEBUG_INFO structure
UNLOAD_DLL_DEBUG_EVENT named UnloadDll
An EXCEPTION_DEBUG_INFO structure
EXCEPTION_DEBUG_EVENT
named Exception
An OUTPUT_DEBUG_STRING_INFO structure
OUTPUT_DEBUG_STRING_EVENT
named DebugString
RIP_EVENT A RIP_INFO structure named RipInfo

I won't go into detail about all those structures in this tutorial, only the
CREATE_PROCESS_DEBUG_INFO structure will be covered here.
Assuming that our program calls WaitForDebugEvent and it returns. The first thing we should
do is to examine the value in dwDebugEventCode to see which type of debug event occured in
the debuggee process. For example, if the value in dwDebugEventCode is
CREATE_PROCESS_DEBUG_EVENT, you can interpret the member in u as
CreateProcessInfo and access it with u.CreateProcessInfo.

3. Do whatever your program want to do in response to the debug event. When


WaitForDebugEvent returns, it means a debug event just occurred in the debuggee process or a
timeout occurs. Your program needs to examine the value in dwDebugEventCode in order to
react to the event appropriately. In this regard, it's like processing Windows messages: you
choose to handle some and ignore some.
4. Let the debuggee continues execution. When a debug event occurs, Windows suspends the
debuggee. When you're finished with the event handling, you need to kick the debuggee into
moving again. You do this by calling ContinueDebugEvent function.

ContinueDebugEvent proto dwProcessId:DWORD, dwThreadId:DWORD,


dwContinueStatus:DWORD

This function resumes the thread that was previously suspended because a debug event occurred.
dwProcessId and dwThreadId are the process and thread IDs of the thread that will be
resumed. You usually take these two values from the dwProcessId and dwThreadId members of
the DEBUG_EVENT structure.
dwContinueStatus specifies how to continue the thread that reported the debug event. There are
two possible values: DBG_CONTINUE and DBG_EXCEPTION_NOT_HANDLED. For all
other debug events, those two values do the same thing: resume the thread. The exception is the
EXCEPTION_DEBUG_EVENT. If the thread reports an exception debug event, it means an
exception occurred in the debuggee thread. If you specify DBG_CONTINUE, the thread will
ignore its own exception handling and continue with the execution. In this scenario, your
program must examine and resolve the exception itself before resuming the thread with
DBG_CONTINUE else the exception will occur again and again and again.... If you specify
DBG_EXCEPTION_NOT_HANDLED, your program is telling Windows that it didn't handle
the exception: Windows should use the default exception handler of the debuggee to handle the
exception.
In conclusion, if the debug event refers to an exception in the debuggee process, you should call
ContinueDebugEvent with DBG_CONTINUE flag if your program already removed the cause
of exception. Otherwise, your program must call ContinueDebugEvent with
DBG_EXCEPTION_NOT_HANDLED flag. Except in one case which you must always use
DBG_CONTINUE flag: the first EXCEPTION_DEBUG_EVENT which has the value
EXCEPTION_BREAKPOINT in the ExceptionCode member. When the debuggee is going to
execute its very first instruction, your program will receive the exception debug event. It's
actually a debug break (int 3h). If you respond by calling ContinueDebugEvent with
DBG_EXCEPTION_NOT_HANDLED flag, Windows NT will refuse to run the debuggee
(because no one cares for it). You must always use DBG_CONTINUE flag in this case to tell
Windows that you want the thread to go on.

5. Continue this cycle in an infinite loop until the debuggee process exits. Your program must
be in an infinite loop much like a message loop until the debuggee exits. The loop looks like this:

.while TRUE
invoke WaitForDebugEvent, addr DebugEvent, INFINITE
.break .if DebugEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
<Handle the debug events>
invoke ContinueDebugEvent, DebugEvent.dwProcessId, DebugEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED
.endw

Here's the catch: Once you start debugging a program, you just can't detach from the debuggee
until it exits.

Let's summarize the steps again:

1. Create a process or attach your program to a running process.


2. Wait for debugging events
3. Do whatever your program want to do in response to the debug event.
4. Let the debuggee continues execution.
5. Continue this cycle in an infinite loop until the debuggee process exits

Example:
This example debugs a win32 program and shows important information such as the process handle,
process Id, image base and so on.

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\user32.lib
.data
AppName db "Win32 Debug Example no.1",0
ofn OPENFILENAME <>
FilterString db "Executable Files",0,"*.exe",0
db "All Files",0,"*.*",0,0
ExitProc db "The debuggee exits",0
NewThread db "A new thread is created",0
EndThread db "A thread is destroyed",0
ProcessInfo db "File Handle: %lx ",0dh,0Ah
db "Process Handle: %lx",0Dh,0Ah
db "Thread Handle: %lx",0Dh,0Ah
db "Image Base: %lx",0Dh,0Ah
db "Start Address: %lx",0
.data?
buffer db 512 dup(?)
startinfo STARTUPINFO <>
pi PROCESS_INFORMATION <>
DBEvent DEBUG_EVENT <>
.code
start:
mov ofn.lStructSize,sizeof ofn
mov ofn.lpstrFilter, offset FilterString
mov ofn.lpstrFile, offset buffer
mov ofn.nMaxFile,512
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or
OFN_EXPLORER or OFN_HIDEREADONLY
invoke GetOpenFileName, ADDR ofn
.if eax==TRUE
invoke GetStartupInfo,addr startinfo
invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+
DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi
.while TRUE
invoke WaitForDebugEvent, addr DBEvent, INFINITE
.if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
invoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION
.break
.elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFile,
DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread,
DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartAddress
invoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_CONTINUE
.continue
.endif
.elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION
.endif
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED
.endw
invoke CloseHandle,pi.hProcess
invoke CloseHandle,pi.hThread
.endif
invoke ExitProcess, 0
end start

Analysis:
The program fills the OPENFILENAME structure and then calls GetOpenFileName to let the user
choose a program to be debugged.

invoke GetStartupInfo,addr startinfo


invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+
DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi

When the user chose one, it calls CreateProcess to load the program. It calls GetStartupInfo to fill
the STARTUPINFO structure with its default values. Note that we use DEBUG_PROCESS
combined with DEBUG_ONLY_THIS_PROCESS flags in order to debug only this program, not
including its child processes.

.while TRUE
invoke WaitForDebugEvent, addr DBEvent, INFINITE

When the debuggee is loaded, we enter the infinite debug loop, calling WaitForDebugEvent.
WaitForDebugEvent will not return until a debug event occurs in the debuggee because we specify
INFINITE as its second parameter. When a debug event occurred, WaitForDebugEvent returns and
DBEvent is filled with information about the debug event.

.if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
invoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK+MB_ICONINFORMATION
.break
We first check the value in dwDebugEventCode. If it's EXIT_PROCESS_DEBUG_EVENT, we
display a message box saying "The debuggee exits" and then get out of the debug loop.

.elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFile,
DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread,
DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartAddress
invoke MessageBox,0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION

If the value in dwDebugEventCode is CREATE_PROCESS_DEBUG_EVENT, then we display


several interesting information about the debuggee in a message box. We obtain those information
from u.CreateProcessInfo. CreateProcessInfo is a structure of type
CREATE_PROCESS_DEBUG_INFO. You can get more info about this structure from Win32 API
reference.

.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_CONTINUE
.continue
.endif

If the value in dwDebugEventCode is EXCEPTION_DEBUG_EVENT, we must check further for


the exact type of exception. It's a long line of nested structure reference but you can obtain the kind of
exception from ExceptionCode member. If the value in ExceptionCode is
EXCEPTION_BREAKPOINT and it occurs for the first time (or if we are sure that the debuggee
has no embedded int 3h), we can safely assume that this exception occured when the debuggee was
going to execute its very first instruction. When we are done with the processing, we must call
ContinueDebugEvent with DBG_CONTINUE flag to let the debuggee run. Then we go back to
wait for the next debug event.

.elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr NewThread, addr AppName, MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT
invoke MessageBox,0, addr EndThread, addr AppName, MB_OK+MB_ICONINFORMATION
.endif

If the value in dwDebugEventCode is CREATE_THREAD_DEBUG_EVENT or


EXIT_THREAD_DEBUG_EVENT, we display a message box saying so.

invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,


DBG_EXCEPTION_NOT_HANDLED
.endw

Except for the EXCEPTION_DEBUG_EVENT case above, we call ContinueDebugEvent with


DBG_EXCEPTION_NOT_HANDLED flag to resume the debuggee.

invoke CloseHandle,pi.hProcess
invoke CloseHandle,pi.hThread

When the debuggee exits, we are out of the debug loop and must close both process and thread
handles of the debuggee. Closing the handles doesn't mean we are killing the process/thread. It just
means we don't want to use those handles to refer to the process/thread anymore.

 
Tutorial 29: Win32 Debug API Part 2

We continue with the subject of win32 debug API. In this tutorial, we will learn how to modify the
debuggee process.

Theory:
In the previous tutorial, we know how to load the debuggee and handle debug events that occur in its
process. In order to be useful, our program must be able to modify the debuggee process. There are
several APIs just for this purpose.

ReadProcessMemory This function allows you to read memory in the specified process. The
function prototype is as follows:

ReadProcessMemory proto hProcess:DWORD, lpBaseAddress:DWORD,


lpBuffer:DWORD, nSize:DWORD, lpNumberOfBytesRead:DWORD

hProcess is the handle to the process you want to read.


lpBaseAddress is the address in the target process you want to start reading. For example, if you
want to read 4 bytes from the debuggee process starting at 401000h, the value in this parameter
must be 401000h.
lpBuffer is the address of the buffer to receive the bytes read from the process.
nSize is the number of bytes you want to read
lpNumberOfBytesRead is the address of the variable of dword size that receives the number of
bytes actually read. If you don't care about it, you can use NULL.

WriteProcessMemory is the counterpart of ReadProcessMemory. It enables you to write


memory of the target process. Its parameters are exactly the same as those of
ReadProcessMemory

The next two API functions need a little background on context. Under a multitasking OS like
Windows, there can be several programs running at the same time. Windows gives each thread a
timeslice. When that timeslice expires, Windows freezes the present thread and switches to the
next thread that has the highest priority. Just before switching to the other thread, Windows saves
values in registers of the present thread so that when the time comes to resume the thread,
Windows can restore the last *environment* of that thread. The saved values of the registers are
collectively called a context.
Back to our subject. When a debug event occurs, Windows suspends the debuggee. The
debuggee's context is saved. Since the debuggee is suspended, we can be sure that the values in
the context will remain unchanged . We can get the values in the context with
GetThreadContext and we can change them with SetThreadContext.
These two APIs are very powerful. With them, you have at your fingertips the VxD-like power
over the debuggee: you can alter the saved register values and just before the debuggee resumes
execution, the values in the context will be written back into the registers. Any change you made
to the context is reflected back to the debuggee. Think about it: you can even alter the value of
the eip register and divert the flow of execution to anywhere you like! You won't be able to do
that under normal circumstance.

GetThreadContext proto hThread:DWORD, lpContext:DWORD

hThread is the handle to the thread that you want to obtain the context from
lpContext is the address of the CONTEXT structure that will be filled when the function
returns successfully.

SetThreadContext has exactly the same parameters. Let's see what a CONTEXT structure
looks like:

CONTEXT STRUCT
ContextFlags dd ?
;----------------------------------------------------------------------------------------------------------
; This section is returned if ContextFlags contains the value
CONTEXT_DEBUG_REGISTERS
;-----------------------------------------------------------------------------------------------------------
iDr0 dd ?
iDr1 dd ?
iDr2 dd ?
iDr3 dd ?
iDr6 dd ?
iDr7 dd ?
;----------------------------------------------------------------------------------------------------------
; This section is returned if ContextFlags contains the value
CONTEXT_FLOATING_POINT
;-----------------------------------------------------------------------------------------------------------
FloatSave FLOATING_SAVE_AREA <>
;----------------------------------------------------------------------------------------------------------
; This section is returned if ContextFlags contains the value CONTEXT_SEGMENTS
;-----------------------------------------------------------------------------------------------------------
regGs dd ?
regFs dd ?
regEs dd ?
regDs dd ?
;----------------------------------------------------------------------------------------------------------
; This section is returned if ContextFlags contains the value CONTEXT_INTEGER
;-----------------------------------------------------------------------------------------------------------
regEdi dd ?
regEsi dd ?
regEbx dd ?
regEdx dd ?
regEcx dd ?
regEax dd ?
;----------------------------------------------------------------------------------------------------------
; This section is returned if ContextFlags contains the value CONTEXT_CONTROL
;-----------------------------------------------------------------------------------------------------------
regEbp dd ?
regEip dd ?
regCs dd ?
regFlag dd ?
regEsp dd ?
regSs dd ?
;----------------------------------------------------------------------------------------------------------
; This section is returned if ContextFlags contains the value
CONTEXT_EXTENDED_REGISTERS
;-----------------------------------------------------------------------------------------------------------
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?) CONTEXT ENDS

As you can observe, the members of this structures are mimics of the real processor's registers.
Before you can use this structure, you need to specify which groups of registers you want to
read/write in ContextFlags member. For example, if you want to read/write all registers, you
must specify CONTEXT_FULL in ContextFlags. If you want only to read/write regEbp,
regEip, regCs, regFlag, regEsp or regSs, you must specify CONTEXT_CONTROL in
ContextFlags.

One thing you must remember when using the CONTEXT structure: it must be aligned on dword
boundary else you'd get strange results under NT. You must put "align dword" just above the line
that declares it, like this:

align dword
MyContext CONTEXT <>

Example:
The first example demonstrates the use of DebugActiveProcess. First, you need to run a target named
win.exe which goes in an infinite loop just before the window is shown on the screen. Then you run
the example, it will attach itself to win.exe and modify the code of win.exe such that win.exe exits the
infinite loop and shows its own window.

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\user32.lib

.data
AppName db "Win32 Debug Example no.2",0
ClassName db "SimpleWinClass",0
SearchFail db "Cannot find the target process",0
TargetPatched db "Target patched!",0
buffer dw 9090h

.data?
DBEvent DEBUG_EVENT <>
ProcessId dd ?
ThreadId dd ?
align dword
context CONTEXT <>

.code
start:
invoke FindWindow, addr ClassName, NULL
.if eax!=NULL
invoke GetWindowThreadProcessId, eax, addr ProcessId
mov ThreadId, eax
invoke DebugActiveProcess, ProcessId
.while TRUE
invoke WaitForDebugEvent, addr DBEvent, INFINITE
.break .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context
invoke WriteProcessMemory, DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr
buffer, 2, NULL
invoke MessageBox, 0, addr TargetPatched, addr AppName,
MB_OK+MB_ICONINFORMATION
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId,DBEvent.dwThreadId,
DBG_CONTINUE
.continue
.endif
.endif
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED
.endw
.else
invoke MessageBox, 0, addr SearchFail, addr AppName,MB_OK+MB_ICONERROR .endif
invoke ExitProcess, 0
end start

;--------------------------------------------------------------------
; The partial source code of win.asm, our debuggee. It's actually
; the simple window example in tutorial 2 with an infinite loop inserted
; just before it enters the message loop.
;----------------------------------------------------------------------

......
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ hInst,NULL
mov hwnd,eax
jmp $ <---- Here's our infinite loop. It assembles to EB FE
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.break .if (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp

Analysis:
invoke FindWindow, addr ClassName, NULL

Our program needs to attach itself to the debuggee with DebugActiveProcess which requires the
process Id of the debuggee. We can obtain the process Id by calling GetWindowThreadProcessId
which in turn needs the window handle as its parameter. So we need to obtain the window handle
first.
With FindWindow, we can specify the name of the window class we need. It returns the handle to the
window created by that window class. If it returns NULL, no window of that class is present.
.if eax!=NULL
invoke GetWindowThreadProcessId, eax, addr ProcessId
mov ThreadId, eax
invoke DebugActiveProcess, ProcessId

After we obtain the process Id, we can call DebugActiveProcess. Then we enter the debug loop
waiting for the debug events.

.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context

When we get CREATE_PROCESS_DEBUG_INFO, it means the debuggee is suspended, ready for


us to do surgery upon its process. In this example, we will overwrite the infinite loop instruction in
the debuggee (0EBh 0FEh) with NOPs ( 90h 90h).
First, we need to obtain the address of the instruction. Since the debuggee is already in the loop by the
time our program attached to it, eip will always point to the instruction. All we need to do is obtain
the value of eip. We use GetThreadContext to achieve that goal. We set the ContextFlags member
to CONTEXT_CONTROL so as to tell GetThreadContext that we want it to fill the "control"
register members of the CONTEXT structure.

invoke WriteProcessMemory, DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr


buffer, 2, NULL

Now that we get the value of eip, we can call WriteProcessMemory to overwrite the "jmp $"
instruction with NOPs, thus effectively help the debuggee exit the infinite loop. After that we display
the message to the user and then call ContinueDebugEvent to resume the debuggee. Since the "jmp
$" instruction is overwritten by NOPs, the debuggee will be able to continue with showing its
window and enter the message loop. The evidence is we will see its window on screen.

The other example uses a slightly different approach to break the debuggee out of the infinite loop.

.......
.......
.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
mov context.ContextFlags, CONTEXT_CONTROL
invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context
add context.regEip,2
invoke SetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context
invoke MessageBox, 0, addr LoopSkipped, addr AppName, MB_OK+MB_ICONINFORMATION
.......
.......

It still calls GetThreadContext to obtain the current value of eip but instead of overwriting the "jmp
$" instruction, it increments the value of regEip by 2 to "skip over" the instruction. The result is that
when the debuggee regains control , it resumes execution at the next instruction after "jmp $".
Now you can see the power of Get/SetThreadContext. You can also modify the other register images
as well and their values will be reflected back to the debuggee. You can even insert int 3h instruction
to put breakpoints in the debuggee process.

 
$$$$$$$$$$$$$$$$$ : $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$ : /| ?_?_? $
$ ._ / |__ ____ ____ ____ ____ ____ ____ $
$ ____| \/ \ _/ \/ \_ /: \/ \_ / ? \ $
$ / |o \ _// _\ | _/_|\ \ |/ ? \_ $
$ \ : /_ ) ____ \/\ |/ / \ _|_ \ $
$ / . \ \/ \ \ | / ?_ \ | /\/? ? $
$ / \ / \ / | \ | / _? + $
$ _ _ \__ |_____/___/\ /:___ /____ /__|_ / | \ \ / $
$ | | rECLAIM |/ |/ |/ \_:_/ | \ \ / $
$ |_ | : : : \_ ? _\ \_/ $
$$$$$$$$ \ | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$: \___/\___/ $$$$$$$$$$$$$$
\|
:

TiTle: How To Create A Game Trainer Using Win32Asm

Chapters....

i) Introduction... Programs needed.


ii) Api calls we will be using.
iii) Trainer Process.
iv) Source Code Section.
v) Resource Editing.
vi) Where to get all the tools for this tutorial.
vii) Creating the final program (compiling your code).
viii) Final Words.

*********************************************************************************

CHAPTER i)
==========

Intro : Hey guys.. ive noticed the lack of tutorials on the subject of game tr
so i decided to contribute to it and write this little essay to inform
hopefully enlighten you all to the world of Assembly language Trainer
Assembly Language has got a bad rap for being complex, and actually fo
best part of it is.. but for simple programs such as the one we will b
there is no REAL complexity.... I`ll endevour to explain everything as
First of all you may be asking yourself why bother with Assembly langu
create my trainers when there are simple trainer maker kits out there.
the benefits from creating your own trainer (in any programming langua
limitless.. but the main advantages are size and flexibility... the co
be showing you today will compile into a 8k program.. if you zip it yo
take it down to 1k... MAN!! considering that most trainers are like 10
hope this gives you some insentive to carry on reading... :o)

Needed : Something to create the asm program in (Text Editor), all my code is T
specific.. so its a good idea to get that.. a resource editor to edit
file which contains the main dialogbox that will be created.. you will
edit this so that people know who made the trainer and that kind of th
and we will be dealing with API calls also so its a good idea to get t
referece... so...

1. Text Editor of your choice. ... i use (notepad)


2. TASM 5.0 to compile the program.
3. Win32 API Reference.
4. Resource Editor.. i use (Borlands v4.5)

With all this out of the way we can start.. :o)

To get the most out of this tutorial it would be best if you have a li
bit of Assembly knowledge... THIS IS NOT ESSENTIAL... because ive desi
the source code so that the real beginers can just change certain valu
then compile the source code into a program.....

*********************************************************************************

CHAPTER ii)
===========

START : Ok, Here goes....

The first thing i am going to do is list all the api calls we will be
you a run down of what they do.....I`ll explain them in the order the
use them..or there abouts :o)

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

HMODULE GetModuleHandle(

LPCTSTR lpModuleName // address of module name to return handle for


);

details: All programs created in windows needs to have something to id


it so that windows can interact with it.. this api gives your
an identity.. :o)

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

int DialogBoxParam(

HINSTANCE hInstance, // handle of application instance


LPCTSTR lpTemplateName, // identifies dialog box template
HWND hWndParent, // handle of owner window
DLGPROC lpDialogFunc, // address of dialog box procedure
LPARAM dwInitParam // initialization value
);

details: This api creates a dialogbox on the screen from a template .


file.. You can edit this .res file with a resource editor on
the best ive seen is Borland Rescource Editor v4.5
-----------------------------------------------------------------------
-----------------------------------------------------------------------

UINT SetTimer(

HWND hwnd, // handle of window for timer messages


UINT idTimer, // timer identifier
UINT uTimeout, // time-out value
TIMERPROC tmprc // address of timer procedure
);

details: This api sends a timer message to a specified location ie y


dialogbox procedure.. I used this to check for key presses.
is a very useful api that is used alot in trainers that use
game keys...

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

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

LRESULT SendMessage(

HWND hwnd, // handle of destination window


UINT uMsg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);

details: Well not really too important in this tutorial i only use i
my code to load the icon.....etc..
-----------------------------------------------------------------------
-----------------------------------------------------------------------

SHORT GetAsyncKeyState(

int vKey // virtual-key code


);

details: This api is used to check wheather the specified virtual ke


been pressed.. basically its used to see if we have pressed
key.. ie.. F12..

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

BOOL CreateProcess(

LPCTSTR lpApplicationName, // pointer to name of executable module


LPTSTR lpCommandLine, // pointer to command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // pointer to process s
LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to thread sec
BOOL bInheritHandles, // handle inheritance flag
DWORD dwCreationFlags, // creation flags
LPVOID lpEnvironment, // pointer to new environment block
LPCTSTR lpCurrentDirectory, // pointer to current directory name
LPSTARTUPINFO lpStartupInfo, // pointer to STARTUPINFO
LPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_
);

details: This api does a lot of work for out trainer.. this is the api tha
runs the game and returns to us all the information we nee
write our trainer values into the games memory. Createproc
is our friend.. :o)

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

BOOL WriteProcessMemory(

HANDLE hProcess, // handle of process whose memory is written to


LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // address of buffer to write data to
DWORD cbWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);

details: This is obviously the most important api call we will use
the trainer because it pokes our values into the games mem
This api is our best friend :o)

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

int MessageBox(

HWND hWnd, // handle of owner window


LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);

details: This api is used to create a small box on the screen usual
to inform the user of some error or other activity.. In my
trainer code its used to indicate an error and also the in
on how to use the trainer.

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

VOID ExitProcess(

UINT uExitCode // exit code for all threads


);

details: well this api is called when we have finished with our tr
it closes our process down and hands control back to good
windows :o)

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

Ok.. thats all the api calls out the way.. i use a couple more in the t
i think but dont worry these are not really needed to code a trainer..
line of my code is commented to the max... so you wont get lost... :o)
*********************************************************************************

CHAPTER iii)
============

Trainer process.....

Step 1. Show our trainer (Call DialogBoxParamA) on the screen.

Step 2. Wait for somthing to happen.. ie about box button pressed... ru

Step 3. If about button is pressed then show (call messageboxa) info.

Step 4. If run game button is pressed then run the game (call createpro

Step 5. Keep sending timer messages to the trainer (call SetTimer)

Step 6. Check to see if a virtual key has been pressed (Call GetAsyncKe

Step 7. If a key has been pressed then jump to the code that writes mem

Step 8. Write memory values to our game (Call WriteProcessMemory) then

Step 9. When trainer is close down exit and return control to windows (

The above steps should make it easier to understand the already comment

*********************************************************************************

CHAPTER iv)
===========

Before we go head first into the source code, ive marked on the code places
that you need to edit to make it work with your trainer addresses... these
places are marked with a CHANGE!!! and even if you dont understand any asm
you will be able to edit these values and also the .res file (covered in the next
and then compile it.. to create your own trainers :o)

.386 ;
.Model Flat, StdCall ;
Locals ;Dont worry about this bit
jumps ;
;
UNICODE=0 ;

;************* Declare procedures ***************

extern WriteProcessMemory:PROC ; Declare api calls that we


extern GetAsyncKeyState:PROC ; going to be using.. (TASM

;************************************************
;************* Include Files ********************
; Files to include
include w32.inc ; This file contains lots
; equates for us to use wi
;************************************************

;************ Declare some constants ************

; Equate some constants to


DLG1 equ 104 ; readable form...
RUN_GAME equ 102 ; Each item in a dialogbox
ABOUT_BOX equ 103 ; an ID number this will m
ICON1 equ 106 ; you can use the names in
SM_ICON equ 0 ; instead of just numbers.
;

;************************************************

;************ Prototype procedures **************

dlg1Proc PROTO :DWORD,:DWORD,:DWORD,:DWORD ; prototype dialogbox mess


; routine.
;************************************************

;*********** Data Section ***********************

.Data

aboutcaption db "About Box",0 ;CHANGE!!! This is the abou

aboutmessage db "???? Trainer",0ah ;CHANGE!!! This to your own


db " ",0ah ;for an extra line use ,0ah
db "Coded by ?????",0 ;on the last line put a ,0

errorcaption db "Error",0 ;CHANGE!!! Error box captio

errormessage db "Sorry!! There was an Error!!",0ah ;CHANGE!!!


db "Make sure the trainer is in the game directory!",0 ;CHANGE!!!

filename db "medieval.exe",0 ;CHANGE!!! .EXE Name

byte_to_write db 090h ;CHANGE!!! bytes you


db 090h ; ;game...ie.. use 90/n
db 090h ; any extra bytes go underneath ;to stop money/bullet
db 090h ; ;if you want to add e
;change the value of
;the writeprocessmemo
@startupinfo dd 0 ; size of startup info-structure
db 68 dup (0) ;

.data?

_hInst dd ? ; Stores The hInstance Here


_hanicon dd ? ; stored the handle of the icon

hProcess dd ? ; Process Info Structure


hThread dd ? ;
dwProcessID dd ? ;
dwThreadID dd ? ;

;***********************************************

;********** Code Section ***********************

.CODE

main:
call GetModuleHandle,0 ; Get handle for our program
mov _hInst,eax ; Store the handle of our program
Push 0 ; Initialization value
Push offset Dlg1Proc ; Address of dialogbox procedure
Push 0 ; Handle of owner window (0 = no owner)
Push DLG1 ; Dialogbox template to load (from .res)
Push _hInst ; Push the hInstance (handle of our program)
Call DialogBoxParamA ; Create the dialogbox and enter message handle

Call ExitProcess,0 ;Exit Program

;************************* This Next Procedure Is For Message handling Of The Dia

dlg1Proc proc uses ebx edi esi, _hwind:DWORD, wmsg:DWORD, wparama:DWORD, lparama:

push 0 ; Address of timer procedure


; (ive had the messages goto the dialogbox inst
push 90 ; CHANGE!!!! this can have an effect on how fas
; i advice you not to touch this unless you kno
push 0 ; Timer identifier
push _hwind ; Place to send the timer message (our dlgproc
call SetTimer ; Do timer

cmp [wmsg], WM_INITDIALOG ; A wm_initdialog message is sent when the dial


jz _initdlg ; Jump to the initialisation routine
cmp [wmsg], WM_COMMAND ; Did something interesting happen?
jz events ; If yes jump to events
cmp [wmsg], WM_CLOSE ; Did the user close the dialogbox?
jz kill_it ; If yes jump to kill_it
cmp [wmsg], WM_DESTROY ; Did the user close the dialogbox?
jz kill_it ; If yes jump to kill_it
cmp [wmsg], WM_TIMER ; Was there a timer message?
jz @timer ; If yes goto @timer

xor eax,eax ; eax = 0

end_it:

ret ; Return and start over again

kill_it:

Call Exitprocess,0 ; Kill the dialogbox

_initdlg:

push ICON1 ; points to the icon in the .res file


push _hinst ; push the hInstance of our program
call LoadIcon ; Load the icon
mov _hanicon, eax ; Store the Icon handle into _hanicon
push eax ; Push handle of icon for the call to
; load the icon into the titlebar
push SM_ICON ; This specifies the small icon....
push WM_SETICON ; Specify which message to send....
push _hwind ; Handle of our program...
call SendMessage ; Send our message..
jmp end_it ; All work done return

;************************ EVENTS CHECKING ********************

events:
cmp [wparama],ABOUT_BOX ; Was the about button pressed?
jnz @next1 ; If no carry on checking for other events
call @about_box ; if yes call the about_box procedure
@next1:
cmp [wparama],RUN_GAME ; Was the Run Game buttin pressed?
jnz @next2 ; If no carry on checking for other events
call @startgame ; if yes call the start game procedure
@next2:

xor eax,eax ; eax = 0


jmp end_it ; return and start again

;************************ TIMER EVENTS CHECKING ***************


@timer:

push VK_f1 ; CHANGE!! F1-F12 this will change the key you
call GetAsyncKeyState ; Find out....
cmp eax,0 ; If no,
jz @n1 ; Carry on and check the other keys....
call @f1 ; else, call the F1 cheat routine

@n1:
push VK_f2 ; CHANGE!! F1-F12 this will change the key you
call GetAsyncKeyState ; Find out....
cmp eax,0 ; If no,
jz @n2 ; Carry on and check the other keys....
call @f2 ; else, call the F2 cheat routine

@n2:
push VK_f3 ; CHANGE!! F1-F12 this will change the key you
call GetAsyncKeyState ; Find out....
cmp eax,0 ; If no,
jz @n3 ; Return cus there are no more keys to check...
call @f3 ; else, call the F3 cheat routine
@n3:
push VK_f4 ; CHANGE!! F1-F12 this will change the key you
call GetAsyncKeyState ; Find out....
cmp eax,0 ; If no,
jz @n4 ; Return cus there are no more keys to check...
call @f4 ; else, call the F4 cheat routine
@n4:
ret

; NOTE!!! ive only done enough code for 4 hotke


; all you have to do is cut and paste... :o)

;********************* F-KEY CHEAT PROCEDURES ********************************

@f1 proc

push 0 ; Number of bytes actually written... (buffer p


push 1 ; CHANGE!!! If you have got extra bytes to be w
; like 9090 then you need to change this to 2 a
push offset byte_to_write ; Actual bytes to be written
push 0040ae7bh ; CHANGE!!! This to your address that you want
; bytes written to..
push hprocess ; Handle of the process to write to (our game)
call WriteProcessMemory ; Write the bytes to our game process
ret ; Work done.. return.

;COPY ALL OF THIS CODE INTO THE SECTIONS


;SO THAT THE OTHER FKEYS WORK!!!

@f1 endp

@f2 proc

;IF YOU WANT THE OTHER FKEYS ENABLED THEN COPY


;ABOVE CODE INTO EACH OF THESE SECTIONS!!!!!!

ret ; All work done return from procedure

@f2 endp

@f3 proc

;IF YOU WANT THE OTHER FKEYS ENABLED THEN COPY


;ABOVE CODE INTO EACH OF THESE SECTIONS!!!!!!

ret ; All work done return from procedure

@f3 endp

@f4 proc

;IF YOU WANT THE OTHER FKEYS ENABLED THEN COPY


;ABOVE CODE INTO EACH OF THESE SECTIONS!!!!!!

ret ; All work done return from procedure

@f4 endp

@startgame proc

push offset hprocess ; Points to buffer that stores the hprocess in


push offset @startupinfo ; Points to buffer that stores the startup inf
push 0 ; NULL
push 0 ; NULL
push NORMAL_PRIORITY_CLASS ; Access we will have over the process.
push 0 ; NULL
push 0 ; NULL
push 0 ; NULL
push 0 ; NULL
push offset filename ; Poniter to EXE name that will be opened.
call createprocess ; Open the process....
cmp eax,0 ; did it work?
jnz @okie ; if it worked jump to @okie
call @error ; if not then call the error message.

@okie:

ret ; all work done.. return.

@startgame endp
dlg1Proc endp

@about_box proc

push 64 ; Style of messagebox


push offset aboutcaption ; Push offset of caption for the about box
push offset aboutmessage ; Push offset of message for the about box
push _hwind ; handle of owner window (our dialogbox)
call messageboxa ; display the messagebox
ret ; work done.. return..

@about_box endp

@error proc

push 0 ; Style of messagebox


push offset errorcaption ; Push offset of caption for error messagebox
push offset errormessage ; Push offset of message for error messagebox
push _hwind ; handle of owner window (our dialogbox)
call messageboxa ; display the messagebox
ret ; work done.. return..

@error endp

End main

;*************** FEW!!!! We made it!! i hope you understood it.. :o) ************

*********************************************************************************

CHAPTER v)
===========

In this chapter i will just go quickly through how to edit a .res file..

Step 1. Load the resource editor (borland resource editor v4.5)


Step 2. Goto the File menu and choose "OPEN PROJECT"
Step 3. Choose the trainer.res file you got inside this tutorial zipf
Step 4. You should see something like this :

DIALOG
104
ICON
105

Step 5. Click on the 104 and you will see a dialogbox appear in the r
hand window.
Step 6. Double click 104 and you go into EDIT mode.. you can now chan
all aspects of the dialogbox.. ie caption on the blue bar.. a
text and edit boxes/buttons can all be edited from here.
All you have to do to edit these RESOURCES are double click o
Step 7. When you have the dialogbox looking how you want.. then you n
goto the File menu again and click on "SAVE PROJECT" now when
compile the code it will have your new edited dialogbox. :o)

*********************************************************************************

CHAPTER vi)
===========

Ok I`m assuming if you have got this far then you really want to code an
so i will do you all a favour and give you the urls for all the things t
need to complete this little asm trianer project :o)

Also i hate reading a tutorial and not being able to find the stuff i ne

WARNING!!! i dont know how long these urls with be around for, i will tr
urls that are on stable sites.. but be warned.

1. Notepad.. I assume you all have a copy of this already. :o)

2. Tasm 5.0.. This zip file has got all the files you need to compile
the trainer.. all you have to do is change the source
code and the .res file.. I have included the TRAINER.ASM
and the TRAINER.RES inside this zipfile.
http://www.cronus.spaceports.com/~reclaim/tasmbuild.zip

3. Win32 API Reference.. win32asm.cjb.net

4. Borland Resource Editor v4.5.. protools.cjb.net

*********************************************************************************

CHAPTER vii)
============

Ok.. finally i will tell you how to obtain a fully working trainer onc
have edited the source code and .res file... its very simple really..

All you need to do is download the tasmbuild.zip unzip it into a direc


your choice then place the TRAINER.ASM and the TRAINER.RES inside the
directory... then all you have to do is double click the RUNME.EXE and
compile your TRAINER.ASM and TRAINER.RES into a nice little program ca
TRAINER.EXE... thats all there is to it... :o)

The TRAINER.ASM and TRAINER.RES have also been included in the tasmbui
so you will either have to edit these files or overwrite them with you
own TRAINER.ASM and TRAINER.RES

*********************************************************************************

CHAPTER viii)
=============

Ok.. final words from me.. You are all free to change my source code
way you want to... be my guest... i hope this short essay has taught y
something.. i also hope you will send me your comments good or bad.. :
email me at... reclaim@operamail.com....

Final Final Word.... :o)

The source code in this tutorial is nothing special in fact its not al
useful.. because it uses a simple writeprocessmemory api to write a co
of bytes into a games memory.. this will be of no use when you have lo
addresses and different values to patch.. which is sometimes the case.
i have done is designed an engine for my trainers. which is basically
set of asm instructions that do a certain task but over and over again
The engine i use is simple but well designed, instead of constantly wr
the writeprocessmemory api.. it just needs values passed to it and it
the work for you.. this makes my trainers very small... well until i s
picture on them anyways :o)

1 last thing.. the source in this essay is included in this essay zipf
dont need to cut and paste... :o)

If i have a good responce from this essay i will write another 1 cover
i designed my trainer engine and also how to defeat trainer spy with l
tricks....etc...

cya in the next essay :o)

.........................
RECLAIM!
-
-----=========-----
-------==========================================----------
----------=====_masta_'s tut on win32-ASM-coding part 2 revision 1=====----------
-------==========================================----------

( I called this revision 1 because it contains new sourcecode without errors


_masta_ found when going through it again - fungus )

--==INTRO==--

Hi,
since part0 and part1 have been relatively successful, I am happy to
present you part2 now.
Actually I wanted to do something on GUI, but I was very busy lately
so something without GUI-coding for now. I think it will be interesting
anyway I hope.
Starting from this tutorial I won't explain the easy things like
MessageBox anymore, because they have been fully explained in both of
the first parts. I don't think it will cause you any problem once you
did the ealier parts.

--==WHAT IS NEEDED?==--

1. Texteditor
2. TASM 5.0 with libs, etc.
3. A Windows API reference (WIN32.HLP)
4. Starcraft (ONLY for testing purposes!;])
5. some Braincells left ;)
6. some basic ASM-knowledge (earlier lessons)
7. Numega Softice 3.xx (not really a must)

--==WHAT IS IT ABOUT THIS TIME?==--

Is there any gamer who doesn't apreciate little aids sometimes ...

more lives
more money
more energy
more gas
more ...

What I am talking about is a trainer, very common in C64-/Amiga-/


PC-DOS-times, unfortunately getting less lately, although there are
some from time to time. But it is still not like in the
"good old times".
So my target is Starcraft (Yes I know there are trainers for it!).

My reasons were: - the game is very popular


- I played it when I got the idea to this tut :)
--==LET'S GO==--

Some thought before starting our session.

Definition of Trainer: - a little program, that changes parts of


memory used by a game to for example gain
more money, etc ...

Normally it isn't allowed in Windows to access memory addresses of


another program. Luckily our dearest friend Billy implemented a
couple of functions, which were meant to debug originally. We can
use these for our purposes.
These functions are OpenProcess, WriteProcessMemory and
ReadProcessMemory. With the help of these we can read (and write)
from (into) memory addresses of another program.
Basically our program acts like a debugger, accessing other programs
memory and changing it.

--==STRUCTURE==--

1. Intro (little introduction shown using a MessageBox)

2. Get Process_ID of the program to be "trained"


(find main window of Starcraft; get process
with the help of the window)

3. OpenProcess

4. Change values

5. Close Handle to process, end (Cleanup)

--==IMPORTANT API-FUNCTIONS==--

The handle of the main window we can get with FindWindowA, where we gotta
get the name of the windowclass ("SWarrClass") and the name of the window
("Starcraft"). We can do this with the help of Softice (TASK->HWND).

With the windowhandle we can get the corresponding process, or rather PID
by using GetWindowThreadProcessId.

Now we take a handle of the memory area of the process with the help of
the PID -> OpenProcess.

Everything is getting easier now. Like in "normal" fileoperations we can


write into the memory of a running program with the handle and the function
WriteProcessMemory.
Last but not least we call CloseHandle, to close our handle to the process,
which is not really important in Win95, but who trusts software coming from
Redmont ;-)?

And very last the known function ExitProcess.

--==THE MEMORY ADDRESSES==--

We can easily get the adds of for example the minerals by using a debugger
and searching for the hex-values of the decimal-values shown on the screen.
In my version it it like the following:

Minerals = 04EFE08h
Gas = 04EFE38h

--==THE SOURCE==--

This time not very long and as usual not very good structured, but should
be easy to understand anyway ...

;This is a slightly edited source to my tutorial (Part 2)


;I did a mistake while searching the informations for the memory locations
;not taking care, that starcraft uses different locations ...

;Only change is that the million-value is written 2 times


;and 8 bytes instead of 4

; Set some params for the assembler


.386P
Locals
jumps

.Model Flat ,StdCall


PROCESS_VM_WRITE equ 020h ; Flags for the write-access
PROCESS_VM_OPERATION equ 008h ; to the process

mb_ok equ 0
minerals_pos equ 04efe08h
gas_pos equ 04efe38h

; declaration of used API-functions

extrn MessageBoxA : PROC ; Show a Messagebox


extrn FindWindowA : PROC ; Find Window with the name
extrn GetWindowThreadProcessId :Proc; Find PID with the HWND
extrn OpenProcess : PROC ; Procedure to access the process
extrn WriteProcessMemory: PROC ; Write into memory of the running
; program
extrn CloseHandle : PROC ; Close the handle again
; Cleanup, after use ;)
extrn ExitProcess : PROC ; Procedure to exit the program

; here begins our Data


.Data

caption db "_masta_'s essay on Win32-ASM-Coding, part 2",0


;Captionstring, 0-terminated

text db "Hi, here we are at part 2",13,10


db "This tut will describe you how to make",13,10
db "Win32-ASM Trainer",0

; Introtext , 0-terminated

err_cap db "ERROR",0 ; Caption for Errormessages

notrun db "Sorry, Starcraft is not running",0 ; Error if SC isn't running

no_write db "Mmmhhhh, a problem, by writing",13,10


db "to Starcrafts memory",13,10,0

readycap db "Ready",0 ; Caption for "ready"

readytxt db "Ok, now you have 1000000 Minerals and Gas",0

; Text for "ready"

million dd 1000000 ; How much do you want??? ;]


dd 1000000

wnd_name db "Starcraft",0 ; Name of the Starcraft-window


cls_name db "SWarClass",0 ; Class of the Starcraft-window

pid_sc dd ? ; Here we save the PID ...

p_hand dd ? ; and here the handle to the


; process

; And here we start with our code


.Code
Main:
push mb_ok
push offset caption
push offset text
push 0
call MessageBoxA ;Startmessage

is_SC_RUN:

push offset wnd_name


push offset cls_name
call FindWindowA ; Find Window handle with Windowclass and
; -name

cmp eax,0 ; if 0, window is not existing


jz SC_isnt_run_end; --> Starcraft is not launched

push offset pid_sc ; Where to save the PID ?


push eax ; PUSH Windowhandle
call GetWindowThreadProcessId ; Determine PID with Windowhandle

open_the_process:
push pid_sc ; PUSH PID
push 0 ; only used when
; building new
; processes
push PROCESS_VM_WRITE OR PROCESS_VM_OPERATION ; activate write-access

call OpenProcess ; Get handle of Starcraft


mov p_hand,eax ; Save handle to p_hand

change_Minerals:

push 0 ; Can be zero mostly


push 8 ; Write 8 Bytes (2 Dwords)
push offset million ; How much ? (1 Million)
push minerals_pos ; 1st Memoryaddress
push p_hand ; Handle to the process
call WriteProcessMemory; write minerals
cmp eax,0
jz error_on_write ; If any error while writing (eax=0) -> end

change_gas: ; the same again for gas, but this time


; the memory address of the gas is PUSHed
push 0
push 8
push offset million
push gas_pos
push p_hand
call WriteProcessMemory
cmp eax,0
jz error_on_write

Trainer_ready:

push mb_ok
push offset readycap
push offset readytxt
push 0
call MessageBoxA ; Everything OK

close_the_PID_Handle:
push p_hand
Call CloseHandle ; CloseHandle
jmp end_ ; Go to End

error_on_write:

push mb_ok
push offset err_cap
push offset no_write
push 0
call MessageBoxA ; Mmmhhh, Error while writing
jmp close_the_PID_Handle ; Close handle before quit

SC_isnt_run_end:

push mb_ok
push offset err_cap
push offset notrun
push 0
call MessageBoxA ; nothing there to train =(

end_:

CALL ExitProcess ; Exit program


End Main ; End of Code Determination
of Jump-point (Main)

;--------------------------==END OF SOURCE==----------------------------

;--------------------------------START---------------------------make.bat
@echo off
echo assembling your trainer
tasm32 /mx /m3 /z /q w95asm_2
tlink32 -x /Tpe /aa /c w95asm_2,w95asm_2,, import32.lib
del *.obj
del *.map
;---------------------------------END----------------------------make.bat

--==FINAL WORDS==--

OK, as I told you before this was a little tutorial, but I think very
interesting anyway. I guess there is not much to optimize (sorry fungus),
maybe the routine for writing into memory (use of a procedure).
I hope my mailbox (masta_t@usa.net) is flodded soon (CRITICS ARE WELCOME)
and you are all here next time. I promise the next one will be about GUI,
because many people told me to do so.
BTW, I am trying to build an IRC channel (EFNET) on this (#win32asm) and
finally there is a project-page 'HTTP://win32asm.cjb.net'!
If anyone is interested, any contribution to this subject is very welcome,
we are waiting for it ...
I really hope there are enough people, who spend their time on this
subject and who are willing to give their knowledge to others, too.

--==GREETINX==--

VucoeT (Translator and Designer), scut (You are GREAT, why not code in Win32?),
|caligo| (bad news about you :(), fravia (best on the web), +Aescalapius
(i hope to break Brainbreaker), not4you (wir Ossis muessen zusammenhalten ;)),
fungus (something to optimze), CyberBobjr (for translating to frensh), DASavant,
mornings, i_magnus, Quest, Silvio, TheDoctor, everyone on #LAC and
#cracking4newbies and to every cracker around the world.

--==WISE WORDS==--

------===========================================================-------
-----=====A hardcoded serial is as common as a 25-year-old virgin=====------
------===========================================================-------
-----=========-----
-
Defeating Trainer Spy with Trainer Maker Kit

IntroWhen I released my first Warcraft II BNE trainer it was the very first to have upgrade
cheats for Archers/Axes and Catapults/Ballistas. Within a week at least five other trainers
were released that had the same cheats as mine. I was pissed. I've been blocking Trainer
Spy from all of my recent trainers ever since. And I'm sure some of you already noticed.
Since then none of my codes have been ripped off. I've written this tutorial so that you too
can protect your hard work from lamers.

Blocking Trainer Spy


Blocking Trainer Spy with TMK is actually pretty easy. All you have to do is add this poke
script to your buttons.

Poke 0 FF 52 19 FF XX

You must replace XX with the number (in hex) of pokes that you want to hide. It sounds a
little complicated at first but let me give you some examples. I'll use the codes from the
starcraft mineral cheat in my first tutorial.

Poke 0 FF 52 19 FF 01
Poke 508728 FF FF

This would successfully block that button from Trainer Spy. Notice that XX is now 01
because there is one poke below to hide. You could also do this.

Poke 0 FF 52 19 FF 02
Poke 508728 FF
Poke 508729 FF

This also works. Notice that XX is now 02 because there are two pokes below it to hide.

Ok now let's say you had ten pokes to block. Would you make XX 10? NO! You would
make XX to be 0A because 0A in hex = 10 in decimal.
Refer to the Hex to Ascii chart for more help with hex.

Conclusion
This is a 99%* working method of stoping Trainer Spy. This will even stop the lamers who
hex edit their copy of Trainer Spy to change the window name.

* Thanks to Faze for letting me know about this.

Note: Trainer Spy is not the only way to steal codes from a trainer. Just don't ask me how.

F.Y.I. - Trainer Maker Kit and Trainer Spy were made by the same guy.
Tutorial written by Drakken
::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: GAMEHACKING TUTORIAL PART 3 ::


:: BY BLIZZARD ::

::::::::::::::::::::::::::::::::::::::::::::::::::::::

I assume you have also read part 1 and 2 of my tutorial. In the first tutorial yo
what cheating in games actually is, and how fun it is. In the second tutorial I s
to find the STATIC ADDRESS instead of a DMA (DYNAMIC MEMORY ALLOCATION).

Do you still remember what we got in the second tutorial? Here it is:

::::::::::::::::::::::::::::::::::::::::::::::::::::::
Tmk button script
Copy and Past into tmk using ctrl+V
Ex: Patched script for a ON button
and Unpatched script for a OFF button

Patched script:
Poke 464FA2 90 90 90 90 90 90

UnPatched script:
Poke 464FA2 89 8F 74 A7 D5 00
::::::::::::::::::::::::::::::::::::::::::::::::::::::

It says it is a TMK BUTTON SCRIPT. What is TMK? TMK is TRAINER MAKING KIT. It is
to build your trainer to it's physical form. Download it from:
http://fly.to/mtc

Start up TRAINER MAKER KIT (TMK) and fill in at PROJECT NAME for example "strongh
press the CREATE button. Now you are in the TMK OBJECTS screen now. Here you can
your trainer. But first we have to configure our trainer. On the down-left you se
tabs: OBJECTS, BUILD SETTINGS and HELP. Press the BUILD SETTINGS TAB.

You will see a list of the running processes (games and programs). Select the Str
Crusader Process from the list (the game must be running). Also behind EXE NAME u
PROCESS list fill in "crusadertrainer". Do NOT add .exe because TMK will do that

Okey go back to the OBJECTS tab. Rightclick on the blue space under DIALOG (your
and select PROPERTIES. Remove "Dialog" and fill in "Stronghold: Crusader Trainer"
Enter. You see that your title has changed. Now go to INSERT --> BUTTON on top of
screen. A button has appeared. Move it to the middle left of your trainer. Then a
button and move that one to the middle right of your trainer. So your trainer wil
this:

|-----------------------------|
| |
| |
| .-------. .-------. |
| |button1| |button2| |
| ------- ------- |
| |
|-----------------------------|

Rightclick on BUTTON 1 and select PROPERTIES. Change its name to ON. Do the same
and change it to OFF.
|-----------------------------|
| |
| |
| .-------. .-------. |
| | ON | | OFF | |
| ------- ------- |
| |
|-----------------------------|

Now remember what we got from TSEARCH?

Patched script:
Poke 464FA2 90 90 90 90 90 90

UnPatched script:
Poke 464FA2 89 8F 74 A7 D5 00

Right-click on ON and select WRITE MEMORY ACTIONS. Fill in Poke 464FA2 90 90 90 9


press APPLY (don't forget to press APPLY!).

Do the same for OFF but fill in Poke 464FA2 89 8F 74 A7 D5 00 there.

Now go to BUILD --> RUN YOUR PROJECT.


You will have to wait a few seconds and then your trainer will appear. Pretty coo

CONGRATULATIONS !!!

Your trainer is also saved as "crusadertrainer.exe" in it's own map under TMK dir
For example: C:/gamehacking/TMK/crusadertrainer/crusadertrainer.exe

::::::::::::::::::::::::::::::::::::::::::::::::::::::

Greetings go out to all of Computer knightS (EFNET, #computerknights) especially


Greetings go out to all of Extalias members especially Snok
Greetings to [Sheep] for helping me out.
Greetings to #cracking4newbies.
Greetings to #gamehacking.
Greetings for all the others. You know who you are ;-)

::::::::::::::::::::::::::::::::::::::::::::::::::::::

BliZZard, blizzard_1337@hotmail.com
another tut....game hacking archive please bie?

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

Changing Hotkeys in a VB Trainer

- eVoByte

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

*-----------*

Tools Needed:

*-----------*

OllyDbg - www.evobyte.net

Hex Editor ( I'm using Hex Workshop ) - www.google.com

Trainer with hotkeys - www.gameditions.com

Brain - ...

*-----------*

This tutorial started off from some guy on btcsquad.com forums not wanting to accidently turn on options while typing in delta force. Well, there is a way to change the hotkeys but to fully

understand the method you may need a bit of ASM knowledge.

Lets look at how an API is called in asm :

CODE
------------
Push Param5
Push Param4
Push Param3
Push Param2
Push Param1
Call ApiName
------------

The parameters are pushed onto the stack in reverse order, then the API is called. Lets take GetAsyncKeyState being as we are using it, and see what we need to be looking for:

CODE

----
SHORT GetAsyncKeyState(
int vKey
);

Parameters

vKey
[in] Specifies one of 256 possible virtual-key codes. For more information, see Virtual-Key Codes.

Windows NT/2000/XP: You can use left- and right-distinguishing constants to specify certain keys. See the Remarks section for further information.
----

Ok, so it has 1 parameter, int vKey. This is what holds the key which is being checked. So lets adapt our Push/Call method for GetAsyncKeyState :

CODE
------------
Push vKey
Call GetAsyncKeyState
------------

Now, this would be all good if the key was assembled as VbKeyNUMPAD1 or VK_NUMPAD1, but it isnt, as this isnt valid asm code. It pushes the hex value for the key instead.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdkr/html/_wcesdk_Virtual_Key_Codes.asp
If you goto this link and scroll down to VK_NUMPAD1, then you will see it has a hex value of 61. This means the GetAsyncKeyState for Numpad 1 will look like :

CODE

Push 61
Call GetAsyncKeyState

Alright, I'm using Diablo*GE*'s LW Trainer which you can get at www.gameditions.com, by clicking trainers, then D.

Ok, now here's where it really all starts.

------

---

------

Ok, so, load up the trainer and press the hotkeys button. Wall Hack On = Numpad 4. Let's concentrate on changing this to key Z.

Load up OllyDbg and select the trainer to debug ( File > Open ). One thing about VB ( might be the same with C++ n asm, not checked yet ), is that the API calls are declared and then the

address is called later instead of the API name. You will see what I mean soon enough.

Right click anywhere on the main window, and goto Search For > All Referenced Text Strings. A window will pop up showing them all, so scroll down until you see:

CODE

ASCII "user32"
ASCII "GetAsycnKeyState"

on the right of the window on the Text String column. Take a note of the line number, like on this trainer of Diablo*GE*'s it is 00403B4C. Close down this Reference Window, maximize the main

window to give yourself more work room.

Now scroll down 'til you get to the line number you just noted down. Now, there will be a block of code below it ( hopefully ). Here is what mine looks like :

CODE

------------
DD Land_War.0040E580
MOV EAX, DWORD PTR DS:[40E588]
OR EAX,EAX
JE SHORT Land_War.00403B67
JMP EAX
PUSH Land_War.00403B4C
MOV EAX,<JMP &MSVBVM50.DllFunctionCall>
CALL EAX
JMP EAX
------------

Select this whole block by selecting the first line, holding shift and then pressing the down arrow on your keyboard. Right click on the selected group and goto :

Find References To > Selected Group

Now, another window will load up with loads of CALL's and some other stuff, but to us, only the CALL's are important. Remember above I said API's are CALLed and the parameters are PUSHed?

Well, double click on one of the CALL's and then scroll up 1 line, and there is the push =)

So, I want to change Wall Hack on mine, which was Numpad 4. If you look on the Virtual Key chart which I gave a link for earlier you will see that the Hex is 64. Double click on each Call, and

then scroll up one until you find "Push 64", and then note down the line number. For Diablo*GE*'s trainer, the address is 0040CB20. Now, finally, you can close OllyDbg but make sure you noted all

the address' for the hotkeys you wanted to change.

Now load up your Hex Editor. Search for the address, in my case 0040CB20.

Being as this number is a multiple of 10 ( has a 0 at the end ) it will most likely be at the beginning of a line. On other hotkeys it may be mid line though.

At 0040Cb20 there is 6A, then next to it is 64. The 6A is an opcode for PUSH, and then 64 is the value. Change the 64 to 5A ( the hex for key Z ) and then save the trainer. Go in game, press Z
and there you have it, wallhack.

Shoutouts : Diablo, Zehcnas, Just M3, i.Brid, jb, OxY, Demented, Bie, Predator, coral ( the guy who wanted hotkeys changing )

- No Order, just cool people -

www.evobyte.net

www.gameditions.com

www.toxic-cell.net

www.btcsquad.com

www.gamehacking.com
VB hotkeys ::

You have to make a timer for hotkeys , put this code as timer code, dont ever use

If GetKeyPress(vbKey"urkey") Then Call WriteAInt(address, value)

if ur code was more than one line you can add them in the next line for example :

If GetKeyPress(vbKey"urkey") Then Call WriteAbyte(Address, value)


Call WriteAByte(address, value)
Call WriteAbyte(address, value )
Call WriteAByte(address, value)

then you have to add this code to the top of your Code library so it becomes the

Private Declare Function GetKeyPress Lib "user32" Alias "GetAsyncKeyState" (ByVal

then you have to change the Timer Properties . change Enabled to true and interva

then you have to change timer code.

now we come back to timer code , we put GPS on as our example .and we want to pre

If GetKeyPress(vbKeyG) Then Call WriteAInt(&H42697C, &H9090)

notice : G in red means the hotkey to activate the code.

, YOU MIGHT DONT GET IT YET , SO WE WORK ON ANOTHER EXAMPLE.

1.We have Saw Scope Code for Df2 and we want to activate it by pressing E.

If GetKeyPress(vbKeyE) Then Call WriteAInt(&H44E6EC, &H9090)


Call WriteAByte(&H44C81B, &HEB)
Call WriteAInt(&H44EBC4, &HFF24)
Call WriteAByte(&H79A698, &H2)

that is it , when you press E the Saw scope activate.

Tutorial About Adding Visual Basic 6 HOTKEYS by x-UnDeaD

>>>> Contact Me <<<<


At-

undead@extalia.com
TUTORIAL WRITTEN BY x-UnDeaD

Add a command button first.


well This is Not TMK , and you cant Put Poke 234252 23 , you have to put the code
For Example GPS On code is

Poke 0042697C 90 90

in TMK well that is in TMK if you put your codes in that way in VB the VB gets er

( Call WriteAInt

at the begging of the code so it becomes like

thisCall WriteAInt 0042697c 90 90

This wont work too , so You have to put the address in Parenthesis

Call WriteAInt (0042697c 90 90)

now You have to Put (&H) at the begging of each Value so it becomes like this

Call WriteAInt(&H42697C, &H9090)

and delete the space between Those 9090 , you have to clean any spaces between He

Call WriteAInt(&H543634, &H909090)

that is what it looks Like when you Put the codes

!!! JUST KEEP IN MIND YOU CANT USE Call WriteAInt FOR ALL CODES !!!

If You Have two line of codes like this

87940 90 90 43253 90 FF

You cant put Call WriteAInt in the begging of each code line For the EVEN line yo

Call WriteAInt (&h87940, &h9090)


Call WriteAByte (&h43253, &h90FF)

Another Example , Saw Scope For Df2 in VB will be written in this way :

Call WriteAInt(&H44E6EC, &H9090)


Call WriteAByte(&H44C81B, &HEB)
Call WriteAInt(&H44EBC4, &HFF24)
Call WriteAByte(&H79A698, &H2)

you can look at each codes and find the tricks in it , ;).
You Can change Your Button look by select Your Button ( command ) and then go to
You Can Make your trainer Now , if You are done with ur codes and you need to get
there is View On Top Toolbar click that and then Choose Object .then you will get
Just Press File at the Top Tool bar and then CHoose "Make" whatever.exe . That is
Any Way Some of you may have known VB before , but you didnt know VB template , f

Tutorial Written By x-UnDeaD...FINNALY DONE :):):)

contact :undead@extalia.com
-----------------------------------------

- How to make a trainer in Visual Basic -

- Using vbTrainerTemplate.zip -

- Snake -

- snake_uc@yahoo.com -

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

PLEASE DO NOT REDISTRIBUTE OR HOST FILE UNLESS PERMISSION IS GIVEN FROM

AUTHOR.. TO CONTACT AUTHOR EMAIL: Snake_UC@yahoo.com ..

Get vbTrainerTemplate.zip at http://snakeuc.no-ip.com/vbfiles/vbTrainerTemplate.z

I found this file i guess its pretty helpful to people who would like to learn ho

Im guessing since you guys are trying to learn how to write a visual basic traine

If you notice in the .bas file there is a couple of great premade functions

Before I start out with explaining the functions I will give you some definitions

Definitions

Null: Amounting to nothing; absent or nonexistent: a null result.

Byte: sequence of adjacent bits, usually eight, operated on as a unit by a comput

When you see &H or 0x in front of a number such as &H505050 or 0x505050 it means

Now I will start expalining the most important functions located in the .bas file
Functions Documentation

GameCheck(ByVal GameTxt As String) As Boolean

What this does is checks if there is a program running with the window title Game

ReadBytes(GameTxt As String, Address As Long, vBuffer As Long, vLength As Long)

What this does is read bytes from memory.

GameTxt is the window title ( see GameCheck() ).

Address is the address to read bytes from

vBuffer is where to store the bytes read from memory

vLength is the length to read in byttes

For example if i wanted to read the address 4bytes from the game minesweeper at t

Dim vBuffer As Long

ReadBytes("Minesweeper", &H1005194, vBuffer, 4)

Then you could do stuff with vBuffer.

ReadFloat(GameTxt As String, Address As Long, vBuffer As Single, vLength As Long)

SEE ReadBytes()

-
-

WriteBytes(ByVal GameTxt As String, ByVal Address As Long, ByRef Buffer() As Byte

Now this is probably what your reading this for.. How to write bytes.. This is eq

GameTxt is the game's window title

Address is the address you want to write to

Buffer() is the bytes you want to write

For example if you wanted to nop 4 bytes at the address 0x1005194 in Minesweeper

Dim Buffer(3) As Byte

Buffer(0) = &H90

Buffer(1) = &H90

Buffer(2) = &H90

Buffer(3) = &H90

WriteBytes("Minesweeper", &H1005194, Buffer())

If you are confused with why it says (3) in Dim Buffer(3) As Byte when we are sup

These are the most important functions the other ones as self explanatory if you

Hopefully this helped,

-Snake

http://snakeuc.no-ip.com
Tutorial on Visual Basic by brzi
Released Under DEViOUS
brzi@devious.tsongkie.com
http://www.deviousonline.tk
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

Tools Needed :
»»»»»»»»»»»»»»
Visual Basic
Api Text Viewer (Comes with Visual Basic)
Api reference (A must have - www.win32asm.cjb.net)
A little brain to remember this

In this tutorial i will show you how to :


»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

1. Disable Ctrl+Alt+Del, Alt+Tab, Ctrl+Esc,Alt+F4


2. Open another program
3. Center a form
4. Make a form to be Always on top
5. ShutDown & Restart your PC
6. Open Web Browser
7. Hide/Show Taskbar
8. Display Windows Registered User
9. Arrange Icons on Desktop
10. Move Forms without using the title bar
11. Determine the location of the mouse pointer
12. Get Windows and System directory
13. Get Disk Info (Free Bytes,Total Bytes etc)
14. Send Mail

- Everything in reusable CODE !!! (You will learn how to use


reusable code and make your programs small !)

NOTE: I am not going to explain this cuz


this is easy and you can figure it out - Thats why i
have included " a little brain " in the Tools
For the API's use your API reference

Man this is going to be a Large tutorial !!

Let's Begin
»»»»»»»»»»»

First start Visual Basic.


By default Form1 is created.
Add a module to the project . (Select Project>Add Module)
Add another module.
Rename the form to frmMain.
Rename the first module to modAPI. (Here we will put our API's)
Rename the second module to modFunction. (Here we will put our functions)

»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code for Disable Ctrl+Alt+Delete,Alt+Tab etc etc

API(s) that we need for this:


SystemParametersInfoA

Open modApi module and enter this:

' Used for DisableCtrlAltDelete


Private Declare Function SystemParametersInfo Lib _
"user32" Alias "SystemParametersInfoA" (ByVal uAction _
As Long, ByVal uParam As Long, ByVal lpvParam As Any, _
ByVal fuWinIni As Long) As Long

Now open modFunction and write the folowing Sub

Sub DisableCtrlAltDelete(bDisabled As Boolean)


' Disables Ctrl+Alt+Del,Alt+Tab etc etc
Dim X As Long
X = SystemParametersInfo(97, bDisabled, CStr(1), 0)
End Sub

How to call this sub:

DisableCtrlAltDelete (True) - to disable Ctrl+Alt+Del


DisableCtrlAltDelete (False) - to enable Ctrl+Alt+Del
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code for opening another program

You dont need any API's for this.

Open modFunction and write the folowing Sub

Sub OpenApp(File As String)


'Shells to another application
X = Shell(File)
End Sub

How to call this sub:

OpenApp (File) - Where File is the file you want to open,


you can specify the full path of the file eg. OpenApp ("c:\Command.com") or
you can use the CommonDialog Control to point to the file
eg. OpenApp (frmMain.dlgOpen.FileName)
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code for centering a form

No API's

Open modFunction and write the folowing Sub

Sub Center(FormName as Form)


Move (Screen.Width - FormName.Width) \ 2, (Screen.Heght - FormName.Heght) \ 2
End Sub

How to call this sub:

Center(TheNameofYourForm) - where TheNameofYourForm is the name of the form


you want to center eg. Center(frmMain) or Center(frmAbout)
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to make a form to be always on top

API(s) that we need for this:

SetWindowPos

Open modAPI and add this:

' Used for AlwaysOnTop


Public SetTop As Boolean
Private Declare Function SetWindowPos Lib "user32" (ByVal h%, ByVal hb%, _
ByVal X%, ByVal Y%, ByVal cx%, ByVal cy%, ByVal f%) As Integer
Const FLAGS = 3
Const HWND_TOPMOST = -1
Const HWND_NOTOPMOST = -2

Now open modFunction and write this Sub

Sub AlwaysOnTop(FormName As Form, bOnTop As Boolean)


'Sets a form as always on top
Dim Success As Integer
If bOnTop = False Then
Success% = SetWindowPos(FormName.hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS)
Else
Success% = SetWindowPos(FormName.hWnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS)
End If
End Sub

How to call this sub:

AlwaysOnTop (TheNameofYourForm, True) - to make the form always to be on top


AlwaysOnTop (TheNameofYourForm, False) - to disable this the always on top
-TheNameofYourForm is the name of the form to be on top eg. AlwaysOnTop (frmMain,
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code for ShutDown or Restart your PC

API(s) that we need for this:

ExitWindowsEx

Open modAPI and add this:

' Used for ExitWindows


Private Declare Function ExitWindowsEx Lib "user32" _
(ByVal uFlags As Long, ByVal dwReserved _
As Long) As Long
Const EWX_LOGOFF = 0
Const EWX_SHUTDOWN = 1
Const EWX_REBOOT = 2
Const EWX_FORCE = 4

Now open modFunction and write this:

Sub ExitWindows(ExitMode As String)


Select Case ExitMode
Case Is = shutdown
t& = ExitWindowsEx(EWX_SHUTDOWN, 0)
Case Is = reboot
t& = ExitWindowsEx(EWX_REBOOT Or EXW_FORCE, 0)
Case Else
MsgBox ("Error in ExitWindows call")
End Select
End Sub

How to call this Sub

ExitWindows (shutdown) - to shutdown the PC


ExitWindows (reboot) - to restart the PC
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Open the Web Browser

API(s) that we need for this

ShellExecute

Open modAPI and add this:

Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd


ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As Strin
ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Const SW_SHOW = 5

Now open modFunction and write this:

Sub OpenWebSite(FormName as String, SiteName as String)


Dim ret&
ret& = ShellExecute (FormName.hWnd, "Open", SiteName, "", App.Path, 1)
End Sub

How to call this sub:

OpenWebSite (TheNameofYourForm.hWnd, "http://www.deviousonline.tk")


I think you know what TheNameofYourForm means so ...
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Hide/Show the Taskbar

Open modAPI and add this:

API(s) that we need for this:

FindWindow
SetWindowPos - we have included this before so we dont need to write it
again

Open modAPI and add this:

Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName A


ByVal lpWindowName As String) As Long

Now open modFunction and write the folowing Sub


'When you want to

Sub HideShowTaskbar (ShowTaskbar as Boolean)

If ShowTaskbar = True then


hWnd1 = FindWindow("Shell_traywnd", "")
SetWindowPos(hWnd1, 0, 0, 0, 0, 0, SWP_HIDEWINDOW)
Else
hWnd1 = FindWindow("Shell_traywnd", "")
SetWindowPos(hWnd1, 0, 0, 0, 0, 0, SWP_SHOWWINDOW)
End If
End Sub

How to call this sub:

HideShowTaskbar (True) - to hide the taskbar


HideShowTaskbar (False) - to show the taskbar
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Display the Windows Registered User and Organization

API(s) that we need for this:

LoadString
GetModuleHandle

Open modAPI and add this to it:

Declare Function LoadString Lib "user32" Alias "LoadStringA" (ByVal hInstance As


ByVal wID As Long, ByVal lpBuffer As String, ByVal nBufferMax As Long) As Long
Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" _
(ByVal lpModuleName As String) As Long

Now open modFunction and write this Sub

Sub DisplayWinUser()
Dim hInst As Integer, user As String, _
org As String, title As String, length As Integer
user = Space$(256)
org = Space$(256)
hInst = GetModuleHandle("user.exe")
length = LoadString(hInst, 514, user, Len(user))
user = Left$(user, length)
length = LoadString(hInst, 515, org, Len(org))
organization = Left$(org, length)
frmMain.lblWinUser.Caption = user
frmMain.lblWinOrg.Caption = organization
End Sub

How to call this sub:

You can put this in Form_Load () event

DisplayWinUser - you must two label called lblWinUser and lblWinOrg


»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Arrange Icons on Desktop


API(s) that we need for this:

FindWindow - we have included this earlier


GetWindow
SendMessage

Open modAPI and add this to it:

Declare Function GetWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, _
ByVal wCmd As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Lon
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Now open modFunction and write this:

Sub ArrangeIcons ()
Dim hWnd1 As Long
Dim hWnd2 As Long
Dim Ret As Long
hWnd1 = FindWindow("Progman", vbNullString)
hWnd2 = GetWindow(hWnd1, GW_CHILD)
hWnd1 = GetWindow(hWnd2, GW_CHILD)
Ret = SendMessage(hWnd1, LVM_ARRANGE, LVA_ALIGNLEFT, 0)
End Sub

Hot to call this Sub:

ArrangeIcons
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Move form without using Title Bar

API(s) that we need for this:

ReleaseCapture
SendMessage - this is included

Open modAPI and add this to it:

Declare Function ReleaseCapture Lib "user32" Alias "ReleaseCapture" () As Long

Now open modFunction and write this sub

Sub MoveWithMouse
If Button = 1 Then ' Checking For Left Button only
Dim ReturnVal As Long
x = ReleaseCapture()
ReturnVal = SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
End If
End Sub

How to call this sub

You must put this sub in the Form_MouseDown event like this:

Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, Y As Single)


MoveWithMouse
End Sub
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Determine to location of the Mouse

API(s) that we need for this:

GetCursorPos

Open modAPI and add this to it:

Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" (lpPoint As POINT

Now open modFunction and write this sub:

Sub MouseLocatioN ()
Dim Pnt as PointAPI
GetCursorPos Pnt
lblMouseLocation.Caption = "MousePointer is located at " & "; Pnt.X;" & "," & ";

How to call this sub

You must put this sub in the Form_MouseDown event like this:

Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, Y As Single)


MouseLocatioN
End Sub
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to get Windows and System Directory

API(s) that we need for this:

GetWindowsDirectory
GetSystemDirectory

Open modAPI and add this to it:

Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA"


(ByVal lpBuffer As String, ByVal nSize As Long) As Long
Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" _
(ByVal lpBuffer As String, ByVal nSize As Long) As Long

Now open modFunction and write this functions

Function GetWindowsDir () As String


Dim Temp as String * 256
Dim x As Integer
x = GetWindowsDirectory(Temp, Len(Temp)) ' Make API Call (Temp will hold retu
GetWindowsDir = Left$(Temp, x)' Trim Buffer and return String
frmMain.lblWinDir.Caption = "Windows Directory: " & GetWindowsDir
End Function

Function GetSystemDir () As String


Dim Temp As String * 256
Dim x As Integer
x = GetSystemDirectory(Temp, Len(Temp))' Make API Call (Temp will hold return
GetSystemDir = Left$(Temp, x) ' Trim Buffer and return String
frmMain.lblSysDir.Caption = "System Directory: " & GetSystemDir
End Function

How to call this function

You can this in Form_Load event

GetWindowsDir
GetSystemDir
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code to Get Disk Info

API(s) that we need for this

GetDiskFreeSpace

Open modAPI and add this to it:

Declare Function GetDiskFreeSpace Lib "kernel32" Alias "GetDiskFreeSpaceA" _


(ByVal lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As
lpNumberOfFreeClusters As Long, lpTtoalNumberOfClusters As Long) As Long

Now open modFunction and write this Function

Function GetDiskInfo(sRootPathName As String, sWhatInfo As String) As String


Dim X As Long
Dim lSectorsPerCluster As Long, lBytesPerSector As Long
Dim lNumberOfFreeClusters As Long, lTotalNumberOfClusters As Long
X = GetDiskFreeSpace(sRootPathName, lSectorsPerCluster, lBytesPerSector, lNum
GetDiskInfo = X

If X Then
CurrentDisk.RootPath = sRootPathName
CurrentDisk.FreeBytes = lBytesPerSector * lSectorsPerCluster * lNumberOfF
CurrentDisk.TotalBytes = lBytesPerSector * lSectorsPerCluster * lTotalNum
CurrentDisk.FreePcnt = (CurrentDisk.TotalBytes - CurrentDisk.FreeBytes) /
CurrentDisk.UsedPcnt = CurrentDisk.FreeBytes / CurrentDisk.TotalBytes
Else
CurrentDisk.RootPath = ""
CurrentDisk.FreeBytes = 0
CurrentDisk.TotalBytes = 0
CurrentDisk.FreePcnt = 0
CurrentDisk.UsedPcnt = 0
End If

Select Case UCase(sWhatInfo)


Case "ROOTPATH"
GetDiskInfo = CurrentDisk.RootPath
Case "FREEBYTES"
GetDiskInfo = Format$(CurrentDisk.FreeBytes, "###,###,##0")
Case "TOTALBYTES"
GetDiskInfo = Format$(CurrentDisk.TotalBytes, "###,###,##0")
Case "FREEPCNT"
GetDiskInfo = Format$(CurrentDisk.FreePcnt, "Percent")
Case "USEDPCNT"
GetDiskInfo = Format$(CurrentDisk.UsedPcnt, "Percent")
End Select
End Function

How to call this function

You can put this in the Form_Load event

To get FreeBytes :
GetDiskInfo ("c:\", "FreeBytes")
To Get TotalBytes:
GetDiskInfo ("c:\", "TotalBytes")
To Get FreePercent
GetDiskInfo ("c:\", "FreePcnt")
To Get UsedPercent:
GetDiskInfo ("c:\", "UsedPcnt")
And instead of "c:\" you can use "d:\' for drive D:
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

- Code for Sending mail

API(s) that we need for this:

ShellExecute - it's included

Open modFunction and write this Sub

Sub SendMail (frm As Form, MailTo as String)


ShellExecute frm.hwnd, "open", "mailto:" & MailTo,
vbNullString, vbNullString, SW_SHOW
End Sub

How to call this Sub

SendMail (TheNameofYourForm, "brzi@devious.tsongkie.com")


»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

You see that we put everything in modules and when we need


something we just call it. This is how you can make your
programs very small. If you compile this the exe should
be about 30kb but if you put all this code in the main
form it will be about 100kb !!! and that is not good.

And finaly the end of this tutorial. THANKS GOD !!!!


Man my fingers hurt so bad :)

Hope you have learned something and how to use reusable code.

For comments,suggestion and stuff refer to the mail address at the top

Untill next time SEE YA ALL !!!


Hello ,

This is a basic speedhack via opengl...

You need to create a speedblock so that you won't get lagged out of the server, a

// These are the basic variables that need to be defined for a speedhack
DWORD last_real=0;
DWORD last_fake=0;
DWORD StartTimeS;
bool speedblock=false;
bool tmp=false;
float speed;
int speedon=1000;
int speedoff=5000;
int TIMOUT=400;
typedef BOOL (WINAPI *QueryPerformanceCounterFunc)(LARGE_INTEGER*);
QueryPerformanceCounterFunc QueryPerformanceCounterPtr=NULL;

// credits to noskill - hooked QueryPerformanceCounter function


BOOL WINAPI newQueryPerformanceCounter(LARGE_INTEGER *lp)
{
bool ret = (*QueryPerformanceCounterPtr)(lp);

DWORD cur_ticks = timeGetTime();


DWORD new_real = lp->LowPart;

if(speedhack)
{
if(!last_real)
{
last_real = last_fake = new_real;
return ret;
}

double factor = (speed<1 ? 1:speed);


if(speedon==0 || speedblock) { factor = 1.0; }

DWORD diff_real = (DWORD)(new_real-last_real);


DWORD diff_fake = (DWORD)(factor * double(diff_real));
lp->LowPart = last_fake + diff_fake;

last_fake += diff_fake;
last_real += diff_real;
}

return ret;
}

Now in glViewport you need some kind of activation key, which would be fire, whic

if((GetAsyncKeyState(VK_LBUTTON)& 0x8000) && speedhack)


{
speedon=400;
speedoff=0;
}
else
{
speedon=0;
}

And now in glEnable, you create a speedblock, so you won't get lagged out of a se

if(speedhack && speedon != 0)


{

if(!tmp)
{
StartTimeS = timeGetTime();
tmp=true;
}
if((int(timeGetTime() - StartTimeS) > TIMOUT/speed) && !speedblock) // How long t
{
speedblock=true;
}
if((int(timeGetTime() - StartTimeS) > (TIMOUT/speed)*2) && speedblock) // Speed-P
{
speedblock=false;
tmp=false;
}
}

Now, to access different speeds, you would use the variable you've created: float

It's pretty simple. Speedhack does not work with an opengl wrapper (as far as I k

Read through the code so you understand it, just don't copy paste everything .

Thanks,
[z3r0h4x]G0dz

P.S: If you need more help, and if you want me to explain things to you, PM me, I

EDIT:

Left one thing out, you must define newQueryPerformanceCounter first, so you woul

if(!strcmp(lpProcName,"QueryPerformanceCounter")){
QueryPerformanceCounterPtr = (QueryPerformanceCounterFunc)GetProcAddress(hModule,
return (FARPROC)newQueryPerformanceCounter;
}

__________________
www.z3r0h4x.tk

[z3r0h4x]G0dz
#################################################################################

Title: Generic Reversing of Hacked Save Game checks.

Author: [SHEEP]

Level: Intermediate

Target: VEXX

Tools: IDA.. (http://www.google.com)


cxbx (http://www.caustik.com/)
Xbox Flirt (http://www.geocities.com/smil0r26/misc/xflirt.zip)
place the xflirt sig file into the SIG folder in IDA.
Hex editor (Your Choice)

#################################################################################

Introduction
============

Micro$oft in their infinite wisdom decided that when the xbox was rlsed
they would sign all of their saved games with a digital signature to
prevent you from tampering with the save games in any way.. I wonder
who the fuck they really think they are? I mean.. its our saved game
we should be able to do what the fuck we like with it. :)

This tutorial will attempt to explain to you how you can enable hacked
saved games to be loaded, its a generic approach so you can apply it
to pretty much any game. There isnt that much work involved so you
should be able to keep up. After this you will hopefully be able to
make your own patchs and maybe spread them so that EVERYONE can use
their own hacked saves for ALL games :)

PART 1
------

i) Converting xbe to exe for IDA.


ii) Loading Vexx Into IDA.
iii) Loading The Xbox Flirt File.

PART 2
------

i) Starting Work.
ii) Flirt And Functions.
iii) XApi Code.
iv) Recognising The Correct Routines.
v) Creating The Patch.

LETS BEGIN!!!!

PART 1
======
Converting xbe to exe for IDA
-----------------------------

First thing we need to do is convert the xbe into an exe..

these are the steps..

1) Load cxbc

2) Goto File/Open..

you now have to select the VEXX default.xbe.

3) Goto File/Export EXE..

you now have to save it somewhere.

4) Close cxbx

ok, now we got that done we can move onto the next stage..

Loading Vexx into IDA


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

We are now going to load the converted xbe into IDA.

1) Load IDA

2) Goto File/Open File

Select the default.exe that you just converted with cxbx.

A dialog box will appear..

3) Just press OK on the dialog box.

4) WAIT!!! this can take a few minutes..

When the numbers in the bottom left hand of the screen stop
moving then we are ready to move to the next stage..

Loading The Xbox Flirt File


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

So that we can get a better understanding of all the routines


within IDA we need to load the FLIRT.. this will re-lable a lot
of the routines for us so that we know exactly where to look.

1) Goto File/Load File

2) Come down to Flirt Signature File and click it.

3) Move down the list and choose the Xbox Flirt file.
4) WAIT!! this can take a little while..

Again.. when the numbers in the bottom left hand corner have
stopped moving we are ready for the next stage..

PART 2
======

Starting Work
-------------

Ok, we are now ready to start the real work..

The first thing we need to do is locate the routines that deal with
signing and checking the saved games..

The way we do this is by looking in the functions window to find


the routines associated with these tasks..

First we need to pull up the functions window.. we do this by following


the next few steps..

1) Goto VIEW/Open Subviews.

2) From the list click on "FUNCTIONS" should be the 4th item down the list.

We now have a window opened with all the functions displayed.

Flirt and Functions


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

The reason we loaded the Flirt earlier was so that it could run through our
list of functions and give them names (if it recognised them) it wont get
all of them as u will notice, LOTS are still labled with the IDA default
function lables... BUT!! it does name the ones we need so thats all that
really matters..

The 3 xapis(functions) we are interested in are..

XCalculateSignatureUpdate
XCalculateSignatureBegin
XCalculateSignatureEnd

They obviously all are related though usually it only takes the first one
to locate the rest within the code as they are all used in conjunction with
each other to form the signing routines..

so, we now do a search in the function window to find these xapis.

1) Make sure the "FUNCTIONS" window is selected.

2) Click on search in the menu.. then click on search from the list.

3) Type in the box, "SIG" without the " " and click ok.
4) If it stops at an xapi that isnt one of the above 3 press CTRL-T
to move onto the next one.

Once you have found it (should have been the 3rd occurance) double
click it and you will be taken to the Xapis code.

XApi Code
---------

You are now within the actual xapi code..

Scroll up a bit until you see this..

*********************************************************************************

; Attributes: library function


.text:0011D084
.text:0011D084 ; __stdcall XCalculateSignatureUpdate(x,x,x)
.text:0011D084 _XCalculateSignatureUpdate@12 proc near ; CODE XREF: sub_5A2B0+15p
.text:0011D084 ; sub_5A2E0+18p

*********************************************************************************

Right click anywhere on the _XCalculateSignatureUpdate@12 and you will be


presented with a little menu.. click on "Jump to Xref to Operand.."

Now you should have in front of you a box with 2 references.

We need to start thinking logicaly now to work out what these 2 refereces are for
well.. we know that the game needs them for only 2 things.. 1. CHECK SIGNATURE
ON SAVED GAME WHEN LOADING. 2) CREATE NEW SIGNATURE WHEN SAVING GAME. So the fact
that there is only 2 references to these functions means we are on the right trac
and dont really have 2 much further to go..

Recognising The Correct Routines


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

We now want to find out which one is used to check our saved game when its loaded
only way to do this is by double clicking 1 at a time and looking at the code aro
it..

So.. click on the first Xref and we can begin, you should land here..

*********************************************************************************

.text:0005A2C4 push esi


.text:0005A2C5 call _XCalculateSignatureUpdate@12 ; XCalculateSigna
.text:0005A2CA mov edx, [esp+arg_4]
.text:0005A2CE add edx, 8
.text:0005A2D1 push edx
.text:0005A2D2 push esi
.text:0005A2D3 call _XCalculateSignatureEnd@8 ; XCalculateSignature
.text:0005A2D8 pop esi
.text:0005A2D9 retn 10h
.text:0005A2D9 sub_5A2B0 endp

*********************************************************************************

We are now in A signature routine.. as you can see the other 2 Xapis I mentioned
earlier are also here.. this is a good sign that we are indeed in the right place

Hmm, have you noticed anything about this routine?? .. Well let me tell you.. the
doesnt seem to be ANY checks at all.. nothing is compared (CMP) or tested(TEST)..
it just seems altogether 2 quiet :)..

Im more inclined to believe that this routine is what MAKES the signature when
the SAVED GAME is being SAVED not LOADED because we have no checks once the code
has been executed.. of course.. checks are not always within the routine themselv
they can be further on.. we need to check just outside of this routine and see if
its being check there..

scroll up until u see this..

*********************************************************************************

.text:0005A2B0 sub_5A2B0 proc near ; CODE XREF: sub_59B40+8Dp

*********************************************************************************

double click the sub_59B40+8Dp and you should be here..

*********************************************************************************

.text:00059BCD call sub_5A2B0 ; We were inside here..


.text:00059BD2 mov eax, [edi+10Ch]
.text:00059BD8 push 1Ch
.text:00059BDA lea edx, [esp+28h+var_1C]
.text:00059BDE push edx
.text:00059BDF push eax
.text:00059BE0 call sub_DE3B0
.text:00059BE5 mov ecx, [esp+30h+var_1C]

*********************************************************************************

As you can see all the way down to the bottom of the routine there are no checks
or compares of any kind.. this is certainly looking to be the SAVE GAME routine
and not the LOAD GAME.

*********************************************************************************

We now want to get back to our original place so we can check that other referenc
so TYPE "G" and a box will appear, into this TYPE "11D082" without the " ".

You should now be back to where we started and can right click on
_XCalculateSignatureUpdate@12 again to get the references..

This time double click the bottom reference.. you will end up here..

*********************************************************************************

.text:0005A2F8 call _XCalculateSignatureUpdate@12 ; XCalculateSignatur


.text:0005A2FD lea edx, [esp+20h+var_14]
.text:0005A301 push edx
.text:0005A302 push esi
.text:0005A303 call _XCalculateSignatureEnd@8 ; XCalculateSignatureEnd
.text:0005A308 mov ecx, [esp+20h+arg_4]
.text:0005A30C lea edx, [esp+20h+var_14]
.text:0005A310 add ecx, 8
.text:0005A313 test dl, 3
.text:0005A316 lea eax, [esp+20h+var_14]
.text:0005A31A jnz short loc_5A350
.text:0005A31C test cl, 3
.text:0005A31F jnz short loc_5A350

*********************************************************************************

AH!!.. thats more like it.. you can see all the checks and compares after the xap

This makes me think we are NOW in the right area.. now.. if you look down the rou
you will notice that there seem to be 2 exit points.. these are RETN 10 instructi
you should also notice that ECX is being placed into EAX on each occasion which i
common practice for any routine wanting to return a GOOD or BAD result.. my guess
that one will return EAX as good and one will return EAX as bad.. but that does l
like complex code doesnt it? :) .. well.. as with pretty much all protections..
especially weak ones it all hinges on 1 compare.. 1 check for GOOD or BAD.. and a
this routine returns either a GOOD or BAD result.. the CHECK must be outside of t
routine and EAX is whats going to be checked.. so..

scroll back up until you see this..

*********************************************************************************

.text:0005A2E0 sub_5A2E0 proc near ; CODE XREF: sub_5A260+2Fp

*********************************************************************************

Double click the sub_5A260+2Fp and we should be here..

*********************************************************************************

.text:0005A28F call sub_5A2E0


.text:0005A294 test eax, eax
.text:0005A296 jnz short loc_5A29F
.text:0005A298
.text:0005A298 loc_5A298: ; CODE XREF: sub_5A260+22j
.text:0005A298 xor eax, eax
.text:0005A29A pop esi
.text:0005A29B add esp, 1Ch
.text:0005A29E retn
.text:0005A29F ; ----------------------------------------------------------------
.text:0005A29F
.text:0005A29F loc_5A29F: ; CODE XREF: sub_5A260+36j
.text:0005A29F mov eax, 1
.text:0005A2A4 pop esi
.text:0005A2A5 add esp, 1Ch
.text:0005A2A8 retn
.text:0005A2A8 sub_5A260 endp

*********************************************************************************
AH!! look at that.. just outside the CALL sub_5a2e0 we can see that EAX IS!!! che

Again.. there are 2 exit points.. but this code is MUCH clearer than the last lot

You can see that if eax is NOT 0 then 1 is placed into EAX and it goes off to ano
routine.. but if EAX is = to 0 then EAX is xored and then shipped off..

As far as NORMAL routines are concerned a 1 = GOOD and 0 = BAD..

I think we have found our patch location.. we need it to always return a GOOD res
we do this by altering the following code..

.text:0005A296 jnz short loc_5A29F


to
.text:0005A296 jmp short loc_5A29F

Creating The Patch


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

We do this using a HEX EDITOR.. and some xbe knowledge..

1) Open your hex editor..

2) Load the VEXX default.xbe

3) To locate a place in the HEX default.xbe we do this..

Subtract the BASE IMAGE of the default.xbe which is usually 10000 from
the address we got from IDA.. so..

.text:0005A296 - BASE IMAGE = 4A296

4) Goto that location in your hex editor..

5) Exchange the byte that is there (75) with (EB)

its now changed to .text:0005A296 jmp short loc_5A29F

6) Save.. CLOSE!

Thats it.. :)) now when u load that default.xbe up you will be able to
load in ANY saved games you like.

(75) is the ASM opcode for JNZ .. and (EB) is the ASM opcode for JMP, I suggest
you learn them.

To be honest VEXX was a pretty simple one to start with because it didnt have
any checks on the SAVE GAME section.. Some games do actually use some checks
after saving your SAVED GAME so you need to just follow the code a little
more to figure out whats going on..

#################################################################################

I hope you enjoyed reading this tutorial and hopefully you learnt something
from it..

if you have any questions you can email me at sh33pr3c@hotmail.com.

Tutorial written for XBOX-SAVES. Visit our website WWW.XBOX-SAVES.COM

#################################################################################
How To Hack Sega GT 2002 To Allow It To Accept Hacked Game Save Files
Up until now, the main obstacle encountered when trying to hack game saves was that the game would
detect that you tried to hack it by comparing the game save data to the "signature" (CRC) of the game
save file(s).

However, DEatHrler has found a way around that! He has successfully modified the main game file
itself (default.xbe) to bypass the CRC check. Thus, hacked game saves will load and work despite the
CRC not matching the data.

Below is a little tutorial that he wrote up related to hacking the Sega GT 2002 default.xbe file to
allow hacked game saves to load. While specific to this game, the principals apply to any game.

[ Update ]

Although you initially need to hack default.xbe to load a game save that you hack, you can then
resave the game and will have a valid game save file with the proper CRC recalculated. The save
can then be used by anyone with the game, regardless of whether or not they have hacked their
default.xbe file. This is certainly very good news for those who are less inclined to hex edit their
default.xbe files.
If you just want to hack sega gt, go to the section "Actualy Hacking
the .xbe" everything else is technical for cracking other games...

Fist, open CXBX (0.4.4 was what was available, all should work)

Go To File/open .xbe file

open your default.xbe of the game you want to crack

and then go to File/export to .exe...

now you have your .exe file to dissasmble in W32Dasm


Open her up and you see something like this; if you've never used w32dasm all the buttons get
confusing so just go to dissasembler/open file to disassemble

open your file and it'll go to work. you should get a screen that looks like this; disassembling takes a
while so give it time.

when you're done go to refs/string data references


locate the file that you susspect to be the save state. In Sega GT it's gdata0.dat there are other files but
they aren't crucial

Double click the file and it'll bring you to the instance it suspsects the file is being accessed
there might be several instances of it being accessed; usually one for saving and one for loading.

You can tell that this particular instance is for loading because the previous one has idata0.dat
accessed before hand which isn't read for data, it's only used in the load menu.

Here comes the arbitrary part: you must determing which function is being used to checksum the files
It's rather obvious in Sega GT because on one of the calls you come to a bit of code that looks like
this:
I'm not exactly sure what it is doing line by line but it looks to me that it is what I need to get rid of

Look near the bottom of the W32dasm window when you have the call selected and you should see, in
the status bar,

"Line: ######## Pg ##### and ##### of #### Code Data @:###### @Offset 0006DD5Ch in
File:default.exe"

The data that you are interested in is the number that I have bolded, it will be different for every game
but this is what it happens to be for Sega GT
Actualy Hacking the .xbe
Open up WinHex and click Position/Go To Offset

Make sure that the button next to the text box is set to "Bytes" or you will get the wrong place

Enter the offset (6DD5C for Sega GT) from the previous step in the text box and hit OK. It'll jump you
to the offset that the call function is on

Now find the offending call in the .xbe and nop it out (put 90s in for all of the addresses the call
function takes up)

You should now have a cracked .xbe, FTP it to your XBOX and load some hacked save states
An Example of a hacked save state... unfortunately the engine doesn't deal with really large numbers,
it limits itself to $9,999,999 but ~$10,000,000 works

I'll try to document the save state to make modification easier; the most notable offset is 00000018
through 0000001B which is for money,

values of FF FF FF 04 will give you around $10.5 mil, I wouldn't suggest going over because the
engine doesn't like extremely large money values (wont let you buy if you have too much)
Bie comment:
This info is taken from http://www.gamehacking.com forum

Tutorial Author: UnderlordKrullik


Email: Underlordkrullx@hotmail.com
Homepage: Unknown
Other known method to contact the author

Unknown

Hacking The PS2 And Converting By UnderlordKrullik (Original Tutorial can be found here at CES Forum)

Here's how to do it....

First off here's what you need..

PS2DIS(program).
The game you want to hack.
The converter.
Codebreaker Or Gameshark Or Action Replay (Cheat devices for the ps2)
I will post the links after.

Ok 2nd put your ps2 game into your cdrom in your pc.. right click on your CD drive icon E or F which ever you put your disk in.. Hit open and copy the Slus file into another folder (I save my slus
file of the game into ps2dis folder). Ok you can close that out now that you have the slus file out you can also take your disc out.

Now open up PS2DIS and load the slus file.. now all the coding in PS2DIS will look simply of ASM hex including labels such as Car names gun names ETC... now all you do is if you not understand
much of ASM look in the labels and double click on say a AKS-74(Gun) it will bring you to the ASM hex strings of it now it should be i would say 7 addresses.. since this is hex this is where the
converter comes in...

now copy all those hex addresses out into a text file and 1 by 1 convert them to Codebreaker or gameshark or action replay whatever cheat device you use on the PS2.. after you Convert them
put them in your cheat device.. you should only use 5 at a time so the game wont crash if there's an invalid... but Not all games use the labels.. so you might have to look just manually down the
games hex and test.

That's about all I'm getting the links and ill be adding the converting tutorial and some pictures.

Here's The Converter


Here's The Ps2Dis

I'm sorry its scus not slus my bad SO here's a sample I'm using Socom II for ps2

Copy the scus to a different folder in your pc

PS2DIS Interface
Labels in socom II I have ammo lable highlighted

Heres the code i will convert hex to Codebreaker, gameshark, ActionReplay


There's also more info at converter site.

There can be very many addresses in a label so you have to convert and manually test each address.

CodeBreaker Basic Converter TUT

Ok in ps2dis all the coding is in hex so make sure the converter is on HEX button

Now I got a random hex code out of labels for socom now double click an address in PS2DIS for a little window to open it should say Address and data looks like this for example Address: 000000
Data: 000000 now copy the address and paste it in the converter then copy data into it it should look like this

the first line 001d4538 is the address in ps2dis then the 74736f68 is the data it should look like the pic above and i have the two 0's circled which is important where those 00's are put 2A now after
you have that done click on the CB2 button and it will convert the hex to codebreaker like this

Notice that the CB2 is poked and that the hole address is changed so it converted the PS2DIS addresses into CB2 addresses now all you need to do is put that in your CB2. Now there is no really
way to know what an address in PS2DIS does that's why most PS2 hackers have a team so they can each convert addresses and test them... kinda like for PC hacking if you do the 12345 method
when you poke like 5 addresses at once but in ps2 then try them out.

If you have anything to ask post.

HINT: this is not the same way for gameshark or action replay if you need it ill post it.
From http://www.gamehacking.com forum.

Author: ghBladez

Looping Tutorial

Ok well here is a small guide on how to loop the label of your choice in the popular disassembler ps2dis. Firstly open your software and the sces sles slus scus file you want to hack and invoke the analyzer by pressing the
tab Analyzer - Invoke, When you have done tap CTRL + G to open up the labels list. Scroll through it and look for a label you like, In this tutorial I'm going to explain to you how i hacked the rank code for SOCOM: US Navy
Seals. So when we have found our label, "PointsEarned" double click it to bring you to the text refer of the code, next you press the space bar (highlighting the function) and press F3 (skipping to the code refer). Now you are
ready to start the real hacking, Scroll up to see the label "RoundStatLBTerrs", Now take that label and press space bar then F3 again to get to the code refer, look up to find the first lw command and copy it to the clipboard.
Then back to pointsearned (A few lines beneath the roundstatlbterrs label. Scroll down to the next jump register (jr) command underneath it which should be about 5 pages down. Once you have found it tap enter to bring you
to the command box and wipe out the current function. Replace this with "beq zero zero $address" address being the first lw up from RoundStatLBterrs. And then Hit Enter which creates the beq (branch when equal).

and then you have your code...


Also if you wish to loop a label more than once use another command such as blt (branch when less than).

Enjoy,
ghBladez

Das könnte Ihnen auch gefallen