才过去一天,我又在研究 SC
的东西了(你的作业呢!!!!!!!!
嘛,我感觉我要死了,但是研究都研究了,时间也花了,没研究出什么不是很浪费,于是抱着这样的心态我开始接触 WASM
。估计大部分人初次接触 WebAssembly
应该都是以各种其他语言开始的吧,然而谁让我在逆向呢(悲)。
ToC
WebAssembly 文本格式
这部分的内容由于校赛需要被移到这里了:
WebAssembly 逆向简述
下面就直接开始了(
开始
从二进制到文本文件
二进制显然是看不了的,这里我们就需要用到 wasm
转 wat
的工具了。我这里使用的是 [wasm2wat](https://webassembly.github.io/wabt/doc/wasm2wat.1.html)
。
输入命令:
我们就得到了逆向所需要的基本文件。
JavaScript
层入口
一切都需要有个入口,而 WebAssembly
的逆向又需要分为 JS
层面和 WebAssembly 层面的。JS
层面的入口我选择了虾泥助手对应的函数,你也可以自行选择。
选择入口的目的是打断点。虽然 Chrome
的 WASM
调试还有些问题,但动态分析还是能很大程度上帮助我们了解函数执行的全貌(帮助我们更好地猜出实现)。
WASM
入口
WASM
的入口位于 f289
,也就是 (;289;)
。这个函数通过相对调用的方式调配了 decryptResource
和 encryptPath
两个函数的执行。真正的入口其实是:
decryptResource
:f304
encryptPath
:f302
这里就用到查表了,我们虽然不一定要完全弄清楚 Table,但使用还是要会的(
decryptResource
既然是调用的 f304
,那我们直接来看:
可以看到,这里仍然没有对数据作什么太多的操作,我们跟着进 f596
:
这里就有点意思了,出现了一个有点意思的未知数字:21514。这里我们还不知道它是什么,去看 f300
:
这里出现了超级敏感的操作:分配内存,而且还做了两次,一次是分配了两个 i32
的大小,而另一次则是和我们的输入有关的,byteLength + 1
大小。然而到这里,当时的我还是一无所知,不过看下面:
这里出现了一个循环和一个 xor
。这已经是很明显的特征了,然而当时的我并没有领悟,懵懵懂懂地看了过去,直到机缘巧合下返回来看……
我们看到,这个循环是对整个输入数组进行的,而循环的过程中对另一个量(实际上是数组,不过我们假装不知道)进行的循环的偏移访问,由此,我们可以推断:另一个量也是一个数组,并且存储的很有可能就是 XOR
的 key。
这时候就要问一个问题了:21514
究竟是什么?
数据段
仍然是 MDN 告诉我们:数据段允许字符串字节在实例化时被写在一个指定的偏移量。而且,它与原生的可执行格式中的数据(.data)段是类似的。而 21514
在执行过程中不断被当作地址使用,我们很容易推断:这是内存空间的一个地址。
于是我们来看 resource_hash.wasm
定义的 data
:
顺藤摸瓜,我们看到了熟悉的东西:
这个 WL[
基本可以算是刻在 DNA 里的特征了,而且正好这个字符串开头就是对应的 21514
,于是此时我们大胆推断:call 60
得到的结果就是字符串的长度。
想要验证这个推断是否正确,可以使用静态分析或者动态分析,这里我直接用了 Chrome 的调试工具,最终证明推断是正确的。但在推断之前,我也静态分析了很长一段时间,因此很难说到底是谁的功劳,应该是二者都有吧,没有静态分析我就不会作出这样的假设,而没有动态分析,估计这时候我还没把第一个函数推出来不是(
XOR 解密
之后就是随手搓一个 XOR
的时间了,这里给出一个 xjb 写的 C
程序:
然后随便下一个资源下来,我用的是 asset-map-aac011a61415a220560587aaf0177b2d98e8c7897d7697db4dd51b509162040d
,执行,binwalk
,然后我就傻了:
再一看 Dolphin
:
用 Ark
和 Kate
打开:
于是 decryptResource
成果解密(我之前怎么就没想到是 gzip
的魔数呢
encryptPath
数据段
有了上一个函数的经验,这里我们首先看的就是 data
段:
果不其然,甚至和刚才那段是同一行,还在那段的前面,出现了我们想要的信息:picosha2
。于是我们推断:最终结果是某一个值的 sha256
结果。
(其实也没那么容易作出判断,这里我是和 picosha2
的源码作比对之后确认了 sha256
计算在最后才得出的推论,但今后其实可以大胆一点,毕竟推错了也没什么太大影响,但一旦对了就能节省不少时间(
f302
同样是从入口开始,这次是 f302
:
可以看到,这里经过了两次 f164
,不知道干了什么,但这里我当时选择了先跳过,于是我们来看 f262
(并且后来证明 f164
并不大影响理解(
f262
不得不说的是,这部分的解密带有运气的色彩
这里最大的发现是它截取了 tail
(也就是第二个参数)的首尾字母,并且下面的 21154
的值恰好就是 %c%c
,于是猜测这两个字母是连续的。测试了一下随便更换 tail
的中间字母,发现也没有任何变化,基本上可以证实了:
接下来就是这两个字母到底是怎么放的问题了,于是我又开始猜测了:是不是开头/结尾?果不其然,结果是开头:
就此,整个 resource_hash.wasm
宣告解密完毕。
结语
这次的逆向过程可以说是我第一次认真对汇编级别的源码进行分析的过程。中间有试过用 wasm2c
转成 C
再用 gcc
编译再导入 IDA
,但效果并不尽如人意(还是我不大会 x86 汇编的锅)。相比之下,WASM
本身比 x86
的指令简单了 114514 倍,强行转过去不是自己给自己增加难度吗(
一晚上就这样过去了,不过总算是有结果了,也算是不辜负我这一晚上的爆肝吧(