10内核重载

Posted ltyandy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10内核重载相关的知识,希望对你有一定的参考价值。

内核重载需求的产生

在内核中有很多HOOK, 例如:KiFastCallEntry, SSDT,IDT,OBJECT HOOK,甚至是内核API的内联HOOK , 有些HOOK很容易找到,并还原, 有些HOOK就很难找到. 在某些时候(例如一个病毒HOOK了int3中断,这样调试器就无法得到断点事件),清除HOOK是一种反反调试的技术. 也是防护与反防护的技术. —总之内核层的对抗非常的激烈, 为了能够一举将所有的HOOK或者其它防护技术统统屏蔽, 内核重载技术应运而生. 简单来说, 内核重载就是将文件中的内核(ntkrnlpa.exe)重新加载到内存中, 这样一来, 所有对内核中的修改都会被还原.

但是, 直接加载并覆盖到原来的内存的话会产生很多错误,例如, 系统开机之后,会对很多的数据进行初始化, 这些数据被初始化之后系统才能正常运行, 如果直接将内核文件的数据覆盖了,就没有这些数据了. 因此, 可以只将原始内核的代码段加载到内存 , 并通过一些设置, 让原始

内核重载的目标

  1. 破掉所有的KiFastCallEntry HOOK 1.1 替换KiFastCallEntry函数.

  2. 破掉所有SSDT HOOK 2.1 使用新的SSDT表(需要修复非常多的数据)

  3. 破掉所有的Inline HOOK 3.1 直接使用新的内核代码段(需要修复非常非常多的数据)

kernelReload.c

#include <ntifs.h>
#include <ntimage.h>
#include <ntddk.h>
#include "kernelFunction.h"
?
?
////////////////////////////////////////////
///////////// 内核重载相关函数   /////////////
////////////////////////////////////////////
?
// 导入SSDT全局变量
NTSYSAPI SSDTEntry KeServiceDescriptorTable;
static char* g_pNewNtKernel; // 新内核
static ULONG g_ntKernelSize; // 内核的映像大小
static SSDTEntry* g_pNewSSDTEntry; // 新ssdt的入口地址
static ULONG g_hookAddr; // 被hook位置的首地址
static ULONG g_hookAddr_next_ins;// 被hook的指令的下一条指令的首地址.
?
?
// 读取NT内核模块
// 将读取到的缓冲区的内容保存到pBuff中.
NTSTATUS loadNtKernelModule( UNICODE_STRING* ntkernelPath, char** pBuff );
?
// 修复重定位.
void fixRelocation( char* pDosHdr, ULONG curNtKernelBase );
?
// 填充SSDT表
// char* pDos - 新加载的内核堆空间首地址
// char* pCurKernelBase - 当前正在使用的内核的加载基址
void initSSDT( char* pDos, char* pCurKernelBase );
?
// 安装HOOK
void installHook( );
?
// 卸载HOOK
void uninstallHook( );
?
// inline hook KiFastCallEntry的函数
void myKiFastEntryHook( );
?
?
////////////////////////////////////////////
/////////////// 驱动入口函数   //////////////
////////////////////////////////////////////
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath)

NTSTATUS status = STATUS_SUCCESS;
DbgBreakPoint( );

// 1. 找到内核文件路径
// 1.1 通过遍历内核链表的方式来找到内核主模块
LDR_DATA_TABLE_ENTRY* pLdr = ((LDR_DATA_TABLE_ENTRY*)pDriver->DriverSection);
// 1.2 内核主模块在链表中的第2项.
for(int i =0;i<2;++i)
pLdr = (LDR_DATA_TABLE_ENTRY*)pLdr->InLoadOrderLinks.Flink;

g_ntKernelSize = pLdr->SizeOfImage;
?
// 1.3 保存当前加载基址
char* pCurKernelBase = (char*)pLdr->DllBase;

KdPrint( ("base=%p name=%wZ\n", pCurKernelBase, &pLdr->FullDllName) );

// 2. 读取nt模块的文件内容到堆空间.
status = loadNtKernelModule( &pLdr->FullDllName, &g_pNewNtKernel );
if(STATUS_SUCCESS != status)

return status;

?
// 3. 修复新nt模块的重定位.
fixRelocation( g_pNewNtKernel, (ULONG)pCurKernelBase );
?
// 4. 使用当前正在使用的内核的数据来填充
//   新内核的SSDT表.
initSSDT( g_pNewNtKernel, pCurKernelBase );
?
// 5. HOOK KiFastCallEntry,使调用号走新内核的路线
installHook( );
?
pDriver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;

?
?
VOID DriverUnload(PDRIVER_OBJECT pDriver)

UNREFERENCED_PARAMETER(pDriver);
uninstallHook( );

?
?
?
// 关闭内存页写入保护
void _declspec(naked) disablePageWriteProtect( )

_asm

push eax;
mov eax, cr0;
and eax, ~0x10000;
mov cr0, eax;
pop eax;
ret;


?
// 开启内存页写入保护
void _declspec(naked) enablePageWriteProtect( )

_asm

push eax;
mov eax, cr0;
or eax, 0x10000;
mov cr0, eax;
pop eax;
ret;


?
?
// 加载NT内核模块
// 将读取到的缓冲区的内容保存到pBuff中.
NTSTATUS loadNtKernelModule( UNICODE_STRING* ntkernelPath, char** pOut )

NTSTATUS status = STATUS_SUCCESS;
// 2. 获取文件中的内核模块
// 2.1 将内核模块作为文件来打开.
HANDLE hFile = NULL;
char* pBuff = NULL;
ULONG read = 0;
char pKernelBuff[0x1000];
?
status = createFile( ntkernelPath->Buffer,
GENERIC_READ,
FILE_SHARE_READ,
FILE_OPEN_IF,
FALSE,
&hFile );
if(status != STATUS_SUCCESS)

KdPrint( ("打开文件失败\n") );
goto _DONE;

?
// 2.2 将PE文件头部读取到内存
status = readFile( hFile, 0, 0, 0x1000, pKernelBuff, &read );
if(STATUS_SUCCESS != status)

KdPrint( ("读取文件内容失败\n") );
goto _DONE;

?
// 3. 加载PE文件到内存.
// 3.1 得到扩展头,获取映像大小.
IMAGE_DOS_HEADER* pDos = (IMAGE_DOS_HEADER*)pKernelBuff;
IMAGE_NT_HEADERS* pnt = (IMAGE_NT_HEADERS*)((ULONG)pDos + pDos->e_lfanew);
ULONG imgSize = pnt->OptionalHeader.SizeOfImage;

// 3.2 申请内存以保存各个区段的内容.
pBuff = ExAllocatePool( NonPagedPool, imgSize );
if(pBuff == NULL)

KdPrint( ("内存申请失败失败\n") );
status = STATUS_BUFFER_ALL_ZEROS;//随便返回个错误码
goto _DONE;

?
// 3.2.1 拷贝头部到堆空间
RtlCopyMemory( pBuff,
   pKernelBuff,
   pnt->OptionalHeader.SizeOfHeaders );
?
// 3.3 得到区段头, 并将按照区段头将区段读取到内存中.
IMAGE_SECTION_HEADER* pScnHdr = IMAGE_FIRST_SECTION( pnt );
ULONG scnCount = pnt->FileHeader.NumberOfSections;
for(ULONG i = 0; i < scnCount; ++i)

//
// 3.3.1 读取文件内容到堆空间指定位置.
//
status = readFile( hFile,
   pScnHdr[i].PointerToRawData,
   0,
   pScnHdr[i].SizeOfRawData,
   pScnHdr[i].VirtualAddress + pBuff,
   &read );
if(status != STATUS_SUCCESS)
goto _DONE;
?

?
?
_DONE:
ZwClose( hFile );
//
// 保存新内核的加载的首地址
//
*pOut = pBuff;
?
if(status != STATUS_SUCCESS )

if(pBuff != NULL)

ExFreePool( pBuff );
*pOut = pBuff = NULL;


return status;

?
?
// 修复重定位.
void fixRelocation( char* pDosHdr , ULONG curNtKernelBase )

IMAGE_DOS_HEADER* pDos = (IMAGE_DOS_HEADER*)pDosHdr;
IMAGE_NT_HEADERS* pNt = (IMAGE_NT_HEADERS*)((ULONG)pDos + pDos->e_lfanew);
ULONG uRelRva = pNt->OptionalHeader.DataDirectory[5].VirtualAddress;
IMAGE_BASE_RELOCATION* pRel =
(IMAGE_BASE_RELOCATION*)(uRelRva + (ULONG)pDos);
?
while(pRel->SizeOfBlock)

typedef struct

USHORT offset : 12;
USHORT type : 4;
TypeOffset;
?
ULONG count = (pRel->SizeOfBlock - 8) / 2;
TypeOffset* pTypeOffset = (TypeOffset*)(pRel + 1);
for(ULONG i = 0; i < count; ++i)

if(pTypeOffset[i].type != 3)

continue;

?
ULONG* pFixAddr = (ULONG*)(pTypeOffset[i].offset + pRel->VirtualAddress + (ULONG)pDos);
//
// 减去默认加载基址
//
*pFixAddr -= pNt->OptionalHeader.ImageBase;

//
// 加上新的加载基址(使用的是当前内核的加载基址,这样做
// 是为了让新内核使用当前内核的数据(全局变量,未初始化变量等数据).)
//
*pFixAddr += (ULONG)curNtKernelBase;

?
pRel = (IMAGE_BASE_RELOCATION*)((ULONG)pRel + pRel->SizeOfBlock);


?
// 填充SSDT表
// char* pNewBase - 新加载的内核堆空间首地址
// char* pCurKernelBase - 当前正在使用的内核的加载基址
void initSSDT( char* pNewBase, char* pCurKernelBase )

// 1. 分别获取当前内核,新加载的内核的`KeServiceDescriptorTable`
//   的地址
SSDTEntry* pCurSSDTEnt = &KeServiceDescriptorTable;
g_pNewSSDTEntry = (SSDTEntry*)
((ULONG)pCurSSDTEnt - (ULONG)pCurKernelBase + (ULONG)pNewBase);
?
// 2. 获取新加载的内核以下三张表的地址:
// 2.1 服务函数表基址
g_pNewSSDTEntry->ServiceTableBase = (ULONG*)
((ULONG)pCurSSDTEnt->ServiceTableBase - (ULONG)pCurKernelBase + (ULONG)pNewBase);
?
// 2.3 服务函数参数字节数表基址
g_pNewSSDTEntry->ParamTableBase = (ULONG*)
((ULONG)pCurSSDTEnt->ParamTableBase - (ULONG)pCurKernelBase + (ULONG)pNewBase);
?
// 2.2 服务函数调用次数表基址(有时候这个表并不存在.)
if(pCurSSDTEnt->ServiceCounterTableBase)

g_pNewSSDTEntry->ServiceCounterTableBase = (ULONG*)
((ULONG)pCurSSDTEnt->ServiceCounterTableBase - (ULONG)pCurKernelBase + (ULONG)pNewBase);

?
// 2.3 设置新SSDT表的服务个数
g_pNewSSDTEntry->NumberOfServices = pCurSSDTEnt->NumberOfServices;
?
//3. 将服务函数的地址填充到新SSDT表(重定位时其实已经修复好了,
//   但是,在修复重定位的时候,是使用当前内核的加载基址的, 修复重定位
//   为之后, 新内核的SSDT表保存的服务函数的地址都是当前内核的地址,
//   在这里要将这些服务函数的地址改回新内核中的函数地址.)
disablePageWriteProtect( );
for(ULONG i = 0; i < g_pNewSSDTEntry->NumberOfServices; ++i)

// 减去当前内核的加载基址
g_pNewSSDTEntry->ServiceTableBase[i] -= (ULONG)pCurKernelBase;
// 换上新内核的加载基址.
g_pNewSSDTEntry->ServiceTableBase[i] += (ULONG)pNewBase;

enablePageWriteProtect( );

?
void installHook( )

g_hookAddr = 0;
?
// 1. 找到KiFastCallEntry函数首地址
ULONG uKiFastCallEntry = 0;
_asm

;// KiFastCallEntry函数地址保存
;// 在特殊模组寄存器的0x176号寄存器中
push ecx;
push eax;
push edx;
mov ecx, 0x176; // 设置编号
rdmsr; ;// 读取到edx:eax
mov uKiFastCallEntry, eax;// 保存到变量
pop edx;
pop eax;
pop ecx;

?
// 2. 找到HOOK的位置, 并保存5字节的数据
// 2.1 HOOK的位置选定为(此处正好5字节,):
// 2be1           sub     esp, ecx ;
// c1e902         shr     ecx, 2   ;
UCHAR hookCode[5] = 0x2b,0xe1,0xc1,0xe9,0x02 ; //保存inline hook覆盖的5字节
ULONG i = 0;
for(; i < 0x1FF; ++i)

if(RtlCompareMemory( (UCHAR*)uKiFastCallEntry + i,
hookCode,
5 ) == 5)

break;


if(i >= 0x1FF)

KdPrint( ("在KiFastCallEntry函数中没有找到HOOK位置,可能KiFastCallEntry已经被HOOK过了\n") );
uninstallHook( );
return;

?
?
g_hookAddr = uKiFastCallEntry + i;
g_hookAddr_next_ins = g_hookAddr + 5;
?
// 3. 开始inline hook
UCHAR jmpCode[5] = 0xe9 ;// jmp xxxx
disablePageWriteProtect( );
?
// 3.1 计算跳转偏移
// 跳转偏移 = 目标地址 - 当前地址 - 5
*(ULONG*)(jmpCode + 1) = (ULONG)myKiFastEntryHook - g_hookAddr - 5;
?
// 3.2 将跳转指令写入
RtlCopyMemory( uKiFastCallEntry + i,
   jmpCode,
   5 );

enablePageWriteProtect( );

?
void uninstallHook( )

if(g_hookAddr)


// 将原始数据写回.
UCHAR srcCode[5] = 0x2b,0xe1,0xc1,0xe9,0x02 ;
disablePageWriteProtect( );
?
// 3.1 计算跳转偏移
// 跳转偏移 = 目标地址 - 当前地址 - 5
?
_asm sti
// 3.2 将跳转指令写入
RtlCopyMemory( g_hookAddr,
   srcCode,
   5 );
_asm cli
g_hookAddr = 0;
enablePageWriteProtect( );

?
if(g_pNewNtKernel)

ExFreePool( g_pNewNtKernel );
g_pNewNtKernel = NULL;


?
?
// SSDT过滤函数.
ULONG SSDTFilter( ULONG index,/*索引号,也是调用号*/
  ULONG tableAddress,/*表的地址,可能是SSDT表的地址,也可能是Shadow SSDT表的地址*/
  ULONG funAddr/*从表中取出的函数地址*/ )

// 如果是SSDT表的话
if(tableAddress == KeServiceDescriptorTable.ServiceTableBase)

// 判断调用号(190是ZwOpenProcess函数的调用号)
if(index == 190)

// 返回新SSDT表的函数地址
// 也就是新内核的函数地址.
return g_pNewSSDTEntry->ServiceTableBase[190];


// 返回旧的函数地址
return funAddr;

?
// inline hook KiFastCallEntry的函数
void _declspec(naked) myKiFastEntryHook( )

?
_asm

pushad; // 压栈寄存器: eax,ecx,edx,ebx, esp,ebp ,esi, edi
pushfd; // 压栈标志寄存器
?
push edx; // 从表中取出的函数地址
push edi; // 表的地址
push eax; // 调用号
call SSDTFilter; // 调用过滤函数
?
;// 函数调用完毕之后栈控件布局,指令pushad将
;// 32位的通用寄存器保存在栈中,栈空间布局为:
;// [esp + 00] <=> eflag
;// [esp + 04] <=> edi
;// [esp + 08] <=> esi
;// [esp + 0C] <=> ebp
;// [esp + 10] <=> esp
;// [esp + 14] <=> ebx
;// [esp + 18] <=> edx <<-- 使用函数返回值来修改这个位置
;// [esp + 1C] <=> ecx
;// [esp + 20] <=> eax
mov dword ptr ds : [esp + 0x18], eax;
popfd; // popfd时,实际上edx的值就回被修改
popad;
?
; //执行被hook覆盖的两条指令
sub esp, ecx;
shr ecx, 2;
jmp g_hookAddr_next_ins;

KernelFunction.h

#pragma once
#include <ntifs.h>
#include <ntddk.h>
?
//////////////////////////////////////////////////////////////////////////
//////////////////////////// 内存操作 /////////////////////////////////////
?
//************************************
// Method:   alloc 申请内存
// Returns:   void* 返回内存空间首地址, 申请失败返回NULL
// Parameter: ULONG size 要申请的字节数
//************************************
void* alloc(ULONG size);
//************************************
// Method:   reAlloc 重新分配空间
// Returns:   void* 返回新空间的内存地址
// Parameter: void * src 原始内存空间(必须由alloc函数所返回)
// Parameter: ULONG size 重新分配的字节数
//************************************
void* reAlloc(void* src, ULONG size);
?
//************************************
// Method:   free 释放内存空间
// Returns:   void
// Parameter: void *
//************************************
void free(void* data);
?
?
?
//////////////////////////////////////////////////////////////////////////
//////////////////////////// 文件操作 /////////////////////////////////////
//************************************
// Method:   createFile 创建文件
// Returns:   NTSTATUS
// Parameter: const wchar_t * filepath 文件路径,路径必须是设备名"\\device\\volumn\\"或符号连接名"\\??\\C:\\1.txt"
// Parameter: ULONG access 访问权限, GENERIC_READ, GENERIC_XXX
// Parameter: ULONG share 文件共享方式: FILE_SHARE_XXX
// Parameter: ULONG openModel 打开方式: FILE_OPEN_IF,FILE_CREATE ...
// Parameter: BOOLEAN isDir 是否为目录
// Parameter: HANDLE * hFile
//************************************
NTSTATUS createFile(wchar_t* filepath,
ULONG access,
ULONG share,
ULONG openModel,
BOOLEAN isDir,
HANDLE* hFile);
?
//************************************
// Method:   getFileSize 获取文件大小
// Returns:   NTSTATUS 
// Parameter: HANDLE hFile 文件句柄
// Parameter: ULONG64 * size 文件大小
//************************************
NTSTATUS getFileSize(HANDLE hFile,
ULONG64* size);
?
//************************************
// Method:   readFile 读取文件内容
// Returns:   NTSTATUS
// Parameter: HANDLE hFile 文件句柄
// Parameter: ULONG offsetLow 文件偏移的低32位, 从此位置开始读取
// Parameter: ULONG offsetHig 文件偏移的高32位, 从此位置开始读取
// Parameter: ULONG sizeToRead 要读取的字节数
// Parameter: PVOID pBuff 保存文件内容的缓冲区 , 需要自己申请内存空间.
// Parameter: ULONG * read 实际读取到的字节数
//************************************
NTSTATUS readFile(HANDLE hFile,
  ULONG offsetLow,
  ULONG offsetHig,
  ULONG sizeToRead,
  PVOID pBuff,
  ULONG* read);
?
NTSTATUS writeFile(HANDLE hFile,
   ULONG offsetLow,
   ULONG offsetHig,
   ULONG sizeToWrite,
   PVOID pBuff,
   ULONG* write);
?
NTSTATUS copyFile(wchar_t* srcPath,
  wchar_t* destPath);
?
NTSTATUS moveFile(wchar_t* srcPath,
  wchar_t* destPath);
?
NTSTATUS removeFile(wchar_t* path);
?
?
//************************************
// Method:   listDirGet 列出一个目录下的文件和文件夹
// Returns:   NTSTATUS
// Parameter: wchar_t * dir 目录名, 目录名必须是设备名"\\device\\volumn\\"或符号连接名"\\??\\C:\\1.txt"
// Parameter: FILE_BOTH_DIR_INFORMATION ** fileInfo 保存文件内容的缓冲区, 该缓冲区由函数内部申请空间, 必须通过函数`listDirFree`来释放.
// Parameter: ULONG maxFileCount 要获取的最大文件个数.如果目录下有100个文件,此参数传了5,则只能获取到5个文件.
//************************************
NTSTATUS listDirGet(wchar_t* dir ,
FILE_BOTH_DIR_INFORMATION** fileInfo,
ULONG maxFileCount);
?
?
?
//************************************
// Method:   firstFile 获取一个目录下的第一个文件
// Returns:   NTSTATUS
// Parameter: wchar_t * dir 目录名, 目录名必须是设备名"\\device\\volumn\\"或符号连接名"\\??\\C:\\1.txt"
// Parameter: HANDLE * hFind 函数输出值,是一个目录句柄
// Parameter: FILE_BOTH_DIR_INFORMATION * fileInfo 保存文件内容的缓冲区,
// 这个缓冲区的大小最好是: sizeof(FILE_BOTH_DIR_INFORMATION) + 267*2
//************************************
NTSTATUS firstFile(wchar_t* dir, HANDLE* hFind, FILE_BOTH_DIR_INFORMATION* fileInfo,int size);
?
//************************************
// Method:   nextFile 获取一个目录下的下一个文件.
// Returns:   NTSTATUS
// Parameter: HANDLE hFind 目录句柄, 该句柄是由firstFile函数所返回 .
// Parameter: FILE_BOTH_DIR_INFORMATION * fileInfo 保存文件信息的缓冲区. 这个缓冲区的大小最好是: sizeof(FILE_BOTH_DIR_INFORMATION) + 267*2
//************************************
NTSTATUS nextFile(HANDLE hFind, FILE_BOTH_DIR_INFORMATION* fileInfo, int size);
?
?
void listDirFree(FILE_BOTH_DIR_INFORMATION* fileInfo);
?
#define ListDirNext(Type,fileinfo) ((Type*)((ULONG_PTR)fileinfo + fileinfo->NextEntryOffset))
#define ListDirForEach(FileInfoType,fileInfo, iterator) \
for (FileInfoType* iterator = fileInfo; \
iterator->NextEntryOffset != 0; \
iterator = ListDirNext(FileInfoType,iterator))
?
?
#pragma pack(1)
typedef struct _ServiceDesriptorEntry

ULONG *ServiceTableBase;        // 服务表基址
ULONG *ServiceCounterTableBase; // 计数表基址
ULONG NumberOfServices;         // 表中项的个数
UCHAR *ParamTableBase;          // 参数表基址
SSDTEntry, *PSSDTEntry;
#pragma pack()
?
typedef struct _LDR_DATA_TABLE_ENTRY

LIST_ENTRY InLoadOrderLinks;    //双向链表
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
// ...
LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
?
?
void disablePageWriteProtect( );
void enablePageWriteProtect( );
VOID DriverUnload( PDRIVER_OBJECT pDriver );

kernelFunction.c

#include "KernelFunction.h"
#include <ntifs.h>
?
?
void* alloc(ULONG size)

return ExAllocatePool(PagedPool, size);

?
void* reAlloc(void* src, ULONG size)

if (!src)

return NULL;

?
void* data = alloc(size);
RtlCopyMemory(data, src, size);
ExFreePool(src);
return data;

?
void free(void* data)

if (data)

ExFreePool(data);


?
NTSTATUS createFile(wchar_t * filepath,
ULONG access,
ULONG share,
ULONG openModel,
BOOLEAN isDir,
HANDLE * hFile)

?
NTSTATUS status = STATUS_SUCCESS;
?
IO_STATUS_BLOCK StatusBlock = 0 ;
ULONG           ulShareAccess = share;
ULONG ulCreateOpt = FILE_SYNCHRONOUS_IO_NONALERT;
?
UNICODE_STRING path;
RtlInitUnicodeString(&path, filepath);
?
// 1. 初始化OBJECT_ATTRIBUTES的内容
OBJECT_ATTRIBUTES objAttrib = 0 ;
ULONG ulAttributes = OBJ_CASE_INSENSITIVE/*不区分大小写*/ | OBJ_KERNEL_HANDLE/*内核句柄*/;
InitializeObjectAttributes(&objAttrib,    // 返回初始化完毕的结构体
   &path,      // 文件对象名称
   ulAttributes,  // 对象属性
   NULL, NULL);   // 一般为NULL
?
// 2. 创建文件对象
ulCreateOpt |= isDir ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE;
?
status = ZwCreateFile(hFile,                 // 返回文件句柄
  access, // 文件操作描述
  &objAttrib,            // OBJECT_ATTRIBUTES
  &StatusBlock,          // 接受函数的操作结果
  0,                     // 初始文件大小
  FILE_ATTRIBUTE_NORMAL, // 新建文件的属性
  ulShareAccess,         // 文件共享方式
  openModel, // 文件存在则打开不存在则创建
  ulCreateOpt,           // 打开操作的附加标志位
  NULL,                  // 扩展属性区
  0);                    // 扩展属性区长度
return status;

?
?
NTSTATUS getFileSize(HANDLE hFile, ULONG64* size)

IO_STATUS_BLOCK isb = 0 ;
FILE_STANDARD_INFORMATION fsi = 0 ;
NTSTATUS status;
status = ZwQueryInformationFile(hFile, /*文件句柄*/
&isb, /*完成状态*/
&fsi, /*保存文件信息的缓冲区*/
sizeof(fsi), /*缓冲区的字节数*/
FileStandardInformation/*要获取的信息类型*/);
if (STATUS_SUCCESS == status)

// 保存文件字节数
*size = fsi.EndOfFile.QuadPart;

return status;

?
NTSTATUS readFile(HANDLE hFile,
  ULONG offsetLow,
  ULONG offsetHig,
  ULONG sizeToRead,
  PVOID pBuff,
  ULONG* read)

NTSTATUS status;
IO_STATUS_BLOCK isb = 0 ;
LARGE_INTEGER offset;
// 设置要读取的文件偏移
offset.HighPart = offsetHig;
offset.LowPart = offsetLow;
?
status = ZwReadFile(hFile,/*文件句柄*/
NULL,/*事件对象,用于异步IO*/
NULL,/*APC的完成通知例程:用于异步IO*/
NULL,/*完成通知例程序的附加参数*/
&isb,/*IO状态*/
pBuff,/*保存文件数据的缓冲区*/
sizeToRead,/*要读取的字节数*/
&offset,/*要读取的文件位置*/
NULL);
if (status == STATUS_SUCCESS)
*read = isb.Information;
return status;

?
NTSTATUS writeFile(HANDLE hFile,
   ULONG offsetLow,
   ULONG offsetHig,
   ULONG sizeToWrite,
   PVOID pBuff,
   ULONG* write)

?
NTSTATUS status;
IO_STATUS_BLOCK isb = 0 ;
LARGE_INTEGER offset;
// 设置要写入的文件偏移
offset.HighPart = offsetHig;
offset.LowPart = offsetLow;
?
status = ZwWriteFile(hFile,/*文件句柄*/
NULL, /*事件对象,用户异步IO*/
NULL,/*APC例程,用于异步IO*/
NULL, /*APC环境*/
&isb,/*IO状态*/
pBuff,/*写入到文件中的缓冲区*/
sizeToWrite,/*写入的字节数*/
&offset,/*写入到的文件偏移*/
NULL);
if (status == STATUS_SUCCESS)
*write = isb.Information;
?
return status;

?
NTSTATUS copyFile(wchar_t* srcPath,
  wchar_t* destPath)

HANDLE hSrc = (HANDLE)-1;
HANDLE hDest = (HANDLE)-1;
NTSTATUS status = STATUS_SUCCESS;
ULONG64 srcSize = 0;
ULONG size = 0;
char*   pBuff = NULL;
__try

// 1. 先打开源文件
status = createFile(srcPath,
GENERIC_READ,
FILE_SHARE_READ,
FILE_OPEN_IF,
FALSE,
&hSrc);
?
if (STATUS_SUCCESS != status)

__leave;

?
?
// 2. 获取源文件大小
if (STATUS_SUCCESS != getFileSize(hSrc, &srcSize))

__leave;

?
// 3. 分配内存空间保存源文件的数据
pBuff = ExAllocatePool(PagedPool, (ULONG)srcSize);
if (pBuff == NULL)

__leave;

?
// 3. 读取源文件的数据到内存中.
status = readFile(hSrc, 0, 0, (ULONG)srcSize, pBuff, &size);
if (STATUS_SUCCESS != status || size != (ULONG)srcSize)

__leave;

?
// 4. 打开目标文件
status = createFile(destPath,
GENERIC_WRITE,
FILE_SHARE_READ,
FILE_CREATE,
FALSE,
&hDest);
if (STATUS_SUCCESS != status)

__leave;

?
// 5. 将源文件的数据写入到目标文件
status = writeFile(hDest, 0, 0, (ULONG)srcSize, pBuff, &size);
if (STATUS_SUCCESS != status || size != srcSize)

__leave;

status = STATUS_SUCCESS;

__finally

// 6. 关闭源文件
if (hSrc != (HANDLE)-1)

ZwClose(hSrc);

?
// 7. 关闭目标文件
if (hDest != (HANDLE)-1)

ZwClose(hDest);

?
// 8. 释放缓冲区
if (pBuff)

ExFreePool(pBuff);


return status;

?
NTSTATUS moveFile(wchar_t* srcPath, wchar_t* destPath)

NTSTATUS status = STATUS_SUCCESS;
// 1. 拷贝一份文件
status = copyFile(srcPath, destPath);
?
// 2. 如果拷贝成功了,删除源文件
if (status == STATUS_SUCCESS)

status = removeFile(srcPath);

return status;

?
NTSTATUS removeFile(wchar_t* filepath)

?
UNICODE_STRING path;
RtlInitUnicodeString(&path, filepath);
?
// 1. 初始化OBJECT_ATTRIBUTES的内容
OBJECT_ATTRIBUTES objAttrib = 0 ;
ULONG             ulAttributes = OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE;
InitializeObjectAttributes(&objAttrib,    // 返回初始化完毕的结构体
   &path,  // 文件对象名称
   ulAttributes,  // 对象属性
   NULL,          // 根目录(一般为NULL)
   NULL);         // 安全属性(一般为NULL)
// 2. 删除指定文件/文件夹
return ZwDeleteFile(&objAttrib);

?
?
NTSTATUS listDirGet(wchar_t* dir, FILE_BOTH_DIR_INFORMATION** fileInfo, ULONG maxFileCount)

NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK isb = 0 ;
HANDLE hDir = (HANDLE)-1;
VOID* pBuff = NULL;
__try
// 1. 打开目录
status = createFile(dir,
GENERIC_READ,
FILE_SHARE_READ,
FILE_OPEN_IF,
TRUE,
&hDir);
if (STATUS_SUCCESS != status)
__leave;
?
// 计算出保存一个文件信息所需的最大字节数 = 结构体大小 + 文件名大小
ULONG signalFileInfoSize = sizeof(FILE_BOTH_DIR_INFORMATION) + 267 * 2;
// 计算出总空间字节数
ULONG totalSize = signalFileInfoSize * maxFileCount;
?
// 申请内存空间
pBuff = ExAllocatePool(PagedPool, totalSize);
if (pBuff == NULL)
__leave;
?
// 第一次调用,获取所需缓冲区字节数
status = ZwQueryDirectoryFile(hDir, /*目录句柄*/
  NULL, /*事件对象*/
  NULL, /*完成通知例程*/
  NULL, /*完成通知例程附加参数*/
  &isb, /*IO状态*/
  pBuff, /*输出的文件信息*/
  totalSize,/*文件信息缓冲区的字节数*/
  FileBothDirectoryInformation,/*获取信息的类型*/
  FALSE,/*是否只获取第一个*/
  0,
  TRUE/*是否重新扫描目录*/);
// 保存缓冲区的内容首地址.
if (status == STATUS_SUCCESS)
*fileInfo = (FILE_BOTH_DIR_INFORMATION*)pBuff;

__finally
?
if (hDir != (HANDLE)-1)

ZwClose(hDir);

if (status != STATUS_SUCCESS && pBuff != NULL)

ExFreePool(pBuff);


return status;

?
NTSTATUS firstFile(wchar_t* dir, HANDLE* hFind, FILE_BOTH_DIR_INFORMATION* fileInfo, int size)

NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK isb = 0 ;
// 1. 打开目录
status = createFile(dir,
GENERIC_READ,
FILE_SHARE_READ,
FILE_OPEN_IF,
TRUE,
hFind);
if (STATUS_SUCCESS != status)
return status;
?
// 第一次调用,获取所需缓冲区字节数
status = ZwQueryDirectoryFile(*hFind, /*目录句柄*/
  NULL, /*事件对象*/
  NULL, /*完成通知例程*/
  NULL, /*完成通知例程附加参数*/
  &isb, /*IO状态*/
  fileInfo, /*输出的文件信息*/
  size,/*文件信息缓冲区的字节数*/
  FileBothDirectoryInformation,/*获取信息的类型*/
  TRUE,/*是否只获取第一个*/
  0,
  TRUE/*是否重新扫描目录*/);

return status;

?
NTSTATUS nextFile(HANDLE hFind, FILE_BOTH_DIR_INFORMATION* fileInfo, int size)

IO_STATUS_BLOCK isb = 0 ;
// 第一次调用,获取所需缓冲区字节数
return ZwQueryDirectoryFile(hFind, /*目录句柄*/
NULL, /*事件对象*/
NULL, /*完成通知例程*/
NULL, /*完成通知例程附加参数*/
&isb, /*IO状态*/
fileInfo, /*输出的文件信息*/
size,/*文件信息缓冲区的字节数*/
FileBothDirectoryInformation,/*获取信息的类型*/
TRUE,/*是否只获取第一个*/
0,
FALSE/*是否重新扫描目录*/);

?
void listDirFree(FILE_BOTH_DIR_INFORMATION* fileInfo)

ExFreePool(fileInfo);

?
?
?

以上是关于10内核重载的主要内容,如果未能解决你的问题,请参考以下文章

eCos内核API与内核实现的衔接

从零开始写 OS 内核

如何从 SYCL 内核中提取控制流?

如何从 SYCL 内核中提取控制流?

linux系统不重启生效宝典

ARM内核常用缩写含义