WebAssembly安全研究总结
一、前言 WebAssembly(简称wasm)是一种可移植、体积小、加载快并且能够在浏览器上运行的一种程序文件。其能够在JavaScript通过接口进行调用执行。开发者们一直都比较关心JS的运行速度问题,V8引擎在JS的运行速度方面做了巨大的优化,但是少数情况下我们进行大量本地运算的时候,仍然可能遇到性能瓶颈,这个时候webassembly的作用就凸现出来了。例如AutoCAD利用编译器将其沉淀了30多年的代码直接编译成WebAssembly,同时性能基于之前的普通Web应用得到了很大的提升。 C/C++/Rust源代码可以被编译为WebAssembly文件,然后JS层就可以对其进行调用。WebAssembly文件中存储着字节码,位于JavaScript引擎中的WebAssembly虚拟机将会执行字节码。字节码的执行有两种方式,一种是在运行时边读取opcode边执行,另一种则是在执行前将整个WebAssembly JIT翻译为本地汇编代码,然后直接跳转到汇编代码执行。V8采用的是第二种方式。 二、WebAssembly虚拟机 WebAssembly虚拟机是一种栈虚拟机,变量使用栈进行传递。WebAssembly虚拟机有两个栈,即数据栈和指令栈。 WebAssembly的数据栈只用于存储数据,不会存储任何指针;指令栈只用于存储指令和数据在数据栈中的下标,不会存储任何数据,并且在执行opcode时会对取出的下标进行边界检查。由于WebAssembly将数据和程序流用栈给分隔开了,也就不会发生像汇编代码中的栈溢出劫持返回地址的漏洞利用手法。简而言之,WebAssembly中的所有指令都无法操作指针,也就不存在任意地址读写。但是传统的漏洞仍然存在,只是不能直接劫持程序流了。 三、WebAssembly文件格式 编译代码 emcc hello.c -s WASM=1 -o hello.html #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char buf[100]; memset(buf,0,100); scanf("%s",buf); printf("hello world: %s\n",buf); return 0; } 将得到的hello.wasm使用wabt项目中的wasm2wat转为S表达式 ./wasm2wat hello.wasm > hello.wat S-表达式是一个非常简单的用来表示树的文本格式,跟wasm二进制文件是简单的对应关系。 (module (type (;0;) (func (param i32) (result i32))) (import "wasi_snapshot_preview1" "fd_write" (func (;0;) (type 9))) (func (;0;) (type 8) i32.const 1 i32.const 2 i32.add .... ) (table (;0;) 9 9 funcref) (memory (;0;) 256 256) (global (;0;) (mut i32) (i32....