7.2 Joern查询实战


7.2 Joern查询实战

本节摘要:Joern 是 Scala 实现的 CPG 平台(约 3.6k stars,Apache-2.0,2026-10 社区口径),本节把它从概念变成趁手工具。先装好 Joern 并认识 REPL——官方还提供基于 Scastie 的在线运行环境,浏览器里就能试查询;然后导入一个代码库,体验它最有杀伤力的工程特性:无需构建环境,源码目录直接入图,并核对导入规模;接着写两类最典型的查询:全库找危险函数调用(结构维度)、从函数参数追到危险 sink 的数据流可达性(依赖维度),外加一个按文件分组的热点统计;再演示一次「探索式滚动循环」的完整过程;最后把这些查询固化成 .sc 脚本,变成可复用的分析资产。练习对象使用开源 C 项目或自建代码库。

学习目标

  • 完成 Joern 安装,能在 REPL 与 .sc 脚本两种形态下工作。
  • 用 importCode 把源码目录导入为 CPG 并确认导入规模。
  • 写出危险函数调用清单查询与参数流向可达性查询。
  • 走完一次「列表、回溯、查路径」的探索循环。
  • 说清「无构建环境导入」的适用边界。

一、安装与认识 REPL

Joern 官方安装脚本一条命令(需要 JDK 运行时,具体依赖以官方文档为准):

# joern_install.sh —— 官方脚本安装 Joern(joern.io 为权威来源) curl -L -o joern-install.sh https://github.com/joernio/joern/releases/latest/download/joern-install.sh bash joern-install.sh joern # 进入 Scala REPL,提示符 joern> ​

REPL 是 Joern 的灵魂:输入一行查询,立刻看到结果,再据此改下一行——与第 02 章《radare2与脚本化》里「分析即对话」的体验一致。暂时不想装环境时,官方文档提供基于 Scastie 的在线 Scala 环境,可以在浏览器里跑本书的大部分查询(能力以官方站点说明为准)。

进入 REPL 后先认识全局变量 cpg——它就是当前代码属性图的入口,一切查询从它出发。三条最基本的「摸底」查询值得背下来:

# probe.sc —— 入图后的三条摸底查询 cpg.method.size // 函数节点总数 cpg.call.size // 调用节点总数 cpg.typeDecl.name.l // 类型(或结构体)名单,看导入的语言特征 ​

二、导入代码库:不需要构建环境

导入只要一行:

# import_demo.sc —— 导入源码目录并确认规模 importCode("./src") // 无需构建环境:直接解析源码建图 println(cpg.method.size) // 函数节点数 println(cpg.call.size) // 调用节点数 println(cpg.identifier.size) // 标识符节点数 ​

与 CodeQL 对比着记:C、C++ 建库要真实编译,Joern 的前端直接从源码文本解析建图。代价是宏展开与类型信息不如真构建精确,收益是「拿到源码就能查」——对第三方开源组件的历史版本做快速体检时,这个特性常常是决定性的。

维度 无构建导入(Joern) 真构建建库(CodeQL 编译型语言)
前置条件 源码目录即可 完整工具链与构建脚本
类型与宏 近似恢复 精确展开
历史版本体检 分钟级起步 每版本一次完整构建
适用 快速侦察、探索 定论级分析

导入后图落在工作区目录,下次启动 Joern 用 loadCpg 即可复用,不必重导。练习对象建议:任选一个中小型开源 C 项目(许可证允许的镜像副本),或把第 08 章要用的自编 crackme 源码先拿来练手。

三、典型查询一:危险函数调用清单

第一类查询是结构维度的:全库列出经典危险函数的调用点。

# danger_calls.sc —— 全库危险函数调用清单(结构维度) cpg.call.name("strcpy|strcat|sprintf|gets|system").code.l ​

一行换一个视角,还是 AST 边上的功夫,但加上分组统计就成了「热点地图」:

# danger_by_file.sc —— 按文件分组统计危险调用,找热点文件 cpg.call.name("strcpy|strcat|sprintf|gets|system") .file.name.l .groupBy(identity).mapValues(_.size) ​

还可以按「危险调用所在函数」再看一层:cpg.call.name("strcpy.*").method.name.l——同一函数里挤了三次 strcpy,与三个函数各一次,复核优先级完全不同。这类查询的价值不在「发现漏洞」,而在三分钟建立全局地图:危险调用集中在哪几个文件、哪几个函数——人工复核的排序就出来了。把它和第 06 章 semgrep 的官方规则集结果交叉对照,还能识别「规则没覆盖到的本地危险封装」。

四、典型查询二:追参数流向

第二类查询进入数据流维度:某个对外入口函数的参数,能否流到危险 sink?这要用到 CPG 的可达性遍历(污点引擎的底层原语):

# arg_flow.sc —— 从入口函数参数追到 system 的数据流(示意,API 以官方文档为准) val src = cpg.method.name("handle_request").parameter val dst = cpg.call.name("system").argument dst.reachableBy(src).p ​

读法:sink.reachableBy(source)——从 system 的实参出发,沿 PDG 边回溯,若能碰到 handle_request 的形参,就返回命中路径(p 输出带路径说明)。返回空列表同样是有效结论:不存在直接数据流——注意「直接」二字,reachableBy 默认的深度与精度受配置影响,重要结论要配合 CFG 检查(路径上是否有净化)来收尾。

把三、四两节串成一次真实的探索循环:

# explore_session.txt —— 一次探索循环的轨迹(示意输出) joern> cpg.call.name("system").code.l res: List("system(cmd)", "system(cmd)") joern> cpg.call.name("system").method.name.l res: List("run_tool", "cleanup_tmp") // 两个持有者,先查前者 joern> val src = cpg.method.name("handle_request").parameter joern> val dst = cpg.call.name("system").argument joern> dst.reachableBy(src).p res: 路径:handle_request(p1) → ... → run_tool(cmd) → system(cmd) // 下一步:检查路径上有无对 p1 的白名单校验(CFG 维度,固化为脚本) ​

五步之内从「全库地图」走到「一条候选数据流路径」——这就是 7.1 节说的探索式滚动循环的体感。

五、固化成脚本与分析资产

REPL 适合探索,资产要落成 .sc 脚本。把常用查询收进一个目录,用命令行批量执行:

# run_scripts.sh —— 批量执行 .sc 查询脚本(joern 命令行形态) joern --script danger_calls.sc --param codePath=./src joern --script arg_flow.sc --param codePath=./src ​

脚本资产的建议目录结构:queries/ 存 .sc 文件、runs/ 存每次执行输出(带日期)、README 记每个查询的用途与已知误报。固化带来两个复利:其一,查询即团队资产,新人接手项目先跑一遍脚本库;其二,脚本是「确定性验证器」——第 10 章的 AI 挖洞流程里,模型提出「handle_request 的参数可能流到 system」的假设时,arg_flow.sc 一秒钟给出机器判定的答案,这正是反幻觉架构里「模型提假设、工具做验证」的一块拼图。

提示:对外部开源项目做分析时遵守其许可证与使用条款;查询结果可能包含项目作者未预期的缺陷信息,披露前先确认项目的安全披露政策。

本节要点回顾

  • Joern 入口是 cpg 全局变量,REPL 逐行试探、.sc 脚本固化复用。
  • importCode 无需构建环境直接建图,代价是类型与宏信息不如真构建精确。
  • 结构维度查调用清单(加分组统计成热点地图),数据流维度查 reachableBy 可达性。
  • 探索循环五步走:列表、挑持有者、回溯、看路径、固化脚本。
  • 查询脚本是团队资产,也是 AI 假设的确定性验证器。

到这里 CPG 还只在源码世界打转。但逆向工程的主战场常是二进制——没源码、stripped、只剩指令流。下一节把 Ghidra 前端接进 Joern,让 x86 二进制也生成同构的 CPG:你在本节学的每一条查询语法,在二进制图上一字不改照样能跑。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U