/*
<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.analyzer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import brut.androlib.AndrolibException;
import com.apkcategorychecker.cli.CommandLineInterface;
import com.apkcategorychecker.framework.Framework;
import com.apkcategorychecker.framework.FrameworkPool;
import com.apkcategorychecker.tool.ToolApkParameters;
import com.apkcategorychecker.tool.ToolDex2Jar;
import com.apkcategorychecker.tool.ToolJar2Class;
import com.apkcategorychecker.writer.FactoryWriter;
import com.apkcategorychecker.writer.Writer;
import com.googlecode.dex2jar.DexException;
//import org.apache.commons.io.IOUtils;
/**
* This class analyze an APK file
* @author Gabriele Martini
*
*/
public class APKAnalyzer{
/*--Attributes--*/
/**
* List of Frameworks
*/
private ArrayList<Framework> listOfFramework;
/**
* Object containing the result of the Analysis
*/
private AnalyzerResult _results;
/**
* Object containing the list of javascript files
*/
private JsElement _jsonElement;
/**
* Constructor
*/
public APKAnalyzer() {
this._results = null;
this._jsonElement = null;
}
/**
* Method to analyze an APK file
*
* @param path
* @param _decodedApkPath
* @param apkName
* @param _outDecoded
* @param _startTime
* @param _csvPath
* @param _counter
* @throws IOException
* @throws AndrolibException
*/
public void Analyze(String path, String _decodedApkPath, String apkName, String _outDecoded, long _startTime, String _csvPath, int _counter) throws IOException, AndrolibException {
try {
/*If an error occurred while decoding apk set minimal information*/
if(_decodedApkPath == null){
this._results = this.setResults("UNDEFINED",
path,
apkName,
"UNDEFINED",
false,
0,
0,
0,
"UNDEFINED",
"UNDEFINED",
"UNDEFINED",
"UNDEFINED",
"UNDEFINED",
"UNDEFINED",
_startTime,
1);
}
/*Instance of ToolDex2Jar; convert the .dex file in .jar file*/
ToolDex2Jar dex2jar = new ToolDex2Jar();
try {
dex2jar.ConvertDex2Jar(_decodedApkPath.concat("/classes.dex"), _decodedApkPath);
} catch(DexException ex){
System.err.println("Unable to convert file classes.dex, writing minimal results.");
this._results = this.setResults(ToolApkParameters.getInstance().getPackage(_decodedApkPath),
path,
apkName,
"UNDEFINED",
false,
ToolApkParameters.getInstance().getHtml(_decodedApkPath),
ToolApkParameters.getInstance().getJavascript(_decodedApkPath),
ToolApkParameters.getInstance().getCSS(_decodedApkPath),
ToolApkParameters.getInstance().getDebuggable(_decodedApkPath),
ToolApkParameters.getInstance().getPermission(_decodedApkPath),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "min"),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "max"),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "target"),
ToolApkParameters.getInstance().getFileSize(path),
_startTime,
1);
}
/*--Instance of ToolJar2Class; extract the content of a .jar--*/
ToolJar2Class jar2class = new ToolJar2Class();
jar2class.ConvertJar2Class(_decodedApkPath + "/classes/ApkDecodeddex2jar.jar", _decodedApkPath);
/*Get the list of Objects Framework*/
this.listOfFramework = FrameworkPool.getInstance().getFramework();
/*For every Framework analyze the Decoded APK; if the Framework match return true*/
for (int i = 0; i < this.listOfFramework.size(); i++) {
if(listOfFramework.get(i).Test(_decodedApkPath)){
/*If the Framework match, set the AnalyzerResult Object*/
this._results = this.setResults(ToolApkParameters.getInstance().getPackage(_decodedApkPath),
path,
apkName,
listOfFramework.get(i).getFrameworkName(),
this.listOfFramework.get(i).checkCordova(),
ToolApkParameters.getInstance().getHtml(_decodedApkPath),
ToolApkParameters.getInstance().getJavascript(_decodedApkPath),
ToolApkParameters.getInstance().getCSS(_decodedApkPath),
ToolApkParameters.getInstance().getDebuggable(_decodedApkPath),
ToolApkParameters.getInstance().getPermission(_decodedApkPath),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "min"),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "max"),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "target"),
ToolApkParameters.getInstance().getFileSize(path),
_startTime,
0);
}
/*If none of the Framework is found, set the AnalyzerResult for Native App*/
else if(!listOfFramework.get(i).Test(_decodedApkPath)){
if(this._results == null){this._results = this.setResults(ToolApkParameters.getInstance().getPackage(_decodedApkPath),
path,
apkName,
"Native",
false,
ToolApkParameters.getInstance().getHtml(_decodedApkPath),
ToolApkParameters.getInstance().getJavascript(_decodedApkPath),
ToolApkParameters.getInstance().getCSS(_decodedApkPath),
ToolApkParameters.getInstance().getDebuggable(_decodedApkPath),
ToolApkParameters.getInstance().getPermission(_decodedApkPath),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "min"),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "max"),
ToolApkParameters.getInstance().getSdkVersion(_decodedApkPath, "target"),
ToolApkParameters.getInstance().getFileSize(path),
_startTime,
0);}
}
}
} catch (ParserConfigurationException | SAXException ex) {
Logger.getLogger(APKAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
}
/*--Write the results in a file--*/
this.Write(CommandLineInterface.getInstance().getWriterFormat(), _csvPath, _counter);
}
public JsElement AnalyzeJsFiles(String _decodedApkPath) throws ParserConfigurationException, SAXException, IOException{
if(_decodedApkPath == null){
this._jsonElement = this.setElement("UNDEFINED", "UNDEFINED");
return this._jsonElement;
}
this._jsonElement = this.setElement(
ToolApkParameters.getInstance().getPackage(_decodedApkPath),
ToolApkParameters.getInstance().getJsFiles(_decodedApkPath)
);
return this._jsonElement;
}
/**
* Set the results
*
* @param _apkpackage
* @param _apkpath
* @param _apkname
* @param _framework
* @param _checkCordova
* @param _html
* @param _javascript
* @param _css
* @param _debuggable
* @param _permissions
* @param _minSdkVersion
* @param _maxSdkVersion
* @param _targetSdkVersion
* @param _fileSize
* @param _startTime
* @param _flag
* @return
*/
private AnalyzerResult setResults( String _apkpackage,
String _apkpath,
String _apkname,
String _framework,
boolean _checkCordova,
int _html,
int _javascript,
int _css,
String _debuggable,
String _permissions,
String _minSdkVersion,
String _maxSdkVersion,
String _targetSdkVersion,
String _fileSize,
long _startTime,
int _flag){
/*Instance of AnalyzerResult*/
AnalyzerResult _settedResults = new AnalyzerResult();
/*Set the Package*/
_settedResults.set_Package(_apkpackage);
/*Set the Path*/
_settedResults.set_APKPath(_apkpath);
/*Set the Name*/
_settedResults.set_APKName(_apkname);
/*Set the Framework used*/
if(_checkCordova && !"Apache Cordova".equals(_framework)){
_settedResults.set_APKBaseFramework("Apache Cordova");
_settedResults.set_APKMainFramework(_framework);
}else if(_checkCordova && "Apache Cordova".equals(_framework)){
_settedResults.set_APKBaseFramework("");
_settedResults.set_APKMainFramework(_framework);
}else if(!_checkCordova){
_settedResults.set_APKBaseFramework("");
_settedResults.set_APKMainFramework(_framework);
}
/*Set the number of html files*/
_settedResults.set_html(_html);
/*Set the number of javascript files*/
_settedResults.set_js(_javascript);
/*Set the number of css files*/
_settedResults.set_css(_css);
/*Set the debuggable parameter*/
_settedResults.set_debuggable(_debuggable);
/*List of Android Permission*/
_settedResults.set_permissions(_permissions);
/*Value of minSdkVersion*/
_settedResults.set_minSdkVersion(_minSdkVersion);
/*Value of maxSdkVersion*/
_settedResults.set_maxSdkVersion(_maxSdkVersion);
/*Value of taregtSdkVersion*/
_settedResults.set_targetSdkVersion(_targetSdkVersion);
/*Set the File Size*/
_settedResults.set_fileSize(_fileSize);
/*Set the Start Time in milliseconds*/
_settedResults.set_startAnalysis(_startTime);
/*Set the Duration Time in milliseconds*/
_settedResults.set_durationAnalysis(System.currentTimeMillis() - _startTime);
/*Set the Decode Flag*/
_settedResults.set_decodeSuccess(_flag);
return _settedResults;
}
private JsElement setElement(String _appId, String _jsList){
/*Instance of JsonElement*/
JsElement _element = new JsElement();
/*Set the App Id*/
_element.set_id(_appId);
/*Set the list of js files*/
_element.set_JsFiles(_jsList);
return _element;
};
/**
* Write the results in a file
*
* @param format Format of result file
* @param outDir Directory of result file
* @param analyzerResult List of results
*/
private void Write(String format, String _csvPath, int _counter) {
/*--Instance of Writer--*/
Writer writer;
/*--Choose the correct writer--*/
writer = FactoryWriter.getInstance().getWriter(format);
/*--Write the results--*/
writer.Write(this._results, _csvPath, _counter);
}
}