codeql下method详解与案例

admin 2026-06-30 07:31:29 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档详细解析了CodeQLJava库中Method类的核心概念与使用方法,重点区分了MethodCall与Method的定义差异。文档系统介绍了Method类在源码定位、继承关系、方法签名、调用关系分析等方面的常用方法,包括getLocation()、getDeclaringType()、callsImpl()等关键函数的功能与应用场景。最后通过两个实战案例演示了如何查找自写代码和废弃方法的使用情况,为代码审计和安全分析提供了具体操作指导。 综合评分: 82 文章分类: 代码审计,安全开发,WEB安全,安全工具,技术标准


cover_image

codeql下method详解与案例

原创

信安路漫漫 信安路漫漫

信安路漫漫

2026年6月11日 07:00 上海

在小说阅读器读本章

去阅读

在 CodeQL Java 库中,Method 类代表 Java 方法本身的定义(即声明),而不是调用。它通常作为 MethodCall.getMethod() 的返回值出现。

理解 Method 类的用法对于编写精准的代码审计规则至关重要,因为它决定了你能否正确识别目标函数、过滤重载以及定位源码。

核心概念区分

在开始之前,必须明确两个概念的区别:

1)MethodCall:代表代码中的一次 调用动作(例如 obj.doSomething())。

2)Method:代表被调用的那个 函数定义(例如 void doSomething() { … })。

💡 速记:MethodCall 是“动词”,Method 是“字典里的词条”。

常用方法解析

1.      定位与源码映射

getLocation()

作用:返回一个 Location 对象,包含行号(StartLine, EndLine)和列号。

注意:如果数据库是基于 .class 构建的,这里返回的是字节码的行号;如果是基于源码构建的,则是源码行号。

getFile()

作用:返回该方法所属的文件对象(File)。

用法:通常配合使用 getFile().getAbsolutePath() 或 getFile().getBaseName() 来获取文件名。

getSourceDeclaration()

作用:非常重要。如果当前方法是泛型实例化后的方法(例如 List.add),或者是在编译单元中的某种引用,这个函数能帮你回溯到最初定义该方法的原始声明处(即 .java 文件中那个不带泛型参数的定义)。

getCompilationUnit()

作用:获取该方法所在的编译单元(通常对应一个 .java 源文件)。

2.继承与重写关系(处理接口继承)

l  getAnOverride()/overrides()

n  作用:查找当前方法重写了哪些父类/父接口的方法。

l  getAPossibleImplementation()

n  作用:反向查找。如果你有一个接口方法(如 getById),用这个函数可以找到所有实现了该接口的类中对应的具体方法。

l  isAbstract()

n  作用:判断方法是否是抽象的(接口中的方法默认通常是 abstract,除非有 default 实现)。

l  isStatic()

n  作用:判断是否为静态方法。

2.方法签名与参数(识别方法身份)

用于精确匹配特定的函数。

getName()

作用:获取方法名(例如 “getById”)。

getSignature()

作用:获取完整的方法签名(包括返回值类型和参数类型),这是区分重载方法(Overload)的关键。

getParameter(int index)

作用:获取指定索引位置的参数对象。

getAParamType

作用:获取所有参数的类型

如下,获取函数下所有的参数

getNumberOfParameters()

作用:获取参数的数量。

getReturnType()

作用:获取方法的返回值类型。

hasName(string name)

作用:谓词(Predicate),用于 where 子句中过滤特定名称的方法。

3.调用关系分析(数据流与控制流)

用于分析谁调用了这个方法,或者这个方法调用了谁。

getACallSite()

作用:getACallSite(m) 是 CodeQL 中用于数据流分析和调用图构建的核心函数。它的作用是:获取当前方法(Callable)内部调用了目标方法 m 的那个具体的“调用点”对象。

#

calls(Method other)

作用:判断当前方法内部是否调用了另一个方法。

getACallee()

作用:获取当前方法内部调用的所有目标方法集合。

callsImpl

作用:callsImpl 是 Method 类的一个谓词(Predicate),用于描述方法之间的实现调用关系。它的核心作用是:判断当前方法是否调用了另一个方法的实现体(而非接口或抽象声明)。

作用详解

区分“接口调用”与“实现调用”

在面向对象编程中,一个方法可能通过接口或抽象类被调用,但实际执行的是其具体实现。callsImpl 专门用于捕获这种“运行时实际执行的实现方法”的调用关系,而不是仅仅停留在接口层面。

支持多态分析

当你想分析某个接口方法的所有具体实现被调用的情况时,callsImpl 能帮你穿透多态,找到真正被执行的代码路径。例如,你有一个 List.add() 接口方法,它可能有 ArrayList.add()、LinkedList.add() 等多个实现。callsImpl 可以帮助你定位到具体是哪个实现被调用了。

用于污点追踪和数据流分析

在安全审计中,如果你关心用户输入是否最终流入某个敏感操作的实现体(如数据库写入、文件写入),callsImpl 可以帮助你从接口层向下追踪到具体的实现方法,从而更精确地构建数据流路径。

如下图所示:

可以获取m这个方法下,调用接口的所有实际利用的方法,如下m方法下,如果调用了一个接口,该方法直接放回该接口的实际方法。

getAModifier()

作用:返回该函数是私有还是公开的

#

getDeclaringType

作用:getDeclaringType() 是 CodeQL 中用于获取方法所属的类或接口类型的核心函数。它的作用是返回当前方法在源代码中被定义的那个 Type(类型)对象,从而让你能够进一步分析该方法的上下文,比如它的包名、父类、注解等。

这个方法在安全审计、代码分析和数据流追踪中非常关键,因为它帮你建立了“方法”与“其宿主类/接口”之间的桥梁。

核心作用详解

定位方法的归属

当你通过某种方式(如调用图、污点传播)找到一个可疑方法时,getDeclaringType() 能让你立刻知道这个方法属于哪个类或接口。这对于判断该方法是否是框架入口、是否是敏感操作、是否需要被过滤至关重要。

支持精确匹配和过滤

你可以结合 hasQualifiedName() 来精确限定你要分析的类。例如,你只想分析 com.example.service.UserService 类中的方法,就可以用 m.getDeclaringType().hasQualifiedName(“com.example.service”, “UserService”) 来过滤。

构建完整的调用链上下文

在分析一个方法调用时,仅知道方法名是不够的。你需要知道是哪个类的实例调用了它。getDeclaringType() 提供了这个上下文,使得你可以构建更完整的调用链,例如:caller.getDeclaringType().getName() + “.” + caller.getName() + ” -> ” + callee.getDeclaringType().getName() + “.” + callee.getName()。

区分重载方法和同名方法

不同类中可能有同名方法(如多个类都有 process() 方法)。通过 getDeclaringType(),你可以明确区分它们,避免误报。

案例

找出所有自写的代码

在 CodeQL 中,判断代码是否属于“自写项目”最简单、最直接的方法是使用 fromSource() 谓词。

import javafrom Method mwhere    m.fromSource() and      // 必须是自写代码    m.isPublic()            // 必须是公共方法select m, m.getName()

查找仍被调用的废弃方法

/** * @name 查找仍被调用的废弃方法 * @description 找出项目源码中带有 @Deprecated 注解且仍有调用者的方法 */ import java from Method deprecatedMethod, Method callerwhere    // 1. 限定范围:必须是当前项目的自写代码    deprecatedMethod.fromSource() and    // 2. 核心判断:该方法必须拥有 @Deprecated 注解    // hasAnnotation 会自动处理 import 简写和全限定名    deprecatedMethod.hasAnnotation("java.lang", "Deprecated") and    // 3. 关系分析:找到调用该废弃方法的“调用者”    // 3. 【修复点2】正确查找调用者    // 逻辑:找到一个方法访问节点(ma),该节点调用的方法是 deprecatedMethod,    // 且该访问节点所在的 enclosingCallable (即调用者) 是 caller    exists(MethodCall ma |        ma.getMethod() = deprecatedMethod and        ma.getEnclosingCallable() = caller    )    and    // 4. (可选优化) 排除测试代码中的调用,只关注业务逻辑    not caller.getDeclaringType().getPackage().getName().matches("%test%")select    deprecatedMethod,    "这个方法已被废弃但仍被使用",    caller,    "调用者位于: " + caller.getDeclaringType().getName()

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:信安路漫漫 信安路漫漫 信安路漫漫《codeql下method详解与案例》

评论:0   参与:  0