From WiiBrew
Jump to navigation Jump to search
Author(s) Fullmetal5
Wiimote.svg Internet

FlashHax is a safe way to enable homebrew on a Wii without hardware modification. FlashHax is achieved by use of the Wii's Internet Channel to download and execute the HackMii Installer. This exploit requires the Internet Channel.


1. A broadband connection.

2. The Internet Channel.


1. Go to the Internet Channel, then go to flashhax.com

2. Select your region.

3. Bookmark the page and open the bookmark for FlashHax

4. The Wii will download the HackMii Installer. After that, the the rest is simple, assuming you know how to use the HackMii Installer.

Note: Your Wii may freeze during step 4, and you will have to try again.

How it works

FlashHax exploits a bug in Flash that allows a property to be modified after it is released from memory. This is done by putting the property onto a text field, attempting to decode the property to something else, and having an event listener to see when that property is modified. When it gets modified there, the event listener is called, which deletes the text field, releasing all memory associated with it, including the property, and then returning a new value to put there, placing a value into freed memory.

This does not seem like a big deal at first glance. After all, allocated memory often has junk values sitting in it before it is initialized. The key thing to note here is that when memory is freed in Flash, it is overwritten by a pointer to the next object that must be freed. If this value is overwritten after it enters the freeing queue, the garbage collection thread can be redirected to another location. Whenever an object is located by the garbage collection thread, the next pointer is overwritten by a zero byte, the integer after that is overwritten by the pointer to the previous object in the queue, and the next few bytes are filled with some small integer values. Since there is a way to point this garbage collection thread anywhere, any memory address can be modified by pointing the next pointer there.

Unfortunately, because of how the garbage collector works, it will also attempt to follow a "pointer" at the value previously there, which means it is important to make sure the chain does not go past there. It turns out that the chain handles 6 objects at a time, which means the 6th object needs to be at the place to overwrite. Because the beginning of the object is overwritten with a zero, while the second integer is overwritten with a previous pointer, the location of this "object" must be placed 4 bytes before the address to be overwritten. The 5th object must then have the address to be overwritten, followed directly by the data that should be present when the overwritten pointer is dereferenced. With this, there are still 4 more iterations that must be done. The first iteration is when the garbage collector handles the trashed text field and moves toward the custom chain, leaving 3 more that require attention. For these three, a simple chain of pointers pointing to the next object are put to use up the remaining parts of the loop. A buffer of junk bytes is placed in between to prevent the garbage collector from overwriting the pointer after it, providing a method to overwrite a single address.

Now, an address to overwrite must be chosen. It makes sense to overwrite a pointer, since a pointer will be put in place of it. At first, it seems like a function pointer or return address should be overwritten to pass code execution to FlashHax, however, Opera does enforce DEP, so a code buffer cannot simply be added. A more useful place to overwrite is a pointer to an OSThread.

With OSThread (and therefore OSContext) in control, one might think to set up a ROP chain by overwriting the stack pointer. However, this is not possible, because the stack pointer is stored in register r1, which is overwritten by the trash bytes that come after the previous pointer on the garbage collector chain. In fact, r6 is the first register that can be controlled. Luckily, the other special-purpose registers such as the program counter and the link register are higher up in the context, so they can be controlled. The program counter can be used to load one gadget, and the link register can hold a second gadget assuming the first gadget is not from a function that saves and loads the link register (i.e. a function that calls another function). However, no more ROP gadgets can be run this way, so a way to load a longer ROP chain is needed.

The problem is now reduced to placing the stack pointer at a controlled location, using up to two ROP gadgets. The stack pointer is currently set at a low value due to the garbage collector setting r1 to that, so it may appear that starting a ROP gadget in the middle of a function is not useful, since it will attempt to free the stack into negative memory. This is actually not the case, because on PowerPC, the stack grows downward, meaning there is actually plenty of space for the stack to be freed, but not much to grow. Because of this, the first ROP gadget can be at the part of a function that is freeing however much of the stack it previously allocated, which is stored in r28, one in the controllable area. Once this is done, the stack pointer is in control. The function chosen happens to save and load the link register, which means the link register can be preloaded with dummy data.

At this point, the OSContext is complete; the other part of the OSThread that must be properly set is the pointer to an OSThreadQueue when context switching. This is simply set to 0x80000004, the location of a few disc metadata values that are not relevant to the Internet Channel, as the queue is only written to in an attempt to move the old thread to the end of the linked list.

With this in mind, a sequence of bytes can be crafted to meet the needs stated above. First, there needs to be a chain of 3 pointers that point forward to the next. After this, the address to be overwritten must be present, which is the fake OSThread, and the last pointer in the previous chain points to this pointer. When the pointer is overwritten, it points directly at the target address, meaning the rest of OSThread, after the trash bytes, need to be placed there. Finally, after the fake OSThread, the ROP chain is present, which the ROP gadget in OSContext loads.

Now that a payload is built, there needs to be a way to place it directly in memory. Flash does not keep array elements together in memory, so an array is not an option. The other option is a string, which is available, but it has its own issues. Similar to C strings, Flash strings are terminated by null characters, but unlike in C, characters are 2 bytes wide in Flash, meaning strings are terminated by double null bytes. There are several points in the hax string that require padding, such as between the garbage collector iterations, that would normally be set to 0. Since this is not possible here, the \u4141 and \u4242 characters are used instead. These values are also placed into all of the unused registers in OSContext to prevent the string from terminating prematurely.

While the Wii itself does not do any ASLR, Flash does not place its variables in deterministic points in memory. To get around this, a heap spray must be done, which seems like something that will not consistently work. Luckily, when the bookmark bar in the Internet Channel is used to load a page, there is a location in memory that is almost always used, so the exploit must be run from the bookmarks bar. To detect whether the page was loaded using the bookmark bar or another way, a #stop parameter is put onto the URL. The Wii removes this tag when adding it to the bookmark bar, so detecting the absence of the #stop parameter is enough to make sure the exploit can run consistently.

To make the heap spray work, an array is first built to contain a string byte for every index in the heap spray array to be built. Then, each of these unique string bytes is appended to the hax string to create a new copy of it, placing it many times in memory to make the garbage collector locate it. The address that is usually filled by the hax string is then put into the event listener in the text field from above, making it reach the hax string. The actual collector is triggered by wasting memory to create a need to recycle the memory occupied by the text field.

Now, to make code execution happen, the ROP chain must load some payload into memory. To do so, it calls three ROP gadgets for each integer loaded: one to load the target value into a register, one to load the write address into another register, and one to write to that address using the value. There is a pointer that automatically increments every time this writing is done, easily allowing some code to be loaded. Since this is all in the hax string, however, there cannot be any pair of null bytes in the same word. In the ROP constants, this is done by padding everything with \u4141, but the payload itself cannot be handled this way, limiting what it can do. After all of these writes, the final gadget in the chain is the payload itself, which is jumped to by returning.

To solve this, the Flash loader also downloads a second payload as a video, so it is not subject to the string limitations. This second payload starts with an "egg" that is located by the first payload. The first payload then copies the beginning of the second payload into lower memory, where DEP is not present. The second payload then makes high memory executable, and executes the rest of itself, which is actually a modified version of Savezelda that has the HackMii Installer bundled with it.