271 lines
11 KiB
Bash
Executable File
271 lines
11 KiB
Bash
Executable File
# makenand.sh
|
|
|
|
# https://problemkaputt.de/gbatek.htm#dsisdmmcinternalnandlayout
|
|
# Overall eMMC Layout
|
|
#
|
|
# Offset Size Description
|
|
# 00000000h 200h PC-style MBR, encrypted with a per-console key
|
|
# 00000200h 200h Stage 2 Boot Info Block 1 (used)
|
|
# 00000400h 200h Stage 2 Boot Info Block 2 (unused, same as above)
|
|
# 00000600h 200h Stage 2 Boot Info Block 3 (unused, nonsense NAND offsets)
|
|
# 00000800h 26600h Stage 2 ARM9 Bootcode (encrypted with universal key)
|
|
# 00026E00h 27600h Stage 2 ARM7 Bootcode (encrypted with universal key)
|
|
# 0004E400h 400h Stage 2 Footer -- unknown format, but first 10 bytes
|
|
# are (unencrypted) build number of Stage 2 bootloader
|
|
# 0004E800h B1000h Unused (all 00h)
|
|
# 000FF800h 200h Unused (all 00h) (or No$gba Footer with CID & Console ID)
|
|
# 000FFA00h 400h Diagnostic area. (often contains build date of
|
|
# device in plaintext) Blank in never-before-booted
|
|
# DSi. Might be written to during firmware updates.
|
|
# 000FFE00h 200h Unused (all FFh)
|
|
# 00100000h EE00h Unused (all 00h)
|
|
# 0010EE00h CDF1200h 1st partition (205.9Mbyte) (main, encrypted, FAT16)
|
|
# 0CF00000h 9A00h Unused (all 00h)
|
|
# 0CF09A00h 20B6600h 2nd partition (32.7Mbyte) (photo, encrypted, FAT12)
|
|
# For 240.0MB chips (Samsung KMAPF0000M-S998 or KLM5617EFW-B301):
|
|
# 0EFC0000h BA00h Unused (all 00h)
|
|
# 0EFCBA00h 34600h 3rd partition (0.2Mbyte) (extra, unformatted)
|
|
# 0F000000h - End of 240MByte Address Space
|
|
# For 245.5MB chips (ST NAND02GAH0LZC5, both rev30 and rev31):
|
|
# 0EFC0000h B600h Unused (all 00h?) (smaller unused area as in 240MB chip)
|
|
# 0EFCB600h 5B4A00h 3rd partition (5.7Mbyte) (extra, unformatted)
|
|
# 0F580000h - End of 245.5MByte Address Space
|
|
#
|
|
# Making a new NAND is easy:
|
|
#
|
|
# - create blank TWL_MAIN
|
|
# - copy VBR
|
|
# - populate it with system files and firmware
|
|
# - create blank TWL_PHOTO
|
|
# - copy VBR
|
|
# - add the management file
|
|
# - create blank nand.bin
|
|
# - copy stage2
|
|
# - copy MBR
|
|
# - copy in TWL_MAIN and TWL_PHOTO
|
|
# - encrypt the NAND
|
|
#
|
|
# HIIIIII VIKRINOX ENJOY MY SLOPPY SCRIPT! IT'S TERRIBLE! I'M SORRY!
|
|
|
|
# mcopy doesn't make directories, this is my shortcut
|
|
makemdirs() {
|
|
local foldersonly=$(dirname $1)
|
|
local current=""
|
|
|
|
IFS='/' read -ra PARTS <<< "$foldersonly"
|
|
for p in "${PARTS[@]}"; do
|
|
#echo "$p"
|
|
current="$current/$p"
|
|
if ! mdir "$2/$current" >/dev/null 2>&1; then
|
|
mmd "$2/$current"
|
|
fi
|
|
done
|
|
}
|
|
|
|
rm -f twl_main.img
|
|
rm -f twl_photo.img
|
|
rm -f nand.bin
|
|
rm -r mount
|
|
|
|
CONSOLE_SIGNING="$1"
|
|
|
|
mkdir mount
|
|
|
|
# Start by making a blank partition!
|
|
# We'll work on each partition as is, then copy them into a completed NAND.
|
|
#
|
|
# The "seek" value is the full size of the partition.
|
|
echo ">>> Working on TWL_MAIN"
|
|
dd if=/dev/zero of=twl_main.img bs=1 count=0 seek=$((0xCDF1200)) status=progress
|
|
|
|
# Create TWL_MAIN VBR
|
|
# I just copied this from a random NAND. The VBR seems to be standard, and it seems good to keep things standard. I don't want to add the risk of errors from changing things.
|
|
dd if="./donor/vbr/TWL_MAIN.bin" of=twl_main.img bs=1 seek=0 count=$(stat -c%s "./donor/vbr/TWL_MAIN.bin") conv=notrunc status=progress
|
|
rm -f temp.bin
|
|
|
|
# Just "mounting" the drive for writing. Not really mounting but whatever.
|
|
cat > mtoolsrc <<EOF
|
|
drive d: file="./twl_main.img"
|
|
EOF
|
|
export MTOOLSRC=./mtoolsrc
|
|
|
|
# First thing to do inside of TWL_MAIN is checking HWInfo (if provided). This will give us a firmware region to target.
|
|
# The status variable will contain the region byte of the launcher TID.
|
|
#
|
|
# Probably not a bad idea to confirm that the TID is for an known region.
|
|
|
|
nogba_consoleid=$(echo $3 | tac -rs .. | echo "$(tr -d '\n')")
|
|
python hwinfo.py --consoleid $nogba_consoleid --hwinfo $2 verify
|
|
if [[ "$2" != "" ]]; then
|
|
if [[ "$CONSOLE_SIGNING" == "dev" ]]; then
|
|
HWINFO_STATUS=$(python hwinfo.py --consoleid $nogba_consoleid --hwinfo $2 --dev verify)
|
|
else
|
|
HWINFO_STATUS=$(python hwinfo.py --consoleid $nogba_consoleid --hwinfo $2 verify)
|
|
fi
|
|
|
|
if [[ "$HWINFO_STATUS" == "Signature is valid" ]] && [[ "$2" != "" ]]; then
|
|
REGION_CODE=$(xxd -p -s 160 -l 1 "$2")
|
|
echo ">>> Region is $REGION_CODE"
|
|
else
|
|
echo ">>> HWInfo is bad, so region was not found! Setting as ALL."
|
|
echo ">>> Factory firmware will be used."
|
|
REGION_CODE="ALL"
|
|
fi
|
|
else
|
|
echo ">>> HWInfo is bad, so region was not found! Setting as ALL."
|
|
echo ">>> Factory firmware will be used."
|
|
REGION_CODE="ALL"
|
|
fi
|
|
|
|
# Make system folders
|
|
echo ">>> Making dirs"
|
|
mmd d:/sys
|
|
mmd d:/sys/log
|
|
mmd d:/shared1
|
|
mmd d:/shared2
|
|
mmd d:/shared2/launcher
|
|
mmd d:/ticket
|
|
mmd d:/title
|
|
mmd d:/tmp
|
|
|
|
# Copy the font data
|
|
if [[ "$REGION_CODE" == "43" ]]; then
|
|
echo ">>> Copying CN FontTable"
|
|
mcopy ./donor/TWLFontTable_CN.dat "d:/sys/TWLFontTable.dat"
|
|
elif [[ "$MODEL" == "4b" ]]; then
|
|
echo ">>> Copying KR FontTable"
|
|
mcopy ./donor/TWLFontTable_KR.dat "d:/sys/TWLFontTable.dat"
|
|
else
|
|
echo ">>> Copying World FontTable"
|
|
mcopy ./donor/TWLFontTable.dat "d:/sys/TWLFontTable.dat"
|
|
fi
|
|
|
|
# Copy other important files
|
|
echo ">>> Writing cert"
|
|
mcopy ./donor/$CONSOLE_SIGNING/cert.sys "d:/sys/cert.sys"
|
|
# MelonDS WILL NOT BOOT without these configs:
|
|
echo ">>> Writing configs"
|
|
mcopy ./donor/shared1/TWLCFG1.dat "d:/shared1/TWLCFG1.dat"
|
|
mcopy ./donor/shared1/TWLCFG0.dat "d:/shared1/TWLCFG0.dat"
|
|
mcopy ./donor/wrap.bin "d:/shared2/launcher/wrap.bin"
|
|
# Not sure if unique, still copying just because.
|
|
echo ">>> Writing HWInfo"
|
|
mcopy ./donor/HWINFO_N.dat "d:/sys/HWINFO_N.dat"
|
|
|
|
# Now we'll install from a region specific title list.
|
|
# Each line contains a path like "title/000300xx/xxxxxxxx/file.ext"
|
|
while IFS= read -r FILE; do
|
|
echo ">>> Working on $FILE"
|
|
makemdirs "$FILE" "d:"
|
|
if [[ "$FILE" == *".tik" ]]; then
|
|
echo ">>> Writing ticket..."
|
|
./twltool syscrypt --consoleid $3 --in "./donor/$CONSOLE_SIGNING/software/$FILE" --out "./tmp.tik" --encrypt
|
|
mcopy -D o "./tmp.tik" "d:/$FILE"
|
|
else
|
|
echo ">>> Moving title datas..."
|
|
# If the item is a title TMD, we will intentionally break it to trigger the backup unlaunch.
|
|
# This is only needed for region specific firmware. Since ALL/HNAA has the backup unlaunch as a TMD, it will automatically trigger.
|
|
if [[ "$FILE" == *"00030017"* ]] && [[ "$FILE" == *"title.tmd" ]]; then
|
|
cp "./donor/$CONSOLE_SIGNING/software/$FILE" "./tmp.tmd"
|
|
printf "G" | dd of="./tmp.tmd" bs=1 seek=400 conv=notrunc status=none
|
|
mcopy -D o "./tmp.tmd" "d:/$FILE"
|
|
mattrib +r "d:/$FILE"
|
|
else
|
|
mcopy -D o "./donor/$CONSOLE_SIGNING/software/$FILE" "d:/$FILE"
|
|
fi
|
|
fi
|
|
done < "./donor/$CONSOLE_SIGNING/software/$REGION_CODE.txt"
|
|
# Now we'll install the general title list (yes this is redundant code, I DON"T CARE IT'S 6AM!!!!!!!!!!!!!!)
|
|
# This contains things like the wifi firmware, and full factory firmware.
|
|
while IFS= read -r FILE; do
|
|
echo ">>> Working on $FILE"
|
|
makemdirs "$FILE" "d:"
|
|
if [[ "$FILE" == *".tik" ]]; then
|
|
echo ">>> Writing ticket..."
|
|
# Encrypt ticket to console.
|
|
./twltool syscrypt --consoleid $3 --in "./donor/$CONSOLE_SIGNING/software/$FILE" --out "./tmp.tik" --encrypt
|
|
mcopy -D o "./tmp.tik" "d:/$FILE"
|
|
else
|
|
echo ">>> Moving title datas..."
|
|
mcopy -D o "./donor/$CONSOLE_SIGNING/software/$FILE" "d:/$FILE"
|
|
fi
|
|
done < "./donor/$CONSOLE_SIGNING/software/ALL.txt"
|
|
|
|
# Create backup unlaunch for safety
|
|
makemdirs "title/00030017/484e4141/content/title.tmd" "d:"
|
|
mcopy -D o "./donor/hb/HNAALaunch.tmd" "d:/title/00030017/484e4141/content/title.tmd"
|
|
mattrib +r "d:/title/00030017/484e4141/content/title.tmd"
|
|
|
|
if [[ "$REGION_CODE" == "ALL" ]]; then
|
|
echo ">>> HWInfo is bad! HNAA unlaunch will be needed."
|
|
else
|
|
echo ">>> HWInfo is good!"
|
|
mcopy "$2" "d:/sys/HWINFO_S.dat"
|
|
fi
|
|
|
|
mdir -/ d:/
|
|
|
|
# Make blank photo partition, same idea as before
|
|
echo ">>> Working on TWL_PHOTO"
|
|
dd if=/dev/zero of=twl_photo.img bs=1 count=0 seek=$((0x20B6600)) status=progress
|
|
|
|
# Create TWL_PHOTO VBR
|
|
dd if="./donor/vbr/TWL_PHOTO.bin" of=twl_photo.img bs=1 seek=0 count=$(stat -c%s "./donor/vbr/TWL_PHOTO.bin") conv=notrunc status=progress
|
|
rm -f temp.bin
|
|
|
|
cat > mtoolsrc <<EOF
|
|
drive d: file="./twl_photo.img"
|
|
EOF
|
|
export MTOOLSRC=./mtoolsrc
|
|
|
|
makemdirs "photo/private/ds/app/484E49$(xxd -p -s 160 -l 1 "$2")/pit.bin" "d:"
|
|
mcopy "./donor/pit.bin" "d:/photo/private/ds/app/484E49$(xxd -p -s 160 -l 1 "$2")/pit.bin"
|
|
|
|
mdir -/ d:/
|
|
|
|
echo ">>> Working on full NAND"
|
|
dd if=/dev/zero of=nand.bin bs=1 count=0 seek=$((0xF000040)) status=progress
|
|
|
|
echo ">>> Installing bootloader (stage2)"
|
|
dd if="./donor/$CONSOLE_SIGNING/stage2/Stage2_v2435-8325_${CONSOLE_SIGNING}.nand" of=nand.bin bs=1 count=$(stat -c%s "./donor/$CONSOLE_SIGNING/stage2/Stage2_v2435-8325_${CONSOLE_SIGNING}.nand") conv=notrunc status=progress
|
|
|
|
echo ">>> Writing NAND MBR"
|
|
NAND_BRAND=$(printf "%s" "$4" | xxd -r -p | xxd -p -s 14 -l 1)
|
|
if [[ "$NAND_BRAND" == "15" ]]; then
|
|
echo ">>> Looks like Samsung"
|
|
dd if="./donor/mbr/KMAPF0000M_MBR.bin" of=nand.bin bs=1 count=$(stat -c%s "./donor/mbr/KMAPF0000M_MBR.bin") skip=0 seek=0 conv=notrunc status=progress
|
|
elif [[ "$NAND_BRAND" == "fe" ]]; then
|
|
echo ">>> Looks like ST"
|
|
dd if="./donor/mbr/NAND02GAH0LZC5r30_MBR.bin" of=nand.bin bs=1 count=$(stat -c%s "./donor/mbr/NAND02GAH0LZC5r30_MBR.bin") skip=0 seek=0 conv=notrunc status=progress
|
|
fi
|
|
echo "$NAND_BRAND"
|
|
|
|
# Offsets for both partitions are in the "seek" parameter (just ignore the /256)
|
|
echo ">>> Copying partitions into NAND"
|
|
dd if=twl_main.img of=nand.bin bs=256 count=$(( $(stat -c%s twl_main.img) / 512 )) skip=0 seek=$((0x10EE00 / 256)) conv=notrunc status=progress
|
|
dd if=twl_photo.img of=nand.bin bs=256 count=$(( $(stat -c%s twl_main.img) / 512 )) skip=0 seek=$((0xCF09A00 / 256)) conv=notrunc status=progress
|
|
|
|
echo '>>> Writing NO$GBA footer'
|
|
echo "44536920654D4D43204349442F435055${4}${nogba_consoleid}000000000000000000000000000000000000000000000000" | xxd -r -p > temp.bin
|
|
dd if=temp.bin of=nand.bin bs=1 count=$(stat -c%s temp.bin) skip=0 seek=$((0xF000000)) conv=notrunc status=progress
|
|
|
|
echo ">>> Encrypting NAND"
|
|
./twltool nandcrypt --consoleid $3 --cid $4 --in nand.bin --out nand_final.bin
|
|
|
|
# Final notes:
|
|
#
|
|
# We need to stop negative compression.
|
|
#
|
|
# The work in progress NAND is zerofilled and decrypted. It will compress down to nothing. Great!
|
|
# However, when we encrypt it for "nand_final.bin", all those zerobytes will turn into encrypted data.
|
|
# The NAND will then compress to a crazy 239mb... not great.
|
|
#
|
|
# We'll turn those zerobytes into compressed data during processing.
|
|
# THEN we'll encrypt, turning everything back into compressable zeroes.
|
|
#
|
|
# This would look like:
|
|
# - Create zerofilled partition
|
|
# - Encrypt partition (keeping in mind the counter for AES-CTR when the partition is actually in the NAND)
|
|
# - Write VBRm and this time zerofill the file tables (encrypted data will otherwise cause errors)
|
|
# - Continue as normal
|