resources: improve string pool decoding and errors reporting
This commit is contained in:
@@ -2,6 +2,7 @@ package jadx.api;
|
||||
|
||||
import jadx.api.ResourceFile.ZipRef;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
import jadx.core.utils.files.InputFile;
|
||||
import jadx.core.xmlgen.ResTableParser;
|
||||
@@ -61,7 +62,7 @@ public final class ResourcesLoader {
|
||||
inputStream = new BufferedInputStream(zipFile.getInputStream(entry));
|
||||
return decoder.decode(entry.getSize(), inputStream);
|
||||
} catch (Exception e) {
|
||||
throw new JadxException("Error load: " + zipRef, e);
|
||||
throw new JadxException("Error decode: " + zipRef.getEntryName(), e);
|
||||
} finally {
|
||||
try {
|
||||
if (zipFile != null) {
|
||||
@@ -90,8 +91,11 @@ public final class ResourcesLoader {
|
||||
});
|
||||
} catch (JadxException e) {
|
||||
LOG.error("Decode error", e);
|
||||
CodeWriter cw = new CodeWriter();
|
||||
cw.add("Error decode ").add(rf.getType().toString().toLowerCase());
|
||||
cw.startLine(Utils.getStackTrace(e.getCause()));
|
||||
return cw;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static CodeWriter loadContent(JadxDecompiler jadxRef, ResourceType type,
|
||||
|
||||
@@ -5,7 +5,6 @@ import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.core.xmlgen.entry.ValuesParser;
|
||||
|
||||
@@ -75,20 +74,12 @@ public class BinaryXMLParser extends CommonBinaryParser {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized CodeWriter parse(InputStream inputStream) {
|
||||
public synchronized CodeWriter parse(InputStream inputStream) throws IOException {
|
||||
writer = new CodeWriter();
|
||||
writer.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
is = new ParserStream(inputStream);
|
||||
firstElement = true;
|
||||
try {
|
||||
decode();
|
||||
} catch (IOException e) {
|
||||
LOG.debug("Binary xml decode failed", e);
|
||||
CodeWriter cw = new CodeWriter();
|
||||
cw.add("Error decode binary xml");
|
||||
cw.startLine(Utils.getStackTrace(e));
|
||||
return cw;
|
||||
}
|
||||
decode();
|
||||
writer.finish();
|
||||
return writer;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package jadx.core.xmlgen;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class CommonBinaryParser extends ParserConstants {
|
||||
|
||||
protected ParserStream is;
|
||||
|
||||
protected String[] parseStringPool() throws IOException {
|
||||
@@ -29,16 +29,14 @@ public class CommonBinaryParser extends ParserConstants {
|
||||
is.checkPos(start + stringsStart, "Expected strings start");
|
||||
long stringsEnd = stylesStart == 0 ? chunkEnd : start + stylesStart;
|
||||
String[] strings = new String[stringCount];
|
||||
byte[] strArray = is.readInt8Array((int) (stringsEnd - is.getPos()));
|
||||
if ((flags & UTF8_FLAG) != 0) {
|
||||
// UTF-8
|
||||
for (int i = 0; i < stringCount; i++) {
|
||||
// is.checkPos(start + stringsStart + stringsOffset[i], "Expected string start");
|
||||
strings[i] = is.readString8();
|
||||
strings[i] = extractString8(strArray, stringsOffset[i]);
|
||||
}
|
||||
is.skipToPos(stringsEnd, "Skip string8 padding");
|
||||
} else {
|
||||
// UTF-16
|
||||
byte[] strArray = is.readInt8Array((int) (stringsEnd - is.getPos()));
|
||||
for (int i = 0; i < stringCount; i++) {
|
||||
// don't trust specified string length, read until \0
|
||||
// stringsOffset can be same for different indexes
|
||||
@@ -56,9 +54,22 @@ public class CommonBinaryParser extends ParserConstants {
|
||||
return strings;
|
||||
}
|
||||
|
||||
private static String extractString8(byte[] strArray, int offset) {
|
||||
int start = offset + skipStrLen8(strArray, offset);
|
||||
int len = strArray[start++];
|
||||
if (len == 0) {
|
||||
return "";
|
||||
}
|
||||
if ((len & 0x80) != 0) {
|
||||
len = ((len & 0x7F) << 8) | (strArray[start++] & 0xFF);
|
||||
}
|
||||
byte[] arr = Arrays.copyOfRange(strArray, start, start + len);
|
||||
return new String(arr, ParserStream.STRING_CHARSET_UTF8);
|
||||
}
|
||||
|
||||
private static String extractString16(byte[] strArray, int offset) {
|
||||
int len = strArray.length;
|
||||
int start = offset + 2;
|
||||
int start = offset + skipStrLen16(strArray, offset);
|
||||
int end = start;
|
||||
while (true) {
|
||||
if (end + 1 >= len) {
|
||||
@@ -69,7 +80,16 @@ public class CommonBinaryParser extends ParserConstants {
|
||||
}
|
||||
end += 2;
|
||||
}
|
||||
return new String(strArray, start, end - start, ParserStream.STRING_CHARSET_UTF16);
|
||||
byte[] arr = Arrays.copyOfRange(strArray, start, end);
|
||||
return new String(arr, ParserStream.STRING_CHARSET_UTF16);
|
||||
}
|
||||
|
||||
private static int skipStrLen8(byte[] strArray, int offset) {
|
||||
return (strArray[offset] & 0x80) == 0 ? 1 : 2;
|
||||
}
|
||||
|
||||
private static int skipStrLen16(byte[] strArray, int offset) {
|
||||
return (strArray[offset + 1] & 0x80) == 0 ? 2 : 4;
|
||||
}
|
||||
|
||||
protected void die(String message) throws IOException {
|
||||
|
||||
@@ -9,6 +9,9 @@ public class ParserStream {
|
||||
protected static final Charset STRING_CHARSET_UTF16 = Charset.forName("UTF-16LE");
|
||||
protected static final Charset STRING_CHARSET_UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
private static final int[] EMPTY_INT_ARRAY = new int[0];
|
||||
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||
|
||||
private final InputStream input;
|
||||
private long readPos = 0;
|
||||
|
||||
@@ -46,34 +49,14 @@ public class ParserStream {
|
||||
return readInt32() & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
public String readString8Fixed(int len) throws IOException {
|
||||
String str = new String(readInt8Array(len), STRING_CHARSET_UTF8);
|
||||
return str.trim();
|
||||
}
|
||||
|
||||
public String readString16Fixed(int len) throws IOException {
|
||||
String str = new String(readInt8Array(len * 2), STRING_CHARSET_UTF16);
|
||||
return str.trim();
|
||||
}
|
||||
|
||||
public String readString8() throws IOException {
|
||||
decodeLength8();
|
||||
int len = decodeLength8();
|
||||
String str = new String(readInt8Array(len), STRING_CHARSET_UTF8);
|
||||
checkInt8(0, "Not a trailing zero at string8 end");
|
||||
return str;
|
||||
}
|
||||
|
||||
public String readString16() throws IOException {
|
||||
int len = decodeLength16();
|
||||
String str = new String(readInt8Array(len), STRING_CHARSET_UTF16);
|
||||
checkInt16(0, "Not a trailing zero at string16 end");
|
||||
return str;
|
||||
}
|
||||
|
||||
public int[] readInt32Array(int count) throws IOException {
|
||||
if (count == 0) {
|
||||
return new int[0];
|
||||
return EMPTY_INT_ARRAY;
|
||||
}
|
||||
int[] arr = new int[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
@@ -84,7 +67,7 @@ public class ParserStream {
|
||||
|
||||
public byte[] readInt8Array(int count) throws IOException {
|
||||
if (count == 0) {
|
||||
return new byte[0];
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
readPos += count;
|
||||
byte[] arr = new byte[count];
|
||||
@@ -147,22 +130,6 @@ public class ParserStream {
|
||||
checkPos(expectedOffset, error);
|
||||
}
|
||||
|
||||
public int decodeLength8() throws IOException {
|
||||
int len = readInt8();
|
||||
if ((len & 0x80) != 0) {
|
||||
len = ((len & 0x7F) << 8) | readInt8();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
public int decodeLength16() throws IOException {
|
||||
int len = readInt16();
|
||||
if ((len & 0x8000) != 0) {
|
||||
len = ((len & 0x7FFF) << 16) | readInt16();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "pos: 0x" + Long.toHexString(readPos);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jadx.core.xmlgen;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.xmlgen.entry.EntryConfig;
|
||||
import jadx.core.xmlgen.entry.RawNamedValue;
|
||||
import jadx.core.xmlgen.entry.RawValue;
|
||||
@@ -59,16 +58,8 @@ public class ResTableParser extends CommonBinaryParser {
|
||||
resStorage.finish();
|
||||
}
|
||||
|
||||
public CodeWriter decodeToCodeWriter(InputStream inputStream) {
|
||||
try {
|
||||
decode(inputStream);
|
||||
} catch (IOException e) {
|
||||
LOG.debug("arsc decode failed", e);
|
||||
CodeWriter cw = new CodeWriter();
|
||||
cw.add("Error decode arsc");
|
||||
cw.startLine(Utils.getStackTrace(e));
|
||||
return cw;
|
||||
}
|
||||
public CodeWriter decodeToCodeWriter(InputStream inputStream) throws IOException {
|
||||
decode(inputStream);
|
||||
|
||||
CodeWriter writer = new CodeWriter();
|
||||
writer.add("app package: ").add(resStorage.getAppPackage());
|
||||
|
||||
Reference in New Issue
Block a user