首页
社区
课程
招聘
[原创] 给"某音"的js虚拟机写一个编译器
发表于: 2020-8-12 15:10 77315

[原创] 给"某音"的js虚拟机写一个编译器

2020-8-12 15:10
77315

其实这篇笔记很久之前就写了, 写的零零碎碎的, 最近翻硬盘的时候看到了, 就想着整理一下发出来, 和大家讨论一下, 其中有些逻辑可能自己都不太清楚了(毕竟写代码不注释, 一周不看代码就不属于自己了, 手动狗头), 描述的有问题欢迎指出哈;

先看看原始文件是什么样的(一部分opcode片段), 这时候看还是比较乱的...

如何逆向这部分我这里不细说了, 单步调试的话还是很容易看出每个操作的意义的, 经过一步步单步分析后, 逻辑就清晰了很多, 可以看到不少压栈出栈的操作, 是一个基于堆栈的栈式虚拟机, 利用数组模拟堆栈, 且有作用域管理 (完整的代码我会放在附件)

esprima和escodegen的仓库

esprima

escodegen

既然已经知道每个opcode的作用, 那么如何针对这些opcode去写一个编译器呢? emmm...我这里选择了一个比较low的方式, 使用esprima把js代码解析成ast, 再使用escodegen解析ast的过程中(修改escodegen.js), 根据不同的type来生成自己的opcode的代码, 最后再写入文件...

比如在IfStatement不同的位置插入接口encrypt_code
59.png

encrypt_code根据不同的位置来生成opcode
60.png

这里我举ifelse分支的例子, 看看如何把js代码编译成该虚拟机可以执行的opcode的, 以及opcode的格式

测试代码:

使用编译器跑一遍, 在encrypt_code入口打印下的类型, 看一下经过编译器了哪些位置, 以及对应的js代码

这里可以看到每种类型对应的js代码, 接下来就是根据不同的类型生成opcode, 生成过程用文字描述会比较冗余, 这里我直接把生成的opcode结构贴上来, 就能很直观的理解了

以下为生成的opcode (虚拟机解析opcode的时候会先减去-32, 这里的已经处理了):

直接看又是很蒙是不是, 没事, 我们拆开和js代码比对来看就很清晰了

到这里以上代码整个opcode的解析过程就已经结束了, 在贴一下虚拟机执行的过程吧, 可以清晰的看到分支最后走到了a = 12

上面描述了如何实现一个简单的逻辑运算,分支派发的实现方式, 根据上述思路, 目前实现逻辑运算, IFELSE, 函数调用, 循环, 数组等等基本js语法, 我也找了md5, crc等一些算法测试, 改了下都可以正常跑

源码执行
61.png

编译后vm执行
62.png

源码执行
63.png

编译后vm执行
64.png

jsvm

用法其实也很简单, 安装完需要的模块后, 把修改后的escodegen.js替换node_modules\escodegen中的, 修改encrypt.js中需要编译的js文件路径再执行, 编译后会在./build/vm.js

最后想说这个东西只是个玩具, 发出来是想和大家交流一下, 文章中因为篇幅的原因没有描述太多细节, 大家想了解更多的细节可以直接去看看源码(写的很随性, 别吐槽...), 还有就是想吐槽下这种实现方式调试很痛苦, 中间很多一部分直接都花在找bug上, 大佬们有好想法可以不吝赐教哈...

 
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-8-12 18:59 被StriveMario编辑 ,原因:
收藏
免费 13
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  orz1ruo   +2.00 2020/08/18 助人为乐~
最新回复 (15)
雪    币: 5573
活跃值: (2153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢大佬分享!
2020-8-12 15:26
0
雪    币: 1867
活跃值: (3958)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
建议看雪老板们,开一个js安全板块emmm
2020-8-12 15:58
1
雪    币: 4046
活跃值: (3432)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
virjar 建议看雪老板们,开一个js安全板块emmm
我觉得可以
2020-8-12 16:40
0
雪    币: 3725
活跃值: (619)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
orz , 膜拜一下.
2020-8-13 09:49
0
雪    币: 4046
活跃值: (3432)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
逻辑错误 orz , 膜拜一下.
 大佬好
2020-8-13 10:16
0
雪    币: 182
活跃值: (540)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
谢谢大佬分享。这种直接从AST到vm指令,遇到break和continue这种语句很麻烦。还有个小问题,这种实现方法默认了var变量也有块级作用域,下面这样的代码,在加密前后会不一致:function test() { var a = 1; { var a = 2; console.log(a); }console.log(a);} test();
还有个问题请教下:这种vm加密如果只对一个js文件中的特定函数加密,怎么处理这个函数内使用了全局变量的情况?
2020-8-13 11:16
0
雪    币: 4046
活跃值: (3432)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
glider菜鸟 谢谢大佬分享。这种直接从AST到vm指令,遇到break和continue这种语句很麻烦。还有个小问题,这种实现方法默认了var变量也有块级作用域,下面这样的代码,在加密前后会不一致:function ...
可以把函数编译后, 放在window里, 在外面调用
2020-8-13 11:35
0
雪    币: 154
活跃值: (3786)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
膜拜
2020-8-14 17:37
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
之前做头条系列爬取的时候,就一直没明白那是个什么样的反爬产品,胡乱修改js解决后也没感觉收获到什么东西,感谢大佬指明方向,受益匪浅。
2020-8-14 18:45
0
雪    币: 4869
活跃值: (18865)
能力值: ( LV13,RANK:317 )
在线值:
发帖
回帖
粉丝
11
学习学习
2020-8-17 23:29
0
雪    币: 3372
活跃值: (757)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
感谢分享~
2020-8-19 17:34
0
雪    币: 2373
活跃值: (1041)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
13
现在各种网站使用栈式虚拟机来加密的情况越来越多了,急需这方面的资料。看了大佬的帖子受益匪浅。get了不少思路。。
2020-11-17 12:37
0
雪    币: 36
活跃值: (1061)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
14
mark
2020-11-17 13:55
0
雪    币: 0
活跃值: (296)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
mark
2022-5-25 12:24
0
雪    币: 0
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
 mark mark
2022-10-5 10:55
0
游客
登录 | 注册 方可回帖
返回
//