学习利用CodeQL进行代码审计。基础语法包含一些概念和例子。本文是查询和类的部分。
查询就是整个QL语言运行后输出的结果。有两种查询类型:
1)select子句格式如下所示(通常在文件末尾),其中from和where语句部分是可选的。我们可以在from中定义变量,在where中给变量赋值和对查询结果的过滤,最后在select中显示结果。
from /* ... variable declarations ... */
where /* ... logical formula ... */
select /* ... expressions ... */
2)在select语句中还可以使用一些关键字:
3)官方例子如下,第一张图结果返回的是select子句 查询的结果,第二张图加了个排序
from int x, int y
where x = 3 and y in [0 .. 2]
select x, y, x * y as product, "product: " + product


1)查询谓词是一个非成员谓词,并在最开头使用query作为注解。它返回谓词计算结果的所有元组,下面是一个官方的示例:
query int getProduct(int x, int y) {
x = 3 and
y in [0 .. 2] and
result = x * y
}

2)编写查询谓词相对比编写select子句的好处是你可以在代码的其他部分中调用谓词。例如,我们可以在类中去调用getProduct:
query int getProduct(int x, int y) {
x = 3 and
y in [0 .. 2] and
result = x * y
}
class MultipleOfThree extends int {
MultipleOfThree() { this = getProduct(_, _) }
}
from MultipleOfThree m
select m
3)这样我们的查询结果就有两个,一个是内置的#select,一个是getProduct


4)二者对比之下,select 子句就像一个匿名谓词,后面你不能调用它。在调试代码时向谓词添加查询注释也很有帮助 。这样,您可以显式地看到谓词求值的元组集。
QL 是一种静态类型语言,因此每个变量都必须有一个声明的类型。在QL中类型是一组值。例如,类型int是整数集。而值可以归属多个集合,也就代表了一个值可以有多种类型。QL 中的类型有基本类型、类、字符类型、类域类型、代数数据类型、类型联合和数据库类型。
这些类型内置在QL 中,并且在全局命名空间中始终可用,也与我们正在查询的数据库没有关系。
1)我们可以在CodeQL中定义自己的类型,一种方法定义一个类。
2)类提供了一种重用和结构化代码的简单方法,例如,你能将相关值分组在一起、在这些值上定义成员谓词、定义子类以重写成员谓词。
3)QL 中的类不会“创建”新对象,它只是表示一个逻辑属性。如果值满足该逻辑属性,则该值属于特定类。
4)定义一个类,需要以下参数:
5)官方案例:
class OneTwoThree extends int {
OneTwoThree() { // characteristic predicate
this = 1 or this = 2 or this = 3
}
string getAString() { // member predicate
result = "One, two or three: " + this.toString()
}
predicate isEven() { // member predicate
this = 2
}
}
6)在CodeQL中,类允许多重继承,但是以下操作是非法的:
1)类的主体可以包含以下内容:
2)在类中,我们可以使用this来指代类本身。当我们定义类时,该类还会从其父类继承所有非私有成员谓词和字段,我们可以覆盖(override)这些谓词和字段。
类似于其他语言中类的构造函数,只能定义一个,我们可以在特征谓词中使用this来限制类中可能的值。在上述例子中,OneTwoThree被限制为1-3中的整数。
这些谓词仅适用于特定类的成员。我们可以在值上调用成员谓词。
(OneTwoThree).getAString()
// 结果是 One, two or three: 1
字段是在类的主体中声明的变量,一个类的主题中可以有任意数量的字段声明。我们可以在类中的谓词适用这些变量,用法和this类似,字段必须受限于特征谓词。官方案例:
class SmallInt extends int {
SmallInt() { this = [1 .. 10] }
}
class DivisibleInt extends SmallInt {
SmallInt divisor; // declaration of the field `divisor`
DivisibleInt() { this % divisor = 0 }
SmallInt getADivisor() { result = divisor }
}
from DivisibleInt i
select i, i.getADivisor()
在这个案例中,先声明了SmallInt divisor并定义了一个divisor字段,将其约束在特征谓词中,然后在成员谓词getADivisor的声明中使用它 。

上面的例子都是具体类,具体类是通过限制较大类型中的值来定义的。具体类中的值也是超类型交集中的那些值,这些值也满足类的特征谓词。
抽象类使用关键字abstract放在关键字class前来定义。抽象的概念相信在许多其他语言中我们都有接触到(例如java)。抽象类我们又可以叫做元类,它定义其子类的谓词和字段。格式如下:
abstract class SqlExpr extends Expr {
...
}