This commit is contained in:
Thomas Roth 2020-11-29 11:58:55 +01:00
commit 4a4ffaed18
24 changed files with 473 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
backups/*
new_flash_image.bin

19
1_sanity_check.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
echo "Running sanity checks..."
if ! openocd -v >/dev/null 2>&1; then
echo "OpenOCD does not seem to be working. Please validate that you have it installed correctly!"
exit 1
fi
if ! /usr/bin/env python3 -V >/dev/null 2>&1; then
echo "Could not run python3. Please validate that you have it installed correctly!"
exit 1
fi
if ! arm-none-eabi-objdump -v >/dev/null 2>&1; then
echo "Could not find arm-none-eabi-objdump. Please validate that it's installed and in PATH."
exit 1
fi
echo "Looks good!"

49
2_backup_flash.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "Usage: backup_flash.sh <Adapter: jlink or stlink>"
exit 1
fi
if test -f backups/flash_backup.bin; then
echo "Already have a backup in backups/flash_backup.bin, refusing to overwrite."
exit 1
fi
ADAPTER=$1
echo "Make sure your Game & Watch is turned on and in the time screen. Press return when ready!"
read -n 1
mkdir -p backups
echo "Attempting to dump flash using adapter $1."
echo "Running OpenOCD... (This will take roughly 30 seconds, you Game and Watch screen will blink in between.)"
if ! openocd -f openocd/flash_"$1".cfg >/dev/null 2>&1; then
echo "Failed to dump SPI flash from device. Verify debug connection and try again."
exit 1
fi
echo "Validating ITCM dump..."
if ! shasum --check shasums/itcm_backup.bin.sha1 >/dev/null 2>&1; then
echo "Failed to correctly dump ITCM. Restart Game & Watch and try again."
exit 1
fi
echo "Extracting checksummed part..."
if ! dd if=backups/flash_backup.bin of=backups/flash_backup_checksummed.bin count=1040384 bs=1 >/dev/null 2>&1; then
echo "Failed to access flash_backup.bin"
echo "Verify openocd works correctly"
exit 1
fi
echo "Validating checksum..."
if ! shasum --check shasums/flash_backup_checksummed.bin.sha1 >/dev/null 2>&1; then
echo "Failed to verify checksum. Try again."
exit 1
fi
rm backups/flash_backup_checksummed.bin
echo "Looks good! Successfully backed up the (encrypted) SPI flash to flash_backup.bin!"

56
3_backup_internal_flash.sh Executable file
View File

@ -0,0 +1,56 @@
#!/bin/bash
set -e
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <Adapter: jlink or stlink>"
exit 1
fi
ADAPTER=$1
if test -f backups/internal_flash_backup.bin; then
echo "Already have a backup in backups/internal_flash_backup.bin, refusing to overwrite."
exit 1
fi
echo "Generating encrypted flash image from backed up data..."
if ! python3 python/tcm_encrypt.py backups/flash_backup.bin backups/itcm_backup.bin payload/payload.bin new_flash_image.bin; then
echo "Failed to build encrypted flash image."
exit 1
fi
echo "Running flashloader..."
if ! ./scripts/flashloader.sh $ADAPTER new_flash_image.bin; then
echo "Flashloader failed, check debug connection and try again."
fi
echo "Flash flashed. Now do the following procedure:"
echo "- Disconnect power from the device"
echo "- Power it again"
echo "- Press and hold the power button"
echo "- Press return (while still holding the power button)!"
read -n 1
echo "Dumping internal flash..."
if ! openocd -f openocd/interface_"$1".cfg \
-c "init;" \
-c "halt;" \
-c "dump_image backups/internal_flash_backup.bin 0x24000000 131072" \
-c "exit;" >/dev/null 2>&1; then
echo "Dumping internal flash failed."
exit 1
fi
echo "Verifying internal flash backup..."
if ! shasum --check shasums/internal_flash_backup.bin.sha1 >/dev/null 2>&1; then
echo "The backup of the internal flash failed. Please try again."
exit 1
fi
rm new_flash_image.bin
echo "Device backed up successful"

36
4_unlock_device.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <Adapter: jlink or stlink>"
exit 1
fi
ADAPTER=$1
echo "Unlocking your device will erase its internal flash. Even though your backup"
echo "is validated, this still can go wrong. Are you sure? (Y/y)"
read -n 1 -r
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo "Aborted."
exit 1
fi
echo "Validating internal flash backup before proceeding..."
if ! shasum --check shasums/internal_flash_backup.bin.sha1 >/dev/null 2>&1; then
echo "Backup is not valid. Aborting."
exit 1
fi
echo "Unlocking device... (Takes up to 30 seconds.)"
if ! openocd -f openocd/interface_"$1".cfg \
-c "init;" \
-c "halt;" \
-f openocd/rdp0.cfg >/dev/null 2>&1; then
echo "Unlocking device failed."
exit 1
fi
echo "Congratulations, your device has been unlocked. Please power-cycle it for the changes to take full effect."

BIN
firmware/flash_dumper.elf Executable file

Binary file not shown.

BIN
firmware/flash_programmer.elf Executable file

Binary file not shown.

19
openocd/flash.cfg Normal file
View File

@ -0,0 +1,19 @@
init
echo "Dump ITCM area"
dump_image backups/itcm_backup.bin 0x0 1300
echo "Reset and halt"
reset halt
echo "Load image"
load_image firmware/flash_dumper.elf
reset halt
sleep 1000
echo "Set stack pointer"
reg sp [mrw 0x20000000]
reg pc [mrw 0x20000004]
echo "Continuing, wait ca. 10 seconds"
resume
sleep 10000
echo "Dumping"
dump_image backups/flash_backup.bin 0x24000000 1048576
echo "Done!"
exit

4
openocd/flash_jlink.cfg Normal file
View File

@ -0,0 +1,4 @@
# Use this script to upload flash dumper using a JLink
source [find openocd/interface_jlink.cfg]
source [find openocd/flash.cfg]

4
openocd/flash_stlink.cfg Normal file
View File

@ -0,0 +1,4 @@
# Use this script to upload flash dumper using an STLink
source [find openocd/interface_stlink.cfg]
source [find openocd/flash.cfg]

View File

@ -0,0 +1,3 @@
source [find interface/jlink.cfg]
transport select swd
source [find target/stm32h7x.cfg]

View File

@ -0,0 +1,5 @@
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32h7x.cfg]
reset_config none

18
openocd/rdp0.cfg Normal file
View File

@ -0,0 +1,18 @@
init
echo "Reset and halt"
reset
halt
# mwr
mww 0x52002008 0x08192A3B
mww 0x52002008 0x4C5D6E7F
sleep 100
mwb 0x52002021 0xaa
sleep 100
mwb 0x52002018 0x02
sleep 200
reset
sleep 10000
# quit
exit

18
openocd/rdp1.cfg Normal file
View File

@ -0,0 +1,18 @@
init
echo "Reset and halt"
reset
halt
# mwr
mww 0x52002008 0x08192A3B
mww 0x52002008 0x4C5D6E7F
sleep 100
mwb 0x52002021 0x55
sleep 100
mwb 0x52002018 0x02
sleep 200
reset
sleep 10000
# quit
exit

66
payload/payload.S Normal file
View File

@ -0,0 +1,66 @@
.section .text
.global _start
_start:
.code 16
foo:
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
mov r2, #0
mov r4, #4
loop:
ldr r0, src
ldr r1, dst
add r0, r0, r2
add r1, r1, r2
ldr r3, [r0]
str r3, [r1]
add r2, r2, r4
b loop
src: .long 0x08000000
dst: .long 0x24000000

BIN
payload/payload.bin Normal file

Binary file not shown.

BIN
payload/payload.elf Normal file

Binary file not shown.

35
python/tcm_encrypt.py Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
import argparse
import sys
parser = argparse.ArgumentParser(description='')
parser = argparse.ArgumentParser()
parser.add_argument('flash_image', nargs=1, type=argparse.FileType('rb'))
parser.add_argument('tcm_ram_image', nargs=1, type=argparse.FileType('rb'))
parser.add_argument('code', nargs=1, type=argparse.FileType('rb'))
parser.add_argument('flash_out', nargs=1, type=argparse.FileType('wb'))
args = parser.parse_args()
def xor(b1, b2):
result = bytearray()
for b1, b2 in zip(b1, b2):
result.append(b1 ^ b2)
return result
flash_image = args.flash_image[0].read()
tcm_ram_image = args.tcm_ram_image[0].read()
code = args.code[0].read()
xor_image = xor(tcm_ram_image[:len(code)], flash_image)
new_flash_part = xor(code, xor_image)
flash_end = flash_image[len(code):]
args.flash_out[0].write(new_flash_part)
args.flash_out[0].write(flash_end)

35
python/tcmhack.py Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
import argparse
import sys
parser = argparse.ArgumentParser(description='')
parser = argparse.ArgumentParser()
parser.add_argument('flash_image', nargs=1, type=argparse.FileType('rb'))
parser.add_argument('tcm_ram_image', nargs=1, type=argparse.FileType('rb'))
parser.add_argument('code', nargs=1, type=argparse.FileType('rb'))
parser.add_argument('flash_out', nargs=1, type=argparse.FileType('wb'))
args = parser.parse_args()
def xor(b1, b2):
result = bytearray()
for b1, b2 in zip(b1, b2):
result.append(b1 ^ b2)
return result
flash_image = args.flash_image[0].read()
tcm_ram_image = args.tcm_ram_image[0].read()
code = args.code[0].read()
xor_image = xor(tcm_ram_image[:len(code)], flash_image)
new_flash_part = xor(code, xor_image)
flash_end = flash_image[len(code):]
args.flash_out[0].write(new_flash_part)
args.flash_out[0].write(flash_end)

40
restore.sh Executable file
View File

@ -0,0 +1,40 @@
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <Adapter: jlink or stlink>"
exit 1
fi
if ! test -f backups/internal_flash_backup.bin; then
echo "No backup of internal flash found in backups/internal_flash_backup.bin"
exit 1
fi
if ! test -f backups/flash_backup.bin; then
echo "No backup of SPI flash found in backups/flash_backup.bin"
exit 1
fi
ADAPTER=$1
echo "Ok, restoring original firmware!"
echo "Restoring SPI flash..."
if ! ./scripts/flashloader.sh $ADAPTER backups/flash_backup.bin; then
echo "Restoring SPI flash failed. Check debug connection and try again."
exit 1
fi
echo "Restoring internal flash..."
if ! openocd -f openocd/interface_"$1".cfg \
-c "init;" \
-c "halt;" \
-c "program backups/internal_flash_backup.bin 0x08000000 verify;" \
-c "exit;" >/dev/null 2>&1; then
echo "Restoring internal flash failed. Check debug connection and try again."
exit 1
fi
echo "Success, your device should be running the original firmware again!"

61
scripts/flashloader.sh Executable file
View File

@ -0,0 +1,61 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
ELF=firmware/flash_programmer.elf
ADDRESS=0
SIZE=$((1024 * 1024))
MAGIC="0xdeadbeef"
ERASE=1
IMAGE=$2
objdump=${OBJDUMP:-arm-none-eabi-objdump}
function get_symbol {
name=$1
objdump_cmd="${objdump} -t ${ELF}"
size=$(${objdump_cmd} | grep " $name" | cut -d " " -f1 | tr 'a-f' 'A-F')
printf "ibase=16\n${size}\n" | bc
}
VAR_program_size=$(printf '0x%08x\n' $(get_symbol "program_size"))
VAR_program_address=$(printf '0x%08x\n' $(get_symbol "program_address"))
VAR_program_magic=$(printf '0x%08x\n' $(get_symbol "program_magic"))
VAR_program_done=$(printf '0x%08x\n' $(get_symbol "program_done"))
VAR_program_erase=$(printf '0x%08x\n' $(get_symbol "program_erase"))
if ! openocd -f openocd/interface_"$1".cfg \
-c "init;" \
-c "echo \"Resetting device\";" \
-c "reset halt;" \
-c "echo \"Programming ELF\";" \
-c "load_image ${ELF};" \
-c "reset halt;" \
-c "sleep 100;" \
-c "echo \"Loading image into RAM\";" \
-c "load_image ${IMAGE} 0x24000000;" \
-c "mww ${VAR_program_size} ${SIZE}" \
-c "mww ${VAR_program_address} ${ADDRESS}" \
-c "mww ${VAR_program_magic} ${MAGIC}" \
-c "mww ${VAR_program_erase} ${ERASE}" \
-c "reg sp [mrw 0x20000000];" \
-c "reg pc [mrw 0x20000004];" \
-c "echo \"Starting flash process\";" \
-c "resume; exit;" >/dev/null 2>&1; then
echo "Loading failed."
exit 1
fi
echo "Loaded flashloader, flashing SPI, please wait."
echo "(If this takes more than 2 minutes something went wrong.)"
echo "(If the screen blinks rapidly, something went wrong.)"
echo "(If the screen blinks slowly, everything worked but the script didn't detect it)"
while true; do
DONE_MAGIC=$(openocd -f openocd/interface_${1}.cfg -c "init; mdw ${VAR_program_done}" -c "exit;" 2>&1 | grep ${VAR_program_done} | cut -d" " -f2)
if [[ "$DONE_MAGIC" == "cafef00d" ]]; then
echo "Done!"
break;
fi
sleep 1
done

View File

@ -0,0 +1 @@
eea70bb171afece163fb4b293c5364ddb90637ae backups/flash_backup_checksummed.bin

View File

@ -0,0 +1 @@
efa04c387ad7b40549e15799b471a6e1cd234c76 backups/internal_flash_backup.bin

View File

@ -0,0 +1 @@
ca71a54c0a22cca5c6ee129faee9f99f3a346ca0 backups/itcm_backup.bin