首页
社区
课程
招聘
[翻译]WebAssembly的静态手动逆向分析
发表于: 2018-11-19 18:58 9226

[翻译]WebAssembly的静态手动逆向分析

2018-11-19 18:58
9226

在我们上一篇关于WebAssembly(Wasm)的博客中,我们初步了解了一个未知的Wasm二进制文件,并对其进行了一些行为分析。今天我们将继续深入研究相同的Wasm样本。我们将通过研究Wasm文本格式手动分析该样本。

为了能够手动分析Wasm文本,我们首先需要学习更多理论。我们之前的博文描述了如何处理内存和数据。在此基础上,我们将介绍一些对逆向Wasm有用的概念,然后应用这些知识来分析Wasm样本。

注意:这篇文章是系列文章的一部分。该系列的上一篇文章介绍了Wasm内存处理,所以可能需要阅读这些文章

正如我们在今年早些时候讨论的那样,Wasm本身不能与外界联系。与外部环境的所有通信都需要通过JavaScript API调用。考虑到这一点,我们现在主要讨论那些Wasm中对实际计算一些有用的指令 ,而不是调用JavaScript的指令。
与x86或x64的指令集相比,Wasm的指令集非常小,有几组不同的功能:

以下是常见Wasm指令的几个示例。有关更全面的说明列表,请参阅参考手册

上面给出是WebAssembly文本格式的说明。由于Wasm是二进制格式,因此这些文本指令将在编译文件中用字节码表示。

让我们分析一个简单的函数:

第一行表示一个名为'max'的函数,以两个整数作为参数,$0和$1,并返回一个 i32 (32-bit integer)类型的整数。

'select'指令有三个参数:第一个操作数(get_local $0),第二个操作数(get_local $1)和一个条件参数(在这种情况下是i32.gt_s指令及其相关的操作数)。如果条件操作数不为零,则'Select'返回第一个操作数,否则返回第二个操作数。

在select中,指令'i32.gt_s'检查第一个参数(get_local $0)是否大于第二个参数(get_local $1)。此检查的结果将保存在“select”运算符的条件操作数中。

因此,如果第一个参数大于第二个参数,则返回第一个参数,否则返回第二个参数。

请注意,不同的工具表示的Wasm文本格式可能会略微不同(就像不同的反汇编器一样)。例如,上面的例子也可以这样表示:

无论我们使用何种文本表示,它都对应于以下高级语言:

有关Wasm文本格式的更多信息,请访问此处

现在,我们理解了堆栈机,局部变量,全局内存,数据存储(如我们以前的帖子提到的),指令集和Wasm文本格式的概念,接下来用所学知识深入分析之前的博客文章中的Wasm示例

从之前的位置继续:最初的浅层分析和行为分析表明我们正在处理的是排序算法。对于这个样本,分析可能会在此时就完成了,具体取决于您可以在一个样品上花费多少时间。

如果我们处理的是一个功能不那么明显的样本怎么办?您可能经常需要查看源代码,接下来进行这项操作。

为了处理代码,我们将再次使用我们之前的博文中的wasm2wat工具。我们已经发现sort函数的函数号为1。下面是Wasm文本表示的该函数的第一部分:

它从函数定义开始,表示函数使用两个整数并返回一个整数。然后定义了一个局部变量local i32。用高级伪代码表示:

Wasm代码:

前两个指令get_local0/1分别获取第一个和第二个函数参数的值,并将它们压入堆栈。然后第三条指令i32.ge_s将对堆栈上的这两个值进行操作,通过隐式弹出它们然后判断第一个值是否大于或等于第二个值。比较的结果将被压入堆栈。如果堆栈顶部的值为非零值,则后续if语句将为true。换句话说,if语句的分支将取决于前面的三条指令。

如前所述,相同的代码可以用不同的方式表示。如果上面的if语句难以理解,这里有一个替代表示:

到目前为止我们所逆向的内容可以用高级伪代码表示,如下所示:

继续使用wasm2wat查看Wasm文本格式,发现sort函数:

这段代码进行数学计算。get_local 0/1指令获取传递给函数的两个参数值,随后的'i32.add'指令对这两个值进行操作,把它们相加并将结果压入栈中。

之后'i32.const 4'指令将4压入堆栈。后续指令i32.div_s将堆栈顶部第二项的值除以最顶部的值。换句话说,先前param1+param2的值将被除以4。在此之后,我们再次执行相同的模式,但这次除以2。同样,接下来的两条指令是i32.mul指令,操作数是4。

最终结果是目前获得的值乘以4。可以更简洁地表示为,代码执行以下计算:(param1 + param2)/4/2 * 4。

让我们看看随后的Wasm代码,右侧添加了我们的注释:

再一次,用高级伪代码表达:

如果这很难掌握,请尝试在Chrome中运行示例,单步执行并在调试器中查看(即DevTools)堆栈和局部变量值的变化,以及全局内存的构造。一篇关于Wasm分析的早期博文介绍了做法。当我们位于'call 0'指令时,在执行之前,局部变量和堆栈将如下所示:

图片

继续查看Wasm代码:

用高级伪代码表示:

总而言之,我们的最终结果是:

我们发现这确实是一个QuickSort实现。如果您愿意,可以通过将上述伪代码与您在Internet上找到的某些现有实现进行比较验证。逆向 partition函数留给读者练习。

我们现在成功地逆向了一个完整的Wasm函数。首先,我们使用wasm2wat程序将Wasm二进制格式转换为其文本格式,并通过分析文本格式,我们能够创建算法的高级伪代码。

存在用于执行自动反编译的工具,一种比我们今天所做的更有效的逆向工程方法。虽然自动反编译可以节省时间,但它通常不完美,对手动分析的理解使我们能够解决这些不完善之处。

翻译:看雪翻译小组 欢歌笑语
校对:看雪翻译小组 Nxe
原文链接:https://www.forcepoint.com/blog/security-labs/manual-reverse-engineering-webassembly-static-code-analysis

 
 
 

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

收藏
免费 2
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  junkboy   +2.00 2018/11/19
最新回复 (1)
雪    币: 11716
活跃值: (133)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
支持, 填补论坛空白
2018-11-19 19:26
0
游客
登录 | 注册 方可回帖
返回
//