diff --git a/baksmali/src/main/java/org/jf/baksmali/UsageException.java b/baksmali/src/main/java/org/jf/baksmali/UsageException.java new file mode 100644 index 00000000..aa95dd37 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/UsageException.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jf.baksmali; + +/** + * Simple exception class used to communicate that the command-line tool + * should print the usage message. + */ +public class UsageException extends RuntimeException { + // This space intentionally left blank. +} diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java new file mode 100644 index 00000000..b5af67d2 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java @@ -0,0 +1,56 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.antlr.stringtemplate.StringTemplate; +import org.antlr.stringtemplate.StringTemplateGroup; +import org.jf.dexlib.DexFile; +import org.jf.baksmali.wrappers.ClassDefinition; + +import java.io.FileReader; +import java.io.File; + +public class baksmali { + public static void main(String[] args) throws Exception + { + String dexFileName = args[0]; + String outputDir = args[1]; + + DexFile dexFile = new DexFile(new File(dexFileName)); + + StringTemplateGroup templates = new StringTemplateGroup( + new FileReader("src/main/resources/templates/baksmali.stg")); + + StringTemplate smaliFileST = templates.getInstanceOf("smaliFile"); + + smaliFileST.setAttribute("classDef", new ClassDefinition(dexFile.ClassDefsSection.getByIndex(0))); + + System.out.println(smaliFileST.toString()); + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java new file mode 100644 index 00000000..1505dce5 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/main.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jf.baksmali; + +import org.jf.baksmali.UsageException; + +/** + * Main class for baksmali. It recognizes enough options to be able to dispatch + * to the right "actual" main. + */ +public class main { + + public static final String VERSION = "0.9"; + + + private static String USAGE_MESSAGE = + "usage:\n" + + " java -jar baksmali.jar --disassemble <.dex file> \n" + + " disassembles the given dex file into a set of .smali files\n" + + " in the given folder\n" + + " java -jar baksmali.jar --version\n" + + " Print the version of this tool (" + VERSION + + ").\n" + + " java -jar baksmali.jar --help\n" + + " Print this message."; + + /** + * This class is uninstantiable. + */ + private main() { + // This space intentionally left blank. + } + + /** + * Run! + */ + public static void main(String[] args) { + boolean gotCmd = false; + boolean showUsage = false; + + try { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("--") || !arg.startsWith("--")) { + gotCmd = false; + showUsage = true; + break; + } + + gotCmd = true; + if (arg.equals("--disassemble")) { + baksmali.main(without(args, i)); + break; + } else if (arg.equals("--version")) { + version(); + break; + } else if (arg.equals("--help")) { + showUsage = true; + break; + } else { + gotCmd = false; + } + } + } catch (UsageException ex) { + showUsage = true; + } catch (RuntimeException ex) { + System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:"); + ex.printStackTrace(); + System.exit(2); + } catch (Throwable ex) { + System.err.println("\nUNEXPECTED TOP-LEVEL ERROR:"); + ex.printStackTrace(); + System.exit(3); + } + + if (!gotCmd) { + System.err.println("error: no command specified"); + showUsage = true; + } + + if (showUsage) { + usage(); + System.exit(1); + } + } + + /** + * Prints the version message. + */ + private static void version() { + System.err.println("baksmali version " + VERSION); + System.exit(0); + } + + /** + * Prints the usage message. + */ + private static void usage() { + System.err.println(USAGE_MESSAGE); + } + + /** + * Returns a copy of the given args array, but without the indicated + * element. + * + * @param orig non-null; original array + * @param n which element to omit + * @return non-null; new array + */ + private static String[] without(String[] orig, int n) { + int len = orig.length - 1; + String[] newa = new String[len]; + System.arraycopy(orig, 0, newa, 0, n); + System.arraycopy(orig, n + 1, newa, n, len - n); + return newa; + } +} \ No newline at end of file diff --git a/baksmali/src/main/java/org/jf/baksmali/wrappers/ClassDefinition.java b/baksmali/src/main/java/org/jf/baksmali/wrappers/ClassDefinition.java new file mode 100644 index 00000000..ddf1792e --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/wrappers/ClassDefinition.java @@ -0,0 +1,147 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.wrappers; + +import org.jf.dexlib.ClassDefItem; +import org.jf.dexlib.TypeIdItem; +import org.jf.dexlib.ClassDataItem; +import org.jf.dexlib.util.AccessFlags; + +import java.util.List; +import java.util.ArrayList; + +public class ClassDefinition { + private ClassDefItem classDefItem; + private ClassDataItem classDataItem; + + public ClassDefinition(ClassDefItem classDefItem) { + this.classDefItem = classDefItem; + this.classDataItem = classDefItem.getClassData(); + } + + private List accessFlags = null; + public List getAccessFlags() { + if (accessFlags == null) { + accessFlags = new ArrayList(); + + for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) { + accessFlags.add(accessFlag.toString()); + } + } + return accessFlags; + } + + private String classType = null; + public String getClassType() { + if (classType == null) { + classType = classDefItem.getClassType().getTypeDescriptor(); + } + return classType; + } + + private String superType = null; + public String getSuperType() { + if (superType == null) { + superType = classDefItem.getSuperclass().getTypeDescriptor(); + } + return superType; + } + + private List interfaces = null; + public List getInterfaces() { + if (interfaces == null) { + interfaces = new ArrayList(); + + List interfaceList = classDefItem.getInterfaces(); + + if (interfaceList != null) { + for (TypeIdItem typeIdItem: interfaceList) { + interfaces.add(typeIdItem.getTypeDescriptor()); + } + } + } + return interfaces; + } + + private List staticFields = null; + public List getStaticFields() { + if (staticFields == null) { + staticFields = new ArrayList(); + + if (classDataItem != null) { + for (ClassDataItem.EncodedField field: classDataItem.getStaticFields()) { + staticFields.add(new FieldDefinition(field)); + } + } + } + return staticFields; + } + + private List instanceFields = null; + public List getInstanceFields() { + if (instanceFields == null) { + instanceFields = new ArrayList(); + + if (classDataItem != null) { + for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) { + instanceFields.add(new FieldDefinition(field)); + } + } + } + return instanceFields; + } + + private List directMethods = null; + public List getDirectMethods() { + if (directMethods == null) { + directMethods = new ArrayList(); + + if (classDataItem != null) { + for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) { + directMethods.add(new MethodDefinition(method)); + } + } + } + return directMethods; + } + + private List virtualMethods = null; + public List getVirtualMethods() { + if (virtualMethods == null) { + virtualMethods = new ArrayList(); + + if (classDataItem != null) { + for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) { + virtualMethods.add(new MethodDefinition(method)); + } + } + } + return virtualMethods; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/wrappers/FieldDefinition.java b/baksmali/src/main/java/org/jf/baksmali/wrappers/FieldDefinition.java new file mode 100644 index 00000000..73cc542e --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/wrappers/FieldDefinition.java @@ -0,0 +1,74 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.wrappers; + +import org.jf.dexlib.ClassDataItem; +import org.jf.dexlib.FieldIdItem; +import org.jf.dexlib.util.AccessFlags; + +import java.util.List; +import java.util.ArrayList; + +public class FieldDefinition { + private ClassDataItem.EncodedField encodedField; + private FieldIdItem fieldIdItem; + + public FieldDefinition(ClassDataItem.EncodedField encodedField) { + this.encodedField = encodedField; + this.fieldIdItem = encodedField.getFieldReference(); + } + + private List accessFlags = null; + public List getAccessFlags() { + if (accessFlags == null) { + accessFlags = new ArrayList(); + + for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForField(encodedField.getAccessFlags())) { + accessFlags.add(accessFlag.toString()); + } + } + return accessFlags; + } + + private String fieldName = null; + public String getFieldName() { + if (fieldName == null) { + fieldName = fieldIdItem.getFieldName().getStringValue(); + } + return fieldName; + } + + private String fieldType = null; + public String getFieldType() { + if (fieldType == null) { + fieldType = fieldIdItem.getFieldType().getTypeDescriptor(); + } + return fieldType; + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/wrappers/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/wrappers/MethodDefinition.java new file mode 100644 index 00000000..bd87aeda --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/wrappers/MethodDefinition.java @@ -0,0 +1,113 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.wrappers; + +import org.jf.dexlib.ClassDataItem; +import org.jf.dexlib.CodeItem; +import org.jf.dexlib.MethodIdItem; +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.InstructionField; +import org.jf.dexlib.util.AccessFlags; + +import java.util.List; +import java.util.ArrayList; + +public class MethodDefinition { + private ClassDataItem.EncodedMethod encodedMethod; + private MethodIdItem methodIdItem; + private CodeItem codeItem; + + public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) { + this.encodedMethod = encodedMethod; + this.methodIdItem = encodedMethod.getMethod(); + this.codeItem = encodedMethod.getCodeItem(); + } + + private String methodName = null; + public String getMethodName() { + if (methodName == null) { + methodName = methodIdItem.getMethodName(); + } + return methodName; + } + + private List accessFlags = null; + public List getAccessFlags() { + if (accessFlags == null) { + accessFlags = new ArrayList(); + + for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.getAccessFlags())) { + accessFlags.add(accessFlag.toString()); + } + } + return accessFlags; + } + + private String prototype = null; + public String getPrototype() { + if (prototype == null) { + prototype = methodIdItem.getPrototype().getPrototypeString(); + } + return prototype; + } + + private Boolean hasCode = null; + public boolean getHasCode() { + if (hasCode == null) { + hasCode = (codeItem != null); + } + return hasCode; + } + + private String registerCount = null; + public String getRegisterCount() { + if (registerCount == null) { + if (codeItem == null) { + registerCount = "0"; + } else { + registerCount = Integer.toString(codeItem.getRegisterCount()); + } + } + return registerCount; + } + + //TODO: how best to abstract this? I don't like exposing dexlib's "Instruction" directly + private List instructions = null; + public List getInstructions() { + if (instructions == null) { + instructions = new ArrayList(); + if (codeItem != null) { + for (InstructionField instruction: codeItem.getInstructions()) { + instructions.add(instruction.getInstruction()); + } + } + } + return instructions; + } +}