吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3291|回复: 8
收起左侧

[C&C++ 原创] xp内核重载 小实验

[复制链接]
古月不傲 发表于 2020-1-20 16:01
本帖最后由 古月不傲 于 2020-1-21 12:02 编辑

[C] 纯文本查看 复制代码
原理:
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
                mov  eax, cr0
                and  eax, not 10000h
                mov  cr0, eax
        }
}

// 开启cr0读写位
void Cr0WpOn()
{
        __asm
        {
                mov  eax, cr0
                or eax, 10000h
                mov  cr0, 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[122];
        g_uJmpPoint = g_uOldNtOpenProcess + 5;
        UCHAR uJmp[5] = { 0 };
        uJmp[0] = 0xE9;
        *(PULONG32)&uJmp[1] = (ULONG32)HookFunc - g_uOldNtOpenProcess - 5;

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

//驱动卸载
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
        UCHAR uJmp[5] = { 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
                mov  eax, cr0
                and  eax, not 10000h
                mov  cr0, eax
        }
}

// 开启cr0读写位
void Cr0WpOn()
{
        __asm
        {
                mov  eax, cr0
                or eax, 10000h
                mov  cr0, 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
        {
                push  eax
                mov   eax, fs:[0x34]
                add   eax, 0x18
                mov   eax, [eax]
                mov   eax, [eax]
                mov   eax, [eax + 0x18]
                mov   uKernelImageBase, eax
                pop  eax
        }
        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[5] = { 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[5].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[uCount] += 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[uIndex];
                }
        }
        return uOldKiFastCallEntry;
}

//钩子函数
__declspec(naked)
VOID HookFunc()
{
        __asm
        {
                pushad
                pushfd
                // mov     ebx,dword ptr [edi+eax*4]
                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:[esp + 0x14], eax

                popfd
                popad

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

//开始加钩子
VOID BeginHook(ULONG32 g_uHookAddress)
{
        UCHAR uJmp[5] = { 0 };
        uJmp[0] = 0xE9;
        ULONG32 uJmpAddress = (ULONG32)HookFunc - g_uHookAddress - 5;
        *(PULONG32)&uJmp[1] = 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 : [ebp + 0x4];
                mov uRetAddress, eax;
                popad;
        }
        //找到Hook点
        g_uHookAddress = SearchHookPoint((PULONG32)uRetAddress);
        //mov     edi,esp
        //cmp     esi,dword ptr [nt!MmUserProbeAddress (80563134)]        g_uJmpAdress = g_uHookAddress + 5;
        //开始Hook
        BeginHook(g_uHookAddress);
        //恢复原来的NtOpenProcess        //不恢复将会造成死循环 无止尽执行新的NtOpenProcess
        Cr0WpOff();
        KeServiceDescriptorTable.ServiceTableBase[122] = g_uOldNtOpenProcessFuncAddress;
        Cr0WpOn();

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

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

免费评分

参与人数 2威望 +1 吾爱币 +5 热心值 +2 收起 理由
苏紫方璇 + 1 + 5 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lx7399 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

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
这几天我也在写内核重载,过几天我也发一个不一样的版本一起学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-22 00:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表