I can't find some variables, can you help me?

Started by Fighter19, November 30, 2013, 10:12:34 AM

Previous topic - Next topic

Fighter19

So clearing all the registers I used is not needed?
Means I can simply leave out all
lis rXX,0 ?

Bully@Wiiplaza

My Wii hacking site...
http://bullywiihacks.com/

My youtube account with a lot of hacking videos...
http://www.youtube.com/user/BullyWiiPlaza

~Bully

Fighter19

#17
Are you sure, because there are already values in those registers?
EDIT:I'll trim the code by removing some unnecessary ADDI instructions.

Bully@Wiiplaza

Yes, I told you.
There's a tutorial about the safety of registers if you're thirsty for details, lol.
My Wii hacking site...
http://bullywiihacks.com/

My youtube account with a lot of hacking videos...
http://www.youtube.com/user/BullyWiiPlaza

~Bully

dcx2

Quote from: Fighter19 on December 03, 2013, 07:45:43 PMHmm I'll probably try to take a look at F6 codes then, though I need to get my hands (the one or the other way) on another version of Wii Play.
So meanwhile using assembler would be a good option. Do I have to break the function which writes to it directly and insert an ASM (of course with Branching etc.)? Well this will take way more time... How to create an ASM code? I mean I can't simply create it using the debugger, is there some sort of mini-linker which parses for example nop -> 60 (I think it is this byte in PPC assembly) ?

I would wait until you have a better handle on C2 codes before trying an F6 code.  They are quite a unique beast.

You do not need a new copy of Wii Play to make an F6 code work.  You only need it to verify that your F6 code works for all versions/regions, but to get it working you only need one copy of the game.

You do not need to handle branching.  When the code handler processes a C2 code, it automatically handles the branches for you.  However, it is your C2 code's responsibility to ensure that the original instruction is executed (if necessary), since the code handler will overwrite the original instruction with a branch when it processes the C2 code.

Note that C2 codes run in the context of whatever function they hook.

In addition to ASMWiiRD, PyiiASMH can also assemble ASM codes.  It has a little bit more flexibility, in that it can also do raw codes (which I used once, for a multi-C2 code), but it requires Python.

While a nop is 60000000, that's actually just a mnemonic for ori r0,r0,0.  A bitwise OR with 0 always results in the original value, which is why this instruction is essentially a nop.

Quote from: Fighter19 on December 03, 2013, 08:54:57 PM
So I overwrite the function that writes to 8037A548 and let it write to a new memory location AND at the original, then use the new address in the other injected code (that overwrites writing to the position address)? Then I have to paste the original code in again, since we don't want to disable moving completely adding a cmp (probably another function in PPC) and check whether the button is "-" (put it simply, probably there it's needed to modify this and copy it to a free location as well) then the rest of the code gets executed (storing it in registers, multiplying, writing it back),  Well this sounds a little dirty but should work fine, shouldn't it?

EDIT2: There is no EASY way to dynamically allocate free space, is there?

I would hook the first function and instead of writing values, I would cache the pointer instead.  Then your other hook can read the cached pointer and write to the address if it wants to.

Yes, you would use a cmp to check whether - has been pressed.  You would use a cmpwi (CoMPare Word to Immediate) if you wanted to check whether ONLY - is held, and then beq- to your hack or bne- over your hack.  If you wanted to mask the - so that you could press it while holding other buttons, you would have to use andi. (AND with Immediate and the . means update the Condition Register flags) to mask off just the bit, and then bne- to your hack or beq- over your hack (note: this is the REVERSE of the cmp)

There is no "easy" way to dynamically allocate space.  One way (that I personally never use) is to use the 80001500 section.  But myself, I prefer to use the "bl trick".  You may need to create a stack frame if you need to preserve LR (the Link Register) before doing the bl trick, but you can use it to create small data areas for your codes.  The trick is that bl puts the address of the next instruction into LR, and then branches.  Set the branch destination to be after your data section, and when you get there, LR holds a pointer to your data.  mflr (Move From Link Register) to get the pointer.  But make sure that LR can be clobbered safely (if your function has mflr at the start and mtlr at the end, you should be safe).  Several of my codes use the bl trick, you can see them because I use .float or .long to initialize the data.

Quote from: Fighter19 on December 04, 2013, 07:13:34 PM
Man, I tried around replacing this function but somehow it freezes.

[spoiler]
stfs f3,4(r3) //Sets position
lis r27,0x8000 //HiByte
addi r27,r27,0x159C //LoByte for free memory
stfs f3,0(r27) //Store f3 (position) to address of r27
lis r22,0x8037 //HiByte
addi r22,r22,0x7FFF //
addi r22,r22,0x2641 //Add together to achieve 8037A640
lhz r23,0(r22) //Load value from 8037A640 (Pressed button) (address of r22) to r23
cmpi 3,0,r23,0x1000  //Is r23 = 0x1000 (So is the "-" Button pressed), using CR3
beq 3,SET //If value in CR3 return true, jump to SET
lis r27,0
lis r23,0
lis r22,0 //If not clean everything up
b END //Jump to a location after SET so it doesn't get executed


SET:
addi r27,r27,0x0020  //Increment by 0x0020
stw r23,0(r27)       //Store the value from r23 (In this case it HAS to be 0x1000) to address of r27
lis r27,0       
lis r23,0
lis r22,0        //clean everything up


END:
nop

(now using the disassembler you can see it now returns to the normal function)
[/spoiler]
In ASMWIIRD ; doesn't work as comment anyway...

Tip: Use the spoiler tag instead of the code tag.  Bigger text and it can be collapsed so that it doesn't interfere with the flow of the thread.

Line comments use # instead of ; or //.

There are many things that need fixed with this code.  You should really re-read the "On the Safety of Registers" link I provided earlier.  I know the CPU architecture link might have been below you, given your knowledge of x86 assembly, but I truly encourage you to read the whole Safety of Registers thread in its entirety.  You need to write your ASM codes while following the PowerPC Application Binary Interface.  You seem to think that register safety depends on the contents of the register, in other words, a register with the value 0 is safe to use, but this is a big no-no.  Register safety is related to the dependency chain of the register in the flow of instructions.  r12 will almost always have non-zero values in it, but that's okay, because the vast majority of instructions never depend on the contents of r12.  For those instructions that do, r12 is loaded right before it is used, so it will be obvious when you should not clobber the value.  In contrast, a register could contain 0, but during some other execution (for example, a different caller), that register might not contain 0, or perhaps the code depends on 0 being in that register.  Remember, 0 does not mean safe.

Your code probably crashed because you clobbered the non-volatile registers r22, r23, and r27 without saving their value.

You should avoid addi when loading addresses.  I think you noticed why.  You had to split the creation of 8037A640 into three instructions.  The reason is because addi's 16-bit Immediate value is signed!  So when you went to add 0xA640 to 80370000, you were actually subtracting 0x59C0, so you got 8036A640.  As Bully said, use ori instead of addi, because ori uses an unsigned Immediate.

You also should NOT use CR3 for your cmp!  That could also cause your code to crash, because CR2-4 are non-volatile, and their contents must be backed up if you intend to use them.  Don't specify a CR, just use the implicit CR0, it's volatile and you're allowed to clobber it.  Note that float compares will use CR1 implicitly, but it's still volatile, so you're allowed to clobber it.

You don't need a nop at the end.  The assemblers will add the nop if it is needed.

You use a lot of addi's when you could just use the displacement operand.  Instead of

addi r27,r27,0x0020  //Increment by 0x0020
stw r23,0(r27)       //Store the value from r23 (In this case it HAS to be 0x1000) to address of r27

Just do

stw r23,32(r27)   # [r27 + 32] = r23

If you would like to see some of the source assembly that I've used to write my codes, here are several examples.  Some are very complex, but well commented.  However, I very much flaunt my expertise with PPC ASM, so some may be very confusing, especially the SMG2 Televitation code, which is so highly optimized I even have trouble following it.

http://wiird.l0nk.org/forum/index.php/topic,8138.0.html

http://wiird.l0nk.org/forum/index.php/topic,8497.msg70986.html#msg70986

http://wiird.l0nk.org/forum/index.php/topic,8455.msg71990.html#msg71990

http://wiird.l0nk.org/forum/index.php/topic,8757.msg73781.html#msg73781

http://wiird.l0nk.org/forum/index.php/topic,8742.msg72940.html#msg72940

http://wiird.l0nk.org/forum/index.php/topic,8591.msg71402.html#msg71402

http://wiird.l0nk.org/forum/index.php/topic,6517.0.html

http://wiird.l0nk.org/forum/index.php/topic,9557.msg80797.html#msg80797 (this one is Bully, but it covers the u-suffixed instructions nicely in the thread)

Fighter19

#20
I've already finished doing the most. So here's a cleanup:
[spoiler]stfs f0,12(r3)
mflr 10
lis r12,0x8024
addi r12,r12,0x43FC
cmp 0,0,r10,r12
bne 0,END
lis r10,0x8000
addi r10,r10,0x159C
lis r12,0x8037
ori r12,r12,0xA640
lhz r11,0(r12)
cmpi 0,0,r11,0x1000
beq 0,SET
li r12,0x0000
stw r12,0x20(r10)
b END


SET:
lwz r12,0(r10)
stw r12,4(r3)
lwz r12,4(r10)
stw r12,0xC(r3)
sth r11,0x20(r10)



END:
[/spoiler]

or in Code form with everything else included:
[spoiler]
C22423A4 0000000B
D003000C 7D4802A6
3D808024 398C43FC
7C0A6000 40820040
3D408000 394A159C
3D808037 618CA640
A16C0000 2C0B1000
41820010 39800000
918A0020 48000018
818A0000 91830004
818A0004 9183000C
B16A0020 00000000
C20A4280 00000004
D05E0020 3F608000
3B7B15AC D05B0000
3B7B0004 D01B0000
3F600000 00000000
280015BC EFFF1000
82200001 800015AC
86A00001 43E6A000
84200001 8000159C
82200001 800015B0
86A00001 442FF000
84200001 800015A0
E0000000 80008000
[/spoiler]

Is this acceptable now, or is it still too dirty?
P.S.: Referring to register safety:I even thought about backing the registers up to restore them later, but since I'm new to assembler I forgot that there is a stack (whooops).

dcx2

#21
It's perfectly fine to mix-n-match Gecko codes and ASM codes.  The only thing to keep in mind is that the C2 code executes when the game calls it, and the Gecko codes execute when the code handler runs.

I've rewritten your example a bit.

[spoiler].set TEST_LR,0x802443FC
.set STORAGE0,0x8000159C
.set STORAGE4,STORAGE0+4
.set STORAGE32,STORAGE0+32
.set BTN_ADDR,0x8037A640
.set BTN_MINUS,0x1000


stfs f0,12(r3)
mflr 10
lis r12,TEST_LR@h
ori r12,r12,TEST_LR@l
cmpw r10,r12
bne- _END
lis r10,STORAGE0@ha
lis r12,BTN_ADDR@ha
lhz r11,BTN_ADDR@l(r12)
cmpwi r11,BTN_MINUS
beq- _SET
lis r12,0x0000
stw r12,STORAGE32@l(r10)
b _END


_SET:
lwz r12,STORAGE0@l(r10)
stw r12,4(r3)
lwz r12,STORAGE4@l(r10)
stw r12,0xC(r3)
sth r11,STORAGE32@l(r10)


_END:[/spoiler]

Some questions.  Why are you testing LR?  Have you verified that there are multiple callers to this piece of code, and that the other callers interfere?

You're still using addi for addresses.  You should kick that habit, it will bite you.

You're explicitly specifying registers for comps and branches.  Avoid doing so unless you need to.

You should use macros for holding addresses.  They're easier to read.

I tend to prefix my jump labels with an _ so that they stand out against the other macros.  This isn't required, it's just a convention I use personally.

While not necessary, I tend to add the branch hints to conditional branches.  I mimic the compiler; a - suffix for branches that go forward and a + suffix for branches that go backwards.

You cannot use li to clear a register,  li is a mnemonic for addi, which does not clear the upper 16-bits.  You should use lis to clear a register, because it will clear the bottom 16 bits.

You use both sth and stw to the same address.  Why?  You probably meant one or the other.

EDIT:

I haven't looked at the function, but the chances are r10 is also safe.  r11 and r12 are almost always safe and if they aren't you should be able to tell quickly from reading the ASM.  r10 down to r3 get gradually less safe.  The only way to know for sure is to analyze the hook, but you never pasted the output of Gecko.NET's disassembly tab's Copy Function on your hook address, so I can't tell you for sure.

Fighter19

#22
To LR, yeah I added the check of LR to make sure that it's getting called from only that function. I think the other caller sets the spawn position, I'm not sure though, maybe also just some other player, but it has the same value as if you start the level from beginning. And I have to say your version's really way more clean, good to see how it's solved accurately. Because I never saw really "handwritten" ASM code I only saw how it looks like in it's disassembled form and I have to say, I would probably have finished way faster if I knew this stuff. >.< But now that I have a comparison on how it should look like and how not, it will be probably easier next time.
Thank you guys.
EDIT:Hmm? I only see sth gets executed where the button is begin stored to it's address, and this only once, so I don't understand what you're referring to.
EDIT2: And also on
lis r12,BTN_ADDR@ha //
lhz r11,BTN_ADDR@l(r12)
Where is low being loaded? It only stores the High address to r12 doesn't it, how can you load the value from the whole address then?

dcx2

#23
I'm not sure you need the LR check.  Does it fail without it?  Generally, LR isn't terribly reliable for that purpose.  For example, other players would probably use the same call chain.  It's just a bit odd, not necessarily wrong.

The mixture of sth and stw can be seen in your original, because you 0 it out if you don't execute your hack.

stw r12,0x20(r10)
[...]
sth r11,0x20(r10)

Be careful with @ha and @h.  @ha is used if you will be adding, @h should be used if you will be oring.  The lower half of the address is provided by the displacement operand, in this case BTN_ADDR@l, which takes the low half of the address as a signed 16-bit integer.  Since the displacement operand is an addition, I use @ha to load the upper half of the address.  @ha accounts for the fact that 0x8000 <= x <= 0xFFFF will be interpreted as negative, and adjusts the upper half as necessary (by adding 1 to the upper half).  The a probably means "arithmetic", aka signed.  @h would be the "logical" version, aka unsigned.

lwz rD,d(rS) # rD = [rS + d]

rS = Source Register, d = Displacement Operand, rD = Destination Register.

EDIT: I made a small adjustment to my code above.  I had the assembler calculate the addresses for me instead.  Slightly safer - computers are much better at math than I am lol

Fighter19


Bully@Wiiplaza

Uhm, you use the .set instruction to assign text to values, then use them below in your actual assembly. It seems it's just for readability which helps a lot not getting confused quickly. Any documentation on all @ arguments though?
My Wii hacking site...
http://bullywiihacks.com/

My youtube account with a lot of hacking videos...
http://www.youtube.com/user/BullyWiiPlaza

~Bully

James0x57

Yep, it's just for readability- like labels for branching.

The assembler sees them like so:
[var]@h = higher (first) 16 bits of the variable
[var]@ha = higher adjusted (first) 16 bits of the variable + 1 (for subsequent adding, as dcx2 mentioned)
[var]@l = lower (last) 16 bits of the variable


Bully@Wiiplaza

#27
Quote from: dcx2 on December 06, 2013, 03:58:01 PM
You cannot use li to clear a register,  li is a mnemonic for addi, which does not clear the upper 16-bits.  You should use lis to clear a register, because it will clear the bottom 16 bits.
Sorry to prove you wrong, sir. :)
Li does clear the upper 16 bits just like lis the lower. It's not a mnemonic for addi.
addi r12, r12, 0x2876
lis r12, 0x1234
ori r12, r12, 0x5678
li r12, 0

Debugger step into:
1) r12 = 0x80000000
2) r12 = 0x80002876
3) r12 = 0x12340000
4) r12 = 0x12345678
5) r12 = 0x00000000
My Wii hacking site...
http://bullywiihacks.com/

My youtube account with a lot of hacking videos...
http://www.youtube.com/user/BullyWiiPlaza

~Bully

megazig

#28
li == addi
lis == addis

the rA is a literal 0 and not register r0, so it does set the whole value

note: SIMM is signed though, so you can't load any value using this method. it must be either 0xFFFFFXXX or 0x00000XXX with li as it'll subtract if SIMM >= 0x8000

dcx2

Ah yes, it slipped my mind that r0 would be treated as a whole 32-bit 0.  It is still true that addi does not clear the upper 16 bits ;)  But it appears li rD,0 is safe after all - although megazig's explanation shows why we lis/ori instead of li/oris.

And li is very much the mnemonic for addi.  Go ahead, type in the assembly command "addi r3,r0,3" into ASMWiiRd, convert to your Gecko code, then convert back to ASM.  It will disassemble to li r3,3.