代码: 全选
use utf8;
use Encode;
use Modern::Perl;
use File::Slurp;
use Mojo::UserAgent;
use MIME::Base64;
# metacpan 搜索 GCM 找到该模块
use Crypt::AuthEnc::GCM qw(gcm_encrypt_authenticate gcm_decrypt_verify);
use Win32::API;
use File::Copy;
use DBI;
use JSON qw/from_json to_json/;
STDOUT->autoflush(1);
my $f1 = "C:\\Users\\". $ENV{"USERNAME"} ."\\AppData\\Local\\Google\\Chrome\\User Data\\Local State";
my $data = from_json( scalar(read_file($f1)) );
# encrypt_key 前5位是 "DPAPI"
my $enc_key = decode_base64( $data->{'os_crypt'}{'encrypted_key'} );
$enc_key = substr($enc_key, 5);
my $dec_key = decryptData( $enc_key );
print_hex($dec_key);
unless ( -e "Cookies" ) {
my $chrome_cookie_file = 'C:/Users/'.$ENV{"USERNAME"}.'/AppData/Local/Google/Chrome/User Data/Default/Cookies';
copy($chrome_cookie_file, 'Cookies') || die "Failed to move files: $!";;
}
my $dbc = DBI->connect("dbi:SQLite:dbname=Cookies", '', '', { RaiseError => 1, AutoCommit => 0});
my @rows = @{$dbc->selectall_arrayref("SELECT host_key, name, value, encrypted_value FROM cookies")};
for my $row (@rows)
{
my ($host_key, $name, $value, $encrypted_value) = @{$row};
next unless ( $host_key eq ".baidu.com" );
printf "%s\n", $name;
# 加密数据以 v10 的 ASCII 编码(即 0x763130)开始,然后是 12 字节的随机数、实际密文,最后是 16 字节的认证标签。 可以按如下方式分离各个组件:
my $nonce = substr($encrypted_value, 3, 12);
my $ciphertext = substr($encrypted_value, 3+12, -16);
my $tag = substr($encrypted_value, -16);
# print_hex($nonce);
# print_hex($ciphertext);
# print_hex($tag);
# decrypt and verify
my $plaintext = gcm_decrypt_verify('AES', $dec_key, $nonce, undef, $ciphertext, $tag);
printf "%s\n", $plaintext;
}
$dbc->commit(); #SQLite is slow at excuting one row at a time. SEE: http://stackoverflow.com/a/8882184
$dbc->disconnect();
sub decryptData
{
#Cleaned up version of http://www.perlmonks.org/?node_id=776481
my $encryptedData = shift;
if($encryptedData eq ''){ return undef; } #avoid errors...
my $pDataIn = pack('LL', length($encryptedData)+1, unpack('L!', pack('P', $encryptedData)));
my $DataOut;
my $pDataOut = pack('LL', 0, 0);
my $CryptUnprotectData = Win32::API->new('Crypt32', 'CryptUnprotectData', ['P', 'P', 'P', 'P', 'P', 'N', 'P'], 'N');
if($CryptUnprotectData->Call($pDataIn, pack('L', 0), 0, pack('L', 0), pack('L4', 16, 0, 0, unpack('L!', pack('P', 0))), 0, $pDataOut)){
my($len, $ptr) = unpack('LL', $pDataOut);
$DataOut = unpack('P'.$len, pack('L!', $ptr));
return $DataOut;
}else{
return undef;
}
}
sub print_hex
{
my $s = shift;
$s=~s/(.)/sprintf "%02X ", ord($1)/ge;
printf "%s\n", $s;
}
sub gbk { encode('gbk', $_[0]) }
sub utf8 { encode('utf8', $_[0]) }
sub u2gbk { encode('gbk', decode('utf8', $_[0])) }
sub uni { decode('utf8', $_[0]) }