ring0 SSDTHook 实现x64/x86

#include "HookSSDT.h"
#include <ntimage.h>

#define SEC_IMAGE  0x001000000

ULONG32 __NtOpenProcessIndex = 0;
PVOID   __ServiceTableBase = NULL;
ULONG32 __OldNtOpenProcessOffset = 0;
PVOID   __OldNtOpenProcess  = NULL;
UCHAR   __OldCode[15] = {0};
BOOLEAN __IsHook = FALSE;
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG32  v1 = 0;
    char FunctionName[] = "NtOpenProcess";
    ULONG64 SSDTAddress = 0;
    DriverObject->DriverUnload = DriverUnload;

    if (GetSSDTAddress(&SSDTAddress) == FALSE)
    {
        return Status;
    }

    DbgPrint("Win7x64 SSDT:%p\r\n", SSDTAddress);

    //寻找23H

    if (GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(FunctionName,
        &__NtOpenProcessIndex) == FALSE)
    {
        return STATUS_UNSUCCESSFUL;
    }

    __ServiceTableBase = ((PSERVER_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->Unknow0;
    __OldNtOpenProcessOffset = ((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex];
    v1 = __OldNtOpenProcessOffset >> 4;
    __OldNtOpenProcess = (PVOID)((ULONG64)__ServiceTableBase + v1);
    HookSSDT(__ServiceTableBase,__NtOpenProcessIndex,FakeOpenProcess,KeBugCheckEx,5,__OldCode,15);
    return Status;
}

BOOLEAN GetSSDTAddress(ULONG64* SSDTAddress)
{
    //kd>  rdmsr c0000082
    PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
    PUCHAR EndSearchAddress = StartSearchAddress + PAGE_SIZE;
    PUCHAR i = NULL;
    UCHAR   v1 = 0, v2 = 0, v3 = 0;
    INT64   Offset = 0;    //002320c7
    ULONG64 VariableAddress = 0;
    *SSDTAddress = NULL;
    for (i = StartSearchAddress; i < EndSearchAddress; i++)
    {
        if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
        {
            v1 = *i;
            v2 = *(i + 1);
            v3 = *(i + 2);
            if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
            {
                memcpy(&Offset, i + 3, 4);
                *SSDTAddress = Offset + (ULONG64)i + 7;
                break;
            }
        }
    }
    //Win32 导出表 搜索  KeServiceDescriptorTable
    if (*SSDTAddress == NULL)
    {
        return FALSE;
    }

    return TRUE;
}
BOOLEAN GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(CHAR* FunctionName,ULONG32* SSDTFunctionIndex)
{
    /*
    0:004> u zwopenprocess
    ntdll!NtOpenProcess:
    00000000`774ddc10 4c8bd1          mov     r10,rcx
    00000000`774ddc13 b823000000      mov     eax,23h
    00000000`774ddc18 0f05            syscall
    00000000`774ddc1a c3              ret
    00000000`774ddc1b 0f1f440000      nop     dword ptr [rax+rax]
    */

    ULONG    i;
    BOOLEAN  IsOk = FALSE;
    WCHAR     FileFullPath[] = L"\\SystemRoot\\System32\\ntdll.dll";     //C:\Windows\
    SIZE_T   MappingViewSize = 0;
    PVOID    MappingBaseAddress = NULL;
    PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
    PIMAGE_NT_HEADERS  NtHeader = NULL;
    UINT32*  AddressOfFunctions = NULL;
    UINT32*  AddressOfNames = NULL;
    UINT16*  AddressOfNameOrdinals = NULL;
    CHAR*    v1        = NULL;
    ULONG32  FunctionOrdinal = 0;
    PVOID    FunctionAddress = 0;
    ULONG32  Offset_SSDTFunctionIndex = 4;
    //将Ntdll.dll 当前的空间中

    *SSDTFunctionIndex = -1;
    IsOk = MappingPEFileInRing0Space(FileFullPath,&MappingBaseAddress, &MappingViewSize);
    if (IsOk==FALSE)
    {
        return FALSE;
    }
    else
    {
        __try{
            NtHeader = RtlImageNtHeader(MappingBaseAddress);   //extern
            if (NtHeader && NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
            {
                ImageExportDirectory =(IMAGE_EXPORT_DIRECTORY*)((UINT8*)MappingBaseAddress +
                    NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

                //AddressOfFunctions 指向函数地址数组
                AddressOfFunctions = (UINT32*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
                AddressOfNames = (UINT32*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);
                AddressOfNameOrdinals = (UINT16*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
                for(i = 0; i < ImageExportDirectory->NumberOfNames; i++)
                {
                    v1 = (char*)((ULONG64)MappingBaseAddress + AddressOfNames[i]);   //获得函数名称
                    if (_stricmp(FunctionName, v1) == 0)
                    {
                        FunctionOrdinal = AddressOfNameOrdinals[i];
                        FunctionAddress = (PVOID)((UINT8*)MappingBaseAddress + AddressOfFunctions[FunctionOrdinal]);

                        *SSDTFunctionIndex = *(ULONG32*)((UINT8*)FunctionAddress+Offset_SSDTFunctionIndex);
                        break;
                    }
                }
            }
        }__except(EXCEPTION_EXECUTE_HANDLER)
        {
            ;
        }
    }

    ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);  //解除映射

    if (*SSDTFunctionIndex==-1)
    {
        return FALSE;
    }

    return TRUE;
}
BOOLEAN
MappingPEFileInRing0Space(WCHAR* FileFullPath,PVOID* MappingBaseAddress, PSIZE_T MappingViewSize)
{

    NTSTATUS          Status;
    UNICODE_STRING    v1;
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK   IoStatusBlock;
    HANDLE   FileHandle = NULL;
    HANDLE   SectionHandle = NULL;

    if (!FileFullPath &&MmIsAddressValid(FileFullPath))
    {
        return FALSE;
    }

    if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
    {
        return FALSE;
    }

    RtlInitUnicodeString(&v1, FileFullPath);
    //初始化一个OBJECT_ATTRIBUTES结构体ObjectAttributes,它指定对象句柄的属性,供打开句柄的例程使用。
    //驱动程序运行进程上下文中,若要运行在系统进程,需要设置OBJ_KERNEL_HANDLE标志到Attributes参数。
    //OBJ_KERNEL_HANDLE标志限制,使用此打开的句柄的进程仅能运行在内核模式。否则句柄可以在驱动运行的进程上下文中访问。

    InitializeObjectAttributes(&ObjectAttributes,
        &v1,
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL,
        NULL
    );

    //传递ObjectAttributes结构的指针到实际打开句柄的例程
    //获得文件句柄
    Status = IoCreateFile(&FileHandle,
        GENERIC_READ | SYNCHRONIZE,
        &ObjectAttributes,   //文件绝对路径
        &IoStatusBlock,
        NULL,
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_READ,
        FILE_OPEN,
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,
        0,
        CreateFileTypeNone,
        NULL,
        IO_NO_PARAMETER_CHECKING
    );
    if (!NT_SUCCESS(Status))
    {
        return FALSE;
    }

    ObjectAttributes.ObjectName = NULL;
    //创建一个Section Object ,即共享内存
    Status = ZwCreateSection(&SectionHandle,
        SECTION_QUERY | SECTION_MAP_READ,
        &ObjectAttributes,
        NULL,
        PAGE_WRITECOPY,
        SEC_IMAGE, //内存对齐  0x1000
        FileHandle
    );
    /*NTSTATUS   ZwCreateSection(
    OUT PHANDLE SectionHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN PLARGE_INTEGER MaximumSize OPTIONAL,
    IN ULONG SectionPageProtection,
    IN ULONG AllocationAttributes,
    IN HANDLE FileHandle OPTIONAL
);*/
    ZwClose(FileHandle);
    if (!NT_SUCCESS(Status))
    {
        return FALSE;
    }
    //生成一个可以访问的MappingBaseAddress
    Status = ZwMapViewOfSection(SectionHandle,
        NtCurrentProcess(),    //映射到当前进程的内存空间中
        MappingBaseAddress,
        0,
        0,
        0,
        MappingViewSize,
        ViewUnmap,
        0,
        PAGE_WRITECOPY
    );
    ZwClose(SectionHandle);
    if (!NT_SUCCESS(Status))
    {
        return FALSE;
    }
    return TRUE;
}
VOID HookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex,PVOID FakeFunctionAddress,
              PVOID OldFunctionAddress,ULONG32 OldFunctionParameterCount,UCHAR* OldFunctionCode,ULONG32 PatchCodeLength)
{
    //寻找一个内核不常用的函数(KeBugCheckEx) 进行InlineHook使其跳转到Fake_NtOpenProcess函数
    ULONG32  v1 = 0;

    WPOFF();
    //          KeBugCheckEx
    //                       mov rax,10    Jmp  Fake  15
    //                         mov rbx,rax
    InlineHook(OldFunctionAddress, FakeFunctionAddress, OldFunctionCode, PatchCodeLength);
    WPON();

    //寻找一个内核不常用的函数(KeBugCheckEx) 计算SSDT中的偏移 进行置换

    v1 = CalcFunctionOffsetInSSDT(ServiceTableBase,OldFunctionAddress, OldFunctionParameterCount);

    WPOFF();
    ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)v1;
    WPON();

    __IsHook = TRUE;
}
VOID
UnHookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex,ULONG32 OldFunctionOffset,PVOID OldFunctionAddress,
    UCHAR* OldFunctionCode,ULONG32 PatchCodeLength)
{

    WPOFF();
    UnInlineHook(OldFunctionAddress, OldFunctionCode, PatchCodeLength);
    WPON();

    WPOFF();
    ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionOffset;
    WPON();
}

VOID InlineHook(ULONG64 OldFunctionAddress, ULONG64 FakeFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{

    ULONG64  v1 = 0;
    UCHAR    PatchCode[] = "\xFF\x25\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";   //InlineHook  Jmp 函数地址
    v1 = FakeFunctionAddress;
    memcpy(OldFunctionCode, (PVOID)OldFunctionAddress, PatchCodeLength);   //保存原先函数的指令
    memcpy(PatchCode + 6, &v1, 8);

    memset((PVOID)OldFunctionAddress, 0x90, PatchCodeLength);   //打补丁   NOP = 0x90
    memcpy((PVOID)OldFunctionAddress, PatchCode, 14);
}
VOID  UnInlineHook(PVOID OldFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
{
    memcpy((PVOID)OldFunctionAddress, OldFunctionCode, PatchCodeLength);
}

ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress,ULONG32 ParameterCount)
{
    //v1 :   INT8 Temp = 0
    CHAR v1 = 0;
    CHAR   Bits[4] = {0};
    ULONG32 v2 = 0,i;
    v2 = (ULONG32)((ULONG64)FunctionAddress-(ULONG64)ServiceTableBase);
    v2 = v2<<4;    //0110  0001    a1  ---->  0001  0000
    if(ParameterCount>4)
    {
        ParameterCount = ParameterCount-4;     //NtReadFile  9个参数
    }
    else
    {
        ParameterCount = 0;
    }

    memcpy(&v1,&v2,1);
    //处理低四位,填写参数个数   如果一个函数的参数为5 那么dwTemp的低4位就是 0001  如果参数是6 就是0002 因为 6要减4 

#define SETBIT(x,y) x|=(1<<y)         //将X的第Y位置1
#define CLRBIT(x,y) x&=~(1<<y)        //将X的第Y位清0
#define GETBIT(x,y) (x & (1 << y))    //取X的第Y位,返回0或非0

    for(i=0;i<4;i++)    //一个16进制 4个二进制      0000
    {
        Bits[i]=GETBIT(ParameterCount,i);
        if(Bits[i])
        {
            SETBIT(v1,i);
        }
        else
        {
            CLRBIT(v1,i);
        }
    }
    /*
    ulParamCount    i        Bits[i]    b       i       b
    0101            0         1          0000     0      0001   set
    0101            1         0          0001     1      0001   clr
    0101            2         1          0001     2      0101   set
    0101            3         0          0101     3      0101   clr

    */
    //把数据复制回去
    memcpy(&v2,&v1,1);
    return v2;
}

NTSTATUS FakeOpenProcess(
    _Out_    PHANDLE            ProcessHandle,
    _In_     ACCESS_MASK        DesiredAccess,
    _In_     POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID         ClientID)
{

    //EnumProcessByForce.exe
    //OpenProcess---->Ntdll(ZwOpenProcess  eax,23H   syscall)----->NtosKrnl.exe(ZwOpenProcss eax,23H SSDT[23H])----->KeCheckBugEx---->Jmp FakeOpenProcess

    PEPROCESS  EProcess = PsGetCurrentProcess();    //EnumProcessByForce进程上下背景文
    if (EProcess != NULL&&MmIsAddressValid(EProcess))
    {
        //通过EProcess 获得进程名称 

        char *ProcessImageName = PsGetProcessImageFileName(EProcess);    //0x2e0
        if (strstr(ProcessImageName, "EnumProcess") != 0)
        {
            return STATUS_ACCESS_DENIED;  //黑名单
        }
    }

    ((pfnNtOpenProcess)__OldNtOpenProcess)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientID);  //白名单
}

VOID WPOFF()
{
    _disable();
    __writecr0(__readcr0() & (~(0x10000)));

}
VOID WPON()
{
    __writecr0(__readcr0() ^ 0x10000);
    _enable();
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
    DbgPrint("ByeByeDriver\r\n");

    if (__IsHook)
    {
        UnHookSSDT(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessOffset, KeBugCheckEx,
            __OldCode, 15);

        __IsHook = FALSE;
    }

}
#pragma once
#include <ntddk.h>

typedef struct _SERVER_SERVICE_DESCRIPTOR_TABLE_
{
    PVOID Unknow0;
    PVOID Unknow1;
    PVOID Unknow2;
    PVOID Unknow3;
}SERVER_SERVICE_DESCRIPTOR_TABLE, *PSERVER_SERVICE_DESCRIPTOR_TABLE;

typedef
NTSTATUS(*pfnNtOpenProcess)(
    _Out_    PHANDLE            ProcessHandle,
    _In_     ACCESS_MASK        DesiredAccess,
    _In_     POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID         ClientID);

extern
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(PVOID BaseAddress);

extern
char* PsGetProcessImageFileName(PEPROCESS EProcess);

BOOLEAN GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(
    CHAR* FunctionName,
    ULONG32* SSDTFunctionIndex);
BOOLEAN
MappingPEFileInRing0Space(WCHAR* FileFullPath, PVOID* MappingBaseAddress, PSIZE_T MappingViewSize);
BOOLEAN GetSSDTAddress(ULONG64* SSDTAddress);
VOID HookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID FakeFunctionAddress);
ULONG32 CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParameterCount);

VOID HookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID FakeFunctionAddress,
    PVOID OldFunctionAddress, ULONG32 OldFunctionParameterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID
UnHookSSDT(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
    UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);

VOID InlineHook(ULONG64 OldFunctionAddress, ULONG64 FakeFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
VOID UnInlineHook(PVOID OldFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);

NTSTATUS FakeOpenProcess(
    _Out_    PHANDLE            ProcessHandle,
    _In_     ACCESS_MASK        DesiredAccess,
    _In_     POBJECT_ATTRIBUTES ObjectAttributes,
    _In_opt_ PCLIENT_ID         ClientID);
VOID WPOFF();
VOID WPON();
VOID DriverUnload(PDRIVER_OBJECT DriverObject);
时间: 2024-11-05 20:30:48

ring0 SSDTHook 实现x64/x86的相关文章

ring0 SSDTHook

SSDT 的全称是 System Services Descriptor Table,系统服务描述符表.这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来.SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址.服务函数个数等.通过修改此表的函数地址可以对常用 Windows 函数及 API 进行 Hook,从而实现对一些关心的系统动作进行过滤.监控的目的.一些 HIPS.防毒软件.系统监控.注册表监控软件往往

十六进制字符串转十进制 x64/x86

ULONG_PTR ulModBase = 0; #if defined(_WIN64) ulModBase = _tcstoui64(strParam,NULL,16); #else ulModBase = _tcstoul(strParam,NULL,16); #endif http://www.cnblogs.com/khler/archive/2010/11/10/1873284.html =================================================

DllImport 自动选择x64或x86 dll

前言 标题不知道怎么确切地命名,在.net的托管世界里,有时不得不使用c的某个动态库,比如ocr.opencv等,如果幸运,有前人已经包装出.net版本,但有些不非常流行的库,只能自己使用pinvoke或c++ cli包装了,比如笔者就遇到了一个,mqtt客户端库. Pinvoke的多平台问题 如果您没有接触过如何调用非托管dll,没有了解过c#的DllImportAttribute,可以看看以下资料: 1.DllImportAttribute 2.Pinvoke 3.extern 关键字 多平

关于C#编写x86与x64程序的分析

电脑硬件CPU可以分为x86与x64, x86的机器只能安装32位的操作系统,如XP, WIN7_86, x64的机器既可以安装32位的系统,又可以安装64位的系统,只是在x64的机器上安装32位的系统,不能够很充分的利用这台机器的资源.x86程序,即适用于32为操作系统的程序,x64即适用于64位操作系统的程序.64位系统上依然可以运行32位的程序,但是这是通过WOW64来运行,通俗上讲,就是模拟出一个32位的CPU来运行这个程序. 接下来是C#程序的编译运行,分为两步,第一步是编译成IL,在

『开源重编译』System.Data.SQLite.dll 自适应 x86 x64 AnyCPU 重编译

背景: > System.Data.SQLite.dll 程序集 不能良好的支持 AngCPU 格式 System.Data.SQLite.dll 在 适应 x86 和 x64 有三个方案: > 分别使用 32 或 64 的 混合编译程序集(程序如果以64位 运行,但引用32位的 程序集 就会报错,反之) —— 所以这种方案 很惹人嫌. > 使用 AnyCPU 的程序集 —— 但是 你得间接引用 C++ 核心程序集:SQLite.Interop.dll —— 即:你得 同时引用 两个程序

x86/x86_64的一些基本概念

本人在构建boost的时候,从"Start Menu" -> "Programs" -> "Visual Studio 2015" -> "Visual Studio Tools" -> "Windows Desktop Command Prompts":    VS2015 x64 ARM Cross Tools Command Prompt.lnk    VS2015 x64 N

WebForm——IIS服务器、开发方式和简单基础

一.B/S和C/S 1.C/S C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据:另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信. 工作模式: 2.B/S B/S架构的全称为Browser/Server,即浏览器/服务器结构.Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻

zabbix agent安装与配置篇

 Zabbix监控windows部署安装 Zabbix agent 在windows上安装部署 (1)手工安装zabbix agent客户端 1.  下载与解压 地址: http://www.zabbix.com/downloads 解压zabbix_agents_X.X.X.win.zip conf目录存放是agent配置文件 bin文件存放windows下32位和64位安装程序 2.  配置与安装 2.1 配置zabbix agent相关配置. 找到conf下的配置文件 zabbix_age

VS2013 配置pthread

参考:http://blog.csdn.net/qianchenglenger/article/details/16907821 一.下载地址 ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip 解压后得到三个文件夹 二.安装 平台:win7 + VS2013 1. 打开Pre-built.2,下面有三个文件夹:dll, include, lib及其它文件. 2. 先查看VS2013的相关属性 项目—属性—