mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-05 02:55:07 +01:00
c9b7cf70b4
first try the 00000000.app with the system language, then with english. if there is still no name for the title, look in banner.bin also made a kick-ass clone of the wii settings screen to adjust the normal wii settings. it is after all the channels.
681 lines
13 KiB
C
681 lines
13 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <gccore.h>
|
|
#include <ogcsys.h>
|
|
|
|
#include "utils.h"
|
|
#include "../settings/cfg.h"
|
|
#include "fatmounter.h"
|
|
#include "id.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;
|
|
}
|
|
|
|
s32 Uninstall_RemoveTicket(u64 tid)
|
|
{
|
|
static tikview viewdata[0x10] ATTRIBUTE_ALIGN(32);
|
|
|
|
u32 cnt, views;
|
|
s32 ret;
|
|
|
|
/* Get number of ticket views */
|
|
ret = ES_GetNumTicketViews(tid, &views);
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
}
|
|
|
|
if (!views) {
|
|
//printf(" No tickets found!\n");
|
|
return 1;
|
|
} else if (views > 16) {
|
|
//printf(" Too many ticket views! (views = %d)\n", views);
|
|
return -1;
|
|
}
|
|
|
|
/* Get ticket views */
|
|
ret = ES_GetTicketViews(tid, viewdata, views);
|
|
if (ret < 0) {
|
|
//printf(" \n\tError! ES_GetTicketViews (ret = %d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Remove tickets */
|
|
for (cnt = 0; cnt < views; cnt++) {
|
|
ret = ES_DeleteTicket(&viewdata[cnt]);
|
|
if (ret < 0) {
|
|
//printf(" Error! (view = %d, ret = %d)\n", cnt, ret);
|
|
return ret;
|
|
}
|
|
}
|
|
//printf(" OK!\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
s32 Uninstall_DeleteTitle(u32 title_u, u32 title_l)
|
|
{
|
|
s32 ret;
|
|
char filepath[256];
|
|
sprintf(filepath, "/title/%08x/%08x", title_u, title_l);
|
|
|
|
/* Remove title */
|
|
ret = ISFS_Delete(filepath);
|
|
return ret;
|
|
}
|
|
|
|
s32 Uninstall_DeleteTicket(u32 title_u, u32 title_l)
|
|
{
|
|
s32 ret;
|
|
|
|
char filepath[256];
|
|
sprintf(filepath, "/ticket/%08x/%08x.tik", title_u, title_l);
|
|
|
|
/* Delete ticket */
|
|
ret = ISFS_Delete(filepath);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//carefull when using this function
|
|
//it will force remove stuff even if something fails
|
|
s32 Uninstall_FromTitle(const u64 tid)
|
|
{
|
|
s32 contents_ret, tik_ret, title_ret, ret;
|
|
u32 id = tid & 0xFFFFFFFF, kind = tid >> 32;
|
|
contents_ret = tik_ret = title_ret = ret = 0;
|
|
|
|
if (kind == 1)
|
|
{
|
|
// Delete title and ticket at FS level.
|
|
tik_ret = Uninstall_DeleteTicket(kind, id);
|
|
title_ret = Uninstall_DeleteTitle(kind, id);
|
|
contents_ret = title_ret;
|
|
}
|
|
else
|
|
{
|
|
// Remove title (contents and ticket)
|
|
tik_ret = Uninstall_RemoveTicket(tid);
|
|
contents_ret = ES_DeleteTitleContent(tid);
|
|
title_ret = ES_DeleteTitle(tid);
|
|
|
|
|
|
// Attempt forced uninstall if something fails
|
|
if (tik_ret < 0 || contents_ret < 0 || title_ret < 0){
|
|
tik_ret = Uninstall_DeleteTicket(kind, id);
|
|
title_ret = Uninstall_DeleteTitle(kind, id);
|
|
contents_ret = title_ret;
|
|
|
|
}
|
|
}
|
|
if (tik_ret < 0 && contents_ret < 0 && title_ret < 0)
|
|
ret = -1;
|
|
else if (tik_ret < 0 || contents_ret < 0 || title_ret < 0)
|
|
ret = 1;
|
|
else
|
|
ret = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------
|
|
taken from anytitledeleter
|
|
name.c -- functions for determining the name of a title
|
|
|
|
Copyright (C) 2009 MrClick
|
|
|
|
-------------------------------------------------------------*/
|
|
|
|
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 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, int lang){
|
|
/*
|
|
languages
|
|
0jap
|
|
2eng
|
|
4german
|
|
6french
|
|
8spanish
|
|
10italian
|
|
12dutch
|
|
*/
|
|
// 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);
|
|
Identify_SU();
|
|
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
|
|
if(strlen(str[lang]) > 1){
|
|
sprintf(name, "%s", str[lang]);
|
|
if (strlen(str[lang+1]) > 1)
|
|
sprintf(name, "%s (%s)", name, str[lang+1]);
|
|
}
|
|
else{
|
|
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;
|
|
}
|
|
|
|
|
|
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 factory 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|