Talk:Sony Update Downloads

From Exploitee.rs

I worked on expanding the pad a bit. Here's the script I use.

#!/usr/bin/perl
use strict;
package abliss;
my $start = shift;

open HEX, "<./history/other/RfHid_v0156_2010091601_NL.hex" or die;
open OUT, ">>pad.bin";
open IN, "<pad.bin";
my @files = (
    "./history/NBL/batch_sync-vfat.sh",
    "./history/board_conf.sh",
    "./history/other/check_spectra1_20100929.sh",
    "./history/other/factory_reset_conditional_keepremote_20101012.sh",
    "./history/other/format_sda_20100514.sh");
my @fds;
for (my $i = 0; $i <= $#files; $i++) {
    open (my $fd, $files[$i]) or die "can't open " . $files[$i];
    push(@fds, $fd);
}
my @contents;

my $hexbyte;
my @hexchars = qw(0 1 2 3 4 5 6 7 8 9 A B C D E F :);
push(@hexchars, "\r");
push(@hexchars, "\n");
my @output = ();
our $xorbyte;
while (read(HEX, $hexbyte, 1)) {
    for (my $i = 0; $i <= $#files; $i++) {
        my $char;
        if (read($fds[$i], $char, 1)) {
            $contents[$i] .= $char;
            if (length($contents[$i]) > 30) {
                $contents[$i] = substr($contents[$i], 1);
            }
        }
    }
    if ($start-- > 0) {
        my $char;
        read(IN, $char, 1);
        $xorbyte = ord($char);
    } else {
        for (my $j = 0; $j <= $#hexchars; $j++) {
            $xorbyte = ord($hexbyte) ^ ord($hexchars[$j]);
            my $choices = "";
            my $ok = 1;
            for (my $i = 0; $i <= $#files; $i++) {
                my $neword = (ord(substr($contents[$i],length($contents[$i]) - 1)) ^ $xorbyte);
                if ($neword > 127 || 
                    ($neword < 32 && 
                     $neword != 9 && # tab
                     $neword != 10 && # LF
                     $neword != 13 # CR
                    )) {
                    $ok = 0;
                    #printf "==== %2d ====\n%s\n", $j, xorlastbyte($contents[$i]);
                    last;
                }
            }
            if ($ok) {
                printf "==== %2d ====\n%s\n", $j, join("\n--\n", map {xorlastbyte($_)} @contents);
            }
        }
        my $answer = <STDIN>;
        chomp $answer;
        if ($answer eq "q") {
            close OUT;
            die;
        }
        $xorbyte = ord($hexbyte) ^ ord($hexchars[$answer]);
        print OUT chr($xorbyte);
    }
    @contents = map {xorlastbyte($_)} @contents;
}

sub xorlastbyte {
    my $content = shift;
    if ($content) {
        my @chars = split(//, $content);
        $chars[-1] = chr(ord($chars[-1])^ $xorbyte);
        return join('', @chars);
    }
}

Here's my pad, 134 chars:

00000000  38 cf 4f aa 7a 8a 2e 3e  2b 41 82 9a ad 31 e9 dc  |8.O.z..>+A...1..|
00000010  ef 47 2f 0b 26 76 12 fe  5f 5b 58 e1 10 18 7d e6  |.G/.&v.._[X...}.|
00000020  ad 92 1b 91 8e 90 69 f7  8a 9b 68 d8 98 58 fa 95  |......i...h..X..|
00000030  63 81 d6 5f 04 7d 29 8b  09 cf b9 21 b8 d9 df dd  |c.._.})....!....|
00000040  c4 7e 71 d9 3f 35 ea 7b  0d ec 7f d1 a3 76 64 88  |.~q.?5.{.....vd.|
00000050  a5 8e 27 49 60 c0 a0 bc  77 54 31 e3 d6 6a bf e5  |..'I`...wT1..j..|
00000060  1b 42 25 da a3 97 b8 e1  ba 54 13 5b 68 31 da ff  |.B%......T.[h1..|
00000070  1c 5c 15 46 4e 32 f1 76  50 e0 4e f3 ab 9a 28 bb  |.\.FN2.vP.N...(.|
00000080  b5 cf 2f 50 24 45                                 |../P$E|

I checked the checksums in the .hex file and they all validate so far.

Catrane 2011.02.11: Nice work, Abliss. It sounds like we're running similar approaches. Here's my script. It prints one line for each byte, listing all the possibilities. I then do a human search for anything that looks predictable and work it by hand. The 756 byte key I posted was also verified using the .hex checksums in addition to visual inspection. The typos in the code make visual inspection a little tricky.

#!/usr/bin/perl

use strict;
use warnings;

use IO::File;

my @files = ();
my @filters = ();
my @rules = ();
my %ruleinfo = ();
my $files_left = 0;

#my $textfilter = "[[:print:]\x0a\x0b\t\n\r\f ]";
my $textfilter = "[[:print:]\x0a\t ]";
my $intelhexfilter = "[0-9A-F:\x0d\x0a]";

my $knownmasks = "";
if ( -f 'knownmasks' )
{
	$knownmasks = `cat knownmasks`;
}

sub checkRules
{
	my ($rule,$char) = @_;
	if ( "text" eq $ruleinfo{$rule}{'type'} )
	{
	} elsif ( "intelhex" eq $ruleinfo{$rule}{'type'} ) {
		if ( $ruleinfo{$rule}{'is_colon'} )
		{
			return 0 unless ( ":" eq $char );
		}
		if ( $ruleinfo{$rule}{'was_colon'} > 0 )
		{
			return 0 if ( ($ruleinfo{$rule}{'was_colon'} < 12) && ("\x0a" eq $char) );
			return 0 if ( ($ruleinfo{$rule}{'was_colon'} < 11) && (("\x0a" eq $char) || ("\x0d" eq $char)) );
			return 0 if ( ":" eq $char );
		}
		return 0 if ( ( ":" eq $char ) && ! $ruleinfo{$rule}{'was_maybe_0a'} );
		return 0 if ( ( "\x0a" eq $char ) && ! $ruleinfo{$rule}{'was_maybe_0d'} );
		
	}
	return 1;
}

sub advanceRules
{
	my ($rule,$options) = @_;
	if ( "text" eq $ruleinfo{$rule}{'type'} )
	{
	} elsif ( "intelhex" eq $ruleinfo{$rule}{'type'} ) {
		my $is_nr = ( $options =~ m/^\\[nr]\\[nr]$/ );
		# 0d0a == \r\n
		my $is_maybe_0d = ( $options =~ m/\\r/ );
		my $is_maybe_0a = ( $options =~ m/\\n/ );
		if ( $ruleinfo{$rule}{'was_colon'} )
		{
			$ruleinfo{$rule}{'was_colon'}++;
			if ( $ruleinfo{$rule}{'was_colon'} > 12 )
			{
				$ruleinfo{$rule}{'was_colon'} = 0;
			}
		}
		if ( $ruleinfo{$rule}{'is_colon'} )
		{
			$ruleinfo{$rule}{'is_colon'} = 0;
			$ruleinfo{$rule}{'was_colon'} = 1;
		} elsif ( $ruleinfo{$rule}{'was_nr'} ) {
			$ruleinfo{$rule}{'is_colon'} = $is_nr;
		}
		$ruleinfo{$rule}{'was_nr'} = $is_nr;
		$ruleinfo{$rule}{'was_maybe_0d'} = $is_maybe_0d;
		$ruleinfo{$rule}{'was_maybe_0a'} = $is_maybe_0a;
	}
}

while ( my $filter = shift )
{
	if ( "text" eq $filter )
	{
		push(@filters,$textfilter);
		push(@rules,$files_left);
		$ruleinfo{$files_left}{'type'} = "text";
	} elsif ( "intelhex" eq $filter ) {
		push(@filters,$intelhexfilter);
		push(@rules,$files_left);
		$ruleinfo{$files_left}{'type'} = "intelhex";
		$ruleinfo{$files_left}{'is_colon'} = 1; # First must be colon.
		$ruleinfo{$files_left}{'was_colon'} = 0;
		$ruleinfo{$files_left}{'was_nr'} = 1; # Make like normal colon setup.
		$ruleinfo{$files_left}{'was_maybe_0d'} = 0;
		$ruleinfo{$files_left}{'was_maybe_0a'} = 1; # Make like normal colon setup.
	} elsif ( "test_text" eq $filter ) {
		my $counter = 0;
		my $fh = IO::File->new("< ".shift) or die "Unable to open file.\n";
		while ( defined( my $char = getc($fh) ) )
		{
			die "failed test at index $counter.\n" unless ( $char =~ m/$textfilter/ );
			$counter++;
		}
		print "test passed.\n";
		exit;
	} elsif ( "test_intelhex" eq $filter ) {
		my $counter = 0;
		my $fh = IO::File->new("< ".shift) or die "Unable to open file.\n";
		while ( defined( my $char = getc($fh) ) )
		{
			die "failed test at index $counter.\n" unless ( $char =~ m/$intelhexfilter/ );
			$counter++;
		}
		print "test passed.\n";
		exit;
	} else {
		die "Invalid filter '$filter'.\n";
	}
	my $file = shift;
	die "Missing filename parameter.\n" unless defined $file;
	die "File '$file' does not exist.\n" unless ( -f $file );
	my $fh = IO::File->new("< $file") or die "Unable to open file '$file'.\n";
	push(@files,$fh);
	$files_left++;
}

while ( $files_left )
{
	my @options = ("\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0a","\x0b","\x0c","\x0d","\x0e","\x0f",
	               "\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1a","\x1b","\x1c","\x1d","\x1e","\x1f",
	               "\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2a","\x2b","\x2c","\x2d","\x2e","\x2f",
	               "\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3a","\x3b","\x3c","\x3d","\x3e","\x3f",
	               "\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f",
	               "\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5a","\x5b","\x5c","\x5d","\x5e","\x5f",
	               "\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f",
	               "\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a","\x7b","\x7c","\x7d","\x7e","\x7f",
	               "\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8a","\x8b","\x8c","\x8d","\x8e","\x8f",
	               "\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9a","\x9b","\x9c","\x9d","\x9e","\x9f",
	               "\xa0","\xa1","\xa2","\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xaa","\xab","\xac","\xad","\xae","\xaf",
	               "\xb0","\xb1","\xb2","\xb3","\xb4","\xb5","\xb6","\xb7","\xb8","\xb9","\xba","\xbb","\xbc","\xbd","\xbe","\xbf",
	               "\xc0","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6","\xc7","\xc8","\xc9","\xca","\xcb","\xcc","\xcd","\xce","\xcf",
	               "\xd0","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6","\xd7","\xd8","\xd9","\xda","\xdb","\xdc","\xdd","\xde","\xdf",
	               "\xe0","\xe1","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7","\xe8","\xe9","\xea","\xeb","\xec","\xed","\xee","\xef",
	               "\xf0","\xf1","\xf2","\xf3","\xf4","\xf5","\xf6","\xf7","\xf8","\xf9","\xfa","\xfb","\xfc","\xfd","\xfe","\xff");
	my $options_left = 256;
	if ( $knownmasks =~ s/^(..)\n// )
	{
		my $knownmask = $1;
		if ( $knownmask =~ m/[0-9a-f]{2}/i )
		{
			my $val;
			eval('$val = "\\x'.$knownmask.'";');
			$options[0] = $val;
			$options_left = 1;
		}
	}

	my @filechars = ();

	for ( my $i = 0; $i < $files_left; $i++ )
	{
		my $char = getc($files[$i]);
		if ( defined($char) )
		{
			$filechars[$i] = $char;
			my $filter = $filters[$i];

			for ( my $x = 0; $x < $options_left; $x++ )
			{
#print "$x vs $options_left\n";
#				print "char is $char\n";
#				print "option is $options[$x]\n";
				my $realchar = $char ^ $options[$x];
				unless ( ($realchar =~ m/$filter/) && checkRules($rules[$i],$realchar) )
				{
					splice(@options,$x,1);
					$x--;
					$options_left--;
				}
			}
		} else {
			$files[$i]->close;
			splice(@files,$i,1);
			splice(@filters,$i,1);
			splice(@rules,$i,1);
			$i--;
			$files_left--;
		}
	}

	last unless $files_left;

	die "Failed to solve.\n" unless $options_left;
	for ( my $i = 0; $i < $files_left; $i++ )
	{
		my $options = "";
		for ( my $x = 0; $x < $options_left; $x++ )
		{
			my $realchar = $filechars[$i] ^ $options[$x];
			$realchar = "\\t" if ( $realchar eq "\t" );
			$realchar = "\\r" if ( $realchar eq "\r" );
			$realchar = "\\n" if ( $realchar eq "\n" );
			#$realchar = "\\v" if ( $realchar eq "\v" );
			$realchar = "\\v" if ( $realchar eq "\x0b" );
			$realchar = "\\a" if ( $realchar eq "\x0a" );
			$realchar = "\\f" if ( $realchar eq "\f" );
			$realchar = "\\s" if ( $realchar eq " " );
			$options .= $realchar;
		}
		print $options."\n" unless $i;
		advanceRules($rules[$i],$options);
	}
}
print "Done\n";