codeql下MethodCall详解
原创
信安路漫漫
信安路漫漫
信安路漫漫
2026年6月11日 07:00
上海
在小说阅读器读本章
去阅读
在进行代码分析时,CodeQL 中最常用的类之一就是 MethodCall。本笔记将系统梳理 MethodCall 的核心概念、常用方法及实战案例,帮助你高效编写查询。
一、核心概念
l MethodCall(及旧版的 MethodAccess)是表示方法调用行为的核心类,广泛应用于代码抽象语法树(AST)与调用图(Call Graph)分析。
l MethodCall 代表代码中实际发生的某次“调用动作”(如 obj.doSomething(arg)),而 Method 表示方法的定义/实现。
示例:
// 方法定义public void someMethod() { // 语句 ResultSet results = statement.executeQuery(query);}
l statement.executeQuery(query); 就是一次具体的 MethodCall。
二、继承体系
l MethodCall 是更通用的 Call 类的子类。
l Call:包含所有类型的调用表达式。
l MethodCall:专门针对普通方法调用,适合大多数 Java 代码分析场景。
三、常用方法与应用场景
1. 获取目标方法
l getMethod() / getCallee()
n 作用:获取被调用的方法定义(Method 对象)。
n 区别:
u getMethod():返回 Method 类型,常用于后续调用如 hasName()、getDeclaringType()。
u getCallee():返回 Callable 类型,语义为“被调用者”,通常等价于 getMethod()。
常见用法:判断是否调用了危险函数(如 Runtime.exec)
from MethodCall callwhere call.getMethod().hasName(\"exec\")select call, \"Found exec call\"
2. 获取参数
l getArgument(int n)
n 作用:获取第 n 个参数(从 0 开始),返回 Expr。
n 场景:污点分析、参数追踪。
示例:查找 executeQuery 的第一个参数
from MethodCall callwhere call.getMethod().hasName(\"executeQuery\")select call.getArgument(0)
3. 获取调用者
l getQualifier()
n 作用:获取调用该方法的对象表达式(点号 . 前的部分)。
n 场景:区分静态调用和实例调用,或定位特定对象的调用。
示例:查找变量调用形式
from MethodCall callwhere call.getQualifier() instanceof VariableAccessselect call
4. 定位调用语句
l getEnclosingStmt()
n 作用:获取包含该调用的语句(Statement)。
n 场景:回溯调用所在的 if、循环、赋值等语句。
示例:查找日志方法调用语句
from MethodCall callwhere call.getMethod().hasName(\"log\")select call.getEnclosingStmt()
5. 环境判断
l isStaticContext() / isEnclosingMethodCall()
n isStaticContext():判断是否在静态上下文(如静态方法或初始化块)中。
n isEnclosingMethodCall():判断当前节点是否为方法调用(递归遍历 AST 时常用)。
示例代码:
String guid = (String) allParams.get(\"guid\");
6. 参数内部分析
l getAChildExpr()
n 作用:获取任意子表达式,便于分析参数内部是否包含敏感操作。
n 场景:分析嵌套调用,如 process(getSecretData())。
示例:查找嵌套敏感调用
from MethodCall outerCall, Expr childwhere outerCall.getMethod().hasName(\"process\") and child = outerCall.getAChildExpr() and child instanceof MethodCall and child.(MethodCall).getMethod().hasName(\"getSecretData\")select outerCall, \"Found nested sensitive call\"
7. 常量判断
l isCompileTimeConstant()
n 作用:判断参数是否为编译期常量。
n 场景:污点分析时排除硬编码字符串,减少误报。
示例:排除硬编码 SQL 查询
from MethodCall callwhere call.getMethod().hasName(\"executeQuery\") and not call.getArgument(0).isCompileTimeConstant()select call, \"Potential SQL Injection with dynamic input\"
四、综合实战案例
场景:检测命令执行漏洞模式 Runtime.getRuntime().exec(cmd)
查询示例:
import javafrom MethodCall execCallwhere // 1. 方法名过滤 execCall.getMethod().hasName(\"exec\") and // 2. 确认调用者类型为 Runtime execCall.getReceiverType().hasName(\"Runtime\") and // 3. 至少有一个参数 execCall.getNumArgument() >= 1select execCall, // 4. 输出调试信息 \"Found potential command injection: \" + execCall.toString(), // 5. 提取第一个参数作为污点源 execCall.getArgument(0) as source
五、其它常用方法速查表
| 方法名 | 类别 | 说明 | 返回类型/说明 |
| getMethod() | 核心 | 获取被调用方法定义 | Method 对象 |
| getCallee() | 核心 | 获取被调用实体 | Callable 对象 |
| getArgument(n) | 核心 | 获取第 n 个参数 | Expr 对象 |
| getNumArgument() | 核心 | 获取参数总数 | int 整数 |
| getQualifier() | 核心 | 获取调用者表达式 | Expr 对象 |
| getReceiverType() | 类型分析 | 获取调用者声明类型 | Type 对象 |
| getType() | 类型分析 | 获取返回值类型 | Type 对象 |
| getEnclosingStmt() | 上下文 | 获取包含该调用的语句 | Stmt 对象 |
| isInStaticContext() | 上下文 | 判断是否为静态上下文 | boolean |
| isCompileTimeConstant() | 常量分析 | 判断是否为编译期常量 | boolean |
| getAChildExpr() | AST 遍历 | 获取任意子表达式 | Expr 对象 |
| getParent() | AST 遍历 | 获取父节点 | AstNode 对象 |
| getLocation() | 定位 | 获取代码位置信息 | Location 对象 |
| getFile() | 定位 | 获取所属文件 | File 对象 |
| getCompilationUnit() | 结构 | 获取编译单元 | CompilationUnit 对象 |
| toString() | 调试 | 转为字符串描述 | string |
| hasLocationInfo() | 校验 | 检查是否有位置信息 | boolean |
| getAPrimaryQlClass() | 高级 | 获取主类定义 | RefType |
欢迎补充交流,如有疑问欢迎留言讨论!
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论