Posts: 99
Threads: 2
Joined: Dec 2021
Reputation:
2
Howdy all,
I have encountered something I’ve never seen before while hacking, perhaps you can shed some light as to what is going on.
The game I am hacking is “Anima- Ark of Sinners.” (USA) Wiiware.
Specifically, I am looking for an infinite health code.
The address for the protagonist’s [Celia] health changes every time the game is booted. This can usually be hacked using ASM, but in this case, it appears the address the actual game code itself is stored at, changes as well.
- I started a new game, and when I took control of Celia, with a full health bar, created a save state.
- I found her health address to be at: 91D31454 000000C8
- The return on breakpoint when taking damage: 80E9AA08 stw r3, 0x0014 (r29)
- So I re-wrote the code like this:
80E9AA08 stw r3, 0x0014 (r29)
li r11, 0xC8
lis r12, 0x91D3
stw r11, 0x1454(r12)
Works great until one of four things happen:
1) I deactivate the code and allow Celia to die.
2) Celia falls to her death.
3) A new area of the game is entered.
4) The game is rebooted, and my save state is not used.
In any of these cases, her health address changes, and the address where the store command is changes also.
I have let her die 5 times and ran a BP on all the new health addresses and came up with a new address where the store command is every time e.g.
80E9AA08 stw r3, 0x0014 (r29) r29 = 91D31440
80E##### stw r3, 0x0014 (r29) r29 = 9#######
80E##### stw r3, 0x0014 (r29) r29 = 9#######
80E##### stw r3, 0x0014 (r29) r29 = 9#######
80E##### stw r3, 0x0014 (r29) r29 = 9#######
What gives?????
If anyone wants to check it out, the quick way to her health is a word search on 000000C8
You’ll get 5** returns.
Take a hit from an enemy and do a decreased value search. You’ll end up with 2 or 3 returns.
It’s pretty obvious which one it is.
Looking forward to your insight!
HW
Posts: 4,226
Threads: 894
Joined: Feb 2018
Reputation:
96
12-06-2021, 12:47 AM
(This post was last modified: 12-06-2021, 12:56 AM by Vega.)
EDIT
The address for the stw instruction changes too? That's odd. I'm guessing the game uses some relocatable module of some sort. Still try out what I crossed below just in case as the way you are writing your source out is incorrect.
Code: 80E9AA08 stw r3, 0x0014 (r29)
This instruction is storing the Health (what's in r3) to its designated spot in dynamic memory. That spot is at r29 + 0x0014. Thus the value of r29 itself is a dynamic memory address. This is why you are having different mem91 addresses.
What's good though is that r29+0x0014 will always point to where the Health is at. Regardless of what r29 is at the time. What you need to do is modify what's in r3 before it gets stored to dynamic memory.
So like this...
Code: li r3, 0xC8 #Set custom Health amount
stw r3, 0x0014 (r29) #Default Instruction, Health gets stored to Dynamic Memory
Posts: 99
Threads: 2
Joined: Dec 2021
Reputation:
2
12-06-2021, 01:08 AM
(This post was last modified: 12-06-2021, 01:21 AM by Hackwiz.)
(12-06-2021, 12:47 AM)Vega Wrote: EDIT
The address for the stw instruction changes too? That's odd. I'm guessing the game uses some relocatable module of some sort. Still try out what I crossed below just in case as the way you are writing your source out is incorrect.
Code: 80E9AA08 stw r3, 0x0014 (r29)
This instruction is storing the Health (what's in r3) to its designated spot in dynamic memory. That spot is at r29 + 0x0014. Thus the value of r29 itself is a dynamic memory address. This is why you are having different mem91 addresses.
What's good though is that r29+0x0014 will always point to where the Health is at. Regardless of what r29 is at the time. What you need to do is modify what's in r3 before it gets stored to dynamic memory.
So like this...
Code: li r3, 0xC8 #Set custom Health amount
stw r3, 0x0014 (r29) #Default Instruction, Health gets stored to Dynamic Memory
li r3, 0xc8
stw r3, 0x0014 (r29)
Was how I wrote the code originally. However, this also gives enemies you attack infinite health.
Again, thanks to the guides on the site and some thinking what had to be logically done, I came up with the code I listed.
stw r3, 0x0014 (r29) #Store decreased health amount
li r11, 0xC8 #Set custom Health amount #Set custom Health amount #Set custom Health amount
lis r12, 0x91D3 #Load upper half-word of address in r29 into r12
stw r11, 0x1454 (r12) #Store r11 at address in r12 + offset [r29 + 0x0014].
Celia can take a beating and still slay enemies.
It dawned on me this morning that I just figured out how to get around a problem which has stymied me on a quite a few games.
Here's another question. Is it possible to run a trace log in Dolphin?
Would be nice to see what is going on when her new health address is generated.
I see options for RAM dumps, but it seems to me that's not the same thing.
li r3, 0xC8 #Set custom Health amount
stw r3, 0x0014 (r29) #Default Instruction, Health gets stored to Dynamic Memory
li r3, 0xC8 #Set custom Health amount
stw r3, 0x0014 (r29) #Default Instruction, Health gets stored to Dynamic Memory
Posts: 4,226
Threads: 894
Joined: Feb 2018
Reputation:
96
That instruction (when executed by the CPU) is being used for each enemy's health as well. Usually when something like that happens, there's an 'index byte' in one of the Global Variable Registers (r14 thru r31). In the majority of Wii games, they like to use '0' to represent Player, and '1' for CPU #1, '2' for CPU #2, etc etc.
You could keep the Memory Write Breakpoint active while constantly unpausing the emulation after every hit while looking at what's in r14 thru r31. Screenshots are recommended to keep record. If you notice a pattern to where let's say r17 is always 0 when its your health but always non-zero on an enemy's health, then that Register could be the 'index byte'. Then you can write a basic check like this...
Code: cmpwi r17, 0 #Pretend the index byte register is r17
bne+ dont_execute #Index is not zero, don't set the Health
li r3, 0xC8 #Set the Health
dont_execute:
stw r3, 0x0014 (r29) #Default instruction, store health
Sometimes these indices won't be used and a more 'hacky' method will be required.
--
In regards to the changing instruction address, a 'hacky' way to solve this problem is using the F6 Gecko Codetype - https://mariokartwii.com/showthread.php?tid=545
You can use your instruction (compiled form) with a string of instructions after/before so you have a unique string to search for. The F6 code will search for this unique string. Once found, it can hook your ASM code at that address.
However this may need more Gecko codetypes on top of it, because F6 code's are executed immediate upon boot. So if the string isn't found right away, it simply won't hook. Relocatable modules are loaded up by the game some time later after the main executable file is loaded (main.dol)
Posts: 99
Threads: 2
Joined: Dec 2021
Reputation:
2
"as the way you are writing your source out is incorrect." I'm assuming you mean not putting # comments after the ASM lines?
Guess it would make it easier to show someone what I think I mean to accomplish
Thanks for taking the time to help me out. This was/is driving me bat-shit crazy.
Now it's time to get familiar with some more new code types.
Posts: 4,226
Threads: 894
Joined: Feb 2018
Reputation:
96
12-06-2021, 01:38 AM
(This post was last modified: 12-06-2021, 02:15 AM by Vega.)
When I read your post, it appeared that you were trying to write to dynamic memory and treating it as static, that's what I meant by 'incorrect'. But I didn't even think about the whole instruction address modifications and the Health effecting the enemies as well. 4 hours of sleep + long day of work is not helping Apologies.
Every game I have ever made codes for doesn't use a relocatable module that will write CPU executable instructions to different memory locations. MKWii does have one, but the module is loaded into the same respective area of memory every time.
Posts: 99
Threads: 2
Joined: Dec 2021
Reputation:
2
Hacked the value for enemy health so I could do BP on Celia and enemies health when taking damage.
What I found was the link register alternated between two consistent addresses that remained consistent even upon either characters death/re-spawn.
When rebooting the game, these two addresses changed in LR, but again, the link register alternated between two consistent addresses that remained consistent even upon either characters death/re-spawn.
Hope that makes sense.
Got to crash for another fun-filled work day.
Posts: 4,226
Threads: 894
Joined: Feb 2018
Reputation:
96
Yes that does make sense. I've seen that before, but not with the Link Register in particular. I'm not sure of a good method to write out some Assembly to address that circumstance without the Assembly being 'hacky'.
Another way to check for Celia vs Enemy, is during the BP hits, go to where the Health is at in Dolphin-memory-engine and take screenshots of that. See if some nearby value(s) around the Health value are showing a distinct pattern on the alternating BP hits. If this ends up being true, load the value(s) first, run a simple check, and branch accordingly.
Have you looked at the F6 Gecko codetype in that thread I have linked earlier? If it doesn't make much sense, I don't mind making a tutorial. In fact, I probably should anyway just in case somebody else in the future is making codes for Games that have CPU-executable instructions that can vary on Memory Location.
Posts: 99
Threads: 2
Joined: Dec 2021
Reputation:
2
You read my mind.
The way the F6 codetype is written is kind of confusing.
What helped me out (at least in the simple asm guide), were the examples of how the code is used to accomplish an outcome.
e.g. To load a large number into a register use:
lis r3, 0x8035
ori r3, r3, 0x4126
Which loads 0x80354126 into r3.
Have a great day!
Posts: 99
Threads: 2
Joined: Dec 2021
Reputation:
2
So here is a code for Super Mario Galaxy.
This is how I'm deciphering it
Mario Size Modifier [brkirch]
F6000001 80208030 #Searches for the following (single) line of code (C03E0024 7C7D1B78) in ram address range 0x80200000 -> 80300000
C03E0024 7C7D1B78 #String searched for in ram address range 0x80200000 -> 80300000
I believe this takes care of this part:
Creates an if (so this code requires an endif), then searches for the NN lines of Z values between XXXX0000 and YYYY0000 (or, if XXXX is 8000, between 80003000 and YYYY0000).
As far as the rest of the operation goes, is this done automatically?
To prevent this code from causing game lag, it will only search the first time it is read by the code handler (the result is saved to the code and reused). If the Z values are found, set po to the starting address of the values (SSSSSSSS) and replace the F6 line with F60003NN SSSSSSSS.
If the Z values are not found, then set code execution status to false and replace the F6 line with F60001NN XXXXYYYY.
So I just need to write the appropriate gecko code utilizing the po afterwards and hope for the best?
Also, you said "executed immediate upon boot. So if the string isn't found right away, it simply won't hook."
Is it possible to use a button activator to force it to try re-hooking?
Cool stuff!!!!
|