Skip to content

Improve FlowDroid to support Field Sources(develop branch) #385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,12 @@
******************************************************************************/
package soot.jimple.infoflow.android;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.stream.XMLStreamException;

import heros.solver.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParserException;

import heros.solver.Pair;
import soot.G;
import soot.Main;
import soot.PackManager;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Unit;
import soot.*;
import soot.jimple.Stmt;
import soot.jimple.infoflow.AbstractInfoflow;
import soot.jimple.infoflow.IInfoflow;
Expand Down Expand Up @@ -108,6 +86,11 @@
import soot.util.HashMultiMap;
import soot.util.MultiMap;

import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.IOException;
import java.util.*;

public class SetupApplication implements ITaintWrapperDataFlowAnalysis {

private final Logger logger = LoggerFactory.getLogger(getClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@
import org.slf4j.LoggerFactory;

import soot.jimple.infoflow.android.data.AndroidMethod;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinitionProvider;
import soot.jimple.infoflow.sourcesSinks.definitions.MethodSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.SourceSinkType;
import soot.jimple.infoflow.data.SootFieldAndClass;
import soot.jimple.infoflow.sourcesSinks.definitions.*;

/**
* Parser for the permissions to method map of Adrienne Porter Felt.
Expand All @@ -44,6 +42,7 @@ public class PermissionMethodParser implements ISourceSinkDefinitionProvider {
private final Logger logger = LoggerFactory.getLogger(getClass());

private Map<String, AndroidMethod> methods = null;
private Map<String, SootFieldAndClass> fields = null;
private Set<ISourceSinkDefinition> sourceList = null;
private Set<ISourceSinkDefinition> sinkList = null;
private Set<ISourceSinkDefinition> neitherList = null;
Expand All @@ -56,6 +55,8 @@ public class PermissionMethodParser implements ISourceSinkDefinitionProvider {
// "^<(.+):\\s(.+)\\s?(.+)\\s*\\((.*)\\)>\\s+(.*?)(\\s+->\\s+(.*))?+$";
private final String regexNoRet = "^<(.+):\\s*(.+)\\s*\\((.*)\\)>\\s*(.*?)?(\\s+->\\s+(.*))?$";

private final String fieldRegex = "^<(.+):\\s*(.+)\\s+([a-zA-Z_$][a-zA-Z_$0-9]*)\\s*>\\s*(.*?)(\\s+->\\s+(.*))?$";

public static PermissionMethodParser fromFile(String fileName) throws IOException {
PermissionMethodParser pmp = new PermissionMethodParser();
pmp.readFile(fileName);
Expand Down Expand Up @@ -119,30 +120,39 @@ public Set<ISourceSinkDefinition> getSinks() {
}

private void parse() {
fields = new HashMap<>(INITIAL_SET_SIZE);
methods = new HashMap<>(INITIAL_SET_SIZE);
sourceList = new HashSet<>(INITIAL_SET_SIZE);
sinkList = new HashSet<>(INITIAL_SET_SIZE);
neitherList = new HashSet<>(INITIAL_SET_SIZE);

Pattern p = Pattern.compile(regex);
Pattern pNoRet = Pattern.compile(regexNoRet);
Pattern fieldPattern = Pattern.compile(fieldRegex);

for (String line : this.data) {
if (line.isEmpty() || line.startsWith("%"))
continue;
Matcher m = p.matcher(line);
if (m.find()) {
createMethod(m);
} else {
Matcher mNoRet = pNoRet.matcher(line);
if (mNoRet.find()) {
createMethod(mNoRet);
} else
logger.warn(String.format("Line does not match: %s", line));
//match field regex
Matcher fieldMatch = fieldPattern.matcher(line);
if (fieldMatch.find()) {
createField(fieldMatch);
}else{
//match method regex
Matcher m = p.matcher(line);
if (m.find()) {
createMethod(m);
} else {
Matcher mNoRet = pNoRet.matcher(line);
if (mNoRet.find()) {
createMethod(mNoRet);
} else
logger.warn(String.format("Line does not match: %s", line));
}
}
}

// Create the source/sink definitions
// Create the source/sink definitions[for method]
for (AndroidMethod am : methods.values()) {
MethodSourceSinkDefinition singleMethod = new MethodSourceSinkDefinition(am);

Expand All @@ -153,6 +163,18 @@ private void parse() {
if (am.getSourceSinkType() == SourceSinkType.Neither)
neitherList.add(singleMethod);
}

// Create the source/sink definitions[for field]
for (SootFieldAndClass sootField : fields.values()) {
FieldSourceSinkDefinition fieldDefinition = new FieldSourceSinkDefinition(sootField.getSignature());

if (sootField.getSourceSinkType().isSource())
sourceList.add(fieldDefinition);
if (sootField.getSourceSinkType().isSink())
sinkList.add(fieldDefinition);
if (sootField.getSourceSinkType() == SourceSinkType.Neither)
neitherList.add(fieldDefinition);
}
}

private AndroidMethod createMethod(Matcher m) {
Expand Down Expand Up @@ -254,4 +276,41 @@ public Set<ISourceSinkDefinition> getAllMethods() {
sourcesSinks.addAll(neitherList);
return sourcesSinks;
}

private SootFieldAndClass createField(Matcher m) {
SootFieldAndClass sootField = parseField(m);
SootFieldAndClass oldField = fields.get(sootField.getSignature());
if (oldField != null) {
oldField.setSourceSinkType(oldField.getSourceSinkType().addType(sootField.getSourceSinkType()));
return oldField;
} else {
fields.put(sootField.getSignature(), sootField);
return sootField;
}
}

private SootFieldAndClass parseField(Matcher m) {
assert (m.group(1) != null && m.group(2) != null && m.group(3) != null && m.group(4) != null);
SootFieldAndClass sootFieldAndClass;
int groupIdx = 1;

// class name
String className = m.group(groupIdx++).trim();

// field type
String fieldType = m.group(groupIdx++).trim();

// field name
String fieldName = m.group(groupIdx++).trim();

// SourceSinkType
String sourceSinkTypeString = m.group(groupIdx).replace("->", "").replace("_","").trim();
SourceSinkType sourceSinkType = SourceSinkType.fromString(sourceSinkTypeString);

// create Field signature
sootFieldAndClass = new SootFieldAndClass(fieldName, className, fieldType, sourceSinkType);

return sootFieldAndClass;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package soot.jimple.infoflow.android.test.droidBench;

import org.junit.Assert;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParserException;
import soot.jimple.infoflow.results.InfoflowResults;

import java.io.IOException;

public class FieldSourceTest extends JUnitTests {

@Test
public void runTestFlowSensitivity1() throws IOException, XmlPullParserException {
InfoflowResults res = analyzeAPKFile("FieldSource/FieldSourceTest.apk");
Assert.assertNotNull(res);
}
}
114 changes: 114 additions & 0 deletions soot-infoflow/src/soot/jimple/infoflow/data/SootFieldAndClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package soot.jimple.infoflow.data;

import soot.jimple.infoflow.sourcesSinks.definitions.SourceSinkType;

public class SootFieldAndClass {

private final String fieldName;
private final String className;
private final String fieldType;
private Boolean isStatic;
private SourceSinkType sourceSinkType = SourceSinkType.Undefined;

private int hashCode = 0;
private String signature = null;

public SootFieldAndClass(String fieldName, String className, String fieldType, SourceSinkType sourceSinkType) {
this.fieldName = fieldName;
this.className = className;
this.fieldType = fieldType;
this.sourceSinkType = sourceSinkType;
}

public String getFieldName() {
return fieldName;
}

public String getClassName() {
return className;
}

public String getFieldType() {
return fieldType;
}

public SourceSinkType getSourceSinkType() {
return sourceSinkType;
}

public void setSourceSinkType(SourceSinkType sourceSinkType) {
this.sourceSinkType = sourceSinkType;
}

public Boolean getStatic() {
return isStatic;
}

public void setStatic(Boolean aStatic) {
isStatic = aStatic;
}

public String getSignature() {
if (signature != null)
return signature;

StringBuilder sb = new StringBuilder(10 + this.className.length() + this.fieldType.length()
+ this.fieldName.length());
sb.append("<");
sb.append(this.className);
sb.append(": ");
if (!this.fieldType.isEmpty()) {
sb.append(this.fieldType);
sb.append(" ");
}
sb.append(this.fieldName);
sb.append(">");
this.signature = sb.toString();

return this.signature;
}

public void setSignature(String signature) {
this.signature = signature;
}

public int getHashCode() {
return hashCode;
}

@Override
public int hashCode() {
if (this.hashCode == 0)
this.hashCode = this.fieldName.hashCode() + this.className.hashCode() * 5;
return this.hashCode;
}

@Override
public boolean equals(Object another) {
if (!(another instanceof SootFieldAndClass))
return false;
SootFieldAndClass otherMethod = (SootFieldAndClass) another;

if (!this.fieldName.equals(otherMethod.fieldName))
return false;
if (!this.className.equals(otherMethod.className))
return false;
if (!this.fieldType.equals(otherMethod.fieldType))
return false;
return true;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("<");
sb.append(className);
sb.append(": ");
sb.append(fieldType);
sb.append(" ");
sb.append(fieldName);
sb.append(">");
return sb.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,19 @@ public SourceSinkType addType(SourceSinkType toAdd) {
return this;
}

public static SourceSinkType fromString(String sourceSinkTypeString) {
switch (sourceSinkTypeString) {
case "NONE":
return Neither;
case "SOURCE":
return Source;
case "SINK":
return Sink;
case "BOTH":
return Both;
}
//return Undefined;
throw new RuntimeException("[SourceSinkType.sourceSinkTypeString]error in target definition: " + sourceSinkTypeString);
}

}