CodeQL-CLI工具小白入门
前言
本文目的旨在帮助新入坑小白摸清楚CodeQL工具入门思路,因本人在学习CodeQL中发现相关资料太少,多是英文资料,且中英文社区的入门文章知识太碎片化(很多都是vscode插件版本教程),官方文档也不接地气,故自己写一篇学习和使用心得。
codeql简介
codeql是一个代码扫描工具,大致原理是将项目代码在编译时生成的AST(抽象语法树)存储为代码数据库(可以类比为SQL数据库等,但语法不一样),再通过官方自己的闭源项目将这个代码数据库封装了一些API查询接口给到开发者,开发者可以通过调用API查询的方式查找自己项目存在编码问题 or CVE漏洞 or BUG,具体原理看其他文章,这里不再赘述。
【官方文档】:https://codeql.github.com/docs/
前置知识
- AST抽象语法树(了解)
- 数据库(了解)
遇到了瓶颈再学问题也不大,先用起来
关于CodeQL
CodeQL支持查询的语言与编译器
https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/
支持的平台
https://codeql.github.com/docs/codeql-overview/system-requirements/
踩坑
1、使用部分clang-x编译器的C语言项目,用CodeQL工具查询不到.c文件内容。(未解决)
本文使用版本
版本:CodeQL CLI,CodeQL CLI二进制下载
系统:Linux
查询规则:如下图,codeql github链接
下载以上两个链接内容,一个是CodeQL CLI:查询规则解析器,一个是官方提供的查询套
目录说明
CodeQL CLI目录
可将codeql目录添加到PATH环境变量中,方便使用codeql命令工具
查询套件目录
如上图所示,图①是整体目录结构,包含各个语言的查询测试套及官方文档,项目自带的docs文档是英文的,web版有中文的:https://docs.github.com/zh。图②是C/C++查询测试套(其他语言同样结构),codeql-suites是官方提供的查询套件,可以直接使用。蓝框部分是官方已经写好的一些查询规则(如Critical致命问题、Likely Bugs疑似Bug问题、Security是部分CVE问题)。图③是官方提供的C/C++ API查询接口。
查询规则写在.ql文件中,.qll是共享文件(封装查询,供其他.ql导入使用)
基础命令
- 首先确保你的项目能单独编译成功
执行步骤:
一、创建代码数据库
codeql database create 【/home/.../自定义数据库名】 --language=cpp --source-root=【C/C++项目源码路径】 --command="C/C++项目编译命令"
编译命令大于1行的,可以将编译命令写到.sh文件中
codeql database create 【/home/.../自定义数据库名】 --language=cpp --source-root=【C/C++项目源码路径】 --command="./buildall.sh"
codeql database create说明文档
二、执行查询命令
codeql database analyze 【上面创建的数据库路径】 【查询套件路径/名称】 --format=<format> --output=【结果输出路径/名称】
- 查询套件可以指定.qls查询套件,也可以单独指定一个.ql查询文件使用。
codeql database analyze说明文档
举例:
创建数据库:
codeql database create /home/**/codeql-db/test_c --language=cpp --source-root=/home/**/test_project_c --command=“make”
使用官方套件查询:
codeql database analyze /home/**/codeql-db/test_c /home/**/codeql-main/cpp/ql/src/codeql-suites/cpp-code-scanning.qls --format=csv --output=test_c.csv
查看test_c.csv文件
csv内容格式说明
- 如果没有查询到相关问题代码,.csv文件为空。
自己编写ql查询规则
1、创建ql文件,在codeql-main项目下
2、填写ql固定格式,可以从官方的ql文件下粘贴进来
@id 【查询语言】/自定义命名
上述①为元数据(MateData),是每个ql必须填写的格式
②是导入库
③是编写查询规则,from和where是可选项,select是必选项。select 后必须接两个元素及以上,用逗号分隔。
3、写一个简易查询规则,查询所有格式化字符串
/*** @name my first ql querys rule* @description print out The String* @kind problem* @id cpp/my-ql* @problem.severity warning* @tags security* */import cppfrom FormatLiteral fl
select fl, fl.getFormat().toString() // getFormat()获取格式化字符串,toString()转字符串
查询结果【正确】
测试代码
引子
进程到上面一章节,大部分人很懵逼ql查询规则怎么写的,from后面引用的FormatLiteral是什么东西?哪里来的?getFormat().toString()又是什么鬼?别急,在下方说明
ql查询规则指南
【官方文档】:https://codeql.github.com/docs/
我们主要根据官方文档的右上角部分学习ql查询规则
新手需要学习:
1、什么是元数据:https://codeql.github.com/docs/writing-codeql-queries/metadata-for-codeql-queries/
2、ql语法:https://codeql.github.com/docs/codeql-language-guides/basic-query-for-cpp-code/
3、API使用:https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-cpp/
元数据
省略,看上述文档即可
ql语法
省略,看上述文档即可,其他ql语法属于进阶内容
API使用(最重要,看完这节直接出师)
打开上述API使用文档,你会看到以下一堆让人一脸懵逼的表格,这些其实就是我们from中引用的官方lib库内容。
库类型 | 说明 |
---|---|
Declaration classes | 谓词类型。可以类比为class类型,用于返回类级别的查询内容 |
Statement classes | 语句类型。用于查询if语句、for语句、while语句、switch语句、goto语句等内容 |
Expression classes | 表达式类型。用于查询有=式的、基于AST语法树的子树表达式语句等内容 |
Type classes | 基础数据类型。有int、short、char、long、string、float、double等类型 |
Preprocessor classes | 预处理类型。用于查询宏定义内容 |
Expression classes表达式类型使用说明
1、假设我们需要编写如下查询规则:将printf等各类打印语句中的字符串内容查询出来
请思考我们应该使用下图①和②中的哪个API?
2、根据Example syntax列的样例寻找与我们查询规则相匹配的语句,所以①很明显与printf语句中的字符串相关(如果你不确定,可点击API查看说明)
3、我们点开Formatliteral类说明
4、查看上图①处getFormat()方法使用说明,获得格式化字符串内容,确定这条是我们想要的
5、在ql查询语句引用FormatLiteral库,取别名为fl
import cppfrom FormatLiteral fl
select fl, fl.getFormat().toString()
6、上述代码有用到toString()方法,根据CodeQL官方文档,所有API都需要实现toString()方法,用于输出到查询结果文件中。
为什么没有where语句,在上述官方ql基础语法中有说明如何使用,这里不再赘述,其他where书写方法属于进阶内容。
学完上述内容就已经入门了,有兴趣的再看看官方查询规则(codeql-main项目)中的ql和qll文件是如何书写的,进阶。
自己编写qls查询套件
- 下次一定