ok, this has been frustrating me for weeks. How does a hacker know what values/commands to put in a standard asm code when i clearly don't even see those commands/values anywhere in wiird's memory? ???
Anyway i'm going to give out a code that has been hacked from another hacker and show what the disassembler looks like. The breakpoint code i am breakpointing is moon jump at 8110EA50 [spoiler] set breakpoint: 8110EA50 - Write
CR : 88000088 XER : 00000000 CTR : 801FFCC0 DSIS: 02400000
DAR : 8110EA50 SRR0: 80395074 SRR1: 0000B032 LR : 8039502C
r0 : 00000000 r1 : 805D5C18 r2 : 805C8D20 r3 : 00000000
r4 : 0000002A r5 : 00000025 r6 : 80E06B48 r7 : 80E05C0C
r8 : 80E05C00 r9 : 00000000 r10 : 80E06BAC r11 : 805D5B48
r12 : 801FFCC0 r13 : 805C4140 r14 : 00000002 r15 : 00000001
r16 : 8055108C r17 : 00000210 r18 : 000004B0 r19 : 00000003
r20 : 8110BE40 r21 : 810FB620 r22 : 810FCEC0 r23 : 80490000
r24 : 80574A18 r25 : 00000004 r26 : 8110EA00 r27 : 8110BE40
r28 : 00000000 r29 : 00000000 r30 : 00000000 r31 : 00000001
f0 : 00000000 f1 : 403ECD1D f2 : BF4D4CB7 f3 : BCBF5688
f4 : 40400000 f5 : 40400000 f6 : C3180002 f7 : 00000000
f8 : 00000000 f9 : 00000000 f10 : 00000000 f11 : 00000000
f12 : 3CA3EACC f13 : 00000000 f14 : 41200000 f15 : 3F800000
f16 : 3D08AB86 f17 : 3D88AB86 f18 : 00000000 f19 : 3E800000
f20 : 42C80000 f21 : 00000000 f22 : 00000000 f23 : 00000000
f24 : 3F800000 f25 : 00000000 f26 : BF860A92 f27 : 00000000
f28 : 00000000 f29 : 00000000 f30 : 40400000 f31 : 3CBF5688
break list
80395074: D03A0050 stfs f1,80(r26)
80395078: 40810008 ble- 0x80395080
8039507C: 48000008 b 0x80395084
80395080: FC600090 fmr f3,f0
80395084: D07A0220 stfs f3,544(r26)
80395088: C002D690 lfs f0,-10608(r2)
8039508C: C0C1002C lfs f6,44(r1)
80395090: EC400032 fmuls f2,f0,f0
80395094: C022D7F0 lfs f1,-10256(r2)
80395098: EC0601B2 fmuls f0,f6,f6
8039509C: ECE2002A fadds f7,f2,f0
803950A0: FC070840 fcmpo cr0,f7,f1
803950A4: 40810008 ble- 0x803950ac
803950A8: FC203890 fmr f1,f7
803950AC: FC400834 fsqrte f2,f1
803950B0: C0A2D6EC lfs f5,-10516(r2)
attempting to break 80395074 (execute)
list
CR : 88000088 XER : 00000000 CTR : 801FFCC0 DSIS: 02400000
DAR : 8110EA50 SRR0: 80395074 SRR1: 0000B032 LR : 8039502C
r0 : 00000000 r1 : 805D5C18 r2 : 805C8D20 r3 : 00000000
r4 : 0000002D r5 : 0000002B r6 : 80E06D3C r7 : 80E05C0C
r8 : 80E05C00 r9 : 00000002 r10 : 80E06DA0 r11 : 805D5B48
r12 : 801FFCC0 r13 : 805C4140 r14 : 00000002 r15 : 00000001
r16 : 80551080 r17 : 00000000 r18 : 00000000 r19 : 00000000
r20 : 810FFE40 r21 : 810FB410 r22 : 810FCA10 r23 : 80490000
r24 : 80574A18 r25 : 00000004 r26 : 81102C00 r27 : 810FFE40
r28 : 00000000 r29 : 00000000 r30 : 00000002 r31 : 00000001
f0 : 00000000 f1 : 403ECD1D f2 : BF4D4CB7 f3 : BCBF5688
f4 : 40400000 f5 : 40400000 f6 : C3200003 f7 : 00000000
f8 : 00000000 f9 : 00000000 f10 : 00000000 f11 : 00000000
f12 : 3DD595D1 f13 : 00000000 f14 : 41200000 f15 : 3F800000
f16 : 3D08AB86 f17 : 3D88AB86 f18 : 00000000 f19 : 3E800000
f20 : 42C80000 f21 : 00000000 f22 : 00000000 f23 : 00000000
f24 : 3F800000 f25 : 00000000 f26 : BF860A92 f27 : 3F296A10
f28 : 41D3C494 f29 : 00000000 f30 : 40400000 f31 : 3CBF5688
80395074: D03A0050 stfs f1,80(r26)
80395078: 40810008 ble- 0x80395080
8039507C: 48000008 b 0x80395084
80395080: FC600090 fmr f3,f0
80395084: D07A0220 stfs f3,544(r26)
80395088: C002D690 lfs f0,-10608(r2)
8039508C: C0C1002C lfs f6,44(r1)
80395090: EC400032 fmuls f2,f0,f0
80395094: C022D7F0 lfs f1,-10256(r2)
80395098: EC0601B2 fmuls f0,f6,f6
8039509C: ECE2002A fadds f7,f2,f0
803950A0: FC070840 fcmpo cr0,f7,f1
803950A4: 40810008 ble- 0x803950ac
803950A8: FC203890 fmr f1,f7
803950AC: FC400834 fsqrte f2,f1
803950B0: C0A2D6EC lfs f5,-10516(r2)
[/spoiler] 284B732A FBFF0400
C2395074 00000004
2C130003 4182000C
D03A0050 4800000C
3D804170 919A0050
60000000 00000000
E0000000 80008000
284B732A 00000000
04395074 D03A0050
E0000000 80008000 cmpwi r19,3
beq- 0x0C
stfs f1,80(r26)
b 0x0C
lis r12,16752
stw r12,80(r26)
nop
I can provide additional information before the breakpoint if necessary. I just don't understand where these values/commands come from. ??? ??? ???
What are you talking about?
C2395074 00000004
2C130003 4182000C
D03A0050 4800000C
3D804170 919A0050
60000000 00000000
=
1)04395074 4BC6E18C : b 0x80003200 : (Empty memory address)
2) 04003200 2C130003 : cmpwi r19,3
3) 04003204 4182000C : beq- 0x80003210
4) 04003208 D03A0050 : stfs f1,80(r26)
5) 0400320C 4800000C : b 0x80003218
6) 04003210 3D804170 : lis r12,16752
7) 04003214 919A0050 : stw r12,80(r26)
8)04003218 48391E60 : b 0x80395078 (= 80395074 + 00000004)
-The C2 code can shorten this long instruction like the above-mentioned.
2) - 7) = Instruction group that hacker voluntarily added.
Why would they have to be somewhere else in memory?
A CPU executes Machine Code. This is the 1s and 0s. Humans aren't very good at reading Machine Code. For instance, the instruction 3D804170 looks very confusing to us.
That is why we use assembly. There is a one-to-one conversion from Machine Code to ASM. In this case, 3D804170 = lis r12,16752. Sometimes you can read a little bit, though. For instance, the last 16 bits of this instruction are an Immediate; specifically, the value 16752. Well, I can tell you that 16752 = 0x4170. Look at the machine code - 3D804170.
When writing an ASM code, we start with a goal in mind, and then write some instructions that accomplish that goal. The keys to this code are r19 (some conditional value) and 80(r26) (some location in memory that holds an interesting value). We want to write either f1 (the "original" value) or 41700000 (the hacked value) to 80(r26), depending on r19.
Here's the code with some comments
2) 04003200 2C130003 : cmpwi r19,3 # is there a 3 in r19?
3) 04003204 4182000C : beq- 0x80003210 # if so, skip this section
4) 04003208 D03A0050 : stfs f1,80(r26) # store f1 to 80(r26)
5) 0400320C 4800000C : b 0x80003218 # skip to the finish
6) 04003210 3D804170 : lis r12,16752 # put 41700000 into r12
7) 04003214 919A0050 : stw r12,80(r26) # store r12 to 80(r26)
So, in the event that r19 has a 3 in it, the code will put 41700000 at the address 80(r26). The blue instructions will be executed.
2) 04003200 2C130003 : cmpwi r19,3 # is there a 3 in r19?
3) 04003204 4182000C : beq- 0x80003210 # if so, skip this section
4) 04003208 D03A0050 : stfs f1,80(r26) # store f1 to 80(r26)
5) 0400320C 4800000C : b 0x80003218 # skip to the finish
6) 04003210 3D804170 : lis r12,16752 # put 41700000 into r12
7) 04003214 919A0050 : stw r12,80(r26) # store r12 to 80(r26)
If there is no 3 in r19, the code will put f1 into 80(r26).
2) 04003200 2C130003 : cmpwi r19,3 # is there a 3 in r19?
3) 04003204 4182000C : beq- 0x80003210 # if so, skip this section
4) 04003208 D03A0050 : stfs f1,80(r26) # store f1 to 80(r26)
5) 0400320C 4800000C : b 0x80003218 # skip to the finish
6) 04003210 3D804170 : lis r12,16752 # put 41700000 into r12
7) 04003214 919A0050 : stw r12,80(r26) # store r12 to 80(r26)
Thank you for the explanation ;D :p
Quote from: Sharkbyte on May 28, 2010, 04:01:49 PM
How does an individual decide what to add volutarily when and/where? ???
what to add: stare at the ASM for a while in the disassembler. Get a feel for what values are in what registers. Write notes.
It also helps to familiarize yourself with the various ASM instructions the PowerPC can use. http://pds.twi.tudelft.nl/vakken/in1200/labcourse/instruction-set/
when/where to add: C2 codes "hook" ASM. You need to find somewhere in the ASM that has the interesting values during the breakpoint. We don't know what's in r26 and it could very well change. However, at the instruction 80395074, r26 has the pointer that we're interested in, r19 has the value we're interested in, etc.
The code handler will take care of writing the branches that make the game jump to your hook and back.
There are 32 registers, r0-r31. Some of them are always forbidden (r1 and r2, specifically). Never, ever, ever use those registers. Okay, well, sometimes you can use r1, but there are very special rules that you have to follow very carefully or it will crash...don't use r1 unless you understand the stack conventions that you must follow.
Where did r12 come from? The author of the code chose r12, probably because it's a "safe register". You must carefully evaluate the ASM to see what registers it is using. This is the tricky part about doing ASM codes. You don't really know for sure what registers are safe. If r12 had some important pointer in it, and we write over that pointer, it is game over.
How do you know what is safe? Some people choose any register that has a 0 in it, but that method frightens me because some registers are actually holding a 0.
If something is loading r12 with a value (e.g. "li r12, 0", "addi r12, r3, 1", etc), then it doesn't matter what's in r12 at that point, because it will be over-written. Any time a register is explicitly written to, that register is safe for all the instructions at the address BEFORE the register is written to, but AFTER the last time it is read from.
If there are no safe registers, you can make some room on the stack and push/pop a few registers to make them safe. But it is tricky. I wrote a little bit more about finding safe registers and identifying dependencies here.
http://wiird.l0nk.org/forum/index.php/topic,5407.msg46274.html#msg46274
I use r12 when there is no empty register.
As for it, r12 is not usually used excluding the jump of the function.
I learnt this from Y.S.
Couldn't you use any register other than r1 & r2 as long as your C2 code sets it back to it's original value when it's done using it?
Yes, this is done by pushing them on the stack at the start of your code and restoring them at the end of your code.
No i'm talking about doing it yourself with li or lis then ori
That would only work if the value in the register was a constant. Like if there was an li r0,3 before your C2 code, then you know nothing but 3 will ever be in r0.
However, if r0 was loaded from a pointer, the value could change. The only way to preserve it would be pushing/popping.
Not so if there was a register with an address close to a portion of unused memory you could store the register there then load it back in at the end of your C2 code
Well actually that's not surefire either because the register you'd be using as a pointer could change
Pushing/Poping from the stack is the same as storing it in unused memory, the stack is just a chunk in memory where values are stored temporary.
From the looks of that dissassembly register 13 is in use, and it stores a pointer so when you load another value in it the game tries to load something from that value (it thinks it is an address).
And you set the register to 0xC5000000 which is not a proper address, thats why the game crashes.
So in order to let this work, you have to use another free register or store the register on the stack (this is a little bit more complex).
But another way to achieve the same result is to go back in the dissassembly, look up some instructions because the game had to load that value first and probably added a value to it.
So if you find the instruction that add a value to it, insert the C2 code there and just edit the register which has the value which is added.
r13 is never safe. It's a special register, I think. r1 and r2 are never ever ever ever safe. ever
When in doubt, r12 is almost always a safe register. r0 is usually pretty safe, too, but there are some restrictions on using r0 with certain instructions.
Finding registers that hold 0 is not safe. Safe registers are those whose value will not be read until they have been written to by something else first; this way, any value that you put into the register won't ever be read by the game.
When providing a disassembly, everything after the blr is useless (i.e. everything after the end of the current function). It's also very important to include the disassembly *before* the breakpoint, so we know what has lead up to the current instruction. If you can, you should include everything up to the previous blr (i.e. the end of the previous function); this way we can see the whole function, which helps when identifying input arguments and such.
It looks like the function that you're hitting (execute BP at 8001F0E0) runs multiple times per frame. It might be adjusting *every* players' height (or even enemies!), instead of just player 1. Notice how the r3 pointer is different between the two breakpoints. You will probably have to follow the blr back to the caller and hook your C2 code somewhere there.
Here is the whole function.
8001F0D4: C0440000 lfs f2,0(r4)
8001F0D8: C0240004 lfs f1, 4 (r4)
8001F0DC: C0040008 lfs f0,8(r4)
8001F0E0: D0430000 stfs f2,0(r3)
8001F0E4: D0230004 stfs f1,4(r3)
8001F0E8: D0030008 stfs f0,8(r3)
8001F0EC: 4E800020 blr
This function loads three floats from r4 and copies them over to r3. It's definitely used by more than one caller. You will have to follow the blr back to the caller after doing your write breakpoint.
Yes, follow your first write breakpoint. This will help you find when 8001F0E0 is processing the chunk of memory you're interested in; it processes many chunks of memory.
To follow the blr back to the caller, just step. blr = Branch to Link Register.
You might want to read this tutorial, it describes this process in greater detail.
http://wiird.l0nk.org/forum/index.php/topic,5080
I don't think you set the right Write breakpoint. Look at the Link Register; that is telling us where our caller is.
In your original Write breakpoint, the LR was 8011C39C. In your subsequent Execute breakpoint the LR was 80168F50. This means there are *at least* two different callers. If you repeatedly did Execute breakpoints and looked at the LR, you could probably find all the various callers...and I bet there would be a lot of 'em.
It is *paramount* that you make sure you find the caller who is handling the character you're interested in. Lots of people call this function that lives between 8001F0D4 and 8001F0EC. We're only interested in one specific phone call.
bl is like calling someone, blr is like hanging up. Lots of other functions will bl 0x8001F0D4 but there's only one of those that we're interested in.