很久以前分析的时候写的,最近开始学习分析bootkit类的病毒,记录下
bootcode代码
以WIN7为例(bootcode代码,win7到win10都一样),MBR大小为1个扇区,大小为512(0x200),
第一块选区0x000-0x162为MBR的可执行代码
第二块选区0x163-0x1b2为错误信息显示,查找分区表失败时会在系统显示这些字符
第三块选区0x1be-0x1fd为分区表。

0x1b5处值为错误信息字符串的偏移,这里值为0x63,再加上0x100就是0x163,即字符串偏移,刚好为第二块选区。
不同版本该值不一样,如xp的为0x2c ,Vista为0x62,win 7到win10系统为0x63。
要检测mbr有没有被修改,我们可以对正常mbr代码区域算个sha256作为白名单,
计算代码开始到错误提示字符串的代码部分hash256,在这个例子是win7,错误提示字符串为0x163,也就是计算从0到0x162部分的sha256
与白名单sha256比较是否一样;不一样,则mbr被修改了。
系统版本 |
字符串偏移 |
白名单Sha256 |
xp |
0x2c |
b5ed343494f0326a08aa6abf7cc9aa4d96207532cf0d2b39453c6eb7bede19e3 |
vista |
0x62 |
4799e8c92d32bca8e5103110a322523adb7a3909324132bd9abab8f3345e094a |
Win7 以上 |
0x63 |
088995559ab317af9b3291408da689651e8353f62e0a478d92eb0b5a947063fd |
1 2 3 4 5 6 7 8
| typedef struct _MBR { BYTE bootCode [440]; DWORD diskSignature ; WORD reserved ; PARTITION partitionTable [4]; WORD sectorEndSignature ; } MBR ;
|
分区表
从0x1be~0x1fd是分区表。最大只能有四个主分区,每个分区表为16bit大小,分区表采用chs寻址方式,具体结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| typedef struct _PARTITION { BYTE bootIndicator ; BYTE head; Word sector:10 ; Word cylinder:6 ; BYTE type ; BYTE lastHead ; Word lastSector:10; Word lastCylinder:6 ; DWORD relativeSector ; DWORD numberSectors ; } PARTITION ;
|
活动分区的首个扇区为VBR,同样只有一个扇区。开头eb 52 90是直接跳过bpb结构到bootStrapCode执行代码。
第一块选区 0xb-0x53为BIOS Parameter Block,即NTFS_BPB结构。
第二块选区 0x54 -0x18b为bootStrapCode代码区域
第三块选取 0x18c-0x1f6为错误显示字符串,引导系统失败时显示该字符串

1 2 3 4 5 6 7 8 9 10 11
| typedef struct _NTFS_VOLUME_BOOT_RECORD { BYTE jumpInstruction [3]; BYTE oemID [4];
BYTE dummy [4]; NTFS_BPB bpb; BYTE bootStrapCode [426]; WORD sectorEndSignature ; } NTFS_VOLUME_BOOT_RECORD
|
BIOS Parameter Block
该结构体提供了NTFS文件系统的一些信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| struct NTFS_BPB { WORD bytesPerSector ;//每扇区字节数 BYTE sectorsPerCluster ; //每簇扇区数,簇是ntfs文件系统的基本单位 WORD reservedSectors ; BYTE fatCopies ; WORD rootDirEntries ; WORD smallSectors ; BYTE mediaDescriptor ;//介质描述符 硬盘为0xf8 WORD sectorsPerFAT ; WORD sectorsPerTrack ;//每磁道扇区数 ntfs不用 WORD numberOfHeads ;//磁头数 ntfs不用 DWORD hiddenSectors ; //隐藏扇区数 ① DWORD largeSectors ; DWORD reserved ; ULONGLONG totalSectors ; //扇区总数 ULONGLONG MFTLogicalClusterNumber ;//$MFT起始簇号 ULONGLONG MirrorLogicalClusterNumber ;$MFTMir起始簇号 DWORD clustersPerMFTRecord ; DWORD clustersPerindexRecord ; ULONGLONG volumeSerial ;//卷序列号 DWORD checksum ;//效验和 } bpb ;
|
VBR和MBR一样,也可以根据错误显示字符串的偏移来推测出操作系统的版本,0x1f8处值为第一个错误信息字符串的偏移,此处值为0x8c,加上0x100即0x18c,该偏移就是错误信息字符串区域。
对于vbr也可以通过计算正常vbr代码区域的sha256作为白名单,vbr代码sha256计算,应该计算 “eb 50 90”(也是代码)+ vbr代码区域 即0x54到错误信息字符串前。
版本 |
字符串偏移 |
白名单Sha256 |
xp |
0x83 |
5cb5aa385e0ada266690a2821e3a36ad372720d2ff47c0b1cd9d6ebcab25bf4e |
vista |
0x80 |
a1932aaba7d6d3adb1637e2ee0c8355706842ba825ea811728165420c518c0b1 |
Win7 |
0x8c |
96d38c1be37b9124fb71d1d0f5c52969f0074687fe17aef0e1bafc54428674f6 |
Win8 |
0x18a(如果前面三个值都没命中,则看0x1f6到0x1f8的值) |
51643dcce7e93d795b08e1f19e38374ae4deaf3b1217527561a44aa9913ded23 |
VBR加载IPL的代码,在IPL中解析NTFS格式定位bootmgr位置
IPL的位置由VBR 的NTFS_BPB的hiddenSectors字段(相对于扇区起始位置0x1c)指定,即IPL的初始扇区。
IPL同样可以使用白名单来验证IPL是否被修改。IPL共15个扇区,但因为最后一个扇区有时会保存于引导启动无关的数据,因此只计算前面14个扇区的IPL。
左边为win7,右边为win10 ,从win 8以后,IPL区域增加了 引导程序启动失败时显示的字符。该字符串偏移 由0x177-0x178处指定。
“An operating system wasn’t found. Try disconnecting any drives that don’t contain an operating system.”

Win7以下则计算14个扇区的sha256,win8 以上则需要排除掉两个地方:错误信息字符串和保存该字符串索引的位置0x117-0x118。
右图win10的sha256就是计算 0x200~0x299 + 0x319-第十四扇区结束。我们可以根据 0x256处的跳转指来来判断对应的操作系统:
如果是e9,则是win8及以上。
版本 |
Sha256 |
xp |
525788a688cfbe9e416122f0bc3cfb32ce9699fd12356b6ccaa173444c7d8f3f |
vista |
ff1aae04bac3e29f062a7fa17320d7d26363256a69f96840718d45301da71291 |
Win7 |
462afe2322bad3d1c2747d7437d5f6c157e00ca37e5d38ebedd25346b3b488ce |
Win 8以上 |
c09d496a1f24086c333468d58256d5db9c73fee945fca74603bdab05f19a6d57 |
上列结构都是针对代码部分做的检测,如果bootkit改动的不是代码,而是改分区表或者BPB的hiddenSectors 字段,则不能检测到是否被感染
正常系统boot引导代码
设置好调试环境后,附加到gdb调试,这时会在bios启动后的第一条指令处断下BIOS会 把MBR加载到0x7c00;这时候所有的段都是0x0,
MBR运行在实模式下,地址都是16bit。在0x7c00设置断点,调整段为16bit,
MBR
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| MEMORY:7C00 loc_7C00: MEMORY:7C00 xor ax, ax MEMORY:7C02 mov ss, ax MEMORY:7C04 mov sp, 7C00h MEMORY:7C07 mov es, ax MEMORY:7C09 mov ds, ax MEMORY:7C0B mov si, 7C00h MEMORY:7C0E mov di, 600h MEMORY:7C11 mov cx, 200h MEMORY:7C14 cld MEMORY:7C15 rep movsb ;把MBR从0x7c00拷贝到0x600,大小为0x200 MEMORY:7C17 push ax MEMORY:7C18 push 61Ch MEMORY:7C1B retf
|
找到分区表的活动分区
1 2 3 4 5 6 7 8 9 10 11 12
| MEMORY:061C FB sti MEMORY:061D B9 04 00 mov cx, 4;最多只有四个主分区 MEMORY:0620 BD BE 07 mov bp, 7BEh;分区表偏移(0x600+0x1be) MEMORY:0623 loc_623: MEMORY:0623 80 7E 00 00 cmp byte ptr [bp+0], 0;MBR的bootIndicator的最高位为1则为活动分区,因此如果小于0,则最高位为1,找到活动分区, ;一些旧的mbr只支持0x80和0x00两个有效值 MEMORY:0627 7C 0B jl short loc_634 ;如果小于0,找到活动分区, MEMORY:0629 0F 85 0E 01 jnz loc_73B;如果大于0,跳转到错误处理,在屏幕上显示Invalid partition table ;因为0x01~0x7f在bootIndicator为无效值 MEMORY:062D 83 C5 10 add bp, 10h ;等于0,则找下一个分区表 MEMORY:0630 E2 F1 loop loc_623 MEMORY:0632 CD 18 int 18h
|
调用int 13,功能号41. 检测是否支持int 13扩展功能。执行int 13中断功能号42后,会将返回信息存放在ah,bx和cx寄存器。如果支持int 13扩展,则cf为0,bx为0xaa55,cx最低位为1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| MEMORY:0634 mov [bp+0], dl MEMORY:0637 push bp MEMORY:0638 mov byte ptr [bp+11h], 5 MEMORY:063C mov byte ptr [bp+10h], 0 MEMORY:0640 mov ah, 41h ; 'A' MEMORY:0642 mov bx, 55AAh MEMORY:0645 int 13h ; DISK - Check for INT 13h Extensions MEMORY:0645 ; BX = 55AAh, DL = 驱动号 MEMORY:0645 ; Return: 如果不支持则设置cf为1 MEMORY:0645 ; AH = 扩展版本号(不需要关心) MEMORY:0645 ; BX = AA55h MEMORY:0645 ; CX = Interface support bit map MEMORY:0647 pop bp ;0x7be 分区表偏移 MEMORY:0648 jb short loc_659 ;cf为1,则跳转, MEMORY:064A cmp bx, 0AA55h MEMORY:064E jnz short loc_659 MEMORY:0650 test cx, 1 MEMORY:0654 jz short loc_659 MEMORY:0656 inc byte ptr [bp+10h] ;[bp+10]为是否支持的int 13扩展的标志, ;后面比较这个值来判断是否支持int 13扩展的功能
|
扩展int 13读硬盘,在堆栈上构建调用int 13扩展读所需要的参数块,在这里将活动分区的VBR拷贝到0x7c00偏移处。如果从硬盘读取VBR数据成功,则cf=0,ah=0
Offset |
Size |
Description |
0 |
1 |
结构体大小 |
1 |
1 |
总是0 |
2 |
2 |
要拷贝的扇区大小,最大是127个扇区 |
4 |
4 |
要拷贝到的位置 |
8 |
4 |
要拷贝的数据的位置 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| MEMORY:0659 loc_659: ; CODE XREF: MEMORY:0648 MEMORY:0659 ; MEMORY:064E MEMORY:0659 pushad MEMORY:065B cmp byte ptr [bp+10h], 0 ;[bp+10] 为1表示支持int 13扩展 MEMORY:065F jz short loc_687 ;不支持int 13扩展,使用标准int 13读硬盘 MEMORY:0661 push large 0 ;构建disk address packet结构 MEMORY:0667 push large dword ptr [bp+8] ;要拷贝的位置,即VBR在硬盘中的位置,使用LBA寻址 ;[bp+0]为分区表结构,[bp+8]为对应的分区在硬盘的位置
MEMORY:066B push 0 ;push 的大小为16bit , 因此这里push了两次,第一次push的值为offser的值,第二次Push的值为segmet的值 MEMORY:066E push 7C00h ;因此这里是拷贝到内存地址0x 7c00:0处 MEMORY:0671 push 1 ;每次拷贝一个扇区 MEMORY:0674 push 10h ;DAP结构大小 MEMORY:0677 mov ah, 42h ; 'B' MEMORY:0679 mov dl, [bp+0] MEMORY:067C mov si, sp MEMORY:067E int 13h ; DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet)
|
标准int 13读VBR
1 2 3 4 5 6 7 8 9 10
| MEMORY:0687 mov ax, 201h ;ah=02,al=01,即调用int 13中断 功能号2。每次读取一个扇区 MEMORY:068A mov bx, 7C00h ;从硬盘拷贝到内存地址0x7c00 MEMORY:068D mov dl, [bp+0] ; MEMORY:0690 mov dh, [bp+1] ; MEMORY:0693 mov cl, [bp+2] MEMORY:0696 mov ch, [bp+3] MEMORY:0699 int 13h ; DISK - READ SECTORS INTO MEMORY MEMORY:0699 ; AL = 读取多少扇区, CH = track, CL = sector MEMORY:0699 ; DH = head, DL = 驱动号, ES:BX -> 拷贝到的内存地址 MEMORY:0699 ; Return: CF set on error, AH = status, AL = number of sectors read
|
VBR代码分析
vbr第一条指令为jmp,跳过bios参数块
1
| MEMORY:7C00 jmp short near ptr unk_7C54
|
设置ss、sp和ds的值
1 2 3 4 5 6 7 8 9 10 11 12
| MEMORY:7C54 loc_7C54: MEMORY:7C54 cli MEMORY:7C55 xor ax, ax MEMORY:7C57 mov ss, ax MEMORY:7C59 mov sp, 7C00h MEMORY:7C5C sti MEMORY:7C5D push 7C0h ;设置ds MEMORY:7C60 pop ds MEMORY:7C61 assume ds:nothing MEMORY:7C61 push ds MEMORY:7C62 push 66h MEMORY:7C65 retf ;retf弹出cs和ip,因此返回到0x7c0:66执行
|
根据VBR结构oemID来检测是否是 ntfs文件系统,如果不是,则在屏幕上显示 “Disk read error”
接着再检测是否支持int 13扩展读。
因为后面需要调用Int 13中断的一些功能号42h-44h,47h,48h,而这些需要支持int 13扩展才能使用。而且标准的int13中断只能访问8gb以内大小的硬盘空间。如果不支持就失败,显示错误信息。
执行int 13中断功能号42后,会将返回信息存放在ah,bx和cx寄存器。如果支持int 13扩展,则cf为0,bx为0xaa55,cx为1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| MEMORY:7C66 loc_7C66: ; CODE XREF: MEMORY:7C65 MEMORY:7C66 mov ds:0Eh, dl MEMORY:7C6A cmp dword ptr ds:3, 'SFTN' MEMORY:7C73 jnz short loc_7C8A MEMORY:7C75 mov ah, 41h ; 'A' MEMORY:7C77 mov bx, 55AAh MEMORY:7C7A int 13h ; DISK - Check for INT 13h Extensions MEMORY:7C7A ; BX = 55AAh, DL = drive number MEMORY:7C7A ; Return: CF set if not supported MEMORY:7C7A ; AH = extensions version MEMORY:7C7A ; BX = AA55h MEMORY:7C7A ; CX = Interface support bit map MEMORY:7C7C jb short loc_7C8A ;判断cf标志 MEMORY:7C7E cmp bx, 0AA55h ;判断返回的bx是不是等于0xaa55,不等于则失败 MEMORY:7C82 jnz short loc_7C8A MEMORY:7C84 test cx, 1 MEMORY:7C88 jnz short loc_7C8D ;cx等于1,支持Int 13扩展 MEMORY:7C8A MEMORY:7C8A loc_7C8A: MEMORY:7C8A MEMORY:7C8A jmp loc_7D6A ;错误处理,调用int 10中断 在屏幕上打印字符串,并停止执行任何指令 MEMORY:7D6A loc_7D6A: ; CODE XREF: MEMORY:loc_7C8A MEMORY:7D6A mov al, byte_1F8 ; MEMORY:7D6D call loc_7D79 ; 显示 "A disk read error occurred" MEMORY:7D70 mov al, byte_1FB MEMORY:7D73 call loc_7D79 ;显示 "Press Ctrl+Alt+Del to restart" MEMORY:7D76 MEMORY:7D76 loc_7D76: ; CODE XREF: MEMORY:7D77 MEMORY:7D76 hlt ;cpu指令,cpu遇到该指令立即停止执行 MEMORY:7D77 ; --------------------------------------------------------------------------- MEMORY:7D77 jmp short loc_7D76 MEMORY:7D79 ; --------------------------------------------------------------------------- MEMORY:7D79 MEMORY:7D79 loc_7D79: ; CODE XREF: MEMORY:7D6D MEMORY:7D79 ; MEMORY:7D73 MEMORY:7D79 mov ah, 1 MEMORY:7D7B mov si, ax ;ax为错误提示字符串 偏移, MEMORY:7D7D MEMORY:7D7D loc_7D7D: ; 调用int 10中断,每次在屏幕上显示一个字符 MEMORY:7D7D lodsb MEMORY:7D7E cmp al, 0 MEMORY:7D80 jz short locret_7D8B MEMORY:7D82 mov ah, 0Eh MEMORY:7D84 mov bx, 7 MEMORY:7D87 int 10h ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE) MEMORY:7D87 ; AL = character, BH = display page (alpha modes) MEMORY:7D87 ; BL = foreground color (graphics modes) MEMORY:7D89 jmp short loc_7D7D MEMORY:7D8B ; --------------------------------------------------------------------------- MEMORY:7D8B MEMORY:7D8B locret_7D8B: ; CODE XREF: MEMORY:7D80 MEMORY:7D8B retn
|
如果支持扩展int13中断调用,接下来调用int13中断获取硬盘信息
1 2 3 4 5 6 7 8 9 10
| MEMORY:7C8D loc_7C8D: ; CODE XREF: MEMORY:7C88 MEMORY:7C8D push ds MEMORY:7C8E sub sp, 18h ;在堆栈开辟buffer,用来保存int 13中断,功能号0x48调用后返回的信息 MEMORY:7C91 push 1Ah MEMORY:7C94 mov ah, 48h ; 'H' MEMORY:7C96 mov dl, ds:0Eh;在0x7c66处被赋值,驱动号,通常是0x80 MEMORY:7C9A mov si, sp ;ds:si为存放返回数据的buffer MEMORY:7C9C push ss MEMORY:7C9D pop ds ; MEMORY:7C9E int 13h ; DISK - IBM/MS Extension - GET DRIVE PARAMETERS (DL - drive, DS:SI - buffer)
|
返回内容存放地址ds:si; 具体结构如下:

判断返回的数据是不是有效数据。不是就屏幕显示错误提示字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| MEMORY:7CA0 lahf MEMORY:7CA1 add sp, 18h;刚好指向扇区大小 MEMORY:7CA4 sahf MEMORY:7CA5 pop ax ; MEMORY:7CA6 pop ds;恢复为0x7c00 MEMORY:7CA7 jb short loc_7C8A ;错误处理, MEMORY:7CA9 cmp ax, word_B ; 和NTFS_BPB 的Bytes per Sector比较是不是相等, MEMORY:7CAD jnz short loc_7C8A
  接下来准备调用int 13拷贝IPL的15个扇区。
MEMORY:7CAF mov word_F, ax MEMORY:7CB2 shr word_F, 4 ;0x200>>4 =0x20 MEMORY:7CB7 push ds MEMORY:7CB8 pop dx ;dx=0x7c0 MEMORY:7CB9 xor bx, bx MEMORY:7CBB mov cx, 2000h MEMORY:7CBE sub cx, ax ;0x2000为16个扇区大小,减去一个扇区大小0x200为0x1e00, ;总共要拷贝的数据大小 MEMORY:7CC0 inc dword_11
|
循环调用int 13拷贝VBR之后的IPL 15个扇区,拷贝到内存0x7e00~0x9bff,代码结束地址为0x8c27,剩余部分都被以0填充。
1 2 3 4 5 6 7 8 9 10
| MEMORY:7CC5 MEMORY:7CC5 loc_7CC5: ; CODE XREF: MEMORY:7CD4 MEMORY:7CC5 add dx, word_F ; 拷贝到的地址, ; 0x7c0+0x20 = 0x7e0 实质上是段地址, ; 初始地址是0x7e0,每拷贝成功一个扇区,dx加20,即下一个扇区地址 MEMORY:7CC9 mov es, dx ; MEMORY:7CCB inc word_16 MEMORY:7CCF call near ptr unk_7D1D ;拷贝IPL的15个扇区 MEMORY:7CD2 sub cx, ax ;每次减0x200大小,为0也就拷贝完15个扇区 MEMORY:7CD4 ja short loc_7CC5
|
进入unk_7D1D函数,可以看到调用了int 13扩展读(功能号42) 来从硬盘拷贝一个扇区到内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| MEMORY:7D1D pushad MEMORY:7D1F push ds MEMORY:7D20 push es MEMORY:7D21 MEMORY:7D21 loc_7D21: ; CODE XREF: MEMORY:7D63 MEMORY:7D21 mov eax, var_11 MEMORY:7D25 add eax, dword_1C MEMORY:7D2A push ds ; MEMORY:7D2B push large offset unk_0 ;构建disk address packet结构 MEMORY:7D31 push eax MEMORY:7D33 push es ;es:eax 为拷贝到的内存位置 MEMORY:7D34 push bx ;要拷贝的位置,使用LBA寻址 MEMORY:7D35 push 1 ;每次值拷贝一个扇区 MEMORY:7D38 push 10h ;DAP大小 MEMORY:7D3B mov ah, 42h ; 'B' MEMORY:7D3D mov dl, byte_E ;驱动号 MEMORY:7D41 push ss MEMORY:7D42 pop ds MEMORY:7D43 mov si, sp MEMORY:7D45 int 13h ; DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet) MEMORY:7D47 pop ecx MEMORY:7D49 pop bx MEMORY:7D4A pop dx MEMORY:7D4B pop ecx MEMORY:7D4D pop ecx MEMORY:7D4F pop ds MEMORY:7D50 jb loc_7D6A ; 如果cf为1,读硬盘失败,跳转到错误处理 MEMORY:7D54 inc var_11 MEMORY:7D59 add dx, word_F MEMORY:7D5D mov es, dx MEMORY:7D5F dec word_16 MEMORY:7D63 jnz short loc_7D21 MEMORY:7D65 pop es MEMORY:7D66 pop ds MEMORY:7D67 popad MEMORY:7D69 retn
|
把IPL的数据全部都从硬盘读到内存后,调用 Int 1a中断, ah为0xbb 检测是否支持TCG
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| MEMORY:7CD6 mov ax, 0BB00h MEMORY:7CD9 int 1Ah ; Trusted Computing Group call - TCG_StatusCheck MEMORY:7CD9 ; Return: EAX = 0 if supported MEMORY:7CD9 ; EBX = 41504354h ('TCPA') MEMORY:7CD9 ; CH:CL = TCG BIOS Version MEMORY:7CD9 ; EDX = BIOS TCG Feature Flags MEMORY:7CD9 ; ESI = Pointer to Event Log MEMORY:7CD9 ; MEMORY:7CDB and eax, eax MEMORY:7CDE jnz short loc_7D0D ;如果eax等于0,BIOS支持TCG MEMORY:7CE0 cmp ebx, 'APCT' MEMORY:7CE7 jnz short loc_7D0D MEMORY:7CE9 cmp cx, 102h MEMORY:7CED jb short loc_7D0D MEMORY:7CEF push ss MEMORY:7CF0 push offset unk_BB07 MEMORY:7CF3 push ss MEMORY:7CF4 push offset unk_E70 MEMORY:7CF7 push ss MEMORY:7CF8 push offset unk_9 MEMORY:7CFB push ebx MEMORY:7CFD push ebx MEMORY:7CFF push ebp MEMORY:7D01 push ss MEMORY:7D02 push ss MEMORY:7D03 push ss MEMORY:7D04 push offset unk_1B8 MEMORY:7D07 popad MEMORY:7D09 push cs MEMORY:7D0A pop es MEMORY:7D0B int 1Ah
|
将IPL非代码部分用0填充。
1 2 3 4 5 6
| MEMORY:7D0D xor ax, ax MEMORY:7D0F mov di, 1028h MEMORY:7D12 mov cx, 0FD8h ;4056空闲大小被清0 MEMORY:7D15 cld MEMORY:7D16 rep stosb MEMORY:7D18 jmp near ptr unk_7E7A;0x7e7a为IPL处代码
|
IPL代码
IPL的15个扇区复制完毕后,接着便是解析NTFS文件系统 找到bootmgr文件。计算每簇所占的字节数
1 2 3 4 5
| MEMORY:7E7A movzx eax, word_B ;ds为0x7c00,隐藏word_b为0x7c0b,即 ;BPB结构的bytesPerSector (每扇区字节数)字段 MEMORY:7E80 movzx ebx, byte_D ;sectorsPerCluster 每簇扇区数, MEMORY:7E86 mul ebx ;eax*ebx 计算每簇的字节数,簇是NTFS系统文件最小计量单位, MEMORY:7E89 mov dword_252, eax
|
计算文件记录(File Record)的大小(文件记录 NTFS文件系统的名词),当簇的大小大于文件记录的大小时,clustersPerMFTRecord的值为负数,但是大小是不可能为负的。举个栗子,这里值是0xf6,实际上是计算2^|-10|=1024
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| MEMORY:7E8D mov ecx, dword_40; clustersPerMFTRecord每个文件记录所占的簇数 ,这里值为0xf6(-10) MEMORY:7E92 cmp cl, 0 ; MEMORY:7E95 jg loc_7EA7 ;大于0跳转,但是大部分是小于0的 MEMORY:7E99 neg cl ;-(-10) MEMORY:7E9B mov eax, 1 MEMORY:7EA1 shl eax, cl ;2^10 MEMORY:7EA4 jmp short loc_7EAE MEMORY:7EA6 nop MEMORY:7EA7 MEMORY:7EA7 loc_7EA7: ; clustersPerMFTRecord值不是负数,直接相乘得到文件记录所占用的字节数 MEMORY:7EA7 mov eax, dword_252 ;0x7e52 每簇所占用字节数 MEMORY:7EAB mul ecx MEMORY:7EAE loc_7EAE: ; CODE XREF: MEMORY:7EA4 MEMORY:7EAE mov _byte_file_record, eax; _byte_file_record 0x7e66
|