打开被独占的文件方法(三) -- 使用直接硬盘访问读取文件

打开被独占的文件方法(三) -- 使用直接硬盘访问读取文件
2010年06月08日 星期二 11:41


使用直接硬盘访问读取文件
“直接访问硬盘”这个想法当然很酷,但很快DOS编程爱好者们就会失望,这里没有硬件操作,因为微软很关心我们的疾苦,提供了方便简单的API,通过这些API可以几乎“直接地”操作硬盘。这样大家就明白了吧,实际上我们是想以RAW模式打开volume,并按cluster来读取文件。希望大家没有被吓到:)
如果直接入手解决这个问题,就需要手动地分析文件系统结构,这样我们就需要编写很多多余的代码,所以我们不会这样去做,而是再一次参考微软伟大的手册――MSDN。"Defragmenting
Files "和"Disk Management Control
Codes"部分对于我们来说非常有用,那里面有文件系统驱动的控制代码,这些代码可以用在各种磁盘整理程序中。打开MSDN,无疑会发现,使用IOCTL代码FSCTL_GET_RETRIEVAL_POINTERS可以获取文件分配图。也就是说我们只需要借助于这个IOCTL就可以获取被占用文件的cluster
list并进行读取。
用此代码调用DeviceIoControl时,InputBuffer应该包含有STARTING_VCN_INPUT_BUFFER结构体,这个结构体描述了文件cluster链的首元素,函数成功执行后,OutputBuffer将装有RETRIEVAL_POINTERS_BUFFER结构体,这个结构体描述了分配图。我们来详细地看一下这个结构体:
typedef struct
{
LARGE_INTEGER StartingVcn;
} STARTING_VCN_INPUT_BUFFER, *PSTARTING_VCN_INPUT_BUFFER;
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;
第一个结构体很容易懂,我们只需要向StartingVcn.QuadPart传递0,而第二个结构体的格式需要好好研究一下。第一个域(ExtentCount)包含着结构体中Extents元素的数目。StartingVcn文件第一个cluster链的链号。每一个Extents元素都包含有一个NextVcn,其含有链中cluser的数目,而Lcn――其第一个cluster的cluster号。也就是说所返回的信息就是cluster链的描述符,其中每一个链都包含有某些个cluster。
现在返回信息的结构体的含义就已经明了了,到了编写函数的时候了,这个函数获取文件完整的cluster list并将其整理为数组形式。
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;
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 = 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 = malloc(*ClCount * sizeof(ULONGLONG));
PrevVCN = OutBuf->StartingVcn;
for (r = 0, Cls = 0; r < OutBuf->ExtentCount; r++)
{
Lcn = OutBuf->Extents[r].Lcn;
for (CnCount = 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;
}
函数完成后我们就得到了描述文件clusters的数组以及clusters的数目,现在可以很容易地拷贝文件了:
void FileCopy(
PCHAR lpSrcName,
PCHAR lpDstName
)
{
ULONG ClusterSize, BlockSize;
ULONGLONG *Clusters;
ULONG ClCount, FileSize, Bytes;
HANDLE hDrive, hFile;
ULONG SecPerCl, BtPerSec, r;
PVOID Buff;
LARGE_INTEGER Offset;
CHAR Name[7];

Name[0] = lpSrcName[0];
Name[1] = ':';
Name[2] = 0;
GetDiskFreeSpace(Name, &SecPerCl, &BtPerSec, NULL, NULL);
ClusterSize = SecPerCl * BtPerSec;

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)
{
hFile = CreateFile(lpDstName, GENERIC_WRITE, 0, NULL,
CREATE_NEW, 0, 0);
if (hFile != 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;
WriteFile(hFile, Buff, BlockSize, &Bytes, NULL);
}
free(Buff);
CloseHandle(hFile);
}
CloseHandle(hDrive);
}
free(Clusters);
}
}
文章到这里其实就结束了,现在要拷贝SAM简直易如反掌:)。在配套的示例中有将SAM拷贝到命令行指定的文件中的代码。
无疑,这种方法形式简单而功能强大,但遗憾的是它有着本质上的缺陷。这种方法只能用来读取以FILE_READ_ATTRIBUTES属性打开的文件,文件不能压缩,不能加密,而且应该有自己的cluster(在NTFS下小文件可以整个放在MFT里)。同时要考虑到,在读取文件时文件可能被修改。
我想,如何与底层文件系统打交道大家都已经明白了。这个方法为rootkit提供了诸多的便利。系统里有保护文件不被修改的程序(比如说反病毒软件),但是拥有了以RAW模式打开volume的权限之后,这些就形同虚设。再有,好的管理员会在自己的server上将重要文件的读写记录入日志文件,而直接访问是逃不过日志记录的。要实现对文件的完全访问就不得不编写自己的NTFS驱动了。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值