#include #include #include #include #include #include #include "utils.h" #include "../settings/cfg.h" #include "fatmounter.h" #define MAX_TITLES 256 s32 Title_GetList(u64 **outbuf, u32 *outlen) { u64 *titles = NULL; u32 len, nb_titles; s32 ret; /* Get number of titles */ ret = ES_GetNumTitles(&nb_titles); if (ret < 0) return ret; /* Calculate buffer lenght */ len = round_up(sizeof(u64) * nb_titles, 32); /* Allocate memory */ titles = memalign(32, len); if (!titles) return -1; /* Get titles */ ret = ES_GetTitles(titles, nb_titles); if (ret < 0) goto err; /* Set values */ *outbuf = titles; *outlen = nb_titles; return 0; err: /* Free memory */ if (titles) free(titles); return ret; } s32 Title_GetTicketViews(u64 tid, tikview **outbuf, u32 *outlen) { tikview *views = NULL; u32 nb_views; s32 ret; /* Get number of ticket views */ ret = ES_GetNumTicketViews(tid, &nb_views); if (ret < 0) return ret; /* Allocate memory */ views = (tikview *)memalign(32, sizeof(tikview) * nb_views); if (!views) return -1; /* Get ticket views */ ret = ES_GetTicketViews(tid, views, nb_views); if (ret < 0) goto err; /* Set values */ *outbuf = views; *outlen = nb_views; return 0; err: /* Free memory */ if (views) free(views); return ret; } s32 Title_GetTMD(u64 tid, signed_blob **outbuf, u32 *outlen) { void *p_tmd = NULL; u32 len; s32 ret; /* Get TMD size */ ret = ES_GetStoredTMDSize(tid, &len); if (ret < 0) return ret; /* Allocate memory */ p_tmd = memalign(32, round_up(len, 32)); if (!p_tmd) return -1; /* Read TMD */ ret = ES_GetStoredTMD(tid, p_tmd, len); if (ret < 0) goto err; /* Set values */ *outbuf = p_tmd; *outlen = len; return 0; err: /* Free memory */ if (p_tmd) free(p_tmd); return ret; } s32 Title_GetVersion(u64 tid, u16 *outbuf) { signed_blob *p_tmd = NULL; tmd *tmd_data = NULL; u32 len; s32 ret; /* Get title TMD */ ret = Title_GetTMD(tid, &p_tmd, &len); if (ret < 0) return ret; /* Retrieve TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); /* Set values */ *outbuf = tmd_data->title_version; /* Free memory */ free(p_tmd); return 0; } s32 Title_GetSysVersion(u64 tid, u64 *outbuf) { signed_blob *p_tmd = NULL; tmd *tmd_data = NULL; u32 len; s32 ret; /* Get title TMD */ ret = Title_GetTMD(tid, &p_tmd, &len); if (ret < 0) return ret; /* Retrieve TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); /* Set values */ *outbuf = tmd_data->sys_version; /* Free memory */ free(p_tmd); return 0; } s32 Title_GetSize(u64 tid, u32 *outbuf) { signed_blob *p_tmd = NULL; tmd *tmd_data = NULL; u32 cnt, len, size = 0; s32 ret; /* Get title TMD */ ret = Title_GetTMD(tid, &p_tmd, &len); if (ret < 0) return ret; /* Retrieve TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); /* Calculate title size */ for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { tmd_content *content = &tmd_data->contents[cnt]; /* Add content size */ size += content->size; } /* Set values */ *outbuf = size; /* Free memory */ free(p_tmd); return 0; } s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen) { u8 *buffer = NULL; u64 *list = NULL; u32 count, cnt, idx; s32 ret; /* Get title list */ ret = Title_GetList(&list, &count); if (ret < 0) return ret; /* Count IOS */ for (cnt = idx = 0; idx < count; idx++) { u32 tidh = (list[idx] >> 32); u32 tidl = (list[idx] & 0xFFFFFFFF); /* Title is IOS */ if ((tidh == 0x1) && (tidl >= 3) && (tidl <= 255)) cnt++; } /* Allocate memory */ buffer = (u8 *)memalign(32, cnt); if (!buffer) { ret = -1; goto out; } /* Copy IOS */ for (cnt = idx = 0; idx < count; idx++) { u32 tidh = (list[idx] >> 32); u32 tidl = (list[idx] & 0xFFFFFFFF); /* Title is IOS */ if ((tidh == 0x1) && (tidl >= 3) && (tidl <= 255)) buffer[cnt++] = (u8)(tidl & 0xFF); } /* Set values */ *outbuf = buffer; *outlen = cnt; goto out; out: /* Free memory */ if (list) free(list); return ret; } /*------------------------------------------------------------- taken from anytitledeleter name.c -- functions for determining the name of a title Copyright (C) 2009 MrClick -------------------------------------------------------------*/ // Max number of entries in the database #define MAX_DB 1024 // Max name length #define MAX_LINE 80 // Contains all title ids (e.g.: "HAC") static char **__db_i; // Contains all title names (e.g.: "Mii Channel") static char **__db; // Contains the number of entries in the database static u32 __db_cnt = 0; s32 loadDatabase(){ FILE *fdb; char dbfile[100]; snprintf(dbfile,sizeof(dbfile),"SD:/database.txt"); // Init SD card access, open database file and check if it worked //fatInitDefault(); SDCard_Init(); fdb = fopen(dbfile, "r"); if (fdb == NULL) return -1; // Allocate memory for the database __db_i = calloc(MAX_DB, sizeof(char*)); __db = calloc(MAX_DB, sizeof(char*)); // Define the line buffer. Each line in the db file will be stored here first char line[MAX_LINE]; line[sizeof(line)] = 0; // Generic char buffer and counter variable char byte; u32 i = 0; // Read each character from the file do { byte = fgetc(fdb); // In case a line was longer than MAX_LINE if (i == -1){ // Read bytes till a new line is hit if (byte == 0x0A) i = 0; // In case were still good with the line length } else { // Add the new byte to the line buffer line[i] = byte; i++; // When a new line is hit or MAX_LINE is reached if (byte == 0x0A || i == sizeof(line) - 1) { // Terminate finished line to create a string line[i] = 0; // When the line is not a comment or not to short if (line[0] != '#' && i > 5){ // Allocate and copy title id to database __db_i[__db_cnt] = calloc(4, sizeof(char*)); memcpy(__db_i[__db_cnt], line, 3); __db_i[__db_cnt][3] = 0; // Allocate and copy title name to database __db[__db_cnt] = calloc(i - 4, sizeof(char*)); memcpy(__db[__db_cnt], line + 4, i - 4); __db[__db_cnt][i - 5] = 0; // Check that the next line does not overflow the database __db_cnt++; if (__db_cnt == MAX_DB) break; } // Set routine to ignore all bytes in the line when MAX_LINE is reached if (byte == 0x0A) i = 0; else i = -1; } } } while (!feof(fdb)); // Close database file; we are done with it fclose(fdb); return 0; } void freeDatabase(){ u32 i = 0; for(; i < __db_cnt; i++){ free(__db_i[i]); free(__db[i]); } free(__db_i); free(__db); } s32 getDatabaseCount(){ return __db_cnt; } s32 __convertWiiString(char *str, u8 *data, u32 cnt){ u32 i = 0; for(; i < cnt; data += 2){ u16 *chr = (u16*)data; if (*chr == 0) break; // ignores all but ASCII characters else if (*chr >= 0x20 && *chr <= 0x7E) str[i] = *chr; else str[i] = '.'; i++; } str[i] = 0; return 0; } s32 getNameDB(char* name, char* id){ // Return fixed values for special entries if (strncmp(id, "IOS", 3) == 0){ sprintf(name, "Operating System %s", id); return 0; } if (strncmp(id, "MIOS", 3) == 0){ sprintf(name, "Gamecube Compatibility Layer"); return 0; } if (strncmp(id, "SYSMENU", 3) == 0){ sprintf(name, "System Menu"); return 0; } if (strncmp(id, "BC", 2) == 0){ sprintf(name, "BC"); return 0; } // Create an ? just in case the function aborts prematurely sprintf(name, "?"); u32 i; u8 db_found = 0; // Compare each id in the database to the title id for (i = 0; i < __db_cnt; i++) if (strncmp(id, __db_i[i], 3) == 0){ db_found = 1; break; } if (db_found == 0) // Return -1 if no mathcing entry was found return -1; else { // Get name from database once a matching id was found sprintf(name, __db[i]); return 0; } } s32 getNameBN(char* name, u64 id){ // Terminate the name string just in case the function exits prematurely name[0] = 0; // Create a string containing the absolute filename char file[256] __attribute__ ((aligned (32))); sprintf(file, "/title/%08x/%08x/data/banner.bin", (u32)(id >> 32), (u32)id); // Bring the Wii into the title's userspace if (ES_SetUID(id) < 0){ // Should that fail repeat after setting permissions to system menu mode // Identify_SysMenu(); // if (ES_SetUID(id) < 0) // return -1; } // Try to open file s32 fh = ISFS_Open(file, ISFS_OPEN_READ); // If a title does not have a banner.bin bail out if (fh == -106) return -2; // If it fails try to open again after identifying as SU if (fh == -102){ // Identify_SU(); // fh = ISFS_Open(file, ISFS_OPEN_READ); } // If the file won't open else if (fh < 0) return fh; // Seek to 0x20 where the name is stored ISFS_Seek(fh, 0x20, 0); // Read a chunk of 256 bytes from the banner.bin u8 *data = memalign(32, 0x100); if (ISFS_Read(fh, data, 0x100) < 0){ ISFS_Close(fh); free(data); return -3; } // Prepare the strings that will contain the name of the title char name1[0x41] __attribute__ ((aligned (32))); char name2[0x41] __attribute__ ((aligned (32))); name1[0x40] = 0; name2[0x40] = 0; __convertWiiString(name1, data + 0x00, 0x40); __convertWiiString(name2, data + 0x40, 0x40); free(data); // Assemble name sprintf(name, "%s", name1); if (strlen(name2) > 1) sprintf(name, "%s (%s)", name, name2); // Close the banner.bin ISFS_Close(fh); // Job well done return 1; } s32 getName00(char* name, u64 id){ // Create a string containing the absolute filename char file[256] __attribute__ ((aligned (32))); sprintf(file, "/title/%08x/%08x/content/00000000.app", (u32)(id >> 32), (u32)id); s32 fh = ISFS_Open(file, ISFS_OPEN_READ); // If the title does not have 00000000.app bail out if (fh == -106) return fh; // In case there is some problem with the permission if (fh == -102){ // Identify as super user // Identify_SU(); // fh = ISFS_Open(file, ISFS_OPEN_READ); } else if (fh < 0) return fh; // Jump to start of the name entries ISFS_Seek(fh, 0x9C, 0); // Read a chunk of 0x22 * 0x2B bytes from 00000000.app u8 *data = memalign(32, 2048); s32 r = ISFS_Read(fh, data, 0x22 * 0x2B); //printf("%s %d\n", file, r);wait_anyKey(); if (r < 0){ ISFS_Close(fh); free(data); return -4; } // Take the entries apart char str[0x22][0x2B]; u8 i = 0; // Convert the entries to ASCII strings for(; i < 0x22; i++) __convertWiiString(str[i], data + (i * 0x2A), 0x2A); // Clean up ISFS_Close(fh); free(data); // Assemble name // Only the English name is returned // There are 6 other language names in the str array sprintf(name, "%s", str[2]); if (strlen(str[3]) > 1) sprintf(name, "%s (%s)", name, str[3]); // Job well done return 2; } s32 printContent(u64 tid){ char dir[256] __attribute__ ((aligned (32))); sprintf(dir, "/title/%08x/%08x/content", (u32)(tid >> 32), (u32)tid); u32 num = 64; static char list[8000] __attribute__((aligned(32))); ISFS_ReadDir(dir, list, &num); char *ptr = list; u8 br = 0; for (; strlen(ptr) > 0; ptr += strlen(ptr) + 1){ printf(" %-12.12s", ptr); br++; if (br == 4) { br = 0; printf("\n"); } } if (br != 0) printf("\n"); return num; } s32 getTitle_Name(char* name, u64 id, char *tid){ char buf[256] __attribute__ ((aligned (32))); s32 r = -1; // Determine the title's name database/banner/00000000.app r = getNameDB(buf, tid); if (r < 0) r = getNameBN(buf, id); if (r < 0) r = getName00(buf, id); switch (r){ // In case a name was found in the database case 0: sprintf(name, "%s", buf); break; // In case a name was found in the banner.bin case 1: sprintf(name, "*%s*", buf); break; // In case a name was found in the 00000000.app case 2: sprintf(name, "+%s+", buf); break; // In case no proper name was found return a ? default: sprintf(name, "Unknown Title"); break; } return 0; } char *titleText(u32 kind, u32 title){ static char text[10]; if (kind == 1){ // If we're dealing with System Titles, use custom names switch (title){ case 1: strcpy(text, "BOOT2"); break; case 2: strcpy(text, "SYSMENU"); break; case 0x100: strcpy(text, "BC"); break; case 0x101: strcpy(text, "MIOS"); break; default: sprintf(text, "IOS%u", title); break; } } else { // Otherwise, just convert the title to ASCII int i =32, j = 0; do { u8 temp; i -= 8; temp = (title >> i) & 0x000000FF; if (temp < 32 || temp > 126) text[j] = '.'; else text[j] = temp; j++; } while (i > 0); text[4] = 0; } return text; } /*------------------------------------------------------------- from any title deleter titles.c -- functions for grabbing all titles of a certain type Copyright (C) 2008 tona -------------------------------------------------------------*/ u32 __titles_init = 0; u32 __num_titles; static u64 __title_list[MAX_TITLES] ATTRIBUTE_ALIGN(32); s32 __getTitles() { s32 ret; ret = ES_GetNumTitles(&__num_titles); if (ret <0) return ret; if (__num_titles > MAX_TITLES) return -1; ret = ES_GetTitles(__title_list, __num_titles); if (ret <0) return ret; __titles_init = 1; return 0; } s32 getTitles_TypeCount(u32 type, u32 *count) { s32 ret = 0; u32 type_count; if (!__titles_init) ret = __getTitles(); if (ret <0) return ret; int i; type_count = 0; for (i=0; i < __num_titles; i++) { u32 upper, lower; upper = __title_list[i] >> 32; lower = __title_list[i] & 0xFFFFFFFF; if((upper == type)&& ((lower !=0x48414741)&&//this filters out haga,haaa, hafa. dupe foctory channels that don't load (lower !=0x48414141)&&//since we dont care about apps that dont load for what we are doing (lower !=0x48414641))) type_count++; } *count = type_count; return ret; } s32 getTitles_Type(u32 type, u32 *titles, u32 count) { s32 ret = 0; u32 type_count; if (!__titles_init) ret = __getTitles(); if (ret <0) return ret; int i; type_count = 0; for (i=0; type_count < count && i < __num_titles; i++) { u32 upper, lower; upper = __title_list[i] >> 32; lower = __title_list[i] & 0xFFFFFFFF; if((upper == type)&& ((lower !=0x48414741)&& (lower !=0x48414141)&& (lower !=0x48414641))) { titles[type_count]=lower; type_count++; } } if (type_count < count) return -2; __titles_init = 0; return 0; }