backtopbacktopbacktop



 

Updates

uLaunchELF v4.42b

Open PS2 Loader v0.8

SMS Media Player v2.9 R4

Free McBoot 1.8b

ESR beta r9b

Open Ps2 Loader Guides & Tutorials

Free MCBOOT Guides & Tutorials
Wii Savegame Parser

Contents


Overview

The following Perl script can decompile a Wii savedata file which was copied from the Wii to an SD card. These are stored in files called data.bin. The script only decompiles the data.bin file. It does not decrypt the files contained therein to plaintext nor does it encrypt the plaintext again and reassemble the data.bin file. So it cannot use it to create data.bin's that can be copied over to the Wii again.

Structure of data.bin files

All multiple byte numbers (e.g. LONG = 4 bytes) are encoded in big endian format. While some information in the data.bin is plaintext and can therefore be used by the script below to parse the bin-file. The two encrypted blocks of data are the header and the actual savegame files stored in the data bin. LONGs or BYTEs that are fixed and therefore have he same value in each data.bin file are called magics.

Header

The header is one big block of encrypted data at the beginning of the data.bin. It consists of 64 byte blocks and ends in front of the first 64 byte block starting with 0x00000070 followed by 0x42B0001.

Basic File Information

The ID number of the Wii the data.bin was encoded on follows after that, then a LONG with the number of files contained in the data.bin. This concludes the first 16 bytes after the header.

Data Size

The next 16 bytes contain one LONG with the size of the block of encrypted file data, two zero LONGs and one LONG describing the number of bytes from the end of the header (including 0x00000070) up to the end of file. A 64 byte of zeros follows the data size information.

Program ID

After another fixed magic LONG (0x00010000) the savegame's parent program's ID is stored in another LONG. Then follows the Wii's MAC address in another LONG. Another fixed LONG (0xF5550000) completes another 16 byte block.

First Hash

A 16 byte hash of unknown purpose.

Files

The data.bin contains as many files as indicated by the number of files in the Basic File Information. Each file starts with a file header begining with a magic LONG 0x03ADF17E and then a LONG describing the individual file size in bytes. Three BYTE magics 0x34, 0x00, 0x01 are followed by a zero-terminated string containing the file's name (e.g."zeldaTp.dat"). A block of of 117 minus the string's length artificially increses each single file header's size to 128 bytes. Then follows the actual encrypted file content followed by a block of randon data to force the file data to fit into complete 64 byte blocks.

Certificate Information

After the file data the certificates that were (probably) used to encrypted and should be used to decrypt the data are given. A 60 byte hash is followed by two LONG magics (0x00000000, 0x00010002) and another 60 byte hash. Then follows a 64 byte block of zeros and a 64 byte zero-terminated string ("Root-CA00000001-MS00000001") patched with zeros. Another magic (0x00000002) is followed by a string containing the Wii's ID in ASCII ("NG0???????"). This is followed by a 64 byte hash and a 60 byte block of zeros. Then follows a magic (0x00010002), a 60 byte hash, a 64 byte block of zeros and another 64 byte string ("Root-CA00000001-MS00000002-NG0???????") followed by a 64 byte block of zeros. A 0x00000002 magic is followed by another string ("AP0000000100000002") followed by 64 zeros. Then follows a 0x00000000 magic and a 60 byte hash which is finally concluded by 60 zeros bytes till the end of file.

Script

This Perl script will decompile a data.bin file displaying the values of the LONGs and BYTEs and sizes of hashes, strings and data blocks. The hashes and data blocks will furthermore be saved in single binary files with according suffixes.

#!/usr/bin/perl
#-----------------------------------
# Wii Savegame Parser
# written by Lockhool
# for #wiidev @ EFnet
#-----------------------------------

use strict;
use Fcntl;

sub readLong($;$);
sub readByte($;$);
sub readString($);
sub readUpto($$);
sub readBlock($$;$);
sub readEof();

my $file_in=shift;
die("\n Usage: ./wiiparse.pl <datafile>\n\n")
unless(sysopen(IN,$file_in,O_RDONLY));

my $add=0;
my $in;

readUpto('Header',0x00000070);
readLong('Magic',0x426B0001);
readLong('WiiID');
my $numfiles = readLong('NumFiles');
readLong('FileDataLen');
readLong('Magic',0x00000000);
readLong('Magic',0x00000000);
readLong('PostHeadLen');
readBlock('Zeros',64);
readLong('Magic',0x00010000);
readLong('PrgID');
readLong('MacAdd');
readLong('Magic',0xF5550000);
readBlock('Hash1',16,'hash1');
for(1..$numfiles){
readLong('Magic'.$_,0x03ADF17E);
my $filesize = readLong('Filesize'.$_);
readByte('Magic'.$_,0x34);
readByte('Magic'.$_,0x00);
readByte('Magic'.$_,0x01);
my $strlen = readString('Filename'.$_);
readBlock('StrFiller'.$_,117-$strlen,'f'.$_.'sfill');
readBlock('Filedata'.$_,$filesize,'f'.$_.'data');
readBlock('DataFiller'.$_,$filesize % 64,'f'.$_.'dfill');
}
readBlock('Hash2',60,'hash2');
readLong('Magic',0x00000000);
readLong('Magic',0x00010002);
readBlock('Hash3',60,'hash3');
readBlock('Zeros',64);
my $strlen = readString('RootCA');
readBlock('Zeros',64-$strlen);
readLong('Magic',0x00000002);
my $strlen = readString('NG');
readBlock('Zeros',64-$strlen);
readBlock('Hash4',64,'hash4');
readBlock('Zeros',60);
readLong('Magic',0x00010002);
readBlock('Hash5',60,'hash5');
readBlock('Zeros',64);
my $strlen = readString('RootCA-MS-NG');
readBlock('Zeros',64-$strlen);
readLong('Magic',0x00000002);
my $strlen = readString('AP');
readBlock('Zeros',64-$strlen);
readLong('Magic',0x00000000);
readBlock('Hash6',60,'hash6');
readEof;

close(IN);

sub readLong($;$){
printf("% 12u : ",$add);
my $name=shift;
my $val=shift;
die("!! '$name' premature EOF !!\n")
unless(4==sysread(IN,$in,4));
$in=unpack("N",$in);
$add+=4;
printf(" LONG '$name' 0x%08X (%u)\n",$in,$in);
if(defined $val){print(' 'x17);
if($val==$in){print('==');}else{print('!=')}
printf(" 0x%08X (%u)\n",$val,$val);
}
return($in);
}

sub readByte($;$){
printf("% 12u : ",$add);
my $name=shift;
my $val=shift;
die("!! '$name' premature EOF !!\n")
unless(1==sysread(IN,$in,1));
$in=ord($in);
$add+=1;
printf(" BYTE '$name' 0x%02X (%u)\n",$in,$in);
if(defined $val){print(' 'x17);
if($val==$in){print('==');}else{print('!=')}
printf(" 0x%02X (%u)\n",$val,$val);
}
return($in);
}

sub readBlock($$;$){
printf("% 12u : ",$add);
my $name=shift;
my $cnt=shift;
my $file=shift;
if(defined $file){$file=$file_in.'.'.$file}
my $size=$cnt;
if(defined $file){
die("!! Can't open $file !!\n")
unless(sysopen(OUT,$file,O_WRONLY|O_CREAT));}
while($cnt!=0){
die("!! '$name' premature EOF !!\n")
unless(1==sysread(IN,$in,1));
if(defined $file){syswrite(OUT,$in,1);}
$add++;
$cnt--;}
if(defined $file){close(OUT);}
printf(" BLOCK '$name' ends after %u bytes\n",$size);
return($size);
}

sub readString($){
printf("% 12u : ",$add);
my $name=shift;
my $upto=shift;
my $size=0;
my $string='';
my $in;
while(1){
die("!! '$name' premature EOF !!\n")
unless(1==sysread(IN,$in,1));
$add+=1;
$size+=1;
$string=$string.unpack('a',$in);
if(ord($in)==0){last;}
}
printf("STRING '$name' ends after %u bytes\n",$size);
print(' 'x15 ."\"$string\"\n");
return($size);
}

sub readEof(){
printf("% 12u",$add);
my $name=shift;
my $upto=shift;
my $size=0;
my $in;
while(1){
last unless(0!=sysread(IN,$in,1));
$add++;
$size++;}
printf(" - %u : EOF reached after %u bytes\n",$add,$size);
return($size);
}

sub readUpto($$){
printf("% 12u : ",$add);
my $name=shift;
my $upto=shift;
my $size=0;
my $in;
while(1){
die("!! '$name' premature EOF !!\n")
unless(4==sysread(IN,$in,4));
$add+=4;
$size+=4;
if($upto==unpack("N",$in)){last;}}
printf(" UPTO '$name' ends after %u bytes\n",$size);
return($size);
}



Untitled Document
Powered by vBadvanced CMPS v3.2.3

All times are GMT -7. The time now is 04:41 PM.
Powered by vBulletin Version 3.8.5
Copyright 2000 - 2011, Jelsoft Enterprises Ltd.


Valid CSS!

backtopbacktopbacktop

Applications - Forums - List - Skins - Arcade

Disclaimer - FAQ - Donate

Page generated in 0.09521 seconds.
Copyright © 2004 - 2017 SKSApps.com
All rights reserved.
No affiliation with Sony Computer Entertainment or Nintendo Company, Ltd.