예제 #1
0
 // 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);
   }
 }
예제 #2
0
  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");
  }
예제 #3
0
 @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();
 }
예제 #4
0
 // 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);
   }
 }
예제 #5
0
 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;
 }
예제 #6
0
 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);
   }
 }
예제 #7
0
  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);
    }
  }
예제 #8
0
  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);
      }
    }
  }