core: use resources ids in manifest decoding
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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<DexNode> dexNodes;
|
||||
|
||||
/**
|
||||
* Resources *
|
||||
*/
|
||||
private Map<Integer, String> resourcesNames = new HashMap<Integer, String>();
|
||||
@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() {
|
||||
|
||||
@@ -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<Integer, String> styleMap = new HashMap<Integer, String>();
|
||||
private Map<Integer, FieldNode> localStyleMap = new HashMap<Integer, FieldNode>();
|
||||
private final Map<Integer, String> styleMap = new HashMap<Integer, String>();
|
||||
private final Map<Integer, FieldNode> localStyleMap = new HashMap<Integer, FieldNode>();
|
||||
private final Map<Integer, String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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<Integer, String> getResourcesNames() {
|
||||
Map<Integer, String> map = new HashMap<Integer, String>();
|
||||
for (ResourceEntry entry : list) {
|
||||
map.put(entry.getId(), entry.getTypeName() + "/" + entry.getKeyName());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Integer, String> resMap;
|
||||
|
||||
public ValuesParser(String[] strings, ResourceStorage resourceStorage) {
|
||||
public ValuesParser(String[] strings, Map<Integer, String> 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user