| QUOTE |
Here is tutorial #1 Please post any questions or comments in this thread.. 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! |
| QUOTE |
| Heres tutorial #2 Please post comments and questions in this thread. 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.. |