windows sdk编程系列文章 --- 直接从硬盘扇区读取文件内容

http://hi.baidu.com/combojiang/item/ed8b49e49affba0b8c3ea838
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <winioctl.h>
#include <malloc.h>

ULONGLONG *GetFileClusters(
                    PCHAR lpFileName,
                    ULONG *ClusterSize, 
                    ULONG *ClCount,
                    ULONG *FileSize 
                    )
{
    HANDLE hFile;
    ULONG   OutSize;
    ULONG   Bytes, Cls, CnCount, r;
    ULONGLONG *Clusters = NULL;
    BOOLEAN Result = FALSE;
    LARGE_INTEGER PrevVCN, Lcn;
    STARTING_VCN_INPUT_BUFFER InBuf;
    PRETRIEVAL_POINTERS_BUFFER OutBuf;
    CHAR          Name[7];
    DWORD SecPerCl;
    DWORD BtPerSec;

    Name[0] = lpFileName[0];
    Name[1] = ':';
    Name[2] = 0;

    GetDiskFreeSpace(Name, &SecPerCl, &BtPerSec, NULL, NULL);

    *ClusterSize = SecPerCl * BtPerSec;

    hFile = CreateFile(lpFileName, FILE_READ_ATTRIBUTES,
                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                       NULL, OPEN_EXISTING, 0, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        *FileSize = GetFileSize(hFile, NULL);

        OutSize = sizeof(RETRIEVAL_POINTERS_BUFFER) + (*FileSize / *ClusterSize) * sizeof(OutBuf->Extents);

        OutBuf = (RETRIEVAL_POINTERS_BUFFER *)malloc(OutSize);

        InBuf.StartingVcn.QuadPart = 0;

        if (DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, &InBuf, 
                            sizeof(InBuf), OutBuf, OutSize, &Bytes, NULL))
        {
            *ClCount = (*FileSize + *ClusterSize - 1) / *ClusterSize;

            Clusters = (ULONGLONG *)malloc(*ClCount * sizeof(ULONGLONG));

            PrevVCN = OutBuf->StartingVcn;

            for (r = 0, Cls = 0; r < OutBuf->ExtentCount; r++)
            {
                Lcn = OutBuf->Extents[r].Lcn;

                for (CnCount = (ULONG)(OutBuf->Extents[r].NextVcn.QuadPart - PrevVCN.QuadPart);
                     CnCount; CnCount--, Cls++, Lcn.QuadPart++) 
                    Clusters[Cls] = Lcn.QuadPart;

                PrevVCN = OutBuf->Extents[r].NextVcn;
            }
        }
   
        free(OutBuf); 

        CloseHandle(hFile);
    }
    return Clusters;
}

void Read(
        PCHAR lpSrcName        
        )
{
    ULONG         ClusterSize, BlockSize;
    ULONGLONG    *Clusters;
    ULONG         ClCount, FileSize, Bytes;
    HANDLE        hDrive;
    ULONG          r;
    PVOID         Buff;
    LARGE_INTEGER Offset;
    CHAR          Name[7];
    
    Clusters = GetFileClusters(lpSrcName, &ClusterSize, &ClCount, &FileSize);

    if (Clusters)
    {
        Name[0] = '\\';
        Name[1] = '\\';
        Name[2] = '.';
        Name[3] = '\\';
        Name[4] = lpSrcName[0];
        Name[5] = ':';
        Name[6] = 0;

        hDrive = CreateFile(Name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);

        if (hDrive != INVALID_HANDLE_VALUE)
        {

            Buff = malloc(ClusterSize);

            for (r = 0; r < ClCount; r++, FileSize -= BlockSize)
            {
                Offset.QuadPart = ClusterSize * Clusters[r];

                SetFilePointer(hDrive, Offset.LowPart, &Offset.HighPart, FILE_BEGIN);

                ReadFile(hDrive, Buff, ClusterSize, &Bytes, NULL);

                BlockSize = FileSize < ClusterSize ? FileSize : ClusterSize;

            }

            free(Buff);

            CloseHandle(hDrive);
        }
        free(Clusters);
    }
}


void main()
{
      Read("c:\\windows\\system32\\comctl32.dll");
}

分析:

GetFileClusters 函数用于获取文件占用的簇列表,以及每个簇占用字节数,文件占用的簇数,文件大小等信息。这个函数中需要解释的一句就是

     for (CnCount = (ULONG)(OutBuf->Extents[r].NextVcn.QuadPart - PrevVCN.QuadPart);
                     CnCount; CnCount--, Cls++, Lcn.QuadPart++) 
       Clusters[Cls] = Lcn.QuadPart;

这句循环用于生成簇列表。其中循环中的这一句是

CnCount = (ULONG)(OutBuf->Extents[r].NextVcn.QuadPart - PrevVCN.QuadPart);

看msdn中的解释:红色部分就是说明了这句的含义。

RETRIEVAL_POINTERS_BUFFER

The RETRIEVAL_POINTERS_BUFFER structure is the output buffer for the control code.


typedef struct RETRIEVAL_POINTERS_BUFFER {
DWORD ExtentCount;
LARGE_INTEGER StartingVcn;
struct {
LARGE_INTEGER NextVcn;
LARGE_INTEGER Lcn;
} Extents[1];} RETRIEVAL_POINTERS_BUFFER, 
*PRETRIEVAL_POINTERS_BUFFER; Members
ExtentCount 
Count of elements in the Extents array. 
StartingVcn 
Starting VCN returned by the function call. This is not necessarily the VCN requested by the function call, as the file system driver may round down to the first VCN of the extent in which the requested starting VCN is found. 
Extents 
Array of Extents structures. For the number of members in the array, see ExtentCount. Each member of the array has the following members. 
NextVcn 
The VCN at which the next extent begins. This value minus either StartingVcn (for the first Extents array member) or the NextVcn of the previous member of the array (for all other Extents array members) is the length, in clusters, of the current extent. The length is an input to the operation. 
Lcn 
The LCN at which the current extent begins on the volume. This value is an input to the FSCTL_MOVE_FILE operation. On the NTFS file system, the value (LONGLONG) –1 indicates either a compression unit that is partially allocated, or an unallocated region of a sparse file. 


理论:

基本概念就是通过文件句柄获取文件所在的簇列表。然后直接打开硬盘,根据簇所在的位置,直接读取文件数据。

方法1:可以通过打开"\\\\.\\PHYSICALDRIVE0",读取MBR,然后根据MBR中的DPT,找到活动分区的偏移,定位到DBR。然后将要定位簇的文件打开,获取文件句柄,将文件句柄传递给DeviceIoControl的FSCTL_GET_RETRIEVAL_POINTERS功能,就可以得到RETRIEVAL_POINTERS_BUFFER结构。

方法2:直接打开"\\\\.\\c:"就是定位到DBR了。然后跟上面同样的操作。

对于一些基本概念,MBR, DPT,DBR,以及fat32和ntfs的文件结构,可以参考下面的链接了解。

http://www.51stor.net/html/magnetism/200806/17-55.html

代码:(vc6, ntfs) 见光盘DirectAccessFile

 最后,注意一点,文件占用的簇是分组连续的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值