几年前我就开始做BIOS rootkits方面的东西(在UEFI成为主流之前)。我知道在初始化启动过程的后期阶段,大多数硬件都有一个BIOS类型设置 ,我的主要关注GPU和硬盘。本文我所做的是我曾经 在 spritesmods 上看到的一些东西。
硬盘破解
我发现一个老版本的西部数码硬盘驱动器很适合现在的研究,所以我把控制器卸下来。
Spritesmods上的那个家伙把固件的闪存芯片弄下来然后把里面的内容全部拷贝出来了,这里唯一的问题是红圈中闪存芯片这个地方。
红圈中是Marvell 88i8846-TFJ2 ARM处理器,有内部的闪存。我不想为了访问内存而手工把整个CPU弄下来,所以我决定使用JTAG方法。
JTAG的头是很知名的,虽然可以被颠倒(在我的案例中头部的第一个pin点用’1’标识)。Pins 6到11是我们需要的JTAG金属圈。
正如你可以看到的,我们决定不焊接pins点。主要原因是其有点生锈并且离得太近,所以很容易把单板弄坏掉。作为替代我决定使用测试点,这可以用万用表的“连续”模式实现。
通过设置万用表的这个模式能够得到两点之间的电阻,‘1’代表完全绝缘(这意味着这两点是不通电的),‘0.01’代表互通性很好。当电阻很低的时候,仪表会发出声音(难以忍受的噪音),所以我们只需要通过声音来判断两点之间是否连接即可。
将硬盘驱动器断开,只要把你要测的两点用万用表测一下即可。然后移动其中一段到其他点上,直到听到蜂鸣声为止。在我的单板上你会发现从头部的pin点到测试点有可见的数据行,这给了你很好的入口(前提是你的视力很好)。
我不想将硬盘插入到我的电脑电源上以免出现一些错误,并且我的电脑在房间的对面,所以我也不想搞个10米长的SATA数据线。下面是我的解决方案:
如果你有备用电源,在没有连接到主板的情况下,你可以将ATX的第三个和第四个pin点短路来将它开启。我的备用电源很老并且少一个风扇,所以我很惊讶居然没有短路和起火(我的房子的所有设备都在一个断路器上,所以短路的话我得花一个小时重启所有设备)。
我使用5美元的SATA来连接USB,这是一个很好的方法。右边的红色单板使用了一个30美元的TIAO USB多协议适配器,基于FT2232H同时以可以用SPI和JTAG。
在这里我有一个愚蠢复杂的设置,由于我的windows机器放在房间的另一边,iMac为JTAG软件运行了一个linux虚拟机(FTDI驱动和OpenOCD)因为这在windows和OSX上安装很麻烦。 Windows系统运行IDA来逆向和调试(当我开始动态调试时我打算在本地网络上用IDA连到OpenOCD的GDB服务器上去)。
现在所有要连接的东西都已经准备好了,给硬盘插上电源然后输入下面的命令:
openocd -f interface/<your interface here>.cfg -f target/test.cfg
需要先为你的硬盘控制CPU配置test.cfg文件,对于大部分marvell的CPU这个配置都有效。我不知道khz适配器行不行,所以我将mine设置成100(由于这个值低于它正常的工作值)。
如果一切正常,你会看到这些信息。现在你可以telnet到4444端口然后发送命令了。
硬盘控制器用的Marvell芯片没有公开的文档,所以如果你想了解相关信息比如内存布局,你需要在NDA上注册然后付费。作为替代,我想要做的是尽可能在固件上和通过探测电路找到更多的信息。
如果你们没有办法焊下闪存并导出信息要得到固件并不容易,所以我们将会在boot进程下工作。 大部分ARM CPU的起始执行地址是0xFFFF0000,这是复位向量。如果我们从这个地址导出65536字节,我们将会找到启动代码,这是一个很好的入口点。
为了导出内存,我们首先要停止CPU,可以使用命令”reset halt”(这是必要的因为我们没有办法在任何一个阶段都能停下来)。如果这个命令没有效果可能是JTAG的RST pin点没有连接,你需要断开并重连硬盘的电源然后快速的修复这个JTAG问题。内存导出用以下命令
“dump_image <file name> <address> <size>”
当我们将导出的镜像文件反汇编时,它是一个很小的只有4KB的启动代码,这段代码能够引导剩下的固件。
我发现JTAG的重置点不是真的系统重置(SRST)只是一个TAP重置(TRST),这对调试不是很有用。这里是对系统重置信号的添加(这样允许重置停止命令在重置向量上中断下来,在任何指令执行之前)。
在我的例子中没有SRST行的测试点,但是在序列标签下面有暴露出非常小的镀铜位,这个可以用来连接CPU的SRST pin点。
红迪网上的Ceriand指出JTAG头跟MICTOR连接器很像(通常是38或40个pin点)。所以如果你不想做任何焊接工作你可以找一个MICTOR连接器和数据线。
同时我发现老版本的PSU硬件无法在低电压下使用(内部的组件可能会爆炸),所以我推荐为Molex电源适配器买一个好的AC(不要买便宜的,一天就坏掉了)。
最后,由于JTAG头有一个RTCK连接器,你需要将opencd的adapter_khz配置为0. 这样JTAG能够使用自适应时钟,这样你能够防止所有超时错误。
引导和引导程序
通过一些逆向我确定第二部分的引导代码无法在正常的启动中使用。执行的时候在一个端口上等待一些数据(最有可能是串行端口),然后采取相关的行动。如果没有数据到来,这段代码将进入一个死循环驱动将永远不会启动。
PCB周围的端口和测试点映射到CPU的0x1C00A000-0x1C00AFFF范围上。现在,由于我没有钱买示波器或者像样的逻辑分析仪。我不得不通过这些端口映射,这样会使事情变得更容易。
所有的这些代码都是为了基于一些值读取进入系统特殊模式的开关:
4-不确定,当它为了一些端口的值进行无限循环。我猜这些值是允许开发者读取/写入/ 擦除处理器内部的闪存。
3-跳转到R4的地址(我的例子中这个值为0,但可能是设计的原因)
6-串行端口的串行控制台可以用ASCII字节(r,w,j,h),可以让开发者发送读取, 写入,跳转和停止命令。
我对端口如何映射到内存不太熟悉,0x1C00A030总是为0,0x1C00A03A总是为0xFFFF(我认为这一个是低电压常数一个是高电压常数)。
有趣的是在“cmp R1,#R3”上设置断点将R3设置成3,代码会跳到地址0然后正常启动(这就是我认为为什么0不代表未初始化)。让我们看看地址0有什么。
地址0通常是RAM,但已经有一些有效的代码了,所以很可能是在启动过程中CPU临时映射地址0到一些内部只读存储器。这是标准的ARM IVT,你可以在任何ARM设备的启动地址看到;使我想到CPU检测到JTAG附加进来时0xFFFF0000上的启动只是被执行了。在我买到逻辑分析仪并找到哪个端口允许我控制启动模式跳转之前,唯一通过JTAG正常启动硬件的办法是在校验之前执行“重置”然后将R1设置成3.
在这个例子中启动代码是节与节之间差距最大的地方,后续有机会我会将它进行映射,导出,并逆向。
*参考来源:malwaretech.com