diff --git a/.gitignore b/.gitignore
index 85a49d5..b48f5c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,7 @@
build
-/*.elf
-/*.dol
-
-# Clion files
-.idea
-cmake-build-debug
-CMakeLists.txt
+output
+*.elf
+*.dol
+*.bin
+*.cert
+*.txt
diff --git a/HBC/boot.dol b/HBC/boot.dol
deleted file mode 100644
index d837663..0000000
Binary files a/HBC/boot.dol and /dev/null differ
diff --git a/HBC/boot.elf b/HBC/boot.elf
deleted file mode 100644
index 98369e3..0000000
Binary files a/HBC/boot.elf and /dev/null differ
diff --git a/HBC/meta.xml b/HBC/meta.xml
index 7bd821b..4aa109d 100644
--- a/HBC/meta.xml
+++ b/HBC/meta.xml
@@ -1,8 +1,8 @@
Xyzzy
- 1.3.1
- 20220713022030
+ 1.3.2
+ 20220718184500
Bushing, DarkMatterCore
Extract your Wii console keys!
Xyzzy is a homebrew application that allows the extraction of the OTP and SEEPROM Encryption Keys.
@@ -15,9 +15,10 @@ Other changes include:
* Support for GCN controllers and newer WiiMotes.
* Retrieves SD IV, MD5 Blanker and MAC address.
* Besides generating a "keys.txt" file with a hexdump of every dumped key, which follows the format required by wad2bin (https://github.com/DarkMatterCore/wad2bin), these files are also created:
- * "bootmii_keys.bin" (follows the BootMii keys.bin format).
* "device.cert" (raw device certificate dump).
* "otp.bin" (raw OTP memory dump).
- * "seeprom.bin" (raw SEEPROM memory dump) (Wii only).
+ * "seeprom.bin" (raw SEEPROM memory dump) (Wii only).
+ * "bootmii_keys.bin" (follows the BootMii keys.bin format) (Wii only).
+ * "boot0.bin" (raw boot0 Mask ROM dump) (Wii only).
diff --git a/README.md b/README.md
index 1f39203..a7105f7 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,8 @@ Other changes include:
* Support for GCN controllers and newer WiiMotes.
* Retrieves SD IV, MD5 Blanker and MAC address.
* Besides generating a "keys.txt" file with a hexdump of every dumped key, which follows the format required by [wad2bin](https://github.com/DarkMatterCore/wad2bin), these files are also created:
- * "bootmii_keys.bin" (follows the BootMii keys.bin format).
* "device.cert" (raw device certificate dump).
* "otp.bin" (raw OTP memory dump).
* "seeprom.bin" (raw SEEPROM memory dump) (Wii only).
+ * "bootmii_keys.bin" (follows the BootMii keys.bin format) (Wii only).
+ * "boot0.bin" (raw boot0 Mask ROM dump) (Wii only).
diff --git a/source/aes.c b/source/aes.c
index 99ec0f0..b82a542 100644
--- a/source/aes.c
+++ b/source/aes.c
@@ -19,7 +19,6 @@
*/
#include
-#include
#include
#include
@@ -748,7 +747,7 @@ void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
rk[1] = GETU32(cipherKey + 4);
rk[2] = GETU32(cipherKey + 8);
rk[3] = GETU32(cipherKey + 12);
-
+
for (i = 0; i < 10; i++)
{
temp = rk[3];
@@ -770,7 +769,7 @@ void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
/* expand the cipher key: */
rijndaelKeySetupEnc(rk, cipherKey);
-
+
/* invert the order of the round keys: */
for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4)
{
@@ -779,7 +778,7 @@ void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
}
-
+
/* apply the inverse MixColumn transform to all round keys but the first and the last: */
for (i = 1; i < Nr; i++)
{
@@ -808,15 +807,15 @@ void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
s1 = GETU32(pt + 4) ^ rk[1];
s2 = GETU32(pt + 8) ^ rk[2];
s3 = GETU32(pt + 12) ^ rk[3];
-
+
#define ROUND(i,d,s) \
d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
-
+
#ifdef FULL_UNROLL
-
+
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
@@ -826,11 +825,11 @@ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
-
+
rk += Nr << 2;
-
+
#else /* !FULL_UNROLL */
-
+
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;)
@@ -840,11 +839,11 @@ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
if (--r == 0) break;
ROUND(0,s,t);
}
-
+
#endif /* ?FULL_UNROLL */
-
+
#undef ROUND
-
+
/*
* apply last round and
* map cipher state to byte array block:
@@ -875,15 +874,15 @@ void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
s1 = GETU32(ct + 4) ^ rk[1];
s2 = GETU32(ct + 8) ^ rk[2];
s3 = GETU32(ct + 12) ^ rk[3];
-
+
#define ROUND(i,d,s) \
d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
-
+
#ifdef FULL_UNROLL
-
+
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
@@ -895,9 +894,9 @@ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
ROUND(9,t,s);
rk += Nr << 2;
-
+
#else /* !FULL_UNROLL */
-
+
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;)
@@ -907,11 +906,11 @@ d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
if (--r == 0) break;
ROUND(0,s,t);
}
-
+
#endif /* ?FULL_UNROLL */
#undef ROUND
-
+
/*
* apply last round and
* map cipher state to byte array block:
@@ -930,14 +929,14 @@ void *aes_init(const u8 *key, bool Enc)
{
u32 *rk = malloc(AES_PRIV_SIZE);
if (rk == NULL) return NULL;
-
+
if (Enc)
{
rijndaelKeySetupEnc(rk, key);
} else {
rijndaelKeySetupDec(rk, key);
}
-
+
return rk;
}
@@ -961,12 +960,12 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
u8 cbc[AES_BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
-
+
ctx = aes_init(key, true);
if (ctx == NULL) return -1;
-
+
memcpy(cbc, iv, AES_BLOCK_SIZE);
-
+
blocks = data_len / AES_BLOCK_SIZE;
for (i = 0; i < blocks; i++)
{
@@ -975,7 +974,7 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
memcpy(pos, cbc, AES_BLOCK_SIZE);
pos += AES_BLOCK_SIZE;
}
-
+
aes_deinit(ctx);
return 0;
}
@@ -994,12 +993,12 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
-
+
ctx = aes_init(key, false);
if (ctx == NULL) return -1;
-
+
memcpy(cbc, iv, AES_BLOCK_SIZE);
-
+
blocks = data_len / AES_BLOCK_SIZE;
for (i = 0; i < blocks; i++)
{
@@ -1009,7 +1008,7 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
memcpy(cbc, tmp, AES_BLOCK_SIZE);
pos += AES_BLOCK_SIZE;
}
-
+
aes_deinit(ctx);
return 0;
}
diff --git a/source/boot0.c b/source/boot0.c
new file mode 100644
index 0000000..d7e7597
--- /dev/null
+++ b/source/boot0.c
@@ -0,0 +1,78 @@
+#include
+#include
+#include
+
+#include "boot0.h"
+#include "tools.h"
+
+#define SRAM_MIRROR 0xD400000
+
+#define HW_SRNPROT 0xD800060
+#define SRAM_MASK 0x20
+
+#define HW_BOOT0 0xD80018C
+#define BOOT0_MASK 0x1000
+
+#define BOOT0_BLK_SIZE 4
+
+u16 boot0_read(void *dst, u16 offset, u16 size)
+{
+ if (!dst || offset >= BOOT0_SIZE || !size || (offset + size) > BOOT0_SIZE) return 0;
+
+ u8 *ptr = (u8*)dst;
+ u8 val[BOOT0_BLK_SIZE] = {0};
+ u16 cur_offset = 0;
+ bool disable_sram_mirror = false;
+
+ // Calculate block offsets and sizes
+ u32 start_addr = (SRAM_MIRROR + ALIGN_DOWN(offset, BOOT0_BLK_SIZE));
+ u8 start_addr_offset = (offset % BOOT0_BLK_SIZE);
+
+ u32 end_addr = (SRAM_MIRROR + ALIGN_UP(offset + size, BOOT0_BLK_SIZE));
+ u8 end_addr_size = ((offset + size) % BOOT0_BLK_SIZE);
+
+ // Make sure the SRAM mirror is enabled (unlikely to be disabled, but let's play it safe)
+ if (!(read32(HW_SRNPROT) & SRAM_MASK))
+ {
+ // Enable SRAM mirror
+ mask32(HW_SRNPROT, 0, SRAM_MASK);
+ disable_sram_mirror = true;
+ }
+
+ // Enable boot0
+ mask32(HW_BOOT0, BOOT0_MASK, 0);
+
+ for(u32 addr = start_addr; addr < end_addr; addr += BOOT0_BLK_SIZE)
+ {
+ if (cur_offset >= size) break;
+
+ // Read SRAM mirror (actually holds boot0 data)
+ *((u32*)val) = read32(addr);
+
+ // Copy data to destination buffer
+ if (addr == start_addr && start_addr_offset != 0)
+ {
+ // Handle unaligned read at start address
+ memcpy(ptr + cur_offset, val + start_addr_offset, BOOT0_BLK_SIZE - start_addr_offset);
+ cur_offset += (BOOT0_BLK_SIZE - start_addr_offset);
+ } else
+ if (addr >= (end_addr - BOOT0_BLK_SIZE) && end_addr_size != 0)
+ {
+ // Handle unaligned read at end address
+ memcpy(ptr + cur_offset, val, end_addr_size);
+ cur_offset += end_addr_size;
+ } else {
+ // Normal read
+ memcpy(ptr + cur_offset, val, BOOT0_BLK_SIZE);
+ cur_offset += BOOT0_BLK_SIZE;
+ }
+ }
+
+ // Disable boot0
+ mask32(HW_BOOT0, 0, BOOT0_MASK);
+
+ // Disable SRAM mirror, if needed
+ if (disable_sram_mirror) mask32(HW_SRNPROT, SRAM_MASK, 0);
+
+ return cur_offset;
+}
diff --git a/source/boot0.h b/source/boot0.h
new file mode 100644
index 0000000..49ec830
--- /dev/null
+++ b/source/boot0.h
@@ -0,0 +1,8 @@
+#ifndef __BOOT0_H__
+#define __BOOT0_H__
+
+#define BOOT0_SIZE 0x1000
+
+u16 boot0_read(void *dst, u16 offset, u16 size);
+
+#endif /* __BOOT0_H__ */
diff --git a/source/main.c b/source/main.c
index 298153b..9052d32 100644
--- a/source/main.c
+++ b/source/main.c
@@ -1,4 +1,3 @@
-#include
#include
#include
#include
@@ -13,16 +12,16 @@ int XyzzyGetKeys(bool vWii);
int main(int argc, char **argv)
{
__exception_setreload(10);
-
+
int ret = 0;
-
+
InitConsole();
InitPads();
-
+
bool vWii = IsWiiU();
-
+
PrintHeadline();
-
+
/* HW_AHBPROT check */
if (AHBPROT_DISABLED)
{
@@ -48,10 +47,10 @@ int main(int argc, char **argv)
printf("without full hardware access rights.\n");
printf("\nProcess cannot continue. Press any button to exit.");
}
-
+
if (ret != -2) WaitForButtonPress(NULL, NULL);
-
+
Reboot();
-
+
return 0;
}
diff --git a/source/mini_seeprom.c b/source/mini_seeprom.c
index c9888c1..e91aec8 100644
--- a/source/mini_seeprom.c
+++ b/source/mini_seeprom.c
@@ -37,7 +37,7 @@ enum {
static void seeprom_send_bits(u16 value, u8 bits)
{
if (!bits || bits > 16) return;
-
+
while(bits--)
{
if (value & (1 << bits))
@@ -46,12 +46,12 @@ static void seeprom_send_bits(u16 value, u8 bits)
} else {
mask32(HW_GPIO1OUT, GP_EEP_MOSI, 0);
}
-
+
eeprom_delay();
-
+
mask32(HW_GPIO1OUT, 0, GP_EEP_CLK);
eeprom_delay();
-
+
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
eeprom_delay();
}
@@ -60,70 +60,70 @@ static void seeprom_send_bits(u16 value, u8 bits)
static u16 seeprom_recv_bits(u8 bits)
{
if (!bits || bits > 16) return 0;
-
+
int res = 0;
-
+
while(bits--)
{
res <<= 1;
-
+
mask32(HW_GPIO1OUT, 0, GP_EEP_CLK);
eeprom_delay();
-
+
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
eeprom_delay();
-
+
res |= !!(read32(HW_GPIO1IN) & GP_EEP_MISO);
}
-
+
return (u16)res;
}
u16 seeprom_read(void *dst, u16 offset, u16 size)
{
if (!dst || offset >= SEEPROM_SIZE || !size || (offset + size) > SEEPROM_SIZE) return 0;
-
+
u16 cur_offset = 0;
-
+
u8 *ptr = (u8*)dst;
u8 val[HW_SEEPROM_BLK_SIZE] = {0};
-
+
// Calculate block offsets and sizes
u8 start_addr = (u8)(offset / HW_SEEPROM_BLK_SIZE);
u8 start_addr_offset = (u8)(offset % HW_SEEPROM_BLK_SIZE);
-
+
u8 end_addr = (u8)((offset + size) / HW_SEEPROM_BLK_SIZE);
u8 end_addr_size = (u8)((offset + size) % HW_SEEPROM_BLK_SIZE);
-
+
if (!end_addr_size)
{
end_addr--;
end_addr_size = HW_SEEPROM_BLK_SIZE;
}
-
+
if (end_addr == start_addr) end_addr_size -= start_addr_offset;
-
+
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
for(u16 i = start_addr; i <= end_addr; i++)
{
if (cur_offset >= size) break;
-
+
// Start command cycle
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
-
+
// Send read command + address
seeprom_send_bits(0x600 | i, 11);
-
+
// Receive data
*((u16*)val) = seeprom_recv_bits(16);
-
+
// End of command cycle
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
// Copy read data to destination buffer
if (i == start_addr && start_addr_offset != 0)
{
@@ -142,70 +142,70 @@ u16 seeprom_read(void *dst, u16 offset, u16 size)
cur_offset += HW_SEEPROM_BLK_SIZE;
}
}
-
+
return cur_offset;
}
u16 seeprom_write(const void *src, u16 offset, u16 size)
{
if (!src || offset >= SEEPROM_SIZE || !size || (offset + size) > SEEPROM_SIZE) return 0;
-
+
u32 level = 0;
u16 cur_offset = 0;
-
+
const u8 *ptr = (const u8*)src;
u8 val[HW_SEEPROM_BLK_SIZE] = {0};
-
+
// Calculate block offsets and sizes
u8 start_addr = (u8)(offset / HW_SEEPROM_BLK_SIZE);
u8 start_addr_offset = (u8)(offset % HW_SEEPROM_BLK_SIZE);
-
+
u8 end_addr = (u8)((offset + size) / HW_SEEPROM_BLK_SIZE);
u8 end_addr_size = (u8)((offset + size) % HW_SEEPROM_BLK_SIZE);
-
+
if (!end_addr_size)
{
end_addr--;
end_addr_size = HW_SEEPROM_BLK_SIZE;
}
-
+
if (end_addr == start_addr) end_addr_size -= start_addr_offset;
-
+
// Disable CPU interruptions
_CPU_ISR_Disable(level);
-
+
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
// EWEN - Enable programming commands
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
seeprom_send_bits(0x4FF, 11);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
for(u16 i = start_addr; i <= end_addr; i++)
{
if (cur_offset >= size) break;
-
+
// Copy data to write from source buffer
if ((i == start_addr && start_addr_offset != 0) || (i == end_addr && end_addr_size != HW_SEEPROM_BLK_SIZE))
{
// Read data from SEEPROM to handle unaligned writes
-
+
// Start command cycle
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
-
+
// Send read command + address
seeprom_send_bits(0x600 | i, 11);
-
+
// Receive data
*((u16*)val) = seeprom_recv_bits(16);
-
+
// End of command cycle
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
if (i == start_addr && start_addr_offset != 0)
{
// Handle unaligned write at start address
@@ -221,39 +221,39 @@ u16 seeprom_write(const void *src, u16 offset, u16 size)
memcpy(val, ptr + cur_offset, HW_SEEPROM_BLK_SIZE);
cur_offset += HW_SEEPROM_BLK_SIZE;
}
-
+
// Start command cycle
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
-
+
// Send write command + address
seeprom_send_bits(0x500 | i, 11);
-
+
// Send data
seeprom_send_bits(*((u16*)val), 16);
-
+
// End of command cycle
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
// Wait until SEEPROM is ready (write cycle is self-timed so no clocking needed)
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
-
+
do {
eeprom_delay();
} while(!(read32(HW_GPIO1IN) & GP_EEP_MISO));
-
+
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
}
-
+
// EWDS - Disable programming commands
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
seeprom_send_bits(0x400, 11);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
-
+
// Enable CPU interruptions
_CPU_ISR_Restore(level);
-
+
return cur_offset;
}
diff --git a/source/otp.c b/source/otp.c
index 0028863..c52d708 100644
--- a/source/otp.c
+++ b/source/otp.c
@@ -13,37 +13,37 @@
u8 otp_read(void *dst, u8 offset, u8 size)
{
if (!dst || offset >= OTP_SIZE || !size || (offset + size) > OTP_SIZE) return 0;
-
+
u8 cur_offset = 0;
-
+
u8 *ptr = (u8*)dst;
u8 val[HW_OTP_BLK_SIZE] = {0};
-
+
// Calculate block offsets and sizes
u8 start_addr = (offset / HW_OTP_BLK_SIZE);
u8 start_addr_offset = (offset % HW_OTP_BLK_SIZE);
-
+
u8 end_addr = ((offset + size) / HW_OTP_BLK_SIZE);
u8 end_addr_size = ((offset + size) % HW_OTP_BLK_SIZE);
-
+
if (!end_addr_size)
{
end_addr--;
end_addr_size = HW_OTP_BLK_SIZE;
}
-
+
if (end_addr == start_addr) end_addr_size -= start_addr_offset;
-
+
for(u8 i = start_addr; i <= end_addr; i++)
{
if (cur_offset >= size) break;
-
+
// Send command + address
HW_OTP_COMMAND = (0x80000000 | i);
-
+
// Receive data
*((u32*)val) = HW_OTP_DATA;
-
+
// Copy read data to destination buffer
if (i == start_addr && start_addr_offset != 0)
{
@@ -62,6 +62,6 @@ u8 otp_read(void *dst, u8 offset, u8 size)
cur_offset += HW_OTP_BLK_SIZE;
}
}
-
+
return cur_offset;
}
diff --git a/source/tools.c b/source/tools.c
index 59ed0fb..abf4d4f 100644
--- a/source/tools.c
+++ b/source/tools.c
@@ -1,7 +1,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -40,13 +39,13 @@ bool IsWiiU(void)
{
s32 ret = 0;
u32 x = 0;
-
+
ret = ES_GetTitleContentsCount(TITLEID_200, &x);
-
+
if (ret < 0) return false; // Title was never installed
-
+
if (x == 0) return false; // Title was installed but deleted via Channel Management
-
+
return true;
}
@@ -72,18 +71,18 @@ void WaitForButtonPress(u32 *out, u32 *outGC)
{
WPAD_ScanPads();
pressed = (WPAD_ButtonsDown(0) | WPAD_ButtonsDown(1) | WPAD_ButtonsDown(2) | WPAD_ButtonsDown(3));
-
+
PAD_ScanPads();
pressedGC = (PAD_ButtonsDown(0) | PAD_ButtonsDown(1) | PAD_ButtonsDown(2) | PAD_ButtonsDown(3));
-
- if (pressed || pressedGC)
+
+ if (pressed || pressedGC)
{
// Without waiting you can't select anything
if (pressedGC) usleep(20000);
-
+
if (out) *out = pressed;
if (outGC) *outGC = pressedGC;
-
+
break;
}
}
@@ -93,59 +92,59 @@ void InitConsole(void)
{
// Initialise the video system
VIDEO_Init();
-
+
// Obtain the preferred video mode from the system
// This will correspond to the settings in the Wii menu
rmode = VIDEO_GetPreferredMode(NULL);
-
+
// Allocate memory for the display in the uncached region
xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
-
+
// Set up the video registers with the chosen mode
VIDEO_Configure(rmode);
-
+
// Tell the video hardware where our display memory is
VIDEO_SetNextFramebuffer(xfb);
-
+
// Make the display visible
VIDEO_SetBlack(FALSE);
-
+
// Flush the video register changes to the hardware
VIDEO_Flush();
-
+
// Wait for Video setup to complete
VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
-
+
// Set console parameters
int x = 24;
int y = 32;
int w = (rmode->fbWidth - 32);
int h = (rmode->xfbHeight - 48);
-
+
// Initialize the console - CON_InitEx works after VIDEO_ calls
CON_InitEx(rmode, x, y, w, h);
-
+
// Clear the garbage around the edges of the console
VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
-
+
printf("\x1b[%u;%um", 37, false);
}
void PrintHeadline(void)
{
ResetScreen();
-
+
int rows, cols;
CON_GetMetrics(&cols, &rows);
-
+
printf("Xyzzy v%s (unofficial).", VERSION);
-
+
char buf[64];
sprintf(buf, "IOS%d (v%d)", IOS_GetVersion(), IOS_GetRevision());
printf("\x1B[%d;%dH", 0, cols - strlen(buf) - 1);
printf(buf);
-
+
printf("\nOriginal code by bushing (RIP). Maintained by DarkMatterCore.\n\n");
}
@@ -204,13 +203,13 @@ static void UnmountUSB(void)
static int MountUSB(void)
{
UnmountUSB();
-
+
if (!USB_PORT_CONNECTED)
{
return -1;
} else {
bool started = false;
-
+
time_t tStart = time(0);
while((time(0) - tStart) < 10) // 10 seconds timeout
{
@@ -218,14 +217,14 @@ static int MountUSB(void)
if (started) break;
usleep(50000);
}
-
+
if (started)
{
if (!fatMountSimple("usb", &__io_usbstorage)) return -1;
return 0;
}
}
-
+
return -1;
}
@@ -248,24 +247,24 @@ int SelectStorageDevice(void)
{
u32 pressed, pressedGC;
int ret = 0, selection = 0;
-
+
const char *options[] = { "SD card", "USB device" };
const int options_cnt = (sizeof(options) / sizeof(options[0]));
-
+
printf("Press HOME or Start to exit.\n\n");
-
+
while(true)
{
Con_ClearLine();
-
+
printf("Select device: ");
-
+
SetHighlight(true);
printf("< %s >", options[selection]);
SetHighlight(false);
-
+
WaitForButtonPress(&pressed, &pressedGC);
-
+
if (pressed == WPAD_BUTTON_LEFT || pressedGC == PAD_BUTTON_LEFT)
{
if (selection > 0)
@@ -275,7 +274,7 @@ int SelectStorageDevice(void)
selection = (options_cnt - 1);
}
}
-
+
if (pressed == WPAD_BUTTON_RIGHT || pressedGC == PAD_BUTTON_RIGHT)
{
if (selection < (options_cnt - 1))
@@ -285,20 +284,20 @@ int SelectStorageDevice(void)
selection = 0;
}
}
-
+
if (pressed == WPAD_BUTTON_HOME || pressedGC == PAD_BUTTON_START)
{
ret = -2;
break;
}
-
+
if (pressed == WPAD_BUTTON_A || pressedGC == PAD_BUTTON_A) break;
}
-
+
if (ret == -2) return ret;
-
+
printf("\n\nMounting %s...", options[selection]);
-
+
switch(selection)
{
case 0:
@@ -310,7 +309,7 @@ int SelectStorageDevice(void)
default:
break;
}
-
+
if (ret >= 0)
{
printf(" OK!");
@@ -319,16 +318,16 @@ int SelectStorageDevice(void)
printf("\n\t- fatMountSimple failed.");
printf("\n\t- Sorry, not writing keys to %s.", options[selection]);
}
-
+
sleep(2);
-
+
return ret;
}
char *StorageDeviceString(void)
{
char *str = NULL;
-
+
switch(device_type)
{
case STORAGE_DEVICE_TYPE_SD:
@@ -340,14 +339,14 @@ char *StorageDeviceString(void)
default:
break;
}
-
+
return str;
}
char *StorageDeviceMountName(void)
{
char *str = NULL;
-
+
switch(device_type)
{
case STORAGE_DEVICE_TYPE_SD:
@@ -359,21 +358,21 @@ char *StorageDeviceMountName(void)
default:
break;
}
-
+
return str;
}
void HexKeyDump(FILE *fp, void *d, size_t len, bool add_spaces)
{
if (!fp || !d || !len) return;
-
+
size_t i;
u8 *data = (u8*)d;
-
+
for(i = 0; i < len; i++)
{
fprintf(fp, "%02X", data[i]);
-
+
if (add_spaces && (i + 1) < len)
{
if (((i + 1) % 16) > 0)
@@ -389,124 +388,124 @@ void HexKeyDump(FILE *fp, void *d, size_t len, bool add_spaces)
signed_blob *GetSignedTMDFromTitle(u64 title_id, u32 *out_size)
{
if (!out_size) return NULL;
-
+
s32 ret = 0;
signed_blob *stmd = NULL;
bool success = false;
-
+
tmd_tid = title_id;
-
+
ret = ES_GetStoredTMDSize(tmd_tid, &tmd_size);
if (ret < 0)
{
printf("ES_GetStoredTMDSize failed! (%d) (TID %X-%X)\n", ret, TITLE_UPPER(tmd_tid), TITLE_LOWER(tmd_tid));
return NULL;
}
-
+
stmd = (signed_blob*)memalign(32, ALIGN_UP(tmd_size, 32));
if (!stmd)
{
printf("Failed to allocate memory for TMD! (TID %X-%X)\n", TITLE_UPPER(tmd_tid), TITLE_LOWER(tmd_tid));
return NULL;
}
-
+
ret = ES_GetStoredTMD(tmd_tid, stmd, tmd_size);
if (ret < 0)
{
printf("ES_GetStoredTMD failed! (%d) (TID %X-%X)\n", ret, TITLE_UPPER(tmd_tid), TITLE_LOWER(tmd_tid));
goto out;
}
-
+
if (!IS_VALID_SIGNATURE(stmd))
{
printf("Invalid TMD signature! (TID %X-%X)\n", TITLE_UPPER(tmd_tid), TITLE_LOWER(tmd_tid));
goto out;
}
-
+
*out_size = tmd_size;
success = true;
-
+
out:
if (!success && stmd)
{
free(stmd);
stmd = NULL;
}
-
+
return stmd;
}
void *ReadFileFromFlashFileSystem(const char *path, u32 *out_size)
{
if (!path || !strlen(path) || !out_size) return NULL;
-
+
s32 ret = 0;
u8 *buf = NULL;
bool success = false;
-
+
snprintf(isfs_file_path, ISFS_MAXPATH, path);
-
+
isfs_fd = ISFS_Open(isfs_file_path, ISFS_OPEN_READ);
if (isfs_fd < 0)
{
printf("ISFS_Open(\"%s\") failed! (%d)\n", isfs_file_path, isfs_fd);
return NULL;
}
-
+
ret = ISFS_GetFileStats(isfs_fd, &isfs_file_stats);
if (ret < 0)
{
printf("ISFS_GetFileStats(\"%s\") failed! (%d)\n", isfs_file_path, ret);
goto out;
}
-
+
if (!isfs_file_stats.file_length)
{
printf("\"%s\" is empty!\n", isfs_file_path);
goto out;
}
-
+
buf = (u8*)memalign(32, ALIGN_UP(isfs_file_stats.file_length, 32));
if (!buf)
{
printf("Failed to allocate memory for \"%s\"!\n", isfs_file_path);
goto out;
}
-
+
ret = ISFS_Read(isfs_fd, buf, isfs_file_stats.file_length);
if (ret < 0)
{
printf("ISFS_Read(\"%s\") failed! (%d)\n", isfs_file_path, ret);
goto out;
}
-
+
*out_size = isfs_file_stats.file_length;
success = true;
-
+
out:
if (!success && buf)
{
free(buf);
buf = NULL;
}
-
+
ISFS_Close(isfs_fd);
isfs_fd = 0;
-
+
return (void*)buf;
}
bool CheckIfFlashFileSystemFileExists(const char *path)
{
if (!path || !strlen(path)) return NULL;
-
+
snprintf(isfs_file_path, ISFS_MAXPATH, path);
-
+
isfs_fd = ISFS_Open(isfs_file_path, ISFS_OPEN_READ);
if (isfs_fd < 0) return false;
-
+
ISFS_Close(isfs_fd);
isfs_fd = 0;
-
+
return true;
}
diff --git a/source/tools.h b/source/tools.h
index 9fd0208..4e3d6d8 100644
--- a/source/tools.h
+++ b/source/tools.h
@@ -4,8 +4,9 @@
#include
#include
#include
+#include
-#define VERSION "1.3.1"
+#define VERSION "1.3.2"
//#define IsWiiU() (((*(vu32*)0xCD8005A0) >> 16) == 0xCAFE)
#define ResetScreen() printf("\x1b[2J")
@@ -14,7 +15,8 @@
#define TITLE_LOWER(x) ((u32)(x))
#define TITLE_ID(x, y) (((u64)(x) << 32) | (y))
-#define ALIGN_UP(x, y) ((((y) - 1) + (x)) & ~((y) - 1))
+#define ALIGN_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
+#define ALIGN_DOWN(x, y) ((x) & ~((y) - 1))
#define MAX_ELEMENTS(x) (sizeof((x)) / sizeof((x)[0]))
diff --git a/source/xyzzy.c b/source/xyzzy.c
index acfc901..0d90beb 100644
--- a/source/xyzzy.c
+++ b/source/xyzzy.c
@@ -6,9 +6,8 @@
/* Kudos to WiiPower and Arikado for additional init code */
-/* DarkMatterCore - 2020 */
+/* DarkMatterCore - 2020-2022 */
-#include
#include
#include
#include
@@ -19,6 +18,7 @@
#include "mini_seeprom.h"
#include "sha1.h"
#include "aes.h"
+#include "boot0.h"
#define SYSTEM_MENU_TID (u64)0x0000000100000002
@@ -161,9 +161,9 @@ static void OTP_ClearData(void)
static bool OTP_ReadData(void)
{
OTP_ClearData();
-
+
u8 ret = otp_read(otp_ptr, 0, OTP_SIZE);
-
+
return (ret == OTP_SIZE);
}
@@ -175,9 +175,9 @@ static void SEEPROM_ClearData(void)
static bool SEEPROM_ReadData(void)
{
SEEPROM_ClearData();
-
+
u16 ret = seeprom_read(seeprom_ptr, 0, SEEPROM_SIZE);
-
+
return (ret == SEEPROM_SIZE && *(((u32*)seeprom_ptr) + 2) != 0);
}
@@ -188,14 +188,14 @@ static bool FillOTPStruct(otp_t **out)
printf("Fatal error: invalid output OTP struct pointer.\n\n");
return false;
}
-
+
otp_t *otp_data = memalign(32, sizeof(otp_t));
if (!otp_data)
{
printf("Fatal error: unable to allocate memory for OTP struct.\n\n");
return false;
}
-
+
/* Read OTP data into otp_ptr pointer */
if (!OTP_ReadData())
{
@@ -203,14 +203,14 @@ static bool FillOTPStruct(otp_t **out)
OTP_ClearData();
return false;
}
-
+
/* Copy OTP data into our allocated struct */
memcpy(otp_data, otp_ptr, sizeof(otp_t));
OTP_ClearData();
-
+
/* Save OTP struct pointer */
*out = otp_data;
-
+
return true;
}
@@ -221,14 +221,14 @@ static bool FillSEEPROMStruct(seeprom_t **out)
printf("Fatal error: invalid output SEEPROM struct pointer.\n\n");
return false;
}
-
+
seeprom_t *seeprom_data = memalign(32, sizeof(seeprom_t));
if (!seeprom_data)
{
printf("Fatal error: unable to allocate memory for SEEPROM struct.\n\n");
return false;
}
-
+
/* Read SEEPROM data into seeprom_ptr pointer */
if (!SEEPROM_ReadData())
{
@@ -236,14 +236,14 @@ static bool FillSEEPROMStruct(seeprom_t **out)
SEEPROM_ClearData();
return false;
}
-
+
/* Copy SEEPROM data into our allocated struct */
memcpy(seeprom_data, seeprom_ptr, sizeof(seeprom_t));
SEEPROM_ClearData();
-
+
/* Save SEEPROM struct pointer */
*out = seeprom_data;
-
+
return true;
}
@@ -254,29 +254,29 @@ static bool FillBootMiiKeysStruct(otp_t *otp_data, seeprom_t *seeprom_data, boot
printf("Fatal error: invalid OTP/SEEPROM/BootMiiKeys struct pointer(s).\n\n");
return false;
}
-
+
bootmii_keys_bin_t *bootmii_keys = memalign(32, sizeof(bootmii_keys_bin_t));
if (!bootmii_keys)
{
printf("Fatal error: unable to allocate memory for BootMiiKeys struct.\n\n");
return false;
}
-
+
/* Fill structure with zeroes */
memset(bootmii_keys, 0, sizeof(bootmii_keys_bin_t));
-
+
/* Fill human info text block */
sprintf(bootmii_keys->human_info, "BackupMii v1, ConsoleID: %08x\n", *((u32*)otp_data->ng_id));
-
+
/* Fill OTP block */
memcpy(&(bootmii_keys->otp_data), otp_data, sizeof(otp_t));
-
+
/* Fill SEEPROM block */
memcpy(&(bootmii_keys->seeprom_data), seeprom_data, sizeof(seeprom_t));
-
+
/* Save BootMiiKeys struct pointer */
*out = bootmii_keys;
-
+
return true;
}
@@ -284,22 +284,22 @@ static void RetrieveSDKey(void)
{
content_map_entry_t *content_map = NULL;
u32 content_map_size = 0;
-
+
u32 ios_version = (u32)IOS_GetVersion();
u64 ios_tid = TITLE_ID(1, ios_version);
-
+
signed_blob *ios_stmd = NULL;
u32 ios_stmd_size = 0;
-
+
tmd *ios_tmd = NULL;
tmd_content *ios_content = NULL;
-
+
char content_path[ISFS_MAXPATH] = {0};
u8 *ios_content_data = NULL;
u32 ios_content_size = 0;
-
+
sha1 hash = {0};
-
+
/* Retrieve shared.map contents */
content_map = (content_map_entry_t*)ReadFileFromFlashFileSystem("/shared1/content.map", &content_map_size);
if (!content_map)
@@ -307,16 +307,16 @@ static void RetrieveSDKey(void)
printf("Failed to retrieve \"%s\" contents!\n\n", content_path);
return;
}
-
+
if ((content_map_size % sizeof(content_map_entry_t)) != 0)
{
printf("Invalid \"%s\" size!\n\n", content_path);
goto out;
}
-
+
/* Calculate content.map entry count */
content_map_size /= sizeof(content_map_entry_t);
-
+
/* Get IOS TMD */
ios_stmd = GetSignedTMDFromTitle(ios_tid, &ios_stmd_size);
if (!ios_stmd)
@@ -324,40 +324,40 @@ static void RetrieveSDKey(void)
printf("Error retrieving IOS%u TMD!\n\n", ios_version);
goto out;
}
-
+
ios_tmd = GetTMDFromSignedBlob(ios_stmd);
-
+
/* Loop through all contents */
for(u16 i = 0; i < ios_tmd->num_contents; i++)
{
u32 j = 0;
ios_content = &(ios_tmd->contents[i]);
-
+
/* Only process shared contents */
if (ios_content->type != 0x8001) continue;
-
+
/* Look for this content's hash in the content.map data */
for(j = 0; j < content_map_size; j++)
{
if (!memcmp(ios_content->hash, content_map[j].content_hash, 20)) break;
}
-
+
/* Continue if we couldn't find this hash */
if (j >= content_map_size) continue;
-
+
/* Generate shared content path and read it */
sprintf(content_path, "/shared1/%.*s.app", sizeof(content_map[j].content_name), content_map[j].content_name);
-
+
ios_content_data = (u8*)ReadFileFromFlashFileSystem(content_path, &ios_content_size);
if (!ios_content_data) continue;
-
+
/* Look for our key */
for(j = 0; j < ios_content_size; j++)
{
if (additional_keys[0].key_size > (ios_content_size - j)) break;
-
+
if (SHA1(ios_content_data + j, additional_keys[0].key_size, hash) != shaSuccess) continue;
-
+
if (!memcmp(hash, additional_keys[0].hash, 20))
{
memcpy(additional_keys[0].key, ios_content_data + j, additional_keys[0].key_size);
@@ -365,14 +365,14 @@ static void RetrieveSDKey(void)
break;
}
}
-
+
free(ios_content_data);
ios_content_data = NULL;
ios_content_size = 0;
-
+
if (additional_keys[0].retrieved) break;
}
-
+
out:
if (ios_stmd) free(ios_stmd);
if (content_map) free(content_map);
@@ -382,20 +382,20 @@ static void RetrieveSystemMenuKeys(bool vWii)
{
signed_blob *sysmenu_stmd = NULL;
u32 sysmenu_stmd_size = 0;
-
+
tmd *sysmenu_tmd = NULL;
tmd_content *sysmenu_boot_content = NULL;
-
+
char content_path[ISFS_MAXPATH] = {0};
u8 *sysmenu_boot_content_data = NULL;
u32 sysmenu_boot_content_size = 0;
-
+
u8 *binary_body = NULL;
-
+
bool priiloader = false;
-
+
sha1 hash = {0};
-
+
/* Get System Menu TMD */
sysmenu_stmd = GetSignedTMDFromTitle(SYSTEM_MENU_TID, &sysmenu_stmd_size);
if (!sysmenu_stmd)
@@ -403,12 +403,12 @@ static void RetrieveSystemMenuKeys(bool vWii)
printf("Error retrieving System Menu TMD!\n\n");
return;
}
-
+
sysmenu_tmd = GetTMDFromSignedBlob(sysmenu_stmd);
-
+
/* Get System Menu TMD boot content entry */
sysmenu_boot_content = &(sysmenu_tmd->contents[sysmenu_tmd->boot_index]);
-
+
/* Check for Priiloader */
for(u32 i = 0; i < priiloader_files_count; i++)
{
@@ -419,7 +419,7 @@ static void RetrieveSystemMenuKeys(bool vWii)
break;
}
}
-
+
/* Generate boot content path and read it */
sprintf(content_path, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(SYSTEM_MENU_TID), TITLE_LOWER(SYSTEM_MENU_TID), \
priiloader ? (0x10000000 | sysmenu_boot_content->cid) : sysmenu_boot_content->cid);
@@ -429,13 +429,13 @@ static void RetrieveSystemMenuKeys(bool vWii)
sprintf(content_path, "/title/%08x/%08x/content/%08x.app", TITLE_UPPER(SYSTEM_MENU_TID), TITLE_LOWER(SYSTEM_MENU_TID), sysmenu_boot_content->cid);
sysmenu_boot_content_data = (u8*)ReadFileFromFlashFileSystem(content_path, &sysmenu_boot_content_size);
}
-
+
if (!sysmenu_boot_content_data)
{
printf("Failed to read System Menu boot content data!\n\n");
goto out;
}
-
+
if (vWii)
{
/* Retrieve a pointer to the PPC Ancast Image header */
@@ -445,25 +445,25 @@ static void RetrieveSystemMenuKeys(bool vWii)
printf("Invalid vWii System Menu ancast image header magic word!\n\n");
goto out;
}
-
+
/* Set the binary body pointer to the end of the PPC Ancast Image header and update size */
binary_body = (sysmenu_boot_content_data + 0x500 + sizeof(ppc_ancast_image_header_t));
sysmenu_boot_content_size = ancast_image_header->body_size;
-
+
/* Calculate hash */
if (SHA1(binary_body, sysmenu_boot_content_size, hash) != shaSuccess)
{
printf("Failed to calculate encrypted vWii System Menu ancast image body SHA-1 hash!\n\n");
goto out;
}
-
+
/* Compare hashes */
if (memcmp(hash, ancast_image_header->body_hash, 20) != 0)
{
printf("Encrypted vWii System Menu ancast image body SHA-1 hash mismatch!\n\n");
goto out;
}
-
+
/* Decrypt System Menu binary using baked in vWii Ancast Key and IV (unavoidable...) */
if (aes_128_cbc_decrypt(vwii_ancast_key, vwii_ancast_iv, binary_body, sysmenu_boot_content_size) != 0)
{
@@ -474,16 +474,16 @@ static void RetrieveSystemMenuKeys(bool vWii)
/* Set the binary body pointer to our allocated buffer */
binary_body = sysmenu_boot_content_data;
}
-
+
/* Retrieve keys starting from the right index */
for(u32 i = 1; i < 3; i++)
{
for(u32 offset = 0; offset < sysmenu_boot_content_size; offset++)
{
if (additional_keys[i].key_size > (sysmenu_boot_content_size - offset)) break;
-
+
if (SHA1(binary_body + offset, additional_keys[i].key_size, hash) != shaSuccess) continue;
-
+
if (!memcmp(hash, additional_keys[i].hash, 20))
{
memcpy(additional_keys[i].key, binary_body + offset, additional_keys[i].key_size);
@@ -492,7 +492,7 @@ static void RetrieveSystemMenuKeys(bool vWii)
}
}
}
-
+
out:
if (sysmenu_boot_content_data) free(sysmenu_boot_content_data);
if (sysmenu_stmd) free(sysmenu_stmd);
@@ -512,32 +512,32 @@ static void GetMACAddress(void)
static void PrintAllKeys(otp_t *otp_data, seeprom_t *seeprom_data, FILE *fp, bool is_txt)
{
if (!otp_data || !fp) return;
-
+
u8 key_idx = 1;
const char **key_names = (is_txt ? key_names_txt : key_names_stdout);
-
+
/* We'll use this for the Korean common key check */
u8 null_key[16] = {0};
-
+
for(u8 i = 0; key_names[i]; i++)
{
/* Do not print SEEPROM keys if its access is disabled */
if (!seeprom_data && (i == 7 || i == 8 || i == 9)) continue;
-
+
/* Only display the Korean common key if it's really available in the SEEPROM data */
/* Otherwise, we'll just skip it */
if (seeprom_data && i == 9 && !memcmp(seeprom_data->korean_key, null_key, sizeof(seeprom_data->korean_key))) continue;
-
+
/* Only display the current additional key if we retrieved it */
if (i >= 10 && !additional_keys[i - 10].retrieved) continue;
-
+
if (is_txt)
{
fprintf(fp, "%s= ", key_names[i]);
} else {
fprintf(fp, "[%u] %s: ", key_idx, key_names[i]);
}
-
+
switch(i)
{
case 0: // boot1 Hash
@@ -574,9 +574,9 @@ static void PrintAllKeys(otp_t *otp_data, seeprom_t *seeprom_data, FILE *fp, boo
HexKeyDump(fp, additional_keys[i - 10].key, additional_keys[i - 10].key_size, !is_txt);
break;
}
-
+
fprintf(fp, "\r\n");
-
+
key_idx++;
}
}
@@ -586,18 +586,18 @@ int XyzzyGetKeys(bool vWii)
int ret = 0;
FILE *fp = NULL;
char path[128] = {0};
-
+
otp_t *otp_data = NULL;
seeprom_t *seeprom_data = NULL;
bootmii_keys_bin_t *bootmii_keys = NULL;
- u8 *devcert = NULL;
-
+ u8 *devcert = NULL, *boot0 = NULL;
+
ret = SelectStorageDevice();
-
+
if (ret >= 0)
{
sprintf(path, "%s:/keys.txt", StorageDeviceMountName());
-
+
fp = fopen(path, "w");
if (!fp)
{
@@ -610,19 +610,19 @@ int XyzzyGetKeys(bool vWii)
{
return ret;
}
-
+
ret = 0;
-
+
PrintHeadline();
printf("Getting keys, please wait...\n\n");
-
+
if (!FillOTPStruct(&otp_data))
{
ret = -1;
sleep(2);
goto out;
}
-
+
if (!vWii)
{
/* Access to the SEEPROM will be disabled in we're running under vWii */
@@ -632,40 +632,55 @@ int XyzzyGetKeys(bool vWii)
sleep(2);
goto out;
}
-
+
if (!FillBootMiiKeysStruct(otp_data, seeprom_data, &bootmii_keys))
{
ret = -1;
sleep(2);
goto out;
}
+
+ /* Get boot0 dump */
+ boot0 = memalign(32, BOOT0_SIZE);
+ if (boot0)
+ {
+ u16 rd = boot0_read(boot0, 0, BOOT0_SIZE);
+ if (rd != BOOT0_SIZE)
+ {
+ free(boot0);
+ boot0 = NULL;
+ printf("boot0_read failed! (%u).\n\n", rd);
+ }
+ } else {
+ printf("Error allocating memory for boot0 buffer.\n\n");
+ }
}
-
+
/* Initialize filesystem driver */
ret = ISFS_Initialize();
if (ret >= 0)
{
/* Retrieve SD key from IOS */
RetrieveSDKey();
-
+
/* Retrieve keys from System Menu binary */
RetrieveSystemMenuKeys(vWii);
-
+
/* Deinitialize filesystem driver */
ISFS_Deinitialize();
} else {
printf("ISFS_Initialize failed! (%d)\n\n", ret);
}
-
+
/* Get MAC address */
GetMACAddress();
-
+
/* Get device certificate */
devcert = memalign(32, DEVCERT_BUF_SIZE);
if (devcert)
{
memset(devcert, 42, DEVCERT_BUF_SIZE); // Why... ?
-
+
ret = ES_GetDeviceCert(devcert);
if (ret < 0)
{
@@ -676,19 +691,19 @@ int XyzzyGetKeys(bool vWii)
} else {
printf("Error allocating memory for device certificate buffer.\n\n");
}
-
+
/* Print all keys to stdout */
PrintAllKeys(otp_data, seeprom_data, stdout, false);
-
+
if (fp)
{
/* Print all keys to output txt */
PrintAllKeys(otp_data, seeprom_data, fp, true);
-
+
fclose(fp);
fp = NULL;
}
-
+
if (devcert)
{
/* Save raw device.cert */
@@ -705,7 +720,7 @@ int XyzzyGetKeys(bool vWii)
sleep(2);
}
}
-
+
/* Save raw OTP data */
sprintf(path, "%s:/otp.bin", StorageDeviceMountName());
fp = fopen(path, "wb");
@@ -719,7 +734,7 @@ int XyzzyGetKeys(bool vWii)
printf("\n\t- Sorry, not writing raw OTP data to %s.\n", StorageDeviceString());
sleep(2);
}
-
+
/* Save raw SEEPROM data */
if (!vWii)
{
@@ -735,7 +750,7 @@ int XyzzyGetKeys(bool vWii)
printf("\n\t- Sorry, not writing raw SEEPROM data to %s.\n", StorageDeviceString());
sleep(2);
}
-
+
sprintf(path, "%s:/bootmii_keys.bin", StorageDeviceMountName());
fp = fopen(path, "wb");
if (fp)
@@ -748,20 +763,39 @@ int XyzzyGetKeys(bool vWii)
printf("\n\t- Sorry, not writing BootMii keys.bin data to %s.\n", StorageDeviceString());
sleep(2);
}
+
+ if (boot0)
+ {
+ /* Save raw boot0.bin */
+ sprintf(path, "%s:/boot0.bin", StorageDeviceMountName());
+ fp = fopen(path, "wb");
+ if (fp)
+ {
+ fwrite(boot0, 1, BOOT0_SIZE, fp);
+ fclose(fp);
+ fp = NULL;
+ } else {
+ printf("\n\t- Unable to open device.cert for writing.");
+ printf("\n\t- Sorry, not writing raw boot0.bin to %s.\n", StorageDeviceString());
+ sleep(2);
+ }
+ }
}
-
+
out:
+ if (boot0) free(boot0);
+
if (devcert) free(devcert);
-
+
if (bootmii_keys) free(bootmii_keys);
-
+
if (seeprom_data) free(seeprom_data);
-
+
if (otp_data) free(otp_data);
-
+
if (fp) fclose(fp);
-
+
UnmountStorageDevice();
-
+
return ret;
}