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
最后,注意一点,文件占用的簇是分组连续的。