Commit 999793c9 authored by Skylot's avatar Skylot

fix: skip trailing bytes in resource table decoding (#487)

parent d111fd06
...@@ -138,6 +138,9 @@ public class ParserConstants { ...@@ -138,6 +138,9 @@ public class ParserConstants {
protected static final int FLAG_COMPLEX = 0x0001; protected static final int FLAG_COMPLEX = 0x0001;
// If set, this resource has been declared public, so libraries are allowed to reference it. // If set, this resource has been declared public, so libraries are allowed to reference it.
protected static final int FLAG_PUBLIC = 0x0002; 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 * ResTable_map
......
...@@ -2,7 +2,6 @@ package jadx.core.xmlgen; ...@@ -2,7 +2,6 @@ package jadx.core.xmlgen;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
...@@ -216,8 +215,7 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -216,8 +215,7 @@ public class ResTableParser extends CommonBinaryParser {
} }
private void parseEntry(PackageChunk pkg, int typeId, int entryId, EntryConfig config) throws IOException { private void parseEntry(PackageChunk pkg, int typeId, int entryId, EntryConfig config) throws IOException {
/* int size = */ int size = is.readInt16();
is.readInt16();
int flags = is.readInt16(); int flags = is.readInt16();
int key = is.readInt32(); int key = is.readInt32();
...@@ -227,17 +225,17 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -227,17 +225,17 @@ public class ResTableParser extends CommonBinaryParser {
ResourceEntry ri = new ResourceEntry(resRef, pkg.getName(), typeName, keyName); ResourceEntry ri = new ResourceEntry(resRef, pkg.getName(), typeName, keyName);
ri.setConfig(config); ri.setConfig(config);
if ((flags & FLAG_COMPLEX) == 0) { if ((flags & FLAG_COMPLEX) != 0 || size == 16) {
ri.setSimpleValue(parseValue());
} else {
int parentRef = is.readInt32(); int parentRef = is.readInt32();
ri.setParentRef(parentRef);
int count = is.readInt32(); int count = is.readInt32();
ri.setParentRef(parentRef);
List<RawNamedValue> values = new ArrayList<>(count); List<RawNamedValue> values = new ArrayList<>(count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
values.add(parseValueMap()); values.add(parseValueMap());
} }
ri.setNamedValues(values); ri.setNamedValues(values);
} else {
ri.setSimpleValue(parseValue());
} }
resStorage.add(ri); resStorage.add(ri);
} }
...@@ -256,9 +254,8 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -256,9 +254,8 @@ public class ResTableParser extends CommonBinaryParser {
} }
private EntryConfig parseConfig() throws IOException { private EntryConfig parseConfig() throws IOException {
long start = is.getPos();
int size = is.readInt32(); int size = is.readInt32();
int read = 28;
if (size < 28) { if (size < 28) {
throw new IOException("Config size < 28"); throw new IOException("Config size < 28");
} }
...@@ -273,19 +270,18 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -273,19 +270,18 @@ public class ResTableParser extends CommonBinaryParser {
byte orientation = (byte) is.readInt8(); byte orientation = (byte) is.readInt8();
byte touchscreen = (byte) is.readInt8(); byte touchscreen = (byte) is.readInt8();
int density = is.readInt16(); int density = is.readInt16();
byte keyboard = (byte) is.readInt8(); byte keyboard = (byte) is.readInt8();
byte navigation = (byte) is.readInt8(); byte navigation = (byte) is.readInt8();
byte inputFlags = (byte) is.readInt8(); byte inputFlags = (byte) is.readInt8();
/* inputPad0 */is.readInt8(); is.readInt8(); // inputPad0
short screenWidth = (short) is.readInt16(); short screenWidth = (short) is.readInt16();
short screenHeight = (short) is.readInt16(); short screenHeight = (short) is.readInt16();
short sdkVersion = (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 screenLayout = 0;
byte uiMode = 0; byte uiMode = 0;
...@@ -294,7 +290,6 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -294,7 +290,6 @@ public class ResTableParser extends CommonBinaryParser {
screenLayout = (byte) is.readInt8(); screenLayout = (byte) is.readInt8();
uiMode = (byte) is.readInt8(); uiMode = (byte) is.readInt8();
smallestScreenWidthDp = (short) is.readInt16(); smallestScreenWidthDp = (short) is.readInt16();
read = 32;
} }
short screenWidthDp = 0; short screenWidthDp = 0;
...@@ -302,7 +297,6 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -302,7 +297,6 @@ public class ResTableParser extends CommonBinaryParser {
if (size >= 36) { if (size >= 36) {
screenWidthDp = (short) is.readInt16(); screenWidthDp = (short) is.readInt16();
screenHeightDp = (short) is.readInt16(); screenHeightDp = (short) is.readInt16();
read = 36;
} }
char[] localeScript = null; char[] localeScript = null;
...@@ -310,7 +304,6 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -310,7 +304,6 @@ public class ResTableParser extends CommonBinaryParser {
if (size >= 48) { if (size >= 48) {
localeScript = readScriptOrVariantChar(4).toCharArray(); localeScript = readScriptOrVariantChar(4).toCharArray();
localeVariant = readScriptOrVariantChar(8).toCharArray(); localeVariant = readScriptOrVariantChar(8).toCharArray();
read = 48;
} }
byte screenLayout2 = 0; byte screenLayout2 = 0;
...@@ -319,36 +312,9 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -319,36 +312,9 @@ public class ResTableParser extends CommonBinaryParser {
screenLayout2 = (byte) is.readInt8(); screenLayout2 = (byte) is.readInt8();
colorMode = (byte) is.readInt8(); colorMode = (byte) is.readInt8();
is.readInt16(); // reserved padding is.readInt16(); // reserved padding
read = 52;
}
if (size >= 56) {
is.readInt32();
read = 56;
} }
int exceedingSize = size - KNOWN_CONFIG_BYTES; is.skipToPos(start + size, "Config skip trailing 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);
}
return new EntryConfig(mcc, mnc, language, country, return new EntryConfig(mcc, mnc, language, country,
orientation, touchscreen, density, keyboard, navigation, orientation, touchscreen, density, keyboard, navigation,
...@@ -358,7 +324,7 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -358,7 +324,7 @@ public class ResTableParser extends CommonBinaryParser {
colorMode, isInvalid, size); 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 // check high bit, if so we have a packed 3 letter code
if (((in0 >> 7) & 1) == 1) { if (((in0 >> 7) & 1) == 1) {
int first = in1 & 0x1F; int first = in1 & 0x1F;
...@@ -367,23 +333,22 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -367,23 +333,22 @@ public class ResTableParser extends CommonBinaryParser {
// since this function handles languages & regions, we add the value(s) to the base char // 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. // 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 { private String readScriptOrVariantChar(int length) throws IOException {
StringBuilder string = new StringBuilder(16); long start = is.getPos();
StringBuilder sb = new StringBuilder(16);
while(length-- != 0) { for (int i = 0; i < length; i++) {
short ch = (short) is.readInt8(); short ch = (short) is.readInt8();
if (ch == 0) { if (ch == 0) {
break; break;
} }
string.append((char) ch); sb.append((char) ch);
} }
is.skip(length); is.skipToPos(start + length, "readScriptOrVariantChar");
return sb.toString();
return string.toString();
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment