diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index ee08d3766..7da8d887a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -281,7 +281,7 @@ public class ClassNode extends LineAttrNode implements ILoadable { if (field == null && obj instanceof Integer) { String str = dex.root().getResourcesNames().get(obj); if (str != null) { - return new ResRefField(dex, str); + return new ResRefField(dex, str.replace('/', '.')); } } return field; 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 ce5820a43..63d7fe6d9 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 @@ -12,7 +12,6 @@ import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.files.InputFile; import jadx.core.xmlgen.ResTableParser; import jadx.core.xmlgen.ResourceStorage; -import jadx.core.xmlgen.entry.ResourceEntry; import java.io.IOException; import java.io.InputStream; @@ -32,6 +31,10 @@ public class RootNode { private final ErrorsCounter errorsCounter = new ErrorsCounter(); private List dexNodes; + + /** + * Resources * + */ private Map resourcesNames = new HashMap(); @Nullable private String appPackage; @@ -95,10 +98,7 @@ public class RootNode { } ResourceStorage resStorage = parser.getResStorage(); - appPackage = resStorage.getAppPackage(); - for (ResourceEntry entry : resStorage.getResources()) { - resourcesNames.put(entry.getId(), entry.getTypeName() + "." + entry.getKeyName()); - } + resourcesNames = resStorage.getResourcesNames(); } public void initAppResClass() { 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 fed045b61..228a5d031 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java @@ -7,6 +7,7 @@ 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; import java.io.IOException; import java.io.InputStream; @@ -42,8 +43,10 @@ public class BinaryXMLParser extends CommonBinaryParser { private boolean firstElement; private boolean wasOneLiner = false; - private Map styleMap = new HashMap(); - private Map localStyleMap = new HashMap(); + private final Map styleMap = new HashMap(); + private final Map localStyleMap = new HashMap(); + private final Map resNames; + private ValuesParser valuesParser; private final ManifestAttributes attributes; @@ -62,6 +65,9 @@ public class BinaryXMLParser extends CommonBinaryParser { } } } + + resNames = root.getResourcesNames(); + attributes = new ManifestAttributes(); attributes.parse(); } catch (Exception e) { @@ -103,6 +109,7 @@ public class BinaryXMLParser extends CommonBinaryParser { break; case RES_STRING_POOL_TYPE: strings = parseStringPoolNoType(); + valuesParser = new ValuesParser(strings, resNames); break; case RES_XML_RESOURCE_MAP_TYPE: parseResourceMap(); @@ -121,7 +128,7 @@ public class BinaryXMLParser extends CommonBinaryParser { break; default: - die("Type: " + Integer.toHexString(type) + " not yet implemented"); + die("Type: 0x" + Integer.toHexString(type) + " not yet implemented"); break; } } @@ -244,48 +251,32 @@ public class BinaryXMLParser extends CommonBinaryParser { } private void decodeAttribute(int attributeNS, int attrValDataType, int attrValData) { - switch (attrValDataType) { - case 0x3: - writer.add(strings[attrValData]); - break; - - case 0x10: - writer.add(String.valueOf(attrValData)); - break; - - case 0x12: - // FIXME: What to do, when data is always -1? - if (attrValData == 0) { - writer.add("false"); - } else if (attrValData == 1 || attrValData == -1) { - writer.add("true"); - } else { - writer.add("UNKNOWN_BOOLEAN_TYPE"); + if (attrValDataType == TYPE_REFERENCE) { + // reference custom processing + String name = styleMap.get(attrValData); + if (name != null) { + writer.add("@*"); + if (attributeNS != -1) { + writer.add(nsPrefix).add(':'); } - break; - - case 0x1: - String name = styleMap.get(attrValData); - if (name != null) { - writer.add("@*"); - if (attributeNS != -1) { - writer.add(nsPrefix).add(':'); - } - writer.add("style/").add(name.replaceAll("_", ".")); + writer.add("style/").add(name.replaceAll("_", ".")); + } else { + FieldNode field = localStyleMap.get(attrValData); + if (field != null) { + String cls = field.getParentClass().getShortName().toLowerCase(); + writer.add("@").add(cls).add("/").add(field.getName()); } else { - FieldNode field = localStyleMap.get(attrValData); - if (field != null) { - String cls = field.getParentClass().getShortName().toLowerCase(); - writer.add("@").add(cls).add("/").add(field.getName()); + String resName = resNames.get(attrValData); + if (resName != null) { + writer.add("@").add(resName); } else { writer.add("0x").add(Integer.toHexString(attrValData)); } } - break; - - default: - writer.add("UNKNOWN_DATA_TYPE_0x" + Integer.toHexString(attrValDataType)); - break; + } + } else { + String str = valuesParser.decodeValue(attrValDataType, attrValData); + writer.add(str); } } 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 ce9d69f30..8ed27be5c 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -71,7 +71,10 @@ public class ResTableParser extends CommonBinaryParser { } CodeWriter writer = new CodeWriter(); - ValuesParser vp = new ValuesParser(strings, resStorage); + writer.add("app package: ").add(resStorage.getAppPackage()); + writer.startLine(); + + ValuesParser vp = new ValuesParser(strings, resStorage.getResourcesNames()); for (ResourceEntry ri : resStorage.getResources()) { writer.startLine(ri + ": " + vp.getValueString(ri)); } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResourceStorage.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResourceStorage.java index 591d03275..d1c6f68bb 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResourceStorage.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResourceStorage.java @@ -7,7 +7,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class ResourceStorage { @@ -49,4 +51,12 @@ public class ResourceStorage { public void setAppPackage(String appPackage) { this.appPackage = appPackage; } + + public Map getResourcesNames() { + Map map = new HashMap(); + for (ResourceEntry entry : list) { + map.put(entry.getId(), entry.getTypeName() + "/" + entry.getKeyName()); + } + return map; + } } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/entry/ResourceEntry.java b/jadx-core/src/main/java/jadx/core/xmlgen/entry/ResourceEntry.java index 72b01be17..33931d92a 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/entry/ResourceEntry.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/entry/ResourceEntry.java @@ -73,14 +73,6 @@ public final class ResourceEntry { return config; } - public String formatAsRef() { - return "@" + typeName + "/" + keyName; - } - - public String formatAsAttribute() { - return "?" + typeName + "/" + keyName; - } - @Override public String toString() { return " 0x" + Integer.toHexString(id) + " (" + id + ")" + config + " = " + typeName + "." + keyName; diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/entry/ValuesParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/entry/ValuesParser.java index ad372576e..7e6de0196 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/entry/ValuesParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/entry/ValuesParser.java @@ -1,11 +1,11 @@ package jadx.core.xmlgen.entry; import jadx.core.xmlgen.ParserConstants; -import jadx.core.xmlgen.ResourceStorage; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,11 +14,11 @@ public class ValuesParser extends ParserConstants { private static final Logger LOG = LoggerFactory.getLogger(ValuesParser.class); private final String[] strings; - private final ResourceStorage resStorage; + private final Map resMap; - public ValuesParser(String[] strings, ResourceStorage resourceStorage) { + public ValuesParser(String[] strings, Map resMap) { this.strings = strings; - this.resStorage = resourceStorage; + this.resMap = resMap; } public String getValueString(ResourceEntry ri) { @@ -43,6 +43,10 @@ public class ValuesParser extends ParserConstants { public String decodeValue(RawValue value) { int dataType = value.getDataType(); int data = value.getData(); + return decodeValue(dataType, data); + } + + public String decodeValue(int dataType, int data) { switch (dataType) { case TYPE_NULL: return null; @@ -67,19 +71,19 @@ public class ValuesParser extends ParserConstants { return String.format("#%03x", data & 0xFFF); case TYPE_REFERENCE: { - ResourceEntry ri = resStorage.getByRef(data); + String ri = resMap.get(data); if (ri == null) { return "?unknown_ref: " + Integer.toHexString(data); } - return ri.formatAsRef(); + return "@" + ri; } case TYPE_ATTRIBUTE: { - ResourceEntry ri = resStorage.getByRef(data); + String ri = resMap.get(data); if (ri == null) { - return "?unknown_ref: " + Integer.toHexString(data); + return "?unknown_attr_ref: " + Integer.toHexString(data); } - return ri.formatAsAttribute(); + return "?" + ri; } case TYPE_DIMENSION: @@ -101,9 +105,9 @@ public class ValuesParser extends ParserConstants { return null; } } - ResourceEntry ri = resStorage.getByRef(ref); + String ri = resMap.get(ref); if (ri != null) { - return ri.getTypeName() + "." + ri.getKeyName(); + return ri.replace('/', '.'); } return "?0x" + Integer.toHexString(nameRef); }