-
-
[原创]typora的launch.dist.js解读
-
发表于: 1天前 667
-
我在研究typora逆向的时候我遇到了JSC
我很感兴趣
好奇JS本身是不支持加载JSC的
它是如何做到require的时候引入了JSC的
过程中发现它是来自于:
7d5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6T1P5i4c8W2L8X3!0V1k6g2)9J5c8X3u0&6N6r3g2F1L8$3c8W2 这个项目
把JS变成JSC的里面会自动嵌入进去这段js加载逻辑
JS本身不支持运行V8编译的字节码(JSC)
但Bytenode作者利用了
Node暴露的V8 code cache被借来执行编译好的字节码

我们可以看到上面图片
答案是写上上面了
原因是它修改了 Node 的模块加载机制
Module._extensions[".jsc"] = loadJsc;
当遇到.jsc文件的时候 会走loadJsc函数
我们详细看看loadJsc函数
首先是一个fs.readFileSync
读取里面字节buffer

用了一个setFlagHashHeader函数
目的是
为了把dummyBytecode里面的V8 header复制到JSC buffer里面
让JSC代码执行的时候可以通过V8引擎的校验
大白话:
相当于:
告诉V8:这个bytecode是在你当前配置下生成的
问:他们V8在执行这个JSC文件字节码不对应的问题?
答:Typora 自带完整的 Electron 运行 不依赖系统安装的 Node.js 或 V8 所以不需要 并且JSC也是里面自带的V8引擎编译的
问:既然引擎是同一套 那为什么会出现flag hash不同出现需要特地覆盖的情况?
答:是因为构造时的JSC V8引擎的参数是默认参数 然后在执行JSC后的V8引擎不是默认参数 如下图
Launch.dist.js里面在V8引擎执行的时候加入了以下的参数
最终才导致的flag hash变化

接着继续看

sourceLength是在读取源码的长度为空间开辟做准备
buffer.slice(8,12)可以读取出jsc的源码长度
buffer2Number是把大端数据变成小端数据
dummySource用”\u200b”
原因也是很无聊
(我开始以为是什么很厉害的说法 干嘛不直接用空格)
就是因为单纯人看不到而已
V8官方代码里面就是只对长度进行hash
也就是长度对的上就行了

在开辟成功后会把开辟好的放到vm.script中占位让V8接受cachedData V8本身设计也是这样如果cachedData通过校验了那就会优先运行它
你可以认为是缓存来的
对于V8来说这样可以节省编译时间
大白话:
优先读字节码
是因为 「同一份脚本编译过就别再编译」 这个性能设计

runInThisContext就是相当于开关运行了

总结:
作者的思路很巧妙
能够特地去研究V8引擎的特性利用cache来运行字节码
还能够实现保护增加逆向难度
[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。