古月不傲 发表于 2020-1-20 16:01

xp内核重载 小实验

本帖最后由 古月不傲 于 2020-1-21 12:02 编辑

原理:
1.为物理地址扩展的 内核模块ntkrnlpa.exe申请一块新的SizeOfImage大小的内存
2.将ntkrnlpa.exe拉伸读取至新申请的内存
3.修复新申请的ntkrnlpa.exe重定位表
4.修复新申请的ntkrnlpa.exe系统服务表
5.在KiFastCallEntry关键部位加钩子
6.处理你感兴趣的程序 让它调用新的内核模块

测试通过

//测试代码
#include <ntddk.h>

//系统服务描述符表
typedef struct ServiceDescriptorEntry {
      unsigned int *ServiceTableBase;                        // 系统服务表基址
      unsigned int *ServiceCounterTableBase;      // 系统服务表被调用的次数
      unsigned int NumberOfServices;                        // 系统服务表函数个数
      unsigned char *ParamTableBase;                        // 系统服务表函数参数大小 (字节)
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

__declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable;

typedef NTSTATUS(NTAPI *PNewZwOpenProcess)(
      _Out_    PHANDLE            ProcessHandle,
      _In_   ACCESS_MASK      DesiredAccess,
      _In_   POBJECT_ATTRIBUTES ObjectAttributes,
      _In_opt_ PCLIENT_ID         ClientId
      );

ULONG32 g_uOldNtOpenProcess = 0;
ULONG32 g_uJmpPoint = 0;

// 关闭cr0读写位
void Cr0WpOff()
{
      __asm
      {
                cli
                moveax, cr0
                andeax, not 10000h
                movcr0, eax
      }
}

// 开启cr0读写位
void Cr0WpOn()
{
      __asm
      {
                moveax, cr0
                or eax, 10000h
                movcr0, eax
                sti
      }
}

VOID PrintTest()
{
      if (strstr((PCHAR)PsGetCurrentProcess() + 0x174, "notepad") != 0)
      {
                KdPrint(("记事本被Hook了\n"));
      }
}

__declspec(naked)
VOID HookFunc()
{
      __asm
      {
                pushad
                pushfd
                call PrintTest
                popfd
                popad

                push 0x0C4
                jmp g_uJmpPoint
      }
}

VOID HookNtOpenProcess()
{
      g_uOldNtOpenProcess = KeServiceDescriptorTable.ServiceTableBase;
      g_uJmpPoint = g_uOldNtOpenProcess + 5;
      UCHAR uJmp = { 0 };
      uJmp = 0xE9;
      *(PULONG32)&uJmp = (ULONG32)HookFunc - g_uOldNtOpenProcess - 5;

      Cr0WpOff();
      RtlCopyMemory((PVOID)g_uOldNtOpenProcess, uJmp, 5);
      Cr0WpOn();
}

//驱动卸载
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
      UCHAR uJmp = { 0x68, 0xc4, 0x00, 0x00, 0x00 };

      Cr0WpOff();
      RtlCopyMemory((PVOID)g_uOldNtOpenProcess, uJmp, 5);
      Cr0WpOn();
}

//驱动加载
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pStrRegPath)
{
      NTSTATUS ntStatus = STATUS_SUCCESS;
      pDriverObject->DriverUnload = DriverUnload;
      HookNtOpenProcess();
      return ntStatus;
}

//内核重载代码
#pragma once

#include <ntddk.h>
#include "PE.h"

//系统服务描述符表
typedef struct ServiceDescriptorEntry {
      unsigned int *ServiceTableBase;                        // 系统服务表基址
      unsigned int *ServiceCounterTableBase;      // 系统服务表被调用的次数
      unsigned int NumberOfServices;                        // 系统服务表函数个数
      unsigned char *ParamTableBase;                        // 系统服务表函数参数大小 (字节)
}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

__declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable;

ServiceDescriptorTableEntry *g_pNewKeServiceDescriptorTable;
ServiceDescriptorTableEntry *g_qNewKeServiceDescriptorTable;

typedef NTSTATUS(NTAPI *PNewZwOpenProcess)(
      _Out_    PHANDLE            ProcessHandle,
      _In_   ACCESS_MASK      DesiredAccess,
      _In_   POBJECT_ATTRIBUTES ObjectAttributes,
      _In_opt_ PCLIENT_ID         ClientId
      );

typedef struct _PE
{
      IMAGE_DOS_HEADER DosHeader;
      IMAGE_NT_HEADERS32 NtHeaders;
      IMAGE_SECTION_HEADER SectionHeader;
}PE, *pPE;

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pStrRegPath);
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
ULONG32 GetKernelImageBase();
PVOID GetNewKernelBuffer(PUNICODE_STRING pStrKernelPathName);
VOID RepirRelocTable(ULONG32 uNewModule, ULONG32 uOldModule);
VOID HookKiFastCallEntry();
ULONG32 SearchHookPoint(PULONG32 pHookAddress);
VOID CallZwOpenProcess();
VOID BeginHook(ULONG32 g_uHookAddress);
VOID RepirSSDT(ULONG32 pNewKernelBuffer, ULONG32 uKernelImageBase);


#pragma once

#include "KernelOverload.h"


// 关闭cr0读写位
void Cr0WpOff()
{
      __asm
      {
                cli
                moveax, cr0
                andeax, not 10000h
                movcr0, eax
      }
}

// 开启cr0读写位
void Cr0WpOn()
{
      __asm
      {
                moveax, cr0
                or eax, 10000h
                movcr0, eax
                sti
      }
}

//找到要Hook的点
ULONG32 SearchHookPoint(PULONG32 pRetAddress)
{
      if (pRetAddress == NULL)
      {
                return -1;
      }
      PUCHAR pAddress = (PUCHAR)pRetAddress;
      for (ULONG32 uCount = 0; uCount < 500; uCount++, pAddress--)
      {
                if ((*(pAddress) == 0x2b &&
                        *(pAddress + 1) == 0xe1 &&
                        *(pAddress + 2) == 0xc1 &&
                        *(pAddress + 3) == 0xe9 &&
                        *(pAddress + 4) == 0x02))
                {
                        return (ULONG32)pAddress;
                }
      }
      return -2;
}

//立刻调用ZwOpenProcess让钩子生效
VOID CallZwOpenProcess()
{
      NTSTATUS ntStatus = 0;
      HANDLE hPorcess = NULL;
      UNICODE_STRING strProcessName = { 0 };
      OBJECT_ATTRIBUTES objAttr = { 0 };
      RtlInitUnicodeString(&strProcessName, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe");
      InitializeObjectAttributes(&objAttr, &strProcessName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
      CLIENT_ID clientId = { 0 };
      ntStatus = ZwOpenProcess(&hPorcess, GENERIC_READ, &objAttr, &clientId);
      if (!NT_SUCCESS(ntStatus))
      {
                KdPrint(("SearchKiFastCallEntry() ZwCreateFile unsuccessed!\n"));
                return;
      }
      ZwClose(hPorcess);
}

// 获取内核模块基址
ULONG32 GetKernelImageBase()
{
      ULONG32 uKernelImageBase = 0;
      _asm
      {
                pusheax
                mov   eax, fs:
                add   eax, 0x18
                mov   eax,
                mov   eax,
                mov   eax,
                mov   uKernelImageBase, eax
                popeax
      }
      return uKernelImageBase == 0 ? 0 : uKernelImageBase;
}

// 获取新的内核模块虚拟缓存
PVOID GetNewKernelBuffer(PUNICODE_STRING pStrKernelPathName)
{
      PE pe = { 0 };
      HANDLE hFile = NULL;
      OBJECT_ATTRIBUTES objectAttributes = { 0 };
      IO_STATUS_BLOCK ioStatusBlock = { 0 };
      InitializeObjectAttributes(&objectAttributes, pStrKernelPathName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
      NTSTATUS ntStatus = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
                FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE, NULL, 0);
      if (!NT_SUCCESS(ntStatus))
      {
                KdPrint(("ZwCreateFile错误:%x\n", ntStatus));
                return NULL;
      }
      LARGE_INTEGER fileOffset = { 0 };
      fileOffset.QuadPart = 0;
      //读取DOS头
      ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, &pe.DosHeader, sizeof(IMAGE_DOS_HEADER), &fileOffset, NULL);
      if (!NT_SUCCESS(ntStatus))
      {
                KdPrint(("ZwReadFile错误:%x\n", ntStatus));
                return NULL;
      }
      fileOffset.QuadPart += pe.DosHeader.e_lfanew;
      //读取NT头
      ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, &pe.NtHeaders, sizeof(IMAGE_NT_HEADERS32), &fileOffset, NULL);
      if (!NT_SUCCESS(ntStatus))
      {
                KdPrint(("ZwReadFile错误:%x\n", ntStatus));
                return NULL;
      }
      PVOID pNewBuffer = ExAllocatePool(NonPagedPool, pe.NtHeaders.OptionalHeader.SizeOfImage);
      if (pNewBuffer == NULL)
      {
                KdPrint(("pNewBuffer错误\n"));
                return NULL;
      }
      PVOID pTempBuffer = pNewBuffer;
      RtlCopyMemory(pTempBuffer, &pe.DosHeader, sizeof(IMAGE_DOS_HEADER));
      pTempBuffer = (PVOID)((ULONG32)pTempBuffer + pe.DosHeader.e_lfanew);
      RtlCopyMemory(pTempBuffer, &pe.NtHeaders, sizeof(IMAGE_NT_HEADERS32));
      fileOffset.QuadPart += sizeof(IMAGE_NT_HEADERS32);
      pTempBuffer = (PVOID)((ULONG32)pTempBuffer + sizeof(IMAGE_NT_HEADERS32));
      //读取节表
      ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, pTempBuffer, (sizeof(IMAGE_SECTION_HEADER) * pe.NtHeaders.FileHeader.NumberOfSections), &fileOffset, NULL);
      if (!NT_SUCCESS(ntStatus))
      {
                KdPrint(("ZwReadFile错误:%x\n", ntStatus));
                return NULL;
      }
      PIMAGE_SECTION_HEADER pTempSectionHeader = pTempBuffer;

      //读取节内容
      for (ULONG32 uCount = 0; uCount < pe.NtHeaders.FileHeader.NumberOfSections; uCount++)
      {
                pTempBuffer = (PVOID)((ULONG32)pNewBuffer + pTempSectionHeader->VirtualAddress);
                fileOffset.QuadPart = pTempSectionHeader->PointerToRawData;
                ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatusBlock, pTempBuffer, pTempSectionHeader->SizeOfRawData, &fileOffset, NULL);
                if (!NT_SUCCESS(ntStatus))
                {
                        KdPrint(("ZwReadFile错误:%x\n", ntStatus));
                        return NULL;
                }
                pTempSectionHeader++;
      }
      return pNewBuffer;
}



#include "KernelOverload.h"
#include "BaseFunctions.h"

PVOID      g_pNewKernelBuffer = NULL;
ULONG32 g_uOldNtOpenProcessFuncAddress = 0;
ULONG32 g_uHookAddress = 0;
ULONG32 g_uJmpAdress = 0;
ULONG32 g_uOffset = 0;

//驱动加载
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pStrRegPath)
{
      NTSTATUS ntStatus = STATUS_SUCCESS;
      pDriverObject->DriverUnload = DriverUnload;
      //获取内核模块基址
      ULONG32 uKernelImageBase = GetKernelImageBase();
      KdPrint(("uKernelImageBase:%08x\n", uKernelImageBase));
      // 获取新的内核模块虚拟缓存
      UNICODE_STRING strKernelPathName = RTL_CONSTANT_STRING(L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
      PVOID pNewKernelBuffer = GetNewKernelBuffer(&strKernelPathName);
      if (!MmIsAddressValid(pNewKernelBuffer))
      {
                KdPrint(("pNewKernelBuffer无效!\n"));
                return STATUS_UNSUCCESSFUL;
      }
      KdPrint(("pNewKernelBuffer:%08x\n", pNewKernelBuffer));
      g_pNewKernelBuffer = pNewKernelBuffer;
      //基址重定位
      RepirRelocTable((ULONG32)pNewKernelBuffer, uKernelImageBase);
      g_uOffset = (ULONG32)pNewKernelBuffer - uKernelImageBase;
      //系统服务表重定位
      RepirSSDT((ULONG32)pNewKernelBuffer, uKernelImageBase);
      KdPrint(("g_uOffset:%08x\n", g_uOffset));
      //对KiFastCallEntry加钩子
      HookKiFastCallEntry();
      return ntStatus;
}

//驱动卸载
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
      //卸载新的模块
      if (g_pNewKernelBuffer)
      {
                ExFreePool(g_pNewKernelBuffer);
                g_pNewKernelBuffer = NULL;
      }
      UCHAR uJmp = { 0x2b, 0xe1, 0xc1, 0xe9, 0x02 };

      Cr0WpOff();
      RtlCopyMemory((PVOID)g_uHookAddress, uJmp, 5);
      Cr0WpOn();
}


//修复重定位表
VOID RepirRelocTable(ULONG32 uNewModule, ULONG32 uOldModule)
{
      PIMAGE_DOS_HEADER pDosHeader = NULL;
      PIMAGE_NT_HEADERS32 pNtHeaders = NULL;
      PIMAGE_BASE_RELOCATION pRelocation = NULL;
      PIMAGE_DATA_DIRECTORY pData = NULL;

      pDosHeader = (PIMAGE_DOS_HEADER)uNewModule;
      pNtHeaders = (PIMAGE_NT_HEADERS32)((ULONG32)pDosHeader + pDosHeader->e_lfanew);
      pData = pNtHeaders->OptionalHeader.DataDirectory;
      //定位重定位表
      pRelocation = (PIMAGE_BASE_RELOCATION)((ULONG32)uNewModule + pData.VirtualAddress);
      //由于新的内核里面的全局变量地址都是用的老的 所以要加上它们之间的偏移量 就等于我们新的内核全局变量地址
      ULONG32 uOffset = uOldModule - pNtHeaders->OptionalHeader.ImageBase;
      while (pRelocation->VirtualAddress != 0 && pRelocation->SizeOfBlock != 0)
      {
                ULONG32 uNumOfRelocs = (pRelocation->SizeOfBlock - 8) / 2;
                PUSHORT pUShort = (PUSHORT)((ULONG32)pRelocation + 8);
                for (ULONG32 uCount = 0; uCount < uNumOfRelocs; uCount++, pUShort++)
                {
                        if (((*pUShort) >> 12) == 3)
                        {
                              PULONG32 pUlong32 = (PULONG32)((*pUShort & 0x0FFF) + pRelocation->VirtualAddress + uNewModule);
                              *pUlong32 += uOffset;
                        }      
                }
                pRelocation = (PIMAGE_BASE_RELOCATION)((ULONG32)pRelocation + pRelocation->SizeOfBlock);
      }
}

//修复新的系统服务表
VOID RepirSSDT(ULONG32 pNewKernelBuffer, ULONG32 uKernelImageBase)
{
      g_pNewKeServiceDescriptorTable = (PServiceDescriptorTableEntry)((ULONG32)&KeServiceDescriptorTable + g_uOffset);
      g_pNewKeServiceDescriptorTable->NumberOfServices = KeServiceDescriptorTable.NumberOfServices;
      ULONG32 uOffset = ((ULONG32)KeServiceDescriptorTable.ServiceTableBase - uKernelImageBase);
      g_pNewKeServiceDescriptorTable->ServiceTableBase = (PULONG32)(pNewKernelBuffer + uOffset);
      for (ULONG32 uCount = 0; uCount < g_pNewKeServiceDescriptorTable->NumberOfServices; uCount++)
      {
                g_pNewKeServiceDescriptorTable->ServiceTableBase += g_uOffset;
      }
      uOffset = ((ULONG32)KeServiceDescriptorTable.ServiceCounterTableBase - uKernelImageBase);
      g_pNewKeServiceDescriptorTable->ServiceCounterTableBase = (PULONG32)(pNewKernelBuffer + uOffset);
      uOffset = ((ULONG32)KeServiceDescriptorTable.ParamTableBase - uKernelImageBase);
      g_pNewKeServiceDescriptorTable->ParamTableBase = (PCHAR)(pNewKernelBuffer + uOffset);
      RtlCopyMemory(g_pNewKeServiceDescriptorTable->ParamTableBase, KeServiceDescriptorTable.ParamTableBase, g_pNewKeServiceDescriptorTable->NumberOfServices);
      g_qNewKeServiceDescriptorTable = g_pNewKeServiceDescriptorTable;
}

//过滤函数
ULONG32 FilterFunc(ULONG32 uKeServiceTableBase, ULONG32 uIndex, ULONG32 uOldKiFastCallEntry)
{
      if (uKeServiceTableBase == (ULONG32)KeServiceDescriptorTable.ServiceTableBase)
      {
                if (strstr((PCHAR)PsGetCurrentProcess() + 0x174, "notepad") != 0)
                {
                        return g_qNewKeServiceDescriptorTable->ServiceTableBase;
                }
      }
      return uOldKiFastCallEntry;
}

//钩子函数
__declspec(naked)
VOID HookFunc()
{
      __asm
      {
                pushad
                pushfd
                // mov   ebx,dword ptr
                push ebx      //函数地址
                push eax      //函数下标
                push edi      //系统服务表基址
                call FilterFunc                //内平栈
                //50 push eax                        
                //51 push ecx
                //52 push edx
                //53 push ebx      esp + 0x14
                //54 push esp
                //55 push ebp
                //56 push esi
                //57 push edi
                //push eflag
                mov dword ptr ss:, eax

                popfd
                popad

                sub esp, ecx
                shr ecx, 2
                jmp g_uJmpAdress
      }
}

//开始加钩子
VOID BeginHook(ULONG32 g_uHookAddress)
{
      UCHAR uJmp = { 0 };
      uJmp = 0xE9;
      ULONG32 uJmpAddress = (ULONG32)HookFunc - g_uHookAddress - 5;
      *(PULONG32)&uJmp = uJmpAddress;

      Cr0WpOff();
      RtlCopyMemory((PVOID)g_uHookAddress, uJmp, 5);
      Cr0WpOn();
}

//新的ZwOpenProcess
NTSTATUS NewZwOpenProcess(
      _Out_    PHANDLE            ProcessHandle,
      _In_   ACCESS_MASK      DesiredAccess,
      _In_   POBJECT_ATTRIBUTES ObjectAttributes,
      _In_opt_ PCLIENT_ID         ClientId
)
{
      ULONG32 uRetAddress = 0;
      // 获取返回地址
      __asm
      {
                pushad;
                mov eax, dword ptr ss : ;
                mov uRetAddress, eax;
                popad;
      }
      //找到Hook点
      g_uHookAddress = SearchHookPoint((PULONG32)uRetAddress);
      //mov   edi,esp
      //cmp   esi,dword ptr       g_uJmpAdress = g_uHookAddress + 5;
      //开始Hook
      BeginHook(g_uHookAddress);
      //恢复原来的NtOpenProcess      //不恢复将会造成死循环 无止尽执行新的NtOpenProcess
      Cr0WpOff();
      KeServiceDescriptorTable.ServiceTableBase = g_uOldNtOpenProcessFuncAddress;
      Cr0WpOn();

      return ((PNewZwOpenProcess)g_uOldNtOpenProcessFuncAddress)(
                ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}

//Hook入口
VOID HookKiFastCallEntry()
{
      Cr0WpOff();
      // 保存原来的NewZwOpenProcess
      g_uOldNtOpenProcessFuncAddress = KeServiceDescriptorTable.ServiceTableBase;
      // 设置新的NewZwOpenProcess
      KeServiceDescriptorTable.ServiceTableBase = (ULONG32)NewZwOpenProcess;
      Cr0WpOn();
      // 立即调用ZwOpenProcess跳转到Hook的新的ZwOpenProcess
      CallZwOpenProcess();
}

coolcalf 发表于 2020-1-20 16:19

不明觉厉

2623666 发表于 2020-1-20 16:23

不知道是什么厉害啊

zxywan 发表于 2020-1-20 16:24

不明觉厉

tjkvvv 发表于 2020-1-20 16:25

看不懂不知道什么意思

keweiye 发表于 2020-1-20 16:37

这个什么用?不重启计算机而重启系统?

Bustle 发表于 2020-1-20 17:01

看晕了,O(∩_∩)O哈哈~

lcsdxx 发表于 2020-1-20 17:06

看不懂技术贴,哈哈哈

哥比彩砖还炫 发表于 2021-2-20 09:11

这几天我也在写内核重载,过几天我也发一个不一样的版本一起学习
页: [1]
查看完整版本: xp内核重载 小实验