#!perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id: typhooncidedit.pl 1881 2008-06-26 10:49:11Z itsme $ # use strict; use Getopt::Long; # # pdocread -n 1 0 0x10000 cid-block.nb # perl typhooncidedit.pl cid-block.nb -c GSMK-000 -w cid-gsmk.nb # pdocwrite -n 1 cid-gsmk.nb # # bootloader command 'info 2' should return the current cid # bootloader command 'set 32 0' should return the current security level # # csum= dword_sum(data[0..0xfff7]) # checksum: decrypt({csum, csum}, encrypt(data[0x010..0x017], key(g+19)) ) # keyix= encrypt(data[0x1a0..0x1a7], key(g+53))[3] # cid = encrypt(data[0x160..0x17f], encrypt(data_1200[keyix], key(g+77)) ) # 0x0000-0x0004 - version # 0x0010-0x0018 - checksum cryptkey # 0x0140-0x0148 - imei # 0x0160-0x0180 - cid # 0x01a0-0x01a8 - keyindex at byte +3 # 0x1200-0x1a00 - cid cryptkey # 0x1c80-0x1c88 - lockflag # 0x1d00-0x1f00 - lockcodes # 0x4000-0x4400 - mccmnc # 0xfff8-0xffff - checksum of 0-0xfff8 # parts changed from default value: # 0000-0003 version # 0140-0147 imei # 0160-017f cid # 01a0-01a7 keyindex # 16b0-16b7 cidcryptkey # 1c80-1c87 lockflag # 4000-400f mccmnc # fff8-ffff checksum # use Crypt::DES; use IO::File; my @keylist= ( pack("C*", 0x51, 0x0F, 0x54, 0x3A, 0xD7, 0xBF, 0xBE, 0xCF), pack("C*", 0xE1, 0x87, 0xEF, 0xDB, 0x1F, 0xEA, 0xB4, 0x07), pack("C*", 0x64, 0xFD, 0x18, 0x47, 0xA9, 0x62, 0x85, 0x67), pack("C*", 0x55, 0x7A, 0x2B, 0xE7, 0xBC, 0xD7, 0xA5, 0x08), pack("C*", 0xE5, 0xF0, 0xDA, 0x27, 0x90, 0x19, 0x22, 0x4A), pack("C*", 0x77, 0xB2, 0xAB, 0xF9, 0xD5, 0x9E, 0x1A, 0x4F), pack("C*", 0x25, 0xF7, 0x75, 0x50, 0x2C, 0xFF, 0x40, 0x7D), pack("C*", 0x39, 0x5A, 0xE6, 0xA6, 0xAC, 0x7B, 0x5B, 0x00), pack("C*", 0xB5, 0x5D, 0x00, 0x77, 0x5E, 0x73, 0xC7, 0x45), pack("C*", 0xCC, 0xE1, 0x97, 0xC4, 0xC1, 0xEC, 0xF2, 0x80), pack("C*", 0x66, 0xAF, 0xD5, 0x91, 0x48, 0x10, 0xDF, 0x28), pack("C*", 0xA0, 0xF3, 0xB6, 0x67, 0xD7, 0xAE, 0xA7, 0x76), pack("C*", 0x49, 0xBC, 0x8C, 0xD3, 0x4A, 0xB5, 0xF3, 0xE9), pack("C*", 0x66, 0x7D, 0x7C, 0xE5, 0xED, 0xBC, 0x83, 0xC5), pack("C*", 0xB0, 0x8F, 0xFF, 0xB1, 0x05, 0x7E, 0xAA, 0x8F), pack("C*", 0x11, 0xAD, 0x63, 0xD2, 0x46, 0x56, 0xD0, 0x92), pack("C*", 0x2A, 0x76, 0x47, 0xE2, 0x5A, 0xC7, 0xEF, 0x5E), pack("C*", 0xCF, 0xEF, 0x22, 0x03, 0x61, 0xF7, 0x16, 0x44), pack("C*", 0x89, 0xFE, 0xBD, 0x59, 0x6B, 0x2F, 0xE9, 0xDB), pack("C*", 0x14, 0xF0, 0xB4, 0x8E, 0x00, 0x5C, 0x1F, 0x7E), pack("C*", 0xDF, 0xF4, 0xF9, 0x4D, 0x98, 0x91, 0x03, 0xCB), pack("C*", 0x8F, 0x9E, 0x51, 0xC7, 0x24, 0x83, 0xF3, 0x25), pack("C*", 0x7C, 0x64, 0xD5, 0x31, 0x83, 0x0C, 0xE4, 0x33), pack("C*", 0x31, 0x24, 0x72, 0x44, 0x0D, 0xA9, 0xDC, 0x5F), pack("C*", 0xF0, 0x9D, 0x6A, 0xBB, 0x0C, 0xFC, 0x76, 0x58), pack("C*", 0x2C, 0xF1, 0xD1, 0xD8, 0x3D, 0x4A, 0x62, 0x91), pack("C*", 0x0E, 0x2A, 0x10, 0xE0, 0x54, 0xFD, 0xE3, 0xC0), pack("C*", 0xF1, 0xB1, 0x65, 0x9B, 0x76, 0x24, 0x4F, 0x60), pack("C*", 0xE6, 0xD8, 0x61, 0xD5, 0xBD, 0xEE, 0x92, 0x2F), pack("C*", 0x30, 0x52, 0x69, 0xE0, 0xB7, 0x33, 0xAB, 0xB0), pack("C*", 0xC9, 0xB6, 0x36, 0x0F, 0xE6, 0xEB, 0x2D, 0xA9), pack("C*", 0xDB, 0x00, 0x55, 0x3C, 0x42, 0xB4, 0xBF, 0xA6), pack("C*", 0x48, 0x0F, 0xA8, 0x43, 0xB3, 0x50, 0x9D, 0x75), pack("C*", 0x23, 0x28, 0xE3, 0x84, 0x97, 0x25, 0x15, 0xA9), pack("C*", 0x34, 0x71, 0x0F, 0x65, 0x42, 0xBC, 0x0B, 0x17), pack("C*", 0x78, 0x77, 0x0A, 0xCE, 0x79, 0x43, 0x76, 0x5C), pack("C*", 0x9E, 0xA9, 0x05, 0xAC, 0xF6, 0x0B, 0xE0, 0x55), pack("C*", 0x8B, 0xDA, 0x05, 0x6E, 0xE7, 0x0A, 0xE9, 0xA5), pack("C*", 0xD7, 0xC3, 0x62, 0x8B, 0x6F, 0x5A, 0xC5, 0x32), pack("C*", 0x4E, 0x7F, 0x4B, 0xFA, 0x24, 0xB8, 0xBA, 0xA8), pack("C*", 0x71, 0x0E, 0x41, 0xB8, 0x8F, 0x05, 0xA3, 0xF5), pack("C*", 0xF2, 0xD2, 0x98, 0x46, 0xAF, 0xC9, 0x70, 0xCB), pack("C*", 0x3B, 0x15, 0xF9, 0x28, 0x75, 0xAB, 0xA3, 0x21), pack("C*", 0xE7, 0x81, 0xE2, 0x68, 0x49, 0xFA, 0xD4, 0xB2), pack("C*", 0x47, 0xA5, 0x24, 0x10, 0x85, 0x28, 0x2E, 0x7D), pack("C*", 0xDF, 0x77, 0x63, 0xB3, 0xF5, 0x4A, 0xEF, 0x44), pack("C*", 0xE7, 0xCD, 0x9A, 0xE5, 0x5D, 0x99, 0xEC, 0x0D), pack("C*", 0xCB, 0xE3, 0x95, 0xBF, 0xF3, 0xF3, 0x0C, 0xA3), pack("C*", 0xAB, 0xD8, 0x75, 0x5C, 0xE0, 0x5B, 0xC8, 0x16), pack("C*", 0xDB, 0x31, 0x30, 0x5E, 0xC3, 0x75, 0xB1, 0x37), pack("C*", 0x63, 0x55, 0x0E, 0x6A, 0x2E, 0x0B, 0xEA, 0x1D), pack("C*", 0x80, 0x0F, 0x2D, 0xA7, 0x27, 0x8A, 0xA9, 0xA3), pack("C*", 0x22, 0x0E, 0xFE, 0x43, 0xA8, 0x85, 0xBA, 0xE8), pack("C*", 0x6D, 0x68, 0xC5, 0xEF, 0x20, 0x32, 0xFD, 0xCD), pack("C*", 0x38, 0x13, 0x1D, 0x5E, 0xF0, 0xE8, 0xE3, 0x7A), pack("C*", 0x90, 0x6B, 0x72, 0xCA, 0xEF, 0xA7, 0xF5, 0xD9), pack("C*", 0x36, 0xB0, 0x85, 0x6E, 0xE6, 0x90, 0x4D, 0x1A), pack("C*", 0x1D, 0x84, 0xEB, 0x0D, 0x15, 0x69, 0x1A, 0x2D), pack("C*", 0xED, 0x71, 0x8E, 0x6A, 0xAC, 0x1A, 0x20, 0x4B), pack("C*", 0x83, 0x61, 0x2B, 0xCD, 0x52, 0x32, 0x36, 0x6E), pack("C*", 0x6E, 0x24, 0xD3, 0x85, 0xA2, 0x63, 0xC6, 0xD4), pack("C*", 0x73, 0xED, 0x6A, 0x60, 0xA8, 0x02, 0x51, 0x81), pack("C*", 0x0A, 0xD5, 0x2B, 0x35, 0x69, 0x88, 0xE9, 0xB9), pack("C*", 0xDF, 0x57, 0x22, 0x5B, 0x59, 0x14, 0xB5, 0x8A), pack("C*", 0x52, 0xD3, 0xB0, 0x2F, 0xE2, 0xE6, 0x70, 0x40), pack("C*", 0xF8, 0x0C, 0x0A, 0x91, 0xE3, 0xE5, 0xEA, 0xEE), pack("C*", 0x18, 0xA9, 0xBA, 0x68, 0x2F, 0x1A, 0x86, 0xEC), pack("C*", 0x2E, 0xB7, 0x1D, 0x1A, 0x0A, 0x33, 0xBA, 0x53), pack("C*", 0x6B, 0x25, 0xE3, 0x14, 0xB0, 0x01, 0x92, 0x83), pack("C*", 0x33, 0x47, 0x93, 0x48, 0xCE, 0xFA, 0x2D, 0x9E), pack("C*", 0x9E, 0x54, 0x04, 0xAA, 0x06, 0xB8, 0x3E, 0x0B), pack("C*", 0xF7, 0xE8, 0xE5, 0xB2, 0x6F, 0x78, 0x8C, 0xF4), pack("C*", 0x40, 0x83, 0x36, 0xDD, 0x13, 0x9C, 0x73, 0xC8), pack("C*", 0xAC, 0x07, 0xCC, 0x2C, 0x70, 0x2A, 0x61, 0xB9), pack("C*", 0x24, 0x3E, 0xD1, 0xA4, 0xF7, 0x4A, 0x5A, 0x3F), pack("C*", 0xC3, 0x52, 0x42, 0xCC, 0x90, 0xCB, 0x75, 0x93), pack("C*", 0x5A, 0x53, 0x6F, 0x32, 0x14, 0x9F, 0x5C, 0x35), pack("C*", 0xEC, 0xB5, 0x7E, 0xE6, 0xD1, 0x5B, 0xD0, 0x66), pack("C*", 0x32, 0xCF, 0xE9, 0xFD, 0x09, 0xB8, 0x22, 0xAF), pack("C*", 0x19, 0x5D, 0xFB, 0x10, 0x73, 0x15, 0xBB, 0x59), pack("C*", 0x3F, 0xFE, 0x57, 0xBA, 0xB9, 0xF2, 0x95, 0xF2), pack("C*", 0x7A, 0xB7, 0x71, 0x1E, 0xF9, 0x76, 0xC0, 0xCE), pack("C*", 0x51, 0x6F, 0x13, 0x5E, 0x45, 0xEA, 0xDE, 0x84), pack("C*", 0x81, 0x71, 0xDA, 0x25, 0x22, 0x3C, 0xA7, 0x6D), pack("C*", 0x79, 0xED, 0xB6, 0x1E, 0x0C, 0x7E, 0x66, 0x28), pack("C*", 0xDE, 0x77, 0x6D, 0x7B, 0xF1, 0x64, 0x7A, 0x19), pack("C*", 0x08, 0x86, 0x19, 0x6F, 0xB1, 0xC9, 0xD6, 0xE5), pack("C*", 0x83, 0xF6, 0xA5, 0xB4, 0xA5, 0x2A, 0x81, 0xF7), pack("C*", 0x90, 0x87, 0x54, 0x06, 0x15, 0x29, 0x17, 0xFF), pack("C*", 0xA1, 0x5B, 0x3A, 0xA5, 0xC0, 0x0B, 0x46, 0x6E), pack("C*", 0xE0, 0x7C, 0xC1, 0xD7, 0x58, 0x3B, 0x52, 0xFB), pack("C*", 0xA8, 0x54, 0x25, 0x64, 0x02, 0xC5, 0x91, 0x21), pack("C*", 0x0A, 0x33, 0xF8, 0x18, 0xDB, 0xDC, 0xEF, 0x9E), pack("C*", 0x4A, 0xCD, 0x9F, 0x45, 0x6E, 0x55, 0x6B, 0xF5), pack("C*", 0x60, 0xB9, 0xD4, 0x3F, 0x3F, 0x29, 0x99, 0xED), pack("C*", 0x77, 0xF3, 0x22, 0xDE, 0x43, 0xF7, 0x1E, 0x11), pack("C*", 0x71, 0x5B, 0x6C, 0xFF, 0x66, 0x80, 0x37, 0x2E), pack("C*", 0x61, 0x34, 0x66, 0x03, 0x04, 0x29, 0x33, 0xD8), pack("C*", 0x10, 0xA5, 0x19, 0x4E, 0x70, 0x7C, 0xF4, 0xE4), pack("C*", 0x79, 0x3C, 0x64, 0xC9, 0x70, 0xA7, 0x72, 0xEF), ); my $keyix; my $writefile; my $newcid; my $docid; sub usage { return <<__EOF__ Usage: typhooncidedit [-i DOCID] [-k keyix] [-w outfile] [-c newcid] infile __EOF__ } my %items= ( version=>{ offset=>0x0000, size=>4, encoding=>1}, chkkey=> { offset=>0x0010, size=>8, encoding=>0}, imei=> { offset=>0x0140, size=>8, encoding=>1}, #get_cid_data cid=> { offset=>0x0160, size=>32, encoding=>1}, #get_cid_data cidkeyix=>{ offset=>0x01a0, size=>8, encoding=>2}, #get_01a0_block cidkey=> { offset=>0x1200, size=>0x800, encoding=>3},#get_cid_decryption_key locks=> { offset=>0x1c80, size=>8, encoding=>1}, #get_cid_data codes=> { offset=>0x1d00, size=>0x200, encoding=>6}, #get_cid_data+decrypt_with_2keys mccmnc=> { offset=>0x4000, size=>0x400, encoding=>1},#get_cid_data checksum=>{ offset=>0xfff8, size=>8, encoding=>5}, ); my %newvalue; GetOptions( "k=s"=> \$keyix, "w=s"=> \$writefile, "c=s"=> \$newcid, "i=s"=> sub { $docid=pack("H*", $_[1]); }, "s=s"=> sub { if ($_[1]=~/(\w+)=(.*)/) { $newvalue{$1}= $2; } }, ) or die usage(); my $fn= shift || die usage(); my $fh= IO::File->new($fn, "r") or die "opening: $fn: $!\n"; binmode $fh; my $g_securityblock; $fh->read($g_securityblock, -s $fh) or die "reading $fn: $!\n"; $fh->close(); printf("0x0000 - version : %08lx\n", unpack("V", substr($g_securityblock, 0, 4))); if (length($docid)) { use integer; my $keyix= unpack('%32C*', $docid)*(unpack('%32C*', substr($docid, 12, 4))-0x13dc25bb); # 96 == 2**32 % 100 $keyix = ($keyix+96)%100; $keyix += 100 if ($keyix<0); } if (!defined $keyix) { $keyix= find_key_index(); if (!defined $keyix) { die "could not determine a key index\n"; } } sub hex_or_quoted { my $data= shift; if ($data =~ /^([[:print:]]+)\x00*$/) { return "'$1'"; } else { return unpack("H*", $data); } } my $blockix= calc_1200_block_index($keyix); printf("0x01a0 - keyindex: %s -> %d\n", unpack("H*", get_01a0_block($keyix)), $blockix); my $cidkey= get_cid_decryption_key($keyix, $blockix); printf("0x%04x - cid key : %s\n", 8*$blockix+0x1200, hex_or_quoted($cidkey)); my $ciddata= get_cid_data($cidkey, 0x160, 0x20); my $cidkeylen=unpack("v", $ciddata); printf("0x0160 - cid : %04x:'%s' %s\n", $cidkeylen, substr($ciddata, 2, $cidkeylen), unpack("H*", substr($ciddata, 2+$cidkeylen))); printf("0x1c80 - lockflag: %s\n", unpack("H*", get_cid_data($cidkey, 0x1c80, 8))); my $imei= unpack("H*", get_cid_data($cidkey, 0x140, 8)); $imei =~ s/(.)(.)/$2$1/g; printf("0x0140 - imei : %s\n", $imei); # for (my $ofs =0; $ofs<8; $ofs++) { # my $ixblock= des_encrypt(substr($g_securityblock, $ofs*8+0x190, 8), $keylist[($keyix+53)%100]); # printf(" 0x%04x: %s\n", 0x190+$ofs*8, unpack("H*", $ixblock)); # } # # for (my $kix= 0 ; $kix<0x100 ; $kix++) { # my $key= des_encrypt(substr($g_securityblock, 8*$kix+0x1200, 8), $keylist[($keyix+77)%100]); # printf(" 0x%04x: %s\n", 0x1200+8*$kix, unpack("H*", $key)); # } for (my $kix= 0 ; $kix<5 ; $kix++) { my $dd= get_cid_data($cidkey, 0x1d00+0x10*$kix, 0x10); my $de= decrypt_with_2keys($keyix, $dd, $kix); printf("0x%04x - lock %2d : %s\n", 0x1d00+0x10*$kix, $kix, hex_or_quoted($de)); } printf("0x4000 - mncmcc : %s\n", unpack("H*", get_cid_data($cidkey, 0x4000, 0x20))); if ($newcid) { printf("olddata: %s\n", unpack("H*", substr($g_securityblock, 0x160, 0x20))); substr($g_securityblock, 0x160, 0x20)= encrypt_cid_data($cidkey, $newcid); printf("newdata: %s\n", unpack("H*", substr($g_securityblock, 0x160, 0x20))); my $newsum= calcsum($g_securityblock, 0xfff8); my $sumenc= decrypt_cid_checksum($keyix, pack("VV", $newsum, $newsum)); substr($g_securityblock, 0xfff8, 8)= $sumenc; printf("newsum=%08lx encsum=%s\n", $newsum, unpack("H*", $sumenc)); if ($writefile) { my $ofh= IO::File->new($writefile, "w") or die "openfile: $writefile: $!\n"; binmode $ofh; $ofh->print($g_securityblock); $ofh->close(); } } exit(0); sub find_key_index { my $sum= calcsum($g_securityblock, 0xfff8); for (my $i=0 ; $i<100 ; $i++) { my $sumdec= decrypt_cid_checksum($i, pack("VV", $sum, $sum)); my $stored= substr($g_securityblock, 0xfff8, 8); if ($sumdec eq $stored) { printf("0xfff8 - checksum: keyix=%d: %08lx - %s\n", $i, $sum, unpack("H*", $sumdec)); return $i; } } return undef; } sub get_cid_data { my ($cidkey, $ofs, $len)= @_; return decrypt_cid_data($cidkey, substr($g_securityblock, $ofs, $len)); } sub get_cid_decryption_key { my ($keyix, $blockix)= @_; return des_encrypt(substr($g_securityblock, 8*$blockix+0x1200, 8), $keylist[($keyix+77)%100]); } sub decrypt_with_2keys { my ($keyix, $data, $ix)= @_; return join("", map { des_encrypt(substr($data, 8*$_, 8), $keylist[($keyix+$ix+$_)%100]) } (0..length($data)/8)); } sub decrypt_cid_data { my ($cidkey, $data)= @_; return des_encrypt($data, $cidkey); } sub encrypt_cid_data { my ($cidkey, $cid)= @_; return des_decrypt(pack("va30", length($cid), $cid), $cidkey); } sub decrypt_cid_checksum { my ($keyix, $sumsum)= @_; my $key= des_encrypt(substr($g_securityblock, 0x10, 8), $keylist[($keyix+19)%100]); return des_decrypt($sumsum, $key); } # ??? sub encrypt_cid_checksum { my ($keyix, $sumsum)= @_; my $key= des_encrypt(substr($g_securityblock, 0x10, 8), $keylist[($keyix+19)%100]); return des_encrypt($sumsum, $key); } sub get_01a0_block { my ($keyix)= @_; my $ixblock= des_encrypt(substr($g_securityblock, 2*8+0x190, 8), $keylist[($keyix+53)%100]); } sub calc_1200_block_index { my ($keyix)= @_; my $ixblock= get_01a0_block($keyix); return ord(substr($ixblock, 3,1)); } sub calcsum { my ($data, $length)= @_; return unpack("%32V*", substr($data, 0, $length)); } sub des_encrypt { my ($data, $key)= @_; #$key &= "\xfe" x 8; my $des= Crypt::DES->new($key); my $result= ""; for (my $i=0 ; $iencrypt(substr($data,$i,8)); } return $result; } sub des_decrypt { my ($data, $key)= @_; #$key &= "\xfe" x 8; my $des= Crypt::DES->new($key); my $result= ""; for (my $i=0 ; $idecrypt(substr($data,$i,8)); } return $result; }