added HBF-Installer to GIT

This commit is contained in:
Christopher Roy Bratusek 2011-10-15 17:31:29 +02:00
parent 4cd74c3b37
commit c271b85907
23 changed files with 2468 additions and 0 deletions

137
installer/Makefile Normal file
View File

@ -0,0 +1,137 @@
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
include $(DEVKITPPC)/wii_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := boot
BUILD := build
SOURCES := source \
source/Network \
../svnrev
DATA := data
INCLUDES :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE)
CXXFLAGS = $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwiiuse -lbte -logc -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
WADFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.wad*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
export LD := $(CC)
else
export LD := $(CXX)
endif
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
$(sFILES:.s=.o) $(SFILES:.S=.o)
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD) \
-I$(LIBOGC_INC)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
-L$(LIBOGC_LIB)
export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol
#---------------------------------------------------------------------------------
run:
wiiload $(TARGET).dol
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).dol: $(OUTPUT).elf
$(OUTPUT).elf: $(OFILES)
#---------------------------------------------------------------------------------
# This rule links in binary data with extension
#---------------------------------------------------------------------------------
%.wad.o : %.wad
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
-include $(DEPENDS)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

BIN
installer/WadMii.exe Normal file

Binary file not shown.

View File

@ -0,0 +1,122 @@
#include "dns.h"
/**
* Resolves a domainname to an ip address
* It makes use of net_gethostbyname from libogc, which in turn makes use of a Wii BIOS function
* Just like the net_gethostbyname function this function is NOT threadsafe!
*
* @param char* The domain name to resolve
* @return u32 The ipaddress represented by four bytes inside an u32 (in network order)
*/
u32 getipbyname(char *domain)
{
//Care should be taken when using net_gethostbyname,
//it returns a static buffer which makes it not threadsafe
//TODO: implement some locking mechanism to make below code atomic
struct hostent *host = net_gethostbyname(domain);
if(host == NULL) {
return 0;
}
u32 *ip = (u32*)host->h_addr_list[0];
return *ip;
}
//Defines how many DNS entries should be cached by getipbynamecached()
#define MAX_DNS_CACHE_ENTRIES 20
//The cache is defined as a linked list,
//The last resolved domain name will always be at the front
//This will allow heavily used domainnames to always stay cached
struct dnsentry {
char *domain;
u32 ip;
struct dnsentry *nextnode;
} ;
static struct dnsentry *firstdnsentry = NULL;
static int dnsentrycount = 0;
/**
* Performs the same function as getipbyname(),
* except that it will prevent extremely expensive net_gethostbyname() calls by caching the result
*/
u32 getipbynamecached(char *domain)
{
//Search if this domainname is already cached
struct dnsentry *node = firstdnsentry;
struct dnsentry *previousnode = NULL;
while(node != NULL)
{
if(strcmp(node->domain, domain) == 0)
{
//DNS node found in the cache, move it to the front of the list
if(previousnode != NULL)
previousnode->nextnode = node->nextnode;
if(node != firstdnsentry)
node->nextnode = firstdnsentry;
firstdnsentry = node;
return node->ip;
}
//Go to the next element in the list
previousnode = node;
node = node->nextnode;
}
u32 ip = getipbyname(domain);
//No cache of this domain could be found, create a cache node and add it to the front of the cache
struct dnsentry *newnode = malloc(sizeof(struct dnsentry));
if(newnode == NULL) {
return ip;
}
newnode->ip = ip;
newnode->domain = malloc(strlen(domain)+1);
if(newnode->domain == NULL)
{
free(newnode);
return ip;
}
strcpy(newnode->domain, domain);
newnode->nextnode = firstdnsentry;
firstdnsentry = newnode;
dnsentrycount++;
//If the cache grows too big delete the last (and probably least important) node of the list
if(dnsentrycount > MAX_DNS_CACHE_ENTRIES)
{
struct dnsentry *node = firstdnsentry;
struct dnsentry *previousnode = NULL;
//Fetch the last two elements of the list
while(node->nextnode != NULL)
{
previousnode = node;
node = node->nextnode;
}
if(node == NULL)
{
printf("Configuration error, MAX_DNS_ENTRIES reached while the list is empty\n");
exit(1);
} else if(previousnode == NULL)
{
firstdnsentry = NULL;
} else {
previousnode->nextnode = NULL;
}
free(node->domain);
free(node);
dnsentrycount--;
}
return newnode->ip;
}

View File

@ -0,0 +1,23 @@
#ifndef _DNS_H_
#define _DNS_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h> //usleep
#include <network.h>
#ifdef __cplusplus
extern "C"
{
#endif
u32 getipbyname(char *domain);
u32 getipbynamecached(char *domain);
#ifdef __cplusplus
}
#endif
#endif /* _DNS_H_ */

View File

@ -0,0 +1,256 @@
#include "http.h"
/**
* Emptyblock is a statically defined variable for functions to return if they are unable
* to complete a request
*/
const struct block emptyblock = {0, NULL};
//The maximum amount of bytes to send per net_write() call
#define NET_BUFFER_SIZE 1024
// Write our message to the server
static s32 send_message(s32 server, char *msg) {
s32 bytes_transferred = 0;
s32 remaining = strlen(msg);
while (remaining) {
if ((bytes_transferred = net_write(server, msg, remaining > NET_BUFFER_SIZE ? NET_BUFFER_SIZE : remaining)) > 0) {
remaining -= bytes_transferred;
usleep (20 * 1000);
} else if (bytes_transferred < 0) {
return bytes_transferred;
} else {
return -ENODATA;
}
}
return 0;
}
/**
* Connect to a remote server via TCP on a specified port
*
* @param u32 ip address of the server to connect to
* @param u32 the port to connect to on the server
* @return s32 The connection to the server (negative number if connection could not be established)
*/
static s32 server_connect(u32 ipaddress, u32 socket_port) {
//Initialize socket
s32 connection = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (connection < 0) return connection;
struct sockaddr_in connect_addr;
memset(&connect_addr, 0, sizeof(connect_addr));
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = socket_port;
connect_addr.sin_addr.s_addr= ipaddress;
//Attemt to open the socket
if (net_connect(connection, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) == -1) {
net_close(connection);
return -1;
}
return connection;
}
//The amount of memory in bytes reserved initially to store the HTTP response in
//Be careful in increasing this number, reading from a socket on the Wii
//will fail if you request more than 20k or so
#define HTTP_BUFFER_SIZE 1024 * 5
//The amount of memory the buffer should expanded with if the buffer is full
#define HTTP_BUFFER_GROWTH 1024 * 5
/**
* This function reads all the data from a connection into a buffer which it returns.
* It will return an empty buffer if something doesn't go as planned
*
* @param s32 connection The connection identifier to suck the response out of
* @return block A 'block' struct (see http.h) in which the buffer is located
*/
struct block read_message(s32 connection)
{
//Create a block of memory to put in the response
struct block buffer;
buffer.data = malloc(HTTP_BUFFER_SIZE);
buffer.size = HTTP_BUFFER_SIZE;
if(buffer.data == NULL) {
return emptyblock;
}
//The offset variable always points to the first byte of memory that is free in the buffer
u32 offset = 0;
while(1)
{
//Fill the buffer with a new batch of bytes from the connection,
//starting from where we left of in the buffer till the end of the buffer
s32 bytes_read = net_read(connection, buffer.data + offset, buffer.size - offset);
//Anything below 0 is an error in the connection
if(bytes_read < 0)
{
//printf("Connection error from net_read() Errorcode: %i\n", bytes_read);
return emptyblock;
}
//No more bytes were read into the buffer,
//we assume this means the HTTP response is done
if(bytes_read == 0)
{
break;
}
offset += bytes_read;
//Check if we have enough buffer left over,
//if not expand it with an additional HTTP_BUFFER_GROWTH worth of bytes
if(offset >= buffer.size)
{
buffer.size += HTTP_BUFFER_GROWTH;
buffer.data = realloc(buffer.data, buffer.size);
if(buffer.data == NULL)
{
return emptyblock;
}
}
}
//At the end of above loop offset should be precisely the amount of bytes that were read from the connection
buffer.size = offset;
//Shrink the size of the buffer so the data fits exactly in it
realloc(buffer.data, buffer.size);
return buffer;
}
/**
* Downloads the contents of a URL to memory
* This method is not threadsafe (because networking is not threadsafe on the Wii)
*/
struct block downloadfile(const char *url)
{
//Check if the url starts with "http://", if not it is not considered a valid url
if(strncmp(url, "http://", strlen("http://")) != 0)
{
//printf("URL '%s' doesn't start with 'http://'\n", url);
return emptyblock;
}
//Locate the path part of the url by searching for '/' past "http://"
char *path = strchr(url + strlen("http://"), '/');
//At the very least the url has to end with '/', ending with just a domain is invalid
if(path == NULL)
{
//printf("URL '%s' has no PATH part\n", url);
return emptyblock;
}
//Extract the domain part out of the url
int domainlength = path - url - strlen("http://");
if(domainlength == 0)
{
//printf("No domain part in URL '%s'\n", url);
return emptyblock;
}
char domain[domainlength + 1];
strncpy(domain, url + strlen("http://"), domainlength);
domain[domainlength] = '\0';
//Parsing of the URL is done, start making an actual connection
u32 ipaddress = getipbynamecached(domain);
if(ipaddress == 0)
{
//printf("\ndomain %s could not be resolved", domain);
return emptyblock;
}
s32 connection = server_connect(ipaddress, 80);
if(connection < 0) {
//printf("Error establishing connection");
return emptyblock;
}
//Form a nice request header to send to the webserver
char* headerformat = "GET %s HTTP/1.0\r\nHost: %s\r\nReferer: %s\r\nCache-Control: no-cache\r\n\r\n";
char header[strlen(headerformat) + strlen(path) + strlen(domain)*2 + 1];
sprintf(header, headerformat, path, domain, domain);
//Do the request and get the response
send_message(connection, header);
struct block response = read_message(connection);
net_close(connection);
//Search for the 4-character sequence \r\n\r\n in the response which signals the start of the http payload (file)
unsigned char *filestart = NULL;
u32 filesize = 0;
int i;
for(i = 3; i < response.size; i++)
{
if(response.data[i] == '\n' &&
response.data[i-1] == '\r' &&
response.data[i-2] == '\n' &&
response.data[i-3] == '\r' &&
response.data[9] == 50 ) // hamachi-mp.bplaced.net / 50 vorhanden | 52 nicht vorhanden
{
filestart = response.data + i + 1;
filesize = response.size - i - 1;
break;
}
}
if(filestart == NULL)
{
//printf("HTTP Response was without a file\n");
free(response.data);
return emptyblock;
}
//Copy the file part of the response into a new memoryblock to return
struct block file;
file.data = malloc(filesize);
file.size = filesize;
if(file.data == NULL)
{
//printf("No more memory to copy file from HTTP response\n");
free(response.data);
return emptyblock;
}
memcpy(file.data, filestart, filesize);
//Dispose of the original response
free(response.data);
return file;
}
int network_read(int connection, u8 *buf, u32 len)
{
u32 read = 0;
s32 ret = -1;
while (read < len)
{
ret = net_read(connection, buf + read, len - read);
if (ret < 0)
return ret;
if (!ret)
break;
read += ret;
}
return read;
}

View File

@ -0,0 +1,31 @@
#ifndef _HTTP_H_
#define _HTTP_H_
#include <errno.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include "dns.h"
/**
* A simple structure to keep track of the size of a malloc()ated block of memory
*/
struct block
{
u32 size;
unsigned char *data;
};
extern const struct block emptyblock;
struct block downloadfile(const char *url);
int network_read(int connection, u8 *buf, u32 len);
#ifdef __cplusplus
}
#endif
#endif /* _HTTP_H_ */

View File

@ -0,0 +1,187 @@
/***************************************************************************
* Copyright (C) 2009
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* networkops.cpp
*
* Network operations
* for Wii-Xplorer 2009
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ogcsys.h>
#include <ogc/machine/processor.h>
#include "http.h"
#include <malloc.h>
#include <string>
#include <vector>
//static NetReceiver Receiver;
static bool networkinit = false;
static bool networkerror = false;
static char IP[16];
static u8 * ThreadStack = NULL;
static bool firstRun = false;
static lwp_t networkthread = LWP_THREAD_NULL;
static bool networkHalt = true;
static bool exitRequested = false;
/****************************************************************************
* Initialize_Network
***************************************************************************/
void Initialize_Network(void)
{
if(networkinit)
return;
s32 result;
result = if_config(IP, NULL, NULL, true);
if(result < 0) {
networkinit = false;
networkerror = true;
return;
}
networkinit = true;
networkerror = false;
return;
}
/****************************************************************************
* DeInit_Network
***************************************************************************/
void DeInit_Network(void)
{
net_deinit();
}
/****************************************************************************
* Check if network was initialised
***************************************************************************/
bool IsNetworkInit(void)
{
return networkinit;
}
/****************************************************************************
* Check that network has error
***************************************************************************/
bool IsNetworkError(void)
{
return networkerror;
}
/****************************************************************************
* Get network IP
***************************************************************************/
char * GetNetworkIP(void)
{
return IP;
}
/****************************************************************************
* HaltNetwork
***************************************************************************/
void HaltNetworkThread()
{
networkHalt = true;
// wait for thread to finish
while(!LWP_ThreadIsSuspended(networkthread))
{
usleep(100);
}
}
/****************************************************************************
* ResumeNetworkThread
***************************************************************************/
void ResumeNetworkThread()
{
networkHalt = false;
LWP_ResumeThread(networkthread);
}
/*********************************************************************************
* Networkthread for background network initialize and update check with idle prio
*********************************************************************************/
static void * networkinitcallback(void *arg)
{
while(!exitRequested)
{
if(networkHalt)
{
LWP_SuspendThread(networkthread);
usleep(100);
continue;
}
if(!networkinit)
Initialize_Network();
if(!firstRun)
{
LWP_SetThreadPriority(networkthread, 0);
firstRun = true;
}
usleep(200000);
}
return NULL;
}
/****************************************************************************
* InitNetworkThread with priority 0 (idle)
***************************************************************************/
void InitNetworkThread()
{
ThreadStack = (u8 *) memalign(32, 16384);
if(!ThreadStack)
return;
LWP_CreateThread (&networkthread, networkinitcallback, NULL, ThreadStack, 16384, 30);
ResumeNetworkThread();
}
/****************************************************************************
* ShutdownThread
***************************************************************************/
void ShutdownNetworkThread()
{
exitRequested = true;
networkinit = false;
networkerror = false;
if(networkthread != LWP_THREAD_NULL)
{
ResumeNetworkThread();
LWP_JoinThread (networkthread, NULL);
networkthread = LWP_THREAD_NULL;
}
if(ThreadStack)
free(ThreadStack);
ThreadStack = NULL;
}

View File

@ -0,0 +1,39 @@
/****************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef _NETWORKOPS_H_
#define _NETWORKOPS_H_
void Initialize_Network(void);
void DeInit_Network(void);
bool IsNetworkInit(void);
bool IsNetworkError(void);
char * GetNetworkIP(void);
void HaltNetworkThread();
void ResumeNetworkThread();
void InitNetworkThread();
void ShutdownNetworkThread();
#endif

View File

@ -0,0 +1,69 @@
#include <gccore.h>
#include <ogc/machine/processor.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "RuntimeIOSPatch.h"
#define MEM_PROT 0xD8B420A
const u8 isfs_permissions_old[] = { 0x42, 0x8B, 0xD0, 0x01, 0x25, 0x66 };
const u8 isfs_permissions_patch[] = { 0x42, 0x8B, 0xE0, 0x01, 0x25, 0x66 };
const u8 setuid_old[] = { 0xD1, 0x2A, 0x1C, 0x39 };
const u8 setuid_patch[] = { 0x46, 0xC0 };
const u8 es_identify_old[] = { 0x28, 0x03, 0xD1, 0x23 };
const u8 es_identify_patch[] = { 0x00, 0x00 };
const u8 hash_old[] = { 0x20, 0x07, 0x4B, 0x0B };
const u8 hash_patch[] = { 0x00 };
const u8 addticket_vers_check[] = { 0xD2, 0x01, 0x4E, 0x56 };
const u8 addticket_patch[] = { 0xE0 };
u32 apply_patch(const char *name, const u8 *old, u32 old_size, const u8 *patch, u32 patch_size, u32 patch_offset)
{
// printf("Applying patch %s.....", name);
u8 *ptr = (u8 *) 0x93400000;
u32 i, found = 0;
u8 *start;
while ((u32) ptr < (0x94000000 - old_size))
{
if(!memcmp(ptr, old, old_size))
{
found++;
start = ptr + patch_offset;
for (i = 0; i < patch_size; i++)
*(start + i) = patch[i];
ptr += patch_size;
DCFlushRange((u8 *) (((u32) start) >> 5 << 5), (patch_size >> 5 << 5) + 64);
}
ptr++;
}
// if(found)
// printf("Patched\n");
// else
// printf("\n");
return found;
}
u32 runtimePatchApply()
{
u32 count = 0;
write16(MEM_PROT, 0);
count += apply_patch("Trucha", hash_old,
sizeof(hash_old), hash_patch, sizeof(hash_patch), 1);
count += apply_patch("ES_Identify", es_identify_old,
sizeof(es_identify_old), es_identify_patch, sizeof(es_identify_patch),
2);
count += apply_patch("NAND Permissions", isfs_permissions_old,
sizeof(isfs_permissions_old), isfs_permissions_patch,
sizeof(isfs_permissions_patch), 0);
count += apply_patch("add ticket patch", addticket_vers_check,
sizeof(addticket_vers_check), addticket_patch, sizeof(addticket_patch),
0);
count += apply_patch("ES_SetUID", setuid_old, sizeof(setuid_old),
setuid_patch, sizeof(setuid_patch), 0);
write16(MEM_PROT, 1);
return count;
}

View File

@ -0,0 +1,14 @@
#ifndef _RUNTIMEIOSPATCH_H_
#define _RUNTIMEIOSPATCH_H_
#ifdef __cplusplus
extern "C" {
#endif
u32 runtimePatchApply();
#ifdef __cplusplus
}
#endif
#endif

135
installer/source/getios.cpp Normal file
View File

@ -0,0 +1,135 @@
#include <ogcsys.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <string>
#include <vector>
std::vector<int> ioslist;
// Check if this is an IOS stub (according to WiiBrew.org)
bool IsKnownStub(u32 noIOS, s32 noRevision)
{
if (noIOS == 3 && noRevision == 65280) return true;
if (noIOS == 4 && noRevision == 65280) return true;
if (noIOS == 10 && noRevision == 768) return true;
if (noIOS == 11 && noRevision == 256) return true;
if (noIOS == 16 && noRevision == 512) return true;
if (noIOS == 20 && noRevision == 256) return true;
if (noIOS == 30 && noRevision == 2816) return true;
if (noIOS == 40 && noRevision == 3072) return true;
if (noIOS == 50 && noRevision == 5120) return true;
if (noIOS == 51 && noRevision == 4864) return true;
if (noIOS == 52 && noRevision == 5888) return true;
if (noIOS == 60 && noRevision == 6400) return true;
if (noIOS == 70 && noRevision == 6912) return true;
if (noIOS == 222 && noRevision == 65280) return true;
if (noIOS == 223 && noRevision == 65280) return true;
if (noIOS == 249 && noRevision == 65280) return true;
if (noIOS == 250 && noRevision == 65280) return true;
if (noIOS == 254 && noRevision == 2) return true;
if (noIOS == 254 && noRevision == 3) return true;
if (noIOS == 254 && noRevision == 260) return true;
// BootMii As IOS is installed on IOS254 rev 31338
if (noIOS == 254 && noRevision == 31338) return true;
return false;
}
bool listIOS()
{
ioslist.clear();
u32 nbTitles;
if (ES_GetNumTitles(&nbTitles) < 0)
return false;
// Allocate the memory for titles
u64 *titles = (u64*)memalign(32, nbTitles*sizeof(u64));
if (titles == NULL)
return false;
if (ES_GetTitles(titles, nbTitles) < 0)
return false;
int i;
u32 titleID;
// For each titles found
for (i = 0; i < (signed)nbTitles; i++)
{
// Skip non-system titles
if (titles[i] >> 32 != 1) continue;
// Skip the system menu
titleID = titles[i] & 0xFFFFFFFF;
if (titleID == 2) continue;
// Skip BC, MIOS and possible other non-IOS titles
if (titleID > 0xFF) continue;
// Skip the running IOS
if (titleID == 0) continue;
// Skip bootmii IOS
if (titleID == 254) continue;
// Check if this title is an IOS stub
u32 tmdSize;
tmd *iosTMD ATTRIBUTE_ALIGN(32);
// Get the stored TMD size for the title
if (ES_GetStoredTMDSize(0x0000000100000000ULL | titleID, &tmdSize) < 0)
return false;
signed_blob *iosTMDBuffer = (signed_blob *)memalign(32, (tmdSize+32)&(~31));
memset(iosTMDBuffer, 0, tmdSize);
// Get the stored TMD for the title
if (ES_GetStoredTMD(0x0000000100000000ULL | titleID, iosTMDBuffer, tmdSize) < 0)
return false;
iosTMD = (tmd *)SIGNATURE_PAYLOAD(iosTMDBuffer);
free(iosTMDBuffer);
// Get the title version
u8 noVersion = iosTMD->title_version;
bool isStub = false;
// Check if this is an IOS stub (according to WiiBrew.org)
if (IsKnownStub(titleID, iosTMD->title_version))
isStub = true;
else
{
// If the version is 00, it's probably a stub
//
// Stubs have these things in common:
// - Title version is mostly 65280, or even better, the last 2 hexadecimal digits are 0;
// - Stub have one app of their own (type 0x1) and 2 shared apps (type 0x8001).
if (noVersion == 0)
isStub = ((iosTMD->num_contents == 3) && (iosTMD->contents[0].type == 1 && iosTMD->contents[1].type == 0x8001 && iosTMD->contents[2].type == 0x8001));
else
isStub = false;
}
if(!isStub)
ioslist.push_back(titleID);
}
return true;
}
bool getIOS(int ios)
{
for(int i = 0; i < (signed)ioslist.size(); i++)
{
if(ioslist[i] == ios)
return true;
}
return false;
}

View File

@ -0,0 +1,7 @@
#ifndef _GETIOS_H_
#define _GETIOS_H_
bool listIOS();
bool getIOS(int ios);
#endif

33
installer/source/main.cpp Normal file
View File

@ -0,0 +1,33 @@
#include <malloc.h>
#include <wiiuse/wpad.h>
#include "RuntimeIOSPatch.h"
#include "menu.h"
#include "video.h"
#include "wad.h"
#include "Network/network.h"
#define HAVE_AHBPROT ((*(vu32*)0xcd800064 == 0xFFFFFFFF) ? 1 : 0)
//---------------------------------------------------------------------------------
int main(int argc, char **argv) {
//---------------------------------------------------------------------------------
// Initialise the video system
InitNetworkThread();
VIDEO_Init();
Video_SetMode();
// This function initialises the attached controllers
WPAD_Init();
if(HAVE_AHBPROT)
runtimePatchApply();
menu();
SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
return 0;
}

429
installer/source/menu.cpp Normal file
View File

@ -0,0 +1,429 @@
#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <sstream>
#include <vector>
#include <wiiuse/wpad.h>
#include "getios.h"
#include "menu.h"
#include "video.h"
#include "wad.h"
#include "../../svnrev/svnrev.h"
using namespace std;
std::vector<string> text1, text2, text3;
int startpos_x = 6;
int startpos_y = 12;
int menu_main_choice;
void show_menu_head()
{
Con_FgColor(6, 1);
printf("\x1b[%i;%iH", startpos_x, startpos_y);
printf("HBF installer v0.2");
Con_FgColor(7, 1);
printf("\t\t\t\t\t(C) 2011");
Con_FgColor(6, 1);
printf(" hamachi-mp");
}
void fill_menu_main()
{
text1.clear();
stringstream buffer;
buffer << "Install The Homebrew Filter rev" << SvnRev();
text1.push_back(buffer.str());
if(CheckAppFound(GetTitleID()))
text1.push_back("Uninstall The Homebrew Filter");
else
text1.push_back("");
text1.push_back("");
text1.push_back("Copyright");
text1.push_back("");
text1.push_back("Exit");
}
void fill_menu_install_uninstall()
{
text2.push_back("Yes, continue");
text2.push_back("No, take me back");
}
void fill_menu_copyright()
{
text3.push_back("Copyright (C) hamachi-mp");
text3.push_back("");
text3.push_back("Thanks to:");
text3.push_back("\tTeam Twiizers");
text3.push_back("\tdevkitPRO");
text3.push_back("\tWaninkoko (WAD Manager)");
text3.push_back("\tWiiCrazy/I.R.on (Crap Installer)");
}
void menu()
{
mopen();
ISFS_Initialize();
listIOS();
fill_menu_main();
fill_menu_install_uninstall();
fill_menu_copyright();
menu_main_choice = text1.size() -1;
/*
int fgcolor = 3;
int fgbold = 1;
printf("\x1b[1;0H");
printf("fgcolor %i\n", fgcolor);
printf("fgbold %i\n", fgbold);
Con_FgColor(fgcolor, fgbold);
printf("test");
while(1)
{
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);
if(pressed & WPAD_BUTTON_UP)
{
printf("test");
}
else if(pressed & WPAD_BUTTON_1)
{
fgcolor--;
printf("\x1b[1;0H");
Con_FgColor(7, 1);
printf("fgcolor %i\n\n", fgcolor);
Con_FgColor(fgcolor, fgbold);
printf("test");
}
else if(pressed & WPAD_BUTTON_2)
{
fgcolor++;
printf("\x1b[1;0H");
Con_FgColor(7, 1);
printf("fgcolor %i\n\n", fgcolor);
Con_FgColor(fgcolor, fgbold);
printf("test");
}
else if(pressed & WPAD_BUTTON_MINUS)
{
fgbold--;
printf("\x1b[2;0H");
Con_FgColor(7, 1);
printf("fgbold %i\n", fgbold);
Con_FgColor(fgcolor, fgbold);
printf("test");
}
else if(pressed & WPAD_BUTTON_PLUS)
{
fgbold++;
printf("\x1b[2;0H");
Con_FgColor(7, 1);
printf("fgbold %i\n", fgbold);
Con_FgColor(fgcolor, fgbold);
printf("test");
}
else if(pressed & WPAD_BUTTON_HOME)
exit(0);
}
*/
int currentMenu = 0;
while(currentMenu != MENU_EXIT)
{
switch (currentMenu)
{
case MENU_MAIN:
currentMenu = menu_main(menu_main_choice);
break;
case MENU_INSTALL:
currentMenu = menu_install_uninstall(1);
break;
case MENU_UNINSTALL:
currentMenu = menu_install_uninstall(0);
break;
case MENU_INSTALLING:
currentMenu = menu_install();
break;
case MENU_UNINSTALLING:
currentMenu = menu_uninstall();
break;
case MENU_COPYRIGHT:
currentMenu = menu_copyright();
break;
}
}
ISFS_Deinitialize();
}
int menu_main(int scrollpos)
{
Con_Clear();
show_menu_head();
fill_menu_main();
if(text1[scrollpos] == "")
scrollpos = text1.size() -1;
Con_FgColor(3, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y);
printf("Main Menu");
Con_FgColor(7, 1);
for(int i=0; i < (signed)text1.size(); i++)
{
printf("\x1b[%i;%iH", startpos_x +4 +i, startpos_y +3);
printf("%s", text1[i].c_str());
}
bool scroll = true;
while(1)
{
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);
if ( pressed & WPAD_BUTTON_DOWN && scrollpos < (signed)text1.size() -1)
{
scrollpos++;
while(text1[scrollpos] == "")
scrollpos++;
scroll = true;
}
else if ( pressed & WPAD_BUTTON_UP && scrollpos != 0)
{
scrollpos--;
while(text1[scrollpos] == "")
scrollpos--;
scroll = true;
}
if(scroll)
{
for(int i=0; i < (signed)text1.size(); i++)
{
printf("\x1b[%i;%iH", startpos_x +4 +i, startpos_y);
if(i == scrollpos)
printf(">>");
else
printf(" ");
}
scroll = false;
}
if( pressed & WPAD_BUTTON_A )
{
menu_main_choice = scrollpos;
switch(scrollpos)
{
case 0:
return MENU_INSTALL;
case 1:
return MENU_UNINSTALL;
case 3:
return MENU_COPYRIGHT;
default:
return MENU_EXIT;
}
}
}
}
int menu_install_uninstall(int install)
{
Con_Clear();
show_menu_head();
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y);
if(install)
printf("Install The Homebrew Filter now");
else
printf("Uninstall The Homebrew Filter now");
for(int i=0; i < (signed)text2.size(); i++)
{
printf("\x1b[%i;%iH", startpos_x +4 +i, startpos_y +3);
printf("%s", text2[i].c_str());
}
int scrollpos = 1;
bool scroll = true;
while(1)
{
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);
if ( pressed & WPAD_BUTTON_DOWN && scrollpos < (signed)text2.size() -1)
{
scrollpos++;
scroll = true;
}
else if ( pressed & WPAD_BUTTON_UP && scrollpos != 0)
{
scrollpos--;
scroll = true;
}
if(scroll)
{
for(int i=0; i < (signed)text2.size(); i++)
{
printf("\x1b[%d;12H", startpos_x +4 +i);
if(i == scrollpos)
printf(">>");
else
printf(" ");
}
scroll = false;
}
if( pressed & WPAD_BUTTON_A )
{
switch(scrollpos)
{
case 0:
if(install)
return MENU_INSTALLING;
else
return MENU_UNINSTALLING;
break;
case 1:
return MENU_MAIN;
}
}
}
}
int menu_install()
{
Con_Clear();
show_menu_head();
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y);
printf("Installing The Homebrew Filter");
printf("\x1b[%i;%iH", startpos_x +4, startpos_y);
if(Wad_InstallFromMemory(startpos_x, startpos_y) >= 0)
{
if(!getIOS(58))
{
s32 fd;
u32 high = (u32)(GetTitleID() >> 32);
u32 low = (u32)(GetTitleID() & 0xFFFFFFFF);
char filepath[ISFS_MAXPATH];
sprintf(filepath, "/title/%08x/%08x/content/title.tmd", high, low);
static fstats filestats ATTRIBUTE_ALIGN(32);
static u8 filearray[1024] ATTRIBUTE_ALIGN(32);
fd = ISFS_Open(filepath, ISFS_OPEN_READ);
if (fd <= 0)
ISFS_Close(fd);
ISFS_GetFileStats(fd, &filestats);
ISFS_Read(fd, filearray, filestats.file_length);
ISFS_Close(fd);
if(filestats.file_length >= 0)
{
fd = ISFS_Open(filepath, ISFS_OPEN_RW);
if(getIOS(61))
filearray[395] = 61;
else
filearray[395] = IOS_GetVersion();
ISFS_Write(fd, filearray, sizeof( filearray ));
ISFS_Close(fd);
}
}
}
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +8, startpos_y);
printf(">> Continue");
while(1)
{
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);
if( pressed & WPAD_BUTTON_A )
return MENU_MAIN;
}
}
int menu_uninstall()
{
Con_Clear();
show_menu_head();
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y);
printf("Uninstalling The Homebrew Filter");
Wad_UninstallFromMemory(startpos_x, startpos_y);
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +8, startpos_y);
printf(">> Continue");
while(1)
{
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);
if( pressed & WPAD_BUTTON_A )
return MENU_MAIN;
}
}
int menu_copyright()
{
Con_Clear();
show_menu_head();
Con_FgColor(7, 1);
for(int i=0; i < (signed)text3.size(); i++)
{
printf("\x1b[%i;%iH", startpos_x +2 +i, startpos_y);
printf("%s", text3[i].c_str());
}
printf("\x1b[%i;%iH", startpos_x + text3.size() +3, startpos_y);
printf(">> Continue");
while(1)
{
WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);
if( pressed & WPAD_BUTTON_A )
return MENU_MAIN;
}
}

18
installer/source/menu.h Normal file
View File

@ -0,0 +1,18 @@
void menu();
int menu_main(int);
int menu_install_uninstall(int);
int menu_install();
int menu_uninstall();
int menu_copyright();
enum
{
MENU_EXIT = -1,
MENU_MAIN,
MENU_INSTALL,
MENU_UNINSTALL,
MENU_INSTALLING,
MENU_UNINSTALLING,
MENU_COPYRIGHT
};

177
installer/source/sha1.c Normal file
View File

@ -0,0 +1,177 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd if true. */
#define SHA1HANDSOFF
#include <stdio.h>
#include <string.h>
#include "sha1.h"
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#ifdef LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
typedef struct {
unsigned long state[5];
unsigned long count[2];
unsigned char buffer[64];
} SHA1_CTX;
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
{
unsigned long a, b, c, d, e;
typedef union {
unsigned char c[64];
unsigned long l[16];
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static unsigned char workspace[64];
block = (CHAR64LONG16*)workspace;
memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
{
unsigned int i, j;
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29);
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
unsigned long i, j;
unsigned char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, (unsigned char *)"\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1Update(context, (unsigned char *)"\0", 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
i = j = 0;
memset(context->buffer, 0, 64);
memset(context->state, 0, 20);
memset(context->count, 0, 8);
memset(&finalcount, 0, 8);
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
SHA1Transform(context->state, context->buffer);
#endif
}
void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf) {
SHA1_CTX ctx;
SHA1Init(&ctx);
SHA1Update(&ctx, ptr, size);
SHA1Final(outbuf, &ctx);
}

6
installer/source/sha1.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _SHA1_H_
#define _SHA1_H_
void SHA1(unsigned char *, unsigned int, unsigned char *);
#endif

84
installer/source/title.c Normal file
View File

@ -0,0 +1,84 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ogcsys.h>
#include "sha1.h"
#define round_up(x,n) (-(-(x) & -(n)))
s32 Title_ZeroSignature(signed_blob *p_sig)
{
u8 *ptr = (u8 *)p_sig;
/* Fill signature with zeroes */
memset(ptr + 4, 0, SIGNATURE_SIZE(p_sig) - 4);
return 0;
}
s32 Title_FakesignTik(signed_blob *p_tik)
{
tik *tik_data = NULL;
u16 fill;
/* Zero signature */
Title_ZeroSignature(p_tik);
/* Ticket data */
tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik);
for (fill = 0; fill < USHRT_MAX; fill++) {
sha1 hash;
/* Modify ticket padding field */
tik_data->padding = fill;
/* Calculate hash */
SHA1((u8 *)tik_data, sizeof(tik), hash);
/* Found valid hash */
if (!hash[0])
return 0;
}
return -1;
}
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;
}

11
installer/source/title.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _TITLE_H_
#define _TITLE_H_
/* Constants */
#define BLOCK_SIZE 1024
/* Prototypes */
s32 Title_FakesignTik(signed_blob *);
s32 Title_GetTicketViews(u64, tikview **, u32 *);
#endif

139
installer/source/video.c Normal file
View File

@ -0,0 +1,139 @@
#include <stdio.h>
#include <ogcsys.h>
#include "video.h"
/* Video variables */
static void *framebuffer = NULL;
static GXRModeObj *vmode = NULL;
void Con_Init(u32 x, u32 y, u32 w, u32 h)
{
/* Create console in the framebuffer */
CON_InitEx(vmode, x, y, w, h);
}
void Con_Clear(void)
{
/* Clear console */
printf("\x1b[2J");
fflush(stdout);
}
void Con_ClearLine(void)
{
s32 cols, rows;
u32 cnt;
printf("\r");
fflush(stdout);
/* Get console metrics */
CON_GetMetrics(&cols, &rows);
/* Erase line */
for (cnt = 1; cnt < cols; cnt++) {
printf(" ");
fflush(stdout);
}
printf("\r");
fflush(stdout);
}
void Con_FgColor(u32 color, u8 bold)
{
/* Set foreground color */
printf("\x1b[%u;%um", color + 30, bold);
fflush(stdout);
}
void Con_BgColor(u32 color, u8 bold)
{
/* Set background color */
printf("\x1b[%u;%um", color + 40, bold);
fflush(stdout);
}
void Con_FillRow(u32 row, u32 color, u8 bold)
{
s32 cols, rows;
u32 cnt;
/* Set color */
printf("\x1b[%u;%um", color + 40, bold);
fflush(stdout);
/* Get console metrics */
CON_GetMetrics(&cols, &rows);
/* Save current row and col */
printf("\x1b[s");
fflush(stdout);
/* Move to specified row */
printf("\x1b[%u;0H", row);
fflush(stdout);
/* Fill row */
for (cnt = 0; cnt < cols; cnt++) {
printf(" ");
fflush(stdout);
}
/* Load saved row and col */
printf("\x1b[u");
fflush(stdout);
/* Set default color */
Con_BgColor(0, 0);
Con_FgColor(7, 1);
}
void Video_Configure(GXRModeObj *rmode)
{
/* Configure the video subsystem */
VIDEO_Configure(rmode);
/* Setup video */
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE)
VIDEO_WaitVSync();
}
void Video_SetMode(void)
{
/* Select preferred video mode */
vmode = VIDEO_GetPreferredMode(NULL);
/* Allocate memory for the framebuffer */
framebuffer = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
// Initialise the console, required for printf
console_init(framebuffer,20,20,vmode->fbWidth,vmode->xfbHeight,vmode->fbWidth*VI_DISPLAY_PIX_SZ);
/* Configure the video subsystem */
VIDEO_Configure(vmode);
/* Setup video */
VIDEO_SetNextFramebuffer(framebuffer);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if (vmode->viTVMode & VI_NON_INTERLACE)
VIDEO_WaitVSync();
/* Clear the screen */
Video_Clear(COLOR_BLACK);
}
void Video_Clear(s32 color)
{
VIDEO_ClearFrameBuffer(vmode, framebuffer, color);
}

24
installer/source/video.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _VIDEO_H_
#define _VIDEO_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Prototypes */
void Con_Init(u32, u32, u32, u32);
void Con_Clear(void);
void Con_ClearLine(void);
void Con_FgColor(u32, u8);
void Con_BgColor(u32, u8);
void Con_FillRow(u32, u32, u8);
void Video_Configure(GXRModeObj *);
void Video_SetMode(void);
void Video_Clear(s32);
#ifdef __cplusplus
}
#endif
#endif

507
installer/source/wad.c Normal file
View File

@ -0,0 +1,507 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <ogcsys.h>
#include "getios.h"
#include "title.h"
#include "video.h"
#include "wad.h"
#include "Network/http.h"
#include "../../svnrev/svnrev.h"
#define round_up(x,n) (-(-(x) & -(n)))
extern const u8 install_wad[];
extern const u32 install_wad_size;
u64 title_id;
/* 'WAD Header' structure */
typedef struct {
/* Header length */
u32 header_len;
/* WAD type */
u16 type;
u16 padding;
/* Data length */
u32 certs_len;
u32 crl_len;
u32 tik_len;
u32 tmd_len;
u32 data_len;
u32 footer_len;
} ATTRIBUTE_PACKED wadHeader;
/* Variables */
static u8 wadBuffer[BLOCK_SIZE] ATTRIBUTE_ALIGN(32);
void * startOfData;
void * endOfData;
void * internalPointer;
void mopen()
{
u32 size = install_wad_size;
startOfData = (void *) install_wad;
endOfData = (void *) install_wad + size;
internalPointer = startOfData;
// Title ID
wadHeader *header = NULL;
signed_blob *p_tik = NULL;
tik *tik_data = NULL;
__Wad_ReadAlloc((void *)&header, 0, sizeof(wadHeader));
u32 offset = 0;
s32 ret;
/* Ticket offset */
offset += round_up(header->header_len, 64);
offset += round_up(header->certs_len, 64);
offset += round_up(header->crl_len, 64);
/* Read ticket */
ret = __Wad_ReadAlloc((void *)&p_tik, offset, header->tik_len);
if (ret < 0)
goto out;
/* Ticket data */
tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik);
out:
/* Free memory */
if (header)
free(header);
if (p_tik)
free(p_tik);
title_id = tik_data->titleid;
}
int mseek(u32 offset, int origin)
{
if (origin == SEEK_SET)
{
internalPointer = startOfData + offset;
} else if (origin == SEEK_CUR)
{
internalPointer = internalPointer + offset;
} else if (origin == SEEK_END) {
internalPointer = endOfData - offset;
} else
{
return -2;
}
if ((internalPointer<startOfData) || (internalPointer> endOfData))
{
return -1;
} else
{
return 0;
}
}
int mread(void * buf, int size, int count)
{
memcpy(buf, internalPointer, size*count);
//DCFlushRange(buf, size*count);
return 0;
}
//-------------------------- INSTALL FROM MEMORY -------------------------------
s32 __Wad_ReadFile(void *outbuf, u32 offset, u32 len)
{
s32 ret;
/* Seek to offset */
mseek(offset, SEEK_SET);
/* Read data */
ret = mread(outbuf, len, 1);
if (ret < 0)
return ret;
return 0;
}
s32 __Wad_ReadAlloc(void **outbuf, u32 offset, u32 len)
{
void *buffer = NULL;
s32 ret;
/* Allocate memory */
buffer = memalign(32, len);
if (!buffer)
return -1;
/* Read file */
ret = __Wad_ReadFile(buffer, offset, len);
if (ret < 0) {
free(buffer);
return ret;
}
/* Set pointer */
*outbuf = buffer;
return 0;
}
s32 __Wad_GetTitleID(wadHeader *header, u64 *tid)
{
signed_blob *p_tik = NULL;
tik *tik_data = NULL;
u32 offset = 0;
s32 ret;
/* Ticket offset */
offset += round_up(header->header_len, 64);
offset += round_up(header->certs_len, 64);
offset += round_up(header->crl_len, 64);
/* Read ticket */
ret = __Wad_ReadAlloc((void *)&p_tik, offset, header->tik_len);
if (ret < 0)
goto out;
/* Ticket data */
tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik);
/* Copy title ID */
*tid = tik_data->titleid;
out:
/* Free memory */
if (p_tik)
free(p_tik);
return ret;
}
u64 GetTitleID()
{
return title_id;
}
bool CheckAppFound(u64 title)
{
char tmd[ISFS_MAXPATH];
u32 high = (u32)(title >> 32);
u32 low = (u32)(title & 0xFFFFFFFF);
sprintf(tmd, "/title/%08x/%08x/content/00000000.app", high, low);
s32 check = ISFS_Open(tmd, ISFS_OPEN_READ);
if(check == -102 || check > 0)
{
ISFS_Close(check);
return true;
}
return false;
}
void __Wad_FixTicket(signed_blob *p_tik)
{
u8 *data = (u8 *)p_tik;
u8 *ckey = data + 0x1F1;
if (*ckey > 1) {
// Set common key
*ckey = 0;
// Fakesign ticket
Title_FakesignTik(p_tik);
}
}
s32 __Wad_Install(int startpos_x, int startpos_y)
{
wadHeader *header = NULL;
signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL;
tmd *tmd_data = NULL;
u32 cnt, offset = 0;
s32 ret;
/* WAD header */
ret = __Wad_ReadAlloc((void *)&header, offset, sizeof(wadHeader));
if (ret >= 0)
offset += round_up(header->header_len, 64);
else
goto err;
/* WAD certificates */
ret = __Wad_ReadAlloc((void *)&p_certs, offset, header->certs_len);
if (ret < 0)
goto err;
else
offset += round_up(header->certs_len, 64);
/* WAD crl */
if (header->crl_len) {
ret = __Wad_ReadAlloc((void *)&p_crl, offset, header->crl_len);
if (ret < 0)
goto err;
else
offset += round_up(header->crl_len, 64);
}
/* WAD ticket */
ret = __Wad_ReadAlloc((void *)&p_tik, offset, header->tik_len);
if (ret < 0)
goto err;
else
offset += round_up(header->tik_len, 64);
/* WAD TMD */
ret = __Wad_ReadAlloc((void *)&p_tmd, offset, header->tmd_len);
if (ret < 0)
goto err;
else
offset += round_up(header->tmd_len, 64);
/* Fix ticket */
__Wad_FixTicket(p_tik);
printf(".....");
/* Install ticket */
ret = ES_AddTicket(p_tik, header->tik_len, p_certs, header->certs_len, p_crl, header->crl_len);
if (ret < 0)
goto err;
printf(".....");
/* Install title */
ret = ES_AddTitleStart(p_tmd, header->tmd_len, p_certs, header->certs_len, p_crl, header->crl_len);
if (ret < 0)
goto err;
printf(".....");
/* Get TMD info */
tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd);
/* Install contents */
for (cnt = 0; cnt < tmd_data->num_contents; cnt++)
{
tmd_content *content = &tmd_data->contents[cnt];
u32 idx = 0, len;
s32 cfd;
printf(".....");
/* Encrypted content size */
len = round_up(content->size, 64);
/* Install content */
cfd = ES_AddContentStart(tmd_data->title_id, content->cid);
if (cfd < 0) {
ret = cfd;
goto err;
}
/* Install content data */
while (idx < len) {
u32 size;
/* Data length */
size = (len - idx);
if (size > BLOCK_SIZE)
size = BLOCK_SIZE;
/* Read data */
ret = __Wad_ReadFile(&wadBuffer, offset, size);
if (ret < 0)
goto err;
/* Install data */
ret = ES_AddContentData(cfd, wadBuffer, size);
if (ret < 0)
goto err;
/* Increase variables */
idx += size;
offset += size;
}
/* Finish content installation */
ret = ES_AddContentFinish(cfd);
if (ret < 0)
goto err;
}
printf(".....");
/* Finish title install */
ret = ES_AddTitleFinish();
if (ret >= 0)
{
// update counter
char buffer[100];
sprintf(buffer, "http://hbf.hamachi-mp.bplaced.net/update.php?rev=%i_installer", SvnRev());
downloadfile(buffer);
Con_FgColor(2, 1);
printf("\x1b[%i;%iH", startpos_x +6, startpos_y);
printf("SUCCESS");
goto out;
}
err:
Con_FgColor(1, 1);
printf("\x1b[%i;%iH", startpos_x +6, startpos_y);
printf("ERROR! (ret = %d)\n", ret);
/* Cancel install */
ES_AddTitleCancel();
out:
/* Free memory */
if (header)
free(header);
if (p_certs)
free(p_certs);
if (p_crl)
free(p_crl);
if (p_tik)
free(p_tik);
if (p_tmd)
free(p_tmd);
return ret;
}
s32 __Wad_Uninstall(int startpos_x, int startpos_y)
{
wadHeader *header = NULL;
tikview *viewData = NULL;
u64 tid;
u32 viewCnt;
s32 ret;
startpos_x = startpos_x +4;
printf("\x1b[%i;%iH", startpos_x, startpos_y);
/* WAD header */
ret = __Wad_ReadAlloc((void *)&header, 0, sizeof(wadHeader));
if (ret < 0) {
Con_FgColor(1, 1);
printf(" ERROR! (ret = %d)", ret);
goto out;
}
/* Get title ID */
ret = __Wad_GetTitleID(header, &tid);
if (ret < 0) {
Con_FgColor(1, 1);
printf(" ERROR! (ret = %d)", ret);
goto out;
}
Con_FgColor(7, 1);
printf("Deleting tickets...");
/* Get ticket views */
ret = Title_GetTicketViews(tid, &viewData, &viewCnt);
if (ret < 0)
{
Con_FgColor(1, 1);
printf("\x1b[%i;%iH", startpos_x, startpos_y +34);
printf(" ERROR! (ret = %d)", ret);
}
/* Delete tickets */
if (ret >= 0) {
u32 cnt;
/* Delete all tickets */
for (cnt = 0; cnt < viewCnt; cnt++) {
ret = ES_DeleteTicket(&viewData[cnt]);
if (ret < 0)
break;
}
if (ret < 0)
{
Con_FgColor(1, 1);
printf("\x1b[%i;%iH", startpos_x, startpos_y +35);
printf("ERROR! (ret = %d)", ret);
}
else
{
Con_FgColor(2, 1);
printf("\x1b[%i;%iH", startpos_x, startpos_y +42);
printf("SUCCESS");
}
}
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +1, startpos_y);
printf("Deleting title contents...");
/* Delete title contents */
ret = ES_DeleteTitleContent(tid);
if (ret < 0)
{
Con_FgColor(1, 1);
printf("\x1b[%i;%iH", startpos_x +1, startpos_y +35);
printf("ERROR! (ret = %d)", ret);
}
else
{
Con_FgColor(2, 1);
printf("\x1b[%i;%iH", startpos_x +1, startpos_y +42);
printf("SUCCESS");
}
Con_FgColor(7, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y);
printf("Deleting title...");
/* Delete title */
ret = ES_DeleteTitle(tid);
if (ret < 0)
{
Con_FgColor(1, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y +35);
printf("ERROR! (ret = %d)", ret);
}
else
{
Con_FgColor(2, 1);
printf("\x1b[%i;%iH", startpos_x +2, startpos_y +42);
printf("SUCCESS");
}
out:
/* Free memory */
if (header)
free(header);
return ret;
}
s32 Wad_InstallFromMemory(int startpos_x, int startpos_y)
{
return __Wad_Install(startpos_x, startpos_y);
}
s32 Wad_UninstallFromMemory(int startpos_x, int startpos_y)
{
return __Wad_Uninstall(startpos_x, startpos_y);
}

20
installer/source/wad.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _WAD_H_
#define _WAD_H_
#ifdef __cplusplus
extern "C" {
#endif
void mopen();
u64 GetTitleID();
bool CheckAppFound(u64 title);
s32 __Wad_ReadAlloc(void **outbuf, u32 offset, u32 len);
s32 Wad_InstallFromMemory(int startpos_x, int startpos_y);
s32 Wad_UninstallFromMemory(int startpos_x, int startpos_y);
#ifdef __cplusplus
}
#endif
#endif