Twilight Hack/Exploit killer
Jump to navigation
Jump to search
// 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:Open 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));
#ifdef 3_3
if (bytes_read != _align_size(file_length, 32)) { // by making the file length not divisible by 32, bytes_read will be less than the aligned size, jumping to the end without deleting the save
#else
if (bytes_read != file_length) {
#endif
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 + 0x56, 8)) return 0; // random strings
if (!_check_strlen(buf + 0x60, 8)) return 0; // inside savegame
if (!_check_strlen(buf + 0x7A, 8)) return 0;
if (!_check_strlen(buf + 0x96, 8)) return 0;
if (!_check_strlen(buf + 0x1BC, 17)) return 0; // player name
if (!_check_strlen(buf + 0x1CD, 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 + 0x2008 + 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;
#ifdef 3_4
int res = 1;
#endif
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(p, "zeldaTp.dat")==0) {
#ifdef 3_3
return WADCheckSavedataZD(wadfile.filedata[i]); // there should not be a "return" here; this means only the first zeldaTp.dat is checked
#else
#ifdef 3_4
res = WADCheckSavedataZD(wadfile.filedata[i]); // this means only the sanity of the last zeldaTp.dat matters
#else
if (!WADCheckSavedataZD(wadfile.filedata[i]))
return 0;
#endif
#endif
}
}
#ifdef 3_4
return res;
#else
#ifndef 3_3
return 1;
#endif
#endif
}