声明: 原创作品,学习目的
反汇编工具: W32DASM 流程图软件: DiagramDesigner
NT52 MBR 主引导代码,反汇编与注释:
学习经验总结:
NT52 MBR 对分区活动标志的要求如下:
只能有一个分区为激活状态,其余分区激活标志必须为0
激活标志为80H,对活动标志初步检查时,只会检查激活标志是否小于0.但后期调用INT 13H读硬盘扇区时,会直接把激活标志赋值给DL(INT 13H的驱动器号入口参数),如果不为80H,肯定会失败.
把DBR扇区载入内存0:7C00之后,会检查是否有55 AA 标志,如果没有此标志,并且分区类型是FAT32的情形下,会尝试装载 备份DBR (FAT32分区开始扇区+6扇区)到0:7C00,如果备份DBR扇区有55 AA 标志,会从备份DBR进行引导.
以下为反汇编源代码与注释:
:0001.0000 33C0 xor ax, ax ;ax置0,重置标志寄存器
:0001.0002 8ED0 mov ss, ax ;SS=0
:0001.0004 BC007C mov sp, 7C00 ;设置堆栈 0:7c00
:0001.0007 FB sti ;开中断,允许响应外部可屏蔽中断
:0001.0008 50 push ax ;入栈AX的值
:0001.0009 07 pop es ;出栈栈中数据赋值给ES,使ES=0
:0001.000A 50 push ax ;入栈AX
:0001.000B 1F pop ds ;出栈栈中数据赋值给DS,使DS=0
:0001.000C FC cld ;设置数据串操作方向为正方向,使SI DI的值递增
:0001.000D BE1B7C mov si, 7C1B ;SI=7c1b
:0001.0010 BF1B06 mov di, 061B ;DI=061B
:0001.0013 50 push ax ;入栈AX
:0001.0014 57 push di ;入栈DI
:0001.0015 B9E501 mov cx, 01E5 ;CX=01E5 十进制 485
:0001.0018 F3 repz
:0001.0019 A4 movsb ;进行内存复制操作把DS:SI 指向的内容复制到ES:DI指向的位置
;根据CX的值进行按字节循环复制,一共复制485个字节
;7C1B正好是 RETF指令后面的语句,也就是 mov bp,07be 这条语句
;此处进行的操作是 把程序代码移动位置,然后从新的位置继续执行指令
;硬盘的MBR被BIOS载入到内存0:7C00的位置,并从此处执行指令
:0001.001A CB retf ;出栈栈中的数据设置CS:IP,使CPU从0:061B执行指令
:0001.001B BDBE07 mov bp, 07BE ;移动位置后的程序,此处是061B 该语句使BP=07BE
;07BE指向的正好是分区表的开始
;07BE-0600=1BE 1BE正好是分区表的开始
:0001.001E B104 mov cl, 04 ;CL=4
:0001.0020 386E00 cmp [bp+00], ch ;SS:[BP+00]的值与CH的值进行比较
;注意CH的值为0 上面根据CX的值进行内存复制操作,执行完以后CX=0
:0001.0023 7C09 jl 002E ;如果ss:[bp+00]的值小于0跳转到002E 执行
;JL是针对有符号数的判断,分区激活标志为80H,二进制数为10000000B
;二进制数10000000当作有符号数是 -128(十进制)
:0001.0025 7513 jne 003A ;不为0跳到003A执行
;分区激活标志既不是80H,也不是0,则跳转到3A执行
:0001.0027 83C510 add bp, 0010 ;BP的值加10H,也就是加16指向下一分区表的开始
:0001.002A E2F4 loop 0020 ;根据CX的值进行循环,也就是遍历分区表,查找活动分区
:0001.002C CD18 int 18 ;调用INT18 从下一启动设备启动
;如果一直没有找到活动分区,调用INT18H
*******************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0023(C)
| 反汇编工具的提示: 从0023有一条跳转到此处的条件转移指令
*******************************************************************************************************************
:0001.002E 8BF5 mov si, bp ;SI=BP 假设BP=7BEH,所以SI=7BEH 假设第一分区表项是激活状态
*******************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0038(C)
| 反汇编工具的提示: 0038有一条条件转移指令跳转到0030
*******************************************************************************************************************
:0001.0030 83C610 add si, 0010 ;si+10H SI=下一分区表开始
:0001.0033 49 dec cx ;CX的值减1
:0001.0034 7419 je 004F ;如果CX=0,跳转到4F执行
;假设该语句在第一次执行时,条件即被满足,那么CX在DEC CX语句之前=1
;也就是最后一个分区表是激活状态时,跳转到4F执行
;假设该语句不是第一次执行时条件得到满足,但只要是能够满足条件
;分区表必定是有一个是激活状态,其余全部为0,此时跳转到4F执行
;总结来说,跳转到4F执行的条件是:
;分区表有一个表项是激活状态(至少小于0,为负),其余分区表项都为0
:0001.0036 382C cmp [si], ch ;判断DS:[SI]的值是不是0
:0001.0038 74F6 je 0030 ;如果是0跳转到0030 进行循环
;正常情形下,假设第一分区表是激活状态,那么后面的分区表项应该是0(非激活)
;假设第一分区是激活状态,后面的都是0,那么此处会进行3次循环
;最后一次会跳转到4F去执行
**************************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0025(C)
| 反汇编工具的提示: 0025有一条条件转移指令跳转到003A
**************************************************************************************************************************
:0001.003A A0B507 mov al, [07B5] ; 把DS:[07B5]的值赋给al
; 07b5-600=1b5 实机值是2C
; 01b5的值实机是 2c 44 63
; 跳转到此处或者执行到此处的条件是: 分区表激活标志不规范
; 0025处有一个判断,如果分区表激活标志不小于0,又不等于0会跳转到此处
; 0038处的判断,如果找到一个分区表项的激活标志小于0,但是下一表项的激活标志
;不为0,也就是说存在多个激活标志或者不规范的取值,都会跳转到此处执行
; 总结,跳转到003A的条件是:
; A 激活标志不小于0 (取值范围不在80H~FFH) 又不等于0
; B 找到一个小于0的激活标志,但下一分区激活标志不等于0
; A与B 只要有一条符合都会跳到此处执行
**************************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.0069(C), :0001.007F(U), :0001.0092(U)
| 反汇编工具的提示
**************************************************************************************************************************
:0001.003D B407 mov ah, 07 ;ah=7
:0001.003F 8BF0 mov si, ax ;si=ax 假设si=072c
;此处的目的是把SI指向一个字符串的开始
**************************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.004D(U)
| 反汇编工具的提示: : 004D有一条条件转移指令跳转到此处: 0041
**************************************************************************************************************************
:0001.0041 AC lodsb ;把si指向的存储单元读入累计器al 此时串操作方向是正方向DF=0
;072c-0600=12c 指向的正好是一个字符串的开始
; Invalid partition table
**************************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0044(C)
| 反汇编工具的提示: 0044有一条条件转移指令跳转到此处: 0042
**************************************************************************************************************************
:0001.0042 3C00 cmp al, 00 ;判断al的值是不是0,实际是判断字符串是否结束
:0001.0044 74FC je 0042 ;如果结束跳转到42执行
:0001.0046 BB0700 mov bx, 0007 ;bx=7
:0001.0049 B40E mov ah, 0E ;ah=0e
:0001.004B CD10 int 10 ;调用INT10H 在屏幕上显示字符
:0001.004D EBF2 jmp 0041 ;跳转到0041 执行,此处是一个小循环,用于显示字符串
;INT 10H调用说明: ah=0e 功能选择 al=要显示的字符 bh=页符 bl=前景色
;程序执行到003A以后,此处程序即会在屏幕上显示 Invalid partition table
;显示完提示信息以后,会进入一个人为制造的死循环 0042 0044构造了一个循环
************************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0034(C)
| 反汇编工具的提示: 0034有一条条件转移指令跳转到此处:004F
| 跳转到此处的条件是: 分区表四个表项有一个表项的激活标志取值小于0,其他全为0
************************************************************************************************************************
:0001.004F 884E10 mov [bp+10], cl ;把CL的值写到ss:[bp+10] bp的值是激活分区的开始地址
;BP+10的值是激活分区后面下一个分区的开始
;cl的值是0
:0001.0052 E84600 call 009B ;调用009B
:0001.0055 732A jnb 0081 ;CF不等于1跳转到0081执行
;判断调用是否成功,成功跳转到0081执行
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.008D(C)
|
:0001.0057 FE4610 inc byte ptr [bp+10] ;ss:[bp+10]的值加1
:0001.005A 807E040B cmp byte ptr [bp+04], 0B ;比较[bp+04],也就是分区属性值是否是0B
:0001.005E 740B je 006B ;分区属性是0B跳转到6B执行
:0001.0060 807E040C cmp byte ptr [bp+04], 0C ;检查分区属性是否是0C
:0001.0064 7405 je 006B ;是0C跳转到6B执行
:0001.0066 A0B607 mov al, [07B6] ;al=[07b6]=44h
:0001.0069 75D2 jne 003D ;如果分区属性不为0C跳转到003D
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.005E(C), :0001.0064(C)
|
:0001.006B 80460206 add byte ptr [bp+02], 06 ;[bp+02]的值加6
;[bp+02]对应分区表项扇区项S 扇区加6
:0001.006F 83460806 add word ptr [bp+08], 0006 ;[bp+08]的值加6
;[bp+08]对应分区表项起始LBA的低16位
:0001.0073 83560A00 adc word ptr [bp+0A], 0000 ;分区起始LBA的高16位加上来自前面运算的进位
:0001.0077 E82100 call 009B ;调用009B
:0001.007A 7305 jnb 0081 ;执行成功,跳转到0081
:0001.007C A0B607 mov al, [07B6] ;AL=44H
:0001.007F EBBC jmp 003D ;跳转到003D
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.0055(C), :0001.007A(C)
|
:0001.0081 813EFE7D55AA cmp word ptr [7DFE], AA55 ;比较 ds:[7DFE]的值是不是AA55
:0001.0087 740B je 0094 ;是AA55跳转到0094执行
:0001.0089 807E1000 cmp byte ptr [bp+10], 00 ;检查 ss:[bp+10]的值是否是0
:0001.008D 74C8 je 0057 ;结果为0 跳转到0057执行
:0001.008F A0B707 mov al, [07B7] ;al=63H
:0001.0092 EBA9 jmp 003D ;跳转到003D执行
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0087(C)
|
:0001.0094 8BFC mov di, sp ;DI=SP
:0001.0096 1E push ds ;入栈DS的值
:0001.0097 57 push di ;入栈DI的值
:0001.0098 8BF5 mov si, bp ;SI=BP
:0001.009A CB retf ;执行RETF指令,移交控制权
* Referenced by a CALL at Addresses:
|:0001.0052, :0001.0077
|
:0001.009B BF0500 mov di, 0005 ;di=5
:0001.009E 8A5600 mov dl, [bp+00] ;dl=ss:[bp] 假设第一分区激活,BP=7BE dl=80
:0001.00A1 B408 mov ah, 08 ;ah=8
:0001.00A3 CD13 int 13 ;调用INT 13H
;int13h ah=8 用于读取驱动器参数
:0001.00A5 7223 jb 00CA ;检查返回值,失败跳转到00CA执行
; AH=8 功能调用 成功返回值: DH=磁头 DL=驱动器数 CL低6位=扇区
:0001.00A7 8AC1 mov al , cl ;al=cl
:0001.00A9 243F and al, 3F ; "与运算" 取AL的低6位也就是扇区数
:0001.00AB 98 cbw ;符号扩展指令,把AL的符号扩展到AH
:0001.00AC 8ADE mov bl , dh ;bl=dh=磁头数
:0001.00AE 8AFC mov bh, ah ;bh=ah=0 AL进行"与运算"之后,符号位肯定是0 AH=0
:0001.00B0 43 inc bx ;BX加1 BX=磁盘总的磁头数
:0001.00B1 F7E3 mul bx ;乘法运算 ax*bx=dx:ax DX是乘法的高16位 AX是乘法的低16位
;实际是进行扇区*磁头的运算
;bx最大值为255 AX值最大为63 结果最大为3EC1H,所以DX的值为0
:0001.00B3 8BD1 mov dx, cx ;dx=cx
:0001.00B5 86D6 xchg dh, dl ;交换DH DL的值
:0001.00B7 B106 mov cl, 06 ;cl=6
:0001.00B9 D2EE shr dh, cl ;移位运算dh向右移6位
:0001.00BB 42 inc dx ;DX加1
;DX的值为总的柱面数
:0001.00BC F7E2 mul dx ;乘法运算 dx*ax=总的扇区数*总的磁头数*总的柱面数,得到磁盘的最大容量
;DX:AX的值为磁盘的总扇区数
;分析: 因为INT 13H/AH=8的返回值得到的最大CHS值为1024/255/63
;1024*255*63=16450560=FB0400H DX的最大值为FB
:0001.00BE 39560A cmp [bp+0A], dx ;比较SS:[BP+0A] 与DX的值
;DX的值为总扇区数的高16位
;BP+0A 的偏移是分区表起始LBA的高16位
:0001.00C1 7723 ja 00E6 ;ja进行无符号数比较 如果分区表起始LBA高16位的值大于DX的值跳转到00E6
;也就是分区的起始LBA大于8G
:0001.00C3 7205 jb 00CA ;分区起始LBA地址的高16位小于DX的值跳转到00CA执行
:0001.00C5 394608 cmp [bp+08], ax ;比较 SS:[BP+08] 与AX的值 AX的值为总扇区数的低16位
;BP+08 的偏移是分区起始LBA的低16位
:0001.00C8 731C jnb 00E6 ;不低于AX的值跳转到00E6 执行
;也就是说分区的起始LBA小于8G跳转到00CA执行
;分区起始LBA高16位等于DX的值,低16位不小于AX的值,也就是大于等于8G跳转到E6
************************************************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.00A5(C), :0001.00C3(C), :0001.00E4(U)
| 反汇编工具提示: 00A5处有一条条件转移指令跳转到此处00CA
************************************************************************************************************************
:0001.00CA B80102 mov ax, 0201 ;AH=02 读功能 AL=01一个扇区
:0001.00CD BB007C mov bx, 7C00 ;BX=7C00 数据缓冲区
:0001.00D0 8B4E02 mov cx, [bp+02] ;CX=SS:[BP+02] 假设BP=7BE SS:[07D0]指向分区表项的第二个字节
;柱面加扇区 CH=柱面数 CL=扇区数 CL的高2位+CH的8位=柱面数 CL的低6位=扇区数
;CX的值正好对应分区表部分的取值
:0001.00D3 8B5600 mov dx, [bp] ;SS:[BP]是分区表的开始,DL是驱动器号,DH对应磁头数
:0001.00D6 CD13 int 13 ;调用INT13H读扇区功能
:0001.00D8 7351 jnb 012B ;如果INT13H读扇区成功,跳转到12B执行.
:0001.00DA 4F dec di ;di的值减1 初始值为5
:0001.00DB 744E je 012B ;检查结果是否为0,等于0 跳转到12B 执行 12B是一条返回指令
:0001.00DD 32E4 xor ah, ah ;ah清0
:0001.00DF 8A5600 mov dl, [bp+00];dl=SS:[BP],假设等于80H
:0001.00E2 CD13 int 13 ;再次调用INT13H
;INT 13H /ah=00h 磁盘系统复位 DL=驱动器号
:0001.00E4 EBE4 jmp 00CA ;跳转到00CA执行 此处是一个小循环,重复4次调用INT13读扇区功能
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.00C1(C), :0001.00C8(C)
|
:0001.00E6 8A5600 mov dl, [bp+00] ;dl=80H 假设
:0001.00E9 60 pusha ;通用寄存器全部入栈
:0001.00EA BBAA55 mov bx, 55AA ;bx=55aa
:0001.00ED B441 mov ah, 41 ;ah=41h 扩展INT13H调用
:0001.00EF CD13 int 13 ;检查驱动器是否支持扩展INT 13H
:0001.00F1 7236 jb 0129 ;检测CF是否为1 为1则不支持扩展INT13H,跳转到0129执行
:0001.00F3 81FB55AA cmp bx, AA55 ;比较BX的值,同样是检查扩展INT13H
:0001.00F7 7530 jne 0129 ;失败跳转到129执行
:0001.00F9 F6C101 test cl, 01 ;检查CL的最低位是否为1
:0001.00FC 742B je 0129 ;仍旧检查扩展INT13H的调用是否成功,不成功跳转到0129执行
:0001.00FE 61 popa ;恢复寄存器的值
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0001.0127(U)
|
:0001.00FF 60 pusha ;通用寄存器全部入栈
:0001.0100 6A00 push 0000
:0001.0102 6A00 push 0000 ;入栈立即数
:0001.0104 FF760A push word ptr [bp+0A] ;入栈分区起始地址的高16位
:0001.0107 FF7608 push word ptr [bp+08] ;入栈分区起始地址的低16位
:0001.010A 6A00 push 0000
:0001.010C 68007C push 7C00
:0001.010F 6A01 push 0001
:0001.0111 6A10 push 0010 ;入栈立即数
;以上构造 "磁盘地址数据包"
;内存中的数据为 10 00 01 00 00 7c 00 00 xx xx xx xx 00 00 00 00
:0001.0113 B442 mov ah, 42 ;AH=42H 扩展INT13H 读扇区功能调用
:0001.0115 8BF4 mov si, sp ;SI=SP指向磁盘地址包的开始
:0001.0117 CD13 int 13 ;调用扩展INT13H 读扇区功能
:0001.0119 61 popa ;用栈中的数据设置通用寄存器的值 此处是把构造的磁盘地址数据包出栈
:0001.011A 61 popa ;恢复通用寄存器的值
:0001.011B 730E jnb 012B ;调用成功,跳转到12B执行
:0001.011D 4F dec di ;di减1
:0001.011E 740B je 012B ;DI值为0跳转到12B执行
:0001.0120 32E4 xor ah, ah ;清零AH的值
:0001.0122 8A5600 mov dl, [bp+00] ;DL=80H 假设激活标志为80
:0001.0125 CD13 int 13 ;调用INT 13H 磁盘复位
:0001.0127 EBD6 jmp 00FF ;再次跳转到00FF循环
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.00F1(C), :0001.00F7(C), :0001.00FC(C)
|
:0001.0129 61 popa ;恢复寄存器的值
:0001.012A F9 stc ;使CF=1
*******************************************************************************************
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0001.00D8(C), :0001.00DB(C), :0001.011B(C), :0001.011E(C)
| 反汇编工具提示: 00D8处有一条条件转移指令跳转到此处12B
*******************************************************************************************
:0001.012B C3 ret ;返回指令
:0001.012C --> :0001.017B ASCII码表示的字符串
*************************************************************************************
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000120 49 6E 76 61 Inva
00000130 6C 69 64 20 70 61 72 74 69 74 69 6F 6E 20 74 61 lid partition ta
00000140 62 6C 65 00 45 72 72 6F 72 20 6C 6F 61 64 69 6E ble Error loadin
00000150 67 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 g operating syst
00000160 65 6D 00 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 em Missing opera
00000170 74 69 6E 67 20 73 79 73 74 65 6D ting system
*************************************************************************************
:0001.017B -0001.01b4 全为 00
:0001.01B5 2C 44 63
[课程]FART 脱壳王!加量不加价!FART作者讲授!