Skip to content

Instantly share code, notes, and snippets.

@mwgamera
Last active August 29, 2015 13:57
Show Gist options
  • Save mwgamera/9774270 to your computer and use it in GitHub Desktop.
Save mwgamera/9774270 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# Analyze header of CRX packages (Chrome extensions).
# klg, Feb 2014
use strict;
use open IO => ':bytes';
use Digest::SHA 'sha256_hex';
use MIME::Base64;
use Crypt::OpenSSL::RSA;
use constant CRX_MAGIC => 0x34327243;
sub pkid($) {
(lc unpack 'a32', sha256_hex @_) =~ y/0-9a-f/a-p/r;
}
sub pkrsa($) {
Crypt::OpenSSL::RSA->new_public_key("-----BEGIN PUBLIC KEY-----\n".
encode_base64(shift)."-----END PUBLIC KEY-----");
}
do {
my $fn = shift // '-';
open my $fh, $fn or die $!;
binmode $fh;
$fn = $fn eq '-' ? '' : "$fn: ";
read $fh, $_, 16 or die $!;
my ($crx, $ver, $pklen, $siglen) = unpack 'V4';
die "${fn}Bad format\n" unless $crx == CRX_MAGIC;
die "${fn}Unknown version of CRX file\n" unless $ver == 2;
read $fh, my $pk, $pklen or die $!;
read $fh, my $sig, $siglen or die $!;
printf "%sID: %s\n", $fn, pkid($pk);
my $rsa = pkrsa($pk);
printf "%sRSA %u bits, ", $fn, 8 * $rsa->size;
my $zip = do { local $/; <$fh> };
$rsa->use_sslv23_padding;
$rsa->use_sha1_hash;
printf "signature %s\n",
('INCORRECT!', 'correct.')[!!$rsa->verify($zip, $sig)];
close $fh;
} while @ARGV;
1;
#!/usr/bin/env perl
# Merge signature with zip to create CRX file.
# klg, Feb 2014
use strict;
use open IO => ':bytes';
use constant {
CRX_MAGIC => 0x34327243,
BLOCK_SIZE => 4049
};
die "Usage: $0 pub sig zip > crx\n" if @ARGV < 3;
my ($pub, $sig) = map { local (@ARGV, $/) = $_; <> } @ARGV[0,1];
warn "Public key should be DER encoded in X509 SubjectPublicKeyInfo format"
unless 0x30 == ord $pub;
open my $zip, $ARGV[2] or die $!;
print pack 'V4', CRX_MAGIC, 2, length($pub), length($sig);
print $pub, $sig;
print while read $zip, $_, BLOCK_SIZE;
close $zip;
1;
#!/usr/bin/env perl
# Split header of CRX Chrome package.
# klg, Feb 2014
use strict;
use open IO => ':bytes';
use constant {
CRX_MAGIC => 0x34327243,
BLOCK_SIZE => 4049
};
do {
open my $crx, (my $ncrx = shift) // '-' or die $!;
binmode $crx;
$ncrx //= 'stdin';
$ncrx =~ s/\.crx$//i;
read $crx, $_, 16 or die $!;
my ($magic, $ver, $publen, $siglen) = unpack 'V4';
die "$ncrx: bad format\n" unless $magic == CRX_MAGIC;
die "$ncrx: Unknown version of CRX file\n" unless $ver == 2;
my ($npub, $nsig, $nzip) = map { "$ncrx.$_" } qw/pub sig zip/;
do { die "$_: output file exists\n" if -f $_ } for ($npub, $nsig, $nzip);
my $i;
open my $pub, '>', $npub or die $!;
read $crx, $_, $i = $publen or die $!;
print $pub $_;
close $pub;
print STDERR "$i bytes written to $npub\n";
open my $sig, '>', $nsig or die $!;
read $crx, $_, $i = $siglen or die $!;
print $sig $_;
close $sig;
print STDERR "$i bytes written to $nsig\n";
$i = 0;
open my $zip, '>', $nzip or die $!;
print($zip $_), $i += length while read $crx, $_, BLOCK_SIZE;
close $zip;
print STDERR "$i bytes written to $nzip\n";
close $crx;
} while @ARGV;
1;
#!/usr/bin/env perl
# Find RSA key with fingerprint matching a regex.
# klg, Feb 2014
use strict;
use Crypt::OpenSSL::RSA;
use MIME::Base64;
use Digest::SHA 'sha256_hex';
use Time::HiRes 'time';
die "Usage: $0 size regex\n" unless @ARGV > 1;
my $bits = int $ARGV[0];
my $regex = qr/$ARGV[1]/i;
warn "Note: Fingerprint contains only letters in a-p range.\n"
if $ARGV[1] =~ /[0-9q-z]/i;
Crypt::OpenSSL::RSA->import_random_seed();
sub pkid($) {
my ($spk) = shift->get_public_key_x509_string =~ /-\n(.*)\n-/s;
(lc unpack 'a32', sha256_hex decode_base64 $spk) =~ y/0-9a-f/a-p/r;
}
my $rsa;
my ($i, $j, $t0, $t1) = (0, 0, time, time);
my $dt = 0.1;
do {
if (time - $t1 > $dt) {
printf STDERR "\rRSA %u bits, %.2f kps, total %u in %.1f sec ...\033[K\r",
8 * $rsa->size, $i / (time - $t1), $j, time - $t0;
$dt += 0.1 if $i < 3;
$dt -= 0.1 if $i > 30;
$dt = 0.1 if $dt < 0.1;
($i, $t1) = (0, time);
}
$i++, $j++;
$rsa = Crypt::OpenSSL::RSA->generate_key($bits);
} until pkid($rsa) =~ $regex;
printf STDERR "\r\033[KID: %s\n", pkid $rsa;
printf STDERR "Found in %.2f seconds, tried %u keys\n", time - $t0, $j;
# Note: this must be piped through `openssl pkey`
# to convert it into format recognizable by Chrome.
print $rsa->get_private_key_string;
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment