长亭百川云 - 文章详情

抽丝剥茧代码属性图CPG-第四弹:CPG中的DFG-3

CodeAnalyzer Ultra

54

2024-07-13

阅前声明(文末彩蛋,每期都有哦~)

引言

书接上文,本节内容继续讲解CPG中其余节点的DFG构建过程~

这么分节的原因主要是考虑到了大家可能会产生阅读疲劳,俗话说:时间要花在刀刃上,所以把重头戏要放在每个小节的开头,这样更有利于大家的学习~(读者内心OS:我哭死)

读后有收获的同学可以点个赞哦,要是能关注一下公众号就更好啦大家的鼓励是笔者硬肝技术的动力!非常感谢大家

文中有错误的地方欢迎大家私信/评论区指正。同时也欢迎大家将自己的想法发布在评论区,希望大家能够畅所欲言,共同进步~

欢迎点击公众号菜单栏"点击进群",与大佬一同交流技术。

17.Branching Statements

不同的分支语句会产生不同的控制流,影响分支执行的条件值会通过分支产生隐式数据流,因此,CPG添加了从分支条件到分支节点的DFG边

17.1.ForEachStatement

forEach语句(ForEachStatement)关注以下字段:

  • variable: Statement: 循环的迭代变量,可以是new变量声明,也可以是已有的变量引用

  • iterable: Statement: 被循环访问的引用(如:容器对象

可迭代值流向变量中的 VariableDeclaration(变量声明)。由于一些语言允许任意逻辑,CPG区分了两种情况:

17.1.1.The variable is a DeclarationStatement

对于大多数语言来说,循环语句中只允许声明一个变量(如:for(e in list))。DFG添加一条边:

  • iterable(被循环访问的对象) --> variable(变量声明语句)中声明的变量

17.1.2.The variable is another type of Statement

这种情况,CPG会假设最后一个变量声明是用于循环的那个,所以DFG只添加一条边:

  • 最后一个变量声明 --> ForEachStatement

17.1.3.验证边

测试代码:

`package com.cpg.dfg;      import java.util.Arrays;   import java.util.List;      public class TestForEachStatement {       public static void main(String[] args) {           List<String> list = Arrays.asList("hello", "SASTing");           for (String s : list) {  // ForEachStatement,属性 variable表示String s,属性iterable表示list               System.out.println(s);           }       }   }   `
  • iterable --> declaration of DeclarationStatement

其实就是 list 流向了 s

17.1.2 中提到的variable(声明语句)中可以声明多个变量的情况,Java中不支持,此处不再验证

17.2.DoStatement

do循环语句(DoStatement)关注以下字段:

  • condition: Statement: do循环语句的条件

DFG边:condition流向DoStatement

17.2.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestDoStatement {       public static void main(String[] args) {           int i=3;           do {  // DoStatement,condition就是 i<10               System.out.println("Hello SASTing!");               i++;           } while (i<10);       }   }   `
  • condition --> DoStatement

17.3.WhileStatement

while循环语句关注以下字段:

  • condition: Statement: 条件

  • conditionDeclaration: Statement: 条件声明语句(A declaration containing the condition in the initializer, used instead of the condition)

DFG边构建如下:

17.3.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestWhileStatement {       public static void main(String[] args) {           int i=10;           while (i>0) {  // WhileStatement,condition就是 i>0               System.out.println(i);               i--;           }       }   }   `
  • condition --> WhileStatement

  • conditionDeclaration --> WhileStatement

C++ allows defining a declaration instead of a pure logical expression as condition

C++ 允许使用声明代替纯逻辑表达式作为条件定义

OK,是针对C++做的适配,与Java无关 == 与我无瓜skip~

17.4.ForStatement

for循环语句(ForStatement)关注以下字段:

  • condition: Statement: for循环的条件

  • conditionDeclaration: Statement: 条件声明语句(A declaration containing the condition in the initializer, used instead of the condition)

DFG边构建如下:

17.4.1.验证边

  • condition --> ForStatement

  • conditionDeclaration --> ForStatement

conditionDeclaration字段的解释与WhileStatement.conditionDeclaration都一样,也是针对C++做的适配,skip~

17.5.IfStatement

if语句(IfStatement)关注以下字段:

  • condition: Statement: if语句的条件

  • conditionDeclaration: Statement: 条件声明语句(A declaration containing the condition in the initialize, used instead of the condition)

DFG边构建如下:

17.5.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestIfStatement {       public static void main(String[] args) {           int i = 1;           if (i > 0) { // IfStatement,condition 就是 i>0               System.out.println("SASTing is cool!");           }           else {               System.out.println("SASTing is handsome!");           }       }   }   `
  • condition --> IfStatement

  • conditionDeclaration --> ForStatement

conditionDeclaration字段源码注释:

C++ alternative to the condition.

所以,skip~

17.6.SwitchStatement

switch语句(SwitchStatement)关注以下字段:

  • selector: Statement: 选择器(也就是switch括号内传进去的对象)

  • selectorDeclaration: Statement: 选择器的声明语句(A declaration containing the selector in the initializer, used instead of the selector)

DFG边构建如下:

17.6.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestSwitchStatement {       public static void main(String[] args) {           Language language = Language.JAVA;           switch (language) { // SwitchStatement,selector就是 language引用               case JAVA:                   System.out.println("Java");                   break;               case CPP:                   System.out.println("Cpp, skip~");               default:                   System.out.println("not support language");           }       }          enum Language {           JAVA, CPP       }   }   `
  • selector --> SwitchStatement

  • selectorDeclaration --> SwitchStatement

C++ allows to use a declaration instead of a expression as selector

OK,是为了适配C++的,skip~

18.FunctionDeclaration

方法声明(FunctionDeclaration)关注以下字段:

  • body: Expression: 方法体(包括方法体内的所有语句)

所有return表达式的流向方法声明

18.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestFunctionDeclaration {       public String test(int a) { // FunctionDeclaration           if (a > 0) {               return "SASTing is handsome!";           }           else {               return "SASTing is cool!";           }       }   }   `

可以看到MethodDeclarationFunctionDeclaration的一个子类,表示方法声明

  • all ReturnStatement --> FunctionDeclaration

19.FieldDeclaration

字段声明(FieldDeclaration)关注以下字段:

  • initializer: Expression?: 字段初始化值(若没有初始化则该字段为null)

数据流从字段初始值流向字段声明字段声明流向下一次字段读取

19.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestFieldDeclaration {       public String name = "SASTing";          public void test() {           System.out.println(name); // read access of the field name       }   }   `
  • initializer --> FieldDeclaration

  • FieldDeclaration --> next read access of the field

tips: 实际上,在CPG中的DFG-2(加链接,待修改)中讲到Reference的DFG构建时,若是一个字段引用,那么该引用的refersTo属性就是此处的字段声明。

20.VariableDeclaration

变量声明(VariableDeclaration)关注以下字段:

  • initializer: Expression?: 变量的初始化值

数据流从initializer流向变量声明,在对变量写入值之前,变量声明的值会流向所有变量读取处

20.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestVariableDeclaration {       public static void main(String[] args) {           String str = "init str"; // initializer of str           System.out.println(str); // read access of str           readStr(str); // read access of str           str = "SASTing"; // write access of str           System.out.println(str); // read access of str, str写入值后的读取,故VariableDeclaration不会流向此处       }       private static void readStr(String str) {           System.out.println(str);       }   }   `
  • initializer --> VariableDeclaration

  • VariableDeclaration --> all read access of str before write access of str

可以看到 VariableDeclaration 没有流向第9行,因为第8行有str写入操作

21.TupleDeclaration

元组声明(TupleDeclaration)关注以下字段:

  • initializer: Expression?: 初始化值

  • element: List<VariableDeclaration>: 元组中的元素列表

initializer流向element,在对变量写入值之前,变量声明的值会流向所有变量读取处

Java并不支持直接声明元组类型,需要借助Google Guava库中的PairTriple或者手动包装一个类似元组的类。故TupleDeclaration的边验证也skip~

22.Assignment

赋值语句(Assignment)关注以下字段:

  • value: Expression: 赋值语句的 rhs (右操作数)

  • target: AssignmentTarget: 赋值语句的 lhs (左操作数)

DFG边的构建在 CPG中的DFG-1 中提到的BinaryOperator operator=的构建方式一致

22.1.验证边

测试代码:

`package com.cpg.dfg;      public class TestAssignment {       public static void main(String[] args) {           int a = 1;           a = 2; // Assignment       }   }   `
  • value --> target

先看其target是一个引用,其内存地址是7469

value的nextDFG指向了reference,地址也是7469,所以存在value --> target 的边

总结

CPG中DFG的构建模块到这里就结束啦,东西不难,就是细节比较多,建议大家对这块内容不要死记硬背,在使用过程中若遇到了DFG,再回过头来看看其DFG的构建过程即可,慢慢就熟悉了~

工具推荐

VLC视频播放器(https://www.videolan.org/vlc/index.an.html)

  • 支持的操作系统:Mac,Linux,Windows,Android,IOS

  • 支持市面上几乎所有的视频格式

  • 免费,无广告,无捆绑

下期预告

CPG中的函数摘要

当遇到CPG无法分析的方法时,数据流会中断,会影响分析精度。因此CPG支持自定义配置函数摘要,用户可以通过配置文件添加函数摘要,使数据流完整。

开源仓库

文中的测试样例已同步****github仓库,欢迎大家多多star,仓库地址如下:

https://github.com/HaHarden/CPGPractise

https://github.com/HaHarden/BenchmarkJava-Pro

技术交流群

进群方式

1. 扫码进群

2. 点击公众号底部菜单栏"点击进群",加笔者好友(备注****进群

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2