首页 > 系统 > Linux >

深入理解 ZwCreateFile

2017-04-12

深入理解 ZwCreateFile,这个文章我没有过多的写什么东西,因为很多东西都文档化了,只需要我们认真而且真正从本质上串一遍,完全的理解了它就可以了!

深入理解 ZwCreateFile,这个文章我没有过多的写什么东西,因为很多东西都文档化了,只需要我们认真而且真正从本质上串一遍,完全的理解了它就可以了!而且有些东西也没有必 要再写了,比如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_opt PLARGE_INTEGER AllocationSize,
In ULONG FileAttributes,
In ULONG ShareAccess,
In ULONG CreateDisposition,
In ULONG CreateOptions,
In_reads_bytes_opt(EaLength) PVOID EaBuffer,
In ULONG EaLength
);

参数理解:
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;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
这个结构是针对很多对象的,不光是针对文件对象的,所以OBJ_PERMANENT(永久), OBJ_EXCLUSIVE(互斥)和OBJ_OPENLINK这三个实际上对于文件对象来说始终是无效的,为什么?
不能设置那三个,那可以设置些什么呢?呼呼

AllocationSize—这是个可选的参数,他是指定初始化文件需要的内存字节数的,所以可向而知,他只有在真正的涉及到文件创建的时候才有意义,也就是说创建,重写,替换这些操作的时候。指向一个typedef union _LARGE_INTEGER {
struct {
ULONG LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct {
ULONG LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_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了,怎么绕过什么了,怎么投机了一下过了什么保护了,其实从个人需求来看,确实是一个突破,若从全局来看,根本是牵一发不动全身的!

相关文章
最新文章
热点推荐