Tweezer Attack

From WiiBrew
Jump to navigation Jump to search

The Tweezer Attack was an exploit that involved the use of a pair of tweezers to bridge areas of memory, allowing homebrew code running in Gamecube mode to have access to limited sections of Wii memory (MEM2) in order to map out the rest of the console a small piece at a time.

Technical explanation

In MIOS, only the bottom 16MB (of 64MB) of MEM2 could be used; this was used to emulate ARAM. Because of this, Nintendo never bothered to clear out the other 48MB, which resulted in 36MB of Broadway data being dumped from MEM2, as well as the 12MB reserved for IOS, including boot2 code for IOSC, FS, and ES, as well as IOS30 code for the other modules (excluding the main part of the kernel, which lives in internal SRAM). As a result, by reconnecting the address lines to other 16MB windows of MEM2, it becomes possible to read these other bytes.

The data itself was uploaded to a computer through a GameCube controller port.

Fix

Prior to the fix, tmbinc had suggested an "anti-tweezer attack" where the lines were shorted into the bottom 16MB, where the emulated ARAM normally was. Nintendo seems to have attempted to patch that out by writing random data and verifying it, however, this would only be effective if the hash was verified after the memory was written, so the anti-tweezer hack probably still works.

The purpose of patching this hack is also unknown; it was initially suspected that it was to protect the Korean common key, although the Korean Wii turned out to not allow GameCube discs anyway (also, it did not even have the patched MIOS version at launch, or even the one that blocks Action Replay).

Decompilation

int do_hash_comparison(void) {
//	using the memory mapper, this should be aliased to
//	0x0D408000.  This resides in the on-chip SRAM.

	u8 *buffer  = (u8 *)0xFFFF8000;
	u8 *MEM2_ptr = (u8 *)0x10000000;  // = 0x90000000
	u32 hash1[5];
	u32 hash2[5]={0x4F00A54E,0x57E1E2C4,0x78634365,
                        0xF56BA5D3,0xF7DECA52};
	int i;

	memset(buffer, 0xCAFEBABE, 0x8000);
	memset(buffer + 0x8000, 0xCAFEBABE, 0x8000);
	aes_set_key(0x2B7E1516, 0x28AED2A6, 0xABF71588, 0x09CF4F3C);
	sha_init();

	for (i=0; i<1024; i++) {
		aes_set_iv(i, i, i, i);
		aes_encrypt(MEM2_ptr, buffer, 0x10000);
		sha_update(MEM2_ptr, 0x10000);
	}

	sha_finalize(hash1);
	if (hash1[0] == hash2[0] && hash1[1] == hash2[1] && hash1[2] == hash2[2] &&
		hash1[3] == hash2[3] && hash1[4] == hash2[4]) {
			do_log_message("%s shaHash: %x %x %x %x %x [%u ticks]\n",
				NULL, hash1[0], hash1[1], hash1[2], hash1[3], hash1[4], 0);
			return 0;
	}

	do_log_message("Hash comparison failed. Halting boot!\n");
	return -1;
}

External Links