Xbox Trainers

Discussion in 'Xbox - Software discussion' started by Bubba1982, May 26, 2005.

  1. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
  2. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
    Bit of a slow week aye.
     
  3. crusoe

    crusoe Member

    Joined:
    May 16, 2005
    Messages:
    29
    Likes Received:
    0
    Trophy Points:
    11
  4. crusoe

    crusoe Member

    Joined:
    May 16, 2005
    Messages:
    29
    Likes Received:
    0
    Trophy Points:
    11
  5. guinnyss

    guinnyss Guest

    is that a good site, because they always seem full.
     
  6. Achilles3

    Achilles3 Guest

    Last edited by a moderator: Jul 20, 2005
  7. guinnyss

    guinnyss Guest

    Achilles3 you again? man you all over the place answering all the questions :)you the man, poeple like me appreciate poeple like you. thanks.
     
  8. Achilles3

    Achilles3 Guest

    I am everywhere.. be very afraid :) Just trying to help out.
     
  9. guinnyss

    guinnyss Guest

    and your doing it good.
     
    Last edited by a moderator: Jul 20, 2005
  10. vgaddict8

    vgaddict8 Guest

    Achilles3, I can't find anything trainers at maxconsole.net. Are the trainers in the forum, or do I have to register?
     
  11. crxshn

    crxshn Member

    Joined:
    Dec 24, 2004
    Messages:
    19
    Likes Received:
    0
    Trophy Points:
    11
    nice

    i been looking for links like these

    thanks heaps fellas

    much appreciated

    please keep them coming :)
     
  12. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
    ok, I posted this tutorial in another thread somewhere, & i can't quite remember where. lol.
    So I'm reposting it and this time I'm gonna bookmark it so I can point people in the right direction when they ask "How do I make Trainers".
    Also, the tutorials are not by me. Just had to mention that so it doesn't seem like I'm taking credit for other people work :)

    Here is tutorial number 1.




    Evox Trainer Tutorial.

    Tools needed:

    Computer
    Xbox
    Latest Evox
    CXBX (http://www.caustik.com/cxbx/)
    Network connection between xbox and computer
    brain

    Useful tools:

    Ida Pro (any will do, 4.30-current is ideal)



    The first step to writing a trainer is to pick a game, just about any game will do,
    but its best to start out with something simple, where its easy to tell the values
    you are dealing with. It helps if the value is something you can see update, such
    as lives or amount of ammo.

    I looked back through the games that I've wrote trainers for, and most of them weren't
    what I'd call simple, Armed and Dangerous and TMNT (# of continues) were easiest, so lets
    try one of those..

    After selecting a game get a copy of the xbe onto your computer and load it up in caustiks
    CXBX, go to the file menu and say 'export exe' and save it to something like tmnt.exe, now
    go to the edit menu, and select the dump xbe info to option, dump it to a file so that you
    can cut and paste.

    Open the output file up with a text editor (notepad/wordpad) and scroll until you see
    something like (from max payne 2):

    Dumping XBE Certificate...

    Size of Certificate : 0x000001EC
    TimeDate Stamp : 0x3FB3F515 (Thu Nov 13 16:18:13 2003)
    Title ID : 0x5454000C
    Title : L"Max Payne 2"

    The part you care about it the title ID, copy that to another text editor window and
    be sure to save it, you'll need it to write the trainer.

    Now load up the game on your xbox (I will be showing how to do the Continue trainer for TMNT),
    telnet to your xbox's ip.. You will see:

    RemoteX Debugger V1.1
    .


    Pick a character, I chose Leonardo..
    Hit A until you you see a bunch of the little robot thingies coming at you..

    Now look at your status bar, you have health (bar) # of Shurikens, score, and '6' hearts.

    type: value 6

    The output should look like:

    Store Game State in slot 0
    ...
    ...
    Done.
    Slot 0 Val 6
    --

    Now lose a life, and continue, now on the screen it says '5' so do a value 5 search.
    the output should look like:

    Store Game State in slot 1
    ...
    ...
    Done.
    Slot 0 Val 6
    Slot 1 Val 5
    --

    repeat the above process again (lose a life and continue) then search for 4..

    Store Game State in slot 2
    ...
    ...
    Done.
    Slot 0 Val 6
    Slot 1 Val 5
    Slot 2 Val 4
    (a bunch of crap)

    I then wen't back to the title screen (Start) and started playing again, now that my life
    count is back to 6, so I do a value 6 search..

    Check 83d00000:83f58000
    83d03088
    83d030d0
    83d0343c
    83d03444
    83d034d8
    83d03910
    83d0395c
    83d08084
    83d0842c
    83d0c2dc
    83d0c2e0
    83d0c2e4
    83d0c2e8
    83d0c2ec
    83d0c600
    83d0c604
    83d0c618
    83d0c634
    83d0c638
    83d0c63c
    83d0c670
    83d17424
    83d1781c
    83d814c0
    83d81830
    83d81c1c
    Check 00a80000:00b80000
    00b72448
    Check 83b34000:83c60000
    83b97274
    83b99a54
    Check 83575000:835b5000

    From this I would have to say that only three of these addresses look like good targets,
    00b72448
    83b97274
    83b99a54

    The next step is to look at what data is stored there..

    so type: db <address> 10
    you should see:

    00b72448 : 06 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 00 | ................
    83b97274 : 06 6a 7e d2 06 6c 81 d2 06 6a 7e d2 07 66 79 d0 | .j~R.l.R.j~R.fyP
    83b99a54 : 06 67 79 d2 59 a1 af e2 bf dc e1 f4 ff ff ff ff | .gyRY!/b?\at

    From this I would have to say the first one is the best canidate. Most if not all games
    for xbox are wrote in C (or C++) and in C a integer (whole number) is 4 bytes long.
    Although you can store values in a single byte, unless memory is tight, it is seldom
    done (from what I've seen so far).

    So now what? Lets see if we can change the value..

    type: poke 00b72448 7

    ! The hearts value went up to 7! We may have the correct address..

    Now its time to see. Now we want to see when this value is changed..

    so type: bpmb 0 00b72448 w

    Now its time to die again. When you hit start to continue the game froze. This is
    good, it means this value WAS updated when you continued..

    BP 0 @ 0002a261
    EAX : 00b72424
    EBX : 00000000
    ECX : 00000001
    EDX : 00000006
    ESI : 013bcd24
    EDI : d0044df0
    EBP : d0044d4c

    TMNT hangs after you do a break point (At least it does for me) so just reboot your system
    (type reset in the telnet window) or turn the xbox on and off and reload TMNT, and reconnect
    with telnet.

    now in IDA pro, click the VIEW-ASM tab, then go to the jump menu, select jump address
    and type in 0002a261.

    .text:0002A250 arg_0 = dword ptr 4
    .text:0002A250
    .text:0002A250 mov eax, dword_2AA8E0
    .text:0002A255 mov edx, [eax+24h]
    .text:0002A258 mov ecx, [esp+arg_0]
    .text:0002A25C sub edx, ecx
    .text:0002A25E mov [eax+24h], edx
    .text:0002A261 retn
    .text:0002A261 sub_2A250 endp

    Look at the instruction before the break, they are moving the value in edx to some memory
    location, this is whats updating the value we see on the screen. So where does this edx
    value come from?

    If you look at the line above that:
    .text:0002A25C sub edx, ecx

    This means: edx = edx - ecx

    if we look back to what our break point said, we see that ecx equals one, so that means its
    edx = edx - 1 and since edx equals 6 after the subtraction, that means it was previously 7.

    so rewrote in english:

    move some address stored at 2AA8E0 into eax
    *move the value that is at eax + 24h into edx
    move the value (1) that was pushed to this routine into ecx
    -subtract ecx from edx and place it in edx
    *move edx back to where it came from (eax + 24h)

    So we have a few options, we can change ecx to 0, we could not subtract the value, or we
    could remove all instructions from the function, or we could just return as soon as we get
    to the function.

    move some address stored at 2AA8E0 into eax
    *move the value that is at eax + 24h into edx
    move the value (1) that was pushed to this routine into ecx
    *move edx back to where it came from (eax + 24h)

    If we remove the subtraction part, we end up moving a value from
    eax+24h to edx
    then from
    edx to eax+24h

    That will keep the value the same, so lets do that..

    The SUB starts at 0002A25C and ends at 0002A25D so we have to remove two bytes,
    the simplist way to do this is to 'NOP' (no operation) the SUB instruction.

    so in your telnet window type:

    poke 0002A25C 90
    poke 0002A25D 90

    Now start playing, and try to die, the value should stay the same, and you now have
    infinite lives!

    Back to top
     
  13. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
    Here is Tutorial Number 2.




    . .
    - - -:- ----------------------:- - -
    | `:: |
    | ________ ' | - M X T -
    _ _ _:___ _________/\ _/____\ \ /\______|____________ ___:_ _ _
    | _\ __ \ / \ \/. __ __ /_ |
    | \\/|. \ \/ .\_ // __/ |. |\// |
    [ ::::: | . || |\ / ||/ \ \ || | . | ::::: ]
    | ::. _| | \/| | /\ \_| |_ .:: |
    _ _ _|______\ ______| |____________ / \______/|________ /______|_ _ _
    : \/ | . \/ | \/ :
    | ::. |
    - - -:---------------------- -:- - -
    ' '
    ' '
    .-------------------- - dootdoo's Trainer Tutorial #2 - --------------------.
    | Date: 27/18/2003 :
    `----------------------- - - - - - - ------------------------'

    ::::::::: [ T u t o r i a l ] :::::::::::::::::::::::::::::::::
    .----------------------- - - - - - - ------------------------.


    Evox Trainer Tutorial.

    Tools needed:

    Computer
    Xbox
    Latest Evox
    CXBX (http://www.caustik.com/cxbx/)
    Network connection between xbox and computer
    brain

    Useful tools:

    Ida Pro (any will do, 4.30-current is ideal)


    Tutorial #2... NBA Jam 2k4 (USA/NTSC)

    I assume that you have read the TMNT tutorial, so you are at least
    slightly familiar with the tools referenced, if not, please go read it first.

    Convert your xbe to an exe, load it into Ida Pro, or whatever your perfered
    disassembler is..

    Our goal is to add an option so that you can buy any attribute for free, regardless
    of how much money you have, and hopefully go on by yourself to extend it to cover
    all purchases on unlockable items.

    I started out doing a traditional search for values, but came up empty, so I looked
    for another way to train the game. I noticed when you start a new career that you
    begin with 10,000 jam points to spend on upgrades for your player. So I took 10,000
    and converted it to hex (I used the calculate in A.X.E hex editor, but windows calc
    will do just fine) and got 2710h, so I search using the text search tool for
    (spc)2710h

    (spc) being a blank space, so that I wouldn't get matches for 42710h, etc.

    The first occurance I come across is:

    .text:0001A2EF mov dword ptr [esi+2Ch], 2710h
    .text:0001A2F6 mov al, 0FFh

    .text:0001A2E0 00 00 89 7E 14 66 A1 A8-5E 2B 00 66 89 46 38 C7 "..ë~¶fí¿^+.fëF8¦"
    .text:0001A2F0 46 2C 10 27 00 00 B0 FF-88 86 E6 03 00 00 88 86 "F,'..¦ êåµ..êå"
    ^^^^^-- Value..

    So I poke 0001A2F2 with a value (ff) and start a new player, what do ya know, instead
    of starting with 10,000 I started out with 10,239.. So now we know we have found what
    initially load the value into some memory location.

    *** So I exit out of the menus, and set a 'bpx 0 0001A2EF' and re-enter the jam store.
    I instantly get a break...

    BP 0 @ 0001a2ef
    EAX : 00000019
    EBX : 00000000
    ECX : 011eaaf4
    EDX : 011eabdc
    ESI : 011eaaf4
    EDI : ffffffff
    EBP : d00648c8

    (yours may be different)

    so I take ESI (011eaaf4) and add '2c' to it and get 11EAB20, this is where the money
    is stored (at least at first). so I clear my break point (bpc 0) and choose a profile.

    I then go to the create a player screen, and look for somewhere to spend money.
    If you hit the 'R' trigger until you are at the guy flexing his muscles you will see
    you can buy attributes..

    So I hit a, and see a bar below, I hit right, and see that my pts decreases, so I hit
    left, then set a breakpoint on the address I learned.

    bpmb 0 11EAB20 w

    (we only care about writes at this point)

    Now hit right again, you should get a break..

    !!!! If you don't then choose the menu option discard and exit, go to the create a
    player option, then turn back on the bpx 0 0001a2ef and use the new offset, sometimes
    it changes on me, sometimes it doesn't..

    I had to follow my advice above, and reget the address ;)

    BP 0 @ 00084d32
    EAX : fffff830
    EBX : 00000003
    ECX : 012dfb90
    EDX : 00000fa0
    ESI : 012d4750
    EDI : 00000002
    EBP : 00000000

    Now go to 0084d32 in your disassembly..

    .text:00084D26 mov eax, [esp+arg_0] ; Get value to subtract (negative number)
    .text:00084D2A add edx, eax ; Take our value (edx) and sub above #
    .text:00084D2C mov [ecx+0E0h], edx ; move new value to where we store money
    .text:00084D32 retn 4

    We have multiple options, we can fix the game to always send '0' or a positive number when
    you buy an item to this function, or we can make it not subtract, or we can let it do
    all that, and just not update our value, I chose to do the third option since it makes it
    easier for me to find other writes to that address (less uf'ing)

    So we

    poke 00084D2C 90
    poke 00084D2d 90
    poke 00084D2e 90
    poke 00084D2f 90
    poke 00084D30 90
    poke 00084D31 90

    yay, now it doesn't cost anything to buy attributes..

    But wait, we aren't done, as you keep hitting right eventually it will stop, since we
    don't have enough money to purchase!

    Okay, so now that we have the write taken care of, lets see where it reads (since its probably
    getting the value, comparing it, then if there is enough, going on)

    so set your break point just as you did above (bpmb 0 11EAB20 w) but this time do a
    bpmb 0 11EAB20 r (be sure to use the address YOU got, since it will likely be different)

    Oh my, as soon as we set this we got a break, but we didn't hit any key...

    .bpmb 0 12DFC70 r
    .Break
    BP 0 @ 00085be5
    EAX : 00000fa0
    EBX : 3c88b0f0
    ECX : 012d4750
    EDX : 00000002
    ESI : 012dfb90
    EDI : 3c88b0f0
    EBP : d00648c8

    .text:00085BDF mov eax, [esi+0E0h]
    .text:00085BE5 push eax
    .text:00085BE6 lea ecx, [esi+4C8h]
    .text:00085BEC push offset aJamPtsD ; "Jam Pts: %d"
    .text:00085BF1 push ecx
    .text:00085BF2 call sub_1B37FD


    What this is doing is effectively in C is something like sprintf(ecxlocation,"Jam Pts: %d", eax)
    eax being our pts, so this is likely JUST doing the screen update stuff, and not effecting
    our compare..

    So we have two options, put something else in eax, so we don't break, or just live with it
    and hold right on our controller and keep entering 'uf's (up enter)

    Sooner or later, you should get a break thats different.. It took me 3 uf's.

    BP 0 @ 000c0c81
    EAX : 00001f40
    EBX : 00000003
    ECX : 012dfb90
    EDX : 000000dc
    ESI : 012d4750
    EDI : 0000000b
    EBP : 00000000

    .text:000C0C73 call sub_C0200
    .text:000C0C78 mov ecx, [esi+14h]
    .text:000C0C7B cmp [ecx+0E0h], eax
    .text:000C0C81 jl short loc_C0CC6

    So this is getting our value with the ecx+0e0h and comparing it to eax, if we are less
    then, then it jumps..

    So we want to remove that..

    poke 000C0C81 90
    poke 000C0C82 90

    Hmm, but we still didn't get the item, lets try that again.

    BP 0 @ 000c04fe
    EAX : 012dfb90
    EBX : 00001f40
    ECX : 00000001
    EDX : 00000001
    ESI : 012d4750
    EDI : 0000000b
    EBP : 00000000

    Oh, a second check, but since we patched the first one, now we get to this one.

    .text:000C04F5 mov eax, [esi+14h]
    .text:000C04F8 cmp ebx, [eax+0E0h]
    .text:000C04FE jg short loc_C0513

    This looks a bit different, but you can see how its similar, now its going to jump if
    the value of the attribute is greater then what we have (ebx - cost, [eax+0e0h] - our $$)

    so

    poke 000C04FE 90
    poke 000C04Ff 90


    Now clear your breakpoint (bpc 0) and try out your new patch.. Yay it works!

    Now for extra credit, attempt the same process with the unlock options =)

    If you do go on to do that, remember there ARE multiple checks, and in odd spots
    I think there are 11 total checks, I always just nop'd the 'jl'

    Hope this helps you out with non value searching usage of the debug tsr..

    `----------------------- - - - - - - ------------------------'
    :::::::::: [ M o r e . I n f o ] ::::::::::::::::::::::::::::::::::::::::
    .----------------------- - - - - - - ------------------------.
    | :
    | This is the second tutorial by dootdoo, first one for MXT. You may |
    | download all our releases and many other evolutionx trainers from |
    | http://trainers.maxconsole.net . |
    | |
    | Visit http://forums.maxconsole.net to discuss this tutorial and reach me |
    | |
    | We are currently looking for : |
    | |
    | Coders - To join the team and produce quality trainers. |
    | |
    | Graphics Artists - To produce artworks and nfo's for the groups work. |
    | |
    | Greetings go out to www.maxconsole.net, Dootdoo, Danshuk, Angelfly, |
    | Team Evolution X, and all those who we forgot , you know who you are! |
    | |
    | If you think you can help in anyway please email info@maxconsole.net . |
    : :
    `----------------------- - - - - - - ------------------------'

    <------------ - (c) MXT 2003 - Training the Scene to the MAX! - -------------->
     
  14. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
    And finally, here is tutorial number 3.


    EvoX Trainer Tutorial
    by Xor
    Intro
    This is my first tutorial. Worse, this is the first draft of my first tutorial. I have little or no idea if it's too simplistic, complicated, condescending, faux-witty or dry. So, please, when you're done reading it, send some constructive (or destructive) criticism my way on the tutorial thread in the MaxConsole forums. Thanks!
    :)
    Basics
    Useful things to have
    Xbox and Game You Want To Crack (well, duh)
    Telnet connection
    Disassembler (I use IDA Pro 4.7)
    Hex editor (I use Hex Workshop)
    Good knowledge of base-16 (AKA hexadecimal)
    Passable Knowledge of Assembly Language
    I Assume...
    ...You know how to set TSR Debug in evox.ini, and you can connect up Telnet, and you've read at least one other tutorial on cracking for EvoX trainers.
    Punctuation
    I use the suffix f to denote a floating point number. e.g. 50.0f
    I use the suffix h to denote a hexadecimal number. e.g. 32h
    I use no suffix at all for an integer. e.g. 50
    Remember not to use suffixes in Telnet!!
    Lateral Thinking
    Okay, so you want infinite lives. The nice on-screen display shows you have three lives.
    You type in "value 3". Lose a life. "value 2". Lose another life. "value 1".
    Scenario 1. You find the memory location (or locations). Hooray. The sun is shining. Skip ahead.
    Scenario 2. Search results draw a blank. What's going on? This is a very simple example, and forgive me if you feel this is too simple (it is in the Basics section), but in the computer world, more often than not we don't start counting at 1. We start at 0. So you might have more luck with "value 2", "value 1", "value 0".
    If that doesn't work, try looking at it the other way around. The original coder, under the influence of alcohol and drugs, may have decided to store how many lives you've lost instead. So try "value 0", "value 1", "value 2".
    If that doesn't work, ask yourself if the lives are subdivided into a finite number of pieces. For example, one life = four pieces of heart. The program might be storing the total number of pieces, so try "value 12", "value 8", "value 4". Or even 11-7-3, or 0-4-8.
    A good cracker will get there in the end.
    As an aside, if you're cracking large numbers, between "value" commands, try to lose odd amounts. For example, go from 10 to 6 to 3, rather than 10-9-8. You're then guaranteed a smaller list. Better still would be 10-3-6. It just saves a little time.
    More Advanced
    Health Bars
    Health Bars may have their data stored as integers. Common values might be:
    0 to 100, or
    0 to 127 (signed char), or
    0 to 255 (unsigned char), or
    0 to 1000.
    If that's the case, then hopefully there'll be a number, on-screen (or on a statistics screen) which you can search for. Obvious, right?
    However, in the Direct3D world of modern gaming, most values are stored as floats (integers with decimals). The two most common values to search for are:
    0.0f to 100.0f, and
    0.0f to 1.0f (in particular)
    How the heck do you search for floats?
    Glad you asked. You can't, directly. But what is a float? A float is just a long integer in disguise. It takes up the same 4 bytes of memory.
    For example, 100.0f = 42c80000h, or 00 00 c8 42, which is exactly the same as the long integer 1,338,507,264.
    Great, so if you know the equivalent long integer you can search for that?
    Afraid not. EvoX Debugger currently won't search for anything longer than a short integer (2 bytes).
    But that's not a problem! Because, happily, we don't need to search for all four bytes in a float. We just need to search for one byte. He-he.
    Some Useful floats from 0.0f to 1.0f
    Float Hex value Decimal to search for
    0.0f 00 00 00 00 0 (duh!)
    0.05f cd cc 4c 3d 61 (=3dh)
    0.1f cd cc cc 3d 61
    0.15f 9a 99 19 3e 62 (=3eh)
    0.2f cd cc 4c 3e 62
    0.45f 66 66 e6 3e 62
    0.5f 00 00 00 3f 63
    0.75f 00 00 40 3f 63
    1.0f 00 00 80 3f 63
    In other words, if your health is somewhere between 15% & 49%, search for 62. Above 50%, search for 63.
    What I tend to do is:
    search for 63 at 100%
    lose health so it looks ~35%. Search for 62
    pick up a med pack so my health is above 50% again. Search for 63.
    For non-rechargeable bars, I might try quick-saving after step 1, and quick-loading before 3. Or try to judge when the value is lower than 15%, i.e. do a 63-62-61 search.
    If this produces results, remember that any memory location found, e.g. 1aafh, is the location of the fourth byte in the sequence (the value we're searching for), so in that case the full health is at 1aach. Bytes 2 & 3 would be at 1aadh and 1aaeh.
    If that doesn't produce results, remember to try the reverse search. In other words, search for damage sustained rather than health remaining (i.e. look from 0.0f to 1.0f).
    If that still doesn't work, you should try another float range, but, speaking as a programmer, 0.0f to 1.0f is the most likely range, since, for example, if you have a health bar of max length xyz pixels, then it is trivial to find the length of the health portion to be drawn.
    e.g. if health = 60%, and the full health bar is 240 pixels long, then the length of the bar at 60% health is 0.6f x 240 = 144. Now, if the float range is between 0.0f and 3.3f (say), then 60% is equivalent to 1.98f. Then the calculation is 1.98f x 240 / 3.3f = 144. Unnecessarily complicated.
    Some useful floats from 0.0f to 100.0f.
    Float Hex value Decimal to search for
    0.0f 00 00 00 00 0 (duh!)
    1.0f 00 00 80 3f 63
    2.0f 00 00 00 40 64
    5.0f 00 00 a0 40 64
    10.0f 00 00 20 41 65
    25.0f 00 00 c8 41 65
    31.0f 00 00 f8 41 65
    32.0f 00 00 00 42 66
    50.0f 00 00 48 42 66
    100.0f 00 00 c8 42 66
    This is a little trickier to handle, because it's more difficult to judge the ranges from the health bar on screen. Use a ruler and calculator as necessary! For 32% plus, search for 66. Between 8% and 31% search for 65. etc.
    Simple, right? In fact, I think it's even easier than finding integer locations, as you don't have to convert the integers to hex all the time. :)
    Sidebar – Clustered Values
    If you're having no luck finding a memory location, try looking instead for something similar, and then looking at nearby addresses using db.
    For example, if you want to give yourself 99 rockets, but the game only ever gives you 1, you might do a search on other types of ammunition. Chances are strong that the rocket memory location is nearby.
    e.g. if Uzi ammo is at 123a0h, try typing
    db 12380 50
    and look for other ammo (or even health, inventory items) in the neighbouring bytes.
    Or, if you're looking for health, and you know where the shield location is, the health is probably nearby.
    Remember, for floats, the important hex numbers to look out for are those in the range 3eh to 42h, and they're usually – but not always - in columns 4, 8, 12 & 16.
    Advanced stuff
    Dealing With Memory Locations
    Here is my procedure for dealing with, say, three possible memory locations for a floating value e.g. 123a4, 456b8, 789cc
    db each location. e.g. db 123a0 10
    Work out the float value from the db output.
    You do this by opening Hex Workshop.
    File->New
    Edit->Insert
    Select 4 (or more) bytes, click OK.
    Then type in those four float bytes as you see them in the db output. Point the cursor at the first one, and you'll see the float equivalent in the Data Inspector panel.
    If the float looks good, then see if it changes after you lose health etc.If it doesn't change it might be a saved value, or possibly a min or max value (for games that track statistics). Make a note in any case. That location might be your only lead if the other memory locations fizzle out.
    Poke the fourth byte of the float, and observe the results on-screen. For example, if the db output contains 00 00 c8 42 (100.0f), poke the fourth byte, e.g. poke 123a7 41, and see if the bar is a quarter of what it was. You could even poke the third byte if you wanted to, e.g. poke 123a6 48, and see if the bar is half the length it was.
    If nothing happens – that does NOT mean you have found a bad location. You just haven't found the source location.
    Conversely, if the poke works and the display changes, that does NOT (necessarily) mean you've found the source location. You may have found the float that controls the size of the health bar, but not the actual health! Test this by pausing at a very low health, poking the value so that it looks like you have full health, then lose some more health. If you die unexpectedly, you've still got more work ahead of you.
    In either case, do not give up now!
    Source Locations
    Let me give an example. Someone has coded a fighting game. They store the health as a float between 0.0f and 450.0f (they're insane). But they may also store another float, between, say, 0.0f and 55.0f, for the length of the health bar. Every time the display is refreshed, the length of the health bar is updated from the source health value.
    So, I come along and decide I want to crack the game. As luck would have it (by looking at the memory locations nearby to my points value, say), I happen across a float, 30.0f. I'm always suspicious of floats in the range 0.1f to 100.0f – and you should be too; they're rare. So I keep an eye on it. Sure enough it changes when I lose health on screen. But poking it makes no difference. (I db it again when the game is unfrozen and the new value doesn't stick)
    I need to trace the source memory location. I need to find the corresponding value between 0.0f and 450f. But I have no idea that that crazy range was used, so I'm forced to use the Disassembler to find the source.
    The Disassembler
    If you want to make trainers, you're going to have to deal with ASM. It's not difficult per se, just a little daunting because there are no useful labels, no useful variable names, no hints as to what might be going on, unlike a nice high-level language like C++. It's a bit like Binary compared to Decimal. You need a clear head to understand it – and a pen and paper (or even a flowchart program) may well be needed.
    So, you've found a memory location. You know that ammo is stored at address abc18h. You can poke it and give yourself more ammo. Then you write something like
    bpmb abc18h w
    to find out when the byte at that address is being written. If the game freezes immediately, then abc18h is not the source location. If it only freezes when you expend ammo, then it is. If it's not, and you have other locations to try, do so now. Otherwise, you'll have to find the original memory location with the debugger. Probably the best way to teach you how to use it is to go through a practical example.
    Example: A Step-By-Step Tutorial
    I'm going to take you through the process of creating a trainer for Max Payne. Why?
    It's a popular game that you're likely to own;
    It's a PITA to crack.
    I recently released a +5 PAL UK trainer for this game (available at MaxConsole). This tutorial will take you through the process of cracking it yourself, for both int and float values.
    If you have Max Payne, I strongly advise you to follow along with your own Telnet session. The memory locations will very probably differ (as Max's memory locations aren't all fixed), and there may be regional differences too in the assembly code locations. But the steps remain the same. If you don't own the game, hopefully you can still make sense of my ramblings - at least read some of my thought processes as I attempt the cracks.
    Part One: Cracking Max Payne for Infinite Reload.
    Load Max Payne.
    Load Tutorial level.
    Tutorial levels are ideal for making trainers, because you tend to get a good selection of items, and places to test ideas.
    You start off with "18 + 60" Beretta bullets. 18 is the number of bullets in the loaded clip, 60 is the number in the reserve clips. You can either go to crack the 18, or the 60. The only thing about cracking the 18 is that it takes away a little bit from the game if you never have to pause to reload (plus the reload animation is cool). Speaking for myself I like the pause. So I'm going to go for the 60.
    Telnet: value 60
    Empty a clip
    Telnet: value 42
    Empty a second clip
    Telnet: value 24
    I get a lot of memory locations at this point, and a lot of checks. Too many checks for my Telnet's scroll memory. So I repeat the last step.
    Telnet: value 24.
    Only one location found: ab1235h
    Telnet: db ab1230 10
    This returns:
    00ab1230: 41 12 00 00 00 18 00 00 00 30 7c ae 00 01 00 00
    In bold is the location found. But remember what I said about neighbouring memory locations? Take a look at the possible long integer next to it:
    00ab1230: 41 12 00 00 00 18 00 00 00 30 7c ae 00 01 00 00
    12h = 18. Quite possibly the value in the clip. Fire off another bullet.
    Telnet: db ab1230 10
    00ab1230: 41 11 00 00 00 18 00 00 00 30 7c ae 00 01 00 00
    That confirms it. Let's confirm the ab1235h location. Empty the third clip.
    Telnet: db ab1230 10
    00ab1230: 41 12 00 00 00 06 00 00 00 30 7c ae 00 01 00 00
    Good. Let's poke it.
    Telnet: poke ab1235 18
    Uh-oh. Nothing happened on screen.
    Telnet: db ab1230 10
    00ab1230: 41 12 00 00 00 06 00 00 00 30 7c ae 00 01 00 00
    That confirms it. The poke didn't stick.
    What does that mean? Well, it means that ab1235h is not the source location. When you think about it, that number will probably have been calculated from two things: the total number of bullets, and the size of the weapon clip. The number we were searching for just relates to the text on the screen. So we should have searched at the beginning for 78.
    As an exercise, you can try searching for 78, etc. Let me save you some time and say that you won't be able to find it! (Nor will searching from one less, i.e. 77 help) Max Payne is a PITA to crack!
    So that means we have to stick with what we've got, and use the debugger to trace the source memory location.
    Telnet: bpmb ab1235 w
    Immediately, I get a breakpoint message. This is expected, because the poke failed. The location is always being written to.
    BP 0 @ a9a1f
    I scan the assembly variables underneath. I'm looking for:
    the bullet value
    a possible float value (for health, or whatever)
    likely useful memory locations
    EAX is 6h, which is the current clip value. I db the values of EDX & ESI (because they're six digits, falling into category c). Neither are promising. But I make a note of them anyway, because they may have offsets (e.g. EDX+124h) which might be useful at some point in the future.
    One more thing to try is this:
    Telnet: uf
    I want to check that there's no other place where the variable is being written. But no, the breakpoint stops at the same place, a9a1fh.
    Time to load the disassembler!
    The relevant line is
    .text:000A9A19 mov [esi+225h], eax

    This is the command before a9a1fh; the breakpoint fires when this command is processed.
    No surprise here: EAX is being copied to the memory location. ESI is ab1010h, which is 225h less than ab1235h. Make a mental note to have a quick look at those 225h bytes...
    At this point, though, the most important question is: when is EAX given its value? We need to trace back through the assembly code.
    loc_A99F3:
    .text:000A99F3 lea eax, [esp+8+arg_4]
    .text:000A99F7 push eax
    .text:000A99F8 lea ecx, [esp+0Ch+arg_0]
    .text:000A99FC push ecx
    .text:000A99FD lea ecx, [esi+1B1h]
    .text:000A9A03 call sub_A8610
    .text:000A9A08 mov edx, [eax]
    .text:000A9A0A mov ecx, edi
    .text:000A9A0C mov [esi+1BDh], edx
    .text:000A9A12 call sub_4CBF0
    .text:000A9A17 mov ecx, edi
    .text:000A9A19 mov [esi+225h], eax

    I have bolded EAX wherever it appears. Ignore all the other junk. It's not relevant – except for the two calls. Those two calls could lead to subroutines which also assign EAX. But let's not look at them until we have to. EAX is assigned at a99f3h. So let's put a breakpoint at a99f7h, after that command has processed.
    Telnet: bpx 0 a99f7
    Telnet: uf

    EAX is not 06. It's d0055bc8h - a massively negative number. So EAX was assigned by one of the call commands. Not from the first one, either, because the next line (a9a08h) assigns the value at the memory location of EAX to EDX. 6h is definitely a value here, not a memory location! So let's look at the second call.
    .text:0004CBF0 mov ecx, [ecx]
    .text:0004CBF2 jmp loc_159B20

    That's it. Nothing going on with EAX. However, we're now jumping to the subroutine at location 159b20h. Let's take a look.
    .text:00159B20 mov ecx, [ecx+3B4h]
    .text:00159B26 call sub_18CAE0
    .text:00159B2B mov ecx, eax
    .text:00159B2D jmp sub_1BFFC0

    Here, there's a call, and another JMP. Put a breakpoint in to check whether the call does anything to EAX.
    Telnet: bpx 0 159b2b
    Telnet: uf

    EAX is still not 6h. It is 1becc72h, which is ~29Mb. A possible memory location? Let's take a look.
    Telnet: db 1becc70 10
    01becc70: 00 01 06 00 00 00 12 00 00 00 a2 00 00 00 00 00

    A-ha! Now, why didn't the search pick up on this earlier? Well, it's a high address, and my guess is that the EvoX Remote Debugger doesn't check that range. Let's poke it!
    Telnet: poke 1becc72 ff

    Wahoo! That changed the clip bullets to 255! Empty a clip. The value just changed on screen to 144! We sneakily poked to ff, as ff=255, the highest value for a single unsigned byte. It went down to 144, revealing to us that a max value routine was called somewhere. The max number of Beretta bullets is clearly 162 (=18+144). Let's find out where that value is set.
    Telnet: bpmb 0 1becc72 w
    Telnet: uf

    Empty another clip to fire the breakpoint.
    BP 0 @ 1bffe1

    And EDX has the value 90h, which is 144, the number of bullets! Let's take a look in the disassembly.
    .text:001BFFDF mov [ecx], edx

    This is what we expected. The value, EDX, is being copied to the memory location of ECX, where ECX is 1becc72h. So let's see what assigns its value to EDX.
    .text:001BFFD7 mov edx, [ecx]
    .text:001BFFD9 mov eax, [esp+arg_0]
    .text:001BFFDD add edx, eax
    .text:001BFFDF mov [ecx], edx

    From this it is clear that EDX is being assigned at 1bffd7h, and then a parameter is being added to it.
    Let's try something now! I'm going to NOP the add command.
    Be sure that the display is frozen when poking more than one byte!Telnet: poke 1bffdd 90
    Telnet: poke 1bffde 90
    Telnet: bpd 0 (disables the breakpoint)
    Telnet: uf

    Now, this was a bad idea, for one very good reason: usually when you're deducting ammo, you use a SUB command. So why use an ADD? Well, because this subroutine is used for both adding and subtracting bullets (i.e. adding when you pick up ammo, adding a negative amount when you lose ammo). If you test Max Payne now and try to pick up the shotgun, you'll see that it's stuck at 0! In other words we NOP'ed the wrong thing. Don't panic. Sometimes pokes go wrong. Either reset the XBOX and reload the game, or poke the original values (which are still there in the hex view of the disassembler).
    Telnet: fr
    Telnet: poke 1bffdd 03
    Telnet: poke 1bffde d0
    Telnet: uf

    Let's reload the tutorial, so we're all on the same page.
    The subroutine where bullets are added/deleted is called sub_1BFFD0.
    Now, there are two ways to go about fixing this problem:
    We need to find out which subroutines call this one. We need to trace back to a point where one sub removes bullets, and one adds bullets. In other words, isolate the remove bullets subroutine. In IDA you do this by selecting the label "sub_1BFFD0" and choosing to Jump to Cross References (the X key).
    I find out that it's called from: sub_18CB30 and sub_18D3E0. Now I set three new breakpoints, one for each call (it's called twice in sub_18D3E0).
    Telnet: bpx 0 18cba1
    Telnet: bpx 1 18d478
    Telnet: bpx 2 18d48e

    I empty a clip. Breakpoint 0 comes up trumps.
    You can then take a look at sub_18CB30 in more detail. You will find that sub_18CB30 removes bullets, and sub_18D3E0 adds them. But let's not bother any more with this case.

    There is a much sneakier solution... ...A sneakier solution which doesn't require setting all those breakpoints. Typically, in programming, we use error checking to make sure values aren't out of bounds. For example, a program which asks you for a number between 0 and 5 will check your answer, and round negative values up to 0, and numbers 6 and greater down to 5. Let's take a look at the assembly directly after the value is set.
    .text:001BFFE1 jns short loc_1BFFE9
    .text:001BFFE3 mov dword ptr [ecx], 0
    loc_1BFFE9:
    .text:001BFFE9 mov edx, [esp+arg_4]
    .text:001BFFED mov eax, [ecx+8]
    .text:001BFFF0 sub eax, edx
    .text:001BFFF2 cmp [ecx], eax
    .text:001BFFF4 jle short locret_1BFFF8
    .text:001BFFF6 mov [ecx], eax
    locret_1BFFF8:
    .text:001BFFF8 retn 8

    I bolded those three commands because [ecx] (the value at ecx, which is the bullet amount, remember) is being compared to EAX, and if the bullet amount is less than EAX, it is skipping ahead. Otherwise, it is assigning EAX to the bullet value! What else could EAX be but a max value?! Let's see!
    Telnet: (clear all breakpoints, unfreeze)
    Telnet: bpx 0 1bfff4

    Empty a clip. EAX = a2h = 162, which we found out earlier was the max bullet value. So let's be sneaky. Let's never jump over this assignment. NOP out the JLE.
    Telnet: poke 1bfff4 90
    Telnet: poke 1bfff5 90
    Telnet: bpd 0
    Telnet: uf

    Empty another clip – and the clip amount goes to 144, and stays there! Congratulations – you now have infinite reload!
    Part Two: Cracking Max Payne for Infinite Health
    You need to be in a controlled situation for working out health values. Somewhere that you can get hurt and heal yourself with no element of chance. In Max Payne, a good place is in the Tutorial level. Make your way to the main street, deal with the three goons, and collect the 4 painkillers from the subway. Quick-save your position now.
    Look at your health. If it's clearly above 50% (it should be, unless you are an even worse player than me!), then
    Telnet: newsearch (as applicable)
    Telnet: value 63

    We're searching in the range 0.0f to 1.0f, as described several pages back. Now, lose some health until you are under 50% (but above 15%!). A good way to do this is to climb on the van, jump up to the black railings (using the wall-fans as stepping stones), and from the bottom of the first flight of stairs, jump over the black railings to the ground. You lose ~30% doing this. When your health is below 50%...
    Telnet: value 62

    Use a painkiller, or two, to get back over 50%.
    Telnet: value 63

    You should now get a list of values. If there's too much junk, lose more health and try value 62 again. The first four values on my machine were 4ed8abh, ab11b7h, ac2a67h, & ac2a6fh. The others were in the 83xxxxxxh range. Let's take a look at the first:
    Telnet: db 4ed8a0 10
    004ed8a0: 00 00 00 00 00 00 00 00 21 35 14 3f 00 00 00 00

    Remember that the float is expected to start at 4ed7a8h (since we were searching for the last byte), and indeed it does! Type that into Hex Workshop to find out the float. It's 0.5789... which tallies with what I expected to see (my health looks around 60% right now).
    Telnet: poke 4ed8ab 3e

    No change. Not the source location. Now you have a choice:
    You can go through all the other variables, one by one, and hope to get lucky, or
    You can go straight to disassembly to find the source location.
    See later...
    Usually option one is fastest. However, there were 18 other possible locations when I tried it, so I'm going to go straight onto the assembly, option 2. 4ed8abh is definitely a copy of the health. It changes when your health changes (try it!). So let's set a breakpoint at the location, and see when it is written to.
    Why were there so many locations found? Well, some seem to relate to previous searches. Also, in a game like Max Payne, you'll note that when you take a hit, your health doesn't instantly change. There's a sort of half-health "bleeding" level, which converges with the true level over the course of a couple of seconds.Telnet: bpmb 0 4ed8ab w

    Immediately I get BP 0 @ aac93.
    Looking at the variables,
    ECX = 4217951fh (which would appear as 1f 95 17 42 in memory)
    EDX = 42340000h
    Both look like promising floats. Typing them into Hex Workshop, ECX = 37.9 (a percentage?), and EDX = 45 (exactly). Neither look like my health, although the first is almost the damage amount.
    Let's look at some of the disassembly occurring immediately before the breakpoint fired.
    .text:000AAC7F fld ds:flt_3B87B4
    .text:000AAC85 fsub [esp+28h+arg_0]
    .text:000AAC89 fst [esp+28h+var_4]
    .text:000AAC8D fstp flt_4ED8A8

    What's FLD doing? A hard-coded float is being pushed onto the floating point stack (i.e. loaded into floating point memory).
    Watch out for hard-coded floats. They're usually very important.Telnet: db 3b87b0 10
    003b87b0: 65 73 00 00 00 00 80 3f 00 00 00 00 a0 04 3e 00
    You should recognize this as 1.0f. If you don't, type it into Hex Workshop and confirm.
    Next, FSUB is called; what it's doing is subtracting the parameter from the number at the top of the floating point stack.
    What the heck is [esp+28h+arg_0]? What's ESP? It's a parameter for the subroutine, and I've no idea what its value is. But why would you subtract something from 1.0f?
    Well, if health is 0.6f, then damage is 1.0f - 0.6f = 0.4f.
    And if damage is 0.4f, health is 1.0f – 0.4f = 0.6f.
    So [esp+28h+arg_0] is one or the other.
    Next, FST means that the value on the stack is to be copied to the destination parameter, i.e. to [esp+28h+var_4]. It's irrelevant to what's going on.
    Finally, FSTP copies the value to the four bytes beginning at 4ed8a8h (which is what triggers the breakpoint at 4ed8abh), and then pops the number from the top of the floating point stack. The pop balances out the push from the FLD.
    Now, we know that 4ed8a8h stores a copy of the health. This means that [esp+28h+arg_0] stored the damage. Let's look at other occurrences of [esp+28h+arg_0] in this subroutine, going up, ignoring the Call commands. First is
    .text:000AAC2B fmul [esp+28h+arg_0]
    FMUL is multiplying the float with whatever's at the top of the floating point stack. Why? Well, for example, to work out how many pixels are to be drawn as red (damaged) on the health meter. Let's carry on up. We're actually only interested if [esp+28h+arg_0] is changed anywhere.
    .text:000AAC10 jz short loc_AAC20
    .text:000AAC12 fld ds:flt_3B87B4
    .text:000AAC18 fsub [esp+28h+arg_0]
    .text:000AAC1C fstp [esp+28h+arg_0]

    This bit's interesting. There's a test going on. If the condition (whatever it is) isn't met, then FLD, FSUB, and FSTP are called. FLD loads 1.0f. FSUB turns the variable around, and FSTP stores that change. Why would you do this?
    Telnet: bpx 0 aac12
    Telnet: uf

    I'm testing to see if that code is ever run. I immediately get a freeze, so it is. Which means that before this point, [esp+28h+arg_0] stores the health, not the damage. Let's look further up.
    .text:000AABEF fld [esp+28h+arg_0]
    .text:000AABF3 fcomp ds:flt_3B87B4
    .text:000AABF9 fnstsw ax
    .text:000AABFB test ah, 41h
    .text:000AABFE jnz short loc_AAC08
    .text:000AAC00 mov [esp+28h+arg_0], 3F800000h

    It's loading the variable, then comparing it with 3b87b4h (=1.0f). This looks suspiciously like one of those bounds tests! It doesn't matter. You can place a breakpoint at aac00h, but I guarantee it won't be hit immediately. If you NOP'ed out the JNZ (jump if not zero) command, you would see your display show full health! But since we're not dealing with the source location, the display would be inaccurate!!! Let's keep on looking.
    .text:000AABCC fst dword ptr [esi+1A4h]
    .text:000AABD2 mov al, [esi+1ACh]
    .text:000AABD8 fstp [esp+28h+arg_0]
    .text:000AABDC test al, al
    .text:000AABDE jz short loc_AABEF
    .text:000AABE0 mov ecx, edi
    .text:000AABE2 call sub_4CB90
    .text:000AABE7 fadd [esp+28h+arg_0]
    .text:000AABEB fstp [esp+28h+arg_0]

    This is something with the same sort of structure. A float is being copied to [esi+1A4h], then later pushed into [esp+28h+arg_0], then tested. The important question to ask here is: what's the float??
    Telnet: bpx 0 aabd2
    Telnet: uf

    This tells me ESI=ab1010h. So I look at ab1010h + 1a4h = ab11b4h...
    Telnet: db ab11b0 10
    00ab11b0: b0 76 ae 00 21 35 14 3f 00 00 00 80 3f 01 00 00 00

    The float in bold is our health value. Actually, ab11b7h was one of the results earlier on, so I'd expect to see that at ab11b4h. Is it a source location? Poke it and find out. It isn't. But it's further up the chain than what we were looking for, so we change our search to ab11b4h.
    We'd have saved a lot of time if we'd set multiple breakpoints on the first few locations found from our value search, and seen which one was hit first! This is Option 3 that I left blank earlier. I wanted to make the point that if you rush into things, it may take a lot longer to train a game - although the ASM experience may be good for you! You can currently set up to four breakpoints at a time in EvoX. Remember to freeze the game before you input multiple breakpoints. Telnet: bpmb 0 ab11b4 w
    Telnet: uf

    Gives a breakpoint at aabd2.
    .text:000AABAF mov ecx, [esi+108h]
    .text:000AABB5 call sub_B8280
    .text:000AABBA mov ecx, [esi+104h]
    .text:000AABC0 call sub_B8280
    .text:000AABC5 mov ecx, edi
    .text:000AABC7 call sub_4CB80
    .text:000AABCC fst dword ptr [esi+1A4h]

    Right, lots of bizarre calls, and finally, the float in memory is stored at [esi+1a4h]. What's going on? It's not obvious, is it? Don't get freaked out just yet!
    The first thing to look for is a preceding FLD. That may be contained in one of the Calls, but don't go looking in those yet. The reason we're looking for FLD particularly is from this code, which follows on from the last section.
    .text:000AABD2 mov al, [esi+1ACh]
    .text:000AABD8 fstp [esp+28h+arg_0]

    Checks and balances: where there's a pop (FSTP), look for a prior push (FLD)!(You could also look for FILD, which pushes an integer onto the floating point stack, but it's unlikely here)
    The FLD occurs at aaaa7h, but there's a problem...
    .text:000AAAA7 fld ds:flt_3B87B4
    .text:000AAAAD fsub [esp+28h+arg_0]
    .text:000AAAB1 fstp flt_4ED8B0

    It's cancelled out by FSTP. Looking further up...
    .text:000AAA44 call sub_4C920
    .text:000AAA49 fstp [esp+28h+arg_0]
    .text:000AAA4D mov ecx, [esi+110h]
    .text:000AAA53 call sub_B82C0
    .text:000AAA58 fmul [esp+28h+arg_0]
    .text:000AAA5C mov ecx, [esi+110h]
    .text:000AAA62 fstp [esp+28h+var_14]
    .text:000AAA66 call sub_B82B0
    .text:000AAA6B mov ecx, [esi+110h]
    .text:000AAA71 fstp [esp+28h+var_10]

    Lots of pops, no pushes. It's highly likely we need to look into a subroutine. So which one? Looking again at the code from aabafh, there are two calls to sub_B8280, but only one pop later, and the proximity of the call command makes me want to look there first.
    .text:0004CB80 mov ecx, [ecx]
    .text:0004CB82 jmp sub_15AC80

    No FLD here, but the code jumps to sub_15AC80...
    .text:0015AC8A call sub_25C420
    .text:0015AC8F fstp [esp+8+var_4]

    Note the FSTP. A pop. It tells me that something must be being pushed in the preceding call (the only available call). Let's take a look at that call...
    .text:0025C420 fld dword ptr [ecx+85h]
    .text:0025C426 retn

    All it does is load a float (which again will be cancelled out by the FSTP at 15ac8fh). However...
    Whenever you see a float loaded, it makes sense to check what it is!Telnet: bpx 0 25c426
    Telnet: uf

    ECX = 23ec36ah, so the float is at 23ec3efh
    Telnet: db 23ec3e0 20
    023ec3e0: 00 00 01 01 00 07 00 00 00 07 00 00 00 00 00 c6
    023ec3f0: bb 26 42 00 00 00 80 3f 00 00 a0 41 00 00 b4 42

    The float is 41.68 in decimal (suspicious - it could be the damage sustained in a float range of 0.0f to 100.0f). Let's poke it.
    Telnet: poke 23ec3f2 41

    Something strange just happened. I sustained more damage, not less, according to my health bar. Which means that the float, in some way, represents the health, but in a range more like 0.0f to 70.0f! It's unlikely to represent the source location of the health, with a crazy range like that. But it's still one rung up the ladder.
    Telnet: bpmb 0 23ec3f2 w
    Telnet: uf

    The breakpoint is not being hit immediately! That means that 23ec3efh is a source location, but not for what we're looking for. What's going on? Well, the data here could be just the height of the health bar that's white – updated only when health changes. Jump off the railings again, to sustain more health damage. This time the breakpoint stops execution. This is a real step forward – breaking on value change, rather than at every cycle.
    BP 0 @ 1879ea

    Let's look at the relevant subroutine.
    .text:001879E0 mov eax, [esp+arg_0]
    .text:001879E4 mov [ecx+85h], eax
    .text:001879EA retn 4

    There's no way of knowing what ESP is. So we need to trace back to find the calling subroutine.
    Highlight sub_1879E0 in IDA and press X to see the calling locations. There are four of them: sub_15ae30+5D, sub_1752D0+109, sub_175D50+276, and sub_1778f0+da2.
    At this point if you're low on health and out of painkillers, reload your quick-saved game, or grab some of the painkillers from the secret room.
    Telnet: bpc 0
    Telnet: uf
    Telnet: bpx 0 15ae8d
    Telnet: bpx 1 1753d9
    Telnet: bpx 2 175fc6
    Telnet: bpx 3 179792

    Now have Max jump off the railings again and lose more health. BP2 fires.
    Telnet: bpc 0
    Telnet: bpc 1
    Telnet: bpc 3
    Telnet: uf

    Note that BP 2 fires again. Get around this by temporarily disabling BP 2.
    Telnet: bpd 2
    Telnet: uf
    Telnet: bpe 2

    Now take a painkiller. BP 2 fires again. This is not what we want! We only want the Breakpoint to fire when health is being subtracted. We need more granularity! Find the places which call this subroutine (sub_175d50). Again, there are four of them, at 176014h, 1760d1h, 17619dh, and 1763e6h. As before, place execution breakpoints on all of them. You will find that the last one, 1763e6h, is the one which fires, and only when health is lost!
    Telnet: bpc 2

    .text:001763DC fsub [esp+50h+arg_0]
    .text:001763E0 push ecx
    .text:001763E1 mov ecx, esi
    .text:001763E3 fstp [esp+54h+var_54]
    .text:001763E6 call sub_175D50

    A float is being subtracted, and then its value copied. What could it be? We can't be certain, but an FSUB is a safe command to NOP, so let's try it, and see what happens.
    Telnet: fr (as necessary)
    Telnet: poke 1763dc 90
    Telnet: poke 1763dd 90
    Telnet: poke 1763de 90
    Telnet: poke 1763df 90

    Jump off the railings. The screen flashes red, but you haven't lost any health! You've found God Mode!
    ...Or Have You?
    Go to the enemy dispenser, and press it (or open the van doors for the sniper rifle if you haven't got it already). Don't fire on the goons yet. See if you take any damage from being shot. You don't. That's good. Now open fire - see if you can kill a goon. You can't. Congratulations, you've just given God Mode to everyone!!
    Did I mention that Max Payne is a PITA to crack?
    What's going on is that Max is being treated the same way as a goon. When a goon takes a hit, the same code is used to deduct damage.
    So what can we do? Well, we need more granularity again. We need to find the subroutines that call sub_1761b0 (which contains the call at 1763e6h), and find the one which is called when Max is hit, but not when a goon is hit.
    Reset your XBOX. Reload Max Payne, and your quick-save from earlier on. Place execution breakpoints at the point where sub_1761b0 is called. There are three of them. You will soon discover that:
    176554h calls sub_1761b0 when (unknown)
    17717bh calls sub_1761b0 when falling down
    1764e4h calls sub_1761b0 when taking fire or enemy takes fire

    This is interesting. We've been looking for God Mode, but here's an opportunity to add an extra trainer option – painless falls. I'll leave that to you as an exercise. Remember that trainer cheats can be too powerful, and some gamers just want a little more convenience, rather than the full-blown God Mode.
    More granularity is still needed to differentiate Max from the goons.
    sub_176410 contains the call to sub_1761b0 when a character is shot. Remember to write something like
    bpx 0 176410

    and then test if it fires when Max is hit, and when a goon is hit. This can be tricky to test accurately. The best thing to do is kill two of the three goons that appear (leave the one with the rifle because he's slow to reload). Quick-save, and reload as necessary.
    You will unfortunately find that the trail stops dead at 1ad73eh. IDA doesn't seem to be able to trace a parent subroutine.
    Max Payne is a PITA to crack!
    So what did I do then? Well, I had a think to myself, and then I remembered that when Max is hit, the screen flashes red. When a goon is hit, it doesn't. So there's a chance that there's a jump statement somewhere which differentiates between Max and a goon. And it probably happens in sub_1761b0, since the falling down code also needs the red-flash code.
    So take a look at sub_1761b0. It's a long sub, with quite a few jumps. One jump in particular skips a lot of code. Directly after the jump the code looks like:
    .text:001763CA mov ecx, [esp+48h+arg_4]
    .text:001763CE push 0
    .text:001763D0 push ecx
    .text:001763D1 lea ecx, [esi+24Ah]
    .text:001763D7 call sub_25C420
    .text:001763DC fsub [esp+50h+arg_0]
    .text:001763E0 push ecx
    .text:001763E1 mov ecx, esi
    .text:001763E3 fstp [esp+54h+var_54]
    .text:001763E6 call sub_175D50

    Remember that this is the section where we tried to NOP the FSUB and made everyone invulnerable. Scroll up the screen, and find where the code first jumps to 1763cah.
    .text:001761DC jnz loc_1763CA
    .text:001761E2 lea ecx, [esi+24Ah]
    .text:001761E8 call sub_25C420

    Telnet: bpx 0 1761e2
    Telnet: uf

    Take good aim at the goon, making absolutely sure he's not firing at you, and fire at him. The code doesn't break. Get hit. The code breaks. It's here. All the code between 1761e2h and 1763cah must relate to Max, i.e. it's that Red Flash code. Surely here's a pretty good place to put a God Mode crack? Who needs a red flash when you're invulnerable?!
    Options within the loop:
    Change the value [esp+50h+arg_0] (which is the shot damage) to 0.0f.
    Give Max extra health to offset the health that will be lost by FSUB later.
    Do nothing. Tell the code to jump past the FSUB at the end.
    Now, for Option 1, I've no idea what the code is to change [esp+50h+arg_0]. So that idea's out the window.
    Similarly, Option 2 would require me to load the old health, FADD the damage, and paste the result back into the old health.
    Option 3 seems like the least effort. The plan is therefore to reproduce everything between 1763cah and 1763dbh within the Red Flash section, and then jump ahead to 1763e0h, past the FSUB. That way the FSUB is still called for goons, but not for Max.
    Note that sub_25C420 (which is a simple FLD requiring ECX), is already called with the correct ECX. What we need therefore is
    .text:001761DC jnz loc_1763CA
    .text:001761E2 lea ecx, [esi+24Ah]
    .text:001761E8 call sub_25C420 (no change on the above)

    .text:001761ED mov ecx, [esp+48h+arg_4] 8b 4c 24 50
    push 0 6a 00
    push ecx 51
    lea ecx, [esi+24Ah] 8d 8e 4a 02 00 00
    jmp loc_1763E0 e9 .. .. .. ..

    I have put above the hex code for each new command. By the way, if you don't know the hex equivalent for something, do a text search for the full command in IDA – very likely it's already being used somewhere else.
    Now the JMP is the only tricky one. Because you need to count the offset differences, which depends where JMP ends. List the poke addresses; they should look like this:
    1761ed 8b
    1761ee 4c
    1761ef 24
    1761f0 50
    1761f1 6a
    1761f2 00
    1761f3 51
    1761f4 8d
    1761f5 8e
    1761f6 4a
    1761f7 02
    1761f8 00
    1761f9 00
    1761fa e9
    1761fb ??
    1761fc ??
    1761fd ??
    1761fe ??

    The JMP value is 1763e0h - 1761ffh = 1e1h. So the final four are
    1761fb e1
    1761fc 01
    1761fd 00
    1761fe 00

    If you Telnet all that in, you will finally have a workable* God Mode. And if you managed to read through and follow all that,
    WELL DONE!
    (*Max can still be killed by special events, like large exploding canisters and speeding trains)
    :)
    Appendix
    Useful links
    MaxConsole EvolutionX Trainer Forum
    Use Google to find ASM (and other) info (Google Groups is especially useful).
    Here are two decent ASM tutorials I found with Google:
    ASM tutorial at http://www.xs4all.nl/~smit/asm01001.htm
    Floating point ASM tutorial at http://programmers-corner.com/viewTutorial.php/31
    Acknowledgments
    I'd like to thank the EvoX team, and all the trainer makers, tutorial writers, testers, forum mods and posters, and everyone else not in the above categories, he-he! Some of us cranky old gamers need a little help now and again, and game makers need to remember that we have limited time on our hands. :)
     
  15. vgaddict8

    vgaddict8 Guest

    Jesus Christ Bubba1982-you got some scary stuff there.

    So where are the trainers at maxconsole.net?
     
  16. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
  17. vgaddict8

    vgaddict8 Guest

    Yeah, I use these two a lot. I also found a few in #xbins channel in efnet for mirc, but is that it?
     
  18. Bubba1982

    Bubba1982 Regular member

    Joined:
    Jun 11, 2013
    Messages:
    486
    Likes Received:
    2
    Trophy Points:
    28
    #xbins is crap for trainers because it only has ntsc stuff and I am a pal user :) and thats why I posted the guides. so that hopefully we can get a few more pal users to create trainers
     
  19. vgaddict8

    vgaddict8 Guest

    That guide looks pretty intimidating. Pretty complicated stuff.
     
  20. achaean

    achaean Member

    Joined:
    Oct 26, 2005
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    11
    Xbox trainers at maxconsole are in the xbox section in The Other Side - Xbox training community forum:http://forums.maxconsole.net/forumdisplay.php?f=44

    This is where the Xored team post all their trainers as well as dootdoo/Evox-T
    You will also find Mikerowesoft's (Xored team member/moderator) trainer pack.
    Just browse the pages to find the latest NTSC/PAL trainers.
     

Share This Page