WinXp下的内核重载

我的想法是重载一个内核后, 当我点击目标软件时可以显示它调用的所有内核函数名称和地址
(Header.h)代码如下:

Header.h 代码
#pragma once
#ifndef LGHEADER
#define LGHEADER
#include <Ntifs.h>
// 定义操作系统版本
#define WINXP 51
#define WIN7  61
#define WIN8  62
#define WIN10 100
// 定义分页模式
#define NormalPageMode 0x1
#define NotNormalPageMode 0x0
// 定义ShellCode汇编指令长度
#define ASMCODELEN 0x8
ULONG MyHookFun;/* 我的Hook函数地址 */
ULONG JmpBaseAddr;/* 要跳回的地址 */
/* 保存内核信息 */
ULONG newKernelMoudle; /* 新内核模块地址 */
ULONG newSsdtTable; /* 新SSDT表地址 */
/*--------------------- 存储Ntdll.dll信息 -----------------------*/
/* NTDLL Info */
PUCHAR ntdllBase;
typedef struct _NtdllInfo
{
        ULONG fIndex;
        CHAR fName[256];
}NtdllInfo, *PNtdllInfo;
PNtdllInfo pNtdllInfoArray[0x550];
// 获取所有函数名称对应的索引
PNtdllInfo GetAllFuncNameArray();
// 系统服务表结构体
typedef struct _SystemServiceTable
{
        PULONG FunctionsAddrTable;
        ULONG CallCount;
        ULONG FunctionsLimit;
        PUCHAR FunctionsArgsAddrTable;
}SystemServiceTable, *PSystemServiceTable;
/*--------------------- 接口函数 -----------------------*/
// 返回对应索引的新SSDT表函数地址
ULONG GetNewSsdtFunction(ULONG fIndex);
// 根据索引获取对应的内核函数名称
VOID GetKernelMoudleFuncNameByIndex(ULONG fIndex, CHAR * bName);
// 主逻辑函数
BOOLEAN MyMain();
#endif

Driver.c 代码

#include "Header.h"
// 主模块
ULONG MyFunIndex = 0x0;/* 函数索引 */
ULONG MyFunaddr = 0x0; /*函数地址*/
PEPROCESS MypEprocess;
CHAR NameBuffer[256] = { 0x0 };
// 注意函数类型要为 __cdecl
void  __declspec(naked) __cdecl LGHookFunction()
{
        //KdBreakPoint();
        __asm
        {
               pushad;
               pushfd;
        }
        /*写代码处*/
        __asm
        {
               mov MyFunIndex, eax;
        }
        // 判断当前进程是否为目标进程
        MypEprocess = PsGetCurrentProcess();
        if (_strnicmp((CHAR *)((ULONG)MypEprocess + 0x174),
               "TestExe.exe", strlen("TestExe.exe"))
               == 0x0)
        {
               // 返回对应 函数索引 的 新内核 的函数地址
               MyFunaddr = GetNewSsdtFunction(MyFunIndex);
               if (MyFunaddr)
               {
                       __asm
                       {
                              mov ebx, MyFunaddr; // 修改函数地址
                       }
                       
                       GetKernelMoudleFuncNameByIndex(MyFunIndex, NameBuffer);
                       KdPrint(("Hook的函数 %s 的地址: %p\n", NameBuffer, MyFunaddr));
               }
        }
        /*********************/
        __asm
        {
               popfd;
               popad;
               mov eax, dword ptr[JmpBaseAddr]; // JmpBaseAddr 是要跳回的地址(只要调用  MyMain() 就会填写)
               jmp eax; // 跳回原来函数位置
        }
}
VOID Unload(PDRIVER_OBJECT DriverObject)
{
        KdPrint(("驱动卸载\n"));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING Regedit)
{
        KdPrint(("驱动加载\n"));
        NTSTATUS status = STATUS_SUCCESS;
        DriverObject->DriverUnload = Unload;
        //KdBreakPoint();
        GetAllFuncNameArray();
        {
               // 填写你的Hook函数地址
               MyHookFun = (ULONG)LGHookFunction;
               // 内核重载主逻辑代码
               MyMain();
        }
        
        return status;
}

FunctionsRealize.c 代码

#include "Header.h"
#include <ntimage.h> // PE模块定义Moudle
// 功能实现模块
 
// 重新运行一份 内核模块
// 复制一份 SSDT 表(修复)
// Hook KiFastCallEntry
 
// 重新运行一份 内核模块
// (1). 拉伸 PE
// (2). 修复重定位
 
// 打开文件
VOID MyOpenFile(PHANDLE phFile, PUNICODE_STRING DllName)
{
    HANDLE hFile = NULL;
    NTSTATUS status = STATUS_SUCCESS;
    IO_STATUS_BLOCK IoStatus;
    OBJECT_ATTRIBUTES FileAttrObject; // 创建文件属性对象
    // 初始化 OBJECT_ATTRIBUTES 结构体
    InitializeObjectAttributes(
        &FileAttrObject, // 文件属性对象指针
        DllName, // 文件名称
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // 文件属性对象初始化和这是内核对象句柄
        NULL, NULL
    );
    status = ZwCreateFile(
        &hFile, // 文件句柄
        GENERIC_ALL,  // 所有访问权限
        &FileAttrObject, // 文件属性对象
        &IoStatus, // 文件操作的返回状态
        NULL,
        FILE_ATTRIBUTE_NORMAL, // 标准文件格式
        FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, // 共享方式
        FILE_OPEN, // 如果文件不存在就创建
        FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
    );
    if (!NT_SUCCESS(status))
    {
        DbgPrint("文件创建不成功!\n");
        return;
    }
 
 
    if (phFile)
    {
        *phFile = hFile;
    }
 
    return;
}
// 获取指定文件大小
ULONG MyGetFileSize(HANDLE hFile)
{
    IO_STATUS_BLOCK IoStatus;
    NTSTATUS status = STATUS_SUCCESS;
    FILE_STANDARD_INFORMATION Fileinfo; // 标准文件属性结构
 
 
    // 获取指定文件大小
    status = ZwQueryInformationFile(hFile, &IoStatus, &Fileinfo, sizeof(Fileinfo),
        FileStandardInformation); // 标准文件
    if (!NT_SUCCESS(status))
    {
        DbgPrint("文件信息查询失败!\n");
        return 0x0;
    }
 
 
    return Fileinfo.EndOfFile.LowPart;
}
// 读取文件到内存
VOID MyReadFile(HANDLE hFile, CHAR * Buffer, ULONG readSize)
{
    IO_STATUS_BLOCK IoStatus;
    NTSTATUS status = STATUS_SUCCESS;
 
 
    // 读取指定文件到内存中
    status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatus, Buffer, readSize, NULL, NULL);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("文件读取失败!\n");
        return;
    }
}
 
// 内存中拉伸PE文件
PUCHAR MemPEspread(PUNICODE_STRING DllName)
{
    HANDLE hFile = NULL;
    ULONG FileSize = 0x0;
    PUCHAR MemFile = NULL;
 
    // 打开文件
    MyOpenFile(&hFile, DllName);
    // 获取文件大小
    FileSize = MyGetFileSize(hFile);
    // 读取文件到指定内存
    // 创建文件缓冲区
    MemFile = (PUCHAR)ExAllocatePool(PagedPool, FileSize);
    MyReadFile(hFile, MemFile, FileSize);
 
    // 将其在内存中按PE格式拉伸
    // 判断是否为 PE 格式
    if (*(PSHORT)MemFile == 0x5A4D) // 判断 MZ 标志
    {
        // 获取 NT 头
        PUCHAR NtHeader = *(PULONG)(MemFile + 0x3C) + MemFile;
        // 判断 NT 头
        if (*(PULONG)NtHeader == 0x4550) // 判断 PE 标志
        {
            /*------------ 准备工作 ------------*/
            // 拉伸
            // 获取镜像大小
            ULONG SizeOfImage = *(PULONG)(NtHeader + 0x50);
            // 获取 PE 头大小
            ULONG SizeOfHeaders = *(PULONG)(NtHeader + 0x54);
            // 申请镜像空间
            PUCHAR MemImage = ExAllocatePool(NonPagedPool, SizeOfImage);
            if (!MmIsAddressValid(MemImage))
            {
                KdPrint(("MemImage Error\n"));
                return NULL;
            }
            /*------------ 拷贝 PE 头 ------------*/
            RtlCopyMemory(MemImage, MemFile, SizeOfHeaders);
            /*------------ 获取PE数据 ------------*/
            // 获取 NT 头
            PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)(((PIMAGE_DOS_HEADER)MemImage)->e_lfanew + MemImage);
            // 获取标准 PE 头
            PIMAGE_FILE_HEADER FileHeader = &NtHeader->FileHeader;
            // 获取可选 PE 头
            PIMAGE_OPTIONAL_HEADER OptionalHeader = &NtHeader->OptionalHeader;
            // 遍历节表
            // 获取可选PE头大小
            ULONG SizeOfOptional = FileHeader->SizeOfOptionalHeader;
            // 获取节的数量
            SHORT SectionNumber = FileHeader->NumberOfSections;
            // 获取节表位置 (NT 头标志 + 文件头 + 可选PE头)
            PUCHAR SectionBaseAddr = (PUCHAR)((PUCHAR)NtHeader + 0x4 + 0x14 + SizeOfOptional);
            PUCHAR pSectionBaseAddr = SectionBaseAddr;
            CHAR Name[0x9] = { 0x0 };        
            /*------------ 拷贝节 ------------*/
            for (int i = 0; i < SectionNumber; i++)
            {
                RtlCopyMemory(Name, pSectionBaseAddr, 0x8);
                KdPrint(("Name: %s\n", Name));
                // 拷贝到对于位置的镜像内存中
                ULONG PointerToRawData = *(PULONG)(pSectionBaseAddr + 0x14);
                ULONG SizeOfRawData = *(PULONG)(pSectionBaseAddr + 0x10);
                ULONG VirtualAddress = *(PULONG)(pSectionBaseAddr + 0xC);
 
 
                RtlCopyMemory(MemImage + VirtualAddress, MemFile + PointerToRawData, SizeOfRawData);
 
 
                pSectionBaseAddr += 0x28; // 下一个节
            }
            /*------------ 修复重定位表 ------------*/
            // 获取重定位表(处于数据目录表第6个)
            ULONG NumberOfRvaAndSizes = OptionalHeader->NumberOfRvaAndSizes; // 数据目录项个数
            PIMAGE_DATA_DIRECTORY DataDirArray = OptionalHeader->DataDirectory; // 数据目录表
            // 获取下标为 0x5 的数据目录
            PUCHAR RelocationVa = DataDirArray[0x5].VirtualAddress + MemImage; // 重定位地址
            PIMAGE_BASE_RELOCATION Relocationtable = (PIMAGE_BASE_RELOCATION)RelocationVa;
            PIMAGE_BASE_RELOCATION pRelocationtable = Relocationtable;
            // 循环修复重定位
            LONG BaseOffset = (LONG)MemImage - OptionalHeader->ImageBase;
            while (pRelocationtable->VirtualAddress || pRelocationtable->SizeOfBlock)
            {
                // 获取重定位项数据开始地址
                SHORT * pLocData =
                    (SHORT *)((ULONG)pRelocationtable + sizeof(IMAGE_BASE_RELOCATION));
                // 块的个数
                ULONG LocDataNumber = (pRelocationtable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;
                for (ULONG i = 0;
                    i < LocDataNumber;
                    i++)
                {
                    if ((pLocData[i] >> 12) == IMAGE_REL_BASED_HIGHLOW)
                    {
                        // 需要修复重定位
                        LONG * pAddr =
                            (LONG *)((pLocData[i] & 0x0FFF) + pRelocationtable->VirtualAddress + MemImage);
                        *pAddr += BaseOffset;
                        //KdPrint(("修复地址: %x\n", pAddr));
                    }
                }
 
 
                // 下一个重定位表
                pRelocationtable =
                    (PIMAGE_BASE_RELOCATION)((PUCHAR)pRelocationtable + pRelocationtable->SizeOfBlock);
            }
            ExFreePool(MemFile);
            return MemImage;
        }
    }
 
    return NULL;
}
 
// 获取操作系统分页模式
ULONG GetWindowsPageMode()
{
    ULONG PageMode = 0x1; // 默认为 2-9-9-12 分页
    __asm
    {
        _emit 0x0F;     // mov  eax, cr4;
        _emit 0x20;
        _emit 0xE0;
        test eax, 0x20; // 判断为什么分页模式
        jnz  End;
        // 为 10-10-12 分页
        mov  dword ptr[PageMode], 0x0;
    End:
        ;
    }
    return PageMode;
}
 
// 获取操作系统版本
ULONG GetWindowsVersion()
{
    RTL_OSVERSIONINFOW lpVersionInformation = { sizeof(RTL_OSVERSIONINFOW) };
    if (NT_SUCCESS(RtlGetVersion(&lpVersionInformation)))
    {
        ULONG dwMajorVersion = lpVersionInformation.dwMajorVersion;
        ULONG dwMinorVersion = lpVersionInformation.dwMinorVersion;
        if (dwMajorVersion == 5 && dwMinorVersion == 1)
        {
            return WINXP;
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 1)
        {
            return WIN7;
        }
        else if (dwMajorVersion == 6 && dwMinorVersion == 2)
        {
            return WIN8;
        }
        else if (dwMajorVersion == 10 && dwMinorVersion == 0)
        {
            return WIN10;
        }
    }
    return 0;
}
 
KIRQL irQl;
// 修改Cr0寄存器, 去除写保护(内存保护机制)
KIRQL RemovWP()
{
    DbgPrint("RemovWP\n");
    // (PASSIVE_LEVEL)提升 IRQL 等级为DISPATCH_LEVEL,并返回旧的 IRQL
    // 需要一个高的IRQL才能修改
    irQl = KeRaiseIrqlToDpcLevel();
    ULONG_PTR cr0 = __readcr0(); // 内联函数:读取Cr0寄存器的值, 相当于: mov eax,    cr0;
    // 将第16位(WP位)清0,消除写保护
    cr0 &= ~0x10000; // ~ 按位取反
    _disable(); // 清除中断标记, 相当于 cli 指令,修改 IF标志位
    __writecr0(cr0); // 将cr0变量数据重新写入Cr0寄存器中,相当于: mov cr0, eax
    DbgPrint("退出RemovWP\n");
    return irQl;
}
// 复原Cr0寄存器
KIRQL UndoWP()
{
    DbgPrint("UndoWP\n");
    ULONG_PTR cr0 = __readcr0();
    cr0 |= 0x10000; // WP复原为1
    _disable(); // 清除中断标记, 相当于 cli 指令,清空 IF标志位
    __writecr0(cr0); // 将cr0变量数据重新写入Cr0寄存器中,相当于: mov cr0, eax
    // 恢复IRQL等级
    KeLowerIrql(irQl);
    DbgPrint("退出UndoWP\n");
    return irQl;
}
 
// 修复 SSDT 表和 W32k 表
BOOLEAN InitKernelSsdtTable(PULONG KernelBaseAddr, PULONG NewKernelBaseAddr)
{
    //KdBreakPoint();
    if (GetWindowsVersion() == WINXP)
    {
        // 如果为 Xp 系统
        extern PSystemServiceTable KeServiceDescriptorTable; // 获取 XP导出的内核服务表
        if (!KeServiceDescriptorTable) return FALSE;
        // 获取影子表地址
        PSystemServiceTable KeServiceTable = KeServiceDescriptorTable;
        PSystemServiceTable KeServiceTableShadow =
            (PSystemServiceTable)((ULONG)KeServiceTable - 0x40);
        
        // 计算内核的偏差
        LONG Offset = (LONG)NewKernelBaseAddr - (LONG)KernelBaseAddr;
 
        // 获取当前新内核SSDT表的地址
        PSystemServiceTable NewKeServiceTable =
            (PSystemServiceTable)((ULONG)KeServiceTable + Offset);
 
        // 修正新内核的SSDT三张表的地址
        // 函数地址表
        NewKeServiceTable->FunctionsAddrTable =
            (PULONG)((ULONG)KeServiceTable->FunctionsAddrTable + Offset);
        // 函数参数表
        NewKeServiceTable->FunctionsArgsAddrTable =
            (PUCHAR)(KeServiceTable->FunctionsArgsAddrTable + Offset);
        // 服务函数调用次数表
        ;
        // 设置新SSDT表的服务个数
        NewKeServiceTable->FunctionsLimit = KeServiceTable->FunctionsLimit;
        // 修复 SSDT 函数表中的函数地址
        RemovWP();
 
        /*for (ULONG i = 0; i < NewKeServiceTable->FunctionsLimit; i++)
        {
            // 减去当前内核的加载基址
            NewKeServiceTable->FunctionsAddrTable[i] -= (ULONG)KernelBaseAddr;
            // 换上新内核的加载基址
            NewKeServiceTable->FunctionsAddrTable[i] += (ULONG)NewKernelBaseAddr;
        }*/
 
        UndoWP();
        //KdPrint(("NewKeServiceTable: %p\n", NewKeServiceTable));
 
        // 保存新内核函数地址
        // 保存新内核SSDT表地址
        newKernelMoudle = (ULONG)NewKernelBaseAddr;
        newSsdtTable = (ULONG)NewKeServiceTable;
    }
    
    return TRUE;
}
 
// 获取当前内核模块的基地址
ULONG GetCurrentKernelMoudleBaseAddr()
{
    ULONG DllBase = 0x0;
    ULONG viewSize = 0x0;
 
 
    KeSetSystemAffinityThread(1);
    __asm {
        push eax;
        push ebx;
        mov eax, fs:[0x34]; // 得到KdVersionBlock的地址
        add eax, 18h;       // 得到指向PsLoadedModuleList的地址
        mov eax, [eax];     // 得到PsLodedModuleList的地址
        mov eax, [eax];     // 取出PsLoadedModuleList里面的内容, 即KLDR_DATA_TABLE_ENTRY结构
        mov ebx, [eax + 18h]; // 取出DllBase, 即ntoskrnl.exe的基地址
        mov DllBase, ebx;
        mov ebx, [eax + 20h]; // 取出模块的大小
        mov viewSize, ebx;
        pop ebx;
        pop eax;
    }
    KeRevertToUserAffinityThread();//恢复线程运行的处理器
 
    return DllBase;
}
 
// 生成跳转的ShellCode
//++++++++++++++++++++++++++++
// ShellCode: 存储代码的容器
// TargetAddr: 要写入 ShellCode 的地址
// JmpAddr: 跳转的目标地址
//++++++++++++++++++++++++++++
// 返回 ShellCode 实际长度
ULONG CreateJmpShellCode(CHAR * ShellCode, ULONG TargetAddr, ULONG JmpAddr)
{
    ULONG CodeLen = 0;
    ULONG ShellCodeLen = 0;
    if (GetWindowsVersion() == WINXP)
    {
        // 如果为 XP
        CHAR GetJmpCode[0x5] = { 0xE9, 0x0, 0x0, 0x0, 0x0 };
        *(PVOID *)(&GetJmpCode[1]) = (PVOID)(JmpAddr - (TargetAddr + 5));
        CodeLen = sizeof(GetJmpCode);
        RtlMoveMemory(ShellCode, GetJmpCode, 0x5);
    }
    return CodeLen;
}
 
// 快速交换内存
ULONG DataLow = 0x0, DataHigh = 0x0;
VOID _declspec(naked) _fastcall FastSwapMemory(ULONG * TargetAddr, ULONG * SoulAddr)
{
    __asm
    {
        pushad;
        pushfd;
 
        mov esi, ecx; // 保存原来地址
        mov edi, edx;
        mov edx, 0x0;
        mov eax, 0x0;
        // 读取ShellCode
        lock CMPXCHG8B qword ptr[edi];
        mov DataLow, eax;
        mov DataHigh, edx;
        // 读取目标内存
        lock CMPXCHG8B qword ptr[esi];
        mov ebx, dword ptr[DataLow];
        mov ecx, dword ptr[DataHigh];
        // HOOK目标内存
        lock CMPXCHG8B qword ptr[esi];
 
        popfd;
        popad;
        retn;
    }
}
 
// 主函数
//++++++++++++++++++++++++++++
// hookAddr: 要Hook的地址
// hookFunctions: 你自己的Hook函数地址
// OriFun: 伪原函数地址
//++++++++++++++++++++++++++++
BOOLEAN InlineHook(ULONG hookAddr, ULONG hookFunctions, ULONG * OriFun)
{
    ULONG SystemVersion = GetWindowsVersion();
    switch (SystemVersion)
    {
    case WINXP:
        // 如果是 XP 系统
    {
        // 判断分页模式
        if (GetWindowsPageMode() == NormalPageMode)
        {
            // 为 2-9-9-12 分页
            CHAR MyJmpOverShellCode[ASMCODELEN] = { 0x90 , 0x90 , 0x90 , 0x90 ,  0x90 , 0x90 , 0x90 , 0x90 };
            CHAR MyJmpBackShellCode[ASMCODELEN] = { 0x90 , 0x90 , 0x90 , 0x90 ,  0x90 , 0x90 , 0x90 , 0x90 };
            ULONG TargetAddr = hookAddr;
            ULONG JmpAddr = hookFunctions;
            // 判断需要多少汇编指令长度
            ULONG RetAddr = 0x0; // 返回原来代码的地址
            ULONG AsmLen = ASMCODELEN;//GetAsmCodeLen(TargetAddr, &RetAddr);
            RetAddr = hookAddr + ASMCODELEN;
            // 获取JmpOverCode
            CreateJmpShellCode(MyJmpOverShellCode, TargetAddr, JmpAddr);
            // 构建返回的通道
            PVOID JmpBackShellCode = ExAllocatePool(NonPagedPool, AsmLen + ASMCODELEN);
            RtlZeroMemory(JmpBackShellCode, AsmLen + ASMCODELEN);
            // 获取JmpBackCode
            ULONG BackAddr = (ULONG)JmpBackShellCode + AsmLen;
            CreateJmpShellCode(MyJmpBackShellCode, BackAddr, RetAddr);
            // 读取Hook地址指定长度数据
            RtlCopyMemory(JmpBackShellCode, (PVOID)TargetAddr, AsmLen);
            // 添加返回通道
            RtlCopyMemory((PCHAR)JmpBackShellCode + AsmLen, (PVOID)MyJmpBackShellCode, ASMCODELEN);
            // 填写返回原函数的地址
            *OriFun = (ULONG)JmpBackShellCode;
            // InlineHook
            RemovWP();
            //KdBreakPoint();
            // Hook TargetAddr
            FastSwapMemory((PULONG)TargetAddr, (PULONG)MyJmpOverShellCode);
            UndoWP();
        }
    }
    break;
    }
    return TRUE;
}
 
// Hook KiFastCallEntry
VOID InstallHookKiFastCallEntry()
{
    ULONG  KiFastCallEntryBaseAddr = 0x0;
 
    // 找到KiFastCallEntry函数首地址
    __asm
    {
        ;// KiFastCallEntry函数地址保存
        ;// 在特殊模组寄存器的0x176号寄存器中
        push ecx;
        push eax;
        push edx;
 
        mov ecx, 0x176; // 设置编号
        rdmsr; // 读取到edx:eax
        mov KiFastCallEntryBaseAddr, eax; // 获取KiFastCallEntry函数地址
 
        pop edx;
        pop eax;
        pop ecx;
    }
 
    // 找到 Hook 地址, Hook它
    ULONG KiFastCallEntryHookAddr = KiFastCallEntryBaseAddr + 0xE6;
    InlineHook(KiFastCallEntryHookAddr, MyHookFun, &JmpBaseAddr);
}
 
// 返回对应新SSDT地址
ULONG GetNewKeServiceTable()
{
    return newSsdtTable;
}
// 返回对应新内核地址
ULONG GetNewKernelFunction()
{
    return newSsdtTable;
}
 
// 返回对应索引的新SSDT表函数地址
ULONG GetNewSsdtFunction(ULONG fIndex)
{
    PSystemServiceTable SsdtTable = (PSystemServiceTable)GetNewKeServiceTable();
    return ((ULONG)SsdtTable->FunctionsAddrTable + fIndex * 4);
}
 
// 主逻辑函数
BOOLEAN MyMain()
{
    UNICODE_STRING DllPath;
    PVOID DllBase = NULL;
    ULONG DllSize = 0x0;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    NTSTATUS status = STATUS_SUCCESS;
 
    // 判断加载的内核模块
    if (GetWindowsPageMode() == NormalPageMode)
    {
        // 为2-9-9-12分页
        RtlInitUnicodeString(&DllPath, L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
    }
    else
    {
        // 为10-10-12分页
        RtlInitUnicodeString(&DllPath, L"\\??\\C:\\WINDOWS\\system32\\ntoskrnl.exe");
    }
    // 获取内核模块基地址
    
    PUCHAR MemKelnelMoudle = MemPEspread(&DllPath);
    KdPrint(("MemFile: %x\n", MemKelnelMoudle));
 
    // Copy Table
    ULONG CurrentKernelBaseAddr = GetCurrentKernelMoudleBaseAddr();
    if (!CurrentKernelBaseAddr) {
        KdPrint(("CurrentKernelBaseAddr Error\n"));
        return FALSE;
    }
    // 初始化新的SSDT
    InitKernelSsdtTable((PULONG)CurrentKernelBaseAddr, (PULONG)MemKelnelMoudle);
 
    // 安装Hook
    InstallHookKiFastCallEntry();
 
    return TRUE;
}

FunctionsExpand.c 代码

#include "Header.h"
#include <ntimage.h> // PE模块定义Moudle
// 将指定模块映射到内存中
// DllFileName: 要映射的DLL文件路径名称
// phFile: 返回DLL文件的句柄
// phSection: 返回节的句柄
// pBaseAddress: DLL映射在此进程中的起始地址
// pviewSize: 映射在内存中的大小
NTSTATUS DllFileMap(UNICODE_STRING * pDllFileName, HANDLE * phFile,
        HANDLE * phSection, PVOID * pBaseAddress, SIZE_T * pviewSize)
{
        NTSTATUS status = STATUS_SUCCESS;
        OBJECT_ATTRIBUTES objectAttributes = { sizeof(OBJECT_ATTRIBUTES) };
        IO_STATUS_BLOCK iosb;
        // 打开DLL文件,并获取文件句柄
        InitializeObjectAttributes(&objectAttributes, pDllFileName,
               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
        status = ZwOpenFile(phFile, GENERIC_READ, &objectAttributes, &iosb,
               FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT);
        if (!NT_SUCCESS(status))
        {
               KdPrint(("ZwOpenFile: %X\n", status)); return status;
        }
        // 创建一个节对象,按照 PE 结构中的 SectionAlignment 大小对齐映射文件
        status = ZwCreateSection(phSection, SECTION_MAP_READ | SECTION_MAP_WRITE,
               NULL, 0, PAGE_READWRITE, 0x1000000, *phFile);
        if (!NT_SUCCESS(status))
        {
               KdPrint(("ZwCreateSection: %X\n", status)); return status;
        }
        // 映射到当前R0进程内存中
        status = ZwMapViewOfSection(*phSection, NtCurrentProcess(), pBaseAddress,
               0, 1024, 0, pviewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
        if (!NT_SUCCESS(status))
        {
               KdPrint(("ZwMapViewOfSection: %X\n", status)); return status;
        }
        return status;
}
// 根据索引获取对应的内核函数名称
void GetKernelMoudleFuncNameByIndex(ULONG fIndex, CHAR * bName)
{
        //KdBreakPoint();
        for (ULONG i = 0; (i < 256) && strlen(pNtdllInfoArray[i]->fName); i++)
        {
               if (pNtdllInfoArray[i]->fIndex == fIndex)
               {
                       RtlCopyMemory(bName, pNtdllInfoArray[i]->fName,  strlen(pNtdllInfoArray[i]->fName));
                       break;
               }
        }
}
// 获取所有函数名称对应的索引
PNtdllInfo GetAllFuncNameArray()
{
        // 映射内核模块到进程中
        HANDLE hFile = NULL;
        HANDLE hSection = NULL;
        SIZE_T viewSize = 0;
        UNICODE_STRING ModuleName =  RTL_CONSTANT_STRING(L"\\??\\C:\\WINDOWS\\system32\\ntdll.dll");
        NTSTATUS status = DllFileMap(&ModuleName, &hFile, &hSection, &ntdllBase,  &viewSize);
        // DosHeader
        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ntdllBase;
        // NtHeader
        PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew +  (PUCHAR)pDosHeader);
        // Export Table
        PIMAGE_EXPORT_DIRECTORY pExportTable =
               (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader +  pNtHeader->OptionalHeader.DataDirectory[0].VirtualAddress);
        // 导出函数名称的个数
        ULONG uNumberOfNames = pExportTable->NumberOfNames;
        // 导出函数名称地址表
        PULONG uNameArrayOfFun = (PULONG)(pExportTable->AddressOfNames +  (PUCHAR)pDosHeader);
        // 导出函数地址表
        PULONG uAddrArrayOfFun = (PULONG)(pExportTable->AddressOfFunctions +  (PUCHAR)pDosHeader);
        // 导出函数序号表
        PSHORT uOrdinalsArrayOfFun = (PSHORT)(pExportTable->AddressOfNameOrdinals +  (PUCHAR)pDosHeader);
        // 遍历导出表获取对应的函数名称
        PCHAR lpName = NULL;
        ULONG FunIndex = 0xFFFF;
        PUCHAR FunAddr = NULL;
        ULONG ArrayIndex = 0x0;
        RtlZeroMemory(pNtdllInfoArray, 0x550 * 4);
        for (ULONG i = 0; i < uNumberOfNames; i++)
        {
               // 获取函数名称
               lpName = (PCHAR)((PUCHAR)pDosHeader + uNameArrayOfFun[i]);
               // 获取函数地址
               FunAddr = (PUCHAR)(uAddrArrayOfFun[uOrdinalsArrayOfFun[i]] +  (PUCHAR)pDosHeader);
               // 获取对应的函数索引
               FunIndex = *(PULONG)(FunAddr + 1);
               if ((FunIndex > 0xFFFF) )/*|| !strstr(lpName, "Nt"))*/
               {
                       continue;
               }
               // 存储函数索引和名称
               PNtdllInfo ntdllInfo = (PNtdllInfo)ExAllocatePool(PagedPool,  sizeof(NtdllInfo));;
               ntdllInfo->fIndex = FunIndex;
               RtlZeroMemory(ntdllInfo->fName, 256);
               RtlCopyMemory(ntdllInfo->fName, lpName, strlen(lpName));
               KdPrint(("%s: %x\n", ntdllInfo->fName, ntdllInfo->fIndex));
               pNtdllInfoArray[ArrayIndex] = ntdllInfo;
               ArrayIndex++;
        }
        return (PNtdllInfo)pNtdllInfoArray;
}

原创文章,转载请注明: 转载自Windows内核安全驱动编程

本文链接地址: WinXp下的内核重载

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注