SyntaxFlow 规则引擎能力迭代
原创
YAK
YAK
Yak Project
2026年6月5日 17:40
湖南
在小说阅读器读本章
去阅读
SyntaxFlow 的 CFG 能力属于过程内(intra-procedural)控制流分析,在 SSA 基本块上工作。
目前,SyntaxFlow 规则已集成多项控制流分析工具。本文将重点阐述其新引入的本地调用(Native Call)功能更新。
一、目前的局限
在编写 SyntaxFlow 规则时,可能遇到如下的情况:
id := r.URL.Query().Get(\"id\") if !filterValidateID(id) { http.Error(w, \"invalid id\", http.StatusBadRequest) return}query := fmt.Sprintf(\"SELECT username FROM users WHERE id = %s\", id)_, _ = db.Query(query) // sink
单靠追踪数据流的上层定义链(def-use chain)这种思路,在此类问题上是行不通的。这是因为通过 db.Query 向上追踪数据流,只能找到filterValidateID和 r.URL.Query().Get,而找不到 if路径里面的 return 信息,此时使用纯数据流分析就很难判断 filterValidateID是否会影响后续 db.Query 的调用。
二、新增NativeCall的基础用法
YAK
1.getCfg
将 SyntaxFlow 命中(实参、赋值右值、调用等)映射到其所在的 SSA BasicBlock,作为内部 CfgCtx(func / block / inst)的统一锚点。
$sink
YAK
2.cfgGuards
以链上点为 sink,在同函数内扫描「头块 CFG 可达 sink」的二路分支:
1.若一侧到不了 sink、另一侧能到,则在截断侧识别 return / panic / break / continue,输出 GuardPredicateValue(形如 cfgGuard(kind=..., polarity=...))
2.若无合格分支,输出 kind=none 的合成守卫,避免过滤链断掉
$sinkCfg
YAK
3.cfgDominates
从函数入口沿控制流到当前 cfg,是否必经 target cfg(图论:target 支配 current)。同块内可按指令序细化。返回布尔常量 true / false。
foo() as $callprintln(* #-> as $sinkArg)$call<getCfg()> as $callCfg$sinkArg<getCfg()> as $sinkCfg$callCfg<cfgPostDominates(target: \"$sinkCfg\")> as $pd // true
YAK
4.cfgPostDominates
从当前 cfg 沿控制流到函数出口,是否必经 target(图论:target 后支配 current)。用于「往后走是否一定经过某点」。参数形式同 cfgDominates。
foo() as $callprintln(* #-> as $sinkArg)$call<getCfg()> as $callCfg$sinkArg<getCfg()> as $sinkCfg$callCfg<cfgPostDominates(target: \"$sinkCfg\")> as $pd // true
YAK
5.使用案例
在了解上述4个 native call 后,之前在本文开头提到的案例就有解决方案了:
id := r.URL.Query().Get(\"id\") if !filterValidateID(id) { http.Error(w, \"invalid id\", http.StatusBadRequest) return}query := fmt.Sprintf(\"SELECT username FROM users WHERE id = %s\", id)_, _ = db.Query(query) // sink
核心思路为使用 cfgGuards 判断上述控制流中没有 return 类型的截断:
<include('golang-database-sql')> as $sink;<include('golang-user-input')> as $input;*.Query as $func;*.QueryRow as $func;// ---------- 1. getCfg:source / sink 锚点 ----------// 用户输入命中点 → 基本块(与 include $input 同源)$input as $srcHit;$srcHit<getCfg()> as $sourceCfg;// Query 实参 → sink 基本块$func(* as $param);$param<getCfg()> as $sinkCfg;// ---------- 2. cfgGuards:sink 侧分支截断(过滤 return 守卫) ----------// sink 块上:存在「另一侧 return、本侧能到 sink」时得到 earlyReturn 等;!opcode:return 保留可分析链$sinkCfg<cfgGuards()> as $guards;$param?{<cfgGuards()>?{!opcode: return}} as $paramOk;// ---------- 3. 数据流 + 再次用 cfgGuards exclude ----------$paramOk #{ until: `/Sprintf/`, until: `*?{opcode:add}`, include: <<<CODE* & $inputCODE, exclude: <<<CODE*?{<cfgGuards(opcode: return)>}CODE,}-> as $path;// ---------- 4. cfgDominates:路径上的点须被 source 块支配 ----------// 从函数入口到该 SSA 点须必经 $sourceCfg(id 赋值所在控制流)$path?{*<cfgDominates(target: \"$sourceCfg\")>?{have: \"true\"}} as $high;alert $high for { level: \"high\", title: \"SQL injection (concat after validation)\" title_zh: \"校验后仍拼接 SQL,且 source 支配污点路径\" risk: \"SQL注入\", message: \"已用 getCfg 锚定 source/sink,cfgGuards 剔除 return 截断分支,cfgDominates 要求路径必经用户输入;请改用 db.Query(\\\"... ?\\\", id)。\",}
三、新增NativeCall的高阶用法
YAK
1.cfgReachable
当前 cfg 能否沿 CFG 到达 targetcfg。返回 true / false。
$callerCfg
1.icfg:是否仅过程内 CFG沿基本块 Succs 走,不进 callee、不从 return 回到 caller;
2.max_depth:限制「穿过多少次调用/返回」,防止 ICFG 搜太深(填写 -1 表示无限制);
3.max_nodes:BFS seen集合大小超过该值则整次搜索失败,返回空路径。
YAK
2.cfgReachPath
与 cfgReachable相同的起点、终点与 icfg 配置:可达时返回 (函数,块) 链证据字符串,不可达为空。
$callerCfg<cfgReachPath(target: \"$calleeCfg\", icfg: true, max_depth: 4)> as $path
过程内不可达时路径为空,可与 cfgReachable 搭配做规则调试输出。
YAK
3.cfgCondition
返回当前基本块上的条件摘要(inst / value / source / schema 等),覆盖 if、switch、loop、merge 继承等场景;无分支条件时可能为空。
$cfg
YAK
4.cfgConditionValues
与 cfgCondition 同源摘要,但直接给出条件关联的 SSA value 列表。
$cfg<cfgConditionValues()> as $v
YAK
5.reachabilityGuard
从函数入口出发,判断 target 是否在 mustExecute 意义下必执行(mode 目前仅 mustExecute)。
返回值(三种)
1.入口全路径必达且后支配成立 → 布尔 true
2.入口 CFG 不可达 target → false
3.否则 → 到达 target 路径上的条件 SSA value 列表(嵌套 if/loop 可能多项)
$from<reachabilityGuard(target=\"$to\", mode=\"mustExecute\")> as $guard
YAK
6.使用案例
id := r.URL.Query().Get(\"id\")tenant := r.URL.Query().Get(\"tenant\")role := r.Header.Get(\"X-Role\")// 过滤 1:ID 格式if !filterValidateID(id) { http.Error(w, \"bad id\", http.StatusBadRequest) return}// 过滤 2:租户if !filterMatchTenant(id, tenant) { http.Error(w, \"tenant mismatch\", http.StatusForbidden) return}// 过滤 3:角色(仅 admin/operator 可查)if !filterRequireRole(role, \"admin\", \"operator\") { http.Error(w, \"forbidden\", http.StatusForbidden) return}// 过滤 4:审计(不 return)filterAuditLog(w, \"getUser\", id)// 仍危险:校验通过后仍拼接limitStr := r.URL.Query().Get(\"limit\")limit, _ := strconv.Atoi(limitStr)if limit <= 0 { limit = 10}query := fmt.Sprintf( \"SELECT id, name FROM users WHERE id = %s AND tenant = '%s' LIMIT %d\", id, tenant, limit,)_, _ = db.Query(query) // sink
在上述的案例中有3个关键的过滤函数 filterValidateID,filterMatchTenant,filterRequireRole,一个无效的过滤函数 filterAuditLog,控制流结构如下:
入口 → Get(id), Get(tenant), Header(role) → [filterValidateID] ─失败→ return → [filterMatchTenant] ─失败→ return → [filterRequireRole] ─失败→ return → filterAuditLog (无 return) → Get(limit) → Sprintf ─┐ → db.Query ← sink(仅「三路校验都过」可达)
尽管我们可以通过串联 cfgGuards和 cfgCondition自底向上追溯调用链,但此方案存在局限:在进行代码扫描时,我们无法预知过滤函数的准确数量。若仅配置一次 cfgCondition,则大概率只能定位到调用链末端的最终过滤函数,而无法回溯到链上的所有中间函数。
下面 Syntaxflow 规则将使用 reachabilityGuard 一次性找到所有有效的过滤函数:

reachabilityGuard 就是为了解决这个问题而出现的,它的含义为:控制流想要从 from 移动到 to 的途中需要满足的所有条件。
四、对旧的语法补充控制流分析功能
YAK
1.<dataflow(...)>
<dataflow(...)> 是 SyntaxFlow 的 native call,在原有 include / exclude / end 路径过滤之上,增加了 按 CFG 锚点裁剪的参数。
1.only_reachable:指定锚点符号(如 $thenCfg),通常来自 <getCfg>,也可以是 frame 里任意能映射到基本块的 SSA 值;只保留「定义点 CFG 能到达该锚点」的结果。
2.only_reachable_mode:控制 CFG 过滤时机。post 在 include/exclude 路径匹配完成后,再按锚点后滤结果;path 在枚举 dataflow 路径时,对每一步扩展做可达性约束。
3.strict:设为 true 时等价于 only_reachable_mode=\"path\",即启用路径级 CFG 过滤。
4.icfg:过程内 CFG 判不可达时,是否启用跨过程 ICFG 再判可达;用于 caller → callee 等跨函数场景。
5.max_depth:仅在 icfg: true 时生效,限制 ICFG 搜索时的调用深度上限(跨过程边层数)。
6.max_nodes:仅在 icfg: true 时生效,限制 CFG/ICFG BFS 访问的状态节点数,防止搜索过大;超出则视为不可达。
案例如下:
$sink<dataflow(<<<CODE * #-> as $p CODE,include: <<<INC * & $input INC,exclude: <<<EXC *?{<cfgGuards(opcode: return)>} EXC,only_reachable: \"$sinkCfg\",only_reachable_mode: \"post\")> as $high
YAK
2.{ ... } ->
扩展了3个CFG相关的配置项:
1.only\_reachable:能 CFG 到达锚点
2.include\_reachable:包含目标 CFG 锚点
3.exclude\_reachable:排除目标 CFG 锚点
语法案例:
$sink * #{ include: * & $source, exclude: *?{opcode: call}, only_reachable: $thenCfg, exclude_reachable: $badCfg, until: * & $param,}-> as $out
include_reachable exclude_reachable 和之前已经存在的 include exclude 有不同的地方,在逻辑上它们的效果类似于剪枝,而后者的效果更倾向于过滤。
下面的案例可以帮助你理解:
c = \"test\"x = cif (c) { a = \"thenStr\" x = a} else { b = \"elseStr\" x = b}println(x)
println(* as $sink)a as $thenVal$sink * #{ include: `* & $thenVal`,}-> as $outInc // 得到 \"thenStr\"$thenVal<getCfg> as $thenCfg$sink * #{ include_reachable: `$thenCfg`,}-> as $outReach // 得到 \"thenStr\" 和 \"test\"
在第二个规则样例中,include_reachable的主要作用是包含 else 这条路径,因此在这条路径上的 \"test\" 也会被查找到,而第一个规则样例主要是为了在数据流中过滤某个变量,因此只保留了 \"thenStr\"。
五、总结
SyntaxFlow 的 CFG 能力是在既有 NativeCall 体系上的控制流语义扩展:
1.getCfg 提供统一基本块锚点
2.cfgGuards、cfgDominates、cfgReachable、reachabilityGuard 等链式 native 负责分支截断、必经关系与入口必达
3.dataflow() 与 # { ... } -> 则通过 only_reachable 及 post/path、icfg 等参数,在原有 include/exclude 路径模型上叠加「定义点是否 CFG 可达锚块」的过滤
控制流分析可以在保留数据流污点骨架的同时,显著减少 if/else 死分支、早 return 校验、phi 多值枚举带来的误报,并在内置规则中逐步替代依赖 opcode:phi 的间接写法。
未来总体目标是:让 SyntaxFlow 在「语法 + 数据流」之外,具备可编写、可组合、可回归的控制流感知规则表达能力,同时保持对存量规则的平滑兼容与渐进迁移。
END
更新记录
Yaklang 1.4.7-beta8
[Yakit]
-
Http Fuzz 专注模式 UI 优化,减少错误日志输出以避免前端过载;
-
gRPC TLS 启动支持查看证书信息
-
优化HTTPFuzzer发包错误提示并新增 TLS 自动重试能力;
-
Codec 编解码支持自动解码 Key;RSA 加密支持 JavaScript 解码风格;
-
修复 file.save 覆盖逻辑失败问题;
-
cli参数生成修正为有序模式
[Irify]
-
优化编译语言判断,提升准确率
-
修复C、GO、TS、Python的编译问题
[Memfit / AIgent]
-
MCP 服务:重构升级 MCP 服务,提供外接 MCP 与 Memfit AI 工具;并新增 MCP 服务工具面板;
-
模型与执行修复:修复 directly answer 多次不退出的问题;
-
能力更新:深度规划支持并发执行任务,todo列表优化展示
YAK官方资源
Yak 语言官方教程:
https://yaklang.com/docs/intro/
Yakit 视频教程:
https://space.bilibili.com/437503777
Github下载地址:
https://github.com/yaklang/yakit
Yakit官网下载地址:
https://yaklang.com/
Yakit安装文档:
https://yaklang.com/products/download\_and\_install
Yakit使用文档:
https://yaklang.com/products/intro/
常见问题速查:
https://yaklang.com/products/FAQ
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论