/* SAAF: A static analyzer for APK files.
* Copyright (C) 2013 syssec.rub.de
*
* 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 de.rub.syssec.saaf.analysis.steps.metadata;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.log4j.Logger;
import de.rub.syssec.saaf.analysis.steps.AbstractStep;
import de.rub.syssec.saaf.application.manifest.permissions.Permission;
import de.rub.syssec.saaf.misc.config.Config;
import de.rub.syssec.saaf.model.APICall;
import de.rub.syssec.saaf.model.APICalls;
import de.rub.syssec.saaf.model.analysis.AnalysisException;
import de.rub.syssec.saaf.model.analysis.AnalysisInterface;
import de.rub.syssec.saaf.model.application.ApplicationInterface;
import de.rub.syssec.saaf.model.application.ClassInterface;
import de.rub.syssec.saaf.model.application.CodeLineInterface;
import de.rub.syssec.saaf.model.application.instruction.InstructionType;
/**
* Read in APICalls.txt during startup and match apicalls onto apk.
*
*/
public class MatchAPICallsStep extends AbstractStep {
private static final Logger logger = Logger
.getLogger(MatchAPICallsStep.class);
/**
* @param enabled
* TODO
*/
public MatchAPICallsStep(Config cfg, boolean enabled) {
super();
this.config = cfg;
this.name = "Match Permissions";
this.description = "Matches the APIcalls onto a set of currently known Permissions.";
this.enabled = enabled;
}
@Override
protected boolean doProcessing(AnalysisInterface analysis)
throws AnalysisException {
logger.info("Searching apicalls of application " + analysis.getApp());
matchCalls(analysis.getApp());
return true;
}
/**
* This method tries to match all the codelines in the app onto known
* permissions based on the android permission map and returns the
* resulting mappings.
*/
public void matchCalls(ApplicationInterface app) {
HashMap<CodeLineInterface, APICall> matchedCalls = new HashMap<CodeLineInterface, APICall>();
List<CodeLineInterface> foundCalls = findCalls(app);
app.setFoundCalls(foundCalls);
for (CodeLineInterface c : foundCalls) {
String className = new String(c.getInstruction()
.getCalledClassAndMethodWithParameter()[0]).replaceAll("/",
".");
for (APICall apiCall : APICalls.getCalls()) {
//check if the called method is matched by this APICall
String method = new String(c.getInstruction().getCalledClassAndMethodWithParameter()[1]);
if (apiCall.getCall().contains(className+ "." + method)) {
// params need to be converted for matching....
// params
String params = new String(c.getInstruction()
.getCalledClassAndMethodWithParameter()[2]);
//build a string from class,method and params and match it agains the APICall
if (apiCall.getCall().contains(className
+ "."
+ new String(
method)
+ "(" + params + ")")) {
/*
* TODO: this needs to also be saved in the smali data
* itself instead of just in this copy
*/
c.setPermission(new Permission(apiCall.getCall()));
matchedCalls.put(c, apiCall);
}
}
}
app.setMatchedCalls(matchedCalls);
}
}
/**
* @param app
* @return
*/
private List<CodeLineInterface> findCalls(ApplicationInterface app) {
List<CodeLineInterface> foundCalls = new ArrayList<CodeLineInterface>();
// better var names
for (ClassInterface smaliClass : app.getAllSmaliClasss(false)) {
for (CodeLineInterface codeline : smaliClass.getAllCodeLines()) {
if (codeline.getInstruction().getType().equals(InstructionType.INVOKE) ||
codeline.getInstruction().getType().equals(InstructionType.INVOKE_STATIC))
{
foundCalls.add(codeline);
}
}
}
return foundCalls;
}
}