From 999793c944bab24b6b68ad2c2dd2084ba8705ac6 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 23 Mar 2019 12:58:45 +0300 Subject: [PATCH] fix: skip trailing bytes in resource table decoding (#487) --- .../jadx/core/xmlgen/ParserConstants.java | 3 + .../java/jadx/core/xmlgen/ResTableParser.java | 71 +++++-------------- 2 files changed, 21 insertions(+), 53 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 9497867cb..6f60fb7bb 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java @@ -138,6 +138,9 @@ public class ParserConstants { protected static final int FLAG_COMPLEX = 0x0001; // If set, this resource has been declared public, so libraries are allowed to reference it. protected static final int FLAG_PUBLIC = 0x0002; + // If set, this is a weak resource and may be overriden by strong resources of the same name/type. + // This is only useful during linking with other resource tables. + protected static final int FLAG_WEAK = 0x0004; /** * ResTable_map 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 8c109c2ca..6fb0c9352 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -2,7 +2,6 @@ package jadx.core.xmlgen; import java.io.IOException; import java.io.InputStream; -import java.math.BigInteger; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -216,8 +215,7 @@ public class ResTableParser extends CommonBinaryParser { } private void parseEntry(PackageChunk pkg, int typeId, int entryId, EntryConfig config) throws IOException { - /* int size = */ - is.readInt16(); + int size = is.readInt16(); int flags = is.readInt16(); int key = is.readInt32(); @@ -227,17 +225,17 @@ public class ResTableParser extends CommonBinaryParser { ResourceEntry ri = new ResourceEntry(resRef, pkg.getName(), typeName, keyName); ri.setConfig(config); - if ((flags & FLAG_COMPLEX) == 0) { - ri.setSimpleValue(parseValue()); - } else { + if ((flags & FLAG_COMPLEX) != 0 || size == 16) { int parentRef = is.readInt32(); - ri.setParentRef(parentRef); int count = is.readInt32(); + ri.setParentRef(parentRef); List values = new ArrayList<>(count); for (int i = 0; i < count; i++) { values.add(parseValueMap()); } ri.setNamedValues(values); + } else { + ri.setSimpleValue(parseValue()); } resStorage.add(ri); } @@ -256,9 +254,8 @@ public class ResTableParser extends CommonBinaryParser { } private EntryConfig parseConfig() throws IOException { + long start = is.getPos(); int size = is.readInt32(); - int read = 28; - if (size < 28) { throw new IOException("Config size < 28"); } @@ -273,19 +270,18 @@ public class ResTableParser extends CommonBinaryParser { byte orientation = (byte) is.readInt8(); byte touchscreen = (byte) is.readInt8(); - int density = is.readInt16(); byte keyboard = (byte) is.readInt8(); byte navigation = (byte) is.readInt8(); byte inputFlags = (byte) is.readInt8(); - /* inputPad0 */is.readInt8(); + is.readInt8(); // inputPad0 short screenWidth = (short) is.readInt16(); short screenHeight = (short) is.readInt16(); short sdkVersion = (short) is.readInt16(); - /* minorVersion, now must always be 0 */is.readInt16(); + is.readInt16(); // minorVersion must always be 0 byte screenLayout = 0; byte uiMode = 0; @@ -294,7 +290,6 @@ public class ResTableParser extends CommonBinaryParser { screenLayout = (byte) is.readInt8(); uiMode = (byte) is.readInt8(); smallestScreenWidthDp = (short) is.readInt16(); - read = 32; } short screenWidthDp = 0; @@ -302,7 +297,6 @@ public class ResTableParser extends CommonBinaryParser { if (size >= 36) { screenWidthDp = (short) is.readInt16(); screenHeightDp = (short) is.readInt16(); - read = 36; } char[] localeScript = null; @@ -310,7 +304,6 @@ public class ResTableParser extends CommonBinaryParser { if (size >= 48) { localeScript = readScriptOrVariantChar(4).toCharArray(); localeVariant = readScriptOrVariantChar(8).toCharArray(); - read = 48; } byte screenLayout2 = 0; @@ -319,36 +312,9 @@ public class ResTableParser extends CommonBinaryParser { screenLayout2 = (byte) is.readInt8(); colorMode = (byte) is.readInt8(); is.readInt16(); // reserved padding - read = 52; } - if (size >= 56) { - is.readInt32(); - read = 56; - } - - int exceedingSize = size - KNOWN_CONFIG_BYTES; - if (exceedingSize > 0) { - byte[] buf = new byte[exceedingSize]; - read += exceedingSize; - is.readFully(buf); - BigInteger exceedingBI = new BigInteger(1, buf); - - if (exceedingBI.equals(BigInteger.ZERO)) { - LOG.info(String - .format("Config flags size > %d, but exceeding bytes are all zero, so it should be ok.", - KNOWN_CONFIG_BYTES)); - } else { - LOG.warn(String.format("Config flags size > %d. Size = %d. Exceeding bytes: 0x%X.", - KNOWN_CONFIG_BYTES, size, exceedingBI)); - isInvalid = true; - } - } - - int remainingSize = size - read; - if (remainingSize > 0) { - is.skip(remainingSize); - } + is.skipToPos(start + size, "Config skip trailing bytes"); return new EntryConfig(mcc, mnc, language, country, orientation, touchscreen, density, keyboard, navigation, @@ -358,7 +324,7 @@ public class ResTableParser extends CommonBinaryParser { colorMode, isInvalid, size); } - private char[] unpackLocaleOrRegion(byte in0, byte in1, char base) throws IOException { + private char[] unpackLocaleOrRegion(byte in0, byte in1, char base) { // check high bit, if so we have a packed 3 letter code if (((in0 >> 7) & 1) == 1) { int first = in1 & 0x1F; @@ -367,23 +333,22 @@ public class ResTableParser extends CommonBinaryParser { // since this function handles languages & regions, we add the value(s) to the base char // which is usually 'a' or '0' depending on language or region. - return new char[] { (char) (first + base), (char) (second + base), (char) (third + base) }; + return new char[]{(char) (first + base), (char) (second + base), (char) (third + base)}; } - return new char[] { (char) in0, (char) in1 }; + return new char[]{(char) in0, (char) in1}; } private String readScriptOrVariantChar(int length) throws IOException { - StringBuilder string = new StringBuilder(16); - - while(length-- != 0) { + long start = is.getPos(); + StringBuilder sb = new StringBuilder(16); + for (int i = 0; i < length; i++) { short ch = (short) is.readInt8(); if (ch == 0) { break; } - string.append((char) ch); + sb.append((char) ch); } - is.skip(length); - - return string.toString(); + is.skipToPos(start + length, "readScriptOrVariantChar"); + return sb.toString(); } }