引自:http://bbs.sunplusedu.com/showtopic-4383.aspx
探索第一部,先研究FAT16和FAT32的文件结构,能在硬盘的茫茫的数据海洋中找到我们想要的数据,这个也是数据恢复技术的基础哦,NTFS 和 自己写程序来实现咱们想做的事,这是后面需要研究的,先不要急进,一部一部由起初开始吧。 FAT的文件结构,先推荐一份资料,(以下全部简称 “资料” ,请注意)写得非常不错的,务必将全部内容啃下来[url]http://www.sjhf.net/Article/sjhfdoc/200404/1.html[/url] 那个网站也只是介绍了FAT的结构,这个非常有用,下面看咱们怎么在硬盘中找到我们想要的文件吧,作为例子 在D盘建立一个文本文件,名字叫 Etual.txt ,内容是:“hello world”,保存,下面咱们就通过簇链找他出来。Let‘s go~~ 工具: 强烈推荐一个工具,也就是上面那个资料里面的那个 winHEX ,因为我们探索的第一步,只需要熟悉FAT文件系统,找出文件来就够了,用winHEX直观,而且功能非常强大,总比每一步都用debug打汇编代码来得好吧? 破解版的下载地址 [url]http://www.sjhf.net/Soft/Class1/200603/37.html[/url] 第二个工具是 window的计数器,用来 16 和10进制之间的转换,当然也可以用其它工具,还有就是用 office的excel 来计数,超爽。 看过黑客帝国了吧?对,咱们现在要去地方也只是只有 0 1代码。 总的流程:(这个已经是最基础最简单的>_<) (1)找主引导记录MBR (2)找D盘的分区链表 (3)找D盘的引导记录(这里包括了BPB表) (4)计算出 FAT1和FAT2表的位置, (5)找到数据区的位置(FDT表在数据区的第一个扇区) (6)根据FDT找到我们的文件的目录登记项 (7)根据目录登记项找到文件存储的第一个簇的地址 (8)根据FAT1表确定簇链,最后读出文件。 总的思想 首先,不要想得那么神秘,下面做的所有操作,其实就可以浓缩成一个操作: BIOS 的 INT13H 中断的调用,因为INT13H的中断可以对硬盘进行访问,读写都可以,当然这个中断需要入口参数,也就是具体的扇区的地址了,所以我们下面做的所有工作,就是计算这个扇区的地址而已,然后提供给 INT13H 中断参数,然后调用中断,最后得到结果,就这么简单,而后面用C和汇编写程序也只是做这些操作而已。当然,这些地址参数不是那么简单可以算到的,非常繁琐,好了,不多说了,开始了。 具体流程: (1) 找主引导记录MBR 先钻研好资料的磁盘基本结构和MBR部分,我只说一些具体的实践过程中的一些小问题和个人的经验而已,具体那些东西最好自己看资料,资料说得非常清楚,否则是听天书。 CHS寻址作为基础还是要学的 cylinder head sector ,柱面,磁头,扇区,为什么要这样?你看一下基本INT13 BIOS 中断的入口参数就知道了,他就是需要这么多参数来定位的。 我的经验是,这样理解,CHS分别是百位十位个位,扇区是最少的单位,柱面最大,S扇区不断加,加到最大值,向H磁头进位,磁头加到最大值,再向C柱面进位,C柱面最大值就标识最大能访问的空间,也限制了一个硬盘的容量。 INT13H中断分为 基本 INT13H中断和扩展INT13中断,简单点理解,基本的用于旧的硬盘,寻址范围是 C * H * S * 512字节 越 8G 的空间,显然不够,所以需要用后来的扩展INT13H来寻址,具体先啃好资料再说…… 寻址方式 就两种嘛,CHS的3要素寻址和LBA线型寻址,CHS是根据CHS3个参数计算出地址,然后找数据的。而LBA寻址是按照一个扇区为单位,所有空间看成逻辑上连续的,从 0扇区开始一个一个扇区的加,直到整个硬盘最后的扇区为止。 CHS的计算很麻烦的,不过是基础,需要学,不过在操作可以完全不用,我们只动用LBA寻址可以达到目的了。 MBR是最重要的,计算机启动的时候BIOS自检之后就是在MBR里面找引导代码的了,如果MBR损坏,可以说硬盘就没有用了,因为计算机根本不认硬盘了,当然可以用软件修复,这是后话。 主引导位于磁盘的 0柱面,0磁头,1扇区,(CHS为 0 0 1)也就是整个硬盘最开始的第一个扇区。柱面跟磁道是一个概念,经常听说0磁道损坏硬盘报废么?0磁道损坏也就是MBR损害了,硬盘是铁定报废的了,这磁道非常重要,不像其它磁道可以屏蔽。 MBR的位置是唯一的,0 0 1 ,所以这个不用找,占1个扇区,一共 512字节。(每个扇区就是512字节了,这个是固定的)打开就是了 >_< 运行 winHEX ,按F9 open disk,选择 physical Media 的物理磁盘,可以打开自己机器的硬盘了,之后软件就显示硬盘显示数据 WinHEX的使用比较简单哦,直接摸索一下就可以上手了,下面也不再浪费口水说这些无谓的问题了。 打开之后调整显示一行显示 16个数据 0~F,这样一个屏幕刚好是一个扇区,看软件左下角的那个 sector 0 of 117210240 这个是按照LBA寻址的,磁盘一共有 117210240 个扇区,本扇区是 第0 个 ,因为编号是0开始的,所以这个就是整个磁盘的第一个扇区,也就是MBR的所在地了。 对照资料,分析这个扇区 前面的引导代码先无视,留下以后研究吧,咱们要的就是分区表,看偏移 1be 那里 连续放的是4个分区表,不过一般只有2个是使用的,第一个是 我的硬盘的分区表是 80 01 01 00 0B FE BF 60 3F 00 00 00 E2 48 95 00 00 00 81 61 0F FE FF FF 21 49 95 00 5F 33 67 06 第一个分区表指向主分区,第二个表指向扩展分区,其实一般来说(其它情况不算――)这里就是咱们的 C 和 D 盘的分区链表,更加直观的理解:这个是主分区和扩展分区的入口地址,真正的入口地址应该是他指向的分区引导记录,什么东西都是从这里开始的,所谓的链就是这样,我们找到了分区链表的第一节了,以后只要沿着这条链子一直找下去就能找到其它E F盘的分区链表位置了。 让我们这么理解吧,分区表相当于一张写着地址的纸条,你可以根据纸条去找到你想找的房子,而我们的分区引导记录相当于房子,就是你根据纸条找到的那间房子,然后房子里面有很多个小房间,也就相当于咱们以后说道的其它表和数据区了,到时再说。 分析这个分区表代表了什么意思: (1) 只向主分区的表 80 | 01 | 0100 | 0B | FE| BF 60 | 3F 00 00 00 | E2 48 95 00 上面用|来分开几个段,对照资料可以看出 80标识启动分区 (主分区的C盘),接着3个字节就是CHS值了,不过计算的规则超奇怪,这个也是CHS麻烦的地方,咱们也来计算一下吧: 01 代表磁头,01 00 这个是柱面和扇区的符合,扇区一共6 位,柱面一共10位,两个符合在一起,一共16位,双字节。先将 01变成2进制 0000 0001 去低6位,这就是扇区的地址了,也就是 000001 变成十进制是 1 ,而剩下的高2位 00 和下一个字节 00 组成柱面的10位地址 00 0000 0000 也就是 0,所以得出 CHS 的地址是 0 1 1,这个是指向分区引导记录的首地址。 接着的 0B 代表 分区类型,0B 代表 FAT32分区 下3个字节数据 FE BF 60 也是CHS值,是指向分区的结算扇区的(这里是C盘的结算扇区),计算方法和上面一样 H = FEH=254D , S = BF的低6位,也就是 1011 1111 取低6位,也就是十进制的63D,柱面 10 0110 0000 = 608 D (D代表10进制,H代表16进制),也就是CHS 608 254 63 这样计算确实是麻烦,有个规律,分区表所在的地方是CHS 0 0 1 ,只要将磁头加1就可以,变成 CHS 0 1 1 ,跟上面计算的一样的,而且这个规律通用,可惜CHS只能访问 8G 硬盘,再好用,实际用到的情况估计不大。 继续下面的4个字节,千万注意,硬盘存储的数据是先低位再高位存储的,所以实际上这4个字节的数据应该是 00 00 00 3F H = 63D ,以后读硬盘的时候都是这样的,千万注意。这个代表分区引导记录前面是 63个扇区。 最后的4个字节, 00 95 48 E2 H = 9783522 这里是代表本分区共有9783522个扇区,每个扇区 512字节,所以这个分区一共9783522*512=5009163264字节,约等于4.665G,这个就是我的C盘的大小了,哈哈~~~ 这个算是最简单的计算了的,自己演算几次,很快上手的了。 好了,说完基础了,现在开始研究一下规律了。 先说说怎么将CHS转换成 LBA ,这样就可以发现分区表前后数字其实是代表一个意义。前面说过CHS本身就是一个进位关系,C最大,S最小,不过有点特别的,这个不是十进制这个也是本身特征决定的…. 扇区是1开始到63 编号的(也就是一个磁道分成63个扇区) 所以扇区加到64就自动变成1,而且向磁头H 进位,H磁头也是同样道理,取值是 0到 254 ,当加到 255 就自动向柱面C进位。 例如上面分析分区表的时候得到CHS 608 254 63 这个数据,将他转化成LBA的话就是下面这样计算就可以了: (608×255+254)×63+63 -1 =9783584 这个很好理解吧?例如十进制的 123,就是 100×1 + 10×2 + 1×3 = 123个1 ,我们上面算CHS转换成LAB的也整整是这个原理而已,最后的-1是为了修正LAB从0开始编号的(就像数组的坐标,应该很好理解吧?)