diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java index f621a589..1d4957ec 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/ArrayDataMethodItem.java @@ -65,6 +65,8 @@ public class ArrayDataMethodItem extends InstructionMethodItem { for (Number number: elements) { LongRenderer.writeSignedIntOrLongTo(writer, number.longValue()); writer.write(suffix); + if (elementWidth == 4) + writeResourceId(writer, number.intValue()); writer.write("\n"); } writer.deindent(4); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index b4508005..e0a969cc 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -43,6 +43,7 @@ import org.jf.util.IndentingWriter; import javax.annotation.Nonnull; import java.io.IOException; +import java.util.Map; public class InstructionMethodItem extends MethodItem { @Nonnull protected final MethodDefinition methodDef; @@ -140,6 +141,8 @@ public class InstructionMethodItem extends MethodItem { writeFirstRegister(writer); writer.write(", "); writeLiteral(writer); + if (instruction.getOpcode().setsWideRegister() == false) + writeResourceId(writer); return true; case Format21t: case Format31t: @@ -337,6 +340,18 @@ public class InstructionMethodItem extends MethodItem { LongRenderer.writeSignedIntOrLongTo(writer, ((WideLiteralInstruction)instruction).getWideLiteral()); } + protected void writeResourceId(IndentingWriter writer) throws IOException { + writeResourceId(writer, ((NarrowLiteralInstruction)instruction).getNarrowLiteral()); + } + + protected void writeResourceId(IndentingWriter writer, int val) throws IOException { + Map resourceIds = methodDef.classDef.options.resourceIds; + String resource = resourceIds.get(Integer.valueOf(val)); + if (resource != null) { + writer.write(" # "); + writer.write(resource); + } + } protected void writeFieldOffset(IndentingWriter writer) throws IOException { writer.write("field@0x"); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/PackedSwitchMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/PackedSwitchMethodItem.java index 45b68c28..5d7dea7e 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/PackedSwitchMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/PackedSwitchMethodItem.java @@ -82,9 +82,12 @@ public class PackedSwitchMethodItem extends InstructionMethodItem "); target.writeTargetTo(writer); + writeResourceId(writer, target.getKey()); writer.write('\n'); } writer.deindent(4); diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java index 64b35b81..0b042036 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -39,11 +39,19 @@ import org.jf.dexlib2.iface.DexFile; import org.jf.dexlib2.util.SyntheticAccessorResolver; import org.jf.util.ClassFileNameHandler; import org.jf.util.IndentingWriter; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; import java.io.*; import java.util.List; +import java.util.Map.Entry; import java.util.concurrent.*; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.parsers.ParserConfigurationException; + public class baksmali { public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) { @@ -66,6 +74,47 @@ public class baksmali { } } + if (options.resourceIdFileEntries != null) { + class PublicHandler extends DefaultHandler { + String prefix = null; + public PublicHandler(String prefix) { + super(); + this.prefix = prefix; + } + + public void startElement(String uri, String localName, + String qName, Attributes attr) throws SAXException { + if (qName.equals("public")) { + String type = attr.getValue("type"); + String name = attr.getValue("name").replace('.', '_'); + Integer public_key = Integer.decode(attr.getValue("id")); + String public_val = new StringBuffer() + .append(prefix) + .append(".") + .append(type) + .append(".") + .append(name) + .toString(); + options.resourceIds.put(public_key, public_val); + } + } + }; + + for (Entry entry: options.resourceIdFileEntries.entrySet()) { + try { + SAXParser saxp = SAXParserFactory.newInstance().newSAXParser(); + String prefix = entry.getValue(); + saxp.parse(entry.getKey(), new PublicHandler(prefix)); + } catch (ParserConfigurationException e) { + continue; + } catch (SAXException e) { + continue; + } catch (IOException e) { + continue; + } + } + } + File outputDirectoryFile = new File(options.outputDirectory); if (!outputDirectoryFile.exists()) { if (!outputDirectoryFile.mkdirs()) { diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java index cb3c563e..197841c6 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java @@ -37,7 +37,9 @@ import org.jf.dexlib2.analysis.InlineMethodResolver; import org.jf.dexlib2.util.SyntheticAccessorResolver; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class baksmaliOptions { // register info values @@ -56,6 +58,9 @@ public class baksmaliOptions { public List bootClassPathEntries = Lists.newArrayList(); public List extraClassPathEntries = Lists.newArrayList(); + public Map resourceIdFileEntries = new HashMap(); + public Map resourceIds = new HashMap(); + public boolean noParameterRegisters = false; public boolean useLocalsDirective = false; public boolean useSequentialLabels = false; @@ -82,4 +87,11 @@ public class baksmaliOptions { } extraClassPathEntries.addAll(Arrays.asList(extraClassPath.split(":"))); } + + public void setResourceIdFiles(String resourceIdFiles) { + for (String resourceIdFile: resourceIdFiles.split(":")) { + String[] entry = resourceIdFile.split("="); + resourceIdFileEntries.put(entry[1], entry[0]); + } + } } diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java index 83009a6d..2442ff24 100644 --- a/baksmali/src/main/java/org/jf/baksmali/main.java +++ b/baksmali/src/main/java/org/jf/baksmali/main.java @@ -218,6 +218,10 @@ public class main { case 'K': options.checkPackagePrivateAccess = true; break; + case 'R': + String rif = commandLine.getOptionValue("R"); + options.setResourceIdFiles(rif); + break; default: assert false; } @@ -407,6 +411,14 @@ public class main { .withArgName("NUM_THREADS") .create("j"); + Option resourceIdFilesOption = OptionBuilder.withLongOpt("resource-id-files") + .withDescription("the resource ID files to use, for analysis. A colon-separated list of prefix=file " + + "pairs. For example R=res/values/public.xml:" + + "android.R=$ANDROID_HOME/platforms/android-19/data/res/values/public.xml") + .hasArg() + .withArgName("FILES") + .create("i"); + Option dumpOption = OptionBuilder.withLongOpt("dump-to") .withDescription("dumps the given dex file into a single annotated dump file named FILE" + " (.dump by default), along with the normal disassembly") @@ -451,6 +463,7 @@ public class main { basicOptions.addOption(noAccessorCommentsOption); basicOptions.addOption(apiLevelOption); basicOptions.addOption(jobsOption); + basicOptions.addOption(resourceIdFilesOption); debugOptions.addOption(dumpOption); debugOptions.addOption(ignoreErrorsOption); @@ -521,4 +534,4 @@ public class main { "/system/framework/apache-xml.jar"); } } -} \ No newline at end of file +}