wasm 学习笔记
Last updated on February 8, 2024 am
wasm 笔记
N1CTF Junior出了一道wasm的题目,前几天在国际赛TetCTF上也出了一道wasm的题,不过是属于签到级别,正好借此机会学习一下。
wasm简介
以下内容摘抄自MDN
WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。
于网络平台而言,WebAssembly 具有巨大的意义——它提供了一条途径,以使得以各种语言编写的代码都可以以接近原生的速度在 Web 中运行。在这种情况下,以前无法以此方式运行的客户端软件都将可以运行在 Web 中。
WebAssembly 被设计为可以和 JavaScript 一起协同工作——通过使用 WebAssembly 的 JavaScript API,你可以把 WebAssembly 模块加载到一个 JavaScript 应用中并且在两者之间共享功能。这允许你在同一个应用中利用 WebAssembly 的性能和威力以及 JavaScript 的表达力和灵活性,即使你可能并不知道如何编写 WebAssembly 代码。
TetCTF
题目只给了一个html文件,用谷歌浏览器打开然后测试一下
就是简单的输入然后判断,在html文件中很容易找到关键地方。
此函数用于接收回车信息,并获取文本内容然后调用processInput
函数
在processInput
函数中,先检查格式长度,然后调用wasm
模块内容
wasm
内容由前面的code
而来
可以在Chrome
等浏览器将文件下载下来
wasm
.init()
1 |
|
调用$1
1 |
|
这个函数就是对一些全局变量进行设定,全局变量在wasm
开始有定义
1 |
|
写成对应的python则是
1 |
|
wasm.array_fill()
继续接着往下看,调用了wasm.array_fill
函数
1 |
|
这个函数有两个参数,结合调用点可知,第一个参数是输入,第二参数是字符
值得一提的是,也可以通过打断点方式查看变量
可以发现wasm
中参数传递是通过栈来进行传递的,local.get
就是把参数放入当前这个函数的栈中,如果有调用其他函数,也先参数压栈,然后调用,这里调用约定是从左向右,即最右边的参数最靠晚压栈。
比如现在要调用i32.add
函数,它需要两个参数,那么就从栈顶依次弹出两个参数,然后调用该函数,如果函数有返回值,那么就压入栈中
现在就可以看到参数97
和19
已经弹出,而函数返回值97+19=116
则压入栈中
写成对应的python
1 |
|
以上两个函数都是对输入和全局变量做一些初始的处理,现在进入到check
函数
wasm.check
1 |
|
这个函数也很长,不过细看就会发现一个块在不断循环
1 |
|
这里涉及到$3
函数
1 |
|
这里稍微调试一下就知道是数组取值而已,重点是$4
函数
1 |
|
也比较长,但都是if else
的操作块,根据参数不同选择不同的操作
结合调用前的堆栈情况,以及调试,可以比较轻松的写出对应的python代码
1 |
|
然后就是最后$5
函数,不过这个函数就是比较而已
1 |
|
solve
因此整体加密函数如下
1 |
|
用z3一把梭
1 |
|
TetCTF{WebAss3mblyMystique}