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

[复制链接]
查看11 | 回复10 | 2021-1-27 05:57:48 | 显示全部楼层 |阅读模式
首先,我HOOK了SSDT的ZwReadFile函数,替换为我的_ZwReadFile,实现对系统所有进程读文件操作的过滤目的。当检测当前进程为w3wp.exe或者为ReadFileTest.exe(由于我获取进程名只获取到16个字节,所以少获取了一个'e',判断时,使用了ReadFileTest.ex)进程时,将判断这两个进程读的文件头10个字节,是否为我指定的内容,如果是,则执行相关解密操作。
其次,在进程进入我的_ZwReadFile时,是可以正常读取文件内容的,然后我想判断一下此次读的文件的头10个字节是否为我指定的内容,由于刚刚已经读到了文件结尾,下一次读时需要将文件位置设置为0,以便再次从文件头中读取文件头10个字节的内容。
于是,有如下代码:
boolIsEncrypt(HANDLEFileHandle)
{
IO_STATUS_BLOCKioStatus;
ULONGdwReaded=0;
FILE_POSITION_INFORMATIONcurrent_fpi;
FILE_POSITION_INFORMATIONfpi;
NTSTATUSstatus;
InterlockedIncrement(&g_uCount);
//获取当前文件位置信息,以便读取文件头后,恢复当前文件指针位置
status=ZwQueryInformationFile(FileHandle,&ioStatus,&current_fpi,sizeof(FILE_POSITION_INFORMATION),FilePositionInformation);
DbgPrint("%ld",current_fpi.CurrentByteOffset);
if(NT_SUCCESS(status))
{
DbgPrint("ZwQueryInformationFilesuccessful");
}
else
{
DbgPrint("ZwQueryInformationFilefailed");
}
//移动文件指针位置到文件头部
fpi.CurrentByteOffset.QuadPart=0i64;
DbgPrint("%ld",fpi.CurrentByteOffset);
//设置文件指针位置信息
status=ZwSetInformationFile(FileHandle,&ioStatus,&fpi,sizeof(FILE_POSITION_INFORMATION),FilePositionInformation);
if(NT_SUCCESS(status))
{
DbgPrint("ZwSetInformationFilesuccessful");
}
else
{
DbgPrint("ZwSetInformationFilefailed");
}
char*szFileHeader=(char*)ExAllocatePool(NonPagedPool,10);
ULONGlength=10;
NTSTATUSstatus1=g_pfnZwReadFile(
FileHandle,
NULL,
NULL,
NULL,
&ioStatus,
szFileHeader,
length,
NULL,
NULL);
if(NT_SUCCESS(status1))
{
DbgPrint("ReadFileHeadersuccessful");
}
else
{
//此处将会被执行,读取文件失败。。。
DbgPrint("ReadFileHeaderfailed:%d,%d,%d",status1,ioStatus.Status,ioStatus.Information);
}
//恢复文件指针位置
ZwSetInformationFile(FileHandle,&ioStatus,&current_fpi,sizeof(FILE_POSITION_INFORMATION),FilePositionInformation);
InterlockedDecrement(&g_uCount);
DbgPrint("FileHeader:%s",szFileHeader);
if(!strcmp(szFileHeader,"QQ:7278449"))
{
returnTRUE;
}
ExFreePool(szFileHeader);
returnFALSE;
}

NTSTATUSNTAPI_ZwReadFile(
INHANDLEFileHandle,
INHANDLEEventOPTIONAL,
INPIO_APC_ROUTINEApcRoutineOPTIONAL,
INPVOIDApcContextOPTIONAL,
OUTPIO_STATUS_BLOCKIoStatusBlock,
OUTPVOIDBuffer,
INULONGLength,
INPLARGE_INTEGERByteOffsetOPTIONAL,
INPULONGKeyOPTIONAL
)
{
NTSTATUSstatus;
charszProcessName[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("CurrentProcessName:%s",szProcessName);
DbgPrint("%s",Buffer);
if(IsEncrypt(FileHandle))
{
DbgPrint("thefileisencrypt!!!");
Decrypt((char*)Buffer,Length);
}
}
returnstatus;
}
注:g_pfnZwReadFile为HOOK后,原ZwReadFile函数的指针。
经过一周时间windbg调试+DebugView,也没能找出读文件失败原因,还请大神指点,表示感谢!
可用分全部奉上....
分 -->
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
char*szFileHeader=(char*)ExAllocatePool(NonPagedPool,10);
这个怎么没看到检查成功失败呢?
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
这里调试了,成功。本来没用堆内存,用的栈上的缓冲区,如下
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
charbuffer[11]={0};
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
其他人说内核少用栈空间,于是才改的。但问题依旧,应该不是这里的问题(已调试验证过)
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
你在_ZwReadFile的开头是不是已经读到了,为什么又去IsEncrypt(FileHandle)这里面再读一遍?直接拿buff里面的比不行吗?我不懂了。
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
嗯,一开始我也是像你这么想。但是有一种情况,这样不行。
比如上层应用读一个文件,只调用了一次ReadFile就把整个文件读取了,你说的方法,没有问题。
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
但,如果上层应用,读一个文件是调用两次以上ReadFile呢?
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
这样分多次读取一个文件的情况,从第二次ReadFile开始
缓冲区里就不会包含有该文件的头信息了
所以我在IsEncrypt里特意去读的文件头
回复

使用道具 举报

千问 | 2021-1-27 05:57:48 | 显示全部楼层
你这一句话两层楼,是为了顶帖子么?好少年啊。
不过,能不能判断INPLARGE_INTEGERByteOffsetOPTIONAL
倒数第二个参数,判断位置,如果位置是开头,就读,不是开头就不读。
如果你要求,别管多少次ReadFile,都要判断最开始几个字节,那估计就得像你这样做了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行