App-zipdetails
view release on metacpan or search on metacpan
bin/zipdetails view on Meta::CPAN
seekTo($offset) ;
my $buffer;
myRead($buffer, $len);
length $buffer == $len
or return '';
return $buffer;
}
sub readSignatureFromOffset
{
my $offset = shift ;
# catch use case where attempting to read past EOF
# sub is expecting to return a 32-bit value so return 54-bit out-of-bound value
return MAX64
if $offset + 4 > $FILELEN ;
my $here = $FH->tell();
my $buffer = readFromOffset($offset, 4);
my $gotSig = unpack("V", $buffer) ;
seekTo($here);
return $gotSig;
}
sub chckForAPKSigningBlock
{
my $fh = shift;
my $cdOffset = shift;
my $cdSize = shift;
# APK Signing Block comes directly before the Central directory
# See https://source.android.com/security/apksigning/v2
# If offset available is less than 44, it isn't an APK signing block
#
# len1 8
# id 4
# kv with zero len 8
# len1 8
# magic 16
# ----------
# 44
return (0, 0, '')
if $cdOffset < 44 || $FILELEN - $cdSize < 44 ;
# Step 1 - 16 bytes before CD is literal string "APK Sig Block 42"
my $magicOffset = $cdOffset - 16;
my $buffer = readFromOffset($magicOffset, 16);
return (0, 0, '')
if $buffer ne "APK Sig Block 42" ;
# Step 2 - read the second length field
# and check that it looks ok
$buffer = readFromOffset($cdOffset - 16 - 8, 8);
my $len2 = unpack("Q<", $buffer);
return (0, 0, '')
if $len2 == 0 || $len2 > $FILELEN;
# Step 3 - read the first length field.
# It should be identical to the second one.
my $startApkOffset = $cdOffset - 8 - $len2 ;
$buffer = readFromOffset($startApkOffset, 8);
my $len1 = unpack("Q<", $buffer);
return (0, 0, '')
if $len1 != $len2;
return ($startApkOffset, $cdOffset - 16 - 8, $buffer);
}
sub scanApkBlock
{
state $IDs = {
0x7109871a => "APK Signature v2",
0xf05368c0 => "APK Signature v3",
0x42726577 => "Verity Padding Block", # from https://android.googlesource.com/platform/tools/apksig/+/master/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
0x6dff800d => "Source Stamp",
0x504b4453 => "Dependency Info",
0x71777777 => "APK Channel Block",
0xff3b5998 => "Zero Block",
0x2146444e => "Play Metadata",
} ;
seekTo($FH->tell() - 4) ;
print "\n";
out "", "APK SIGNING BLOCK";
scanApkPadding();
out_Q "Block Length Copy #1";
my $ix = 1;
while ($FH->tell() < $APK - 8)
{
my ($bytes, $id, $len);
($bytes, $len) = read_Q ;
out $bytes, "ID/Value Length #" . sprintf("%X", $ix), Value_Q($len);
($bytes, $id) = read_V;
out $bytes, " ID", Value_V($id) . " '" . ($IDs->{$id} // 'Unknown ID') . "'";
outSomeData($len-4, " Value");
++ $ix;
}
out_Q "Block Length Copy #2";
my $magic ;
myRead($magic, 16);
( run in 1.058 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )