From ef8a685621814ad9c3ee91c0d96f22cc5f2383ac Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 9 Oct 2015 21:41:38 +0300 Subject: [PATCH] resources: initial version of .arsc file decode --- jadx-core/clsp-data/android-5.1.jar | Bin 120237 -> 194116 bytes .../main/java/jadx/api/JadxDecompiler.java | 19 +-- .../src/main/java/jadx/api/ResourceFile.java | 4 +- .../java/jadx/api/ResourceFileContent.java | 19 +++ .../src/main/java/jadx/api/ResourceType.java | 2 +- .../main/java/jadx/api/ResourcesLoader.java | 33 ++--- .../java/jadx/core/dex/nodes/RootNode.java | 3 +- .../java/jadx/core/utils/StringUtils.java | 57 ++++---- .../jadx/core/xmlgen/BinaryXMLParser.java | 39 +++--- .../jadx/core/xmlgen/ManifestAttributes.java | 43 +++--- .../jadx/core/xmlgen/ParserConstants.java | 15 +++ .../java/jadx/core/xmlgen/ResContainer.java | 68 ++++++++++ .../java/jadx/core/xmlgen/ResTableParser.java | 12 +- .../main/java/jadx/core/xmlgen/ResXmlGen.java | 127 ++++++++++++++++++ .../java/jadx/core/xmlgen/ResourcesSaver.java | 46 +++++++ .../jadx/core/xmlgen/entry/EntryConfig.java | 10 +- .../jadx/core/xmlgen/entry/RawNamedValue.java | 5 + .../java/jadx/gui/treemodel/JResource.java | 74 +++++++++- 18 files changed, 480 insertions(+), 96 deletions(-) create mode 100644 jadx-core/src/main/java/jadx/api/ResourceFileContent.java create mode 100644 jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java create mode 100644 jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java create mode 100644 jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java diff --git a/jadx-core/clsp-data/android-5.1.jar b/jadx-core/clsp-data/android-5.1.jar index 8e171f7675fe4f9b6336d0aa9d10a09d30a515fb..68b8a5541218a403a10aa67af5b550248a5dfd5a 100644 GIT binary patch delta 74492 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�LWp2)X>wAI3=4wcQYknxGfcZ3)z0plKS;qtvhG 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 -v5g*4_C!k*xm7e=yLFG44KiB;pz3O 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 G0001^4{Hqo delta 37 scmX@|hI{R5_J%EtGp=mE@r8+zak{}bCN@5124)6EMh1pySAYZq03p8%i2wiq diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index 6a404b601..b78aa9cdc 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -3,7 +3,6 @@ package jadx.api; import jadx.core.Jadx; import jadx.core.ProcessClass; import jadx.core.codegen.CodeGen; -import jadx.core.codegen.CodeWriter; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.MethodNode; @@ -15,6 +14,7 @@ import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.InputFile; import jadx.core.xmlgen.BinaryXMLParser; +import jadx.core.xmlgen.ResourcesSaver; import java.io.File; import java.io.IOException; @@ -150,7 +150,7 @@ public final class JadxDecompiler { return getSaveExecutor(!args.isSkipSources(), !args.isSkipResources()); } - private ExecutorService getSaveExecutor(boolean saveSources, boolean saveResources) { + private ExecutorService getSaveExecutor(boolean saveSources, final boolean saveResources) { if (root == null) { throw new JadxRuntimeException("No loaded files"); } @@ -172,17 +172,7 @@ public final class JadxDecompiler { } if (saveResources) { for (final ResourceFile resourceFile : getResources()) { - executor.execute(new Runnable() { - @Override - public void run() { - if (ResourceType.isSupportedForUnpack(resourceFile.getType())) { - CodeWriter cw = resourceFile.getContent(); - if (cw != null) { - cw.save(new File(outDir, resourceFile.getName())); - } - } - } - }); + executor.execute(new ResourcesSaver(outDir, resourceFile)); } } return executor; @@ -294,7 +284,7 @@ public final class JadxDecompiler { return root; } - BinaryXMLParser getXmlParser() { + synchronized BinaryXMLParser getXmlParser() { if (xmlParser == null) { xmlParser = new BinaryXMLParser(root); } @@ -321,4 +311,5 @@ public final class JadxDecompiler { public String toString() { return "jadx decompiler " + getVersion(); } + } diff --git a/jadx-core/src/main/java/jadx/api/ResourceFile.java b/jadx-core/src/main/java/jadx/api/ResourceFile.java index cb661fc48..6e739ff17 100644 --- a/jadx-core/src/main/java/jadx/api/ResourceFile.java +++ b/jadx-core/src/main/java/jadx/api/ResourceFile.java @@ -1,6 +1,6 @@ package jadx.api; -import jadx.core.codegen.CodeWriter; +import jadx.core.xmlgen.ResContainer; import java.io.File; @@ -48,7 +48,7 @@ public class ResourceFile { return type; } - public CodeWriter getContent() { + public ResContainer getContent() { return ResourcesLoader.loadContent(decompiler, this); } diff --git a/jadx-core/src/main/java/jadx/api/ResourceFileContent.java b/jadx-core/src/main/java/jadx/api/ResourceFileContent.java new file mode 100644 index 000000000..8525ec46d --- /dev/null +++ b/jadx-core/src/main/java/jadx/api/ResourceFileContent.java @@ -0,0 +1,19 @@ +package jadx.api; + +import jadx.core.codegen.CodeWriter; +import jadx.core.xmlgen.ResContainer; + +public class ResourceFileContent extends ResourceFile { + + private final CodeWriter content; + + public ResourceFileContent(String name, ResourceType type, CodeWriter content) { + super(null, name, type); + this.content = content; + } + + @Override + public ResContainer getContent() { + return ResContainer.singleFile(getName(), content); + } +} diff --git a/jadx-core/src/main/java/jadx/api/ResourceType.java b/jadx-core/src/main/java/jadx/api/ResourceType.java index dae2805b6..3399f8ca6 100644 --- a/jadx-core/src/main/java/jadx/api/ResourceType.java +++ b/jadx-core/src/main/java/jadx/api/ResourceType.java @@ -34,7 +34,6 @@ public enum ResourceType { public static boolean isSupportedForUnpack(ResourceType type) { switch (type) { case CODE: - case ARSC: case LIB: case FONT: case IMG: @@ -43,6 +42,7 @@ public enum ResourceType { case MANIFEST: case XML: + case ARSC: return true; } return false; diff --git a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java index 8a9dae101..eda08ec82 100644 --- a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java +++ b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java @@ -5,6 +5,7 @@ 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.ResContainer; import jadx.core.xmlgen.ResTableParser; import java.io.BufferedInputStream; @@ -43,17 +44,17 @@ public final class ResourcesLoader { } public interface ResourceDecoder { - Object decode(long size, InputStream is) throws IOException; + ResContainer decode(long size, InputStream is) throws IOException; } - public static Object decodeStream(ResourceFile rf, ResourceDecoder decoder) throws JadxException { + public static ResContainer decodeStream(ResourceFile rf, ResourceDecoder decoder) throws JadxException { ZipRef zipRef = rf.getZipRef(); if (zipRef == null) { return null; } ZipFile zipFile = null; InputStream inputStream = null; - Object result = null; + ResContainer result = null; try { zipFile = new ZipFile(zipRef.getZipFile()); ZipEntry entry = zipFile.getEntry(zipRef.getEntryName()); @@ -79,16 +80,17 @@ public final class ResourcesLoader { return result; } - static CodeWriter loadContent(final JadxDecompiler jadxRef, final ResourceFile rf) { + static ResContainer loadContent(final JadxDecompiler jadxRef, final ResourceFile rf) { try { - return (CodeWriter) decodeStream(rf, new ResourceDecoder() { + return decodeStream(rf, new ResourceDecoder() { @Override - public Object decode(long size, InputStream is) throws IOException { + public ResContainer decode(long size, InputStream is) throws IOException { if (size > LOAD_SIZE_LIMIT) { - return new CodeWriter().add("File too big, size: " - + String.format("%.2f KB", size / 1024.)); + return ResContainer.singleFile(rf.getName(), + new CodeWriter().add("File too big, size: " + + String.format("%.2f KB", size / 1024.))); } - return loadContent(jadxRef, rf.getType(), is); + return loadContent(jadxRef, rf, is); } }); } catch (JadxException e) { @@ -96,21 +98,22 @@ public final class ResourcesLoader { CodeWriter cw = new CodeWriter(); cw.add("Error decode ").add(rf.getType().toString().toLowerCase()); cw.startLine(Utils.getStackTrace(e.getCause())); - return cw; + return ResContainer.singleFile(rf.getName(), cw); } } - private static CodeWriter loadContent(JadxDecompiler jadxRef, ResourceType type, + private static ResContainer loadContent(JadxDecompiler jadxRef, ResourceFile rf, InputStream inputStream) throws IOException { - switch (type) { + switch (rf.getType()) { case MANIFEST: case XML: - return jadxRef.getXmlParser().parse(inputStream); + return ResContainer.singleFile(rf.getName(), + jadxRef.getXmlParser().parse(inputStream)); case ARSC: - return new ResTableParser().decodeToCodeWriter(inputStream); + return new ResTableParser().decodeFiles(inputStream); } - return loadToCodeWriter(inputStream); + return ResContainer.singleFile(rf.getName(), loadToCodeWriter(inputStream)); } private void loadFile(List list, File file) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index 8ca5a4e0c..160f08500 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -10,6 +10,7 @@ import jadx.core.utils.ErrorsCounter; import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.files.InputFile; +import jadx.core.xmlgen.ResContainer; import jadx.core.xmlgen.ResTableParser; import jadx.core.xmlgen.ResourceStorage; @@ -74,7 +75,7 @@ public class RootNode { try { ResourcesLoader.decodeStream(arsc, new ResourcesLoader.ResourceDecoder() { @Override - public Object decode(long size, InputStream is) throws IOException { + public ResContainer decode(long size, InputStream is) throws IOException { parser.decode(is); return null; } diff --git a/jadx-core/src/main/java/jadx/core/utils/StringUtils.java b/jadx-core/src/main/java/jadx/core/utils/StringUtils.java index 2f707d07d..3385321ed 100644 --- a/jadx-core/src/main/java/jadx/core/utils/StringUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/StringUtils.java @@ -27,30 +27,14 @@ public class StringUtils { private static void processChar(int c, StringBuilder res) { switch (c) { - case '\n': - res.append("\\n"); - break; - case '\r': - res.append("\\r"); - break; - case '\t': - res.append("\\t"); - break; - case '\b': - res.append("\\b"); - break; - case '\f': - res.append("\\f"); - break; - case '\'': - res.append('\''); - break; - case '"': - res.append("\\\""); - break; - case '\\': - res.append("\\\\"); - break; + case '\n': res.append("\\n"); break; + case '\r': res.append("\\r"); break; + case '\t': res.append("\\t"); break; + case '\b': res.append("\\b"); break; + case '\f': res.append("\\f"); break; + case '\'': res.append('\''); break; + case '"': res.append("\\\""); break; + case '\\': res.append("\\\\"); break; default: if (32 <= c && c <= 126) { @@ -114,4 +98,29 @@ public class StringUtils { } return sb.toString(); } + + public static String escapeResValue(String str) { + int len = str.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 0; i < len; i++) { + char c = str.charAt(i); + switch (c) { + case '&': sb.append("&"); break; + case '<': sb.append("<"); break; + case '>': sb.append(">"); break; + case '"': sb.append("""); break; + case '\'': sb.append("'"); break; + + case '\n': sb.append("\\n"); break; + case '\r': sb.append("\\r"); break; + case '\t': sb.append("\\t"); break; + case '\b': sb.append("\\b"); break; + case '\f': sb.append("\\f"); break; + default: + sb.append(c); + break; + } + } + return sb.toString(); + } } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java index cce1ca17d..b334591bf 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java @@ -34,6 +34,7 @@ public class BinaryXMLParser extends CommonBinaryParser { private static final Logger LOG = LoggerFactory.getLogger(BinaryXMLParser.class); private static final String ANDROID_R_STYLE_CLS = "android.R$style"; + private static final boolean ATTR_NEW_LINE = false; private CodeWriter writer; private String[] strings; @@ -76,7 +77,7 @@ public class BinaryXMLParser extends CommonBinaryParser { resNames = root.getResourcesNames(); attributes = new ManifestAttributes(); - attributes.parse(); + attributes.parseAll(); } catch (Exception e) { throw new JadxRuntimeException("BinaryXMLParser init error", e); } @@ -221,12 +222,13 @@ public class BinaryXMLParser extends CommonBinaryParser { int comment = is.readInt32(); int startNS = is.readInt32(); int startNSName = is.readInt32(); // actually is elementName... - if (!wasOneLiner && !"ERROR".equals(currentTag) && !currentTag.equals(strings[startNSName])) { + if (!wasOneLiner && !"ERROR".equals(currentTag) + && !currentTag.equals(strings[startNSName])) { writer.add(">"); } wasOneLiner = false; currentTag = strings[startNSName]; - writer.startLine("<").add(strings[startNSName]); + writer.startLine("<").add(currentTag); writer.attachSourceLine(elementBegLineNumber); int attributeStart = is.readInt16(); if (attributeStart != 0x14) { @@ -240,22 +242,16 @@ public class BinaryXMLParser extends CommonBinaryParser { int idIndex = is.readInt16(); int classIndex = is.readInt16(); int styleIndex = is.readInt16(); - if ("manifest".equals(strings[startNSName])) { - writer.add(" xmlns:\"").add(nsURI).add("\""); - } - if (attributeCount > 0) { - writer.add(" "); + if ("manifest".equals(currentTag) || writer.getIndent() == 0) { + writer.add(" xmlns:android=\"").add(nsURI).add("\""); } + boolean attrNewLine = attributeCount == 1 ? false : ATTR_NEW_LINE; for (int i = 0; i < attributeCount; i++) { - parseAttribute(i); - writer.add('"'); - if (i + 1 < attributeCount) { - writer.add(" "); - } + parseAttribute(i, attrNewLine); } } - private void parseAttribute(int i) throws IOException { + private void parseAttribute(int i, boolean newLine) throws IOException { int attributeNS = is.readInt32(); int attributeName = is.readInt32(); int attributeRawValue = is.readInt32(); @@ -268,10 +264,16 @@ public class BinaryXMLParser extends CommonBinaryParser { } int attrValDataType = is.readInt8(); int attrValData = is.readInt32(); + + String attrName = strings[attributeName]; + if (newLine) { + writer.startLine().addIndent(); + } else { + writer.add(' '); + } if (attributeNS != -1) { writer.add(nsPrefix).add(':'); } - String attrName = strings[attributeName]; writer.add(attrName).add("=\""); String decodedAttr = attributes.decode(attrName, attrValData); if (decodedAttr != null) { @@ -279,6 +281,7 @@ public class BinaryXMLParser extends CommonBinaryParser { } else { decodeAttribute(attributeNS, attrValDataType, attrValData); } + writer.add('"'); } private void decodeAttribute(int attributeNS, int attrValDataType, int attrValData) { @@ -295,7 +298,11 @@ public class BinaryXMLParser extends CommonBinaryParser { FieldNode field = localStyleMap.get(attrValData); if (field != null) { String cls = field.getParentClass().getShortName().toLowerCase(); - writer.add("@").add(cls).add("/").add(field.getName()); + writer.add("@"); + if ("id".equals(cls)) { + writer.add('+'); + } + writer.add(cls).add("/").add(field.getName()); } else { String resName = resNames.get(attrValData); if (resName != null) { diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java b/jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java index 9f4710419..35f51fbce 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ManifestAttributes.java @@ -4,6 +4,8 @@ import jadx.core.utils.exceptions.JadxException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedHashMap; @@ -15,10 +17,12 @@ import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; public class ManifestAttributes { private static final Logger LOG = LoggerFactory.getLogger(ManifestAttributes.class); + private static final String ATTR_XML = "/android/attrs.xml"; private static final String MANIFEST_ATTR_XML = "/android/attrs_manifest.xml"; private enum MAttrType { @@ -27,7 +31,7 @@ public class ManifestAttributes { private static class MAttr { private final MAttrType type; - private final Map values = new LinkedHashMap(); + private final Map values = new LinkedHashMap(); public MAttr(MAttrType type) { this.type = type; @@ -37,7 +41,7 @@ public class ManifestAttributes { return type; } - public Map getValues() { + public Map getValues() { return values; } @@ -47,15 +51,23 @@ public class ManifestAttributes { } } - private final Document doc; private final Map attrMap = new HashMap(); public ManifestAttributes() throws Exception { - InputStream xmlStream = null; + } + + public void parseAll() throws Exception { + parse(loadXML(ATTR_XML)); + parse(loadXML(MANIFEST_ATTR_XML)); + LOG.debug("Loaded android attributes count: {}", attrMap.size()); + } + + private Document loadXML(String xml) throws JadxException, ParserConfigurationException, SAXException, IOException { + Document doc;InputStream xmlStream = null; try { - xmlStream = ManifestAttributes.class.getResourceAsStream(MANIFEST_ATTR_XML); + xmlStream = ManifestAttributes.class.getResourceAsStream(xml); if (xmlStream == null) { - throw new JadxException(MANIFEST_ATTR_XML + " not found in classpath"); + throw new JadxException(xml + " not found in classpath"); } DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); doc = dBuilder.parse(xmlStream); @@ -64,9 +76,10 @@ public class ManifestAttributes { xmlStream.close(); } } + return doc; } - public void parse() { + private void parse(Document doc) { NodeList nodeList = doc.getChildNodes(); for (int count = 0; count < nodeList.getLength(); count++) { Node node = nodeList.item(count); @@ -127,13 +140,13 @@ public class ManifestAttributes { Node valueNode = attributes.getNamedItem("value"); if (valueNode != null) { try { - int key; + long key; String nodeValue = valueNode.getNodeValue(); - if (attr.getType() == MAttrType.ENUM) { - key = Integer.parseInt(nodeValue); + if (nodeValue.startsWith("0x")) { + nodeValue = nodeValue.substring(2); + key = Long.parseLong(nodeValue, 16); } else { - nodeValue = nodeValue.replace("0x", ""); - key = Integer.parseInt(nodeValue, 16); + key = Long.parseLong(nodeValue); } attr.getValues().put(key, nameNode.getNodeValue()); } catch (NumberFormatException e) { @@ -145,7 +158,7 @@ public class ManifestAttributes { } } - public String decode(String attrName, int value) { + public String decode(String attrName, long value) { MAttr attr = attrMap.get(attrName); if (attr == null) { return null; @@ -157,7 +170,7 @@ public class ManifestAttributes { } } else if (attr.getType() == MAttrType.FLAG) { StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : attr.getValues().entrySet()) { + for (Map.Entry entry : attr.getValues().entrySet()) { if ((value & entry.getKey()) != 0) { sb.append(entry.getValue()).append('|'); } @@ -166,6 +179,6 @@ public class ManifestAttributes { return sb.deleteCharAt(sb.length() - 1).toString(); } } - return "UNKNOWN_DATA_0x" + Integer.toHexString(value); + return "UNKNOWN_DATA_0x" + Long.toHexString(value); } } 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 33b2ab074..53bcbd5a1 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ParserConstants.java @@ -1,5 +1,8 @@ package jadx.core.xmlgen; +import java.util.HashMap; +import java.util.Map; + public class ParserConstants { /** @@ -141,6 +144,7 @@ public class ParserConstants { protected static final int ATTR_MAX = ResMakeInternal(2); // Localization of this resource is can be encouraged or required with an aapt flag if this is set protected static final int ATTR_L10N = ResMakeInternal(3); + // for plural support, see android.content.res.PluralRules#attrForQuantity(int) protected static final int ATTR_OTHER = ResMakeInternal(4); protected static final int ATTR_ZERO = ResMakeInternal(5); @@ -149,6 +153,17 @@ public class ParserConstants { protected static final int ATTR_FEW = ResMakeInternal(8); protected static final int ATTR_MANY = ResMakeInternal(9); + protected static final Map PLURALS_MAP = new HashMap() { + { + put(ATTR_OTHER, "other"); + put(ATTR_ZERO, "zero"); + put(ATTR_ONE, "one"); + put(ATTR_TWO, "two"); + put(ATTR_FEW, "few"); + put(ATTR_MANY, "many"); + } + }; + private static int ResMakeInternal(int entry) { return 0x01000000 | entry & 0xFFFF; } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java new file mode 100644 index 000000000..d0bf76d23 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java @@ -0,0 +1,68 @@ +package jadx.core.xmlgen; + +import jadx.core.codegen.CodeWriter; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +public class ResContainer implements Comparable { + + private final String name; + @Nullable + private CodeWriter content; + + private final List subFiles; + + private ResContainer(String name, @Nullable CodeWriter content, List subFiles) { + this.name = name; + this.content = content; + this.subFiles = subFiles; + } + + public static ResContainer singleFile(String name, CodeWriter content) { + return new ResContainer(name, content, Collections.emptyList()); + } + + public static ResContainer multiFile(String name) { + return new ResContainer(name, null, new ArrayList()); + } + + public String getName() { + return name; + } + + public String getFileName() { + return name.replace("/", File.separator); + } + + @Nullable + public CodeWriter getContent() { + return content; + } + + public void setContent(@Nullable CodeWriter content) { + this.content = content; + } + + public List getSubFiles() { + return subFiles; + } + + @Override + public int compareTo(ResContainer o) { + return name.compareTo(o.name); + } + + @Override + public String toString() { + return "ResContainer{" + + "name='" + name + "'" + + ", content=" + content + + ", subFiles=" + subFiles + + "}"; + } +} 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 3e0c98a8d..e769984cc 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -58,9 +58,19 @@ public class ResTableParser extends CommonBinaryParser { resStorage.finish(); } - public CodeWriter decodeToCodeWriter(InputStream inputStream) throws IOException { + public ResContainer decodeFiles(InputStream inputStream) throws IOException { decode(inputStream); + ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames()); + ResXmlGen resGen = new ResXmlGen(resStorage, vp); + + ResContainer res = ResContainer.multiFile("res"); + res.setContent(makeDump()); + res.getSubFiles().addAll(resGen.makeResourcesXml()); + return res; + } + + public CodeWriter makeDump() throws IOException { CodeWriter writer = new CodeWriter(); writer.add("app package: ").add(resStorage.getAppPackage()); writer.startLine(); diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java new file mode 100644 index 000000000..a093321fe --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResXmlGen.java @@ -0,0 +1,127 @@ +package jadx.core.xmlgen; + +import jadx.core.codegen.CodeWriter; +import jadx.core.utils.StringUtils; +import jadx.core.xmlgen.entry.RawNamedValue; +import jadx.core.xmlgen.entry.ResourceEntry; +import jadx.core.xmlgen.entry.ValuesParser; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResXmlGen { + + private static final Logger LOG = LoggerFactory.getLogger(ResXmlGen.class); + private static final Set SKIP_RES_TYPES = new HashSet(Arrays.asList( + "layout", + "mipmap", + "id" + )); + + private final ResourceStorage resStorage; + private final ValuesParser vp; + + public ResXmlGen(ResourceStorage resStorage, ValuesParser vp) { + this.resStorage = resStorage; + this.vp = vp; + } + + public List makeResourcesXml() { + Map contMap = new HashMap(); + for (ResourceEntry ri : resStorage.getResources()) { + if (SKIP_RES_TYPES.contains(ri.getTypeName())) { + continue; + } + String fn = getFileName(ri); + CodeWriter cw = contMap.get(fn); + if (cw == null) { + cw = new CodeWriter(); + cw.add(""); + cw.startLine(""); + cw.incIndent(); + contMap.put(fn, cw); + } + addValue(cw, ri); + } + + List files = new ArrayList(contMap.size()); + for (Map.Entry entry : contMap.entrySet()) { + String fileName = entry.getKey(); + CodeWriter content = entry.getValue(); + + content.decIndent(); + content.startLine(""); + content.finish(); + files.add(ResContainer.singleFile(fileName, content)); + } + Collections.sort(files); + return files; + } + + private void addValue(CodeWriter cw, ResourceEntry ri) { + if (ri.getSimpleValue() != null) { + String valueStr = vp.decodeValue(ri.getSimpleValue()); + addSimpleValue(cw, ri.getTypeName(), "name", ri.getKeyName(), valueStr); + } else { + cw.startLine(); + cw.add('<').add(ri.getTypeName()).add(' '); + cw.add("name=\"").add(ri.getKeyName()).add("\">"); + cw.incIndent(); + for (RawNamedValue value : ri.getNamedValues()) { + addItem(cw, value); + } + cw.decIndent(); + cw.startLine().add("'); + } + } + + private void addItem(CodeWriter cw, RawNamedValue value) { + String keyName = null; + String keyValue = null; + int nameRef = value.getNameRef(); + if (ParserConstants.isResInternalId(nameRef)) { + keyValue = ParserConstants.PLURALS_MAP.get(nameRef); + if (keyValue != null) { + keyName = "quantity"; + } + } + String valueStr = vp.decodeValue(value.getRawValue()); + addSimpleValue(cw, "item", keyName, keyValue, valueStr); + } + + private void addSimpleValue(CodeWriter cw, String typeName, String attrName, String attrValue, String valueStr) { + cw.startLine(); + cw.add('<').add(typeName); + if (attrName != null && attrValue != null) { + cw.add(' ').add(attrName).add("=\"").add(attrValue).add('"'); + } + cw.add('>'); + cw.add(StringUtils.escapeResValue(valueStr)); + cw.add("'); + } + + private String getFileName(ResourceEntry ri) { + StringBuilder sb = new StringBuilder(); + String locale = ri.getConfig().getLocale(); + sb.append("res/values"); + if (!locale.isEmpty()) { + sb.append('-').append(locale); + } + sb.append('/'); + sb.append(ri.getTypeName()); + if (!ri.getTypeName().endsWith("s")) { + sb.append('s'); + } + sb.append(".xml"); + return sb.toString(); + } +} diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java new file mode 100644 index 000000000..97260ded6 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java @@ -0,0 +1,46 @@ +package jadx.core.xmlgen; + +import jadx.api.ResourceFile; +import jadx.api.ResourceType; +import jadx.core.codegen.CodeWriter; + +import java.io.File; +import java.util.List; + +public class ResourcesSaver implements Runnable { + private final ResourceFile resourceFile; + private File outDir; + + public ResourcesSaver(File outDir, ResourceFile resourceFile) { + this.resourceFile = resourceFile; + this.outDir = outDir; + } + + @Override + public void run() { + if (!ResourceType.isSupportedForUnpack(resourceFile.getType())) { + return; + } + ResContainer rc = resourceFile.getContent(); + if (rc != null) { + saveResources(rc); + } + } + + private void saveResources(ResContainer rc) { + if (rc == null) { + return; + } + List subFiles = rc.getSubFiles(); + if (subFiles.isEmpty()) { + CodeWriter cw = rc.getContent(); + if (cw != null) { + cw.save(new File(outDir, rc.getFileName())); + } + } else { + for (ResContainer subFile : subFiles) { + saveResources(subFile); + } + } + } +} diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java b/jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java index 99731003c..91ab35509 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java @@ -20,8 +20,7 @@ public class EntryConfig { return country; } - @Override - public String toString() { + public String getLocale() { StringBuilder sb = new StringBuilder(); if (language != null) { sb.append(language); @@ -29,6 +28,13 @@ public class EntryConfig { if (country != null) { sb.append("-r").append(country); } + return sb.toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getLocale()); if (sb.length() != 0) { sb.insert(0, " ["); sb.append(']'); diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java b/jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java index c75da989f..2f947c48b 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java @@ -16,4 +16,9 @@ public class RawNamedValue { public RawValue getRawValue() { return rawValue; } + + @Override + public String toString() { + return "RawNamedValue{nameRef=" + nameRef + ", rawValue=" + rawValue + '}'; + } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java index 395a4d495..654f6ce76 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -1,8 +1,10 @@ package jadx.gui.treemodel; import jadx.api.ResourceFile; +import jadx.api.ResourceFileContent; import jadx.api.ResourceType; import jadx.core.codegen.CodeWriter; +import jadx.core.xmlgen.ResContainer; import jadx.gui.utils.OverlayIcon; import jadx.gui.utils.Utils; @@ -31,6 +33,7 @@ public class JResource extends JNode implements Comparable { } private final String name; + private final String shortName; private final List files = new ArrayList(1); private final JResType type; private final ResourceFile resFile; @@ -40,12 +43,18 @@ public class JResource extends JNode implements Comparable { private Map lineMapping; public JResource(ResourceFile resFile, String name, JResType type) { + this(resFile, name, name, type); + } + + public JResource(ResourceFile resFile, String name, String shortName, JResType type) { this.resFile = resFile; this.name = name; + this.shortName = shortName; this.type = type; } public final void update() { + loadContent(); removeAllChildren(); for (JResource res : files) { res.update(); @@ -53,6 +62,13 @@ public class JResource extends JNode implements Comparable { } } + protected void loadContent() { + getContent(); + for (JResource res : files) { + res.loadContent(); + } + } + public String getName() { return name; } @@ -65,16 +81,64 @@ public class JResource extends JNode implements Comparable { if (!loaded && resFile != null && type == JResType.FILE) { loaded = true; if (isSupportedForView(resFile.getType())) { - CodeWriter cw = resFile.getContent(); - if (cw != null) { - lineMapping = cw.getLineMapping(); - content = cw.toString(); + ResContainer rc = resFile.getContent(); + if (rc != null) { + addSubFiles(rc, this, 0); } } } return content; } + protected void addSubFiles(ResContainer rc, JResource root, int depth) { + CodeWriter cw = rc.getContent(); + if (cw != null) { + if (depth == 0) { + root.lineMapping = cw.getLineMapping(); + root.content = cw.toString(); + } else { + String name = rc.getName(); + String[] path = name.split("/"); + String shortName = path.length == 0 ? name : path[path.length - 1]; + ResourceFileContent fileContent = new ResourceFileContent(shortName, ResourceType.XML, cw); + addPath(path, root, new JResource(fileContent, name, shortName, JResType.FILE)); + } + } + List subFiles = rc.getSubFiles(); + if (!subFiles.isEmpty()) { + for (ResContainer subFile : subFiles) { + addSubFiles(subFile, root, depth + 1); + } + } + } + + private static void addPath(String[] path, JResource root, JResource jResource) { + if (path.length == 1) { + root.getFiles().add(jResource); + return; + } + int last = path.length - 1; + for (int i = 0; i <= last; i++) { + String f = path[i]; + if (i == last) { + root.getFiles().add(jResource); + } else { + root = getResDir(root, f); + } + } + } + + private static JResource getResDir(JResource root, String dirName) { + for (JResource file : root.getFiles()) { + if (file.getName().equals(dirName)) { + return file; + } + } + JResource resDir = new JResource(null, dirName, JResType.DIR); + root.getFiles().add(resDir); + return resDir; + } + @Override public Integer getSourceLine(int line) { if (lineMapping == null) { @@ -170,7 +234,7 @@ public class JResource extends JNode implements Comparable { @Override public String makeString() { - return name; + return shortName; } @Override