内核重载步奏:
1、把ntkrnlpa.exe从磁盘中加载到内存
2、内核基地址重定位
3、SSDT重定位,还有一个动态获取已加载驱动ntkrnlpa.exe的首地址
4、先自己调用一个SSDT函数 获得KiFastCallEntry 的函数地址,然后HOOK获取调用SSDT程序的进程名字判断是不是我们工具的名字是转入新内核不是走旧内核;

#pragma once //只编译一次
#ifdef __cplusplus
extern"C"
{
#endif
#include "ntddk.h"
#include "ntimage.h"
#ifdef __cplusplus
}
#endif //如果是c++代码用c的方式链接{它}
#define _max(a,b)  a>b?a:b
//这是一个SSDT表的结构类型先声明一下
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase;
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
extern "C"{
        __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
}
//遍历驱动名用的一个结构
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;
        union {
                LIST_ENTRY HashLinks;
                struct {
                        PVOID SectionPointer;
                        ULONG CheckSum;
                };
        };
        union {
                struct {
                        ULONG TimeDateStamp;
                };
                struct {
                        PVOID LoadedImports;
                };
        };
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
//全局变量
PVOID sizeof_image;    //映射到内存的地址指针
ULONG  OrigImage;    //原来的内核基地址
ServiceDescriptorTableEntry_t *  pNewSSDT;//新SSDT地址
ULONG        g_ntcreatefile;         //保存原始的SSDT
ULONG        g_fastcall_hookpointer; //保存要HOOK的地址
ULONG        g_goto_origfunc;        //判断后要返回的地址
//恢复内存保护 
void PageProtectOn()
{
        __asm
        {
                mov  eax, cr0
                or   eax, 10000h
                mov  cr0, eax
                sti
        }
}
//去掉内存保护
void PageProtectOff()
{
        __asm
        {
                cli
                mov  eax, cr0
                and  eax, not 10000h
                mov  cr0, eax
        }
}
//****************************************判断HOOK部分的******************************************
//声明函数指针
typedef NTSTATUS(*NTCREATEFILE) (
        __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_bcount_opt(EaLength) PVOID EaBuffer,
        __in ULONG EaLength
        );  //声明
//特征码搜寻
ULONG SearchHookPointer(ULONG StartAddress)
{
        ULONG        u_index;
        UCHAR        *p = (UCHAR*)StartAddress;
        for (u_index = 0; u_index < 200; u_index++)
        {
                if (
                        *p == 0x33 &&
                        *(p + 1) == 0xC9 &&
                        *(p + 2) == 0x8B &&
                        *(p + 3) == 0x57 &&
                        *(p + 4) == 0x0C)
                {
                        return (ULONG)p;
                }
                p--;
        }
        return 0;
}
//进程判断
ULONG   FilterKiFastCallEntry()
{

        ULONG l_deviation;//偏移
        ULONG l_base_address;// 基地址
        ULONG l_current_address;//当前地址
        __asm
        {
                mov     l_deviation, eax
                        mov     l_base_address, edi
                        mov     l_current_address, edx
        }

        //判断是不是要进入SSDT中的函数
        if (l_base_address == (ULONG)KeServiceDescriptorTable.ServiceTableBase)
        {
                
                if (strstr((char*)PsGetCurrentProcess() + 0x16c, "FishcOD.exe") || strstr((char*)PsGetCurrentProcess() + 0x16c, "cheatengine") != 0)
                {
                        //返回新重载的SSDT里
                        return pNewSSDT->ServiceTableBase[l_deviation];
                }
        }
        //返回原来的地址
        return l_current_address;
}
//判断是否是我们通行的进程
__declspec(naked)
void NewKiFastCallEntry()
{
        __asm
        {
                xor     ecx, ecx
                mov     edx, dword ptr[edi + 0Ch]
                mov     edi, dword ptr[edi]
                mov     cl, byte ptr[eax + edx]
                mov     edx, dword ptr[edi + eax * 4]
                sub     esp, ecx
                shr     ecx, 2
                pushad
                pushfd
                call    FilterKiFastCallEntry
                mov[esp + 0x18], eax //换的是栈里边的值

                popfd
                popad
                jmp   g_goto_origfunc
        }
}
//还原HOOK   KiFastCallEntry
void UnHookKiFastCallEntry()
{
        UCHAR        str_origfuncode[5] = { 0x33, 0xC9, 0x8B, 0x57, 0x0C };
        if (g_fastcall_hookpointer == 0)
        {
                return;
        }
        PageProtectOff();
        RtlCopyMemory((PVOID)g_fastcall_hookpointer, str_origfuncode, 5);
        PageProtectOn();
}
//替换转跳指令
void HookKiFastCallEntry(ULONG HookPointer)
{
        ULONG        u_temp;
        UCHAR        str_jmp_code[5];
        str_jmp_code[0] = 0xE9;
        u_temp = (ULONG)NewKiFastCallEntry - HookPointer - 5;
        *(ULONG*)&str_jmp_code[1] = u_temp;
        PageProtectOff();
        RtlCopyMemory((PVOID)HookPointer, str_jmp_code, 5);
        PageProtectOn();
}
//我们呢自己的NtCreateFile
NTSTATUS NewNtCreateFile(
        __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_bcount_opt(EaLength) PVOID EaBuffer,
        __in ULONG EaLength
        )
{
        
        ULONG        u_call_retaddr;
        __asm{
                pushad
                mov eax, [ebp + 0x4]
                mov u_call_retaddr, eax
                popad
        }
        g_fastcall_hookpointer = SearchHookPointer(u_call_retaddr);
        if (g_fastcall_hookpointer == 0)
        {
                KdPrint(("search failed."));
        }
        else{
                KdPrint(("search success."));
        }
        g_goto_origfunc = g_fastcall_hookpointer + 0x12;
        HookKiFastCallEntry(g_fastcall_hookpointer);
        //还原SSDT
        PageProtectOff();
        KeServiceDescriptorTable.ServiceTableBase[66] = (unsigned int)g_ntcreatefile;
        PageProtectOn();
        
        return ((NTCREATEFILE)g_ntcreatefile)(
                FileHandle, \
                DesiredAccess, \
                ObjectAttributes, \
                IoStatusBlock, \
                AllocationSize, \
                FileAttributes, \
                ShareAccess, \
                CreateDisposition, \
                CreateOptions, \
                EaBuffer, \
                EaLength);
}
//HOOKNtCreateFile
void SearchKiFastCallEntry()
{
        
        HANDLE                                hFile;
        NTSTATUS                        Status;
        OBJECT_ATTRIBUTES        ObjAttr;
        UNICODE_STRING                usFileName;
        IO_STATUS_BLOCK                IoStatusBlock;
        RtlInitUnicodeString(&usFileName, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
        InitializeObjectAttributes(\
                &ObjAttr, \
                &usFileName, \
                OBJ_CASE_INSENSITIVE, \
                NULL, \
                NULL);
        g_ntcreatefile = KeServiceDescriptorTable.ServiceTableBase[66];
        PageProtectOff();
        KeServiceDescriptorTable.ServiceTableBase[66] = (unsigned int)NewNtCreateFile;
        PageProtectOn();
        Status = ZwCreateFile(\
                &hFile, \
                FILE_ALL_ACCESS, \
                &ObjAttr, \
                &IoStatusBlock, \
                NULL, \
                FILE_ATTRIBUTE_NORMAL, \
                FILE_SHARE_READ, \
                FILE_OPEN, \
                FILE_NON_DIRECTORY_FILE, \
                NULL, \
                0);
        if (NT_SUCCESS(Status))
        {
                ZwClose(hFile);
        }
}
//************************************重定位部分********************************************************************
//SSDT重定位
VOID RelocationSSDT(PVOID NewAddress, ULONG RawAddress)
{                       
        
        ULONG RelativeOffset; //相对的偏移量
        RelativeOffset = (ULONG)NewAddress - RawAddress;//相对的偏移地址
        pNewSSDT = (ServiceDescriptorTableEntry_t*)((ULONG)&KeServiceDescriptorTable + RelativeOffset); //新SSDT地址
        if (!MmIsAddressValid(pNewSSDT))
        {
                KdPrint(("pNewSsdt is Error"));
                return;
        }

        pNewSSDT->NumberOfServices = KeServiceDescriptorTable.NumberOfServices; //拷贝SSDT函数数量
        ULONG uDeviation; //函数偏移
        uDeviation = (ULONG)KeServiceDescriptorTable.ServiceTableBase - RawAddress;//Relative Virtual Address 相对于基址
        pNewSSDT->ServiceTableBase = (unsigned int*)((ULONG)NewAddress + uDeviation); //新地址加相对偏移地址(旧SSDT-旧基址)
        if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
        {
                KdPrint(("pNewSSDT->ServiceTableBase is Error"));
                return;
        }
        //遍历修改SSDTServiceTableBase数组的值
        int i;
        for (i = 0; i<pNewSSDT->NumberOfServices; i++)
        {
                pNewSSDT->ServiceTableBase[i] += RelativeOffset;
        }

        KdPrint(("success RelocationSSDT"));
}
//基地址重定位
void BaseRelocation(PVOID pNewImage)
{
        ULONG                                        i;                    //for循环变量
        ULONG                                        uRelocTableSize;      //存放数据块中的数据总个数
        ULONG                                        OriginalImageBase;    //内存文件的首装入地址
        ULONG                                        Type;                 //16位数据高4位
        ULONG                                         *uRelocAddress;       //指向需要修改内容的地址
        PIMAGE_DOS_HEADER                pImageDosHeader;      //DOS头
        PIMAGE_NT_HEADERS                pImageNtHeader;       //NT头
        IMAGE_DATA_DIRECTORY        ImageDataDirectory;   //数据表
        IMAGE_BASE_RELOCATION        *pImageBaseRelocation;//重定位表

        //将新内核地址作为一个PE文件头,依次向下,目的是寻找重定位表结构
        pImageDosHeader = (PIMAGE_DOS_HEADER)pNewImage;
        //定位到IMAGE_NT_HEADER
        pImageNtHeader = (PIMAGE_NT_HEADERS)((ULONG)pNewImage + pImageDosHeader->e_lfanew);
        //获取内核文件的imagebase,以便后面做偏移修改。
        OriginalImageBase = pImageNtHeader->OptionalHeader.ImageBase;
        //定位到数据目录
        ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
        //定位到重定位表结构
        pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
        if (pImageBaseRelocation == NULL)
        {
                return;
        }
        //修改数据*************************
        while (pImageBaseRelocation->SizeOfBlock)
        {   //得到需要更改数据的个数

                uRelocTableSize = (pImageBaseRelocation->SizeOfBlock - 8) / 2;
                //循环遍历
                for (i = 0; i<uRelocTableSize; i++)
                {//判断高4位是否等于3
                        Type = pImageBaseRelocation->TypeOffset[i] >> 12;
                        if (Type == IMAGE_REL_BASED_HIGHLOW)
                        {
                                //让指针指向要修改的数据
                                uRelocAddress = (ULONG *)((ULONG)(pImageBaseRelocation->TypeOffset[i] & 0xfff) + pImageBaseRelocation->VirtualAddress + (ULONG)pNewImage);
                                //修改重定位数据,原数据加上一个偏移
                                *uRelocAddress = (*uRelocAddress + (OrigImage - OriginalImageBase));

                        }
                }
                //把指针移到下一个快,如果->SizeOfBlock为空了,表示没有块了退出循环
                pImageBaseRelocation = (IMAGE_BASE_RELOCATION *)((ULONG)pImageBaseRelocation + pImageBaseRelocation->SizeOfBlock);
        }
        KdPrint(("基址重定位完毕"));
}
//重载内核
VOID  ReloadKernel()  //重载内核
{

        //创建文件*******
        HANDLE    hfile;     //接受句柄
        NTSTATUS  status;    //状态
        IO_STATUS_BLOCK      io_status_block;    //接受状态结构
        OBJECT_ATTRIBUTES    object_attributes;  //句柄属性
        UNICODE_STRING       path_name;
        RtlInitUnicodeString(&path_name, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
        //初始化对象属性
        InitializeObjectAttributes(&object_attributes, //对象属性变量 POBJECT_ATTRIBUTES OUT  
                &path_name,                                                                   //文件名   PUNICODE_STRING
                OBJ_CASE_INSENSITIVE,                      //表示不区分大小写
                NULL,                                      //NULL
                NULL);                                     //NULL
        //创建文件
        status = ZwCreateFile(
                &hfile,                  //返回的句柄  OUT PHANDLE
                FILE_ALL_ACCESS,         //访问权限->所有权限
                &object_attributes,      //POBJECT_ATTRIBUTES 该结构包含要打开的文件名
                &io_status_block,        //PIO_STATUS_BLOCK 返回结果状态 OUT
                0,                       //初始分配大小,0是动态分配
                FILE_ATTRIBUTE_NORMAL,   //文件属性 一般为<-或者0;
                FILE_SHARE_READ,         //指定共享方式一般<- 或者0;
                FILE_OPEN,               //这个参数指定要对文件干嘛
                FILE_NON_DIRECTORY_FILE, //指定控制打开操作和句柄使用的附加标志位
                NULL,                    //指向可选的扩展属性区
                0);                      //扩展属性区的长度
        if (!NT_SUCCESS(status))
        {
                KdPrint(("ZwCreateFile Failed!"));
                return;
        }
        //读取DOS头******
        IMAGE_DOS_HEADER        image_dos_header;//dos头结构
        LARGE_INTEGER       large_integer;//记录偏移
        large_integer.QuadPart = 0;
        status = ZwReadFile(hfile,       //ZwCreateFile成功后得到的句柄  
                NULL,                        //一个事件  NULL
                NULL,                        //回调例程。NULL
                NULL,                        //NULL
                &io_status_block,            //PIO_STATUS_BLOCK 返回结果状态 OUT ,同上
                &image_dos_header,           //存放读取数据的缓冲区 OUT PVOID  
                sizeof(IMAGE_DOS_HEADER),    //试图读取文件的长度
                &large_integer,              //要读取数据相对文件的偏移量PLARGE_INTEGER
                0);                          //NULL
        if (!NT_SUCCESS(status))
        {
                KdPrint(("Read ImageDosHeader Failed!"));
                ZwClose(hfile);
                return;
        }
        //读取NT头*******
        IMAGE_NT_HEADERS   image_nt_header;//NT头
        large_integer.QuadPart = image_dos_header.e_lfanew; //PE头偏移
        status = ZwReadFile(hfile,       //ZwCreateFile成功后得到的句柄  
                NULL,                        //一个事件  NULL
                NULL,                        //回调例程。NULL
                NULL,                        //NULL
                &io_status_block,            //PIO_STATUS_BLOCK 返回结果状态 OUT ,同上
                &image_nt_header,           //存放读取数据的缓冲区 OUT PVOID  
                sizeof(IMAGE_NT_HEADERS),    //试图读取文件的长度
                &large_integer,              //要读取数据相对文件的偏移量PLARGE_INTEGER
                0);                          //NULL
        if (!NT_SUCCESS(status))
        {
                KdPrint(("Read image_nt_header Failed!"));
                ZwClose(hfile);
                return;
        }
        //读取区块*****
        IMAGE_SECTION_HEADER * p_image_section_header;//指向多个区块结构
        //分配所有模块总大小
        p_image_section_header = (IMAGE_SECTION_HEADER*)ExAllocatePool(NonPagedPool,        //NonPagedPool  从非分页内存池中分配内存 
                sizeof(IMAGE_SECTION_HEADER)*image_nt_header.FileHeader.NumberOfSections);
        //读
        large_integer.QuadPart += sizeof(IMAGE_NT_HEADERS); //区块偏移
        status = ZwReadFile(hfile,       //ZwCreateFile成功后得到的句柄  
                NULL,                        //一个事件  NULL
                NULL,                        //回调例程。NULL
                NULL,                        //NULL
                &io_status_block,            //PIO_STATUS_BLOCK 返回结果状态 OUT ,同上
                p_image_section_header,           //存放读取数据的缓冲区 OUT PVOID  
                sizeof(IMAGE_SECTION_HEADER)*image_nt_header.FileHeader.NumberOfSections,    //试图读取文件的长度
                &large_integer,              //要读取数据相对文件的偏移量PLARGE_INTEGER
                0);                          //NULL
        if (!NT_SUCCESS(status))
        {
                KdPrint(("Read p_image_section_header Failed!"));
                ExFreePool(p_image_section_header);
                ZwClose(hfile);
                return;
        }
        //复制数据**********
        //PVOID sizeof_image;//定义成全局变量  因为卸载的时候要释放掉内存
        sizeof_image = ExAllocatePool(NonPagedPool, image_nt_header.OptionalHeader.SizeOfImage);//NonPagedPool  从非分页内存池中分配内存 
        if (sizeof_image == 0)
        {
                KdPrint(("sizeof_image ExAllocatePool Failed!"));
                ExFreePool(sizeof_image);
                ExFreePool(p_image_section_header);  //释放内存
                ZwClose(hfile);
                return;
        }
        //初始化下内存
        memset(sizeof_image, 0, image_nt_header.OptionalHeader.SizeOfImage);
        RtlCopyMemory(sizeof_image, &image_dos_header, sizeof(IMAGE_DOS_HEADER));        //dos头
        RtlCopyMemory((PVOID)((ULONG)sizeof_image + image_dos_header.e_lfanew),
                &image_nt_header, sizeof(IMAGE_NT_HEADERS));                                 //nt头
        RtlCopyMemory((PVOID)((ULONG)sizeof_image + image_dos_header.e_lfanew + sizeof(IMAGE_NT_HEADERS)),       //区块
                p_image_section_header, sizeof(IMAGE_SECTION_HEADER)*image_nt_header.FileHeader.NumberOfSections);//计算区块总大小

        
        ULONG sizeof_raw_data;
        for (ULONG i = 0; i<image_nt_header.FileHeader.NumberOfSections; i++)
        {   
                sizeof_raw_data = _max(p_image_section_header[i].Misc.VirtualSize, p_image_section_header[i].SizeOfRawData);
                large_integer.QuadPart = p_image_section_header[i].PointerToRawData;   
                //读
                status = ZwReadFile(hfile,        
                        NULL,                        
                        NULL,                        
                        NULL,                        
                        &io_status_block,            
                        (PVOID)((ULONG)sizeof_image + p_image_section_header[i].VirtualAddress),          
                        sizeof_raw_data,             
                        &large_integer,              
                        0);                          
                if (!NT_SUCCESS(status))
                {
                        KdPrint(("循环区块出错[%s]%x\n",
                                p_image_section_header[i].Name,
                                (ULONG)sizeof_image + p_image_section_header[i].VirtualAddress));

                        ExFreePool(sizeof_image);
                        ExFreePool(p_image_section_header);  //释放内存
                        ZwClose(hfile);
                        return;
                }
        }
        BaseRelocation(sizeof_image);
        KdPrint(("重载内存成功"));

        ExFreePool(p_image_section_header);  
        ZwClose(hfile);
        return;
}
//动态获取基地址
PVOID SearchDriver(PDRIVER_OBJECT pDriverObject, wchar_t *strDriverName)
{   


        LDR_DATA_TABLE_ENTRY        *pDataTableEntry, *pTempDataTableEntry;
        PLIST_ENTRY                                pList;        //下一个节点
        UNICODE_STRING                        usModuleName; // 存放字符串
        
        RtlInitUnicodeString(&usModuleName, strDriverName);
        
        pDataTableEntry = (LDR_DATA_TABLE_ENTRY*)pDriverObject->DriverSection;
        if (!pDataTableEntry)
        {
                return 0;
        }

        pList = pDataTableEntry->InLoadOrderLinks.Flink;

        
        while (pList != &pDataTableEntry->InLoadOrderLinks)
        {
                
                pTempDataTableEntry = (LDR_DATA_TABLE_ENTRY *)pList;

                
                if (0 == RtlCompareUnicodeString(&pTempDataTableEntry->BaseDllName, &usModuleName, FALSE))
                {
                        return pTempDataTableEntry->DllBase;

                }
                
                pList = pList->Flink;
        }
        KdPrint(("获取ntkrnlpa.exe基地址失败"));
        return 0;
}
//***************************************************************************
//卸载函数
VOID MyDriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
        KdPrint(("成功进入卸载函数"));
        if (sizeof_image != 0)
        {
                KdPrint(("sizeof_image内存释放"));
                ExFreePool(sizeof_image);//释放内存
        }
        UnHookKiFastCallEntry();
        KdPrint(("全部卸载完成"));
}
//驱动入口
extern"C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
        IN PUNICODE_STRING pRegistryPath)
{
        KdPrint(("加载驱动成功"));
        pDriverObject->DriverUnload = MyDriverUnload;//卸载函数
        //获取基地址
        OrigImage = (ULONG)SearchDriver(pDriverObject, L"ntoskrnl.exe");
        if (!OrigImage)
        {
                KdPrint(("获取ntoskrnl.exe失败"));
                return 0;
        }
        KdPrint(("ntoskrnl.exe驱动模块首地址=%x", OrigImage));
        //内核重载
        ReloadKernel();
        RelocationSSDT(sizeof_image, OrigImage);
        KdPrint(("加载内存模块首地址=%x", sizeof_image));
        //HOOK KiFastCallEntry;
        SearchKiFastCallEntry();
        return STATUS_SUCCESS;
}