PDA

View Full Version : Wii menu TP-hack-killer analysis



wraggster
June 21st, 2008, 19:10
Some missed news while i was away from bushing:


Okay, I’ve spent a little bit of time trying to reconstruct the C code used to build the channel from my disassembler. The full IDA Pro output for those funcs is here: http://static.hackmii.com/verifyzelda.html.

Below, you’ll find my C version. I’ve tried to make it function exactly like the one in the new system menu. Hopefully I did a good job, because I’d like to see people try to find bug in this that could lead to an exploit. There are at least two here, which we used in combination; can you find any more?

Don’t worry, I’ll give the answers if nobody gets them

// this helper function gets called during the NAND check
// for the TP hack files

int ipl::utility::ESMisc::DeleteSavedata(u32 titleid_h, u32 titleid_l) {
char pathname[0x100];
int deleted_files = 0;

sprintf(pathname, “/title/%08x/%08x/data/”, titleid_hi, titleid_lo);

int num_dir_entries = 0;
int retval = nandReadDir(pathname, 0, &num_dir_entries);
if (retval != 0 || num_dir_entries == 0) {
OSReportError(”iplESMisc.cpp::DeleteSavedata: ”
“Could not read1 %s: %d\n”, pathname);
goto done;
}

dirent_t *direntries=malloc(sizeof dirent_t * num_dir_entries);
if (direntries == NULL) {
OSReportError(”iplESMisc.cpp::DeleteSavedata:”
“Could not alloc: %d\n”);
goto done;
}

retval = nandReadDir(pathname, num_dir_entries, direntries);
if (retval != 0) {
OSReportError(”iplESMisc.cpp::DeleteSavedata: ”
“Could not read2 %s: %d\n”, pathname);
goto done;
}

int i;
for (i=0; i < num_dir_entries; i++) {
char buf[0x100];
strcpy(buf, pathname);
strcat(buf, direntries[i].filename);
retval = NANDPrivateDelete(buf);
if (retval != 0) {
OSReportError(”iplESMisc.cpp::DeleteSavedata: Failed to delete %s: %d\n”, buf);
goto done;
}
deleted_files = 1;
}
done:
if (direntries != NULL) free(direntries);
return deleted_files;
}

// this function is called upon boot or something
ipl::utility::ESMisc::VerifySavedataZD(u32 titleid_hi, u32 titleid_lo) {
int savegame_bad = 1;
char pathname[0x100];

sprintf(pathname, “/title/%08x/%08x/data/%s”, titleid_hi, titleid_lo, “zeldaTp.dat”);

if(ipl::utility::ESMisc::ChangeUid(titleid_hi, titleid_lo)==0) goto done;

int retval = nandPrivateOpen(pathname, &fd, O_RDWR);
if (retval == -ENOENT) {
OSReportError(”iplESMisc.cpp::VerifySavedataZD: Does not exist %s: %d\n”, pathname);
goto done;
}

if (retval == 0) {
OSReportError(”iplESMisc.cpp::VerifySavedataZD:Ope n save data file failed: %d\n”);
goto done;
}

u32 file_length;
retval = NANDGetLength(fd, &file_length);
if (retval != 0) {
OSReportError(”iplESMisc.cpp::VerifySavedataZD:Get file length failed: %d\n”);
goto done;
}

char *buf = malloc(file_length);
if (buf == NULL) {
OSReportError(”iplESMisc.cpp::VerifySavedataZD: Alloc failed: %d\n”);
goto done;
}

int bytes_read;
bytes_read = NANDRead(fd, buf, _align_size(file_length, 32));

if (bytes_read != _align_size(file_length, 32)) {
OSReportError(”iplESMisc.cpp::VerifySavedataZD: Read file failed: %d\n”);
goto done;
}

if (WADCheckSavedataZD(buf) == 0) {
OSReport(”iplESMisc.cpp::VerifySavedataZD: Verify failed for %016llx\n”,
titleid_hi << 32 | titleid_lo);
NAND_Close(fd);
fd = 0;
ipl::utility::ESMisc::DeleteSavedata(titleid_h, titleid_l);
}
savegame_bad = 0;

done:
if (buf) free(buf);
if (fd) NANDClose(fd);
ipl::utility::ESMisc::ChangeUid(1,2);

return savegame_bad;
}

int _align_size(int value, int alignment) {
// round up value to next highest multiple of alignment
// e.g align_size(40, 32) = 64
return value + (alignment-1) & ~alignment;
}

int _check_strlen(char *string, int max) {
int i;
for (i=0; i< max; i++) if (string[i]==’\0′) return 1;
return 0;
}

int _check_save(char *buf) {
if (!_check_strlen(buf + 0×56, 8)) return 0; // random strings
if (!_check_strlen(buf + 0×60, 8)) return 0; // inside savegame
if (!_check_strlen(buf + 0×7A, 8)) return 0;
if (!_check_strlen(buf + 0×96, 8)) return 0;
if (!_check_strlen(buf + 0×1BC, 17)) return 0; // player name
if (!_check_strlen(buf + 0×1CD, 17)) return 0; // horse name
return 1;
}

int WADCheckSavedataZD(char *buf) {
int i;
// check 3 primary saveslots
for (i=0; i<3; i++) if (!_check_save(buf + i*0xA94)) return 0;
// check 3 backup saveslots
for (i=0; i< 3; i++) if (!_check_save(buf + 0×2008 + i*0xA94)) return 0;
return 1;
}

// this function is called when any savegame WAD is being
// installed (copied from SD)
int _wad_check_for_twilight_hack(WAD *wadfile) {
int i;
for (i=0; i < wadfile.numfiles; i++) {
// skip any leading directory names
char *p = strrchr(wadfile.filename[i], ‘/’);
if (p == NULL) p = wadfile.filename[i];
else p++;
if (strcmp(wadfile.filename[i], “zeldaTp.dat”)==0) {
return WADCheckSavedataZD(wadfile.filedata[i]);
}
}
}

http://hackmii.com/2008/06/wii-menu-tp-hack-killer-analysis/

KristenBaldousor
June 21st, 2008, 20:14
I really can't find any exploit, is pretty tight code i must say, the again, I can't nearly understand most of the code, still looked for some flaws or leaked memory traces and couldn't finf any.

I consider myself still an apprentice of C and C++, even though I already graduated from college, still got a long road to follow before I can call myself a good programmer, :P

BTW, are those happy faces part of the code, what do they do??? I had never seen them?? they must be some pretty advance code i never got a hold of while I was on the career, xDDDDDDD