简介
CodeQL 是 GitHub 开发的一种静态分析工具,广泛用于代码安全性和质量的检测。CodeQL 允许开发人员使用一种类似于 SQL 的查询语言来分析源代码,并查找潜在的漏洞或代码缺陷。它通过创建一个"代码数据库",使得用户可以查询程序中的各种数据流、控制流、API 调用等信息,从而发现安全漏洞、代码重复或不良编码实践。
CodeQL 支持多种编程语言,包括但不限于:C/C++、Java、JS、Python、Golang、Ruby、Rust、C#等。
环境搭建
下面我们搭建 CodeQL 所需要的环境。
CodeQL CLI
CodeQL CLI 是进行代码分析的核心工具,它允许您创建数据库、运行查询等操作
- Linux
bash
wget https://github.com/github/codeql-cli-binaries/releases/download/v2.20.7/codeql-linux64.zip
配置.bashrc文件,这里我是通过定义别名来使用的:
shell
alias codeql=/tools/binary/codeql/codeql
VSCode插件
扩展插件搜索 codeql 插件,然后安装即可。

点击插件自动更新右边的齿轮按钮设置插件一些参数,Code QL>Cli:Execuble Path表示我们的 CodeQL CLI 路径,这里我们设置为我们的 codeql 目录下的 codeql 路径。

工作区
下载工作区
shell
git clone --recursive https://github.com/github/vscode-codeql-starter
从文件打开工作区。
创建数据库
接下来我们需要为要审计的项目创建一个 CodeQL 数据库,以便进行查询。
假如我们要审计以下test.c文件:
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char buffer[16];
strcpy(buffer, input); // 无边界检查
printf("Copied: %s\n", buffer);
return 0;
}
使用以下命令来创建:
shell
codeql database create ./test-db --language=cpp --command="gcc test.c -o test"
codeql database create:创建数据库;test-db:指定数据库创建成功后存放在test-db目录下;language:指定语言,这里选择cpp即 C++;command:编译指令,如果使用 make 编译那么就将 make 语句写在这里。
选择数据库
在 VSCode 中选择数据库。

之后我们就可以编写ql语句文件,然后运行在数据库中查询就可以了。而且我们不仅可以自己编译数据库,还可以使用别人编译好的数据库。
QL查询语句
CodeQL 所使用的查询语言是一种类 SQL 的语法。用于查找每种受支持语言最相关和最有趣的问题。您还可以编写自定义查询来查找与您自己的项目相关的问题。
重要的查询类型包括:
- 警报查询:突出显示代码中特定位置的问题的查询。
- 路径查询:描述代码中源和接收器之间的信息流的查询。
基本结构
q
import <语言库> // 如 java, cpp, python
from <变量声明>
where <条件表达式>
select <输出结果>
- import - 导入库
codeql 为每种语言提供了大量库,包含类、谓词和辅助工具。
import cpp
cpp 模块会自动导入所有核心 C/C++ 库,使你能访问整个抽象语法树(AST)、数据流、控制流等类和谓词。
- from - 变量声明
用于声明要操作的元素(如函数、表达式、语句等)。
示例:
sql
from Function f, Parameter p
- where - 过滤条件
用于描述逻辑约束,筛选出满足条件的变量。
常见构造:逻辑运算(and, or, not),聚合与比较(=, !=, <, >=),调用谓词(isPublic(), hasName()),库提供的数据流、控制流谓词。
sql
where f.getName() = "main"
- select - 输出结果
定义最终展示的内容。
查询输出格式:
q
select element,string
element 是由查询标识的代码元素,用于定义警报的显示位置;string 表示一条消息,其中还可以包含连接和占位符,说明生成警报的原因。
示例:
sql
select c, "Found dangerous call here: " + c.getTarget().getName()
基础抽象类
| 类名 | 描述 | 子类示例 |
|---|---|---|
Element |
所有 CodeQL 元素基类 | --- |
AstNode |
抽象语法树节点 | Stmt, Expr, Decl |
Stmt |
所有语句 | IfStmt, SwitchStmt, ReturnStmt |
Expr |
所有表达式 | CallExpr, BinaryExpr |
Decl |
所有声明 | Function, VariableDecl |
Type |
所有类型 | PrimitiveType, PointerType |
声明类
- 变量声明
| CodeQL 类 | 示例 |
|---|---|
GlobalVariable |
int g; |
NamespaceVariable |
namespace ns { int x; } |
MemberVariable |
class C{int x;}; |
示例:查找所有类型为std::string的类成员变量。
sql
from MemberVariable v
where v.getType().getName() = "string"
select v
- 函数声明
| CodeQL 类 | 示例 |
|---|---|
Function |
void foo() |
VirtualFunction |
virtual void f() |
FormattingFunction |
printf() |
Parameter |
void foo(int param) |
查找静态函数:
sql
from Function f
where f.isStatic()
select f, "static function"
查找从未调用的函数:
sql
from Function f
where not exists(FunctionCall fc | fc.getTarget() = f)
select f, "unused function"
- 模板与类
| CodeQL 类 | 示例 |
|---|---|
ClassDecl |
class C {...} |
StructDecl |
struct S{...} |
ClassTemplateInstantiation |
vector<int> |
TemplateParameter |
typename T |
Constructor |
ClassName() |
Destructor |
~ClassName() |
TemplateDecl |
template<typename T> |
TemplateInstantiation |
vector<int> |
TemplateParameter |
typename T |
查找所有vector<int>实例化点:
sql
from ClassTemplateInstantiation c
where c.getTemplate().getName() = "vector"
select c
语句类
- 控制流语句
| CodeQL 类 | 示例 |
|---|---|
IfStmt |
if(x) |
IfElseStmt |
if(x) else y |
SwitchStmt |
switch(x) |
WhileStmt |
while (x) |
DoStmt |
do {...} while(x) |
ForStmt |
for(int i=0;i<n;i++) |
RangeBasedForStmt |
for(auto& x : v) |
查找空if语句:
sql
from IfStmt ifs, BlockStmt blk
where ifs.getThen() = blk and blk.getNumStmt() = 0 and not ifs.hasElse()
select ifs, "redundant if"
- 跳转语句
| CodeQL 类 | 示例 |
|---|---|
BreakStmt |
break; |
ContinueStmt |
continue; |
ReturnStmt |
return x; |
GotoStmt |
goto label; |
- 复合语句
| CodeQL 类 | 示例 |
|---|---|
CompoundStmt |
{ ... } |
BlockStmt |
一组语句 |
表达式类
- 运算符
| CodeQL 类 | 示例 |
|---|---|
BinaryExpr |
a + b |
UnaryExpr |
!x |
AssignExpr |
a = b |
CallExpr |
foo() |
MemberAccess |
obj.a |
ArrayAccess |
arr[i] |
查找调用sprintf的位置且 format 字符串不是字面量(格式化字符串漏洞):
sql
from FunctionCall fc
where fc.getTarget().getName() = "sprintf"
and not fc.getArgument(1) instanceof StringLiteral
select fc, "sprintf with non-literal format string"
- 字面量
| 类 | 示例 |
|---|---|
IntegerLiteral |
42 |
StringLiteral |
"abc" |
FloatingLiteral |
3.14 |
查找右边为 0 的赋值:
sql
from AssignExpr e
where e.getRValue().getValue().toInt() = 0
select e
- 特殊表达式
| 类 | 示例 |
|---|---|
NewExpr |
new int[x] |
DeleteExpr |
delete p |
LambdaExpr |
[&](int x){...} |
其它元素
- 类型类
| CodeQL 类 | 示例 |
|---|---|
PrimitiveType |
int |
PointerType |
int* |
ReferenceType |
int& |
ArrayType |
int[10] |
ClassType |
std::string |
- 预处理器类
| CodeQL 类 | 示例 |
|---|---|
Macro |
#define X 1 |
MacroInvocation |
X |
IncludeDirective |
#include <stdio.h> |
自动化分析
使用 CodeQL 官方的 C/C++ 安全查询包分析目标数据库。
shell
codeql database analyze test-db codeql/cpp-queries --format=sarifv2.1.0 --output=result.sarif
在 VSCode 中安装 SARIF Viewer 插件分析 result.sarif 文件。

Reference
CodeQL 入门和基本使用
适用于 C 和 C++ 的 CodeQL 库 --- CodeQL[原创\]CodeQL入门 - U-Boot Challenge-二进制漏洞-看雪论坛-安全社区\|非营利性质技术交流社区](https://bbs.kanxue.com/thread-277560.htm#msg_header_h1_3)