基于AST的逻辑指纹提取混淆检测器通过构建抗扰动语义结构标识,识别重命名、格式化等无功能改动后的同源混淆,核心包括函数声明、控制流骨架、调用关系拓扑、数据流关键点及作用域感知指纹序列,支持模糊匹配与集成检测流程。
要手动实现一个基于 AST 的逻辑指纹提取混淆检测器,关键不是比对原始字符串或行号,而是构建可复用、抗扰动的语义结构标识。它能识别代码是否被重命名、格式化、加空行等无功能改动后仍保持相同逻辑,从而判断是否属于“同源混淆”而非独立重写。
提取稳定、不可约的语义节点逻辑指纹必须避开易变的表层信息(如变量名、缩进、注释),只捕获编译器真正依赖的结构特征:函数声明:记录函数名(仅用于分组,不参与哈希)、参数数量、返回类型结构(如是否为 void / Promise / object)、是否有 async 或 generator 修饰控制流骨架:统计 if、else、for、while、switch、try/catch 的嵌套层级与出现频次,不记录条件表达式具体内容调用关系拓扑:提取所有 CallExpression 的 callee 名称(如 fetch、axios.get、Math.max),忽略参数值和属性访问链深度数据流关键点:识别赋值左侧的 Identifier(即被赋值的目标),仅保留其作用域层级(全局/函数/块级)和绑定类型(const/let/var/function)
构建作用域感知的指纹序列同一段逻辑在不同作用域中行为可能不同,指纹需体现上下文隔离:遍历 AST 时维护作用域栈,每进入函数/块级作用域就生成一个子指纹段每个子段以作用域类型 + 参数/变量声明签名开头(例如 “FUNC_2P_VOID” 表示双参数无返回函数)
内部节点按 DFS 遍历顺序追加简码(如 “IF-EL-RET” 表示 if+else+return 组合)
最终将各段拼接后取 SHA256 前 12 字符,形成轻量但高区分度的指纹支持模糊匹配与相似度判定真实场景中,混淆可能引入局部逻辑调整(如拆分 if、合并变量),纯哈希比对会失效:对两个指纹序列做编辑距离计算(Levenshtein),阈值设为总长度的 15% 以内视为高度相似支持子结构匹配:若主函数指纹一致,但某嵌套箭头函数新增一层 try-catch,则标记为“弱混淆”,提示人工复核对高频标准库调用(如 JSON.parse、Array.map)做白名单归一化,避免因导入别名(如 const j = JSON)导致误判集成到检测流程中该检测器不替代人工审计,而是作为初筛工具嵌入协作或交付环节:接收待检代码与基准版本(如主干 commit 或设计文档附带参考实现)
分别生成指纹,输出结构差异报告(例如:“控制流骨架一致,但变量绑定减少 3 处,疑似删减日志逻辑”)
支持批量扫描 PR 中的 .js/.ts 文件,标记指纹与历史高频恶意模式(如加密载荷解包、隐蔽 eval)接近的文件不复杂但容易忽略的是:指纹必须与语言规范对齐。比如 ES 模块的顶层 this 是 undefined,而 script 是 window,这种隐式上下文差异要在作用域建模中显式编码,否则跨环境混淆会漏判。
