CodeQL初识 — java分析的简单学习
这里的内容多为文档的译文, 理解不通的地方建议去文章附加的链接看文档原文。
找出定义了invoke
函数的类
import java
from Method method
where method.hasName("invoke")
select method.getName(), method.getDeclaringType()
一些java常用的ql类库
我们经常会用到的ql类库大体如下:
名称 解释
Method 方法类,Method method表示获取当前项目中所有的方法
MethodAccess 方法调用类,MethodAccess call表示获取当前项目当中的所有方法调用
Parameter 参数类,Parameter表示获取当前项目当中所有的参数节级元素
查询结构
在初始 import
声明,这个简单的查询包括三个部分,提供类似的目的,在那里,并选择部分的SQL query.
查询部分 | 目的 | 详细信息 |
---|---|---|
import java |
进口的标准CodeQL库Java。 | 每个查询开始与一个或更多 import 发言。 |
from IfStmt ifstmt, Block block |
定义的变量,用于查询。 声明的形式: <type> <variable name> |
我们使用: 一个 IfStmt 变量 if 报表 一个 Block 可变的那块 |
where ifstmt.getThen() = block and block.getNumStmt() = 0 |
限定条件的变量。 | ifstmt.getThen() = block 涉及的两个变量。 这块必须是的 then 分 if 发言。 block.getNumStmt() = 0 国这块必须是空(即,它包含没有发言). |
select ifstmt, "This 'if' statement is redundant." |
界定了什么报告对每个匹配。 select 报表的查询是用来寻找实例的穷人的编码做法总是在形式: select <program element>, "<alert message>" |
报告得到的 if 发言串解释的问题。 |
节级元素
https://codeql.github.com/docs/writing-codeql-queries/query-help-files/
感觉这里其实对应的就是各个语言的文件目录结构(不知道对不对)
Element | Attributes | Children | Purpose of section |
---|---|---|---|
example |
None | 任何框元 | 证明一个例子码违反规则的实施通过查询与指导如何解决它。 默认的标题。 |
fragment |
None | 任何框元 | 见" 查询,帮助纳入 "下面。 None标题。 |
hr |
None | None | 一水平的规则。 没有标题。 |
include |
src 查询帮助的文件。 |
None | 包括一个查询帮助的文件在位置的这种元件。 见" 查询,帮助纳入 "下面。 没有标题。 |
overview |
None | 任何框元 | 概述目的的查询。 通常这是第一个部分的查询文件。 None标题。 |
recommendation |
None | 任何框元 | 建议如何解决任何警告,这种查询的标识。 默认的标题。 |
references |
None | li 元素 |
参考列表。 通常这是最后一个部分的查询文件。 默认的标题。 |
section |
title 标题部分 |
任何框元 | 一般用途的部分的标题定义的 title 属性。 |
semmleNotes |
None | 任何框元 | 实施事项有关的查询。 本部分仅用于查询,执行规则的定义的第三方。 默认的标题。 |
Java 的 CodeQL 库
库类总结
标准 Java 库中最重要的类可以分为五个主要类别:
- 用于表示程序元素的类(例如类和方法)
- 表示 AST 节点的类(例如语句和表达式)
- 表示元数据的类(例如注释和评论)
- 计算度量的类(例如圈复杂度和耦合)
- 用于导航程序调用图的类
我们将依次讨论这些,简要描述每个类别中最重要的类。
程序元素
这些类代表命名的程序元素:包(Package)、编译单元(CompilationUnit)、类型(Type)、方法(Method)、构造函数(Constructor)和变量(Variable)。
它们的共同超类是 Element,它提供了通用的成员谓词来确定程序元素的名称并检查两个元素是否相互嵌套。
引用可能是方法或构造函数的元素通常很方便。 Callable 类是 Method 和 Constructor 的通用超类,可用于此目的。
类型
Class Type 有许多子类来表示不同类型的类型:
- PrimitiveType 表示原始类型,即 boolean、byte、char、double、float、int、long、short 之一; QL 还将 void 和
(空文字的类型)分类为原始类型。 - RefType 表示一个引用(即非原始)类型;它又具有几个子类:
- Class 代表一个Java 类。
- 接口代表一个Java接口。
- EnumType 表示 Java 枚举类型。
- Array 表示 Java 数组类型。
引用类型也根据其声明范围进行分类:
- TopLevelType 表示在编译单元的顶层声明的引用类型。
- NestedType 是在另一个类型中声明的类型。
几个对Class
进行分析分类之后得到的不同类
- TopLevelClass 表示在编译单元的顶层声明的类。
- NestedClass 表示在另一个类型中声明的类,例如:
- LocalClass,它是在方法或构造函数中声明的类。
- AnonymousClass,这是一个匿名类。
泛型
还有几个 Type 的子类用于处理泛型类型。
GenericType 是 GenericInterface 或 GenericClass。
泛型的内容还有很多,但是在这里就不说了,感兴趣的去爬文档: https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-java/
变量
Class Variable 表示Java 意义上的变量,它要么是类的成员字段(无论是否静态),要么是局部变量,要么是参数。因此,有满足这些特殊情况的三个子类:
- Field 表示一个 Java 字段。
- LocalVariableDecl 表示一个局部变量。
- Parameter 表示方法或构造函数的参数。
抽象语法树
此类别中的类表示抽象语法树 (AST) 节点,即语句(Stmt 类)和表达式(Expr 类)。有关标准 QL 库中可用的表达式和语句类型的完整列表,请参阅“用于处理 Java 程序的抽象语法树类”。
Expr 和 Stmt 都提供成员谓词来探索程序的抽象语法树:
- Expr.getAChildExpr 返回给定表达式的子表达式。
- Stmt.getAChild 返回直接嵌套在给定语句中的语句或表达式。
- Expr.getParent 和 Stmt.getParent 返回 AST 节点的父节点。
例如,以下查询查找其父级为 return 语句的所有表达式:
import java
from Expr e
where e.getParent() instanceof ReturnStmt
select e
元数据
注释,类 Annotatable
是一个超类的所有程序要素,可以附加说明。 这包括包装,标类型、领域、方法、构造和地方变量声明。 对于每一个这样的元件,其谓 getAnAnnotation
可以让你找回的任何注解元。 例如,以下的查询发现的所有注释上造:
import java
from Constructor c
select c.getAnAnnotation()
➤ 看到这个查询的控制台上LGTM.com . 的LGTM.com 演示项目所使用的注释,可以看到例子,它们被用来抑制警告,并记号码为已过时。
这些注释表示,由类 Annotation
. 一个注释是简单地表达其类型为一个 AnnotationType
.
最后再放几个有用的手册链接:
https://codeql.github.com/docs/ql-language-reference/#ql-language-reference QL语参考
https://codeql.github.com/codeql-standard-libraries/java/ java的各种成员函数说明文档列表
https://codeql.github.com/docs/codeql-cli/manual/ CodeQL CLI手册,主要是各种文件和CodeQL的内部处理机制流程