X86-asm代码使usb磁盘不可启动

时间:2017-09-13 07:15:07

标签: assembly x86 boot bios usb-mass-storage

我们在基于MCU的定制硬件上开发了USB复合设备(CDC和MSD类)。磁盘是RAM磁盘(24kb空间),上电时,MCU供应商固件格式化(FAT 12)。不幸的是,该设备被视为可引导磁盘,典型的BIOS尝试引导它。但是,我们知道将各种USB磁盘连接到不同的PC会产生不同的结果,这取决于磁盘FAT类型和BIOS行为(显然每个BIOS都有先于USB的USB启动)。 我们的目标是拥有无法启动的 USB磁盘(FAT12格式化)

我们尝试了很多解决方案,但都没有效果。 在我们看来,BIOS似乎不只是检查是否存在有效的引导扇区,将第一个扇区复制到地址0x7C00并跳转到该地址,从而控制x86 ASM引导代码。实际上,我们使用以下命令格式化了一个带有Linux的商用USB记忆棒:

mkdosfs -F 12 /dev/sda1

这个USB记忆棒现在有一个FAT12卷引导记录和我们还没有找到一个在试图从它启动时卡住的BIOS

因此,我们将其引导扇区复制到我们的设备中,我们希望它可以用作商用USB记忆棒。不:尝试引导磁盘时BIOS会挂起。下面是上面Linux命令生成的引导扇区的反汇编。

;Jump instructions
0x00007c00 eb 3c                            jmp    0x00007c3e
0x00007c02 90                               nop

;VBR segment
0x00007c03 6d                               
0x00007c04 6b 66 73 2e                      
0x00007c08 66 61                              

..............

;Boot code
0x00007c3e 0e                               push   %cs
0x00007c3f 1f                               pop    %ds
0x00007c40 be 5b 7c                         mov    $0x7c5b,%si
0x00007c43 ac                               lods   %ds:(%si),%al
0x00007c44 22 c0                            and    %al,%al
0x00007c46 74 0b                            je     0x00007c53
0x00007c48 56                               push   %si
0x00007c49 b4 0e                            mov    $0xe,%ah
0x00007c4b bb 07 00                         mov    $0x7,%bx
0x00007c4e cd 10                            int    $0x10
0x00007c50 5e                               pop    %si
0x00007c51 eb f0                            jmp    0x00007c43
0x00007c53 32 e4                            xor    %ah,%ah
0x00007c55 cd 16                            int    $0x16
0x00007c57 cd 19                            int    $0x19
0x00007c59 eb fe                            jmp    0x00007c59

;String to be displayed followed by zeros

0x00007c5b 54                               
0x00007c5c 68 69 73                         

..........

;Boot signature
0x00007dfe 55                               
0x00007dff aa                               

显然,上面的代码打印字符串“这不是可引导的磁盘。请插入可引导的软盘并按任意键再试一次”,然后调用INT16H和INT19H。

为什么我正在编写的PC中的BIOS打印出来:“尝试从USB磁盘启动”然后跳转到我的硬盘驱动器,而在我们的设备中写入的相同汇编代码却没有?也就是说,它写道“请插入......”?有一个代码可以替代它,永远不会尝试启动我的自定义USB磁盘?

此外,在读取第一个扇区读取之前,BIOS是否与USB设备进行了一些特殊通信,例如,设备描述符中的某些内容是为了了解它是否可以用作启动盘?

提前谢谢大家。

2 个答案:

答案 0 :(得分:1)

最终,可能无法阻止您的自定义USB设备在其可能插入的任何PC上用作启动设备。但是,你可以做的事情应该涵盖大多数情况,第一个是在引导扇区结束时没有0xAA55签名,第二个是调用INT 0x18引导扇区,要求BIOS尝试下一个启动装置。

BIOS如何启动USB设备

这里的基本问题是USB大容量存储设备的BIOS启动没有标准。在BIOS实现之间,确定USB设备是否可启动的确切程度如何。然而,所有实现都将遵循两个基本步骤。

首先是确定是否将USB设备模拟为"软盘","硬盘"," cdrom"," zip&# 34;或其他类型的驱动器。对于您的设备,它应该归结为在软盘或硬盘驱动器仿真之间进行选择。可以使用各种标准来进行此选择,例如驱动器的大小,是否可以将其自身报告为可移动的以及使用的命令集。特别是驱动器软盘仿真可以支持的大小的上限,我相信大约530MB,并且这个大小通常用于确定设备类型。某些BIOS也可以配置为在其设置中强制使用某种设备类型。

下一步是确定设备是否可引导。这意味着至少读取驱动器的第一个扇区,因为如果无法读取它,则无法启动它。然后BIOS可以尝试确定引导扇区是否有效。如果它正在模拟硬盘驱动器,则应始终检查是否存在0xAA55签名,但如果它正在模拟软盘,它可能会也可能不会执行此检查。如果它正在模拟硬盘驱动器,它也可能会检查有效的MBR样式分区,如果要模拟软盘,它可能会检查有效的FAT BIOS参数块(BPB)。

因此,在引导扇区末尾没有0xAA55幻数会阻止USB设备至少在某些情况下被用作引导设备。但是,最有可能的是BIOS会选择对您的设备使用软盘仿真,并且许多BIOS除了验证它的可读性外,还不会对引导扇区进行任何验证。但是,如果你的USB设备假装它比实际大得多,超出了软盘仿真所支持的范围,那么它应该更有可能使用硬盘仿真。

调用INT 0x18

但是,即使BIOS确实加载并执行了设备的引导扇区,所有内容也不会丢失。您可以调用INT 0x18,它最初用于在原始IBM PC上启动盒式磁带BASIC,但由BIOS Boot Specification重新定义为失败启动尝试的恢复向量。在现代PC上,包括任何支持启动USB设备的PC,调用它将告诉BIOS尝试下一个启动设备。 (自MBR发明以来,标准MBR实现中的引导失败后实际调用了INT 0x18,因此它实际上并不像它听起来那么不寻常。)

以下是调用INT 0x18的引导扇区的源代码我用于在我可用的各种PC上进行测试:

    .code16

    .text

    jmp start
    nop
    .org    0x03    # insure a two byte long JMP insn was used

    .org    0x3e    # skip over FAT BIOS Parameter Block
start:
    xor %ax, %ax
    mov %ax, %ss
    mov $0x7c00, %sp

    call    print_message

    .ascii  "\r\nOOPS... The BIOS tried to boot the custom device.\r\n"
    .byte   0

    xor %ax, %ax
    int $0x16       # read from keyboard

    # Try using the BIOS Boot Specification's recovery vector so
    # that BIOS tries another boot device. On an a real 5150 IBM PC
    # this starts cassette BASIC.  On a PC that doesn't support the
    # BBS then it may print an error message, do nothing or crash.

    int $0x18

    call    print_message

    # INT 0x18 didn't work, didn't start BASIC and didn't crash.
    # Print an error message to user and invoke the INT 0x19
    # reboot vector.

    .ascii  "\r\nRemove the custom device and press any key to reboot"
    .ascii  " the computer.\r\n"
    .byte   0

    xor %ax, %ax
    int $0x16       # read from keyboard

    int $0x19       # reboot

infinite_loop:
    jmp infinite_loop

print_message:
    pop %si
loop_message:
    lods    %cs:(%si), %al
    test    %al,%al
    jz  end_message
    mov $0xe, %ah
    mov $0x7, %bx
    int $0x10       # print a character
    jmp loop_message
end_message:
    jmp *%si

    .org    0x1FF
    .byte   00      # note no 55 aa signature

您应该可以修改此代码以用于您的设备。确保从设备的BPB复制FAT12 BPB(偏移量0x003和0x03e之间的字节)。你可能想要删除INT 0x16的第一次调用,它在调用INT 0x18之前等待按键。要汇编和链接代码,您可以使用以下命令:

as -o myfat12.o myfat12.s
ld --oformat=binary -o myfat12.bin -Ttext=0x7c00 myfat12.o

要将BPB从您的设备复制到使用上述命令创建的引导扇区,您可以使用以下内容:

dd conv=notrunc if=/dev/sda of=myfat12.bin bs=1 skip=3 seek=3 count=59

在我的测试中,上面的代码运行得相当不错,但在一种情况下,BIOS只是一遍又一遍地尝试相同的启动设备。在另一种情况下,PC(一个15岁的Pentium 4)在尝试从USB闪存驱动器启动代码时崩溃,但没有脱离实际的USB软盘。崩溃可能与我试图尽可能密切地复制你设备的不寻常的24k FAT12 BPB有关。

第二个"删除自定义设备......"消息从未在我的测试中打印过。引导块从未在第一个位置执行,或者调用0x18执行了某些操作并且从未返回。如果INT 0x18没有做任何有用的事情,您可能希望将这些指令移动到第一条消息。

答案 1 :(得分:0)

尝试调用INT 18H,这是由BIOS Boot Specification(Compaq,Phoenix,Intel 1996)指定的,以尝试下一个启动设备。

或者,可能需要使用INT 13H自行加载下一个磁盘的引导扇区。