From d2f26367743c4393d469809633fa2f3074679e0c Mon Sep 17 00:00:00 2001 From: Aetias Date: Sat, 21 Oct 2023 10:36:14 +0200 Subject: [PATCH] Match secure area CRC --- .gitignore | 1 + INSTALL.md | 28 +++++++++++++++++++++++++--- Makefile | 5 +++++ README.md | 2 +- tools/rom/build.c | 35 +++++++++++++++++++---------------- 5 files changed, 51 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 4497de2f..c8c16468 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ ph_jpn/ ph_usa/ ph_eur/ *.nds +*bios.bin diff --git a/INSTALL.md b/INSTALL.md index fe653525..43b80275 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -4,6 +4,7 @@ Contents: - [Prerequisites](#prerequisites) - [Build the ROM](#build-the-rom) + - [Matching the base ROM](#matching-the-base-rom) ## Prerequisites @@ -19,9 +20,8 @@ python tools/setup.py ## Build the ROM -This repository does not include any of the game's assets. You will need an original decrypted ROM for the version(s) you want -to build. -Put the original ROM in the root directory of this repository. Please verify that your dumped ROM matches one of the versions +This repository does not include any of the game's assets, and you will need an original decrypted base ROM. +Put the base ROM in the root directory of this repository. Please verify that your dumped ROM matches one of the versions below: | Version | File name | SHA1 | @@ -31,3 +31,25 @@ below: Run `make extract` to extract from the base ROM. You only need to do this once. Once you have extracted the base ROM, simply run `make` to rebuild it. + +### Matching the base ROM + +**This is optional!** You only need to follow these steps if you want a matching ROM. + +> [!NOTE] +> For interested readers: +> Retail games are usually "encrypted," which means that the first 0x800 bytes of the secure area is encrypted using a +4168-byte key found in the ARM7 BIOS. The secure area is 0x4000 bytes long and lives at the start of the ARM9 program at +address 0x2000000. +> This encryption is optional, and games will run just fine without it. In fact, this project doesn't even produce an +encrypted ROM. However, the ROM header includes a checksum of the secure area **after** encryption, so we must calculate it +somehow. + +First, [extract the ARM7 BIOS from your DS device](https://wiki.ds-homebrew.com/ds-index/ds-bios-firmware-dump). Put the +ARM7 BIOS in the root directory of this repository, and verify that your dumped BIOS matches the one below: + +| File name | SHA1 | +| --------------- | ------------------------------------------ | +| `arm7_bios.bin` | `6ee830c7f552c5bf194c20a2c13d5bb44bdb5c03` | + +Now, `make` should automatically detect the ARM7 BIOS and will build a matching ROM (soon™). diff --git a/Makefile b/Makefile index 62f2212c..6af70c03 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ TOOLS_DIR := $(ROOT)/tools BASE_DIR := $(ROOT)/ph_$(REGION_NAME) LCF_FILE := $(BUILD_DIR)/arm9_linker_script.lcf OBJS_FILE := $(BUILD_DIR)/arm9_objects.txt +ARM7_BIOS := $(ROOT)/arm7_bios.bin ASM_FILES := $(wildcard asm/*.s) CXX_FILES := $(wildcard src/*.cpp) @@ -49,7 +50,11 @@ tools: .PHONY: rom rom: arm9 +ifneq (,$(wildcard $(ARM7_BIOS))) + $(TOOLS_DIR)/rom/buildrom -a $(BASE_DIR) -b $(TARGET_DIR) -r $(REGION_SUFFIX) -o $(NDS_FILE) -7 $(ARM7_BIOS) +else $(TOOLS_DIR)/rom/buildrom -a $(BASE_DIR) -b $(TARGET_DIR) -r $(REGION_SUFFIX) -o $(NDS_FILE) +endif .PHONY: extract extract: diff --git a/README.md b/README.md index a0860a16..5ca2ea69 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ assembly code by hand. **The repository only contains code.** To build the ROM, you must own an existing copy of the game to extract assets from. -**Note:** The project can not build a ROM yet. Furthermore, it only targets the European version, and other versions might +**Note:** The project can build a ROM, but it doesn't match the original ROM yet. Furthermore, it only targets the European version, and other versions might be supported later. ## How to install diff --git a/tools/rom/build.c b/tools/rom/build.c index 363d244a..878157e6 100644 --- a/tools/rom/build.c +++ b/tools/rom/build.c @@ -68,24 +68,25 @@ uint32_t BlowfishF(size_t x) { return f; } -void BlowfishEncrypt(uint32_t *a, uint32_t *b) { +void BlowfishEncrypt(uint32_t *pLeft, uint32_t *pRight) { uint32_t tmp; - for (size_t i = 0; i < 0x12; ++i) { - tmp = *a ^ blowfish.subkeys[i]; - *a = *b ^ BlowfishF(tmp); - *b = tmp; + uint32_t x = *pRight; + uint32_t y = *pLeft; + for (size_t i = 0; i < 0x10; ++i) { + tmp = x ^ blowfish.subkeys[i]; + x = y ^ BlowfishF(tmp); + y = tmp; } - tmp = *a ^ blowfish.subkeys[0x11]; - *a = *b ^ blowfish.subkeys[0x10]; - *b = tmp; + *pLeft = x ^ blowfish.subkeys[0x10]; + *pRight = y ^ blowfish.subkeys[0x11]; } void BlowfishApplyCode(uint32_t code[3]) { BlowfishEncrypt(&code[1], &code[2]); BlowfishEncrypt(&code[0], &code[1]); - for (size_t i = 0; i < 0x12; i += 2) { - blowfish.subkeys[i + 0] ^= REVERSE32(code[0]); - blowfish.subkeys[i + 1] ^= REVERSE32(code[1]); + for (size_t i = 0; i < 0x12; ++i) { + uint32_t x = REVERSE32(code[i % 2]); + blowfish.subkeys[i] ^= x; } uint32_t scratch0 = 0; @@ -109,8 +110,8 @@ bool BlowfishInit(const uint8_t *encKey, const Header *pHeader, size_t level) { uint32_t code[3]; memcpy(&code[0], pHeader->gamecode, sizeof(code[0])); - code[1] = code[0] << 1; - code[2] = code[0] >> 1; + code[1] = code[0] >> 1; + code[2] = code[0] << 1; BlowfishApplyCode(code); if (level >= 2) BlowfishApplyCode(code); if (level >= 3) { @@ -524,13 +525,15 @@ bool FinalizeHeader(FILE *fpRom, Header *pHeader, const char *arm7bios, uint32_t if (fread(&encKey, sizeof(encKey), 1, fp) != 1) FATAL("Failed to read encrypion key\n"); fclose(fp); - if (!BlowfishInit(encKey, pHeader, 2)) return false; - BlowfishEncrypt(&secureArea[0], &secureArea[1]); if (!BlowfishInit(encKey, pHeader, 3)) return false; for (size_t i = 2; i < 0x200; i += 2) { BlowfishEncrypt(&secureArea[i], &secureArea[i + 1]); } - header.secureAreaCrc = Crc(secureArea, sizeof(secureArea)); + memcpy(secureArea, "encryObj", 8); + BlowfishEncrypt(&secureArea[0], &secureArea[1]); + if (!BlowfishInit(encKey, pHeader, 2)) return false; + BlowfishEncrypt(&secureArea[0], &secureArea[1]); + header.secureAreaCrc = Crc(secureArea, 0x4000); } header.headerCrc = Crc(&header, offsetof(Header, headerCrc));