使用 soot/FlowDroid 分析 CFG,Infoflow, PDG

Infoflow Analysis

main 函数的定义方式

基本思路

  1. 构造 SetupApplication
  2. 构造 InfoFlowHandler
  3. app.runInfoflow()
  4. printResult()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package playFlowDroid;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import org.xmlpull.v1.XmlPullParserException;
import soot.G;
import soot.Scene;
import soot.jimple.infoflow.Infoflow;
import soot.jimple.infoflow.android.InfoflowAndroidConfiguration;
import soot.jimple.infoflow.android.SetupApplication;
import soot.jimple.infoflow.android.config.SootConfigForAndroid;
import soot.jimple.infoflow.config.IInfoflowConfig;
import soot.jimple.infoflow.data.pathBuilders.DefaultPathBuilderFactory;
import soot.jimple.infoflow.handlers.ResultsAvailableHandler;
import soot.jimple.infoflow.results.InfoflowResults;
import soot.jimple.infoflow.taintWrappers.ITaintPropagationWrapper;
import soot.options.Options;
public class InfoFlowAnalysisDemo {
public static void main(String args[]) {
//File file = new File("/home/gary/dev/testAPKs/crackme.apk");
File file = new File("/home/gary/dev/testAPKs/enriched1.apk");
String apkPath = file.getAbsolutePath();
System.out.println(apkPath);
String platformPath = "/home/gary/dev/android-platforms";
SetupApplication app = new SetupApplication(platformPath, apkPath, null);
try {
app.calculateSourcesSinksEntrypoints("./SourcesAndSinks.txt");
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
PrintWriter wr = null;
try {
wr = new PrintWriter(new File("sootOutput/infoflowHandlerOutput.txt"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
MyInfoFlowHandler myhandler = new MyInfoFlowHandler(wr);
myhandler.setResultFilePath("sootOutput/HandlerAnalysis.xml");
InfoflowResults result = app.runInfoflow(myhandler);
wr.close();
PrintWriter wr2 = null;
try {
wr2 = new PrintWriter(new File("sootOutput/infoflow.txt"));
result.printResults(wr2);
wr2.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

关于InfoflowHandler的定义

实现 ResultsAvailableHandler 的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package playFlowDroid;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import javax.xml.stream.XMLStreamException;
import soot.jimple.infoflow.handlers.ResultsAvailableHandler;
import soot.jimple.infoflow.results.InfoflowResults;
import soot.jimple.infoflow.results.ResultSinkInfo;
import soot.jimple.infoflow.results.ResultSourceInfo;
import soot.jimple.infoflow.results.xml.InfoflowResultsSerializer;
import soot.jimple.infoflow.solver.cfg.IInfoflowCFG;
public class MyInfoFlowHandler implements ResultsAvailableHandler {
private PrintWriter wr = null;
private String resultFilePath = null;
public String getResultFilePath() {
return resultFilePath;
}
public void setResultFilePath(String resultFilePath) {
this.resultFilePath = resultFilePath;
}
public MyInfoFlowHandler() {
this.wr = null;
}
public MyInfoFlowHandler(PrintWriter wr) {
this.wr = wr;
}
private void print(String string) {
try {
System.out.println(string);
if (wr != null)
wr.write(string + "\n");
}
catch (Exception ex) {
// ignore
ex.printStackTrace();
}
}
@Override
public void onResultsAvailable(IInfoflowCFG cfg, InfoflowResults results) {
// TODO Auto-generated method stub
// Dump the results
if (results == null) {
print("No results found.");
} else {
// Report the results
for (ResultSinkInfo sink : results.getResults().keySet()) {
print("Found a flow to sink " + sink + ", from the following sources:");
for (ResultSourceInfo source : results.getResults().get(sink)) {
print("\t- " + source.getSource() + " (in " + cfg.getMethodOf(source.getSource()).getSignature()
+ ")");
if (source.getPath() != null)
print("\t\ton Path " + Arrays.toString(source.getPath()));
}
}
// Serialize the results if requested
// Write the results into a file if requested
if (resultFilePath == null){
System.out.println("result file path is nor defined ... use setResultFilePath()");
}
if (resultFilePath != null && !resultFilePath.isEmpty()) {
InfoflowResultsSerializer serializer = new InfoflowResultsSerializer(cfg);
try {
serializer.serialize(results, resultFilePath);
} catch (FileNotFoundException ex) {
System.err.println("Could not write data flow results to file: " + ex.getMessage());
ex.printStackTrace();
throw new RuntimeException(ex);
} catch (XMLStreamException ex) {
System.err.println("Could not write data flow results to file: " + ex.getMessage());
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
}
}
}

pdg 和 ifg 的 生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package playFlowDroid;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.xmlpull.v1.XmlPullParserException;
import soot.Body;
import soot.BodyTransformer;
import soot.EquivalentValue;
import soot.G;
import soot.PackManager;
import soot.Scene;
import soot.SootMethod;
import soot.Transform;
import soot.jimple.infoflow.android.SetupApplication;
import soot.jimple.toolkits.infoflow.InfoFlowAnalysis;
import soot.jimple.toolkits.infoflow.SimpleMethodInfoFlowAnalysis;
import soot.options.Options;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.graph.HashMutableDirectedGraph;
import soot.toolkits.graph.pdg.HashMutablePDG;
import soot.toolkits.graph.pdg.PDGNode;
public class ProgramDependencyGraphDemo {
public static void main(String args[]) {
File file = new File("/home/gary/dev/testAPKs/crackme.apk");
// File file = new File("/home/gary/dev/testAPKs/enriched1.apk");
String apkPath = file.getAbsolutePath();
System.out.println(apkPath);
String platformPath = "/home/gary/dev/android-platforms";
SetupApplication app = new SetupApplication(platformPath, apkPath, null);
try {
app.calculateSourcesSinksEntrypoints("./SourcesAndSinks.txt");
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
// app.runInfoflow(null);
// setup various arguments
G.reset();
Options.v().set_src_prec(Options.src_prec_apk);
Options.v().set_process_dir(Collections.singletonList(apkPath));
Options.v().set_android_jars(platformPath);
Options.v().set_whole_program(true);
Options.v().set_allow_phantom_refs(true);
Options.v().set_output_format(Options.output_format_jimple);
Scene.v().loadNecessaryClasses();
// check EntryPointCreator
if (app.getEntryPointCreator() == null) {
System.out
.println("EntryPointCreator is null! Make sure you have called calculateSourcesSinksEntryPoints()");
}
// setup analysis entry point
SootMethod entryPoint = app.getEntryPointCreator().createDummyMain();
Options.v().set_main_class(entryPoint.getSignature());
Scene.v().setEntryPoints(Collections.singletonList(entryPoint));
// customize user-defined transform
Transform PDGTransform = new Transform("jtp.mypdg", new BodyTransformer() {
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
G.v().out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
G.v().out.println("Starting User-defined period jtp.mypdg:" + b.getMethod().getSignature());
InfoFlowAnalysis dfa = new InfoFlowAnalysis(true, true, true);
G.v().out.println("!----------dfa Constructed-------------------");
HashMutableDirectedGraph<EquivalentValue> ifg = dfa.getMethodInfoFlowSummary(b.getMethod());
G.v().out.println("!----------InfoFlow graph Generated----------");
HashMutablePDG pdg = new HashMutablePDG(new BriefUnitGraph(b));
G.v().out.println("!----------PDG graph Generated --------------");
// ifg.printGraph();
generateIFG(ifg, b.getMethod().getSignature());
// pdg.printGraph();
generatePDG(pdg, b.getMethod().getSignature());
G.v().out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
}
});
PackManager.v().getPack("jtp").add(PDGTransform);
// run soot pack
PackManager.v().runPacks();
}
// generate Infoflow Graph
public static void generateIFG(HashMutableDirectedGraph<EquivalentValue> ifg, String methodSignature) {
// generate infoflow graph file content
StringBuffer ifgFile = new StringBuffer("");
for (EquivalentValue node : ifg) {
ifgFile.append("Node = " + node + '\n');
ifgFile.append("Preds:" + '\n');
for (EquivalentValue p : ifg.getPredsOf(node)) {
ifgFile.append(" ");
ifgFile.append(p.toString() + '\n');
}
ifgFile.append("Succs:" + '\n');
for (EquivalentValue s : ifg.getSuccsOf(node)) {
ifgFile.append(" ");
ifgFile.append(s.toString() + '\n');
}
}
// write ifgFile
File outFile = new File("sootOutput/" + methodSignature + ".ifg");
try {
if (outFile.exists()) {
if (!outFile.delete()) {
System.err.println("Delete file " + outFile + " failed ....");
}
}
if (outFile.createNewFile()) {
PrintWriter p = new PrintWriter(new FileOutputStream(outFile.getAbsolutePath()));
p.write(ifgFile.toString());
p.close();
} else {
System.err.println("Create file " + outFile + "failed ....");
}
} catch (Exception e) {
e.printStackTrace();
}
}
// generate Program Dependency Graph
public static void generatePDG(HashMutablePDG pdg, String methodSignature) {
// generate Program Dependency Graph file content
StringBuffer pdgFile = new StringBuffer("");
for (PDGNode node : pdg) {
pdgFile.append("Node = " + node + '\n');
pdgFile.append("Preds:" + "\n");
for (PDGNode pred : pdg.getPredsOf(node)) {
DGEdge<PDGNode> edge = new DGEdge<PDGNode>(pred, node);
List<String> labels = pdg.edgeToLabels.get(edge);
pdgFile.append(" " + pred + " [" + labels + "]" + '\n');
}
pdgFile.append("Succs:" + '\n');
for (PDGNode succ : pdg.getSuccsOf(node)) {
DGEdge<PDGNode> edge = new DGEdge<PDGNode>(node, succ);
List<String> labels = pdg.edgeToLabels.get(edge);
pdgFile.append(" " + succ + " [" + labels + "]" + '\n');
}
}
// write ifgFile
File outFile = new File("sootOutput/" + methodSignature + ".pdg");
try {
if (outFile.exists()) {
if (!outFile.delete()) {
System.err.println("Delete file " + outFile + " failed ....");
}
}
if (outFile.createNewFile()) {
PrintWriter p = new PrintWriter(new FileOutputStream(outFile.getAbsolutePath()));
p.write(pdgFile.toString());
p.close();
} else {
System.err.println("Create file " + outFile + "failed ....");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}