Basic syntax of CodeQL notes (1)


Preface

      Learn to use CodeQL for Java code auditing. Contains some concepts and examples.


CodeQL basic syntax

     CodeQL uses a parsing engine to parse the projects we need to audit into a database. Note that the database here is converted into a middle-tier database that CodeQL can recognize. Because the core parsing engine is not open source, an intermediate database is generated. Then we can write relevant QL rules, and then the CodeQL engine will find data that meets the conditions in the database according to the rules, and we can then analyze it.

1. Grammatical structure

     1) The syntax structure of QL query is:

from [datatype] var  /* ... 变量声明... */
where condition(var = something)   /* ... 逻辑公式 ... */
select var    /* ... 表达式 ... */

     2) A small example is to output i among all integer numbers i when i==1.

// 表示我们要引入CodeQL的类库,因为我们分析的项目是java的,所以在ql语句里,必不可少
import java

// 表示我们定义一个变量i,它的类型是int,表示我们获取所有的int类型的数据
from int i
// 表示当i等于1的时候,符合条件
where i = 1
// 表示输出i
select i

Insert image description here
     3) You can also use the official platform to practice writing some rules. LGTM query console: https://lgtm.com/query
Insert image description here

2. Class library

     1) The CodeQL parsing engine will convert the project code we need to audit into an AST database that can be recognized by CodeQL. The format is as follows. It can be seen that there are generally two levels, one is the imported package and the other is the class. Below the class are some methods, properties, etc. The class library is actually the corresponding relationship of the above AST.
Insert image description here
     2) For example, if you want to get the methods in all classes, Method in AST means getting all the methods in the current project. As follows:

import java

from Method method
select method

Insert image description here
Insert image description here
     3) Upgrade it and filter the results through some methods built into the Method class. For example, get the method name named get.

import java
 
from Method method
where method.hasName("get")
/**
method.getName() 获取的是当前方法的名称
method.getDeclaringType() 获取的是当前方法所属class的名称。
**/
select method.getName(), method.getDeclaringType()

Insert image description here

3. Predicate

     1) Predicates are used to describe the logical relationships that constitute a QL program. Conceptually it is similar to a function. Personally, I understand from the official documentation that the predicate is a one-element array or two-element array. The set predicate arity of a one-element array is one, and the set predicate arity of a two-element array is two. Typically, all tuples in a predicate have the same number of elements. The number of predicates is the number of elements, excluding possible result variables. There are many built-in predicates in QL, you can refer to the official documentation: https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#built-ins.
     2) Define a predicate condition:

  • Keyword predicate required
  • An identifier starting with a lowercase letter is required, for example: isCountry
  • Define parameters, connect multiple parameters with commas. For each parameter, you need to specify the parameter type and the identifier of the parameter variable.
  • The predicate itself is enclosed in large curly braces "{ }"

     3) Official example:

predicate isCountry(string country) {
    
    
  country = "Germany"
  or
  country = "Belgium"
  or
  country = "France"
}

predicate hasCapital(string country, string capital) {
    
    
  country = "Belgium" and capital = "Brussels"
  or
  country = "Germany" and capital = "Berlin"
  or
  country = "France" and capital = "Paris"
}

     4) The above example of querying get can also be rewritten as follows.

import java
 
predicate isGet(Method method) {
    
    
exists(|method.hasName("get"))
}
 
from Method method
where isGet(method)
select method.getName(), method.getDeclaringType()
语法解释:
predicate 表示当前方法没有返回值。
exists子查询,是CodeQL谓词语法里非常常见的语法结构,它根据内部的子查询返回true or false,
来决定筛选出哪些数据。

Insert image description here
     5) Predicates can be divided into predicates with results and predicates without results. The difference is whether the special variable result is introduced. If there is result, it can replace the predicate. Refer to the official case:

// 无结果的谓词 
predicate isSmall(int i) {
    
    
  i in [1 .. 9]
}
// 如果i是正整数并且小于10,则isSmall(i)成立。


// 有结果的谓词 
int getSuccessor(int i) {
    
    
  result = i + 1 and
  i in [1 .. 9]
}

// 如果i是正整数并且小于10,则这个谓词的结果就是接替i

4. Basic data types and their built-in functions

     1) Basic data types in QL language, including integer, floating point, date, Boolean and string types. It should be noted that for the QL language, all the data types it supports have corresponding built-in functions - in layman's terms, the functions that the system has written for us are predicates, and we can use them directly. .
     2) For example, if we want to find the absolute value of an integer, we can directly call the built-in function abs(), such as 1.abs().
Insert image description here
     2) If we want to call a certain type of variable, the general form is: directly add a period after the variable, and then add the built-in function to be called. At the same time, we can also connect multiple functions in series through dots, that is, perform multiple processing on variables continuously. For example, for an integer variable s, first find the absolute value and then take the square root. We can express this processing process For: s.abs().sqrt().
Insert image description here
     3) String type, similar to other languages.

from string s
where s = "he\"llo"
select s

Insert image description here
Insert image description here
     4) Integer and floating point types.

from float a, int b
where a = 5.3 and b = 2
// pow的作用就是参数的几次幂  下方例子就是5.3的2次幂
select a.pow(b)

Insert image description here
Insert image description here
     5) Date type. Write a query to calculate how many days have passed since the first Wuhan epidemic.

from date start, date now
// toDate()作用就是将指定的字符串转换为日期值
where start = "1/12/2019".toDate() and now = "25/10/2022".toDate()
select start.daysTo(now)

Insert image description here
Insert image description here

Guess you like

Origin blog.csdn.net/qq_44029310/article/details/127387768