在内核中我们进行文件操作,可以使用
IoCreateFile
也可以用
ZwCreateFile。
但究竟这两者有什么差别呢?下面是这两个函数的格式如下:
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,
IN ULONG EaLength ,
IN CREATE_FILE_TYPE CreateFileType ,
IN PVOID ExtraCreateParameters OPTIONAL,
IN ULONG Options
) ;NTSTATUS
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 );
这两个函数都必须运行在PASSIVE_LEVEL级别上。
1)在 ZwCreateFile 内部调用了 IoCreateFile 。
用ZwCreateFile会导致PREVIOUS MODE成为KERNEL MODE, 从而破坏NT本身的安全检查机制. 而IoCreateFile 不会。 假设你处在用户进程的上下文环境中,如果不指定 Options 为 IO_NO_PARAMETER_CHECKING,IoCreateFile调用会失败,原因是IoCreateFile检查参数,如果发现他在用户模式上下文中,但是创建是内核模式的调用,所以会导致失败。
2)hook ZwCreateFile 比较容易,只要hook ssdt就能简单实现。 IoCreateFile是由 NTOSKRNL.EXE导出的函数。 hook IoCreateFile 要复杂一些 。
当然,你可以在内核中调用ZwCreateFile失败时,可以调用IoCreateFile。下面是这样一个例子。
ReadFileIntoBuffer proc uses ebx esi edi sourceString:dword
local @Handle : dword
local @IoStatusBlock:IO_STATUS_BLOCK
local @ByteOffset:LARGE_INTEGER
local @DestinationString:UNICODE_STRING
local @ObjectAttributes:OBJECT_ATTRIBUTES
local @FileInformation:FILE_STANDARD_INFORMATION
xor eax, eax
xor esi, esi
lea edi, @FileInformation
mov ecx,6
rep stosd
xor eax, eax
mov dword ptr @ByteOffset, esi
lea edi, [@ByteOffset+4]
stosd ; 初始化ByteOffset
call KeGetCurrentIrql
test al, al
jbe short CanCreate
xor eax, eax
jmp Quit
CanCreate:
push sourceString
lea eax, @DestinationString
push eax
call RtlInitUnicodeString ; 将参数传入的宽字符串转换成UNICODE_STRING
push esi ; EaLength
push esi ; EaBuffer
push 60h ; CreateOptions
xor ebx, ebx
inc ebx
push ebx ; CreateDisposition
push ebx ; ShareAccess
lea eax, @DestinationString
mov @ObjectAttributes.ObjectName, eax
mov edi, 80h
push edi ; FileAttributes
push esi ; AllocationSize
lea eax, @IoStatusBlock
push eax ; IoStatusBlock
lea eax, @ObjectAttributes
push eax ; ObjectAttributes
push 100001h ; DesiredAccess
lea eax, @Handle
push eax ; FileHandle
mov @ObjectAttributes._Length, 18h
mov @ObjectAttributes.RootDirectory, esi
mov @ObjectAttributes.Attributes, 240h
mov @ObjectAttributes.SecurityDescriptor, esi
mov @ObjectAttributes.SecurityQualityOfService, esi
call ZwCreateFile
test eax, eax
jge short ZwCreateOk
push 100h ; Options
push esi ; ExtraCreateParameters
push esi ; CreateFileType
push esi ; EaLength
push esi ; EaBuffer
push esi ; CreateOptions
push ebx ; Disposition
push ebx ; ShareAccess
push edi ; FileAttributes
push esi ; AllocationSize
lea eax, @IoStatusBlock
push eax ; IoStatusBlock
lea eax, @ObjectAttributes
push eax ; ObjectAttributes
push edi ; DesiredAccess
lea eax, @Handle
push eax ; FileHandle
call IoCreateFile
test eax, eax
jl short CreateFailed
ZwCreateOk:
push 5 ; FileInformationClass
push 18h ; FileInformationLength
lea eax, @FileInformation
push eax ; FileInformation
lea eax, @IoStatusBlock
push eax ; IoStatusBlock
push @Handle ; FileHandle
call ZwQueryInformationFile
test eax, eax
jl short QueryFailed
lea eax,[@FileInformation + 8]
cmp [eax], esi ; 判断文件长度EndOfFile是否为0
jz short QueryFailed
push 206B6444h ; Tag
push [eax] ; NumberOfBytes
push esi ; PoolType
call ExAllocatePoolWithTag
mov edi, eax
cmp edi, esi
jz short QueryFailed
push esi ; Key
lea eax, @ByteOffset
push eax ; ByteOffset
lea eax,[@FileInformation + 8]
push [eax] ; Length
lea eax, @IoStatusBlock
push edi ; Buffer
push eax ; IoStatusBlock
push esi ; ApcContext
push esi ; ApcRoutine
push esi ; Event
push @Handle ; FileHandle
call ZwReadFile
push @Handle ; Handle
mov ebx, eax
call ZwClose
cmp ebx, esi
jge short ReadOK
push edi
call ExFreePool
jmp short CreateFailed
; ---------------------------------------------------------------------------
ReadOK:
mov eax, edi
jmp short Quit
; ---------------------------------------------------------------------------
QueryFailed:
push @Handle ; Handle
call ZwClose
CreateFailed:
xor eax, eax
Quit :
ret
ReadFileIntoBuffer endp
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,
IN ULONG EaLength ,
IN CREATE_FILE_TYPE CreateFileType ,
IN PVOID ExtraCreateParameters OPTIONAL,
IN ULONG Options
) ;NTSTATUS
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 );
这两个函数都必须运行在PASSIVE_LEVEL级别上。
1)在 ZwCreateFile 内部调用了 IoCreateFile 。
用ZwCreateFile会导致PREVIOUS MODE成为KERNEL MODE, 从而破坏NT本身的安全检查机制. 而IoCreateFile 不会。 假设你处在用户进程的上下文环境中,如果不指定 Options 为 IO_NO_PARAMETER_CHECKING,IoCreateFile调用会失败,原因是IoCreateFile检查参数,如果发现他在用户模式上下文中,但是创建是内核模式的调用,所以会导致失败。
2)hook ZwCreateFile 比较容易,只要hook ssdt就能简单实现。 IoCreateFile是由 NTOSKRNL.EXE导出的函数。 hook IoCreateFile 要复杂一些 。
当然,你可以在内核中调用ZwCreateFile失败时,可以调用IoCreateFile。下面是这样一个例子。
ReadFileIntoBuffer proc uses ebx esi edi sourceString:dword
local @Handle : dword
local @IoStatusBlock:IO_STATUS_BLOCK
local @ByteOffset:LARGE_INTEGER
local @DestinationString:UNICODE_STRING
local @ObjectAttributes:OBJECT_ATTRIBUTES
local @FileInformation:FILE_STANDARD_INFORMATION
xor eax, eax
xor esi, esi
lea edi, @FileInformation
mov ecx,6
rep stosd
xor eax, eax
mov dword ptr @ByteOffset, esi
lea edi, [@ByteOffset+4]
stosd ; 初始化ByteOffset
call KeGetCurrentIrql
test al, al
jbe short CanCreate
xor eax, eax
jmp Quit
CanCreate:
push sourceString
lea eax, @DestinationString
push eax
call RtlInitUnicodeString ; 将参数传入的宽字符串转换成UNICODE_STRING
push esi ; EaLength
push esi ; EaBuffer
push 60h ; CreateOptions
xor ebx, ebx
inc ebx
push ebx ; CreateDisposition
push ebx ; ShareAccess
lea eax, @DestinationString
mov @ObjectAttributes.ObjectName, eax
mov edi, 80h
push edi ; FileAttributes
push esi ; AllocationSize
lea eax, @IoStatusBlock
push eax ; IoStatusBlock
lea eax, @ObjectAttributes
push eax ; ObjectAttributes
push 100001h ; DesiredAccess
lea eax, @Handle
push eax ; FileHandle
mov @ObjectAttributes._Length, 18h
mov @ObjectAttributes.RootDirectory, esi
mov @ObjectAttributes.Attributes, 240h
mov @ObjectAttributes.SecurityDescriptor, esi
mov @ObjectAttributes.SecurityQualityOfService, esi
call ZwCreateFile
test eax, eax
jge short ZwCreateOk
push 100h ; Options
push esi ; ExtraCreateParameters
push esi ; CreateFileType
push esi ; EaLength
push esi ; EaBuffer
push esi ; CreateOptions
push ebx ; Disposition
push ebx ; ShareAccess
push edi ; FileAttributes
push esi ; AllocationSize
lea eax, @IoStatusBlock
push eax ; IoStatusBlock
lea eax, @ObjectAttributes
push eax ; ObjectAttributes
push edi ; DesiredAccess
lea eax, @Handle
push eax ; FileHandle
call IoCreateFile
test eax, eax
jl short CreateFailed
ZwCreateOk:
push 5 ; FileInformationClass
push 18h ; FileInformationLength
lea eax, @FileInformation
push eax ; FileInformation
lea eax, @IoStatusBlock
push eax ; IoStatusBlock
push @Handle ; FileHandle
call ZwQueryInformationFile
test eax, eax
jl short QueryFailed
lea eax,[@FileInformation + 8]
cmp [eax], esi ; 判断文件长度EndOfFile是否为0
jz short QueryFailed
push 206B6444h ; Tag
push [eax] ; NumberOfBytes
push esi ; PoolType
call ExAllocatePoolWithTag
mov edi, eax
cmp edi, esi
jz short QueryFailed
push esi ; Key
lea eax, @ByteOffset
push eax ; ByteOffset
lea eax,[@FileInformation + 8]
push [eax] ; Length
lea eax, @IoStatusBlock
push edi ; Buffer
push eax ; IoStatusBlock
push esi ; ApcContext
push esi ; ApcRoutine
push esi ; Event
push @Handle ; FileHandle
call ZwReadFile
push @Handle ; Handle
mov ebx, eax
call ZwClose
cmp ebx, esi
jge short ReadOK
push edi
call ExFreePool
jmp short CreateFailed
; ---------------------------------------------------------------------------
ReadOK:
mov eax, edi
jmp short Quit
; ---------------------------------------------------------------------------
QueryFailed:
push @Handle ; Handle
call ZwClose
CreateFailed:
xor eax, eax
Quit :
ret
ReadFileIntoBuffer endp