Skip to content

Commit b5b5a09

Browse files
committed
update cha.dl and add docs/cha-optimization.md
1 parent bf7f615 commit b5b5a09

3 files changed

Lines changed: 138 additions & 0 deletions

File tree

docs/cha-optimization.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# cha-optimization
2+
3+
## 实现&分析
4+
在实际测试中发现,如果路径过长会出现neo4j查询不出来的情况,还需要对CHA进行进一步优化。优化方向有两个:
5+
6+
1. 尽可能减少节点的数量
7+
2. 尽可能减少环路的出现
8+
9+
目前采取的遍历算法,有点类似于从entry出发,进行广度优先遍历(bfs)。实际的节点表现可能是这样的
10+
11+
![callgraph-example](./images/callgraph-entry-bfs.png)
12+
13+
从这张图可以看出,有用的节点其实是标有颜色的那些节点,其中绿色表示entry,红色表示sink。但是在导入的时候其他节点也会被导入。
14+
15+
我们可以通过从sink向上回溯,筛选出那些能够到达sink的节点,就可以把这些有颜色的节点筛选出来。
16+
17+
定义SinkReachable(method:Method, sink:Method, step:number) 表示 method 经过 step步能调用到 sink 。
18+
19+
那么久可以根据CallGraph(insn, caller, callee) 一步步向上回溯了,具体规则见
20+
21+
```dl
22+
// 初始化 sink 到 sink 为 0
23+
SinkReachable(sink, sink, 0) :-
24+
SinkMethod(sink).
25+
26+
// 如果caller 调用 了 callee
27+
// 且 callee n 步到 sink
28+
// 那么能够推导出 caller n+1 步 能到 sink
29+
SinkReachable(caller, sink, n+1) :-
30+
n < MAXSTEP,
31+
SinkReachable(callee, sink, n),
32+
CallGraph(_, caller, callee).
33+
```
34+
35+
更近一步我们还可以寻找从entry 到 sink 的最短路径
36+
37+
定义 ShortestPathToSink(caller:Method, sink:Method, step:number) 表示caller 经过最短step步 到达 sink
38+
39+
```dl
40+
// 筛选出entry 到 sink 的 最短长度 n
41+
ShortestPathToSink(entry, sink, n) :-
42+
n = min step : {SinkReachable(entry, sink, step)},
43+
SinkMethod(sink),
44+
EntryMethod(entry).
45+
46+
// 如果caller 到 sink 最短距离 为 n
47+
// 且 calle 到 sink 的距离为n-1
48+
// 且 caller 调用 callee
49+
// 那么可以推导出 callee 到 sink 的 最短距离为 n-1
50+
ShortestPathToSink(callee, sink, n-1) :-
51+
n < MAXSTEP + 1,
52+
ShortestPathToSink(caller, sink, n),
53+
SinkReachable(callee, sink, n-1),
54+
CallGraph(_, caller, callee).
55+
```
56+
57+
这里稍微解释一下
58+
59+
```dl
60+
ShortestPathToSink(entry, sink, n) :-
61+
n = min step : {SinkReachable(entry, sink, step)},
62+
SinkMethod(sink),
63+
EntryMethod(entry).
64+
```
65+
66+
大概的执行顺序是
67+
68+
1. 先从EntryMethod 选出一个 entry
69+
2. 从SinkMethod 选出一个 sink
70+
3. 然后从SinkReachable 找出第一个值为entry 第二个值为sink的数据,从这些数据中选出最小的step
71+
72+
这种就找到entry到sink的最短距离为n
73+
74+
## 使用方法
75+
76+
通过宏定义 可以配置不同的优化级别
77+
78+
1. `#define CHAO 1` 返回的是所有能到sink的节点
79+
2. `#define CHAO 2` 返回的是entry到sink最短路径上的节点
80+
3. 如果没有 CHAO 宏定义 则 返回的是entry在MAXSTEP之内能到达的所有节点
81+
82+
使用样例
83+
84+
[ctf-buggyLoader.dl](../example/ctf-buggyLoader.dl)
85+
86+
```dl
87+
#define MAXSTEP 5
88+
#define CHAO 2
89+
90+
#include "inputDeclaration.dl"
91+
#include "utils.dl"
92+
#include "cha.dl"
93+
94+
95+
.decl NonParamPublicMethod(method:Method, class:Class)
96+
.output NonParamPublicMethod
97+
98+
// 声明sink
99+
SinkDesc("exec", "java.lang.Runtime").
100+
SinkDesc("<init>", "java.lang.ProcessBuilder").
101+
SinkDesc("start", "java.lang.ProcessImpl").
102+
SinkDesc("loadClass", "java.lang.ClassLoader").
103+
SinkDesc("defineClass", "java.lang.ClassLoader").
104+
SinkDesc("readObject", "java.io.ObjectInputStream").
105+
SinkDesc("readExternal", "java.io.ObjectInputStream").
106+
107+
// 声明入口方法
108+
EntryMethod(method),
109+
Reachable(method, 0),
110+
NonParamPublicMethod(method, class) :-
111+
MethodInfo(method, simplename, _, class, _, _, arity),
112+
MethodModifier("public", method),
113+
simplename != "<init>",
114+
arity = 0,
115+
SubClass(class, "java.io.Serializable").
116+
117+
.output SinkMethod
118+
```
119+
120+
## 优化效果
121+
122+
以ctf-buggyLoader为例
123+
124+
1. 无 CHAO 宏定义
125+
- Nodes: 68561
126+
- Relations: 1080201
127+
- Time 1:39.87 s
128+
2. `#define CHAO 1`
129+
- Nodes: 3864
130+
- Relations: 55736
131+
- Time: 20.859 s
132+
3. `#define CHAO 2`
133+
- Nodes: 722
134+
- Relations: 3672
135+
- Time: 20.134 s
136+
137+
优化效果还行,之所以优化之后的时间更短,我猜测可能是IO更浪费时间,因为不优化的CallNode.csv 和 CallEdge.csv 都上百M了 。
30.9 KB
Loading

logic/cha.dl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ SinkReachable(caller, sink, n+1) :-
7373

7474
ShortestPathToSink(entry, sink, n) :-
7575
n = min step : {SinkReachable(entry, sink, step)},
76+
SinkMethod(sink),
7677
EntryMethod(entry).
7778

7879
ShortestPathToSink(callee, sink, n-1) :-

0 commit comments

Comments
 (0)