初学这个per脚本分析
yuqa
|
1#
yuqa 发表于 2009-01-04 07:40
初学这个per脚本分析
初学这个per脚本分析
use strict; use warnings; use bigint lib=>'GMP'; use Crypt::Rijndael; use Digest::SHA qw(sha256); use IO::File; use Getopt::Long; $|=1; my $docidhex; my $newcid; my $newcidfile; my $clearlocks; #perl tstrsa.pl -i 000000000909011515250bac180a054e ..\devices\00171\cid.nb # layout of cid data block: # 04b5 : index to lockdatakey # 07ba : index to lockdata block # 1000-9000 : contains 2048 byte aes encrypted lockdata block # b000-f000 : contains 64 bytes rsa encrypted lockdata key # ffe0-END : aes encrypted hash of cid data block sub usage { return <<__EOF__ Usage: startrek_cidedit -i DOCID cidfile.nb __EOF__ } GetOptions( "i=s" => \$docidhex, ) or die usage(); if (!@ARGV || !$docidhex) { die usage(); } my $ifn= shift; my $ifh= IO::File->new($ifn, "r") or die "$ifn: $!\n"; binmode $ifh; my $ciddata; $ifh->read($ciddata, 65536); $ifh->close(); #my $docid= pack("H*", "000000000909011515250bac180a054e"); #my $docid= pack("H*", "000000008805010a2102102b090c05cd"); my $docid= pack("H*", $docidhex); print "decrypting\n"; my $lockdata= decrypt_cid_block($ciddata, $docid); #print "oldcid\n"; #print hexdump($newcid); #print "lockdata\n"; #print hexdump($lockdata); my $changed= 0; if ($clearlocks) { substr($lockdata, 0, 8)= pack("Vvv", 1, 0, 0); substr($lockdata, 10, 2)= pack("v", 0); substr($lockdata, 0x0404, 8)= pack("VV", 0, 0); $changed=1; } else { print "lockdata\n"; print hexdump($lockdata); } #print "re-decrypting\n"; #my $lockdata2= decrypt_cid_block($newcid, $docid); #print "newcid\n"; #print hexdump($newcid); #print "lockdata2\n"; #print hexdump($lockdata2); exit(0); sub decrypt_cid_block { my ($ciddata, $docid)= @_; # part1: verify cid block checksum my $shadoc = swapdw(sha256($docid)); #printf("decrypt_cid_block\n"); # these are used to calculate the aes keys my $sha64k = swapdw(sha256(substr($ciddata, 0, 0xffe0))); my $bufend = substr($ciddata, 0xffe0, 0x20); my $aeskey1= substr($shadoc, 0, 16) . substr($sha64k, 0, 16); my $aesiv1= substr($sha64k, 16, 16) . substr($shadoc, 0, 16); my $result= doaesdecrypt($bufend, $aeskey1, $aesiv1); if ($result ne $sha64k) { printf("bufend=%s\n", unpack("H*", $bufend)); printf("result=%s\n", unpack("H*", $result)); printf("sha64k=%s\n", unpack("H*", $sha64k)); die "buffer checksum failed\n"; } # part2: decrypt the data section my $exp = 65537; my $pq = 88438332459575713003174419268502556144700924300208596763704599584326505691433; my $y = 69399065592429616374372553429979240083906900467887630575728849318636934515345; my $ciddata_4b5= ord(substr($ciddata, 0x4b5, 1)); my $offset_4b5= 0xB000 + (($ciddata_4b5 &0xf)<<10); #printf("ciddata[4b5]= %02x -> offset %04x\n", $ciddata_4b5, $offset_4b5); my $encryptedkey = substr($ciddata, $offset_4b5, 0x40); my $keydata=""; for (my $i=0 ; $i<length($encryptedkey) ; $i+=32) { my $num = tonumber(substr($encryptedkey, $i, 32)); my $decrypted = $num->bmodpow($exp, $pq); my $decdata = todata($decrypted); $keydata.= $decdata; if (unpack("%8C*", substr($decdata, 0, 24)) != ord(substr($decdata, 30,1))) { printf("%s : %02x\n", unpack("H*", $decdata), unpack("%8C*", substr($decdata, 0, 24))); die "key-checksum mismatch\n"; } } my $aeskey2= substr($keydata, 0, 16).substr($keydata, 32, 16); my $aesiv2= join("", map { substr($shadoc, $_, 1).substr($keydata, $_+16,1) } (0..7)) .join("", map { substr($shadoc, $_+8, 1).substr($keydata, $_+48,1) } (0..7)); #printf("aeskey2=%s\n", unpack("H*", $aeskey2)); #printf("aesiv2=%s\n", unpack("H*", $aesiv2)); my $ciddata_7ba= ord(substr($ciddata, 0x7ba, 1)); my $offset_7ba= 0x1000+(($ciddata_7ba&0x1f)<<10); #printf("ciddata[7ba]= %02x -> offset %04x\n", $ciddata_7ba, $offset_7ba); my $encryptedlockdata= substr($ciddata, $offset_7ba, 0x800); #printf("enclockdata=%s\n", unpack("H*", $encryptedlockdata)); my $lockdata= doaesdecrypt($encryptedlockdata, $aeskey2, $aesiv2); #printf("lockdata=%s\n", unpack("H*", $lockdata)); if (swapdw(sha256(substr($lockdata, 0, 0x7e0))) ne substr($lockdata, 0x7e0, 0x20)) { printf("sha[000-7e0]=%s\n", unpack 'H*', swapdw(sha256(substr($lockdata, 0, 0x7e0)))); warn "invalid data-checksum\n"; } return $lockdata; } sub encrypt_cid_block { my ($ciddata, $lockdata, $docid)= @_; my $shadoc = swapdw(sha256($docid)); #printf("encrypt_cid_block\n"); # part2: decrypt the data section my $exp = 65537; my $pq = 88438332459575713003174419268502556144700924300208596763704599584326505691433; my $y = 69399065592429616374372553429979240083906900467887630575728849318636934515345; my $ciddata_4b5= ord(substr($ciddata, 0x4b5, 1)); my $offset_4b5= 0xB000 + (($ciddata_4b5 &0xf)<<10); #printf("ciddata[4b5]= %02x -> offset %04x\n", $ciddata_4b5, $offset_4b5); my $encryptedkey = substr($ciddata, $offset_4b5, 0x40); my $keydata=""; for (my $i=0 ; $i<length($encryptedkey) ; $i+=32) { my $num = tonumber(substr($encryptedkey, $i, 32)); my $decrypted = $num->bmodpow($exp, $pq); my $decdata = todata($decrypted); $keydata.= $decdata; if (unpack("%8C*", substr($decdata, 0, 24)) != ord(substr($decdata, 30,1))) { printf("%s : %02x\n", unpack("H*", $decdata), unpack("%8C*", substr($decdata, 0, 24))); die "key-checksum mismatch\n"; } } my $aeskey2= substr($keydata, 0, 16).substr($keydata, 32, 16); my $aesiv2= join("", map { substr($shadoc, $_, 1).substr($keydata, $_+16,1) } (0..7)) .join("", map { substr($shadoc, $_+8, 1).substr($keydata, $_+48,1) } (0..7)); #printf("aeskey2=%s\n", unpack("H*", $aeskey2)); #printf("aesiv2=%s\n", unpack("H*", $aesiv2)); substr($lockdata, 0x7e0, 0x20)= swapdw(sha256(substr($lockdata, 0, 0x7e0))); #printf("lockdata=%s\n", unpack("H*", $lockdata)); my $encryptedlockdata= doaesencrypt($lockdata, $aeskey2, $aesiv2); #printf("enclockdata=%s\n", unpack("H*", $encryptedlockdata)); my $ciddata_7ba= ord(substr($ciddata, 0x7ba, 1)); my $offset_7ba= 0xec00+(($ciddata_7ba&0x1f)<<10); #printf("ciddata[7ba]= %02x -> offset %04x\n", $ciddata_7ba, $offset_7ba); substr($ciddata, $offset_7ba, 0x800)= $encryptedlockdata; # part1: verify cid block checksum # these are used to calculate the aes keys my $sha64k = swapdw(sha256(substr($ciddata, 0, 0xffe0))); my $aeskey1= substr($shadoc, 0, 16) . substr($sha64k, 0, 16); my $aesiv1= substr($sha64k, 16, 16) . substr($shadoc, 0, 16); my $bufend= doaesencrypt($sha64k, $aeskey1, $aesiv1); substr($ciddata, 0xffe0, 0x20)= $bufend; return $ciddata; } sub hexdump { return join("\n", map { my $x=substr($_[0], $_*16, 16);$x =~ tr/[\x00-\x1f\x7f-\xff]/./; sprintf("%04x: %s %s", $_*16, unpack("H*", substr($_[0], $_*16, 16)), $x); } (0..length($_[0])/16-1))."\n"; } exit(0); sub tonumber { my $data= shift; my $num= 0; for (reverse unpack("C*", $data)) { $num = $num*256 + $_; } return $num; } sub todata { my $num= shift; my @data; while ($num) { push @data, $num % 256; $num = $num / 256; } return pack("C32", @data); } sub doaesdecrypt { my ($in, $key, $iv)= @_; my $aes= Crypt::Rijndael->new($key); return ivdecrypt($aes, $iv, $in); } sub ivdecrypt { my ($aes, $iv, $in)= @_; #printf("ivdecrypt\n"); my $out= ""; my $iv_lo= substr($iv, 0, 16); my $iv_hi= substr($iv, 16, 16); for (my $i=0 ; $i < length($in) ; $i += 32) { my $crp_lo = substr($in, $i, 16); my $dat_lo= $aes->decrypt($crp_lo); $out .= $dat_lo ^ $iv_lo; $iv_lo = $crp_lo; #printf("%dlo: d=%s c=%s i=%s\n", $i/32, map { unpack("H*", $_) } ($dat_lo, $crp_lo, $iv_lo)); my $crp_hi = substr($in, $i+16, 16); my $dat_hi= $aes->decrypt($crp_hi); $out .= $dat_hi ^ $iv_hi; $iv_hi = $crp_hi; #printf("%dhi: d=%s c=%s i=%s\n", $i/32, map { unpack("H*", $_) } ($dat_hi, $crp_hi, $iv_hi)); } # d0 = aes(c0) | c0 = unaes(d0) # o0= d0^iv0 | d0 = o0^iv0 # iv1 = d0 . # d1 = aes(c1) # o1 .= d1^iv1 # iv2 = d1 # return $out; } sub doaesencrypt { my ($in, $key, $iv)= @_; my $aes= Crypt::Rijndael->new($key); return ivencrypt($aes, $iv, $in); } sub ivencrypt { my ($aes, $iv, $in)= @_; #printf("ivencrypt\n"); my $out= ""; my $iv_lo= substr($iv, 0, 16); my $iv_hi= substr($iv, 16, 16); for (my $i=0 ; $i < length($in) ; $i += 32) { my $dat_lo = substr($in, $i, 16) ^ $iv_lo; my $crp_lo= $aes->encrypt($dat_lo); $out .= $crp_lo; $iv_lo = $crp_lo; #printf("%dlo: d=%s c=%s i=%s\n", $i/32, map { unpack("H*", $_) } ($dat_lo, $crp_lo, $iv_lo)); my $dat_hi = substr($in, $i+16, 16) ^ $iv_hi; my $crp_hi= $aes->encrypt($dat_hi); $out .= $crp_hi; $iv_hi = $crp_hi; #printf("%dhi: d=%s c=%s i=%s\n", $i/32, map { unpack("H*", $_) } ($dat_hi, $crp_hi, $iv_hi)); } # d0 = o0^iv0 # c0 = unaes(d0) # iv1 = d0 return $out; } sub swapdw { return pack 'V*', unpack 'N*', $_[0]; } |