Making Wii game cheats
Finding memory addresses and patching PowerPC assembly to get unlimited powerups in Newer Super Mario Bros. Wii
Making Wii game cheats
Backstory
I was playing the very awesome Newer Super Mario Bros. Wii romhack, and I wanted cheats for it. My family and I have 100%‘d the game at least 30 times by now and thats not an overstatement. My mom really enjoys the romhack, especially because of how faithful it is to Nintendo’s level design despite being very unique.
Unfortunately, my parents forbid me from using our hard-earned star coins for buying powerups. So to make my parents rest assured that our star coins will never deplete, I set out to make cheats for the modified game.
Overview
The problem is a result of how Newer handles Toad Houses. It has two variations of them, Shops and Challenge Houses. However, the original game has simpler houses. There’s three of them, a red one for general powerups that involves a picture-matching puzzle, a yellow one for receiving a star powerup from a chest and a green one where you shoot yourself out of a cannon into power up bubbles that grant you the number of powerups specified on the bubble.
The big difference between the two games is that the original game makes toad houses unlimited-use upon game completion, but the romhack doesn’t have an end-game mechanic like this.
Looking online, there are very few cheats for this romhack. None of which accomplish what I want.
The Process
Generally, if you want to find where a value is stored in memory, you should probably have the ability to easily manipulate it. But it’s a little harder when you might not be dealing with a simple numeric value.
To begin getting unlimited powerups, I wanted to first get unlimited stars or enough to increment my powerup counts to find their memory locations. So I began a search through memory for a U16 type (since 300+ star coins wouldn’t fit in a U8), with a value of 12 (my current number of total star coins). I completed some levels and refined my search to no avail.

I repeated the process, starting a new search with other data types and hoping to find the total count of star coins. It took time to complete the levels but it was all wasted effort.
It was around this time I learnt I could also just make save states between runs and restore “before and after” states to refine memory searches extremely quickly. But this trick was useless in this case, since I realised that the game probably computes the total from all the levels states.
This meant I had to find the level states in memory. I did the trick of saving states of the level completion. I made several save states for this, one for uncompleted, one for completed, then three with varying stars collected. But I still had no idea what to find. Luckily, someone already did the hard work of finding these values! If we didn’t have this resource though, we’d get all memory values, then train it to normal conditions.
We set up the search first:

Then we set it to search for values that never change, and run the search and filter multiple times.

We keep doing this over and over, walking around the world map and also throughout the level. Once we’ve trained it on values that never change (since our level state wouldn’t change until we finish the level), we can now compare against the various save states we prepared. We load the “completed level only” save state, then use the following search query:

We repeat this with the level being completed with an incrementing number of star coins with our save states. Eventually, we land on some (hopefully just one) memory location.

And now we have the state of this single level! In my case, this was level 1-3. This U32 value doesn’t mean much to us, but let’s fully complete this level. Doing this results in the value becoming 535. This value probably represents a fully completed level!
Detour
I found the 531 value, then double clicked the description field to make a note for myself. Then Dolphin crashed! I ended up having to figure it out. A section of the crash report:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 QtCore 0x10547ae70 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 248
1 QtCore 0x1055e1900 QTimerInfoList::activateTimers() + 948
2 libqcocoa.dylib 0x104badcb4 QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void*) + 28
3 CoreFoundation 0x192023624 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
4 CoreFoundation 0x1920235b8 __CFRunLoopDoSource0 + 224
5 CoreFoundation 0x1920232f0 __CFRunLoopDoSources0 + 232
6 CoreFoundation 0x192021ec0 __CFRunLoopRun + 836
7 CoreFoundation 0x1920fbb5c _CFRunLoopRunSpecificWithOptions + 536
8 HIToolbox 0x19f3c6544 RunCurrentEventLoopInMode + 320
9 HIToolbox 0x19f3c98d0 ReceiveNextEventCommon + 492
10 HIToolbox 0x19f54be3c _BlockUntilNextEventMatchingListInMode + 48
11 AppKit 0x196882f28 _DPSBlockUntilNextEventMatchingListInMode + 292
12 AppKit 0x1965407e4 _DPSNextEvent + 580
13 AppKit 0x196dabdc0 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 780
14 AppKit 0x196dab8e4 -[NSApplication(NSEventRouting) nextEventMatchingMask:untilDate:inMode:dequeue:] + 244
15 AppKit 0x1965339a0 -[NSApplication run] + 396
16 libqcocoa.dylib 0x104bae6c4 QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 1696
17 QtCore 0x1054842c0 QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 532
18 QtCore 0x10547b538 QCoreApplication::exec() + 128
19 Dolphin 0x1021ca4d8 main + 4924 This stack trace isn’t particularly helpful, but looking at Dolphin’s cheats manager source code clears it a bit.
void CheatsManager::RegisterAfterFrameEventCallback()
{
m_VI_end_field_event =
m_system.GetVideoEvents().vi_end_field_event.Register([this] { OnFrameEnd(); });
} The cheats manager sets up a callback for frame events. vi_end_field_event probably refers to the video interface and the last “field” being like the scan line of a CRT, as part of the raster? Did we have CRTs and the Wii at the same time? I don’t remember. Regardless, the OnFrameEnd method runs when it receives word.
void CheatsManager::OnFrameEnd()
{
if (!isVisible())
return;
auto* const selected_cheat_search_widget =
qobject_cast<CheatSearchWidget*>(m_tab_widget->currentWidget());
if (selected_cheat_search_widget != nullptr)
{
selected_cheat_search_widget->UpdateTableVisibleCurrentValues(
CheatSearchWidget::UpdateSource::Auto);
}
} And the method gets called, and it never moves onto the appropriate thread. This checks out since I had auto-updating memory values when I made edits to the table.
Back to The Process
Now that the cheats manager wouldn’t crash every time I used it, I could safely find memory values.
Now that I found my fully completed level, let’s look at all the surrounding memory values!

I have about two levels behind me, also fully completed, and I have 1-4 fully completed too! The midway castle was fully completed and the next level is 1-5. There’s a mushroom house which I’m able to access which is probably the second instance of 512 (since it branches off the normal route it probably appears later to avoid breaking vanilla level logic). The next instance of 512 after our last 535 down is likely 1-5! The easiest way to trial our hypothesis is to double click the 512 value and set it to 535 like the other levels, and see what happens!
Before we set the value, the level looks like this!

Initially, nothing happens. But if we move Mario off of the level tile and come back to it, it should reload that data from memory for the user interface. And now we’ve “completed” the level!

The map state still needs reloading to grant us the ability to move to the next level. So let’s enter and exit any level.
The path is now clear!

Looping back to when I mentioned someone else’s work. NewerSMBW is open source on GitHub, and it definitely has to have these all figured out.
#define COND_COIN1 1
#define COND_COIN2 2
#define COND_COIN3 4
#define COND_COIN_ALL 7
#define COND_NORMAL 0x10
#define COND_SECRET 0x20
#define COND_BOTH_EXITS 0x30
#define COND_SGNORMAL 0x80
#define COND_SGSECRET 0x100
#define COND_UNLOCKED 0x200 // NEWER EXCLUSIVE And it’s here! Each level state is a bitmask.

My screen can’t fit the entire thing in view but I suspect this entire block is dedicated to level states. Setting everything to 535 should complete every level with 3 star coins! But there’s a lot of space for a game with only 128 levels. The base game probably leaves a healthy amount of space for many level slots per world. Setting all of them does work but we now have a star coin count of 1260 which is a lot more than the advertised 300 something ish.
The easiest thing to do is get a fully completed save and just steal the right memory values from that when its loaded.
And here’s the finished AR Code! It literally just sets all of the memory values to the completed state.
04C7FECC 00000217
04C7FED0 00000217
04C7FED4 00000217
04C7FED8 00000217
04C7FEDC 00000217
04C7FEE0 00000237
04C7FEE4 00000217
04C7FEE8 00000237
04C7FF04 00000217
04C7FF2C 00000217
04C7FF44 00000210
04C7FF4C 00000210
04C7FF60 00000217
04C7FF64 00000030
04C7FF6C 00000200
04C7FF74 00000217
04C7FF78 00000217
04C7FF7C 00000217
04C7FF80 00000217
04C7FF84 00000237
04C7FF88 00000217
04C7FF8C 00000217
04C7FF90 00000217
04C7FF94 00000237
04C7FF98 00000217
04C7FFAC 00000217
04C7FFD4 00000217
04C7FFF4 00000210
04C7FFF8 00000210
04C80008 00000217
04C8000C 00000030
04C80014 00000010
04C8001C 00000217
04C80020 00000237
04C80024 00000217
04C80028 00000217
04C8002C 00000217
04C80030 00000217
04C80034 00000217
04C80054 00000217
04C8007C 00000217
04C8009C 00000210
04C800A0 00000210
04C800B0 00000217
04C800B4 00000030
04C800C4 00000217
04C800C8 00000217
04C800CC 00000217
04C800D0 00000237
04C800D4 00000217
04C800D8 00000237
04C800DC 00000217
04C800E0 00000217
04C800FC 00000217
04C80124 00000217
04C8013C 00000210
04C80144 00000210
04C80148 00000210
04C80158 00000217
04C8015C 00000030
04C8016C 00000217
04C80170 00000217
04C80174 00000217
04C80178 00000217
04C8017C 00000237
04C80180 00000217
04C80184 00000217
04C80188 00000217
04C8018C 00000237
04C80190 00000217
04C801A4 00000217
04C801CC 00000217
04C801F0 00000210
04C80200 00000217
04C80204 00000030
04C80214 00000217
04C80218 00000217
04C8021C 00000237
04C80220 00000217
04C80224 00000217
04C80228 00000237
04C8022C 00000217
04C80230 00000217
04C80234 00000217
04C8024C 00000217
04C80274 00000217
04C80294 00000210
04C80298 00000210
04C802A8 00000217
04C802AC 00000030
04C802BC 00000237
04C802C0 00000217
04C802C4 00000217
04C802C8 00000217
04C802CC 00000237
04C802D0 00000217
04C802D4 00000217
04C802D8 00000217
04C802F4 00000217
04C8031C 00000217
04C80334 00000210
04C8033C 00000210
04C80350 00000217
04C80354 00000030
04C8035C 00000010
04C80364 00000217
04C80368 00000217
04C8036C 00000217
04C80370 00000217
04C80374 00000217
04C80378 00000217
04C8037C 00000217
04C80380 00000217
04C80384 00000217
04C80388 00000217
04C8039C 00000217
04C803A0 00000217
04C803C0 00000217
04C803C4 00000217
04C803E4 00000200
04C803FC 00000030
04C80404 00000010
04C8040C 00000217
04C80410 00000217
04C80414 00000217
04C80418 00000217
04C8041C 00000217
04C80420 00000217
04C80424 00000217
04C80428 00000217
04C8042C 00000217
04C80430 00000217
04C804A4 00000030
04C804B4 00000217
04C804B8 00000237
04C804BC 00000217
04C804C0 00000237
04C804C4 00000217
04C804C8 00000217
04C804CC 00000237
04C804D0 00000217
04C804D4 00000217
04C804D8 00000217
04C804DC 00000217
04C804E0 00000237
04C804E4 00000217
04C804E8 00000217
04C804EC 00000217
04C804F0 00000217
04C804F4 00000217
04C804F8 00000217
04C804FC 00000217
04C80508 00000217
04C8050C 00000217
04C80510 00000217
04C80514 00000217
04C8052C 00000210
04C80538 00000210
04C8053C 00000210
04C80540 00000210
04C80544 00000210 Not the smallest AR Code you’ve seen but it works.
Next, we can begin by looking for the powerup counts! Since NewerSMBW layers on top of the existing game, the vanilla game’s memory locations should work. But I’m aware the romhack adds a new powerup. The romhack has to hook existing game code and store its own state somewhere where it won’t conflict with the base game, so let’s look for an existing code that does what we want!
[Inf. powerups by schooluser]
015DBB77 00000063
015DBB7B 00000063
015DBB7F 00000063
015DBB83 00000063
015DBB87 00000063
015DBB8B 00000063
015DBB8F 00000063 We can see it setting 7 addresses that are contiguous in memory to 99 as U8. Trying it in the romhack version seems to not do anything. Memory locations must have changed slightly then or we have an incompatible code. We’ll have to look for the memory locations ourselves.
Easiest thing to do is buy a bunch of powerups using our newfound star coins, making a save state beforehand, then make a save state with your slightly fuller inventory. We start a search for one of the powerups, with a type of U8.
After a few repeats, we find a value, show it in memory and find that a block of values looks like our inventory!


what happens if we set them all to 99?

Works perfectly, and the new hammer powerup’s address is right after the star powerup’s address, which means there must have been an empty space for it!
The resulting AR Code just sets all of these addresses to 99 forever.
055E13BC 00000063
055E13C0 00000063
055E13C4 00000063
055E13C8 00000063
055E13CC 00000063
055E13D0 00000063
055E13D4 00000063
055E13D8 00000063 Lastly, I’d like the ability to rapid fire for all 3 of the projectile-based powerups. We’ll look for another existing code.
[Shoot Inf. Ice/Fireballs by Bully@Wiiplaza]
041233A4 60000000
041233AC 60000000
0411A5C8 60000000
0411A5D0 60000000 Trialling this, it actually still functions! This seems to patch actual instructions rather than change a numerical value.
An AR Code has the format of TTAAAAAA VVVVVVVV, where TT is the Action Replay type. 04 indicates a 32-bit write. 05 is also the same thing but just refers to the upper half of the addressable memory range.
I suspect the asm we need to patch is quite far. As I stated before, the romhack has to store its stuff outside of the address range the stock game uses.
We’ll use the Branch Watch feature in Dolphin to filter out codepaths until we find the one we want. First we start the branch watch
We get the powerup, do some irrelevant actions like moving around, killing enemies and shooting 2 fireballs without hitting the third (where we’d be blocked from doing so).

We then hit Code Path Not Taken to exclude all of the code that ran and only keep code that didn’t run yet.
Once we’ve done this, we do the thing we want to catch. We press the fire button thrice and our third shot is blocked. We quickly hit Pause Branch Watch and then Code Path Was Taken to see the instructions we just ran.

We can now see the instructions and we can view them in the Code window! Remember to pause so we can view the asm.

The bge- instruction looks just like what we need to patch!

The register r0 contains the number of fireballs thrown. We patch the bge- with nop so the comparison is never used, we just go to li r3, 1 and the fireball shoot is allowed to happen.
Trying it now shows we can now shoot up to 6 fireballs at a time!

Big jump from 2 but you may have spotted the culprit preventing unlimited fireballs already.

There’s one more comparison to patch. Let’s nop the other bge- and see what happens!

Unlimited fireballs! We’ve read the asm and patched the two checks for limiting the fireballs thrown. The likelihood this double check exists is for when you’re in a level where you can walk through the right of the screen and wrap around to the left. The fireballs thrown here would get stuck here forever if not obstructed. You’d be able to throw 2 fireballs at a time up until there are 6 fireballs on-screen. This checks out if you try it in the mid-world tower “Pipeline Tower” in world 2. You’ll need two players to kill the spike balls to make space for this experiment.
We repeat what we did for the other powerups, but hammer and ice balls are ephemeral rather than persistent so the secondary check doesn’t exist.
The finished AR Code looks like this:
041233A4 60000000
041233AC 60000000
0411A5C8 60000000
0411A5D0 60000000
04DFDC5C 60000000 The End
That was a lot of fun, I hope you found it as interesting as I did!