由于修改论文的需要(感觉审稿人太难被取悦了),在一篇TFS的论文里看到有介绍codesensor这个工具(奇怪TFS上竟然也能发软件分析和软件安全的文章):
Liu, Shigang, Guanjun Lin, Qing-Long Han, Sheng Wen, Jun Zhang, and Yang Xiang. "DeepBalance: Deep-Learning and Fuzzy Oversampling for Vulnerability Detection." IEEE Transactions on Fuzzy Systems (2019).
这篇文章介绍:一般来讲从源代码中生成AST是non-trivial的,因为需要编译环境的支撑。他们使用了一个叫CodeSensor的工具,基于island grammars [1] 的概念,可以在不需要library支撑的情况下生成AST(Joern其实也用的是这种技术,另外像srcML,应该也是吧?)作者也给出了CodeSensor的GitHub链接:https://github.com/fabsx00/codesensor,我看了一下,已经8年没有更新了。抱着试试看的心理尝试了一下,竟然还可以用!
[1] Moonen, Leon. "Generating robust parsers using island grammars." In Proceedings Eighth Working Conference on Reverse Engineering, pp. 13-22. IEEE, 2001.
这里简单介绍一下在Windows 10,Java 1.8上使用的经验,感觉这个工具兼容性很强呀。
https://github.com/fabsx00/codesensor/issues/1 看到这里有人在求文档,就知道肯定不是我一个人看了论文之后想试试。
首先,在这里https://github.com/fabsx00/codesensor/blob/master/INSTALL,看到作者说是需要Antlr的特殊版本的,如果按照这里面给的网址(https://www.antlr.org/download/antlr-3.4-complete-no-antlrv2.jar),可以预见是下不了的。不过实际上Antlr的所有Jar包都可以在这里下到:https://github.com/antlr/website-antlr3/tree/gh-pages/download
把下载的Jar包放到codesensor目录下,然后借助Git的sh.exe来运行codesensor目录下的build.sh(具体方法参看这里),竟然就可以成功生成CodeSensor.jar了,然后假设我们分析的源码文件是test.c,那么我们只需要运行:
java -jar CodeSensor.jar test.c > output.txt
就可以把codesensor的输出结果存入output.txt这个文件中。我们可以看到其可以将AST生成一个序列化的形式,然后就可以在这个基础上做进一步的分析了。例如针对下面这个c function:
short add (short b){
short a=32767;
if(b>0){
a=a+b;
}
return a;
}
其生成的序列形式是:
SOURCE_FILE 1:0 1:0 0
FUNCTION_DEF 1:0 7:0 1
RETURN_TYPE 1:0 1:0 2 short
TYPE_NAME 1:0 1:0 3 short
LEAF_NODE 1:0 1:0 4 short
FUNCTION_NAME 1:6 1:6 2 add
LEAF_NODE 1:6 1:6 3 add
PARAMETER_LIST 1:10 1:18 2 ( short b )
LEAF_NODE 1:10 1:10 3 (
PARAMETER_DECL 1:11 1:17 3 short b
TYPE 1:11 1:11 4 short
TYPE_NAME 1:11 1:11 5 short
LEAF_NODE 1:11 1:11 6 short
NAME 1:17 1:17 4 b
LEAF_NODE 1:17 1:17 5 b
LEAF_NODE 1:18 1:18 3 )
LEAF_NODE 1:19 1:19 2 {
STATEMENTS 2:1 6:1 2
SIMPLE_DECL 2:1 2:14 3 short a ; a = 32767 ;
VAR_DECL 2:1 2:7 4 short a ; a = 32767
TYPE 2:1 2:1 5 short
TYPE_NAME 2:1 2:1 6 short
LEAF_NODE 2:1 2:1 7 short
NAME 2:7 2:7 5 a
LEAF_NODE 2:7 2:7 6 a
LEAF_NODE 0:0 0:0 5 ;
INIT 2:7 2:7 5 a = 32767
ASSIGN 2:7 2:9 6 a = 32767
LVAL 2:7 2:7 7 a
NAME 2:7 2:7 8 a
LEAF_NODE 2:7 2:7 9 a
ASSIGN_OP 2:8 2:8 7 =
LEAF_NODE 2:8 2:8 8 =
RVAL 2:9 2:9 7 32767
FIELD 2:9 2:9 8 32767
LEAF_NODE 2:9 2:9 9 32767
LEAF_NODE 2:14 2:14 4 ;
SELECTION 3:1 3:8 3
KEYWORD 3:1 3:1 4 if
LEAF_NODE 3:1 3:1 5 if
LEAF_NODE 3:3 3:3 4 (
CONDITION 3:4 3:4 4 b > 0
EXPR 3:4 3:6 5 b > 0
FIELD 3:4 3:4 6 b
LEAF_NODE 3:4 3:4 7 b
REL_OPERATOR 3:5 3:5 6 >
LEAF_NODE 3:5 3:5 7 >
FIELD 3:6 3:6 6 0
LEAF_NODE 3:6 3:6 7 0
LEAF_NODE 3:7 3:7 4 )
STATEMENTS 3:8 5:1 4
LEAF_NODE 3:8 3:8 5 {
STATEMENTS 4:2 4:2 5
EXPR_STATEMENT 4:2 4:7 6 a = a + b ;
EXPR 4:2 4:2 7 a = a + b
ASSIGN 4:2 4:4 8 a = a + b
LVAL 4:2 4:2 9 a
FIELD 4:2 4:2 10 a
LEAF_NODE 4:2 4:2 11 a
ASSIGN_OP 4:3 4:3 9 =
LEAF_NODE 4:3 4:3 10 =
RVAL 4:4 4:6 9 a + b
FIELD 4:4 4:4 10 a
LEAF_NODE 4:4 4:4 11 a
LEAF_NODE 4:5 4:5 10 +
FIELD 4:6 4:6 10 b
LEAF_NODE 4:6 4:6 11 b
LEAF_NODE 4:7 4:7 7 ;
LEAF_NODE 5:1 5:1 5 }
JUMP_STATEMENT 6:1 6:9 3 return a ;
KEYWORD 6:1 6:1 4 return
LEAF_NODE 6:1 6:1 5 return
DESTINATION 6:8 6:8 4 a
EXPR 6:8 6:8 5 a
FIELD 6:8 6:8 6 a
LEAF_NODE 6:8 6:8 7 a
LEAF_NODE 6:9 6:9 4 ;
LEAF_NODE 7:0 7:0 2 }
和文章中相比要更复杂一些,并且感觉有一些冗余。
不过8年前的工具竟然能在现在的系统上正常运行,不得不说是很感人的一件事情了。