From 05bb63fac6171ae3778822aa12f772385cba8d79 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Tue, 23 Apr 2024 19:21:31 +0200 Subject: [PATCH] Print apk V2 certificates --- .../com/reandroid/apkeditor/info/Info.java | 9 ++++++ .../reandroid/apkeditor/info/InfoOptions.java | 14 +++++++++ .../reandroid/apkeditor/info/InfoWriter.java | 15 +++++++++ .../apkeditor/info/InfoWriterJson.java | 16 ++++++++++ .../apkeditor/info/InfoWriterText.java | 31 +++++++++++++++++-- .../apkeditor/info/InfoWriterXml.java | 13 ++++++++ 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/reandroid/apkeditor/info/Info.java b/src/main/java/com/reandroid/apkeditor/info/Info.java index 34aa18eb..c652ad92 100644 --- a/src/main/java/com/reandroid/apkeditor/info/Info.java +++ b/src/main/java/com/reandroid/apkeditor/info/Info.java @@ -91,6 +91,7 @@ private void print(ApkModule apkModule) throws IOException { printResources(apkModule); printDex(apkModule); + printSignatures(apkModule); } private void printSourceFile() throws IOException { InfoOptions options = getOptions(); @@ -126,6 +127,14 @@ private void printDex(ApkModule apkModule) throws IOException { DexDirectory dexDirectory = DexDirectory.readStrings(apkModule.getZipEntryMap()); infoWriter.writeDexInfo(dexDirectory); } + private void printSignatures(ApkModule apkModule) throws IOException { + InfoOptions options = getOptions(); + if(!options.signatures && !options.signatures_base64){ + return; + } + InfoWriter infoWriter = getInfoWriter(); + infoWriter.writeSignatureInfo(apkModule.getApkSignatureBlock(), options.signatures_base64); + } private void printResList(ApkModule apkModule) throws IOException { InfoOptions options = getOptions(); if(options.resList.size() == 0){ diff --git a/src/main/java/com/reandroid/apkeditor/info/InfoOptions.java b/src/main/java/com/reandroid/apkeditor/info/InfoOptions.java index 2011514b..aa50208a 100644 --- a/src/main/java/com/reandroid/apkeditor/info/InfoOptions.java +++ b/src/main/java/com/reandroid/apkeditor/info/InfoOptions.java @@ -42,11 +42,15 @@ public class InfoOptions extends Options { public boolean resources = false; public final List typeFilterList; public boolean dex = false; + public boolean signatures = false; + public boolean signatures_base64 = false; + public InfoOptions(){ super(); this.resList = new ArrayList<>(); this.typeFilterList = new ArrayList<>(); } + @Override public void parse(String[] args) throws ARGException { parseInput(args); @@ -77,6 +81,8 @@ public void parse(String[] args) throws ARGException { activities = containsArg(ARG_activities, args, activities); resources = containsArg(ARG_resources, args, false); dex = containsArg(ARG_dex, args, false); + signatures = containsArg(ARG_signatures, args, false); + signatures_base64 = containsArg(ARG_signatures_base64, args, false); @@ -184,6 +190,8 @@ public static String getHelp(){ new String[]{ARG_resources, ARG_DESC_resources}, new String[]{" ", " "}, new String[]{ARG_dex, ARG_DESC_dex}, + new String[]{ARG_signatures, ARG_DESC_signatures}, + new String[]{ARG_signatures_base64, ARG_DESC_signatures_base64}, new String[]{" ", " "}, new String[]{ARG_ALL_help, ARG_DESC_help} }; @@ -274,6 +282,12 @@ public static String getHelp(){ private static final String ARG_dex = "-dex"; private static final String ARG_DESC_dex = "Prints dex information"; + private static final String ARG_signatures = "-signatures"; + private static final String ARG_DESC_signatures = "Prints signature information"; + + private static final String ARG_signatures_base64 = "-signatures-base64"; + private static final String ARG_DESC_signatures_base64 = "Prints signature information with base64 certificates"; + private static final String[] availableTypes = new String[]{TYPE_TEXT, TYPE_JSON, TYPE_XML}; } diff --git a/src/main/java/com/reandroid/apkeditor/info/InfoWriter.java b/src/main/java/com/reandroid/apkeditor/info/InfoWriter.java index 064f1f95..fdeb074c 100644 --- a/src/main/java/com/reandroid/apkeditor/info/InfoWriter.java +++ b/src/main/java/com/reandroid/apkeditor/info/InfoWriter.java @@ -15,6 +15,8 @@ */ package com.reandroid.apkeditor.info; +import com.reandroid.archive.block.ApkSignatureBlock; +import com.reandroid.archive.block.CertificateBlock; import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.coder.ValueCoder; import com.reandroid.arsc.container.SpecTypePair; @@ -23,6 +25,7 @@ import com.reandroid.dex.model.DexFile; import com.reandroid.utils.HexUtil; import com.reandroid.arsc.value.*; +import com.reandroid.utils.collection.CollectionUtil; import java.io.Closeable; import java.io.IOException; @@ -35,6 +38,13 @@ public InfoWriter(Writer writer){ this.writer = writer; } + public void writeSignatureInfo(ApkSignatureBlock signatureBlock, boolean base64) throws IOException { + if(signatureBlock == null){ + writeNameValue("certificates", "null"); + }else { + writeCertificates(CollectionUtil.toList(signatureBlock.getCertificates()), base64); + } + } public void writeResources(PackageBlock packageBlock, List typeFilters, boolean writeEntries) throws IOException { Iterator itr = packageBlock.iterator(); while (itr.hasNext()){ @@ -47,6 +57,8 @@ public void writeDexInfo(DexDirectory dexDirectory) throws IOException { writeDexInfo(dexFile, true); } } + + public abstract void writeCertificates(List certificateList, boolean base64) throws IOException; public abstract void writeDexInfo(DexFile dexFile, boolean writeSectionInfo) throws IOException; public abstract void writeResources(ResourceEntry resourceEntry, boolean writeEntries) throws IOException; public abstract void writePackageNames(Collection packageBlocks) throws IOException; @@ -98,6 +110,9 @@ static String getValueAsString(Value value){ } return HexUtil.toHex8("0x", value.getData()); } + static String toBase64(byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } static final String TAG_RES_PACKAGES = "resource-packages"; static final String TAG_PUBLIC = "public"; diff --git a/src/main/java/com/reandroid/apkeditor/info/InfoWriterJson.java b/src/main/java/com/reandroid/apkeditor/info/InfoWriterJson.java index 5edbed8c..a83007f8 100644 --- a/src/main/java/com/reandroid/apkeditor/info/InfoWriterJson.java +++ b/src/main/java/com/reandroid/apkeditor/info/InfoWriterJson.java @@ -15,6 +15,7 @@ */ package com.reandroid.apkeditor.info; +import com.reandroid.archive.block.CertificateBlock; import com.reandroid.arsc.array.ResValueMapArray; import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.container.SpecTypePair; @@ -25,6 +26,7 @@ import com.reandroid.arsc.value.ResValueMap; import com.reandroid.dex.model.DexFile; import com.reandroid.dex.sections.Marker; +import com.reandroid.json.JSONObject; import com.reandroid.json.JSONWriter; import java.io.IOException; @@ -43,6 +45,20 @@ public InfoWriterJson(Writer writer) { this.mJsonWriter = jsonWriter; } + @Override + public void writeCertificates(List certificateList, boolean base64) throws IOException { + JSONWriter jsonWriter = mJsonWriter.object() + .key("certificates").array(); + for(CertificateBlock certificateBlock : certificateList){ + JSONObject jsonObject = certificateBlock.toJson(); + if(base64){ + jsonObject.put("base64", toBase64(certificateBlock.getCertificateBytes())); + } + jsonWriter.value(jsonObject); + } + jsonWriter.endArray().endObject(); + } + @Override public void writeDexInfo(DexFile dexFile, boolean writeSectionInfo) throws IOException { JSONWriter jsonWriter = mJsonWriter.object() diff --git a/src/main/java/com/reandroid/apkeditor/info/InfoWriterText.java b/src/main/java/com/reandroid/apkeditor/info/InfoWriterText.java index 40ac629f..2ff0979d 100644 --- a/src/main/java/com/reandroid/apkeditor/info/InfoWriterText.java +++ b/src/main/java/com/reandroid/apkeditor/info/InfoWriterText.java @@ -15,6 +15,7 @@ */ package com.reandroid.apkeditor.info; +import com.reandroid.archive.block.CertificateBlock; import com.reandroid.arsc.array.ResValueMapArray; import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.container.SpecTypePair; @@ -28,6 +29,7 @@ import com.reandroid.dex.sections.MapList; import com.reandroid.dex.sections.Marker; import com.reandroid.utils.HexUtil; +import com.reandroid.utils.StringsUtil; import java.io.IOException; import java.io.Writer; @@ -35,12 +37,28 @@ import java.util.Iterator; import java.util.List; -public class InfoWriterText extends InfoWriter{ +public class InfoWriterText extends InfoWriter { + public InfoWriterText(Writer writer) { super(writer); } - + @Override + public void writeCertificates(List certificateList, boolean base64) throws IOException { + Writer writer = getWriter(); + writer.write("\n"); + writeNameValue("Certificates", certificateList.size()); + for(CertificateBlock certificateBlock : certificateList) { + writeWithTab(writer, ARRAY_TAB, certificateBlock.printCertificate()); + if(base64) { + writer.write(ARRAY_TAB); + writer.write("Base64: "); + writer.write(toBase64(certificateBlock.getCertificateBytes())); + writer.write("\n"); + } + } + flush(); + } @Override public void writeDexInfo(DexFile dexFile, boolean writeSectionInfo) throws IOException { Writer writer = getWriter(); @@ -276,6 +294,15 @@ public void flush() throws IOException { writer.flush(); } + + private void writeWithTab(Writer writer, String tab, String value) throws IOException { + String[] splits = StringsUtil.split(value, '\n'); + for(String line : splits){ + writer.write(tab); + writer.write(line.trim()); + writer.write("\n"); + } + } private static int getDecimalPlaces(int max){ int i = 0; while (max != 0){ diff --git a/src/main/java/com/reandroid/apkeditor/info/InfoWriterXml.java b/src/main/java/com/reandroid/apkeditor/info/InfoWriterXml.java index 437854c5..74ddc77a 100644 --- a/src/main/java/com/reandroid/apkeditor/info/InfoWriterXml.java +++ b/src/main/java/com/reandroid/apkeditor/info/InfoWriterXml.java @@ -15,10 +15,12 @@ */ package com.reandroid.apkeditor.info; +import com.reandroid.archive.block.CertificateBlock; import com.reandroid.dex.model.DexFile; import com.reandroid.dex.sections.MapItem; import com.reandroid.dex.sections.MapList; import com.reandroid.dex.sections.Marker; +import com.reandroid.utils.collection.ComputeList; import com.reandroid.xml.kxml2.KXmlSerializer; import com.reandroid.arsc.array.ResValueMapArray; import com.reandroid.arsc.chunk.PackageBlock; @@ -45,6 +47,17 @@ public InfoWriterXml(Writer writer) { super(writer); } + @Override + public void writeCertificates(List certificateList, boolean base64) throws IOException { + List infoList = new ComputeList<>(certificateList, certificateBlock -> { + String value = certificateBlock.printCertificate(); + if(base64) { + value = value + "\n" + toBase64(certificateBlock.getCertificateBytes()); + } + return value; + }); + writeArray("certificates", infoList.toArray()); + } @Override public void writeDexInfo(DexFile dexFile, boolean writeSectionInfo) throws IOException { KXmlSerializer serializer = getSerializer();