Commit 84edfac8 authored by Skylot's avatar Skylot

resources: improve string pool decoding and errors reporting

parent 69252ce7
...@@ -2,6 +2,7 @@ package jadx.api; ...@@ -2,6 +2,7 @@ package jadx.api;
import jadx.api.ResourceFile.ZipRef; import jadx.api.ResourceFile.ZipRef;
import jadx.core.codegen.CodeWriter; import jadx.core.codegen.CodeWriter;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.InputFile; import jadx.core.utils.files.InputFile;
import jadx.core.xmlgen.ResTableParser; import jadx.core.xmlgen.ResTableParser;
...@@ -61,7 +62,7 @@ public final class ResourcesLoader { ...@@ -61,7 +62,7 @@ public final class ResourcesLoader {
inputStream = new BufferedInputStream(zipFile.getInputStream(entry)); inputStream = new BufferedInputStream(zipFile.getInputStream(entry));
return decoder.decode(entry.getSize(), inputStream); return decoder.decode(entry.getSize(), inputStream);
} catch (Exception e) { } catch (Exception e) {
throw new JadxException("Error load: " + zipRef, e); throw new JadxException("Error decode: " + zipRef.getEntryName(), e);
} finally { } finally {
try { try {
if (zipFile != null) { if (zipFile != null) {
...@@ -90,8 +91,11 @@ public final class ResourcesLoader { ...@@ -90,8 +91,11 @@ public final class ResourcesLoader {
}); });
} catch (JadxException e) { } catch (JadxException e) {
LOG.error("Decode error", 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, private static CodeWriter loadContent(JadxDecompiler jadxRef, ResourceType type,
......
...@@ -5,7 +5,6 @@ import jadx.core.dex.instructions.args.ArgType; ...@@ -5,7 +5,6 @@ import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.DexNode; import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
import jadx.core.xmlgen.entry.ValuesParser; import jadx.core.xmlgen.entry.ValuesParser;
...@@ -75,20 +74,12 @@ public class BinaryXMLParser extends CommonBinaryParser { ...@@ -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 = new CodeWriter();
writer.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); writer.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
is = new ParserStream(inputStream); is = new ParserStream(inputStream);
firstElement = true; firstElement = true;
try {
decode(); 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;
}
writer.finish(); writer.finish();
return writer; return writer;
} }
......
package jadx.core.xmlgen; package jadx.core.xmlgen;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
public class CommonBinaryParser extends ParserConstants { public class CommonBinaryParser extends ParserConstants {
protected ParserStream is; protected ParserStream is;
protected String[] parseStringPool() throws IOException { protected String[] parseStringPool() throws IOException {
...@@ -29,16 +29,14 @@ public class CommonBinaryParser extends ParserConstants { ...@@ -29,16 +29,14 @@ public class CommonBinaryParser extends ParserConstants {
is.checkPos(start + stringsStart, "Expected strings start"); is.checkPos(start + stringsStart, "Expected strings start");
long stringsEnd = stylesStart == 0 ? chunkEnd : start + stylesStart; long stringsEnd = stylesStart == 0 ? chunkEnd : start + stylesStart;
String[] strings = new String[stringCount]; String[] strings = new String[stringCount];
byte[] strArray = is.readInt8Array((int) (stringsEnd - is.getPos()));
if ((flags & UTF8_FLAG) != 0) { if ((flags & UTF8_FLAG) != 0) {
// UTF-8 // UTF-8
for (int i = 0; i < stringCount; i++) { for (int i = 0; i < stringCount; i++) {
// is.checkPos(start + stringsStart + stringsOffset[i], "Expected string start"); strings[i] = extractString8(strArray, stringsOffset[i]);
strings[i] = is.readString8();
} }
is.skipToPos(stringsEnd, "Skip string8 padding");
} else { } else {
// UTF-16 // UTF-16
byte[] strArray = is.readInt8Array((int) (stringsEnd - is.getPos()));
for (int i = 0; i < stringCount; i++) { for (int i = 0; i < stringCount; i++) {
// don't trust specified string length, read until \0 // don't trust specified string length, read until \0
// stringsOffset can be same for different indexes // stringsOffset can be same for different indexes
...@@ -56,9 +54,22 @@ public class CommonBinaryParser extends ParserConstants { ...@@ -56,9 +54,22 @@ public class CommonBinaryParser extends ParserConstants {
return strings; 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) { private static String extractString16(byte[] strArray, int offset) {
int len = strArray.length; int len = strArray.length;
int start = offset + 2; int start = offset + skipStrLen16(strArray, offset);
int end = start; int end = start;
while (true) { while (true) {
if (end + 1 >= len) { if (end + 1 >= len) {
...@@ -69,7 +80,16 @@ public class CommonBinaryParser extends ParserConstants { ...@@ -69,7 +80,16 @@ public class CommonBinaryParser extends ParserConstants {
} }
end += 2; 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 { protected void die(String message) throws IOException {
......
...@@ -9,6 +9,9 @@ public class ParserStream { ...@@ -9,6 +9,9 @@ public class ParserStream {
protected static final Charset STRING_CHARSET_UTF16 = Charset.forName("UTF-16LE"); protected static final Charset STRING_CHARSET_UTF16 = Charset.forName("UTF-16LE");
protected static final Charset STRING_CHARSET_UTF8 = Charset.forName("UTF-8"); 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 final InputStream input;
private long readPos = 0; private long readPos = 0;
...@@ -46,34 +49,14 @@ public class ParserStream { ...@@ -46,34 +49,14 @@ public class ParserStream {
return readInt32() & 0xFFFFFFFFL; 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 { public String readString16Fixed(int len) throws IOException {
String str = new String(readInt8Array(len * 2), STRING_CHARSET_UTF16); String str = new String(readInt8Array(len * 2), STRING_CHARSET_UTF16);
return str.trim(); 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 { public int[] readInt32Array(int count) throws IOException {
if (count == 0) { if (count == 0) {
return new int[0]; return EMPTY_INT_ARRAY;
} }
int[] arr = new int[count]; int[] arr = new int[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
...@@ -84,7 +67,7 @@ public class ParserStream { ...@@ -84,7 +67,7 @@ public class ParserStream {
public byte[] readInt8Array(int count) throws IOException { public byte[] readInt8Array(int count) throws IOException {
if (count == 0) { if (count == 0) {
return new byte[0]; return EMPTY_BYTE_ARRAY;
} }
readPos += count; readPos += count;
byte[] arr = new byte[count]; byte[] arr = new byte[count];
...@@ -147,22 +130,6 @@ public class ParserStream { ...@@ -147,22 +130,6 @@ public class ParserStream {
checkPos(expectedOffset, error); 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 @Override
public String toString() { public String toString() {
return "pos: 0x" + Long.toHexString(readPos); return "pos: 0x" + Long.toHexString(readPos);
......
package jadx.core.xmlgen; package jadx.core.xmlgen;
import jadx.core.codegen.CodeWriter; import jadx.core.codegen.CodeWriter;
import jadx.core.utils.Utils;
import jadx.core.xmlgen.entry.EntryConfig; import jadx.core.xmlgen.entry.EntryConfig;
import jadx.core.xmlgen.entry.RawNamedValue; import jadx.core.xmlgen.entry.RawNamedValue;
import jadx.core.xmlgen.entry.RawValue; import jadx.core.xmlgen.entry.RawValue;
...@@ -59,16 +58,8 @@ public class ResTableParser extends CommonBinaryParser { ...@@ -59,16 +58,8 @@ public class ResTableParser extends CommonBinaryParser {
resStorage.finish(); resStorage.finish();
} }
public CodeWriter decodeToCodeWriter(InputStream inputStream) { public CodeWriter decodeToCodeWriter(InputStream inputStream) throws IOException {
try {
decode(inputStream); 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;
}
CodeWriter writer = new CodeWriter(); CodeWriter writer = new CodeWriter();
writer.add("app package: ").add(resStorage.getAppPackage()); writer.add("app package: ").add(resStorage.getAppPackage());
......
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