diff options
author | Ben Gruver <bgruv@google.com> | 2015-10-01 08:34:21 -0700 |
---|---|---|
committer | Ben Gruver <bgruv@google.com> | 2015-10-01 08:34:21 -0700 |
commit | ea3fdd7e860db85a062bbadc90f3a5a7555d0d25 (patch) | |
tree | 4aae5978087484137ef0a55da1c5d38059c8d102 /baksmali | |
parent | 546fdfe3d10ed255daf016d9707c12ac659dd50e (diff) | |
parent | a9dcd62b92ceac9cadb5a3b828852f13349ae78e (diff) | |
download | smali-ea3fdd7e860db85a062bbadc90f3a5a7555d0d25.tar.gz |
Merge branch 'master' into smalidea
Diffstat (limited to 'baksmali')
12 files changed, 135 insertions, 25 deletions
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java index 9c171f49..2529af8a 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java @@ -146,8 +146,7 @@ public class ClassDefinition { } private void writeInterfaces(IndentingWriter writer) throws IOException { - List<String> interfaces = Lists.newArrayList(classDef.getInterfaces()); - Collections.sort(interfaces); + List<String> interfaces = classDef.getInterfaces(); if (interfaces.size() != 0) { writer.write('\n'); diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java index 4081a75c..6e009fb7 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -366,7 +366,8 @@ public class MethodDefinition { private List<MethodItem> getMethodItems() { ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>(); - if ((classDef.options.registerInfo != 0) || (classDef.options.deodex && needsAnalyzed())) { + if ((classDef.options.registerInfo != 0) || (classDef.options.normalizeVirtualMethods) || + (classDef.options.deodex && needsAnalyzed())) { addAnalyzedInstructionMethodItems(methodItems); } else { addInstructionMethodItems(methodItems); @@ -460,7 +461,7 @@ public class MethodDefinition { private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) { MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classDef.options.classPath, method, - classDef.options.inlineResolver); + classDef.options.inlineResolver, classDef.options.normalizeVirtualMethods); AnalysisException analysisException = methodAnalyzer.getAnalysisException(); if (analysisException != null) { diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java index 47fa406d..1e297029 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -44,19 +44,18 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; 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) { - if (options.registerInfo != 0 || options.deodex) { + if (options.registerInfo != 0 || options.deodex || options.normalizeVirtualMethods) { try { Iterable<String> extraClassPathEntries; if (options.extraClassPathEntries != null) { diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java index b6cc1571..5dd060f1 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java @@ -36,6 +36,7 @@ import org.jf.dexlib2.analysis.ClassPath; import org.jf.dexlib2.analysis.InlineMethodResolver; import org.jf.dexlib2.util.SyntheticAccessorResolver; +import javax.annotation.Nullable; import java.io.File; import java.util.Arrays; import java.util.HashMap; @@ -54,7 +55,7 @@ public class baksmaliOptions { public int apiLevel = 15; public String outputDirectory = "out"; - public String dexEntry = "classes.dex"; + @Nullable public String dexEntry = null; public List<String> bootClassPathDirs = Lists.newArrayList(); public List<String> bootClassPathEntries = Lists.newArrayList(); @@ -75,6 +76,7 @@ public class baksmaliOptions { public boolean ignoreErrors = false; public boolean checkPackagePrivateAccess = false; public boolean useImplicitReferences = false; + public boolean normalizeVirtualMethods = false; public File customInlineDefinitions = null; public InlineMethodResolver inlineResolver = null; public int registerInfo = 0; diff --git a/baksmali/src/main/java/org/jf/baksmali/dump.java b/baksmali/src/main/java/org/jf/baksmali/dump.java index 1ef7df0e..57a48af8 100644 --- a/baksmali/src/main/java/org/jf/baksmali/dump.java +++ b/baksmali/src/main/java/org/jf/baksmali/dump.java @@ -52,7 +52,7 @@ public class dump { consoleWidth = 120; } - RawDexFile rawDexFile = new RawDexFile(new Opcodes(apiLevel, experimental), dexFile); + RawDexFile rawDexFile = new RawDexFile(Opcodes.forApi(apiLevel), dexFile); DexAnnotator annotator = new DexAnnotator(rawDexFile, consoleWidth); annotator.writeAnnotations(writer); } catch (IOException ex) { diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java index 71598fa6..17ec3839 100644 --- a/baksmali/src/main/java/org/jf/baksmali/main.java +++ b/baksmali/src/main/java/org/jf/baksmali/main.java @@ -31,9 +31,11 @@ package org.jf.baksmali; import com.google.common.collect.Lists; import org.apache.commons.cli.*; import org.jf.dexlib2.DexFileFactory; +import org.jf.dexlib2.DexFileFactory.MultipleDexFilesException; import org.jf.dexlib2.analysis.InlineMethodResolver; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedOdexFile; +import org.jf.dexlib2.dexbacked.OatFile.OatDexFile; import org.jf.util.ConsoleUtil; import org.jf.util.SmaliHelpFormatter; @@ -217,6 +219,9 @@ public class main { case 'k': options.checkPackagePrivateAccess = true; break; + case 'n': + options.normalizeVirtualMethods = true; + break; case 'N': disassemble = false; break; @@ -256,10 +261,20 @@ public class main { } //Read in and parse the dex file - DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry, - options.apiLevel, options.experimental); + DexBackedDexFile dexFile = null; + try { + dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry, options.apiLevel, options.experimental); + } catch (MultipleDexFilesException ex) { + System.err.println(String.format("%s contains multiple dex files. You must specify which one to " + + "disassemble with the -e option", dexFileFile.getName())); + System.err.println("Valid entries include:"); + for (OatDexFile oatDexFile: ex.oatFile.getDexFiles()) { + System.err.println(oatDexFile.filename); + } + System.exit(1); + } - if (dexFile.isOdexFile()) { + if (dexFile.hasOdexOpcodes()) { if (!options.deodex) { System.err.println("Warning: You are disassembling an odex file without deodexing it. You"); System.err.println("won't be able to re-assemble the results unless you deodex it with the -x"); @@ -270,7 +285,7 @@ public class main { options.deodex = false; } - if (!setBootClassPath && (options.deodex || options.registerInfo != 0)) { + if (!setBootClassPath && (options.deodex || options.registerInfo != 0 || options.normalizeVirtualMethods)) { if (dexFile instanceof DexBackedOdexFile) { options.bootClassPathEntries = ((DexBackedOdexFile)dexFile).getDependencies(); } else { @@ -391,9 +406,9 @@ public class main { .create("r"); Option classPathOption = OptionBuilder.withLongOpt("bootclasspath") - .withDescription("the bootclasspath jars to use, for analysis. Defaults to " + - "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar. If the value begins with a " + - ":, it will be appended to the default bootclasspath instead of replacing it") + .withDescription("A colon-separated list of bootclasspath jar/oat files to use for analysis. Add an " + + "initial colon to specify that the jars/oats should be appended to the default bootclasspath " + + "instead of replacing it") .hasOptionalArg() .withArgName("BOOTCLASSPATH") .create("c"); @@ -445,6 +460,10 @@ public class main { "4.2.1.") .create("k"); + Option normalizeVirtualMethods = OptionBuilder.withLongOpt("normalize-virtual-methods") + .withDescription("Normalize virtual method references to the reference the base method.") + .create("n"); + Option dumpOption = OptionBuilder.withLongOpt("dump-to") .withDescription("dumps the given dex file into a single annotated dump file named FILE" + " (<dexfile>.dump by default), along with the normal disassembly") @@ -494,6 +513,7 @@ public class main { basicOptions.addOption(noImplicitReferencesOption); basicOptions.addOption(dexEntryOption); basicOptions.addOption(checkPackagePrivateAccessOption); + basicOptions.addOption(normalizeVirtualMethods); debugOptions.addOption(dumpOption); debugOptions.addOption(ignoreErrorsOption); @@ -547,8 +567,7 @@ public class main { "/system/framework/services.jar", "/system/framework/apache-xml.jar", "/system/framework/filterfw.jar"); - - } else { + } else if (apiLevel < 21) { // this is correct as of api 17/4.2.2 return Lists.newArrayList( "/system/framework/core.jar", @@ -561,6 +580,22 @@ public class main { "/system/framework/android.policy.jar", "/system/framework/services.jar", "/system/framework/apache-xml.jar"); + } else { // api >= 21 + // TODO: verify, add new ones? + return Lists.newArrayList( + "/system/framework/core-libart.jar", + "/system/framework/conscrypt.jar", + "/system/framework/okhttp.jar", + "/system/framework/core-junit.jar", + "/system/framework/bouncycastle.jar", + "/system/framework/ext.jar", + "/system/framework/framework.jar", + "/system/framework/telephony-common.jar", + "/system/framework/voip-common.jar", + "/system/framework/ims-common.jar", + "/system/framework/mms-common.jar", + "/system/framework/android.policy.jar", + "/system/framework/apache-xml.jar"); } } } diff --git a/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java b/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java index 35304f7e..1fbafeab 100644 --- a/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java +++ b/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java @@ -81,7 +81,7 @@ public class DisassemblyTest { String inputFilename = getInputFilename(testName); byte[] inputBytes = BaksmaliTestUtils.readResourceBytesFully(getInputFilename(testName)); - DexBackedDexFile inputDex = new DexBackedDexFile(new Opcodes(options.apiLevel, false), inputBytes); + DexBackedDexFile inputDex = new DexBackedDexFile(Opcodes.forApi(options.apiLevel), inputBytes); Assert.assertEquals(1, inputDex.getClassCount()); ClassDef inputClass = Iterables.getFirst(inputDex.getClasses(), null); Assert.assertNotNull(inputClass); diff --git a/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java b/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java new file mode 100644 index 00000000..d85d7913 --- /dev/null +++ b/baksmali/src/test/java/org/jf/baksmali/InterfaceOrderTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali; + +import org.junit.Test; + +public class InterfaceOrderTest extends IdenticalRoundtripTest { + @Test + public void testInterfaceOrder() { + runTest("InterfaceOrder", new baksmaliOptions()); + } +} diff --git a/baksmali/src/test/resources/DuplicateTest/DuplicateDirectMethods.smali b/baksmali/src/test/resources/DuplicateTest/DuplicateDirectMethods.smali index b1f30c9a..fd43b021 100644 --- a/baksmali/src/test/resources/DuplicateTest/DuplicateDirectMethods.smali +++ b/baksmali/src/test/resources/DuplicateTest/DuplicateDirectMethods.smali @@ -22,7 +22,6 @@ # return-void # .end method - .method private clah()V .registers 1 diff --git a/baksmali/src/test/resources/DuplicateTest/DuplicateDirectVirtualMethods.smali b/baksmali/src/test/resources/DuplicateTest/DuplicateDirectVirtualMethods.smali index 8d87c1d8..52865737 100644 --- a/baksmali/src/test/resources/DuplicateTest/DuplicateDirectVirtualMethods.smali +++ b/baksmali/src/test/resources/DuplicateTest/DuplicateDirectVirtualMethods.smali @@ -17,7 +17,6 @@ # .end method - # virtual methods .method public alah()V .registers 1 @@ -40,7 +39,6 @@ # return-void # .end method - .method public clah()V .registers 1 diff --git a/baksmali/src/test/resources/DuplicateTest/DuplicateVirtualMethods.smali b/baksmali/src/test/resources/DuplicateTest/DuplicateVirtualMethods.smali index 74af4c58..3c080024 100644 --- a/baksmali/src/test/resources/DuplicateTest/DuplicateVirtualMethods.smali +++ b/baksmali/src/test/resources/DuplicateTest/DuplicateVirtualMethods.smali @@ -22,7 +22,6 @@ # return-void # .end method - .method public clah()V .registers 1 diff --git a/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali b/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali new file mode 100644 index 00000000..b4745cb3 --- /dev/null +++ b/baksmali/src/test/resources/InterfaceOrderTest/InterfaceOrder.smali @@ -0,0 +1,37 @@ +.class public LInterfaceOrder; +.super Ljava/lang/Object; + +# Note how these two interfaces are not in alphabetical order +.implements Ljava/io/Serializable; +.implements Ljava/util/EventListener; +.implements Ljava/lang/Runnable; +.implements Ljava/io/Flushable; +.implements Ljava/lang/Clonable; +.implements Ljava/util/Observer; +.implements Ljava/io/Closeable; + +# direct methods +.method public constructor <init>()V + .registers 1 + return-void +.end method + +.method public close()V + .registers 1 + return-void +.end method + +.method public flush()V + .registers 1 + return-void +.end method + +.method public run()V + .registers 1 + return-void +.end method + +.method public update(Ljava/util/Observable;Ljava/lang/Object;)V + .registers 3 + return-void +.end method |