CodeQL学习笔记(4)-CodeQL for Java(程序元素)
字数 1576 2025-08-20 18:17:53
CodeQL for Java 程序元素详解
1. CodeQL基础概念
CodeQL将源代码解析为抽象语法树(AST),其中每个节点代表一个代码元素。这些元素按照源代码的嵌套结构形成分层树形结构:
- 顶层节点通常是整个代码文件(
CompilationUnit) - 逐层向下展开:package → class → method → variable等
- 每个子节点代表特定的代码元素类型(package、class、method等)
CodeQL提供了一套类库来表示这些节点类型,对应Java中的各种元素类型。
2. 基本查询结构
一个典型的CodeQL查询包含以下部分:
import java // 导入标准库
from MethodAccess ma // 定义变量
where
ma.getMethod().hasName("equals") and // 约束条件1
ma.getArgument(0).(StringLiteral).getValue() = "" // 约束条件2
select ma, "This comparison to empty string is inefficient, use isEmpty() instead." // 结果输出
查询思维是迭代过程:先用较宽泛的条件定位大范围目标,再逐步添加限制条件精确筛选。
3. 程序元素类库
3.1 核心元素类
| CodeQL类 | Java对应元素 | 说明 |
|---|---|---|
Element |
- | 所有程序元素的基类 |
Package |
package | Java包 |
CompilationUnit |
Java源文件 | 编译单元 |
Type |
类型 | Java中的类型 |
Method |
方法 | Java方法 |
Constructor |
构造函数 | Java构造函数 |
Variable |
变量 | Java变量 |
3.2 类型系统(Type)
Type是CodeQL中表示Java类型的核心类,其继承关系如下:
Type
├── PrimitiveType (基本类型)
│ ├── boolean, byte, char, double, float, int, long, short
│ └── 还包括QL中的void和null
└── RefType (引用类型)
├── Class (类)
├── Interface (接口)
├── EnumType (枚举)
├── Array (数组)
├── TopLevelType/TopLevelClass (顶层类型/类)
└── NestedType/NestedClass (嵌套类型/类)
├── LocalClass (局部类)
└── AnonymousClass (匿名类)
类型查询示例
- 查找所有int类型的变量:
from Variable v, PrimitiveType pt
where v.getType() = pt and pt.hasName("int")
select v
- 查找名称与所在文件不一致的顶层类型:
from TopLevelType tl
where tl.getName() != tl.getCompilationUnit().getName()
select tl
- 查找直接继承Object的嵌套类:
from NestedClass nc
where nc.getASupertype() instanceof TypeObject
select nc
4. 泛型系统
4.1 泛型类型表示
| CodeQL类 | Java对应 | 说明 |
|---|---|---|
GenericType |
泛型类型 | 泛型类型基类 |
GenericInterface |
泛型接口 | 如Map<K,V> |
GenericClass |
泛型类 | 如ArrayList<E> |
TypeVariable |
类型参数 | 如K,V,E等 |
ParameterizedType |
参数化类型 | 如Map<String,File> |
RawType |
原始类型 | 如不使用泛型的Map |
WildcardTypeAccess |
通配符类型 | 如? extends Number |
4.2 泛型查询示例
- 查找所有
java.util.Map的参数化实例:
from GenericInterface map, ParameterizedType pt
where map.hasQualifiedName("java.util", "Map") and
pt.getSourceDeclaration() = map
select pt
- 查找边界为Number的类型变量:
from TypeVariable tv, TypeBound tb
where tb = tv.getATypeBound() and
tb.getType().hasQualifiedName("java.lang", "Number")
select tv
- 查找使用原始类型Map的变量:
from Variable v, RawType rt
where rt = v.getType() and
rt.getSourceDeclaration().hasQualifiedName("java.util", "Map")
select v
- 查询通配符类型的上下界:
from WildcardTypeAccess w
where w.getUpperBound().getType().hasQualifiedName("java.lang", "Number") or
w.getLowerBound().getType().hasQualifiedName("java.lang", "Float")
select w
5. 变量系统
| CodeQL类 | Java对应 | 说明 |
|---|---|---|
Variable |
变量 | 变量基类 |
Field |
字段 | 类字段 |
LocalVariableDecl |
局部变量 | 方法内变量 |
Parameter |
参数 | 方法/构造函数参数 |
6. 查询优化技巧
- 精确匹配String类型的equals调用:
from MethodAccess ma
where ma.getMethod().hasName("equals") and
ma.getQualifier().getType() instanceof TypeString and
ma.getArgument(0).(StringLiteral).getValue() = ""
select ma, "Use isEmpty() instead of equals(\"\")"
- 使用继承关系缩小范围:
from Class c
where c.getASupertype().hasQualifiedName("java.util", "AbstractList")
select c
- 结合多条件精确查询:
from Method m
where m.hasName("toString") and
m.getDeclaringType() instanceof EnumType and
m.isPublic() and
not m.isOverriding()
select m
7. 总结
CodeQL for Java的核心在于理解:
- Java元素与CodeQL类的对应关系
- 类型系统的层次结构
- 泛型系统的表示方法
- 查询的迭代思维:从宽泛到精确
掌握这些核心概念后,可以构建出各种复杂的代码分析查询,用于漏洞挖掘、代码审计等场景。