Main Menu
Main Page
Forums
Recent changes
Random page
Help

Databases
GlitchDex
AttackDex
ItemDex

Major Glitches
Trainer escape glitch
Old man trick
Celebi trick
Select glitches (Japan)
SRAM glitch
CoolTrainer♀ corruption
LOL glitch
Rival LOL glitch
Super Glitch
ZZAZZ glitch
Pomeg corruption glitch (Glitzer Popping)
Tweaking
Elite Four door glitch (Japan)
Pokémon merge glitch
Pokémon cloning
Time Capsule exploit
Arbitrary code execution
Coin Case glitch
More

Other Glitch Categories
Glitches by generation
Glitches between two generations
Japan-only/language specific glitches
Music glitches
Natural glitches
Non-core series glitches
Non-Pokémon glitches
Officially acknowledged glitches
Recurring glitches
Dead glitches

References
Pokémon GameShark codes
The Big HEX List
GB programming
Curiosities
Debugging features
Easter eggs
Error traps
Glitch areas
Glitch myths
Non-glitch exploits
Placeholder texts
Pokémon glitch terminology
Unused content and prerelease information

Useful Tools
8F Helper
GBz80 to Items
Old man trick name generator
PATH (Prama's Advanced Tweaking Heaven)
Save file editors
Special stat/Pokémon converter
Trainer escape Trainer Pokémon finder

Affiliates
Legendary Star Blob 2 (Hakuda)
Pokémon Speedruns wiki
PRAMA Initiative
Become an affiliate!

Search Wiki

 

Search Forums

 

Author Topic: Gen III Remote Code Execution  (Read 2803 times)

0 Members and 1 Guest are viewing this topic.

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Gen III Remote Code Execution
« on: February 18, 2017, 07:58:35 pm »
TL;DR: with a Wii or GameCube where you can run homebrew (obviously easier with a Wii), and a GBA->GC link cable, you can abuse the functionality officially used by Pokémon Colosseum/XD/a bunch of Berry Glitch fixdiscs to get code exec in the context of Gen III.
(of course, you could also use the GBA BIOS multiboot, but here you don't have to press any buttons on the GBA BIOS to get multiboot going! And because this is in the Gen III ROM, this can legitimately be called Gen III RCE :P)

What is this?
Have you ever connected up Pokémon Colosseum/XD to your Gen III game? Remember how it told you to turn the GBA on with the GBA->GC link cable plugged in, then it took an awfully long time on the copyright screen and then showed some Colosseum/XD thing?
The awfully long time on the copyright screen was Colosseum/XD transferring a multiboot image (basically a GBA ROM image with modifications, namely it runs from RAM lol) to your GBA. The Colosseum/XD thing on the GBA was basically your GBA executing that multiboot image.
After two days of reversing (this multiboot protocol is pretty different to the one used by the BIOS, but it does have a couple of similarities), I got a respectable PoC working. So, where else to release this to the world?

Here's an image of, basically, the very PoC I'm releasing today. The payload only supports an English Pokémon Ruby, version 1.0, 1.1 or 1.2 (because that's the only of my Gen III carts I could find; I didn't know what version it was; and the GC/Wii-side application doesn't work inside Dolphin); The payload now supports every Generation III game, except Pokémon LeafGreen v1.1 (Japan) due to it being undumped; it calls the game's save-loading function, replaces the first character of the player name with 'z', then returns to the game (by calling the game's main loop as a function, because just returning would reload the save and overwrite the change made).



Where's the code?
Right here: https://github.com/Wack0/gba-gen3multiboot

If you want to modify the GBA-side payload, you can naturally find it in the gba directory. Note that the payload is in the C language. A refreshing change of pace from position-independent ASM shellcode, I'm sure you'll agree.

To compile this, you'll need devkitPro (devkitARM for the GBA side and devkitPPC for the GC/Wii side). Remember, this is very much a proof of concept which I'm sure will be improved on by others.

How do I run it after compiling?

I assume you have a Wii (I'm not even going to mention GameCube, I think all the good ways to get homebrew running there need a Wii anyway lol), with the Homebrew Channel installed and running. Just execute the compiled gen3multiboot_wii.dol there. When testing, I always used wiiload, it being quicker than copying a new binary to the SD card every time.

Make sure you have a GameCube controller plugged into controller port 1 and your GC->GBA link cable plugged into port 2.

Hey, it didn't work. What gives?

Code execution on the GBA side is not 100% reliable for some reason. A couple of different things could go wrong. If you see an error about KeyC derivation, you should just be able to turn your GBA off, press any button on your GameCube controller plugged into port 1, then turn your GBA back on again.

If, however, your GBA didn't seem to notice the code being transferred to it, and your Wii has frozen on a line with a CRC, you're going to need to power off both GBA and Wii, turn your Wii back on, get back into the Homebrew Channel and run gen3multiboot_wii.dol again.

It may take a few tries but it will eventually work.

What is this "different" protocol?

If you want technical details, best see the source code.
At a higher level, it goes like this:

  • GBA game starts, game calls the multiboot main() function
  • GC sends a reset command, GBA sends a game code
  • GC receives game code, maybe checks to see if it's supported, and sends it back to GBA
  • GBA checks this, if it's wrong then GBA stops listening on the JoyBus link cable
  • GC generates and sends the first of three 32-bit encryption keys. This is officially (yay for debug messages!) called "KeyA" (imaginative). GBA checks one of the bytes to make sure it's valid, then generates and sends its own encryption key, "KeyB".
  • KeyA and KeyB are XORed together to form the initial value of the checksum (algorithm used is the same as the GBA BIOS multiboot). This value is also obfuscated to form a session key that will be used to encrypt most of the multiboot image when it is sent (again, algorithm used is the same as GBA BIOS)
  • GC sends the size of the multiboot image it's about to send, in uint32s, to GBA. GC then sends the ROM header (up to 0xA0, the end of the Nintendo logo) to GBA in the clear. When this is done, GBA checks the received Nintendo logo to make sure it's the same as the Nintendo logo in the ROM of the cartridge it's executing. If not, GBA stops listening on the JoyBus link cable.
  • GC sends the rest of the multiboot image to the GBA. Each uint32 is encrypted using the session key, which is also incremented in the same way as the GBA BIOS multiboot. Each plaintext uint32 is also checksummed, using the existing checksum as the initial value, again the algorithm used here is the same as the GBA BIOS multiboot.
  • GBA, as it's receiving the image, decrypts it, and checksums the plaintext in the same way. After this is done, the GBA will send GC a value that can be used with the correct multiboot image checksum to derive KeyC, which was created by GBA using some historical value of its VCount register.
  • GC receives this value, and attempts to derive KeyC. It will use the derived KeyC to create a "boot key" which is sent to GBA; if this boot key is the same as the one the GBA already created, it will call the entry point of the sent multiboot image. If not, GBA will stop listening on the JoyBus link cable.

This took me quite some time of reversing work to figure out (there was lots of info about the GBA BIOS multiboot protocol on the internet; only ARM ASM code about this one, from the Pokémon reverse engineering project). I hope it helps someone.
« Last Edit: February 20, 2017, 12:35:22 pm by Wack0 »
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Yeniaul

  • Guest
Re: Gen III Remote Code Execution
« Reply #1 on: February 18, 2017, 08:10:33 pm »
I'm still sad I couldn't help out with this, even though it happened on my Discord server right in front of me.
My self-esteem just tanked.
Dammit.

Unused Trainer

  • GCLF Member
  • Offline Offline
  • CHARIZRAD 'M ROXORX or is it.
    • View Profile
Re: Gen III Remote Code Execution
« Reply #2 on: February 19, 2017, 04:42:01 am »
Is this a RAM code?

Háčky

  • Distinguished Member
  • *
  • Offline Offline
  • Pick which packet as an error?
    • View Profile
Re: Gen III Remote Code Execution
« Reply #3 on: February 19, 2017, 06:58:51 am »
Another technique that might be useful is to take advantage of the Mystery Events feature that overrides an NPC script (used to install Norman’s Eon Ticket script). By storing a script that uses the callasm command, you could execute code on demand by talking to a particular NPC.

By writing such a script into the save file using multiboot, it might be possible to do this even in games where Mystery Events is unavailable (FireRed/LeafGreen and non-Japanese Emerald).

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #4 on: February 19, 2017, 12:35:44 pm »
Testing payloads under emulation

What you need:
  • latest Dolphin
  • VBA-M, the WX version
  • GameCube ISO: Interactive Multi-Game Demo Disc Version 16 (USA)
  • GBA BIOS (needed for linking, you can even easily dump this from your real GBA using GBA BIOS multiboot + some Wii homebrew)
  • Hex editor
  • A payload you want to test (gba/gba_pkjb.gba or data/gba_mb.gba)

First up you need to configure your Dolphin and VBA-M to get them linked together properly, there's enough guides round the internet for this, but here's some quick instructions anyway: configure Dolphin to have controller 2 as GBA, set up the GBA BIOS in VBA-M, make sure "Skip BIOS" is ticked and "Pause when inactive" is unticked on VBA-M Edit menu, in VBA-M options->link menu configure link type to be gamecube, make sure "Link on boot" is ticked, choose "Start Network Link".

Now, make a copy of that Interactive Multi-Game Demo Disc Version 16 ISO. Why is this ISO important? It has a Berry Glitch fix included! (Also, the PPC side here has lots of nice debug messages that show up in Dolphin logs and really helped me reverse the multiboot algo.)

Anyway, open up the copy of the ISO in your hex editor. First, go to offset 0x45ded5fc and patch two bytes here to 48 00 -- this bypasses the game code check so Japanese games will work. You'll need to do the same thing at offset 0x45ecdf1c. Next, go to offset 0x45f2ae30 -- that's where the multiboot image is stored that gets transferred by the Berry Glitch fix. So replace the bytes there with your own payload (up to 31,872 bytes - that's the size of the original multiboot payload used here), save.

Open your modified ISO up in dolphin, when you get to the main menu of the demo disc press down twice to get to the berry fix entry, and press A (X key is mapped to A button by default). After some health and safety etc screens, the multiboot part will start and show a screen of saying how this will fix the Berry Glitch and give out shiny Zigzagoons. Just press A again, and then open up your ROM in VBA-M. If everything goes well there should be some "data transferring" stuff in Dolphin, there will be longer copyright screen in VBA-M, and then your payload should run (and error should then show in Dolphin) :)
« Last Edit: February 19, 2017, 01:20:02 pm by Wack0 »
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #5 on: February 19, 2017, 04:38:24 pm »
Meanwhile, I'm busy working on getting the example payload compatible with all of Gen 3.

I'd like to note something pretty important here.

Game Freak were sneaky fuckers.

In FR/LG (and probably Emerald as well) they left the save file loading code in place..

..then they added new code that reloads the save at the title screen after setting up ASLR.

Of course, my current in-dev payload now bypasses this.. by bypassing the title screen entirely and jumping straight to the Continue/New Game menu.
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #6 on: February 20, 2017, 12:39:14 pm »
I've made a new commit that updates the payload: https://github.com/Wack0/gba-gen3multiboot/commit/d448823ffb540cb462548552efe4b5650e66de95

It now supports every Generation III game (except Pokémon LeafGreen v1.1 (Japan) due to it being undumped).

I haven't tested some Generation III games, mostly Sapphire which in every instance have the same offsets as Ruby. If the payload doesn't work on one of your Generation III games, post here, or create a GitHub issue, or both.

Payload code now goes into the payload() function in payload.c, because main() is now over 200 lines long to detect the Generation III game.

Coming soon(tm): actual save-block structure definition. "Soon(tm)" because I don't really want to do that right now. If anyone wants to do it for memake a start or help me with it, pull requests would be much appreciated - it may motivate me to finish it sooner. :)
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Unused Trainer

  • GCLF Member
  • Offline Offline
  • CHARIZRAD 'M ROXORX or is it.
    • View Profile
Re: Gen III Remote Code Execution
« Reply #7 on: February 21, 2017, 01:43:51 am »
So even Fire Red/Leaf Green game?

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #8 on: February 21, 2017, 04:04:11 am »
So even Fire Red/Leaf Green game?

Yes, although with the following caveats:

- some payloads designed for RSE won't work on FRLG (the example one works fine everywhere though)
- parts of the FRLGE save files are crypted, working on rectifying that
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #9 on: February 21, 2017, 09:10:21 am »
I have just made a patcher for the Interactive Multi-Game Demo Disc Version 16 (USA) ISO because I got too bored of doing it manually.

It's made in C#, here's the code:

Code: [Select]
using System;
using System.IO;
using System.Text;

class ReplacePayload {

static bool ByteArrayCompare(byte[] a1,int offseta1, byte[] a2,int offseta2,int length) {
if (offseta1 + length > a1.Length)
return false;
if (offseta2 + length > a2.Length)
return false;

    for (int i=0; i<length; i++)
if (a1[offseta1+i]!=a2[offseta2+i])
            return false;

return true;
}

public static void Main(string[] args) {
if (args.Length < 2) {
Console.WriteLine("Usage: {0} <ISO path> <payload path>",System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
Console.WriteLine("ISO must be \"Interactive Multi-Game Demo Disc Version 16 (USA).iso\"");
return;
}
// read the payload
byte[] payload;
try {
payload = File.ReadAllBytes(args[1]);
} catch (Exception e) {
Console.WriteLine("An error occured when reading the payload.");
Console.WriteLine(e.ToString());
return;
}
// check the Nintendo logo
byte[] NintendoLogo = Convert.FromBase64String("JP+uUWmaoiE9hIIKhOQJrREki5jAgX8ho1K+GZMJziAQRkpK+Ccx7FjH6DOC486/hfTflM5LCcGUVorAE3Kn/J+ETXOjypphWJejJ/wDmHYjHcdhAwSuVr84hABApw79/1L+A2+VMPGX+8CFYNaAJaljvgMBTjji+aI0/7s+A0R4AJDLiBE6lGXAfGOH8Dyv1iXkizgKrHIh1PgH");
if (!ByteArrayCompare(payload,4,NintendoLogo,0,NintendoLogo.Length)) {
Console.WriteLine("The payload file is not a valid GBA binary (bad Nintendo logo)");
return;
}
// check the length
if (payload.Length > 31872) {
Console.WriteLine("The payload file is too big. Payload files to be patched in to the ISO can not be larger than 31872 bytes.");
return;
}
// open the file
FileStream fs;
try {
fs = new FileStream(args[0],FileMode.Open,FileAccess.ReadWrite);
} catch (Exception e) {
Console.WriteLine("An error occured when opening the ISO.");
Console.WriteLine(e.ToString());
return;
}

// make sure this ISO is the right one
byte[] gameCodeBytes = new byte[6];
try {
fs.Read(gameCodeBytes,0,6);
} catch (Exception e) {
fs.Close();
Console.WriteLine("An error occured when reading the game code from the ISO.");
Console.WriteLine(e.ToString());
return;
}
if (Encoding.ASCII.GetString(gameCodeBytes) != "D79E01") {
fs.Close();
Console.WriteLine("This ISO is not Interactive Multi-Game Demo Disc Version 16 (USA)!");
return;
}
// patch the jumps
foreach (long offset in new long[] { 0x45ded5fc, 0x45ecdf1c }) {
try {
fs.Seek(offset,SeekOrigin.Begin);
fs.WriteByte(0x48);
fs.WriteByte(0x00);
} catch (Exception e) {
fs.Close();
Console.WriteLine("An error occured when patching the Berry Glitch fix executable in the ISO.");
Console.WriteLine(e.ToString());
return;
}
}
// patch the payload
try {
fs.Seek(0x45f2ae30,SeekOrigin.Begin);
fs.Write(payload,0,payload.Length);
} catch (Exception e) {
fs.Close();
Console.WriteLine("An error occured when patching the multiboot payload in the ISO.");
Console.WriteLine(e.ToString());
return;
}
fs.Close();
Console.WriteLine("The ISO has been patched successfully and now contains your payload and works with any Gen 3 game.");
}
}

To compile it, just save it out as replace_payload.cs, open up a command prompt window in the directory you saved it to and run C:\windows\Microsoft.NET\Framework\v4.0.30319\csc replace_payload.cs (for .NET 4.x) or C:\windows\Microsoft.NET\Framework\v2.0.50727\csc replace_payload.cs (for .NET 2.x). It supports both.

You should also be able to use mono in other operating systems too, I believe there the command would be msc replace_payload.cs
(you can also use the official MS .NET Framework in wine if that's your thing.)

It's a command line executable, just run it like replace_payload.exe "Interactive Multi-Game Demo Disc Version 16 (USA) - Copy.iso" gba_pkjb.gba

Obviously replace the ISO and multiboot image paths as appropriate. Run it on a copy of the ISO as it will overwrite the ISO.
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Yeniaul

  • Guest
Re: Gen III Remote Code Execution
« Reply #10 on: February 21, 2017, 09:27:04 am »
Remember, look at how the encryption behaves, not how it works.

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #11 on: February 21, 2017, 03:01:50 pm »
New commits, added FR/LG/E secure-area decryption, party reloading from the loaded save file after calling the payload (so now it's possible to modify the party and have the changes reflected; watch out for the crypto and the checksumming though!), and some helpful macros (GAME_x where x can be RUBY, SAPP, RS, FR, LG, FRLG, EM and LANG_JAPAN) to more easily allow for payloads compatible with all of Gen III.

About "payloads compatible with all of Gen III", here's a Hall of Fame payload. It contains partial savedata structures that are themselves partially from pokeruby. Eventually more complete structures will get integrated into the project.

Code: [Select]
/*
 * Example Gen3-multiboot payload by slipstream/RoL 2017.
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 *
 * payload.c: place where user payload should go :)
 */

#include <gba.h>
#include "payload.h"

typedef struct {
s16 x;
s16 y;
} Coords16;

typedef struct {
s8 mapGroup;
s8 mapNum;
s8 warpId;
s16 x;
s16 y;
} WarpData;

// ugh..

struct PokemonSubstruct0
{
    u16 species;
    u16 heldItem;
    u32 experience;
    u8 ppBonuses;
    u8 friendship;
};

struct PokemonSubstruct1
{
    u16 moves[4];
    u8 pp[4];
};

struct PokemonSubstruct2
{
    u8 hpEV;
    u8 attackEV;
    u8 defenseEV;
    u8 speedEV;
    u8 spAttackEV;
    u8 spDefenseEV;
    u8 cool;
    u8 beauty;
    u8 cute;
    u8 smart;
    u8 tough;
    u8 sheen;
};

struct PokemonSubstruct3
{
 /* 0x00 */ u8 pokerus;
 /* 0x01 */ u8 metLocation;

 /* 0x02 */ u16 metLevel:7;
 /* 0x02 */ u16 metGame:4;
 /* 0x03 */ u16 pokeball:4;
 /* 0x03 */ u16 otGender:1;

 /* 0x04 */ u32 hpIV:5;
 /* 0x04 */ u32 attackIV:5;
 /* 0x05 */ u32 defenseIV:5;
 /* 0x05 */ u32 speedIV:5;
 /* 0x05 */ u32 spAttackIV:5;
 /* 0x06 */ u32 spDefenseIV:5;
 /* 0x07 */ u32 isEgg:1;
 /* 0x07 */ u32 altAbility:1;

 /* 0x08 */ u32 coolRibbon:3;
 /* 0x08 */ u32 beautyRibbon:3;
 /* 0x08 */ u32 cuteRibbon:3;
 /* 0x09 */ u32 smartRibbon:3;
 /* 0x09 */ u32 toughRibbon:3;
 /* 0x09 */ u32 championRibbon:1;
 /* 0x0A */ u32 winningRibbon:1;
 /* 0x0A */ u32 victoryRibbon:1;
 /* 0x0A */ u32 artistRibbon:1;
 /* 0x0A */ u32 effortRibbon:1;
 /* 0x0A */ u32 giftRibbon1:1;
 /* 0x0A */ u32 giftRibbon2:1;
 /* 0x0A */ u32 giftRibbon3:1;
 /* 0x0A */ u32 giftRibbon4:1;
 /* 0x0B */ u32 giftRibbon5:1;
 /* 0x0B */ u32 giftRibbon6:1;
 /* 0x0B */ u32 giftRibbon7:1;
 /* 0x0B */ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald
};

union PokemonSubstruct
{
    struct PokemonSubstruct0 type0;
    struct PokemonSubstruct1 type1;
    struct PokemonSubstruct2 type2;
    struct PokemonSubstruct3 type3;
    u16 raw[6];
};

// yes, I know, international lengths, who cares..
#define POKEMON_NAME_LENGTH 10
#define OT_NAME_LENGTH 7

struct BoxPokemon
{
    u32 personality;
    u32 otId;
    u8 nickname[POKEMON_NAME_LENGTH];
    u8 language;
    u8 isBadEgg:1;
    u8 hasSpecies:1;
    u8 isEgg:1;
    u8 unused:5;
    u8 otName[OT_NAME_LENGTH];
    u8 markings;
    u16 checksum;
    u16 unknown;

    union
    {
        u32 raw[12];
        union PokemonSubstruct substructs[4];
    } secure;
};

struct Pokemon
{
    struct BoxPokemon box;
    u32 status;
    u8 level;
    u8 pokerus;
    u16 hp;
    u16 maxHP;
    u16 attack;
    u16 defense;
    u16 speed;
    u16 spAttack;
    u16 spDefense;
};

typedef struct {
Coords16 pos;
WarpData location;
WarpData warps[4];
u16 battleMusic;
u8 weather;
u8 unk_2F;
u8 flashUsed;
u16 mapDataID;
// there's a better way to do this, but for PoC purposes it's fine
union {
struct {
u16 mapView[0x100];
u8 playerPartyCount;
struct Pokemon party[6];
} rse;
struct {
u8 playerPartyCount;
struct Pokemon party[6];
} frlg;
} version;
} partialSaveBlock1;

// Your payload code should obviously go into the body of this, the payload function.
void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
// HoF-warp example payload!
partialSaveBlock1* psb1 = (partialSaveBlock1*)SaveBlock1;
if (GAME_FRLG) {
psb1->location.mapGroup = 1; // generic indoors?
psb1->location.mapNum = 80; // Hall of Fame
// set coords to the same place that the champions' room script sets them to
psb1->location.x = psb1->pos.x = 5;
psb1->location.y = psb1->pos.y = 12;
psb1->mapDataID = 0xDA; // from HoF map-header
} else {
psb1->location.mapGroup = 16; // Ever Grande City
psb1->location.mapNum = 11; // Hall of Fame
// set coords to the same place that the champions' room script sets them to
psb1->location.x = psb1->pos.x = 7;
psb1->location.y = psb1->pos.y = 16;
psb1->mapDataID = ( GAME_EM ? 298 : 299 ); // from HoF map-header
}
psb1->location.warpId = 0xff;
// make sure the HoF script doesn't crash, which it will do if 0 pokémon
if (!GAME_FRLG) {
if (psb1->version.rse.playerPartyCount == 0) {
psb1->version.rse.playerPartyCount = 1;
// this isn't enough, the heal animation recalculates the party count ignoring empty spots
// so let's hack together one. i don't care about it becoming a bad egg at all.
psb1->version.rse.party[0].box.personality++;
}
} else {
if (psb1->version.frlg.playerPartyCount == 0) {
psb1->version.frlg.playerPartyCount = 1;
// this isn't enough, the heal animation recalculates the party count ignoring empty spots
// so let's hack together one. i don't care about it becoming a bad egg at all.
psb1->version.frlg.party[0].box.personality++;
}
}
}

Also on the to-do list: Pokémon data structure element getters/setter functions (yaknow, to deal with the substructures and the crypto and the checksumming).
« Last Edit: February 21, 2017, 03:08:00 pm by Wack0 »
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #12 on: February 26, 2017, 08:44:59 am »
New major commit.

  • Added save-block structure definitions
  • Added a helper library, includes functions for decrypting and encrypting Pokémon structures (encrypting also fixes the checksum); a function to get a Pokémon substructure (it's less than 10% of the size of the original!); helper functions for getting specific substructures; functions for calculating and fixing a Pokémon's checksum (in case you want to do this manually); functions for calculating Enigma Berry checksums; and a function for calculating a ramscript (that feature that overrides NPC scripts) checksum.
  • Changed the example payload, it's now an adapted version of the one in the previous post that warps to the Hall of Fame, that way the example is the ideal of how a payload should look (supporting all R/S/FR/LG/E, etc).

Now, writing payloads should be easier.

Here's another example payload that adds a ramscript, which replaces Brendan's mother's script (R/S/E)/Red's mother's script (FR/LG), causing them to say "Pwned!". (Yes, I know you won't be able to see it if you're playing R/S/E as May, but really, it's such a small change that you should be able to figure it out pretty easily.)

Code: [Select]
/*
 * Example Gen3-multiboot payload by slipstream/RoL 2017.
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 *
 * payload.c: place where user payload should go :)
 */

#include <gba.h>
#include <string.h>
#include "payload.h"

// Your payload code should obviously go into the body of this, the payload function.
void payload(pSaveBlock1 SaveBlock1,pSaveBlock2 SaveBlock2,pSaveBlock3 SaveBlock3) {
struct RamScript* ramScript;
if (GAME_RS) ramScript = &(SaveBlock1->rs.ramScript);
else if (GAME_FRLG) ramScript = &(SaveBlock1->frlg.ramScript);
else if (GAME_EM) ramScript = &(SaveBlock1->e.ramScript);
else return;
ramScript->data.magic = 0x33;
if (GAME_FRLG) {
ramScript->data.mapGroup = 4; // Pallet Town indoors
ramScript->data.mapNum = 0; // Red's house 1F
ramScript->data.objectId = 1; // Red's mother
} else {
ramScript->data.mapGroup = 1; // Littleroot Town indoors
ramScript->data.mapNum = 0; // Brendan's house 1F
ramScript->data.objectId = 1; // Brendan's mother
}
u8 script[] = ""
"\xb8\x00\x00\x00\x00" // setvaddress 0
"\xbd\x0e\x00\x00\x00" // vtext msgtext
"\x66" // waittext
"\x6d" // waitbutton
"\x6c" // release
"\x02" // end
"\xCA\xEB\xE2\xD9\xD8\xAB\xFF"; // msgtext: "Pwned!"
// copy the script to its rightful place
memcpy(&(ramScript->data.script),script,sizeof(script));
// fix the checksum
ramScript->checksum = CalculateRamScriptChecksum(ramScript);
// all done!
return;
}
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016

suloku

  • GCLF Member
  • Offline Offline
  • CHARIZRAD 'M ROXORX or is it.
    • View Profile
Re: Gen III Remote Code Execution
« Reply #13 on: March 18, 2017, 07:44:44 am »
A little of topic here, but since you reversed the transfered rom and know how game detection works, modifiying the colosseum USA/JAP bonus disc to accept other region carts would be feasible? I'd really like to test that. I checked a little the code, do they only use gamecodes for that?

Another technique that might be useful is to take advantage of the Mystery Events feature that overrides an NPC script (used to install Norman’s Eon Ticket script). By storing a script that uses the callasm command, you could execute code on demand by talking to a particular NPC.

By writing such a script into the save file using multiboot, it might be possible to do this even in games where Mystery Events is unavailable (FireRed/LeafGreen and non-Japanese Emerald).

It is, in fact I found that Emerald/FRLG seem to use the same slot for mistery gift script for the WonderCard script (not really checked with jap versions, since the only mistery gift script was for RS, as eon ticket in emerald is hardcoded and mistery gift only enabled an in-game flag).

I'm not sure if this reachead Glitch City, but I coded a program to create custom wondercards, and what you suggest can easily be done with a wondercard too, meaning you could even send the script+asm to other people via the wifi adapter. There's 992 bytes for the script available if I remember correctly, and it can easily be assigned to another npc.

Wack0

  • Coder, reverser, beta collector [BetaArchive staff]
  • Staff
  • *****
  • Offline Offline
  • Gender: Male
  • cBRH - Doing nothing since 2k7
    • View Profile
Re: Gen III Remote Code Execution
« Reply #14 on: March 18, 2017, 03:34:58 pm »
A little of topic here, but since you reversed the transfered rom and know how game detection works, modifiying the colosseum USA/JAP bonus disc to accept other region carts would be feasible? I'd really like to test that. I checked a little the code, do they only use gamecodes for that?

I reversed the transfer process itself, not any transfered multiboot images.
C H E C K E D . B U I L D S . A R E . A W E S O M E N E S S

BetaArchiveSoftHistory Forumsirc.rol.im #galaxy,#softhistory

Also known as The Distractor.

Shane, please stop telling children that there's a Mew outside under the delivery trucks. - Management

Pokémon: arbitrary code execution 1996-2016