ZwReadFile失败,异常代码0xC0000005,求指点

哈尔滨-猫猫 2014-01-02 09:53:55
首先,我HOOK了SSDT的ZwReadFile函数,替换为我的_ZwReadFile,实现对系统所有进程读文件操作的过滤目的。当检测当前进程为w3wp.exe或者为ReadFileTest.exe(由于我获取进程名只获取到16个字节,所以少获取了一个'e',判断时,使用了ReadFileTest.ex)进程时,将判断这两个进程读的文件头10个字节,是否为我指定的内容,如果是,则执行相关解密操作。

其次,在进程进入我的_ZwReadFile时,是可以正常读取文件内容的,然后我想判断一下此次读的文件的头10个字节是否为我指定的内容,由于刚刚已经读到了文件结尾,下一次读时需要将文件位置设置为0,以便再次从文件头中读取文件头10个字节的内容。

于是,有如下代码:
bool IsEncrypt(HANDLE FileHandle)
{
IO_STATUS_BLOCK ioStatus;
ULONG dwReaded = 0;
FILE_POSITION_INFORMATION current_fpi;
FILE_POSITION_INFORMATION fpi;
NTSTATUS status;

InterlockedIncrement(&g_uCount);
//获取当前文件位置信息,以便读取文件头后,恢复当前文件指针位置
status = ZwQueryInformationFile(FileHandle, &ioStatus, ¤t_fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
DbgPrint("%ld", current_fpi.CurrentByteOffset);
if (NT_SUCCESS(status))
{
DbgPrint("ZwQueryInformationFile successful");
}
else
{
DbgPrint("ZwQueryInformationFile failed");
}

//移动文件指针位置到文件头部
fpi.CurrentByteOffset.QuadPart = 0i64;
DbgPrint("%ld", fpi.CurrentByteOffset);
//设置文件指针位置信息
status = ZwSetInformationFile(FileHandle, &ioStatus, &fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
if (NT_SUCCESS(status))
{
DbgPrint("ZwSetInformationFile successful");
}
else
{
DbgPrint("ZwSetInformationFile failed");
}

char *szFileHeader = (char*)ExAllocatePool(NonPagedPool, 10);
ULONG length = 10;

NTSTATUS status1 = g_pfnZwReadFile(
FileHandle,
NULL,
NULL,
NULL,
&ioStatus,
szFileHeader,
length,
NULL,
NULL);
if (NT_SUCCESS(status1))
{
DbgPrint("Read File Header successful");
}
else
{
//此处将会被执行,读取文件失败。。。
DbgPrint("Read File Header failed : %d, %d, %d", status1, ioStatus.Status, ioStatus.Information);
}

//恢复文件指针位置
ZwSetInformationFile(FileHandle, &ioStatus, ¤t_fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
InterlockedDecrement(&g_uCount);

DbgPrint("FileHeader : %s", szFileHeader);
if (!strcmp(szFileHeader, "QQ:7278449"))
{
return TRUE;
}
ExFreePool(szFileHeader);
return FALSE;
}



NTSTATUS NTAPI _ZwReadFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL
)
{
NTSTATUS status;
char szProcessName[256] = {0};
GetProcessName((ULONG)PsGetCurrentProcessId(), szProcessName);

InterlockedIncrement(&g_uCount);
status = g_pfnZwReadFile(
FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
Buffer,
Length,
ByteOffset,
Key);
InterlockedDecrement(&g_uCount);

if (!strcmp(szProcessName, "w3wp.exe") || !strcmp(szProcessName, "ReadFileTest.ex"))
{
DbgPrint("Current Process Name : %s", szProcessName);
DbgPrint("%s", Buffer);
if (IsEncrypt(FileHandle))
{
DbgPrint("the file is encrypt!!!");
Decrypt((char*)Buffer, Length);
}
}

return status;
}

注:g_pfnZwReadFile为HOOK后,原ZwReadFile函数的指针。
经过一周时间windbg调试+DebugView,也没能找出读文件失败原因,还请大神指点,表示感谢!
可用分全部奉上....
...全文
645 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
liutingting2020 2014-07-18
  • 打赏
  • 举报
回复
可以给我发一个源码吗?就发上面那个QQ就好啦。谢谢哦。
liutingting2020 2014-07-18
  • 打赏
  • 举报
回复
亲,你是不是对文件进行防护啊。我现在也在做这方面。还想多和你交流。我的QQ:865213875
zgcbj 2014-01-08
  • 打赏
  • 举报
回复
楼主,该结帖啦
哈尔滨-猫猫 2014-01-03
  • 打赏
  • 举报
回复
1.如何判断用户的ReadFile是我想要过滤的文件? 2.如果用户层只调用了CreateFile 而之后没有进行读操作呢? 3.假如打开文件时,我判断文件是否是加密的,那我保存什么呢? 文件路径:我不是所有进程读这个文件,都要给解密 文件句柄:那如果上层应用读一个文件的时候,用了两次以上CreateFile呢? 还有很多未知问题,因为我的目的是过滤一下某些进程读文件操作,而去hook 离其较远的CreateFile,中间n多问题的。
哈尔滨-猫猫 2014-01-03
  • 打赏
  • 举报
回复
g_pfnZwReadFile是原ZwReadFile的函数指针 Hook ZwReadFile的时候,要保存原函数的入口地址啊,以便于驱动卸载时恢复ssdt~ 如果Hook CreateFile会有很多问题,如:
hahayezhe112 2014-01-03
  • 打赏
  • 举报
回复
g_pfnZwReadFile 里面是什么?文件指针吗,指向读函数? 你已经Hook了ZwReadFile,怎么去调用读函数呢? 我觉得你的思路是否可以改下,改成hook打开文件的函数,在打开文件之前根据路径打开一次,读取前10个字节去判断。
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
LARGE_INTEGER li; li.QuadPart = 0i64; 然后把&li传进去 实现从头读文件 但是效果还是不行,读文件依然失败,同样的错误。 解释一下哈,用qq用习惯了,总是习惯用 ctrl+enter换行,,,蛋碎了,又不小心按错
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
不读不行啊,我HOOK了ZwReadFile,我最起码应该保证上层所有读操作能正常进行下去,否则上层很容易蹦掉或者卡死的。 话说DDK帮助里 我也研究了一下这个ByteOffset,也尝试了,貌似给这个值NULL,使用的应该是当前文件指针位置,也就有了我保存当前位置,又恢复当前位置的操作。 另外,根据文档,也可以这里直接传递一个PLARGE_INTEGER 大整数指针过去,可以指定文件指针位置,类似如下代码:
zgcbj 2014-01-02
  • 打赏
  • 举报
回复
你这一句话两层楼,是为了顶帖子么?好少年啊。 不过,能不能判断 IN PLARGE_INTEGER ByteOffset OPTIONAL 倒数第二个参数,判断位置,如果位置是开头,就读,不是开头就不读。 如果你要求,别管多少次ReadFile,都要判断最开始几个字节,那估计就得像你这样做了。
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
这样分多次读取一个文件的情况,从第二次ReadFile开始 缓冲区里就不会包含有该文件的头信息了 所以我在IsEncrypt里 特意去读的文件头
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
但,如果上层应用,读一个文件是调用两次以上ReadFile呢?
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
嗯,一开始我也是像你这么想。但是有一种情况,这样不行。 比如上层应用读一个文件,只调用了一次ReadFile就把整个文件读取了,你说的方法,没有问题。
zgcbj 2014-01-02
  • 打赏
  • 举报
回复
你在 _ZwReadFile的开头是不是已经读到了,为什么又去 IsEncrypt(FileHandle)这里面再读一遍?直接拿buff里面的比不行吗?我不懂了。
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
其他人说内核少用栈空间,于是才改的。但问题依旧,应该不是这里的问题(已调试验证过)
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
char buffer[11] = {0};
哈尔滨-猫猫 2014-01-02
  • 打赏
  • 举报
回复
这里调试了,成功。本来没用堆内存,用的栈上的缓冲区,如下
zgcbj 2014-01-02
  • 打赏
  • 举报
回复
char *szFileHeader = (char*)ExAllocatePool(NonPagedPool, 10); 这个怎么没看到检查成功失败呢?

21,618

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧