REGeneral/PX-init.js-deobf

GitHub: REGeneral/PX-init.js-deobf

基于 Babel 的 PerimeterX init.js 去混淆工具,通过符号执行和静态分析还原被控制流平坦化及 basE91 字符串表隐藏的代码逻辑。

Stars: 0 | Forks: 0

# PX-init.js-deobf 使用 babel 编写的 PerimeterX init.js 文件去混淆工具。 ## 该工具针对的 PX 版本 我是针对带有 Human 品牌的 sensor 进行逆向工程的,其混淆使用了以下技术: - `basE91 字符串表`:一个通过 `hE()` 解码的大型 `hD[]` 数组,以及使用 `with(state) switch(sum)` 的控制流平坦化。 快速检查是否为正确版本的方法: ``` grep -c '8191 & c' init.js (>0 -> basE91 tables present) grep -c 'with (' init.js (>0 -> with/switch flattening) ``` ## 用法 ``` node pxclean.js init.js out.js --report ``` 依赖项: ``` npm i @babel/parser @babel/traverse @babel/generator @babel/types ``` 输出的代码用于阅读/分析,而不是用于在网站上重新运行(我很确定 PX 会对其自身的源码进行自检)。工具保证在语法上是有效的,如果出现任何格式错误,该工具会重新解析结果并在不写入文件的情况下中止。 ## 分析文章 我在一些事情上得到了 AI 的帮助,特别是在平坦化处理方面。我还没有看到有人发布过针对 init 的去混淆工具,所以我想试一试。 PX 将函数逻辑隐藏在一个 dispatcher 循环中。“程序计数器”是 2-4 个累加器变量的总和。每个 switch case 都是一个执行某些工作的 basic block,然后将常量添加到累加器以选择下一个 block,并 break 回到循环中: ``` function hI() { for (var …, hA = UF[0], hI = UF[1], hK = …; hA + hI !== 234; ) // (234 = terminal PC) with (hK.ci || hK) // (exposes the state object) switch (hA + hI) { // (PC = hA + hI) case hI - -58: …work…; hA += -329, hI += 368; break; // (next block) case -157: …work…; hI += 233; // (falls through to next PC) case hA - -347: default: return …; // (terminal block) } } var hK = hI(58, -254); // (initial accumulators) ``` 有三个因素导致其难以阅读: - block 的顺序是**被打乱的**:如果不进行累加器算术运算,你无法判断什么在什么之后运行。 - case 标签是可以被计算的:(`case hA - -347:`),因此匹配哪个 case 取决于那一刻的累加器值。 - 字符串查找是**动态的**:在 block 中你看到的是 `hF[hE(hA + 403)]` 而不是 `hF["length"]`,因为只有当你在该 block 中知道 `hA` 的值时,索引 `hA + 403` 才是已知的。 ### `hD` 以及为什么它不能被完全静态消除 反平坦化背后的主要目标是解析每一个 `hE(..)` 调用,使得 `hD` 字符串表(及其解码器)变得不再被引用,从而让死代码消除可以删除它们。这对编解码器起了作用,但仍有 6 个动态 `hE` 调用未被解析,因此 `hD` 被保留了下来。 这 6 个调用存在于静态执行无法到达的数据受控(data gated)block 中。 它们不在直线编解码器中,而是位于: - 事件处理程序清理循环:例如 L2810/L4523 处的 `removeEventListener` 循环,这些循环仅在特定的检测事件触发并存储了状态之后才会运行,以及 - 模糊循环:(L5238, L5967)其周围的控制流会根据运行时数据进行分支。 为了到达这些 block,符号执行器必须知道只在运行时才存在的状态: - 检测是否真的触发了 - 事件对象/dom 状态包含什么 - 数据驱动的循环要运行多少次迭代 当执行器遇到其中一个分支时,它会将相关的累加器标记为 TOP,并拒绝继续执行或猜测索引。猜测还不如保留原样,内联一个错误的字符串会破坏分析。因此,该工具在仅凭源码可证明的边界处停止。 静态推理可以为你解析整个 payload 编解码器以及大约 79% 的动态字符串索引,剩下的 21% 是只能通过实时运行时数据才能到达的控制流,因此要彻底消除 `hD`,需要运行脚本并在执行期间提取这些值。
标签:Babel, Bots防护分析, CMS安全, JavaScript, MITM代理, 云资产清单, 代码反混淆, 数据可视化, 自动化payload嵌入, 自定义脚本, 逆向工程