这里记录了一些joern常用的查询操作,以防我自个忘记以前是怎么操作的了…
写在前面
这些天才发现,最有用的api是.help
命令。比如你想知道cpg.method
下面有什么有用的api,使用cpg.method.help
,就可以发现列出了关于这个method后面相关的api的描述。同理,只要你想知道什么方法下有什么可以调用的api,使用.help
方法,基本上就可以了解了。
简单的查询
先列几个作者在华为演讲ppt里列的几个基本查询:
PPT可以在这里下载:https://fabs.codeminers.org/talks/2019-joern.pdf
序号 | 语句 | 功能 |
---|---|---|
1 | cpg.method.where(_.parameter.size > 4).l | 列出所有参数个数大于4的方法 |
2 | cpg.method.where(_.controlStructure.size > 4).l | 列出所有条件语句个数大于4个的方法 |
3 | cpg.method.where(_.numberOfLines >= 500).l | 列出代码行数超过500的方法 |
4 | cpg.method.where(_.ast.isReturn.l.size > 1) | 列出有多个返回语句的方法 |
5 | cpg.method.where(.depth(.isControlStructure) > 3).name.l | 列出嵌套分支深度大于3的方法 |
6 | Cpg.method.external.name.l.distinct.sorted | 程序中使用的所有外部方法 |
7 | cpg.call(”str.*”).code.l | 所有关于str的调用 |
8 | cpg.call(“str.*”).method.name.l | 所有调用str的方法 |
9 | cpg.call(“sprintf”).argument(2).filterNot(_.isLiteral).code.l | 查看参数:sprintf的第二个参数不是文字 |
10 | cpg.method.map(x => (x.start.callIn.size,x.name)).l.sorted.reverse.take( 100) | 按caller的数目对方法进行排序(取100个) |
11 | val src = cpg.call(“malloc”).filter(.argument (1).arithmetics ).l cpg .call(“memcpy”).whereNonEmpty { call => call .argument (1).reachableBy (src.start ) .filterNot (.argument (1).codeExact (call.argument (3).code)) } | 找malloc的调用,其中第一个参数包含算术表达式;memcpy的第一个参数是buffer,第三个参数不等于malloc的第一个参数 |
稍微复杂的查询
joern的文档更新了,提到了astChildren和astParent的用法,感觉新的操作增加了!
查询printf函数打印了什么信息,可以用astChildren
这个接口,遍历ast树的子节点。
cpg.call.name("printf").astChildren.isLiteral.code.l
或者反过来,知道了字符串的信息,看是什么函数调用了它。
cpg.literal.where(_.code == "\"What is the meaning of life?\\n\"").astParent.isCall.l
repeat
和until
也是很有用的接口,可以实现自动化地遍历节点。比如,要找常量42的详细信息,可以从main函数一直遍历ast的子节点,如下面命令所示:
cpg.method.name("main").repeat(_.astChildren).until(_.isLiteral.code("42")).l
平常用的查询
找赋值语句,并且提取出它的语句,文件路径,赋值语句行号,参数这些信息。下面的代码看起来有些复杂,其实主要步骤就三个,选择初始节点,遍历查询,提取信息。
cpg.call.where{ c=>
c.code.contains("++")||c.code.contains("--") || c.name.contains("assignment") }.
map( x=> (
x.node.code,
x.location.filename,
x.argument(1).code,
x.argument(2).code,
x.lineNumber)).l
运行结果:
找到所有的条件控制语句
cpg.method("foo").ast.isControlStructure.code.l
后续看到什么有用的再慢慢补充吧…