From 5a9c66ea87a9d5209ead6b1cfeafb0b69552421d Mon Sep 17 00:00:00 2001 From: Aiden Isik Date: Mon, 13 Jan 2025 19:39:44 +0000 Subject: [PATCH] Initial commit --- build.sh | 7 ++ cause360error.s | 231 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100755 build.sh create mode 100644 cause360error.s diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..78abee6 --- /dev/null +++ b/build.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +fcx-as -o cause360error.o -mregnames -a32 -mppc64 cause360error.s + +fcx-ld --accept-unknown-input-arch --oformat=pei-i386 --subsystem xbox --major-subsystem-version 1 --minor-subsystem-version 0 --major-os-version 0 --minor-os-version 0 --section-alignment=0x10000 --file-alignment 512 --disable-dynamicbase --image-base 0x82000000 --disable-long-section-names -e _start -o cause360error.exe cause360error.o + +synthxex --skip-machine-check --input cause360error.exe --output cause360error.xex diff --git a/cause360error.s b/cause360error.s new file mode 100644 index 0000000..fae4d6d --- /dev/null +++ b/cause360error.s @@ -0,0 +1,231 @@ +# Assembly program to make the Xbox 360 display an error code +# +# Copyright (c) 2025 Aiden Isik +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +.global _start + +# Code +.text + +# Read 32-bit little endian value and byte-swap it +# IN: r4 == base address of little endian value +# IN: LR == address to return to +# OUT: r4 == read and byteswapped value +get32BitLittleEndian: + # r5 == how many bytes to left shift each value read + # r6 == working register used to store currently retrieved bytes + # r7 == register to store current byte before shift + + li r5, 24 # Register storing how many bits to shift each value + + # Most significant byte + lbz r6, 3(r4) + slw r6, r6, r5 + subi r5, r5, 8 + + lbz r7, 2(r4) + slw r7, r7, r5 + subi r5, r5, 8 + or r6, r6, r7 + + lbz r7, 1(r4) + slw r7, r7, r5 + or r6, r6, r7 + + # Least significant byte + lbz r7, 0(r4) + or r6, r6, r7 + + mr r4, r6 # Final value + blr + + +# If the function was not found, return 0 (set r3 = 0, then return) +# IN: r12 == address to return to +# OUT: r3 == 0 +kernelFunctionNotFound: + li r3, 0 + mtlr r12 + blr + + +# So I don't know if this works or not: it turns out the kernel does NOT have an export name table +# Keeping this here in case it's useful in the future for something else + +# Getting function address by name +# IN: r3 == address of name string of function +# IN: LR == address to return to +# OUT: r3 == address of kernel function (or 0 if it could not be found) +getKernelFunctionAddrByName: + mflr r12 + + # Getting the address of the PE header + lis r4, 0x8004 + ori r4, r4, 0x3C + + bl get32BitLittleEndian + addis r4, r4, 0x8004 # Final address (RVA + kernel base address) + + # Getting the address of the export directory table + addi r4, r4, 0x78 + bl get32BitLittleEndian + addis r4, r4, 0x8004 # Final address (RVA + kernel base address) + + # Get number of name pointers (and put it in CTR) + mr r8, r4 + addi r4, r4, 0x18 + bl get32BitLittleEndian + mtctr r4 + + # Get addresses of the name pointer table and the ordinal table + addi r9, r8, 0x20 # Name pointer table RVA address + addi r4, r8, 0x24 # Ordinal table RVA address + + bl get32BitLittleEndian + addis r10, r4, 0x8004 # Ordinal table address + + mr r4, r9 + bl get32BitLittleEndian + addis r4, r4, 0x8004 # Name pointer table address + + # At this point, r4 contains the name pointer table address, and r10 contains the ordinal table address + # r0 (with care), r8, r9 and r11 are free to use. r5, r6 and r7 are used by get32BitLittleEndian, + # r12 is used for our return address, and r3 contains the function name's address. + + # We *could* do a binary search here, since this table is alphabetically sorted. + # However, I don't see the marginal speed increase being worth the effort in this case. + # We're also looping backwards here, just because it's easier. + +namePointerTableLoop: + # Getting the address to the current name and putting it in r8 + mfctr r8 + subi r8, r8, 1 + mulli r8, r8, 4 + add r8, r4, r8 + + li r11, 0 +functionNameLoop: + # Putting characters to compare in r8 and r9, respectively + # r11 is our character offset + lbzx r8, r4, r11 + lbzx r9, r3, r11 + addi r11, r11, 1 + + # Checking if characters match, if they don't, move onto the next entry + cmpw cr0, r8, r9 + bne checkNextNameEntry + + # If both characters are \0, we found our function in the table (as the whole string matches) + cmpwi cr0, r8, 0 + beq getCorrespondingOrdinalToNameEntry + + # Next character + beq functionNameLoop + +checkNextNameEntry: + bdnz namePointerTableLoop + + # If we get here, we didn't find the function name in the table. + b kernelFunctionNotFound + +getCorrespondingOrdinalToNameEntry: + # At this point, we have our entry to the ordinal table in CTR. + # Convert it to the address of the entry in the ordinal table + mfctr r8 + subi r8, r8, 1 + mulli r8, r8, 4 + add r4, r8, r10 + + # Get the ordinal at that address in the ordinal table + bl get32BitLittleEndian + + # Finally, get the address of the function using the ordinal + mr r3, r4 + mtlr r12 + b getKernelFunctionAddrByOrdinal + + +# Getting function address by ordinal +# IN: r3 == ordinal number +# IN: LR == address to return to +# OUT: r3 == address of kernel function (or 0 if it could not be found) +getKernelFunctionAddrByOrdinal: + mflr r12 + + # Getting the address of the PE header + lis r4, 0x8004 + ori r4, r4, 0x3C + + bl get32BitLittleEndian + addis r4, r4, 0x8004 # Final address (RVA + kernel base address) + + # Getting the address of the export directory table + addi r4, r4, 0x78 + bl get32BitLittleEndian + addis r4, r4, 0x8004 # Final address (RVA + kernel base address) + + # Making sure the ordinal exists (ordinal is not greater than or equal to export count) + mr r8, r4 # Putting export directory table address into a register unused by get32BitLittleEndian + addi r4, r4, 0x14 # Address of export count + + bl get32BitLittleEndian # Get export count + cmpw r3, r4 + bgt kernelFunctionNotFound # Ordinal does not exist + + # Get address of the export address table, and retrieve the address of our function + subi r3, r3, 1 # Converting ordinal into kernel EAT index + + addi r4, r8, 0x1C # Put address of RVA to EAT into r4 + bl get32BitLittleEndian # Get RVA to EAT + addis r4, r4, 0x8004 # Address + + # Finally, read our address from the export address table and return it + mulli r3, r3, 4 # Multiply index by 4 to get export offset + add r4, r4, r3 # Add export offset to EAT address to get export address + bl get32BitLittleEndian + addis r3, r4, 0x8004 # Finally, the address of our function + + mtlr r12 + blr + + +_start: + # Getting address of VdDisplayFatalError function and putting it in CTR to call + li r3, 434 # Ordinal 434 == VdDisplayFatalError + bl getKernelFunctionAddrByOrdinal + + mtctr r3 # Put our acquired address into CTR for calling + + # Clearing the argument-passing registers so we don't pass anything we don't want + # We don't use these for anything else, so it's safe. + li r4, 0 + li r5, 0 + li r6, 0 + li r7, 0 + li r8, 0 + li r9, 0 + li r10, 0 + + # Call with E74 + lis r3, 0x0001 + ori r3, r3, 0x244A + bctr + + # Exit code + # Not implemented yet, and not relevant here specifically, but this is probably what I'll do + # Call XexGetModuleHandle(0 (current executable), address to put handle) + # Then call XexUnloadImage(AndExitThread?)(handle address), to exit + # Would that actually work to stop the program? If it does it could save a lot of effort.