|
在VB中对硬盘的底层操作大全(二)
在VB中对硬盘的底层操作大全
第一篇中讲到怎样读取物理硬盘的BootRecord的数据,用了如下的方法:
Public Const GENERIC_READ = &H80000000
Public Const GENERIC_WRITE = &H40000000
Public Const FILE_SHARE_READ = &H1
Public Const FILE_SHARE_WRITE = &H2
Public Const OPEN_EXISTING = 3
'//为了简单起见,注意下面的声明语句部分地方已经改动过
Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _
(ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, _
lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Public Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, _
ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long) As Long
Public Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, _
ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Dim Buffer(1 To 512) As Byte
Dim hDevice As Long
Dim hadRead As Long
hDevice = CreateFile("\\.\PHYSICALDRIVE0", GENERIC_READ Or GENERIC_WRITE, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0&, 0&)
Call ReadFile(hDevice, Buffer(1), 512, hadRead, ByVal 0&) '//(****)
Dim i As Long
For i = 1 To 512
Debug.Print Hex$(Buffer(i));
Next
Call CloseHandle(hDevice)
这样数组buffer()里的512Byte的数据即为第一个物理硬盘的BootRecord数据了。我们可以将它保存在另外一个文件里,这样当万一我们的硬盘受到病毒的破坏导致分区不见了,就可以从这个文件恢复BootRecord,从而修复硬盘。
啊,那么怎样写数据入BootRecord呢?
MSDN里没有怎么讲,凭着我不入地狱谁入地狱的精神,我试过用WriteFile API函数就可以了,
首先看看怎样在瞬间“清空”硬盘的BootRecord。
将上面带 (****) 号的一句换成:
'//注意!千万不要调试/运行本段程序,除非你不想要你的硬盘了(在别人的机上除外哦 :)))
Call WriteFile(hDevice,Buffer(1),512,hadRead,Byval 0&)
由于Buffer()里面的数据都是00000……,这样,机器上的第一个物理硬盘的BootRecord数据全部变成0…000了,换句话说,MBR和主分区表DPT都被破坏了。如果想破坏硬盘上的所有数据,那也是很简单的事,只要不断地 WriteFile,用0000填充硬盘上的所有数据就可以了,这样硬盘上的其他部分(DBR、FAT、DIR、DATA)都会被清空。(哎呀,怎么越讲越离题了!都教人搞破坏去了,该批斗!)
言归正传了,如果首先在Buffer()存有原来硬盘的BootRecord数据,再调用WriteFile,那么就是变成恢复硬盘的BootRecord了,(要是少了这一步,那真是一失足成千古恨)。
下面开始今天的新内容。
一、我们知道一个物理硬盘可以分成多个区的,从而形成多个逻辑盘。那么逻辑盘的信息是保存在哪里的呢?例如一个逻辑盘的卷标、序列号、大小等。其实每个逻辑盘也有类似的BootRecord。而且根据文件系统的不同,其BootRecord的数据结构都不太相同。下面就列出几种常见的文件系统的BootRecord的数据结构。
(1)NTFS的:
Private Type NTFSBOOTRECORD
JumpCodeAndNop(1 To 3) As Byte
OEMName(1 To 8) As Byte
BytesPerSector As Integer
SectorsPerCluster As Byte
Unused(1 To 7) As Byte
MediaDescriptor As Byte
Unused2 As Integer
SectorsPerTrack As Integer
HeadCount As Integer
Unused3(1 To 8) As Byte
DontKnow1 As Integer
DontKnow2 As Integer
SectorsInStorageUnit As Currency
LCNMFTData As Currency
LCNMFTMirrorData As Currency
FileRecordClusters As Long
IndexBufferClusters As Long
SerialNumber As Long
End Type
(2)FAT16的:
Private Type FAT12FAT16BOOTRECORD
JumpCodeAndNop(1 To 3) As Byte
OEMName(1 To 8) As Byte
BytesPerSector As Integer
SectorsPerCluster As Byte
ReservedSectors As Integer
NumberOfFATCopies As Byte
MaxRootDirEntries As Integer 'N/A on FAT32
SectorsSmallerThan32MB As Integer 'N/A on FAT32
MediaDescriptor As Byte 'F8h for Hard Disks
SectorsPerFATOld As Integer 'N/A on FAT32
SectorsPerTrack As Integer
NumberOfHeads As Integer
HiddenSectors As Long
Sectors As Long
DriveNum As Byte
Reserved As Byte
BootSignature As Byte
VolumeID As Long
VolumeLabel(1 To 11) As Byte
FileSystemType(1 To 8) As Byte
End Type
(3)FAT32的:
Private Type FAT32BOOTRECORD
JumpCodeAndNop(1 To 3) As Byte
OEMName(1 To 8) As Byte
BytesPerSector As Integer
SectorsPerCluster As Byte
ReservedSectors As Integer
NumberOfFATCopies As Byte
MaxRootDirEntries As Integer 'N/A on FAT32
SectorsSmallerThan32MB As Integer 'N/A on FAT32
MediaDescriptor As Byte 'F8h for Hard Disks
SectorsPerFATOld As Integer 'N/A on FAT32
SectorsPerTrack As Integer
NumberOfHeads As Integer
HiddenSectors As Long
Sectors As Long
SectorsPerFAT As Long
Flags As Integer
Version As Integer
RootDirectoryCluster As Long
FileSystemInformationSector As Integer
BackupBootSector As Integer
Reserved(1 To 12) As Byte
LogicalDriveNumber As Byte
Unused As Byte
ExtendedSignature As Byte '29h
SerialNumber As Long
VolumeName(1 To 11) As Byte
FATName(1 To 8) As Byte
ExecutableCode(1 To 420) As Byte
BootRecordSignature(1 To 2) As Byte '55h AAh
End Type
我们怎样知道一个逻辑盘(如C:\;D:\;G:\)的文件系统是什么呢?方法有很多,例如在“我的电脑”中对着逻辑盘右击鼠标,选择“属性”,就可以看到它的文件系统了。(只见一大堆烂番茄飞向小生,“我们要的是用编程方法呀!!SB……”)
用 GetVolumeInformation API函数即可轻松搞定了,下面是个获取一个盘的文件系统的自定义函数。其中参数Drive为盘符,如“C:”、“D:”、“I:”
Public Function GetFileSystem(Drive As String) As String
Dim VolName As String, FileSystem As String, SerialNum As Long
Dim MaxFileLen As Long, Flags As Long
VolName = String(16,chr$(0))
FileSystem = String(16,chr$(0))
GetVolumeInformation Drive & "\", VolName, Len(VolName) - 1, _
SerialNum, MaxFileLen, Flags, FileSystem, Len(FileSystem) - 1
Dim Pos As Integer
Pos = InStr(FileSystem, Chr(0))
If Pos Then
GetFileSystem = UCase(Left(FileSystem, Pos - 1))
Else
GetFileSystem = UCase(FileSystem)
End If
End Function
好了,最后,怎样读取逻辑盘的BootRecord呢?方法跟读取物理硬盘的BootRecord基本相同。各个逻辑盘的名称为在盘符前面添加"\\.\",如C盘即为"\\.\C:",H盘即为"\\.\H:"
下面例子我们打开D:盘,并读取BootRecord的数据。
Dim hDrive as long
Dim Buffer(1 To 512) As Byte, Read As Long
Dim RetVal As Long
Dim i AS long
hDrive = CreateFile("\\.\D:", GENERIC_READ, FILE_SHARE_READ Or _
FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
If hDrive = INVALID_HANDLE_VALUE Then
MsgBox "Error opening the drive."
Else
RetVal = ReadFile(hDrive, Buffer(1), 512, Read, byval 0&)
If RetVal And (Read = UBound(Buffer)) Then
'//在此打印Buffer里的数据内容
For i=1 to 512
Debug.print Hex$(Buffer(i));
Next
Else
MsgBox "Error reading the drive."
End If
End If
CloseHandle hDrive |
|