从分析一个简单的程序入门joern的用法

官网给了一个简单的教程,这篇文章就是按github上的文档来实践的。

网址:https://github.com/ShiftLeftSecurity/joern/blob/master/docs2/docs/quickstart.mdx
这个工具的作者最近更新频率好高。太强了。

文章目录

    • 获取样本程序
    • 打开joern的shell
    • 导入代码
    • 查询代码属性图
    • 关闭工程
    • 管理工程

获取样本程序

这里用joern作者提供的一个样本程序叫x42

$ git clone [email protected]:ShiftLeftSecurity/x42.git

如果遇到下面这个问题:permission denied (publickey)

从分析一个简单的程序入门joern的用法_第1张图片
可以使用这个链接的方法来解决:https://baijiahao.baidu.com/s?id=1628034638876029219&wfr=spider&for=pc

打开joern的shell

在joern的文件夹下,运行./joern即可打开shell。这个joern shell是基于scala的REPL,REPL类似于python的IDLE。作者提到,如果没用过scala也没关系,仍然可以用joern的命令做到狠多事情。如果很熟悉scala的话,你会感叹它的灵活性。

导入代码

这里就不像上次那篇博客用joern-parse来导入代码,shell里也可以直接使用importCode命令导入代码。

importCode(inputPath="./x42/c", projectName="x42-c")
  • inputPath是代码路径
  • projectName是工程名称,下次用joern就可以直接使用open("x42-c")打开

从分析一个简单的程序入门joern的用法_第2张图片

查询代码属性图

马上就要用joern和代码属性图来分析程序了。joern的程序分析的实现是基于查询语言的,一种专门为代码属性图设计的语言。它包含了代码属性图各种各样节点的有用表示,以及有用的函数来查询它们的属性及它们之间的关系。代码属性图中最顶层的入口点加载在内存中。然后查询语言中的根对象叫cpg,如果我们在shell里输入cpg,只会返回一个id,并没有什么卵用。

在这里插入图片描述

我们首先学习一个有用的技巧,输入cpg.然后按TAB键,会列出cpg可用的方法。

从分析一个简单的程序入门joern的用法_第3张图片
查看关于cpg的描述信息可以输入help.cpg查看描述

res12: String = """
Upon importing code, a project is created that holds an intermediate
representation called `Code Property Graph`. This graph is a composition of
low-level program representations such as abstract syntax trees and control flow
graphs, but it can be arbitrarily extended to hold any information relevant in
your audit, information about HTTP entry points, IO routines, information flows,
or locations of vulnerable code. Think of Ocular and Joern as a CPG editors.

In practice, `cpg` is the root object of the query language, that is, all query
language constructs can be invoked starting from `cpg`. For example,
`cpg.method.l` lists all methods, while `cpg.finding.l` lists all findings of
potentially vulnerable code."""

输入cpg.help可以查看cpg下面各个方法的描述

res13: String = """Available starter steps:
____________________________________________________________________________
 step             | description                                            |
===========================================================================|
 .all             | All nodes of the graph                                 |
 .argument        | All arguments (actual parameters)                      |
 .arithmetic      | All arithmetic operations                              |
 .assignment      | All assignments                                        |
 .call            | All call sites                                         |
 .comment         | All comments in source-based CPGs                      |
 .controlStructure| All control structures (source-based frontends)        |
 .file            | All source files                                       |
 .identifier      | All identifier usages                                  |
 .jumpTarget      | All jump targets, i.e., labels                         |
 .literal         | All literals, e.g., numbers or strings                 |
 .local           | All local variables                                    |
 .member          | All members of complex types (e.g., classes/structures)|
 .metaData        | Meta data blocks for graph                             |
 .method          | All methods                                            |
 .methodRef       | All method references                                  |
 .methodReturn    | All formal return parameters                           |
 .namespace       | All namespaces                                         |
 .parameter       | All parameters                                         |
 .returns         | All actual return parameters                           |
 .tag             | All tags                                               |
 .typeDecl        | All declarations of types                              |
 .types           | All used types                                         |

"""

首先来看一下x42程序:

// X42.c
#include 
#include 
#include 

int main(int argc, char *argv[]) {
  if (argc > 1 && strcmp(argv[1], "42") == 0) {
    fprintf(stderr, "It depends!\n");
    exit(42);
  }
  printf("What is the meaning of life?\n");
  exit(0);
}

这个程序主要分为两个部分:

  1. 程序向STDERR写了什么东西吗?
  2. 如果有个调用写了STDERR,那这个传入x42程序的参数的值是否是有条件限制的呢?

Joern使我们很容易回答这两个问题。回答第一个问题,我们只需要搜索图里属性为CALL的节点,然后使用filter直接选择那些和类型为ARGUMENT且值为stderr的节点有关系的CALL节点。

cpg.call.filter(_.argument.code("stderr")).l 

结果如下:

从分析一个简单的程序入门joern的用法_第4张图片

这个查询告诉我们确实有个地方向STDERR写了点啥玩意。接下来,我们看第二个问题。由于我们分析的程序是用C语言写的,所以我们在代码属性图里搜索main函数里的argcargv参数,这些参数可能会触发写STDERR的调用。基于上一步的查询,现在我们可以使用astParent来移到代码属性图的抽象语法树层面来,而找到更多的关于fprintf调用的信息。移到AST层,只给了我们一个block,并不是很有用:

cpg.call.filter(_.argument.code("stderr")).astParent.l

从分析一个简单的程序入门joern的用法_第5张图片

另外一层给了我们一个if语句,更有用:

cpg.call.filter(_.argument.code("stderr")).astParent.astParent.l

从分析一个简单的程序入门joern的用法_第6张图片

这个ControlStructure里的code属性告诉我们,写STDERR的调用是基于argcargv的。

关闭工程

现在我们完成了分析,让我们关闭工程。不需要担心会丢失数据,因为x42-c工程在importCode的时候就创建完毕了。

close

从分析一个简单的程序入门joern的用法_第7张图片
最后,离开joern,按ctrl-D或者输入exit.

从分析一个简单的程序入门joern的用法_第8张图片

管理工程

输入命令workspace可以看到你之前建立的所有工程,如下图:
从分析一个简单的程序入门joern的用法_第9张图片
这样我们可以查询到各个工程的状态,有时候忘记自己建立的工程的名字,也可以在这里查看到。
接下来你可以使用open("simple")打开这个simple的工程。

你可能感兴趣的:(静态分析,joern)