搜档网
当前位置:搜档网 › 手工(代码)分析硬盘分区表

手工(代码)分析硬盘分区表

手工(代码)分析硬盘分区表


一、WINHEX软件
如果你对硬盘分区表不熟悉,建议你下载一个WINHEX的软件,利用它来辅助理解本文(本人实际上就是这么做的,一边看书,一边打开WINHEX,一边调试程序)。在使用WINHEX时,有一点需要注意一下,我们看到的最小单元就是一个BYTE,连续4个单元就是1个DWORD,不过它是倒着显示的,也就是说我们看到的A1B2C3D4这是一个DWORD数据,那么它实际上等于D4C3B2A1H。(参考1)



二、硬盘数据存储区域
对于FAT文件系统(NTFS及其他文件系统不在本文讨论的范围内)硬盘上数据大致可以分为MBR DBR FAT DIR DATA五个区域,本文只讨论MBR区。MBR区又称为主引导记录区,位于整个硬盘的0磁道 0柱面 1扇区,一共512个字节,其实MBR一共占用63个扇区,不过通常只使用第一个扇区而已。其中,前446个字节为引导程序,随后的64个字节为硬盘分区表,每个分区表描述信息占位16个字节,一共可以描述4个分区,最后2个字节为55H AAH 是分区有效结束标志。关于引导程序我们PASS略过,主要介绍随后的分区表信息,它们每16个字节的各个字节表述含义都是一样的。



三、关于分区数大于4
很多情况下,我们的分区数目不止于四个,但MBR中最多只能容纳四个,为此MS引入了虚拟MBR的概念,所谓虚拟MBR就是在硬盘分区表的后面还有很多和主引导扇区一样的扇区(具体个数取决于你硬盘分区的数量),此虚拟MBR占位512个字节,只不过它的引导程序没有任何意义,一般为全0填充,它的分区表信息也只有2项(各个字节含义同主引导扇区),第一个部分描述本分区信息,第二个部分描述的是下一个分区的信息。如果下一个分区的信息为全0 则表示分区结束。通常情况下,主引导扇区的4个分区也不是全都使用的,第一个为引导区(通常的C盘),第2个为扩展分区,顺着这个链就可以一直找出所有的分区。

四、关于硬盘逻辑锁
由于系统启动时,是需要扫描这个分区链的,正常这个分区链是开链,也就是有开始有结束(全0结束)。但是如果认为的将这个分区链变成一个闭合的链,那势必将引导程序陷入一个死循环,引导程序如果不能找到全0的分区结束标志,那么它就会一直再这个链上跑,并不会启动系统,这就是所谓的硬盘逻辑锁的产生原因。(需要注意的是,这个动作和操作系统有关系。比如老的DOS系统中有这个扫描动作,因此可以根据这个原理制作“硬盘锁”。)
好了,讲到这里,我们借助于WINHEX,随便打开一个物理硬盘(参考2),我们顺着这个分区链就可以找出全部的分区了,并能了解该分区的一些基本信息,

比如起始扇区,分区类型,分区大小等等,下面我们使用ASM代码来描述一下如何扫描这个链表。为了保持程序的完整性和可读性,不再有讲解性内容,而是以注释的形式进行讲解。

;#Mode=CON
.586
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
include fpu.inc
include gdi32.inc
include masm32.inc

includelib masm32.lib
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
includelib fpu.lib
include macro.asm

.data
diskname db '\\.\PHYSICALDRIVE0',0
ctitle db '分区号 分区首地址(扇区) 分区容量(MB)',0
cline db '=======================================',0
cspace db ' ',0
_13 db 13,0
_10 db 10,0
.data?
iobuffer db 512 dup(?)
strbuffer db 512 dup(?)
fqhbuf db 128 dup (?)
fqaddr db 128 dup (?)
vmbrbuf db 128 dup (?)
hdisk dd ?
dwbytesread dd ?
nextp dd ?
vmbrsec dd ?
vmbr dq ?
vmbr2 dq ?
fqh dd ?
.const
_2048 dd 2048
.CODE
START:
mov fqh,1
invoke StdOut,offset ctitle
invoke StdOut,offset _13
invoke StdOut,offset _10
invoke StdOut,offset cline
invoke StdOut,offset _13
invoke StdOut,offset _10
invoke CreateFile,addr diskname,GENERIC_READ or GENERIC_WRITE ,\
FILE_SHARE_READ or FILE_SHARE_WRITE ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
mov hdisk,eax
invoke SetFilePointer,hdisk,0,NULL,FILE_BEGIN
invoke ReadFile,hdisk,addr iobuffer,512,addr dwbytesread,0
;读取MBR区(0扇区)
mov esi,offset iobuffer
;0扇区所有的数据都在iobuffer里,我们主要操作缓冲区
xor ebx,ebx
.while ebx<4
;MBR区只能有4个主引导区,所以我们循环4次就可以了
.if ebx>0
add esi,16 ;每个主分区信息占16个字节,这里对下面—>
.endif ;|——————————————————>
mov eax,[esi+450] ;—>[ESI+450]能否正确寻址,至关重要
.if al==11 || al==12 || al==07 ;11也就是0BH ,0cH表示FAT32 07表示NTFS分区
finit
fild DWORD ptr[esi+458]
fild _2048
fdiv ;除以2048后,转换为MB单位
invoke FpuFLtoA,0,2,addr strbuffer,SRC1_FPU OR SRC2_DIMM OR STR_REG ;调用浮点函数库转换浮点到字符
;需要引用库includelib fpu.lib include fpu.inc
invoke wsprintf,addr fqaddr,CTEXT('%8X'),DWORD PTR [ESI+454]
invoke wsprintf,addr fqhbuf,CTEXT('%4d'),fqh
invoke StdOut,offset fqhbuf
invoke StdOut,offset fqaddr
invoke StdOut,offset cspace
invoke StdOut,offset strbuffer
invoke StdOut,offset _13
invoke StdOut,offset _10
inc fqh
.endif
.if al==15 || al==05 ;15 or 05也就是0FH(05H) 表示

扩展分区
mov eax,[esi+454]
;这里取VMBR地址链的首地址(虚拟MBR的基地址,这2种叫法都是我自己叫的
;别人不知道正是的中文翻译是什么)
mov vmbrsec,eax ;保存VMBR首地址,因为下面要计算和输出这个地址
xor edx,edx
shld edx,eax,9
shl eax,9
;对VMBR地址进行*512的计算,因为结果大于32位,
;所以以下代码段引进了64位的计算
mov DWORD ptr vmbr,eax
mov DWORD ptr vmbr+4,edx
invoke SetFilePointer,hdisk,DWORD ptr vmbr,addr DWORD ptr vmbr+4,FILE_BEGIN ;设置文件指针,因为涉及到64位,请注意
;该函数的第3个参数,一定是64位中高32位
;的值的指针
invoke ReadFile,hdisk,addr iobuffer,512,addr dwbytesread,0
jmp localsector ;转到扫描扩展分区链的处理程序段
.endif
inc ebx
.endw
localsector: ;扩展分区链处理
.repeat
mov esi,offset iobuffer
finit
fild DWORD ptr[esi+458] ;取分区容量,单位扇区
fild _2048
fdiv
invoke FpuFLtoA,0,2,addr strbuffer,SRC1_FPU OR SRC2_DIMM OR STR_REG
mov eax,DWORD ptr [esi+470] ;
add eax,63 ;
add eax,vmbrsec ;VMBR表首地址+63后是分区的首地址
invoke wsprintf,addr fqaddr,CTEXT('%8X'),eax
invoke wsprintf,addr fqhbuf,CTEXT('%4d'),fqh
invoke StdOut,offset fqhbuf
invoke StdOut,offset fqaddr
invoke StdOut,offset cspace
invoke StdOut,offset strbuffer
invoke StdOut,offset _13
invoke StdOut,offset _10
mov eax,DWORD ptr [esi+470];取下一个分区的VMBR的指针
mov nextp,eax
;保存,以备循环终止条件使用,这个指针为0时,则扩展分区扫描结束
push eax
pop eax
xor edx,edx
shld edx,eax,9
shl eax,9 ;EAX*512 乘积放在EDX:EAX中
add eax,DWORD ptr vmbr
adc edx,DWORD ptr vmbr+4
;2个DQ型数据相加,表示下一个分区的指针(NEXTP*512+VMBR)
mov DWORD ptr vmbr2,eax
mov DWORD ptr vmbr2+4,edx ;新指针保存另一个变量中,以备下面调用
;这里绝对不能更改VMBR的值
.break .if nextp == 0
invoke SetFilePointer,hdisk,DWORD ptr vmbr2,addr DWORD ptr vmbr2+4,FILE_BEGIN ;注意这里指针是VMBR2了
invoke ReadFile,hdisk,addr iobuffer,512,addr dwbytesread,0
inc fqh ;分区号自增1
.until nextp==0;如果NEXTP=0 表示分区结束,就是再也没有分区了,程序结束
ret

end START

运行结果:



参考:

1.“big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时

,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。
Intel处理器采用的是“小尾”方式。https://www.sodocs.net/doc/7e15830576.html,/blogger/post_show.asp?BlogID=182860&PostID=2114034

2:WinHex默认启动时弹出打开向导,如果没有的话,可以从 tools 菜单中打开。





相关主题