深入理解 ZwCreateFile

前言:

任何编码的东西必须充分的了解规则!

我试探性的搜索了下关于这个native api的相关的问题,很郁闷的发现,这些问题90%都是没有真正理解了这个函数导致的!

有的人连函数干嘛的都不知道就着急的写驱动,真是不可一世!所谓兼收并蓄为的是厚积薄发,其间如履薄冰。说的很贴切!

对此我一直支持achills师傅的思想!搞明白了最基本的和必须的东西,一切后续的东西迎刃而解!

这个文章我没有过多的写什么东西,因为很多东西都文档化了,只需要我们认真而且真正从本质上串一遍,完全的理解了它就可以了!而且有些东西也没有必 要再写了,比如HOOK SSDT inline hook等,现在缺的不是怎么实现一个代码的流程,缺的是两个东西:一个是思路,一个是准确性。

原型:

NTSYSAPI
NTSTATUS
NTAPI
ZwCreateFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);

参数理解:
OUT-
FileHandle--------这是一个指向一个变量的指针,用来最后存放file object handle的
IoStatusBlock-----这个也是个指针变量,指向一个叫做IO_STATUS_BLOCK的结构体,最后函数返回的时候,这个结构体的成员 里面要填充一些值,具体的呢就是完成状态,请求操作的一些信息,最重要的一个成员就是Information成员,他显示了函数对文件的处理方式,他的值 可能是下面的几个:
FILE_SUPERSEDED(替代)
FILE_OPENED(打开)
FILE_CREATED(创建)
FILE_OVERWRITTEN(重写)
FILE_EXISTS(存在)
FILE_DOES_NOT_EXIST(文件不存在)

再看下这个IO_STATUS_BLOCK的具体结构:
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
} DUMMYUNIONNAME;

ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

通过上述的两个输出的参数我们可以看到,这个ZwCreateFile函数就是返回创建好的文件对象的句柄,然后返回一个期间处理的方式。

IN-
DesiredAccess----这个参数指定一个访问权限,大概有以下的权限:
FILE_ANY_ACCESS 0x0000 // any type
FILE_READ_ACCESS 0x0001 // file & pipe
FILE_READ_DATA 0x0001 // file & pipe
FILE_LIST_DIRECTORY 0x0001 // directory
FILE_WRITE_ACCESS 0x0002 // file & pipe
FILE_WRITE_DATA 0x0002 // file & pipe
FILE_ADD_FILE 0x0002 // directory
FILE_APPEND_DATA 0x0004 // file
FILE_ADD_SUBDIRECTORY 0x0004 // directory
FILE_CREATE_PIPE_INSTANCE 0x0004 // named pipe
FILE_READ_EA 0x0008 // file & directory
FILE_WRITE_EA 0x0010 // file & directory
FILE_EXECUTE 0x0020 // file
FILE_TRAVERSE 0x0020 // directory
FILE_DELETE_CHILD 0x0040 // directory
FILE_READ_ATTRIBUTES 0x0080 // all types
FILE_WRITE_ATTRIBUTES 0x0100 // all types
FILE_ALL_ACCESS // All of the preceding +
STANDARD_RIGHTS_ALL
最后一个权限最大
这里面要注意的是范围问题,有的值只适合目录,有的只适合管道,有的只适合命名管道,有的同时适用,想下这个地方可以做什么文章

ObjectAttributes---指向下面这个结构的一个变量,就是来表明文件对象的属性的。
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; /* type SECURITY_DESCRIPTOR */
PVOID SecurityQualityOfService; /* type SECURITY_QUALITY_OF_SERVICE */
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
这个结构是针对很多对象的,不光是针对文件对象的,所以OBJ_PERMANENT(永久), OBJ_EXCLUSIVE(互斥),
and OBJ_OPENLINK这三个实际上对于文件对象来说始终是无效的,为什么?
不能设置那三个,那可以设置些什么呢?呼呼


AllocationSize---这是个可选的参数,他是指定初始化文件需要的内存字节数的,所以可向而知,他只有在真正的涉及到文件创建的时候才有意义,也就是说创建,重写,替换这些操作的时候。指向一个LARGE_INTEGER:
typedef union _LARGE_INTEGER {
_ANONYMOUS_STRUCT struct
{
ULONG LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct
{
ULONG LowPart;
LONG HighPart;
} u;
#endif //MIDL_PASS
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
这个结构体在内核结构里面很常见,呼呼,,支持到64位,看情况设置。不过我至今没有明白QuadPart这个是干嘛的!

FileAttributes---这个参数指定文件的属性,刚才是文件对象的属性。可以是以下的:
FILE_ATTRIBUTE_READONLY
FILE_ATTRIBUTE_HIDDEN
FILE_ATTRIBUTE_SYSTEM
FILE_ATTRIBUTE_DIRECTORY
FILE_ATTRIBUTE_ARCHIVE
FILE_ATTRIBUTE_NORMAL
FILE_ATTRIBUTE_TEMPORARY
FILE_ATTRIBUTE_SPARSE_FILE
FILE_ATTRIBUTE_REPARSE_POINT
FILE_ATTRIBUTE_COMPRESSED
FILE_ATTRIBUTE_OFFLINE
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
FILE_ATTRIBUTE_ENCRYPTED

ShareAccess---指定共享的权限,以下三种的组合:
FILE_SHARE_READ
FILE_SHARE_WRITE
FILE_SHARE_DELETE

CreateDisposition---这个参数指定要对文件干嘛,呼呼,可以是下面的值:
FILE_SUPERSEDE
FILE_OPEN
FILE_CREATE
FILE_OPEN_IF
FILE_OVERWRITE
FILE_OVERWRITE_IF


CreateOptions---这个参数指定创建或者打开文件的时候做的一些事情,可以是以下的组合:
FILE_DIRECTORY_FILE
FILE_WRITE_THROUGH
FILE_SEQUENTIAL_ONLY
FILE_NO_INTERMEDIATE_BUFFERING
FILE_SYNCHRONOUS_IO_ALERT
FILE_SYNCHRONOUS_IO_NONALERT
FILE_NON_DIRECTORY_FILE
FILE_CREATE_TREE_CONNECTION
FILE_COMPLETE_IF_OPLOCKED
FILE_NO_EA_KNOWLEDGE
FILE_OPEN_FOR_RECOVERY
FILE_RANDOM_ACCESS
FILE_DELETE_ON_CLOSE
FILE_OPEN_BY_FILE_ID
FILE_OPEN_FOR_BACKUP_INTENT
FILE_NO_COMPRESSION
FILE_RESERVE_OPFILTER
FILE_OPEN_REPARSE_POINT
FILE_OPEN_NO_RECALL
FILE_OPEN_FOR_FREE_SPACE_QUERY
这个我不太清楚,概念有点模糊

EaBuffer---这个是个可选的参数,用来存放一些扩展的属性
EaLength---存放扩展属性的字节大小
有个疑问,这个扩展属性什么时候用呢?(TDI里面常用这个)

更详细的参数的理解参考
http://xiaomaier.bokee.com/3439967.html

返回值理解:
如果成功,返回STATUS_SUCCESS
如果失败,返回
STATUS_ACCESS_DENIED,
STATUS_OBJECT_NAME_NOT_FOUND, STATUS_OBJECT_NAME_COLLISION,
STATUS_OBJECT_NAME_INVALID, STATUS_SHARING_VIOLATION, STATUS_NOT_A_DIRECTORY, or
STATUS_FILE_IS_A_DIRECTORY.

说明:
1.与这个native api相关的r3api是CreateFile
2.DDK里面对这个函数有详细的说明


扩展:
1.与CreateFile这个api的异同。
同:
(1)功能基本相同,都是可以打开或者创建一个文件对象,包括文件,磁盘,卷,管道,串口,油槽等
(2)都是返回一个文件句柄
异:
(1)在vista及以上的版本,CreateFile做了扩展,加上了事务性文件系统
HANDLE WINAPI CreateFileTransacted(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile,
__in HANDLE hTransaction,
__in_opt PUSHORT pusMiniVersion,
PVOID pExtendedParameter
);

但是ZwCreateFile还是那样
(2)HANDLE WINAPI CreateFile(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,//
__in LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in HANDLE hTemplateFile
);
NTSYSAPI
NTSTATUS
NTAPI
ZwCreateFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,///
IN ULONG CreateDisposition,//
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);

2.内核里与ZwCreateFile功能相似的还有一个函数IoCreateFile
NTSTATUS IoCreateFile
(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL, I
N ULONG EaLength,
IN CREATE_FILE_TYPE CreateFileType,
IN PVOID ExtraCreateParameters OPTIONAL,
IN ULONG Options
) ;
windbg看下,其实ZwCreateFile内部调用了IoCreateFile

至于这两个函数的区别可以参考combojiang的http://hi.baidu.com/combojiang/blog/item/cd6269de55ce235eccbf1adb.html

IoCreateFile内部还调用了一个allmul函数,这个函数是用来做int64的移位的,具体的参考
http://hi.baidu.com/combojiang/blog/item/29411c5c6841ae45fbf2c088.html

据说IoCreateFile函数更优良一些,IceSword就调用了这个函数来打开ntoskrnl。exe的

3.hook ZwCreateFile是很简单的,,hook SSDT就可以了!考虑个问题:
ZwCreateFile是创建文件的,那么如果我们hook之后比如函数变成了my_ZwCreateFile(),这个时候我们还想调用ZwCreateFile创建文件的话,就会出错,还想再创建文件,怎么办?
这个得做个线程模式的切换。
详细的可以参考http://www.cnblogs.com/jokerfox/archive/2009/04/14/1435819.html

4.ZwCreateFile是运行在PASSIVE_LEVEL上的。那么比如要调用这个函数的程序必须运行在DISPATCH_LEVEL呢?怎么调用?
http://xuyingpin.blogbus.com/logs/10845127.html
http://xuyingpin.blogbus.com/logs/11152569.html


最简单的使用方法:
BOOL testCreateFile(IN PUNICODE_STRING filename)
{
HANDLE hFile=NULL;
NTSTATUS status;
IO_STATUS_BLOCK isb;
OBJECT_ATTRIBUTES oa;

InitializeObjectAttributes(&oa,filename,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);

status=ZwCreateFile(&hFile,GENERIC_ALL,&oa,&isb,NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,FILE_CREATE,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,NULL,0);

if(NT_SUCCESS(status))
{
status=STATUS_SUCCESS;
}
else
{
status=isb.Status;
}

DbgPrint("hFile=%08X",hFile);

if(hFile)
{
ZwClose(hFile);
}
return status;

hook ZwCreateFile的思路:
1.hook SSDT
NTSTATUS NewZwCreateFile(OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength) {
NTSTATUS ntS = (NTSTATUS) NULL;

DbgPrint("ZwCreateFile called\n");


ntS = ((ZWCREATEFILE)(OldZwCreateFile)) (
FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatusBlock,
AllocationSize,
FileAttributes,
ShareAccess,
CreateDisposition,
CreateOptions,
EaBuffer,
EaLength);
return(ntS);
}
http://dev.csdn.net/article/36/36751.shtm
http://www.zeroplace.cn/article.asp?id=138

2.通过调试寄存器hook
http://www.xfocus.net/articles/200709/950.html

3.inline hook
http://hackbase.com/tech/2009-05-11/52690.html系列


总结:
我们站在一个稍微高的地方来看一些东西

任何用户态或核心态的函数CreateFile或者内核态的ZwCreateFile等都是为了获得handle,为进一步的访问做准备。而在获得 handle的过程中,调用者需要提供DesiredAccess和ShareAccess等选项。如果文件已经被另一个调用者以排他方式打开,这时候的 访问就会失败。

那么我们可以这么想一个问题,如果我们精通一种验证机制,或者说构造一种验证机制的话,那么访问不需要这么复杂就可以实现,这就是邪恶的绕过技术!那么针对我刚才说的话,具体的可以参考这么几种技术:

搜索句柄表,关闭句柄
DKOM
区域映射
I/O

我还不清楚这里面的研究空间有多大,反正我见好多人都是怎么xx了,怎么绕过什么了,怎么投机了一下过了什么保护了,其实从个人需求来看,确实是一个突破,若从全局来看,根本是牵一发不动全身的!


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
(此资源来自网络,本人不负任何责任) 易 游等等的虚拟还原功能都是用这开发的 一 安装和使用方法: 1 安装:看install.txt文件; 2 挂载:filedisk /mount 0 c:\proj\myfiledisk\a.img e: 3 卸载:filedisk /umount e: 详细看example.txt文件,在本站的下载中心有下载,包括核心层和应用层的源码。 最多可以同时挂4个设备,分别定义4个设备号,如果同一设备号使用2次,会进入OPEN_FILE两次,出现"FileDisk: IOCTL_FILE_DISK_OPEN_FILE: Media already opened\n"的错误提示; 二 基本知识: 1 关于DefineDosDevice函数: 在应用层开发中调用它来创建一个\??目录下的符号链接,如: BOOL okay = DefineDosDevice(DDD_RAW_TARGET_PATH, "test", "\\Device\\FileDisk0"); 调用成功后,将会在设备命名空间的\??目录下生成一个名为”test“的符号链接,该链接指向”“\\Device\\FileDisk0“这个对象。 而在核心态的驱动程序中,需要调用以下的函数来创建相应的符号链接: IoCreateSymbolicLink(linkname, targname); Linkname是要创建的符号链接名,相当于上面函数中的”test”,targname是该链接指向的设备对象。 2 filedisk的源映像可以是img,iso,flp等,这些都是磁盘上一个分区的平面映像,所以挂上后可以直接访问,但不能是整个硬盘的img映像或其它格式如rar等; 3 filedisk的源映像文件名称必须是全路径,即使是在当前目录下也必须是全路径; 4 源映像文件如果不存在且参数中没有指定只读,那么只要在参数中指定了大小则会主动创建它,使用前会提示先“格式化”,之后就可正常使用了; 三 核心层源码分析: 1 DriverEntry: 主函数入口;备份传入路径,查询注册表值,调用ZwCreateDirectoryObject创建设备目录,重复4次调用 FileDiskCreateDevice创建设备,初始化操作函数指针。 2 FileDiskCreateDevice:调用IoCreateDevice创建设备,KeInitializeEvent初始化事件对象,PsCreateSystemThread创建内核线程,入口函数是FileDiskThread,传入的函数参数为IoCreateDevice返回的设备对象。 3 FileDiskThread:首先调用KeSetPriorityThread更改自身线程的优先级为LOW_REALTIME_PRIORITY,然后开始for(;;),调用KeWaitForSingleObject函数等待事件对象有信号,如果等到,判断事件类型,有如下几种: IRP_MJ_READ:调用ZwReadFile读取文件,从内核到用户缓冲区; IRP_MJ_WRITE:调用ZwWriteFile写入文件,从用户到内核缓冲区; IRP_MJ_DEVICE_CONTROL:在FileDiskDeviceControl设置事件才会触发,主要有如下两种操作码: IOCTL_FILE_DISK_OPEN_FILE:调用FileDiskOpenFile。 IOCTL_FILE_DISK_CLOSE_FILE:调用FileDiskCloseFileFileDiskOpenFile:根据用户程序传入的映像文件全路径,调用ZwCreateFile在内核中打开它,如果文件不存在则再创建它,返回文件句柄。 FileDiskCloseFile:调用ZwClose关闭文件。 4 FileDiskCreateClose: 仅返回成功;对应Create,Close操作。 5 FileDiskReadWrite:将IO包插入队列,然后调用KeSetEvent函数,激活事件对象;对应Read,Write操作。 6 FileDiskDeviceControl:用户程序调用DeviceIoControl的响应函数,主要有如下两种操作: IOCTL_FILE_DISK_OPEN_FILE:设置好参数,将IO包插入队列,设置对象为有信号。 IOCTL_FILE_DISK_CLOSE_FILE:将IO包插入队列,设置对象为有信号。 其它的操作类型因为输入输出共用一个缓冲区,所以都采用系统默认处理,设置好需要输出的参数后,就直接从这个函数返回了。如: IOCTL_DISK_GET_DRIVE_GEOMETRY,IOCTL_CDROM_GET_DRIVE_GEOMETRY等; 7 有4种操作是自定义的:FileDiskReadWrite函数两种,FileDiskDeviceControl函数两种,对应的操作码分别是: IRP_MJ_READ,IRP_MJ_WRITE,IOCTL_FILE_DISK_OPEN_FILE,IOCTL_FILE_DISK_CLOSE_FILE这4种,在FileDiskThread中等待这4种事件发生,如果等到,就调用相应的函数处理。 四 应用层源码分析: 1 mount:调用DefineDosDevice在应用层创建一个指向设备命名空间的符号链接,用CreateFile打开此链接,然后调用DeviceIoControl,控制码是IOCTL_FILE_DISK_OPEN_FILE,内核程序响应后,执行真正打开源映像文件的操作。 2 umount: 上面大致一样,只是多一些步骤,不同的是控制码改为IOCTL_FILE_DISK_CLOSE_FILE,之后必须发送FSCTL_DISMOUNT_VOLUME

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值