/* <Author: Gabriele Martini Description: This Software is a A Command-Line Program written in Java to check what Framework it's been used to build the APK> Copyright (C) <2014> <Gabriele Martini> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.apkcategorychecker.tool; import java.io.File; import java.io.IOException; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import brut.androlib.AndrolibException; import brut.androlib.ApkDecoder; import brut.androlib.err.CantFind9PatchChunk; import brut.androlib.err.CantFindFrameworkResException; import brut.androlib.err.InFileNotFoundException; import brut.androlib.err.OutDirExistsException; import brut.androlib.err.UndefinedResObject; import brut.directory.DirectoryException; /** * This class decode an APK in a directory with the name of APK * * @author Gabriele Martini */ public class ToolDecoder { /** * Instance of ApkDecoder */ private final ApkDecoder decoder = new ApkDecoder(); /** * Name of choosed APK */ private String ApkChoosedName; /** * Path of output directory */ private File outDir; /** * Verbosity * */ private static enum Verbosity { NORMAL, VERBOSE, QUIET; } /** * Method to decode an APK file using Apktool * * @param _apkPath Path of APK file * @return */ public String DecodeApk(String _apkPath, String _outDecoded){ Verbosity verbosity = Verbosity.NORMAL; setupLogging(verbosity); File ApkChoosed = new File(_apkPath); /*--Set the APK file--*/ decoder.setApkFile(ApkChoosed); /*--Retrieve the name of the APK to give the name to the output directory--*/ int ApkChoosedNameLength = ApkChoosed.getName().length(); ApkChoosedName = ApkChoosed.getName(); ApkChoosedName = ApkChoosedName.substring(0, ApkChoosedNameLength - 4); /*--Set the output directory--*/ //outDir = new File(_apkPath.substring(0, _apkPath.length() - 4)); if(_outDecoded == null){ this.outDir = new File(ApkChoosedName); }else{ this.outDir = new File(_outDecoded+ "/" + ApkChoosedName); } try { decoder.setOutDir(outDir); } catch (AndrolibException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { decoder.setDecodeSources((short) 0); } catch (AndrolibException e) { // TODO Auto-generated catch block e.printStackTrace(); } decoder.setKeepBrokenResources(true); decoder.setDebugMode(true); decoder.setBaksmaliDebugMode(false); decoder.setFrameworkDir(this.outDir.getAbsolutePath() + "/framework"); /*--Decode the APK with Apktool--*/ try { decoder.decode(); } catch (OutDirExistsException ex) { System.err.println("Destination directory (" + outDir.getAbsolutePath() + ") " + "already exists."); return null; } catch (InFileNotFoundException ex) { System.err.println("Input file was not found or was not readable."); return null; } catch (CantFindFrameworkResException ex) { System.err.println("Can't find framework resources for package of id: " + String.valueOf(ex.getPkgId()) + ". You must install proper " + "framework files, see project website for more info."); return null; } catch (IOException ex) { System.err.println("Could not modify file. Please ensure you have permission."); return null; } catch (DirectoryException ex) { System.err.println("Could not modify internal dex files. Please ensure you have permission."); return null; } catch(CantFind9PatchChunk ex) { System.err.println("Error: CantFind9PatchChunk."); return null; } catch(UndefinedResObject ex) { System.err.println("Could not decode whole apk, writing minimal results."); return null; } catch(AndrolibException ex) { System.err.println("Could not decode whole apk, writing minimal results."); return null; } return this.outDir.getPath(); } /** * Method to set log verbosity * * @param verbosity */ private static void setupLogging(Verbosity verbosity) { Logger logger = Logger.getLogger(""); for (Handler handler : logger.getHandlers()) { logger.removeHandler(handler); } LogManager.getLogManager().reset(); if (verbosity == Verbosity.QUIET) { return; } Handler handler = new Handler() { public void publish(LogRecord record) { if (getFormatter() == null) { setFormatter(new SimpleFormatter()); } try { String message = getFormatter().format(record); if (record.getLevel().intValue() >= Level.WARNING.intValue()) System.err.write(message.getBytes()); else System.out.write(message.getBytes()); } catch (Exception exception) { reportError(null, exception, 5); } } public void close() throws SecurityException { } public void flush() { } }; logger.addHandler(handler); if (verbosity == Verbosity.VERBOSE) { handler.setLevel(Level.ALL); logger.setLevel(Level.ALL); } else { handler.setFormatter(new Formatter() { public String format(LogRecord record) { return record.getLevel().toString().charAt(0) + ": " + record.getMessage() + System.getProperty("line.separator"); } }); } } }