解决基于VM的CrackMe的问题

来源:岁月联盟 编辑:猪蛋儿 时间:2020-03-16
接下来,我们需要创建基于字节码执行的实际函数,因此让我们采用前面的伪代码并将其放入脚本中。
调用就绪后,现在只需创建一个函数来解析字节码并调用对应于操作码的函数。虽然我们不能创建一个确切的switch语句,但是我们可以使用字典,遍历每个指令,使用opcode来确定执行哪个函数,并确保在调用VM函数之前设置了self.operand1和self.operand2。
最后,让我们添加一个main()函数,该函数将打开ram.bin,读取它,并将数据传递到VM类,然后在它输出标记之前(使用分隔符 “}” 分割它,并以一种非常符合python风格的方式将它添加回字符串)。在添加了所有内容之后,我们就得到了最后的脚本。执行脚本将输出后,把这个结果输入到标记检查器,我们就得到相应的结果。
我们有正确的标志!但是,目前我们正在从内存转储中获取标志。如果我们没有给定的内存转储,而必须解析主可执行文件以首先找到字节码的地址,然后转储并解析,该怎么办?好吧,让我们看看是否可以做到!
首先,我们需要编写一个YARA规则来检测和定位将指向VM字节码的memcpy()调用。如果这是一个真正的恶意软件样本,这个方法会很不切实际的,因为它依赖于存在只有一个二进制memcpy()调用,因为YARA只是用来检测恶意软件样本,而不查找地址。
现在,让我们开始编写规则mwt_vm_rule.yar。 YARA根据给定的规则在样本中搜索字符串,十六进制模式等。我们需要找到对memcpy()的调用的十六进制字节,并使用该字节创建规则,因此让我们快速跳回IDA,并查看我们正在处理的内容。
因此,查看这个函数,将值0x1FB推入,将偏移量推入,将dword推入,然后调用memcpy()。我们希望在本例中获得偏移量,但是我们不能简单地搜索push offset 0x404040,因为重新编译可能会改变这个偏移量,所以不是0x404040,而是0x404010,这将导致YARA在检测模式方面出现问题。这对于被推送的dword和对memcpy()地址的调用是相同的。因此,我们必须在规则中使用几个通配符。通配符表示为??,表示该位置可能有值。由于通配符相当多,因此增加了误报的机会。因此,我们将使用大小0x1FB作为常量来保持低误报。
因此,我们的YARA规则(基于上面的十六进制视图)如下所示:
{A3 ?? ?? ?? ?? 68 FB 01 00 00 68 ?? ?? ?? ?? A1 ?? ?? ?? ?? 50 E8 ?? ?? ?? ??}
将其放入.yar文件中,就形成了完整的规则:
在终端上使用yara mwt_vm_rule.yar vm1.exe运行此命令,将返回mwt_vm_rule vm1.exe,这意味着规则有效,并且字节模式位于二进制文件中!现在,我们只需要将此端口移植到Python3,从全字节模式解析地址,将虚拟地址转换为文件偏移量,然后提取数据即可!现在开始吧。
同样,我们将使用类,这次是类YARA()。对于_init__()函数,我们将接受文件名作为参数,并使用yara.compile()初始化规则。
这样,我们可以创建一个find_rule()函数,该函数使用YARA的.match()函数在二进制文件中搜索字节模式。然后,我们解析实际字节匹配返回的内容(它将包含我们需要的地址)并将其返回,我将其放在try语句中,因为该匹配可能在相似的示例中不存在,因此我们可以解决此问题。
到目前为止,执行此代码(在返回值上使用binascii.hexlify())将返回此值字符串,该字符串已由|分割。显示重要字节:
A33c42400068fb010000 | 6840404000 | a13c42400050e84a000000
0x68是用于推送的操作码,而404040是VM字节码的地址。但是,它是字节码的虚拟地址,这意味着它只有在程序被映射到内存时才有用。我们在这里处理静态二进制文件,因此我们需要将此值转换为文件偏移量。为此,我们从字节码的地址中减去该节的虚拟地址,然后将指向原始数据的指针添加到该值。因此,“等式”如下所示:
Address - VirtualAddress + PointerToRawData
这非常简单,我们将使用pefile进行计算。首先,我们从VM字节码地址中减去图像的基本地址,剩下的是0x4040。然后我们循环遍历每个可执行部分,直到找到一个虚拟地址大于字节码地址的部分。一旦找到它,我们就从上一节获取虚拟地址和PointerToRawData并从循环中断开。把这些放在一起,我们就得到文件偏移量0x1E40,然后返回它。
在此基础上,让我们使用一个“main”函数get_address()将所有内容绑定在一起。这将调用每个函数,并最终将文件偏移量返回给调用函数。
我们还可以稍微修改main()函数,所以现在我们调用YARA(filename).get_address(data),然后在打开的文件中查找偏移量,读取字节码,然后将其传递给VM()类。就这样!现在,我们可以获取二进制文件,从中解析字节码,然后对其进行解释!尽管YARA并不是很实用,但我的主要目标是展示如何使用它以及如何基于函数实际编写基本规则,所以希望你从中学到一些东西!
 

上一页  [1] [2]