1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
| public static void disassembleDexFile(String dexFilePath, DexFile dexFile, boolean deodex, String outputDirectory, String[] classPathDirs, String bootClassPath, String extraBootClassPath, boolean noParameterRegisters, boolean useLocalsDirective, boolean useSequentialLabels, boolean outputDebugInfo, boolean addCodeOffsets, boolean noAccessorComments, int registerInfo, boolean verify, boolean ignoreErrors, String inlineTable, boolean checkPackagePrivateAccess) { baksmali.noParameterRegisters = noParameterRegisters; baksmali.useLocalsDirective = useLocalsDirective; baksmali.useSequentialLabels = useSequentialLabels; baksmali.outputDebugInfo = outputDebugInfo; baksmali.addCodeOffsets = addCodeOffsets; baksmali.noAccessorComments = noAccessorComments; baksmali.deodex = deodex; baksmali.registerInfo = registerInfo; baksmali.bootClassPath = bootClassPath; baksmali.verify = verify;
if (registerInfo != 0 || deodex || verify) {//0 || false || false try { String[] extraBootClassPathArray = null; if (extraBootClassPath != null && extraBootClassPath.length() > 0) { assert extraBootClassPath.charAt(0) == ':'; extraBootClassPathArray = extraBootClassPath.substring(1).split(":"); }
if (dexFile.isOdex() && bootClassPath == null) { //ext.jar is a special case - it is typically the 2nd jar in the boot class path, but it also //depends on classes in framework.jar (typically the 3rd jar in the BCP). If the user didn't //specify a -c option, we should add framework.jar to the boot class path by default, so that it //"just works" if (extraBootClassPathArray == null && isExtJar(dexFilePath)) { extraBootClassPathArray = new String[] {"framework.jar"}; } ClassPath.InitializeClassPathFromOdex(classPathDirs, extraBootClassPathArray, dexFilePath, dexFile, checkPackagePrivateAccess); } else { String[] bootClassPathArray = null; if (bootClassPath != null) { bootClassPathArray = bootClassPath.split(":"); } ClassPath.InitializeClassPath(classPathDirs, bootClassPathArray, extraBootClassPathArray, dexFilePath, dexFile, checkPackagePrivateAccess); }
if (inlineTable != null) { inlineResolver = new CustomInlineMethodResolver(inlineTable); } } catch (Exception ex) { System.err.println("\n\nError occured while loading boot class path files. Aborting."); ex.printStackTrace(System.err); System.exit(1); } }
File outputDirectoryFile = new File(outputDirectory); if (!outputDirectoryFile.exists()) { if (!outputDirectoryFile.mkdirs()) { System.err.println("Can't create the output directory " + outputDirectory); System.exit(1); } }
if (!noAccessorComments) {//!false syntheticAccessorResolver = new SyntheticAccessorResolver(dexFile); }
//sort the classes, so that if we're on a case-insensitive file system and need to handle classes with file //name collisions, then we'll use the same name for each class, if the dex file goes through multiple //baksmali/smali cycles for some reason. If a class with a colliding name is added or removed, the filenames //may still change of course ArrayList<ClassDefItem> classDefItems = new ArrayList<ClassDefItem>(dexFile.ClassDefsSection.getItems()); Collections.sort(classDefItems, new Comparator<ClassDefItem>() { public int compare(ClassDefItem classDefItem1, ClassDefItem classDefItem2) { return classDefItem1.getClassType().getTypeDescriptor().compareTo(classDefItem1.getClassType().getTypeDescriptor()); } });
ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
for (ClassDefItem classDefItem: classDefItems) { /** * The path for the disassembly file is based on the package name * The class descriptor will look something like: * Ljava/lang/Object; * Where the there is leading 'L' and a trailing ';', and the parts of the * package name are separated by '/' */
String classDescriptor = classDefItem.getClassType().getTypeDescriptor();
//validate that the descriptor is formatted like we expect if (classDescriptor.charAt(0) != 'L' || classDescriptor.charAt(classDescriptor.length()-1) != ';') { System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class"); continue; }
File smaliFile = fileNameHandler.getUniqueFilenameForClass(classDescriptor);
//create and initialize the top level string template ClassDefinition classDefinition = new ClassDefinition(classDefItem);
//write the disassembly Writer writer = null; try { File smaliParent = smaliFile.getParentFile(); if (!smaliParent.exists()) { if (!smaliParent.mkdirs()) { System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class"); continue; } }
if (!smaliFile.exists()){ if (!smaliFile.createNewFile()) { System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class"); continue; } }
BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(smaliFile), "UTF8"));
writer = new IndentingWriter(bufWriter); classDefinition.writeTo((IndentingWriter)writer); } catch (Exception ex) { System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class"); ex.printStackTrace(); smaliFile.delete(); } finally { if (writer != null) { try { writer.close(); } catch (Throwable ex) { System.err.println("\n\nError occured while closing file " + smaliFile.toString()); ex.printStackTrace(); } } }
if (!ignoreErrors && classDefinition.hadValidationErrors()) { System.exit(1); } } }
|