首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
WEB安全
发新帖
2
34
[原创]JS 盾(JS DUN PROTECT)加固小记
发表于: 2026-6-23 19:40
4396
[原创]JS 盾(JS DUN PROTECT)加固小记
一只鸭子
2026-6-23 19:40
4396
# JS 盾(JS DUN PROTECT)分析日记 > **作者:** 人生导师 > **日期:** 2025 年 6 月 结论先说:JS盾的设计思路很强——双层动态代码执行、VM指令集覆盖完整、虚拟方法表(X.$)的设计在国内JSVMP里算独一档。但它的强度核心在于**膨胀**而非**精巧**:13000+行的JSVMP、层层嵌套的短路混淆、壳产出的运行时检测代码。追了两天,摸清了整体结构,结论是**除非有明确的业务需求,不要对抗这个东西,非常非常浪费生命。** 下面从头拆。 测试代码很简单,就一段 `console.log`: ```js function myScript(){ console.log("把要加固的代码粘贴到框框里,剩下的就交给我们吧") }; myScript(); ``` 加固产物膨胀得巨大,字节码满天飞,调用链乱成一锅粥。不过正因为源码简单,加固后不至于难上天际,正好拿来摸清整体结构。 --- ## 工具和阅读策略 VSCode 直接报废——括号全乱,格式化不可信,甚至直接报错。最后用 Vim 手动看。搞完 AKM 之后有个经验:对混淆严重的代码,**先看括号闭合状态,看的是结构而不是变量名。** 扣了一个小时后发现,这个加固不能按之前阿卡迈那种逐行扣法来搞。必须先通读一遍,理解整体结构,然后才能逐块分析。 --- ## 整体架构 整个文件是一个 `eval` 包裹的立即执行函数: ```js eval(function r(n, Z) { var r = "JS DUN PROTECT", e, k, y, t, f, ...; return (((((...) && (...) || (...)) && ...)); }(...)) ``` `eval` 里的函数 `r` 接收两个参数:`n`(字节码)和 `Z`(始终为 `undefined`,用于短路判断)。整个函数体就是一条 `return` 语句——用 `&&` 和 `||` 短路运算串起来的超长表达式链。 这条链按执行顺序做了三件事: 1. **初始化阶段**:声明变量,缓存原生方法引用(`Math.sin`、`JSON.stringify`、`String.fromCharCode` 等) 2. **字节码解码 + 第一轮 VM 执行**:解码一个巨大的编码数组,传入 VM 解释器 `p`(即函数 `X`)执行 3. **第二轮 VM 执行**:重置计数器,再次调用 `p`,这次传入代码生成器相关的 handler 函数 两轮 VM 之间的衔接点长这样: ```js 前面是超长字节码数据 "H77"]))) || 1) && (T = 0) && 0 || (V = p(Q, 后面跟N个函数)) ``` 拆开看: | 片段 | 作用 | |------|------| | `])))` | 关闭字节码数组和第一轮 `p(...)` 调用 | | `\|\| 1)` | 无论第一轮返回什么都为 truthy | | `&& (T = 0) && 0` | 重置计数器 T,然后故意让左侧变 falsy | | `\|\| (V = p(Q, ...))` | 触发第二轮 VM 调用,结果赋给 V | 这种 `&& 0 || expr` 的写法在整个文件里到处都是。本质就是「先执行副作用,再跳到下一个表达式」——把顺序语句伪装成了一条表达式。 --- ## 核心设计:X.$ 虚拟方法表 这是我目前没见别家用过的手法,也是整个加固里最有价值的部分。 ```js X.$ = [ X.$ = "1.1", X.apply[X.$] = X.call[X.$] = X.call, X.apply, [].push, [].pop, [].concat, [].slice, X.bind, function (r, n, Z, e, k) { return 7 == r ? X.$[1][X.$[0]](X.$[3], n, Z, e, k) : 2 == r ? X.$[1][X.$[0]](X.$[r], n, Z, e) : X.$[1][X.$[0]](X.$[r], n, Z) } ] ``` 这三行代码构造了一个数组,充当 VM 的操作原语表(vtable)。表里的每一项对应一个底层操作: | index | 值 | 含义 | |-------|-----|------| | 0 | `"1.1"` | 属性名 key | | 1 | `Function.prototype.call` | call 间接引用 | | 2 | `Function.prototype.apply` | apply | | 3 | `Array.prototype.push` | 压栈 | | 4 | `Array.prototype.pop` | 弹栈 | | 5 | `Array.prototype.concat` | 数组合并 | | 6 | `Array.prototype.slice` | 数组截取 | | 7 | `Function.prototype.bind` | 绑定 | | 8 | dispatcher 函数 | 统一调度入口 | 这个设计分三层来理解。 ### 第一层:函数对象属性污染 数组构造过程中有个前置副作用: ```js X.$ = "1.1" // 先赋值字符串 X.call["1.1"] = X.call // 给 Function.prototype.call 挂了个 "1.1" 属性 X.apply["1.1"] = X.call // 同理 ``` JS 函数本质是对象,可以挂任意属性。这里用字符串 key 把真实的函数引用藏了起来——你用 `Object.keys` 遍历根本看不到。 ### 第二层:双层 call 跳板 调度器里的核心表达式: ```js X.$[1][X.$[0]](func, thisArg, ...args) ``` 展开执行过程: ``` X.$[1] → Function.prototype.call X.$[0] → "1.1" X.$[1]["1.1"] → Function.prototype.call(刚才挂上去的属性) 调用 call,this 指向 call 本身 → call.call(func, thisArg, ...args) → func.call(thisArg, ...args) ``` 两层 `.call` 绕了一圈,本质就是 `func.call(thisArg, ...args)`。但静态分析工具看到的是 `X.$[1][X.$[0]](...)`——完全没法推断出实际调用了什么。 ### 第三层:opcode 化分发 调度器通过参数 `r` 选择目标函数: ``` X.$[8](3, arr, val) → push.call(arr, val) // 压栈 X.$[8](4, arr) → pop.call(arr) // 弹栈 X.$[8](5, arr1, arr2) → concat.call(arr1, arr2) // 合并 X.$[8](6, arr, n) → slice.call(arr, n) // 截取 X.$[8](7, arr, a, b, c) → push.call(arr, a, b, c) // 多值压栈 X.$[8](2, fn, ctx, args) → fn.apply(ctx, args) // 函数调用 ``` `r` 不是普通参数,而是函数 opcode。整个 VM 的栈操作和函数调用全部收敛到 `X.$[8]` 这一个入口。 ### 这种设计巧妙在哪 **破坏 AST 可读性**:没有任何直接函数调用,全部变成数组索引访问加间接 call。AST 分析工具基本废了——它看到的是属性访问和函数调用,但完全不知道调用目标是什么。 **统一执行入口**:所有底层操作走一个调度器,方便做 hook 检测。如果有人 hook 了 `push` 或 `call`,调度器层面可以感知到异常。 **opcode 化**:JS 的原生方法被编号成指令,跟 VM 的字节码指令集在同一个抽象层级。整个执行流都在 VM 的控制之下,没有逃逸到外部。 --- ## 壳与代码生成 第二天的重心放在了壳的机制上。JS盾的壳跟 Android 加固的思路很像,只不过不需要 mmap 去开空间——JS 里直接 `Function` 构造器搞定。 整体流程: 1. 最外层字节码(嵌入在 `eval` 调用中)传给 VM 执行 2. VM 执行完毕后产出**第二块字节码**——这块字节码才是真正生成目标 JS 代码的 3. 壳负责:代码产出、字符串解码、格式化检测(格式化后代码会被检测到并拒绝执行) 4. 因为要写域名白名单,解密出来的 JS 里还夹带了域名校验和时间格式化 我用模型辅助补了一下环境(`document`、`navigator`、`location` 等),解密产物可以在 Node 上跑了。补环境的代码大概长这样: ```js const realNow = Date.now; Object.defineProperty(Date, "now", { configurable: true, enumerable: false, writable: true, value: function () { return 1782277958218 } }); globalThis.location = { href: 'https://www.baidu.com/', host: 'www.baidu.com', hostname: 'www.baidu.com', }; globalThis.window = globalThis; globalThis.self = globalThis; // ... 补了一堆 document / navigator / screen / history ... ``` 补环境这块不算难——缺什么补什么,配合模型很快。 --- ## JSVMP 本体:太大了 壳解密出来的 JSVMP 代码,格式化后 **24000 行**(原始 13000 行),是我见过最大的 JSVMP。 见过第一天的 VM 结构和 X.$ 设计之后,已经能判断这块的本质:用膨胀换安全。opcode 足够多、调用链足够乱、字节码足够长——但**设计上没有超出第一天看到的那套框架**。只是量变,不是质变。 所以没深入追。一些字符串可以通过 AST 直接看到明文。花时间进去能扣出来,但性价比太低。如果有业务需求——比如要过某个用了 JS盾的站的协议——那另说。纯研究角度,不值得。 这里有个坑:代码格式化后会触发壳的检测逻辑,导致拒绝执行。所以如果想自动化处理,要么**不格式化直接补环境跑**,要么自己写一个可靠的反混淆器(这条路的成本远超预期)。 --- ## 值得学习的思路 拆完之后想了一下:如果让我自己实现一个类似的保护方案,应该怎么分层递进?以下是整理后的思路。 ### 第一阶段:简单 Loader - Base64 编码/压缩 - 运行时恢复 - `Function` 构造器执行 目的是熟悉代码隐藏→恢复→执行的完整流程。不涉及 VM。 ### 第二阶段:小型 VM 支持几十条基础指令: ``` LOAD_CONST LOAD_VAR STORE_VAR ADD SUB CALL RETURN JMP JMP_IF ``` 把简单 JS 编译成自己的字节码,再写解释器执行。到这一步就能理解「VM 怎么把 JS 变成字节码再执行回来」。 ### 第三阶段:自动变换 在第二阶段的基础上增加随机化: - 指令集随机化(每次构建 opcode 映射不同) - 常量池布局变化 - 控制流布局变化 - 字节码格式变化 这样不同构建产物之间不完全一致——即使算法相同,静态特征也对不上。 对于环境检测部分,建议交给被加密的业务代码自己处理。做的是盾,不是整体反爬方案。关注点收敛,否则越做越散。 --- ## 总结 JS盾在 JSVMP 这个方向上做到了国内 T0 级的程度。核心亮点是 **X.$ 虚拟方法表**——用数组索引 + 双层 call 跳板隐藏函数调用,再通过 opcode 化把原生方法纳入 VM 控制。这套设计值得学,也值得在自己的项目里借鉴。 但是它的问题也很明显:**强度靠膨胀撑起来的。** 13000 行的字节码、层层嵌套的短路混淆、格式化检测——这些会让逆向的人很痛苦,但不代表攻不破。只是时间成本太高,对单兵来说不划算。 对比 Android 端的 VMP,JS 盾已经算仁慈了——至少不用读超级碎片化的汇编。但结论不变:**没有业务需求驱动的话,追这个东西是在浪费生命。** 壳的代码生成、字符串解码、格式化检测这些机制是通的,JSVMP 本体没深追。等哪天真有需求了再说。
回复或点赞可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-6-24 20:42 被一只鸭子编辑 ,原因: 更新内容
#其他
收藏
・
2
点赞
・
34
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
nonovo
为你点赞!
2026-9-7 15:01
菜鸟小飞飞
为你点赞!
2026-8-22 22:30
mb_lthgjpwj
为你点赞!
2026-8-21 07:42
lpyqwq
你的分享对大家帮助很大,非常感谢!
2026-7-29 22:47
npc0vo
期待更多优质内容的分享,论坛有你更精彩!
2026-7-27 22:22
Tokameine
为你点赞!
2026-7-16 19:29
mb_dtidoewd
这个讨论对我很有帮助,谢谢!
2026-7-16 19:26
wx_晨梦
你的帖子非常有用,感谢分享!
2026-7-16 07:58
afishlong
为你点赞!
2026-7-14 18:41
nekomiao
你的分享对大家帮助很大,非常感谢!
2026-7-11 16:24
mb_uyxhrjco
感谢你的积极参与,期待更多精彩内容!
2026-7-10 11:49
xiaoqianran
感谢你的积极参与,期待更多精彩内容!
2026-7-9 02:52
git_95192AFCaternos
+1
为你点赞!
2026-7-3 17:29
Cohen
+1
你的帖子非常有用,感谢分享!
2026-7-2 11:36
git_86861charleywright
谢谢你的细致分析,受益匪浅!
2026-7-1 01:56
王叔叔
感谢你的积极参与,期待更多精彩内容!
2026-6-30 15:32
小傲骨
感谢你分享这么好的资源!
2026-6-29 17:35
孤独的街
感谢你的贡献,论坛因你而更加精彩!
2026-6-29 12:02
哇哈哈919
你的分享对大家帮助很大,非常感谢!
2026-6-25 18:07
MsScotch
非常支持你的观点!
2026-6-25 11:24
ONewTach
谢谢你的细致分析,受益匪浅!
2026-6-25 08:54
mb_cebxltxx
为你点赞!
2026-6-24 16:49
杨如画
这个讨论对我很有帮助,谢谢!
2026-6-24 14:55
LyonzzZ
这个讨论对我很有帮助,谢谢!
2026-6-24 14:53
huangyalei
你的分享对大家帮助很大,非常感谢!
2026-6-24 11:43
梧桐生
谢谢你的细致分析,受益匪浅!
2026-6-24 11:08
路过1
非常支持你的观点!
2026-6-24 10:13
IPerseus
感谢你分享这么好的资源!
2026-6-24 09:58
mb_asiwnxyv
感谢你分享这么好的资源!
2026-6-23 22:16
mb_rjdrqvpa
感谢你的积极参与,期待更多精彩内容!
2026-6-23 21:20
顽劣
谢谢你的细致分析,受益匪浅!
2026-6-23 20:15
令狐双
你的帖子非常有用,感谢分享!
2026-6-23 20:11
mb_ctripmfd
感谢你分享这么好的资源!
2026-6-23 20:06
mb_itintnpm
你的帖子非常有用,感谢分享!
2026-6-23 19:53
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
17
)
LuoJunJunJun
雪 币:
20
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
8
粉丝
0
关注
私信
LuoJunJunJun
2
楼
你的帖子非常有用,感谢分享!
2026-6-24 14:52
0
xingbing
雪 币:
158
活跃值:
(5671)
能力值:
( LV2,RANK:10 )
在线值:
发帖
2
回帖
1376
粉丝
2
关注
私信
xingbing
3
楼
学习
2026-6-24 14:55
0
一只鸭子
雪 币:
331
活跃值:
(920)
能力值:
( LV3,RANK:20 )
在线值:
发帖
15
回帖
57
粉丝
76
关注
私信
一只鸭子
4
楼
感觉写的好水,好像说了什么内容但是又没说什么东西
2026-6-24 20:42
0
mb_wqvhhpxn
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
10
粉丝
0
关注
私信
mb_wqvhhpxn
5
楼
学习
2026-6-25 10:40
0
Imxz
雪 币:
112
活跃值:
(9420)
能力值:
( LV2,RANK:10 )
在线值:
发帖
6
回帖
752
粉丝
9
关注
私信
Imxz
6
楼
tql;
2026-6-25 15:34
0
mb_ddvtjyuf
雪 币:
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
7
粉丝
0
关注
私信
mb_ddvtjyuf
7
楼
good
2026-6-29 11:29
0
kingking888
雪 币:
3152
活跃值:
(6202)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
288
粉丝
6
关注
私信
kingking888
8
楼
666
2026-6-30 01:10
0
zylyy
雪 币:
144
活跃值:
(2723)
能力值:
( LV2,RANK:10 )
在线值:
发帖
11
回帖
490
粉丝
3
关注
私信
zylyy
9
楼
666
2026-6-30 02:21
0
mb_vdakxenl
雪 币:
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
13
粉丝
0
关注
私信
mb_vdakxenl
10
楼
666
2026-7-6 17:02
0
mb_lghhumnu
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
22
粉丝
0
关注
私信
mb_lghhumnu
11
楼
666
2026-7-13 18:06
0
往事三杯酒
雪 币:
272
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
14
粉丝
0
关注
私信
往事三杯酒
12
楼
6666
2026-7-16 18:34
0
道友请留步
雪 币:
138
能力值:
( LV1,RANK:0 )
在线值:
发帖
1
回帖
45
粉丝
0
关注
私信
道友请留步
13
楼
111111111111
2026-8-7 09:47
0
smallfawn
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
3
粉丝
0
关注
私信
smallfawn
14
楼
666666666
2026-8-21 15:32
0
xiaoez
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
14
粉丝
0
关注
私信
xiaoez
15
楼
666
2026-8-24 14:47
0
mb_czswwkmf
雪 币:
215
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
2
粉丝
0
关注
私信
mb_czswwkmf
16
楼
666
2026-8-29 13:23
0
zaomiaossr
雪 币:
24
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
6
粉丝
0
关注
私信
zaomiaossr
17
楼
66666666666
2026-9-7 14:30
0
mb_qimctavn
雪 币:
5228
活跃值:
(6625)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
386
粉丝
1
关注
私信
mb_qimctavn
18
楼
6
2026-9-7 14:45
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
一只鸭子
15
发帖
57
回帖
20
RANK
关注
私信
他的文章
[原创]基于 Trace 的 VMP 还原实践文档
325
[讨论]逆向死没死
383
[原创] 七神VMP真正的分析与还原
5465
[原创] 用 P-code 做 VMP 还原:一份实战向的 IR 入门
3206
[讨论]模型的理解
378
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部