hsiafan / apk-parser

Apk parser for java
BSD 2-Clause "Simplified" License
1.21k stars 360 forks source link

throws a IllegalArgumentException when use AbstractApkFile's 'getV2Signer()' method #72

Open Crystalyh opened 6 years ago

Crystalyh commented 6 years ago

List v2signers = apkFile.getApkV2Singers(); I debuged the code, find that error ocures in class AbstractApkFile's method 'parseApkSigningBlock()' at line 145 ApkSigningBlock apkSigningBlock = parser.parse(); I think maybe because that my apk file is not signed by v2, but when I tested by a v2 signer apk, there still exists that error, I just don't know why , so can you explain my question, thank you so much!

hsiafan commented 6 years ago

Can you provide the apk file caused this problem? A download link is good for me.

myhloli commented 5 years ago

same error with me Exception in thread "main" java.lang.IllegalArgumentException at java.nio.Buffer.position(Buffer.java:244) at net.dongliu.apk.parser.utils.Buffers.position(Buffers.java:107) at net.dongliu.apk.parser.parser.ApkSignBlockParser.parse(ApkSignBlockParser.java:47) at net.dongliu.apk.parser.AbstractApkFile.parseApkSigningBlock(AbstractApkFile.java:152) at net.dongliu.apk.parser.AbstractApkFile.getApkV2Singers(AbstractApkFile.java:142)

null-dev commented 5 years ago

@hsiafan Hey, if you still need an example of this, I have an APK here: https://s3.wasabisys.com/nd-public/tmp/parse-fail.apk

celiovasconcelos commented 4 years ago

Same here 😢

hohaiuhsx commented 4 years ago

Same error!!! I debugged the code and found that these changes could be fixed! image

package net.dongliu.apk.parser.parser;

import net.dongliu.apk.parser.struct.signingv2.ApkSigningBlock;
import net.dongliu.apk.parser.struct.signingv2.Digest;
import net.dongliu.apk.parser.struct.signingv2.Signature;
import net.dongliu.apk.parser.struct.signingv2.SignerBlock;
import net.dongliu.apk.parser.utils.Buffers;
import net.dongliu.apk.parser.utils.Unsigned;

import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

public class ApkSignBlockParser {
    private ByteBuffer data;

    public ApkSignBlockParser(ByteBuffer data) {
        this.data = data.order(ByteOrder.LITTLE_ENDIAN);
    }

    public ApkSigningBlock parse() throws CertificateException {
        // sign block found, read pairs
        List<SignerBlock> signerBlocks = new ArrayList<>();
        while (data.remaining() >= 8) {
            int id = data.getInt();
            int size = Unsigned.ensureUInt(data.getInt());
            if (id == ApkSigningBlock.SIGNING_V2_ID) {
                ByteBuffer signingV2Buffer = Buffers.sliceAndSkip(data, size);
                // now only care about apk signing v2 entry
                while (signingV2Buffer.hasRemaining()) {
                    SignerBlock signerBlock = readSigningV2(signingV2Buffer);
                    signerBlocks.add(signerBlock);
                }
            } else {
                // just ignore now
                if (size < data.remaining()) {
                    Buffers.position(data, data.position() + size);
                } else {
                    break;
                }
            }
        }
        return new ApkSigningBlock(signerBlocks);
    }

    private SignerBlock readSigningV2(ByteBuffer buffer) throws CertificateException {
        buffer = readLenPrefixData(buffer);

        ByteBuffer signedData = readLenPrefixData(buffer);
        ByteBuffer digestsData = readLenPrefixData(signedData);
        List<Digest> digests = readDigests(digestsData);
        ByteBuffer certificateData = readLenPrefixData(signedData);
        List<X509Certificate> certificates = readCertificates(certificateData);
        ByteBuffer attributesData = readLenPrefixData(signedData);
        readAttributes(attributesData);

        ByteBuffer signaturesData = readLenPrefixData(buffer);
        List<Signature> signatures = readSignatures(signaturesData);

        ByteBuffer publicKeyData = readLenPrefixData(buffer);
        return new SignerBlock(digests, certificates, signatures);
    }

    private List<Digest> readDigests(ByteBuffer buffer) {
        List<Digest> list = new ArrayList<>();
        while (buffer.hasRemaining()) {
            ByteBuffer digestData = readLenPrefixData(buffer);
            int algorithmID = digestData.getInt();
            byte[] digest = Buffers.readBytes(digestData);
            list.add(new Digest(algorithmID, digest));
        }
        return list;
    }

    private List<X509Certificate> readCertificates(ByteBuffer buffer) throws CertificateException {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        List<X509Certificate> certificates = new ArrayList<>();
        while (buffer.hasRemaining()) {
            ByteBuffer certificateData = readLenPrefixData(buffer);
            Certificate certificate = certificateFactory.generateCertificate(
                    new ByteArrayInputStream(Buffers.readBytes(certificateData)));
            certificates.add((X509Certificate) certificate);
        }
        return certificates;
    }

    private void readAttributes(ByteBuffer buffer) {
        while (buffer.hasRemaining()) {
            ByteBuffer attributeData = readLenPrefixData(buffer);
            int id = attributeData.getInt();
//            byte[] value = Buffers.readBytes(attributeData);
        }
    }

    private List<Signature> readSignatures(ByteBuffer buffer) {
        List<Signature> signatures = new ArrayList<>();
        while (buffer.hasRemaining()) {
            ByteBuffer signatureData = readLenPrefixData(buffer);
            int algorithmID = signatureData.getInt();
            int signatureDataLen = Unsigned.ensureUInt(signatureData.getInt());
            byte[] signature = Buffers.readBytes(signatureData, signatureDataLen);
            signatures.add(new Signature(algorithmID, signature));
        }
        return signatures;
    }

    private ByteBuffer readLenPrefixData(ByteBuffer buffer) {
        int len = Unsigned.ensureUInt(buffer.getInt());
        return Buffers.sliceAndSkip(buffer, len);
    }

    // 0x0101—RSASSA-PSS with SHA2-256 digest, SHA2-256 MGF1, 32 bytes of salt, trailer: 0xbc
    private static final int PSS_SHA_256 = 0x0101;
    // 0x0102—RSASSA-PSS with SHA2-512 digest, SHA2-512 MGF1, 64 bytes of salt, trailer: 0xbc
    private static final int PSS_SHA_512 = 0x0102;
    // 0x0103—RSASSA-PKCS1-v1_5 with SHA2-256 digest. This is for build systems which require deterministic signatures.
    private static final int PKCS1_SHA_256 = 0x0103;
    // 0x0104—RSASSA-PKCS1-v1_5 with SHA2-512 digest. This is for build systems which require deterministic signatures.
    private static final int PKCS1_SHA_512 = 0x0104;
    // 0x0201—ECDSA with SHA2-256 digest
    private static final int ECDSA_SHA_256 = 0x0201;
    // 0x0202—ECDSA with SHA2-512 digest
    private static final int ECDSA_SHA_512 = 0x0202;
    // 0x0301—DSA with SHA2-256 digest
    private static final int DSA_SHA_256 = 0x0301;

}