phoenixbios工具 (PhoenixBios)

方法

目前,创建BIOS rootkit示例代码的数量非常有限,2009年3月唯一公开的代码BIOS rootkit演示一起发布(据我所知)。我的第一个目标是重现Core Security在2009年的研究结果中,我的第二项任务是研究如何扩大结果。我的最终目标是创建一些可以轻松部署的基础BIOS的rootkit。

2009年,基于引导风扇区域的类似安全领域进行了研究rootkit。与基于BIOS的rootkit不同的领域发展迅速,导致了许多不同的主导记录(MBR)的rootkit正在开发和公布。这种类型的rootkit被称为“Bootkit,这个比较类似于基于BIOS的rootkit,在加载操作系统之前,它旨在加载自己。这种相似性导致了很多bootkit开发人员指出,应该可以直接从BIOS执行这种攻击,而不是从MBR加载。虽然有这样的想法,但没有这样的代码公开的例子。

完成这个项目的第一步是建立一个可以进行的项目BIOS测试和开发环境进行修改和调试。他们关于持久性BIOS感染论文中,Sacco和Ortega详细介绍了他们是如何发现的VMware包含一个BIOS ROM可用于从BIOS应用程序本身开始调试GDB服务器。在VMware成功后,它将完成 VMware BIOS修改移植到其他类似的修改中BIOS平台,我将在这里描述下半部分。

VMware BIOS配置

好了,现在有足够的背景数据来做这个!

第一步是从VMware本身提取BIOS。在Windows任何资源提取器都可以使用(Resource Hacker.)打开vmware-vmx.exe可执行文件。许多不同的二进制资源捆绑在这个应用程序中,BIOS存储在资源ID 6006(至少在VMware 7中就是这样)。在其他版本中,这可能是不同的,但关键是资源文件的大小是512kb。下图显示Resource Hacker中的内容:

将此BIOS映像绑定到vmware-vmx.exe它也可以在应用程序中单独使用,每次更改后无需修改vmware可执行文件。VMware允许图像VMX在设置文件中指定多个隐藏选项。有时候,我打算在这个网站的工具页面上记录一些文件,因为有些功能很有用!对BIOS有用的修改和调试例如:

bios440.filename = \\"BIOS.ROM\\"debugStub.listen.guest32 = \\"TRUE\\"debugStub.hideBreakpoint = \\"TRUE\\"monitor.debugOnStartGuest32 = \\"TRUE\\"

第一个设置允许直接从文件而不是vmware-vmx加载应用程序BIOS rom。以下两行启用内置GDB服务器。以下两行启用内置GDB服务器image服务器将监控端口8832上的连接。最后一行指示VMware停止 guest image BIOS代码执行的第一行。这是非常有用的,因为它允许任何东西BIOS定义和切断执行前的内存。测试使用IDA Pro作为GDB在第一个客户端,BIOS停止指令VMware guest在下面的屏幕截图中可以看到虚拟机示例:

本测试环境最初使用时,IDA与GDB服务器连接存在重大问题。在与不同的GDB经过多次尝试和错误测试,客户端发现是VMware版本问题。版本6和6.5在IDA它看起来不太好,所以VMware7用于大多数测试。BIOS它由16位代码组成,而不是IDA默认的32位代码需要IDA在调试选项中定义手动内存区。允许将内存地址定义为正确反编译的16位代码。

重新创造过去的结果 – VMware BIOS修改

如前所述,Sacco&Ortega已经对BIOS两次修改,Wojtczuk&Tereshkin也对BIOS修改。在这三次演示中,只有Sacco&Ortega演示包括所描述技术的任何源代码或示例代码。因为这是现有唯一的例子,它被用作基于它的例子BIOS的rootkit项目起点。

Sacco&Ortega论文对其设置和测试技术的描述相当全面。VMware安装程序完成如上所述,下一步是实现他们提供的BIOS修改代码。需要提供的代码BIOS ROM提取到每个模块中。VMware附带的BIOS ROM是Phoenix BIOS。研究表明,使用这种类型BIOS,一种称为“phxdeco开源工具和Phoenix Phoenix直接提供的名称为Phoenix BIOS Editor商业工具有两种主要工具。Sacco&Ortega推荐使用论文Phoenix BIOS Editor他们的代码用于应用程序。还有可以从网上下载的试用版,页面有项目所需的所有功能。我想找一个下载链接,但是我没有找到任何看似甚至一半合法的试用版,但是Google确实提供了各种链接。但我仍然认为找一些合法的试用版还是很容易的。安装工具后,下一步是构建自定义BIOS。

我先测试了一下VMware对BIOS图像的小修改会改变VMware并生效徽标颜色。接下来,我操作了原因Sacco&Ortega提供的Python编译脚本BIOS修改。除了Python BIOS一个程序集脚本print错了,一切都很好,一个新的BIOS磁盘保存。然而,将此BIOS加载到VMware没有同样的成功,VMware会显示一条消息,指出虚拟机错误,正在关闭。这个问题的调试是在IDA和GDB但问题很难追溯(加上IDA有版本问题)。为了解决得更快,我下去了VMware不同版本的测试环境将与Sacco&Ortega匹配测试环境。经过一番搜索,他们使用了详细版本VMware已找到并安装。不幸的是,这个问题还没有解决,VMware报告同样的崩溃错误。虽然我已经看到了BIOS作为演示文稿的一部分,很明显,他们的示例代码在任何测试系统上都需要额外的修改。

通过调试Sacco&Ortega代码学到了很多不同的东西。最后,问题缩小到一个汇编程序指令。该指令正在远程调用绝对地址,绝对地址不正在使用BIOS地址正确。输入正确的地址后,BIOS代码执行成功,rootkit开始搜索硬盘驱动器进行修改。扫描硬盘需要很长时间(只有15)gb),并在系统启动前多次运行。概念证明代码包括修复notepad.exe启动时显示消息或修改的功能unix系统上的/etc/passwd文件,以便将root密码设置为固定值。

Bootkit测试

虽然项目时间比较长,但是还是有各种各样的项目。bootkit测试了代码的功能,并重新创建了结果,以确定哪个最合适bootkit,还有一个基础BIOS的rootkit。检查了四个不同的启动程序,即Stoned,Whistler,Vbootkit和Vbootkit2 bootkits。Stoned和Whistler bootkits设计功能比rootkit功能更像恶意软件,没有简单的源代码结构。Vbootkit启动工具有很大的不同,因为它没有被设计成恶意软件,而且(相对于其他)有很好的源代码。该bootkit旨在从CD但只有在Windows 在测试版中进行测试。当与Windows 7当零售一起使用时,因为Windows使用不同的文件签名,因此bootkit根本没有加载。确定新的文件签名需要一段时间,以便测试文件bootkit,但仍无法成功加载。允许测试Windows 7的beta版本。当Vbootkit2软件在Windows 7 beta当系统运行时,一切都按预期运行。Vbootkit软件包括将过程升级到system(高于administrators)级别权限,捕获键和重置用户密码。这些都包含在内rootkit有价值的项目,但将应用程序移植到Windows 零售业仍然是一项非常困难的工作。接下来检查Vbootkit软件; 它被设计成和Windows 2003,XP与2000一起使用。虽然没有包装,但可以从CD操作,但只需稍加修改即可添加此功能。虽然该软件只包括升级过程权限的能力,但它只是一个有价值的功能。该bootkit选用软件BIOS rootkit,这将在下一节介绍。NVLabs是bootkit作者本身是基于作者的bootkit,因此,它很多方面代表了这个项目的主要功能,非常感谢他们公开代码!他们的源代码似乎不再可用于他们的网站,但它仍然可以从Archive.org下载

BIOS代码注入

以前测试的Sacco&Ortega概念代码证明其功能非常脆弱rootkit应执行的操作类型。开发新的rootkit第一步是开发一种强大的方法BIOS执行附加代码。

Sacco&Ortega修补了BIOS解压模块,因为它已经被解压了(所以它也可以解压所有其他内容)BIOS加载时调用。这种推理是合理的,但需要修改dll。在正常操作期间,BIOS会压缩存在的每一个压缩BIOS模块调用一次解压缩模块。VMware BIOS包括22个压缩模块,需要解压22次。该模块将覆盖我们的附加代码,因为它停留在缓冲区,因此有必要重新定位我们的附加代码。

我使用的过程包括以下步骤:

在解压模块的开头插入一个新的调用代码。将我们所有的附加代码复制到新的内存部分。更新解压模块以指向我们代码所在内存中的新位置。返回解压模块并继续执行。

该过程允许包括大量附加代码BIOS ROM代码在存储器中移动到存储器后,从可靠的位置运行。以上四个步骤如下图所示:

(mspaint真棒)

可能有很多不同的方法可以实现这个问题,但目标是创建尽可能独立于系统的代码。为了实现这一点,所有绝对地址都被删除,只使用接近呼叫或跳转。这个例外是引用我们在可用内存中的位置,因为预计无论系统如何,这都是一个固定的位置。以下是用于处理代码重定位的汇编代码:

start_mover:; The following two push instructions will save the current state of the registers onto thestack.pushapushf; Segment registers are cleared as we will be moving all code to segment 0xor ax, ax ; (This may or may not be obvious, but xor'ing the register sets it to 0).xor di, dixor si, sipush cs; Push the code segment into the data segment, so we can overwrite the calling address codepop ds; (CS is moved to DS here)mov es, ax ; Destination segment (0x0000)mov di, 0x8000 ; Destination offset, all code runs from 0x