吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 985|回复: 7
收起左侧

[Web逆向] ob及变种混淆 ast 反解skill

  [复制链接]
13955925361 发表于 2026-10-29 17:40
本帖最后由 13955925361 于 2026-10-29 17:49 编辑

ob混淆反解skill · 对外分发版

obfuscator.io(ob)及其变种混淆 JS 的 AST 反解技能包:一套站点无关的可复用 Babel pass 库 +
"观察 → 归因 → 写 pass → 验证" 的工作流 + 解密器接线 playbook + 语义无损验证脚本。

本版不含任何样例代码、原始混淆文件或反解产物,也没有一键复跑脚本(它需要样例输入)。
所有命令都以你自己的 encode.js 为输入。skill/cases/ 里保留的是推导思路与判据,
不是可分发的代码;文档中不出现可定位的站点地址。
脚本注释里提到的 run_all.js 是开发包的一键复跑器(需要样例输入),本版未含。

一、目录结构

ob混淆反解skill/
├── skill/                     ★技能本体(文档 + 脚本)
│   ├── SKILL.md               入口:特征速查、管线、验收标准(先读这份)
│   ├── WORKFLOW.md            Stage 0~F 操作手册
│   ├── DECRYPTOR.md           解密器接线心法 + 原型库 A/B/C/D
│   ├── PITFALLS.md            28 个坑 + 十二条共性错误思考 + 排查顺序
│   ├── cases/                 三个案例的完整推导链(思路示范)
│   └── scripts/
│       ├── probe.js               Stage 0 指纹探测
│       ├── deob.js                ★默认入口(自动带 --auto-oracle --split-alias)
│       ├── deobfuscate.js         主管线(A 归一化 → B 解密 → C 还原 → D/E 收敛)
│       ├── passes.js              ★可复用 pass 库(含 --auto-oracle 多组解密器发现)
│       ├── test_gates.js          第 0 阶段:闸门自检
│       ├── check_decode_safety.js ⑥ 该不该解(S1~S4)
│       ├── verify.js              F1~F4 验收
│       ├── check_badvalues.js     错值 / 漏解检测
│       ├── runtime_smoke.js       产物真加载冒烟
│       └── browser_truth_probe.js 生成浏览器真值探针页(可选·事后)
├── node_modules/              56 个依赖包(按闭包复制,约 25 MB)
├── package.json
└── RUN.md                     本文件

二、环境要求

  1. 自带 node_modules:从 @babel/parser @babel/traverse @babel/types @babel/generator jsdom
    五个入口按各包 dependencies 递归求闭包后复制,放在任何目录都能跑,不需要 npm install。
  2. 栈大小:大 bundle 必须 node --stack-size=8000,否则会 Maximum call stack size exceeded。
  3. 全程离线:解密不需要浏览器、不需要 MCP。可选的浏览器对拍是产物出来之后的事后核对。

三、快速开始:解密你自己的 encode.js

按顺序执行(S = 本包根目录,encode.js 换成你的文件):

# 0) ★前置:先验"闸门本身"可不可信,再采信后面 safety 的结论
node --stack-size=8000 skill/scripts/test_gates.js encode.js --log out.gates.log

# 1) ⑥ 该不该解:数组封闭性 / 调用点纯读 / 取值确定性 / 值合法性
node --stack-size=8000 skill/scripts/check_decode_safety.js encode.js --json out.safety.json

# 2) 主管线:默认入口 deob.js 已替你带上 --auto-oracle 与 --split-alias
#    为什么设成默认:漏掉 --split-alias 不报错,只会让 `(wt=kt)(364)` 这类赋值式别名调用
#    【整组 0 处被解】,产物看着正常,只有 4) 的 provider 残留会报警——靠人记不如靠默认值。
node skill/scripts/deob.js encode.js decode.js
#    外部解密器(如 decrypt.js):node skill/scripts/deob.js encode.js decode.js --oracle-file decrypt.js
#    要显式关掉:--no-split-alias / --no-auto-oracle(本层开关,不传下游)

# 3) 验收:node verify.js <原始encode.js> <产物> [参考答案]
#    第三参数可省——没有参考答案时 D1/D2 自动跳过,F1~F4 仍是硬判据
node skill/scripts/verify.js encode.js decode.js

# 4) 错值 + 漏解检测(★必带 --base,否则覆盖率/方向性指标出不来)
node skill/scripts/check_badvalues.js decode.js --base encode.js

# 5) 产物真加载冒烟(jsdom + DOM/浏览器 API 桩)
node skill/scripts/runtime_smoke.js decode.js

--help 可看各脚本全部参数;外部解密器(不在 encode.js 里)用
deobfuscate.js --decrypt-module <你的解密器.js> 接线。

四、结果怎么判读

环节 合格 红线
⓪ preflight A 组该拒的都拒、该解的都解,C 组检查器不崩不空转 preflight 不过 ⇒ 后面 safety 的"危险 0 组"不可信
⑥ safety 危险 0 组(且报告里无 unchecked) 危险 N 组 ⇒ 那几组不能常量化;未覆盖/未判定 ≠ 通过
deob 日志有"解密 N 处"与"C7 回收",无 Babel 报错 解密 0 处 ⇒ 没认到形态(换 --group/--decrypt-module,别改主干)
verify F1~F4 全过;provider 残留 = 0 F3 悬空引用、F4 整组残留
bad badValues 为空;provider 形态数组残留 = 0;随机串占比低于原始 随机串占比反升 ⇒ 数组错位(静默错值)
smoke SMOKE OK(或报告与原始文件行为一致) 加载即卡死 / selfDefending 残留

三档口径:危险(查到且不符,exit=1)/ 未覆盖(该验却没验,exit=1)/ 未判定
(连重放都失败、拿不到 oracle)。第三档不产生替换风险,但绝不是"查过且通过"。

五、已知边界

  • 解密器在外部文件:单文件发现层看不到它,--auto-oracle 报 0 组属正常——改用 --decrypt-module 接线。
  • 该不该解的闸门是保守的:判不了就报"危险/未覆盖"并跳过该组,不会为了多解而放宽。
  • 两个真值源都是"解完之后"的可选核对(不是解密流程的一部分):
    ① browser_truth_probe.js 生成静态探针页,在真实浏览器跑原解码器切片,与沙箱值逐项对拍;
    ② 目标站同源双 iframe(A=原始 / B=产物)比可观测行为。没人开浏览器就先跑到第 4) 步全绿,产物即可用。

六、推荐阅读顺序

  1. skill/SKILL.md —— 特征速查表 + 验收硬指标,判断"这个站属于哪类"。
  2. skill/WORKFLOW.md —— 每个阶段干什么、先做什么(成员归并必须早于归一化)。
  3. skill/DECRYPTOR.md —— 解密器怎么接线;原型不匹配时怎么自己推。
  4. skill/PITFALLS.md —— 卡住时按末尾的"排查顺序"走,不要一上来就改 pass。
  5. skill/cases/ —— 需要"怎么想"的示范时再读。


ob-ast-deobfuscation —— obfuscator.io AST 反解流水线

这套技能解决什么

把 obfuscator.io(ob)及其变种混淆的 JS 还原成可读、可分析、可纯算的代码。核心资产是一套站点无关的
可复用 Babel pass 库
+ "观察→归因→写 pass→验证"的工作流 + 解密器接线 playbook。

设计哲学(务必先读):最终目标只有一个——反混淆成功。特征一样能直接复用最好;特征不一样,
也要能根据特征现场推理、写出插件完成还原。所以本 skill 沉淀的是"怎么想"的能力(学习原型框架 +
记忆踩坑归因 + 思考新形态推导),主干是通用 pass 库 + 推导方法,案例库是"如何从 AST 结构特征推导 pass"
的思考示范,不是"新网站匹配到样例N就套用样例N代码"的撞库查表。面对新站:

  • 结构 pass 直接复用——它们针对 AST 形态 + 作用域语义编写,形态在就触发、不在就安全空转,绝不因换站产出错代码;
    这条成立的前提是形态先被压统一:所以成员归并(Stage 0.5)必须排在归一化之前。不做它,各站的对象
    就是增量构建/别名组装/嵌套各式各样,后面每个 pass 都得加站点特有的附加筛选条件——可复用的要素就没了。
  • 默认不需要重写解密器接线:--auto-oracle 已把原型 A/D 都覆盖成一条按【结构特征】的通用前置
    (全作用域发现 N 组“数组 provider + 轮转 + selector” → 逐组抠源码沙箱重放 → 汇总成多组 oracle 表)。
    只有当解密器脱离真实环境跑不起来(要浏览器对象/自定义算法)时,才把接线写进 --oracle-module 的模块里,
    主干依然不动。★绝对不要为某个站去主干 pass 加“本站筛选条件”——那是下一个站又要改一次的债。详见 DECRYPTOR.md;
  • 原型都不匹配时,靠 cases 教的推导链(观察→归因→写 pass→验证)现场推——特例的价值是教会思考,
    特征还原只是副产品
    。

一句话:授人以渔。结构框架要背熟、可复用;具体筛选条件(偏移量/函数真名/参数形态/编码方式)每站现写;
特征对不上时,用 cases 里的思考方式自己推导。

目录

ob-ast-deobfuscation/
├── SKILL.md          本篇·总览与快速上手
├── WORKFLOW.md       七阶段流水线的步骤与原理(Stage 0→A→B→C→D→E→F)
├── DECRYPTOR.md      ★解密器接线 playbook:原型库 + 五步框架 + 推导法(每站唯一必重写处)
├── PITFALLS.md       踩坑记录(每条:现象→根因→修法→可复用教训)
├── cases/
│   ├── case-1-inline-trio.md         内联三件套+轮转(原型A)·无CFF/无包装器
│   ├── case-2-external-decryptor.md  外部双参解密器(原型B)·stringArrayWrappers+CFF+toString反调试
│   └── case-3-cff-wrappers.md        单文件内联四件套+索引表(原型D)·CFF外壳是 for(;!![];)·错值陷阱
└── scripts/
    ├── passes.js       可复用 pass 库(3 个 A-前置 + 14 个结构 pass + 静态求值下层 + 解密器接线层 + runPipeline)
    ├── probe.js        Stage0 特征探测(只读,输出指纹→决定开哪些pass/怎么接解密器)
    ├── deobfuscate.js  管线运行器(结构pass全复用,只在此接线本站解密器)
    ├── verify.js       静态语义无损验证(F1解析/F2编译/F3零悬空 + D1字符串/D2属性名 对照组差分)
    ├── check_badvalues.js 错值检测 + 【基线自证】(--base <原始文件>:非内建名下标 / provider 残留 /
    │                    fn(数字) 调用点消解率 / 随机串占比方向——后三条抓“根本没解”,不靠参考答案)
    ├── test_gates.js    【前置自检】用真实文件把闸门自己打一遍(写法绕过 / 崩/空转 / 把“没查”报成“安全”),
    │                    A 组 7 项 + C 组 4 项;发现不出组则 SKIP(盲区,不算通过)
    ├── check_decode_safety.js 【该不该解】四道闸门(S1 数组封闭性 / S2 调用点纯读 /
    │                    S3 取值确定性 / S4 值合法性),逐组出结论,任一不过 exit=1
    ├── browser_truth_probe.js 【真值对拍】把原始文件的解码器原样切片、在真 Chrome 里跑,
    │                    与 Node 沙箱重放逐组逐调用点比(验“值对不对、有没有整体错位”)
    └── runtime_smoke.js 运行时冒烟(整包加载 + 正则回溯定点探针,抓静态测不出的"一加载就卡死")

快速上手(新站点标准动作)

# 依赖:@babel/parser @babel/traverse @babel/types @babel/generator(脚本按位置向上找 node_modules)

# 0) 【前置自检】先验工具再验站点:拿一个有解密器组的原始文件把闸门自己打一遍
#    任何一项不符 ⇒ 后面 safety 报的“危险 0 组”全部不成立(发现不出组时 SKIP,那是盲区)
node scripts/test_gates.js encode.js [--group 组键] [--log gates.log]

# 1) Stage0 探测:看清用了哪些混淆手段 + 定位解密器
node scripts/probe.js /path/to/encode.js

# 2) 接线解密器并跑管线(据 probe 结果选选项)
#    · 解密器在外部文件(原型B):
node scripts/deobfuscate.js encode.js out.js --oracle-file decrypt.js [--oracle-name _0x293d]
#    · 解密器在源文件内(原型 A/D,无论几组、嵌在哪个作用域):一条命令自解析,无需手工抠源码
node scripts/deobfuscate.js encode.js out.js --auto-oracle [--oracle-name I]
#    · 调用点用别名(`wt = kt` / `(t = Mt, t(452))`):加 --split-alias(别名链由接线层自动反查)
#    · 解密器要真实环境才能跑:把接线写进自己的模块 → --oracle-module wire.js(主干不动)
#    · 仅结构还原/冒烟(不接解密器):不给 --oracle-file/--auto-oracle 即可

# 2.5) 【该不该解】逐组过四道闸门,再决定要不要常量化(★不解也要说明理由)
node scripts/check_decode_safety.js encode.js [--group 组键] [--json safety.json]
#      S1 数组封闭性(轮转之外有没有被写/逃逸)|S2 调用点纯读(不是赋值目标、不喂 eval)
#      S3 取值确定性(重读/交叉读一致 → 不依赖调用历史)|S4 值合法性(下标在范围内、可打印)
#      四道全过 ⇒ 可解;任一不过 ⇒ 打印证据 + exit=1,不许默默常量化
#      结果分三档:危险(查到且不符)/ 未覆盖(该验却没验,exit=1)/ 未判定(连重放都失败,汇总里单列)

# 3) 验证语义无损(【默认不需要参考答案】;有对照组才传第三个参数做 D1/D2 差分)
node scripts/verify.js encode.js out.js [reference.js]
#    静态全绿也可能【静默错值】或【漏解】—— 必跑错值 + 基线自证(基准=原始文件):
node scripts/check_badvalues.js out.js --base encode.js

# 3.5) 【终审】独立真值源(★不靠自己的沙箱自证)——【解完之后】做,不参与解密
#      ★解密全程离线:没有浏览器/MCP 时,跑到 4) 全绿就能交付;这一步是可选加强证据
node scripts/browser_truth_probe.js encode.js probe/
#      生成 index.html + node.json:原始解码器原样切片、各包一个 IIFE(防同名遮蔽),
#      有人开浏览器时读回 {groups,totalSites,okSites,mismCount}(mismCount 必须 0);没人开就先放着。
#      再进一步(同样只在产物完成后):目标站同源双 iframe 分别注入原始/产物,比导出面与字段结构。

# 4) 运行时冒烟(★必做:静态层在原理上测不出"语法合法但一执行就卡死")
node scripts/runtime_smoke.js out.js [--ref encode.js]

可复用 pass 库(scripts/passes.js)

站点无关、直接复用的结构 pass(形态在则触发,不在则安全空转):

Pass 作用 触发形态 关键安全闸门
A-前置<br>normalizeLiterals<br>splitSequenceStatements<br>restoreParamInit 先把"声明形态"立起来:模板串→字符串;语句级逗号序列拆成多句;函数头的形参初始化提成 var 声明 `a!b!c`.split('!') / a=…,b=…; / function f(a,b){ a={…}, b=fn } / function f(a,Y){ Y={}; … } / if (IH={}, IH["k"]=fn, …) 只提"常量/静态可证"的形参初始化;给形参占位改名以断开旧绑定,否则 binding 永挂在形参上;只认 if 的 test(其 test 只求值一次;while/for-test 每轮求值、do-while 在体后求值,提出去都不等价)
expressionSplit (A0) 拆赋值式别名调用 (wt=kt)(364) 仅纯改名赋值
constantFold (A1) 折常量表达式 a+b/x-y/!![]/-1 isNodesEquivalent 防死循环、exit 序防爆栈
identifierInline (A2) 别名内联收敛 var x=y;以及形参单次赋值 fx = I(含嵌在 if(test) 大逗号序列里的) 无重赋值 + 遮蔽检查;init 是形参绝不内联(值由调用方决定)
memberConsolidate (C0早期+C1解密后) 增量对象归并字面量 var o={};o[k]=v value hoist-safe + 写入门(条件门内不提) + 读晚于写;整体读取(Id=o/f(o))允许,只有把它当赋值/update/delete 目标才拒
removeDeadAliasAssignments (C1-D) 删死别名赋值 Id = IH 而 Id 被赋值后零次读取 左值单次赋值 + 零引用 + 右值无副作用 + 值被丢弃
collapseObjectAlias (C1-X) 对象别名折叠 IH = Y(同一对象换名后用 IH["k"]) Y 必须常量绑定 + X 单次赋值 + 赋值无条件 + 读取晚于赋值且能看到 Y + 全部替换成功才删赋值
inlineWrapperStrings (C2-S) 包装器字符串属性内联 _0x56c137['k'] resolveWrapperObject 三闸门 + 收敛迭代
inlineWrapperCalls (C2-J) 花指令调用内联 _0x56c137['cmp'](a,b) 自由名 binding 身份一致 + 沿用原形参名
removeUnusedWrappers (C2-R) 删空引用包装器 引用归零的对象 零引用零重赋值
removeSelfDefending (C6) 剥 selfDefending 自保护 / console 禁言壳 var X=W(this,function(){...search("(((.+)+)+)+$")...}); X(); 回调含嵌套量词正则 或 读 console 成员且串集含 log+warn;删 X() 与 W["k"](X) 两种触发器
unflattenCFF (C3) 控制流平坦化还原 while(!![]){switch(seq[i++])} / for(;!![];){...} 序列任一值缺 case 放弃;case 落穿(fallthrough)放弃;外壳带 init 时把 init 整段提到循环前(等价,init 只求值一次),非 for 的 init/let/const 则放弃;摊平后同处删 seq/idx 声明(替换前判定引用是否全在被替换子树内)
removeUnusedVars (C4) 死变量回收 零引用 var init 无副作用才删、先 reparse
removeDeadBranch (C5) 删恒定条件分支 if(true/false) var 提升保全 + 含函数声明放弃 + let/const 不摊平
removeDecryptInfrastructure (C7) 按引用计数连锁拆除解密三件套(轮转→selector→provider) 轮转 IIFE + 零引用函数声明 顺序硬依赖(反过来中间步计数永不为零);自记忆化 f=function(){} 是体内赋值必须放行;序列项只换占位值不整句删;binding 查不到视为在用;有 eval/Function 时只对全局零引用声明补“名字不得是字符串字面量”闸门(闭包内名字反射不可达,否则会白扣体积,见 PITFALLS #25)

接线层(decryptStrings(ast, oracle, oracleName) + 三个入口):
buildOracleFromExternalFile(原型 B:外部文件 module.exports)、buildOraclesByGroupReplay /
extractInlineStringDecryptor(原型 A/D:全作用域多组发现 + 逐组沙箱重放,含 provider→selector→轮转按序重放)、
--oracle-module(自己写接线模块)。selector 的两种 ob 写法都认:形态 M(自记忆化两条语句,偏移量在内层下标里)
与形态 S(单 return + 逗号序列)。★只认其中一种会让整个原型 A 站认不出解密器(case① 实测踩过,见 PITFALLS #23)。

已通用化的静态求值下层(站点无关,形态在则生效):singleAssignedValue(单次无条件赋值:覆盖
var a=v 与 if (..., a=v, ...) 两类载体)、staticObjectOf / staticStringOf(常量对象字面量取值)、
memberAssignedLiteral(o["k"]=<字面量> 成员赋值取值)、staticNumberPath(解密器参数的静态数值)。
详见 DECRYPTOR.md。

runPipeline(ast, opts) 按标准顺序串起来(顺序即依赖,见 WORKFLOW.md),opts 控制解密器接线、
是否开 expressionSplit、死分支轮数、只跑指定 pass。

特征速查表(识别入口层)

这是索引,不是答案:拿 probe.js 输出的指纹名对照,快速认出"这站像哪个原型 / 要开哪些 pass",
命中后必须回到 DECRYPTOR.md 或 cases 看推导链——表只告诉你"像谁",为什么这么写、
怎么纠错、本站要现写哪些筛选条件,全在推导示范里。指纹为 0 时对应 pass 安全空转,开着也无害。

probe.js 指纹 高值意味着 动作 去哪看推导
Top8 高频调用名 + numericArgCalls 定位到解密器 / 大数组函数。★两者都是下限不是事实:真名可能被形参别名遮掉而不进 Top8(case3 实测真名 I 不在榜),numericArgCalls 也不含"参数是索引表成员"的调用(case3:127 vs 实际 3902) 命不中就转看"形态类指纹";认原型 → 接线 Stage B DECRYPTOR.md §2 · case3 §1.1
rotatorIIFE(push+shift 循环)+ rotatorSizes 数组在运行期被原地校正;字节数悬殊时大的是主程序外壳不是轮转器 沙箱按 provider → 解密器 → 轮转器 重放,漏一步就静默错值 DECRYPTOR §1 步骤2 · case1 §4 · case3 §3
解密器 module.exports 在外部文件 原型 B buildOracleFromExternalFile case2 §1-2
解密器自记忆化(体内给自身赋值)+ 赋值式别名调用 (w=k)(n) 原型 A(常见多组、嵌在函数体内) --auto-oracle --split-alias:形态 M + 全作用域多组发现 case1 §2-4
解密器在源文件内、单return+逗号序列+z=z-N 原型 D(单组、顶层) 同一条 --auto-oracle(形态 S) DECRYPTOR §1 · case3 §2
assignToParam 高 + var 声明极少 ob 把索引表/解密器别名塞进函数开头大逗号序列(可能在 if(test) 里),不是 declarator A2 认“形参单次赋值”;静态求值用 singleAssignedValue PITFALLS #15 · case3 §4
memberAssignLiteral 高 索引表用 o["k"]=<字面量> 构建,不在对象字面量里 staticStringOf 回落 memberAssignedLiteral case3 §5
wrapperLikeObjects 高 stringArrayWrappers 包装器 C2-S/C2-J/C2-R,作用域绑定三闸门 case2 §3
switchOnUpdate 高(与 whileTrue 无关) 控制流平坦化 CFF;外壳可能写成 for(;!![];),此时 whileTrue=0 C3;缺 case / case 落穿放弃;序列载体要认全(switch(IZ[i++]) / switch(obj["k"][i++]) / switch("0\|1\|2"[i++]),只认第一种会让“C1 一归并、C3 还原数就掉”) case2 §4 · case3 §6
ifConstTest 高 恒真恒假死分支 C5 迭代删(var 提升保全) WORKFLOW Stage D/E
emptyObjectIncr 高 增量对象 var o={};o[k]=v C0早期+C1(hoist-safe 才归并,可能正确空转) case2 §6
emptyObjectIncr 高 但对象是从形参接来的(binding.kind==='param') ob 的“对象池”花指令:X={}; X["k"]=fn; Y=X; Y["k"](…),整段可能塞在 if(test) 或 for(init) 里;残留表现是大量 X["随机串"] 与 X["随机串"]=function 成对 按顺序:A-前置提成 var → C1 归并 → C1-D 删死别名 → C1-X 折别名 → C2 内联/删除。少任何一步都会停在“只剩成员读写但不删” case3 §7
toStringMarkers / debuggerStmt selfDefending 自保护 必须剥(C6):嵌套量词正则在源码变长后会指数回溯,产物一加载就卡死;console 禁言壳同为脚手架,一并剥 case2 §5 · PITFALLS #10

四条不可违背的语义安全底线

  • A. 能证明等价才替换:证明不了就原样保留(宁可留混淆,不可改行为)。
  • B. 作用域敏感:同名不同作用域绝不混为一谈;一律用引用处 scope 向上 getBinding,禁止按名全局查表
    (obfuscator 会跨函数重用同一个名字做不同对象,按名查表会拿错值且错得毫无痕迹)。
  • C. 刷新作用域看需要,不机械 reparse:一句话判据——接下来要跑的代码读不读 scope/binding?
    读:pass 之间用 reparse(重:整树重解析,runPipeline 的 step() 已统一做)、pass 内部改完又接着读就补 scope.crawl()(轻:只重扫当前作用域);不读:跳过。遍历引用一律 referencePaths.slice() 快照。
  • D. 变换必须配删除:任何"摊平/内联/折叠"的 pass,都要在同一处把随之失去用途的声明一并删掉。
    典型:C3 摊平 while(!![]){switch(seq[idx++])} 后,var seq=..., idx=0 就是纯脚手架。
    ★更难的是判据:replaceWithMultiple 之后 binding 已 stale(旧 referencePaths 仍指向脱树的旧节点,node 非 null),
    引用计数恒非 0、事后怎么查都"还有引用"。所以要在替换前判定"这些引用是否全落在即将被替换的子树内"。

验收标准(硬指标)

反混淆的唯一硬标准是语义无损,不是"代码变短",也不是"跟课程答案像不像"。
★默认没有参考答案:F1-F4 + 错值形态 + 基线自证(以原始文件算工作量) + 真跑冒烟 就已经能定案;
D1/D2 只是“凑巧有对照组”时多加的一层差分——而且对照组可能和产物有同源缺陷,“跟答案一样”≠“对”(坑26)。
每轮改完 pass 都用同一套客观检查卡一遍:

  • F1 产物可解析 / F2 可编译(vm.Script)/ F3 零新增悬空引用(产物 free 变量集合 ⊆ 原文件);
  • F4 特征残留(CFF 外壳/恒真 if 应为 0;剩下的 switch 应是业务原生);
  • D2 成员属性名“只对照组有” = 0(没误删任何 API 调用)。三类已内置解释,都不得当成误删:
    脚手架属性(console/constructor/bind,C6 剥壳正确移除)、包装器属性名内联后消失(值已就地出现在调用点)、
    换了载体(o.getterFor(i) 被 C2-J 内联成方法体、t.architecture = n 被归并进 {architecture: n})——
    最后一类判据只认“名字在产物里以键位/定义位/字面量仍在”,不许放宽到任意同名标识符(否则真误删也会被解释掉);
    ★反向的那个数(“只有我有”)不是分数,是待办清单:它多就说明有花指令包装器没删。case3 顺着它
    从 1079 降到 180,每一档下降都对应一个可复用的新闸门(C1-D / C1-X / if(test) 载体,见 case3 §7.1)。
  • D1 字符串差分:少的若住在对照组保留的解密器字符串数组里,已由“本站 C7 已拆除三件套”自动解释(死项),
    剩下的须人工归因(多为不透明谓词哨兵串/CFF序列串/被折叠合并的碎片,确认非误删);
  • F5 错值检测 + F6 基线自证(check_badvalues.js out.js --base encode.js):
    · 【抓解错了】产物里不得出现 "xxx"["随机串"] 这种非内建方法名下标;可打印率不得 <90%。
    ★这是唯一能抓“oracle 接错/数组错位”的静态手段:F1-F3 全绿、字符串看着都正常,但语义已经错了。
    · 【抓没解完】provider 形态数组残留必须 = 0、fn(数字) 调用点必须大量消解、
    随机串占比必须低于原始文件。三条全部以【原始 encode.js】为基准,不需要参考答案;
    退出码直接受它们影响(坑26:只靠“错值形态”永远查不出“根本没解”)。

静态层通过 ≠ 产物能用。必补 runtime_smoke.js:

  • 产物整包加载不超时(超时 = JSON.stringify//search 之类灾难性回溯,语法完全合法);
  • 正则回溯定点探针 0 命中:这一层不依赖站点环境,即使产物因缺全局早早抛错也能查出卡死结构;
  • 注意"执行抛错"不等于通过——代码没跑到底,卡死点可能根本没走到,必须看探针结论。

细节见 WORKFLOW.md、PITFALLS.md、cases/。

ob混淆反解skill.7z

2.16 MB, 下载次数: 310, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 4吾爱币 +4 热心值 +4 收起 理由
cnyjh + 1 + 1 谢谢@Thanks!
ClipperX + 1 + 1 我很赞同!
yaccc + 1 谢谢@Thanks!
helian147 + 2 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

zwh8698 发表于 2026-10-29 18:40
这个就很厉害了 真的
kof21411 发表于 2026-10-29 19:54
yaccc 发表于 2026-10-29 20:58
附件我下载不了不知道为什么 能甩个蓝奏云吗 感觉这个项目搭配rea很好用
 楼主| 13955925361 发表于 2026-10-29 21:05
yaccc 发表于 2026-10-29 20:58
附件我下载不了不知道为什么 能甩个蓝奏云吗 感觉这个项目搭配rea很好用

文件太大了,我压zip超过5M,上传不上去,下好了后叫ai帮你把skill装起来,想解哪个文件混淆直接叫ai用skill解就行,因为是通用的,速度肯定没有一键解快,他会自己写pass,遇到新类型它会自己写ast,你让ai多跑一段时间就行,不是一键搞定的那种类型。
new_ 发表于 2026-10-31 15:11
我去. 正好需要这个东西, 很强
nicen2 发表于 2026-10-31 23:49
学习一下,让AI
handpear 发表于 2026-11-10 15:54
感谢分享,学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-11-11 07:18

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表