// A sample to de-optimize system folder of an extracted ROM public static void deOptimizeFiles(String systemFolder, String workingDir) { File bootOat = new File(MiscUtil.path(systemFolder, "framework", "arm", "boot.oat")); if (!bootOat.exists()) { LLog.i(bootOat + " not found"); return; } String outputJarFolder = MiscUtil.path(workingDir, "result-jar"); try { bootOat2Jar( bootOat.getAbsolutePath(), MiscUtil.path(systemFolder, "framework"), outputJarFolder); } catch (IOException ex) { LLog.ex(ex); } }
public static void smaliRaw(File inputFile) { if (!inputFile.isFile()) { LLog.i(inputFile + " is not a file."); } String folderName = MiscUtil.getFilenamePrefix(inputFile.getName()); String outputBaseFolder = MiscUtil.path(inputFile.getAbsoluteFile().getParent(), folderName); baksmaliOptions options = new baksmaliOptions(); Opcodes opc = new Opcodes(org.jf.dexlib2.Opcode.LOLLIPOP); options.apiLevel = opc.apiLevel; options.allowOdex = true; options.jobs = 4; java.util.List<DexBackedDexFile> dexFiles = new ArrayList<>(); java.util.List<String> outSubFolders = new ArrayList<>(); if (Elf.isElf(inputFile)) { final byte[] buf = new byte[8192]; try (Elf e = new Elf(inputFile)) { Oat oat = getOat(e); for (int i = 0; i < oat.mDexFiles.length; i++) { Oat.DexFile df = oat.mDexFiles[i]; dexFiles.add(readDex(df, df.mHeader.file_size_, opc, buf)); String opath = new String(oat.mOatDexFiles[i].dex_file_location_data_); opath = MiscUtil.getFilenamePrefix(getOuputNameForSubDex(opath)); outSubFolders.add(MiscUtil.path(outputBaseFolder, opath)); } } catch (IOException ex) { LLog.ex(ex); } } else { dexFiles = DexUtil.loadMultiDex(inputFile, opc); String subFolder = "classes"; for (int i = 0; i < dexFiles.size(); i++) { outSubFolders.add(MiscUtil.path(outputBaseFolder, subFolder)); subFolder = "classes" + (i + 2); } } if (outSubFolders.size() == 1) { outSubFolders.set(0, outputBaseFolder); } for (int i = 0; i < dexFiles.size(); i++) { options.outputDirectory = outSubFolders.get(i); org.jf.baksmali.baksmali.disassembleDexFile(dexFiles.get(i), options); LLog.i("Output to " + options.outputDirectory); } LLog.i("All done"); }
@Override public DexFile rewriteDexFile(DexFile dexFile) { try { return org.jf.dexlib2.immutable.ImmutableDexFile.of(super.rewriteDexFile(dexFile)); } catch (Exception e) { LLog.i("Failed to re-construct dex " + e); // LLog.ex(e); } return new FailedDexFile(); }
// Get optimized dex from oat public static void extractOdexFromOat(File oatFile, File outputFolder) { try (Elf e = new Elf(oatFile)) { Oat oat = getOat(e); for (int i = 0; i < oat.mDexFiles.length; i++) { Oat.OatDexFile odf = oat.mOatDexFiles[i]; Oat.DexFile df = oat.mDexFiles[i]; String opath = new String(odf.dex_file_location_data_); opath = getOuputNameForSubDex(opath); if (outputFolder == null) { outputFolder = new File(MiscUtil.workingDir()); } File out = MiscUtil.changeExt(new File(outputFolder, opath), "dex"); df.saveTo(out); LLog.i("Output raw dex: " + out.getAbsolutePath()); } } catch (IOException ex) { LLog.ex(ex); } }
public static ArrayList<String> getBootJarNames(String bootOat) { ArrayList<String> names = new ArrayList<>(); try (Elf e = new Elf(bootOat)) { Oat oat = getOat(e); for (Oat.OatDexFile df : oat.mOatDexFiles) { String s = new String(df.dex_file_location_data_); if (s.contains(":")) { continue; } names.add(s.substring(s.lastIndexOf('/') + 1)); } } catch (IOException ex) { LLog.ex(ex); } return names; }
public static void extractDexFromBootOat( String oatFile, String outputFolder, String bootClassPath, String noClassJarFolder) { try (Elf e = new Elf(oatFile)) { Oat oat = getOat(e); File outFolder = new File(outputFolder); if (!outFolder.exists()) { outFolder.mkdirs(); } if (noClassJarFolder == null) { convertToDex(oat, outFolder, bootClassPath, false); } else { convertToDexJar(oat, outFolder, bootClassPath, noClassJarFolder, true); } } catch (IOException ex) { LLog.ex(ex); } }
private static void convertToDex( Oat oat, File outputFolder, String bootClassPath, boolean addSelfToBcp) throws IOException { final Opcodes opcodes = new Opcodes(oat.guessApiLevel()); LLog.i("Preparing bootclasspath from " + bootClassPath); if (bootClassPath == null || !new File(bootClassPath).exists()) { LLog.e("Invalid bootclasspath: " + bootClassPath); } final OatDexRewriterModule odr = new OatDexRewriterModule(bootClassPath, opcodes); final DexRewriter deOpt = odr.getRewriter(); DexFile[] dexFiles = getOdexFromOat(oat, opcodes); if (addSelfToBcp) { for (DexFile d : dexFiles) { odr.mBootClassPath.addDex(d); } } for (int i = 0; i < oat.mOatDexFiles.length; i++) { Oat.OatDexFile odf = oat.mOatDexFiles[i]; String dexLoc = new String(odf.dex_file_location_data_); String opath = getOuputNameForSubDex(dexLoc); if ("base.apk".equals(opath)) { opath = MiscUtil.getFilenamePrefix(oat.mSrcFile.getName()); } File outputFile = MiscUtil.changeExt(new File(outputFolder, opath), "dex"); LLog.i("De-optimizing " + dexLoc); DexFile d = deOpt.rewriteDexFile(dexFiles[i]); if (!OatDexRewriter.isValid(d)) { LLog.i("convertToDex: skip " + dexLoc); continue; } if (outputFile.exists()) { File old = outputFile; outputFile = MiscUtil.appendTail(outputFile, "-deodex"); LLog.i(old + " already existed, use name " + outputFile.getName()); } DexPool.writeTo(outputFile.getAbsolutePath(), d); LLog.i("Output to " + outputFile); } }
public static void convertToDexJar( Oat oat, File outputFolder, String bootClassPath, String noClassJarFolder, boolean isBoot) throws IOException { final Opcodes opcodes = new Opcodes(oat.guessApiLevel()); LLog.i("Preparing bootclasspath from " + bootClassPath); final OatDexRewriterModule odr = new OatDexRewriterModule(bootClassPath, opcodes); HashMap<String, ArrayList<Oat.DexFile>> dexFileGroup = new HashMap<>(); for (int i = 0; i < oat.mOatDexFiles.length; i++) { Oat.OatDexFile odf = oat.mOatDexFiles[i]; String opath = new String(odf.dex_file_location_data_); int spos = opath.indexOf(':'); if (spos > 0) { // .../framework.jar:classes2.dex opath = opath.substring(0, spos); } opath = opath.substring(opath.lastIndexOf('/') + 1); ArrayList<Oat.DexFile> dfiles = dexFileGroup.get(opath); if (dfiles == null) { dfiles = new ArrayList<>(); dexFileGroup.put(opath, dfiles); } dfiles.add(oat.mDexFiles[i]); if (!isBoot) { Oat.DexFile dex = oat.mDexFiles[i]; odr.mBootClassPath.addDex(readDex(dex, dex.mHeader.file_size_, opcodes, null)); } } final int BSIZE = 8192; final byte[] buf = new byte[BSIZE]; final DexRewriter deOpt = odr.getRewriter(); for (String jarName : dexFileGroup.keySet()) { File outputFile = MiscUtil.changeExt(new File(outputFolder, jarName), "jar"); String classesIdx = ""; int i = 1; int readSize; try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(outputFile))) { for (Oat.DexFile dex : dexFileGroup.get(jarName)) { jos.putNextEntry(new ZipEntry("classes" + classesIdx + ".dex")); final int dexSize = dex.mHeader.file_size_; ByteBuffer dexBytes = ByteBuffer.allocateDirect(dexSize); dex.mReader.seek(dex.mDexPosition); int remain = dexSize; int read = BSIZE > dexSize ? dexSize : BSIZE; while ((readSize = dex.mReader.readRaw(buf, 0, read)) != -1 && remain > 0) { dexBytes.put(buf, 0, readSize); remain -= readSize; if (remain < BSIZE) { read = remain; } } LLog.i("De-optimizing " + jarName + (i > 1 ? (" part-" + classesIdx) : "")); int length = dexBytes.position(); dexBytes.flip(); byte[] data = new byte[length]; dexBytes.get(data); DexFile d = new DexBackedDexFile(opcodes, data); d = deOpt.rewriteDexFile(d); if (!OatDexRewriter.isValid(d)) { LLog.i("convertToDexJar: skip " + jarName); continue; } MemoryDataStore m = new MemoryDataStore(dexSize + 512); DexPool.writeTo(m, d); jos.write(m.mBuffer.mData, 0, m.mBuffer.mMaxDataPosition); classesIdx = String.valueOf(++i); jos.closeEntry(); } // Copy files from original jar try (JarFile jarFile = new JarFile(new File(noClassJarFolder, jarName))) { final Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { final JarEntry e = entries.nextElement(); String name = e.getName(); if (name.startsWith("classes") && name.endsWith(".dex")) { continue; } jos.putNextEntry(new ZipEntry(name)); try (InputStream is = jarFile.getInputStream(e)) { int bytesRead; while ((bytesRead = is.read(buf)) != -1) { jos.write(buf, 0, bytesRead); } } jos.closeEntry(); } } LLog.i("Output " + outputFile); } catch (IOException e) { LLog.ex(e); } } }