From b50706505f3f5ea562239b68710f9ab34e55a570 Mon Sep 17 00:00:00 2001 From: Jan S Date: Sat, 10 Sep 2022 17:58:26 +0200 Subject: [PATCH] fix(res): implemented parsing RES_TABLE_TYPE_LIBRARY chunks (#1663)(PR #1664) * core: Implemented parsing RES_TABLE_TYPE_LIBRARY chunks * skip unknown data at the end of type chunk --- .../jadx/core/xmlgen/ParserConstants.java | 9 ++- .../java/jadx/core/xmlgen/ResTableParser.java | 64 ++++++++++++++++--- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java b/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java index 10221641ff9..49fe38c02b0 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java @@ -28,9 +28,12 @@ protected ParserConstants() { protected static final int RES_XML_LAST_CHUNK_TYPE = 0x017f; protected static final int RES_XML_RESOURCE_MAP_TYPE = 0x0180; - protected static final int RES_TABLE_PACKAGE_TYPE = 0x0200; - protected static final int RES_TABLE_TYPE_TYPE = 0x0201; - protected static final int RES_TABLE_TYPE_SPEC_TYPE = 0x0202; + protected static final int RES_TABLE_PACKAGE_TYPE = 0x0200; // 512 + protected static final int RES_TABLE_TYPE_TYPE = 0x0201; // 513 + protected static final int RES_TABLE_TYPE_SPEC_TYPE = 0x0202; // 514 + protected static final int RES_TABLE_TYPE_LIBRARY = 0x0203; // 515 + protected static final int RES_TABLE_TYPE_OVERLAY = 0x0204; // 516 + protected static final int RES_TABLE_TYPE_STAGED_ALIAS = 0x0206; // 517 /** * Type constants diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java index 7528a0f862a..9dcae36999d 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -153,13 +153,28 @@ private PackageChunk parsePackage() throws IOException { while (is.getPos() < endPos) { long chunkStart = is.getPos(); int type = is.readInt16(); - if (type == RES_NULL_TYPE) { - continue; - } - if (type == RES_TABLE_TYPE_SPEC_TYPE) { - parseTypeSpecChunk(); - } else if (type == RES_TABLE_TYPE_TYPE) { - parseTypeChunk(chunkStart, pkg); + LOG.trace("res package chunk start at {} type {}", chunkStart, type); + switch (type) { + case RES_NULL_TYPE: + LOG.info("Null chunk type encountered at offset {}", chunkStart); + break; + case RES_TABLE_TYPE_TYPE: // 0x0201 + parseTypeChunk(chunkStart, pkg); + break; + case RES_TABLE_TYPE_SPEC_TYPE: // 0x0202 + parseTypeSpecChunk(chunkStart); + break; + case RES_TABLE_TYPE_LIBRARY: // 0x0203 + parseLibraryTypeChunk(chunkStart); + break; + case RES_TABLE_TYPE_OVERLAY: // 0x0204 + throw new IOException( + String.format("Encountered unsupported chunk type TYPE_OVERLAY at offset 0x%x ", chunkStart)); + case RES_TABLE_TYPE_STAGED_ALIAS: // 0x0206 + throw new IOException( + String.format("Encountered unsupported chunk type TYPE_STAGED_ALIAS at offset 0x%x ", chunkStart)); + default: + LOG.warn("Unknown chunk type {} encountered at offset {}", type, chunkStart); } } return pkg; @@ -192,10 +207,10 @@ private String makeNewKeyName(int idx) { } @SuppressWarnings("unused") - private void parseTypeSpecChunk() throws IOException { + private void parseTypeSpecChunk(long chunkStart) throws IOException { is.checkInt16(0x0010, "Unexpected type spec header size"); - /* int size = */ - is.readInt32(); + int chunkSize = is.readInt32(); + long expectedEndPos = chunkStart + chunkSize; int id = is.readInt8(); is.skip(3); @@ -203,6 +218,28 @@ private void parseTypeSpecChunk() throws IOException { for (int i = 0; i < entryCount; i++) { int entryFlag = is.readInt32(); } + if (is.getPos() != expectedEndPos) { + throw new IOException(String.format("Error reading type spec chunk at offset 0x%x", chunkStart)); + } + } + + private void parseLibraryTypeChunk(long chunkStart) throws IOException { + LOG.trace("parsing library type chunk starting at offset {}", chunkStart); + is.checkInt16(12, "Unexpected header size"); + int chunkSize = is.readInt32(); + long expectedEndPos = chunkStart + chunkSize; + int count = is.readInt32(); + for (int i = 0; i < count; i++) { + int packageId = is.readInt32(); + String packageName = is.readString16Fixed(128); + LOG.info("Found resource shared library {}, pkgId: {}", packageName, packageId); + if (is.getPos() > expectedEndPos) { + throw new IOException("reading after chunk end"); + } + } + if (is.getPos() != expectedEndPos) { + throw new IOException(String.format("Error reading library chunk at offset 0x%x", chunkStart)); + } } private void parseTypeChunk(long start, PackageChunk pkg) throws IOException { @@ -241,6 +278,13 @@ private void parseTypeChunk(long start, PackageChunk pkg) throws IOException { parseEntry(pkg, id, i, config.getQualifiers()); } } + if (chunkEnd > is.getPos()) { + // Skip remaining unknown data in this chunk (e.g. type 8 entries") + long skipSize = chunkEnd - is.getPos(); + LOG.debug("Unknown data at the end of type chunk encountered, skipping {} bytes and continuing at offset {}", skipSize, + chunkEnd); + is.skip(skipSize); + } } private void parseEntry(PackageChunk pkg, int typeId, int entryId, String config) throws IOException {