首页
社区
课程
招聘
[原创]SSDT HOOK及键盘过滤驱动
发表于: 2020-11-16 22:01 9282

[原创]SSDT HOOK及键盘过滤驱动

2020-11-16 22:01
9282

SSDT全称为System Service Descriptor Table,即系统服务描述符表。SSDT的作用就是把Ring3的WIN32 API函数和Ring0的内核API联系起来。R3下的一些API最终会对应ntdll.dll中的一个Nt开头的函数。将系统服务号放入EAX然后调用KiSystemService进入内核根据系统服务号得到对应系统服务的内核地址。HIPS,杀毒软件往往会通过SSDT HOOK实现监控系统的目的。
32位系统中SSDT是由内核Ntoskrnl.exe导出的一张表,导出符号为KeServiceDescriptorTable。在64位系统上是不导出的。
以下程序实现将ntdll.dll文件映射到内核空间并从导出表中获取导出函数地址,然后获取SSDT函数索引号。
具体操作流程如下:
1 调用InitializeObjectAttributes宏初始化文件对象,它主要初始化文件路径,内核下的文件路径需要在路径前面加上\??\
2 调用ZwCreateSection函数生成一个内存映射对象得到句柄hSection,该对象建立在由ZwOpenFile函数创建的文件对象基础上。该内存映射对象对视图读写具有SECTION_MAP_READ和SECTION_MAP_WRITE访问权限,同时设置内存映射方式为SEC_IMAGE,以PE中的SectionAlignment大小对齐映射文件
3 调用ZwMapViewOfSection函数把文件映射到内存得到lpMemory。该指针直接读写内存
4 调用ZwUnmapViewOfSection解除文件映射,进程句柄,lpMemory作为参数。
5 接下来根据PE文件结构获取导出函数地址并从导出函数中获取SSDT函数索引号,根据IMAGE_DOS_HEADER和IMAGE_NT_HEADERS计算出OptionalHeader,获取数据目录中导出表的RVA地址查找匹配的函数名称从AddressOfNamesOrdinal中获取索引值,32位系统下导出函数偏移1字节后的四字节就是SSDT函数索引号,64位系统下需要偏移4字节

获取SSDT函数地址
32系统上获取SSDT地址,直接获取Ntoskrnl.exe导出符号KeServiceDescriptorTable即可

64位系统下无法直接获取导出符号KeServiceDescriptorTable,从KiSystemCall64函数中进行内存扫描获取KeServiceDescriptorTable的地址

SSDT HOOK实现
64位系统Patch Guard机制把SSDT所在的内存作为重点保护对象,修改SSDT内存会触发Patch Guard导致系统蓝屏,64位系统下要使用SSDT HOOK必须绕过Patch Guard。
将SSDT表中存储的ZwQueryDriverFile函数地址修改成新函数的地址,当系统从SSDT中获取ZwQueryDirectoryFile函数地址的时候获取到的就是新函数的地址,其中,SSDT的内存是写保护属性的,所以采用MDL方式可以绕过写保护属性。

2 过滤驱动
设备栈中的成员是设备,IRP的传递方向是由上到下,新添加的设备总是附加在设备栈的顶部,最上层的设备最先获得IRP
键盘过滤驱动创建一个键盘设备将它附加在键盘类KbdClass设备栈上,当有键盘按下IRP消息的时候该设备最先接收到IRP消息,实现IRP HOOK。
创建过滤驱动设备的过程如下:
1 IoCreateDevice创建一个FILE_DEVICE_KEYBOARD键盘设备并调用IoCreateSymbolicLink为该设备创建一个符号链接。
2 调用 IoGetDeviceObjectPointer函数获取KeyboardClass0驱动设备对象
3 通过IoAttachDeviceToDeviceStack将创建的键盘设备附加到KeyboardClass0设备对象所在的设备栈顶

自定义键盘驱动捕获到IRP请求再把该IRP请求发送给操作系统
IRP读请求中处理流程如下:
1 调用IoCopyCurrentIrpStackLocationToNext将当前设备中的IRP复制到下一个设备中
2 调用IoSetCompletionRoutine函数设置完成回调函数,将在下一层驱动完成由IRP指定的操作请求时调用这个函数
3 调用IoCallDriver函数将IRP发送到下一个设备

完成回调函数的具体代码如下

任何时候设备栈底都会有一个键盘的IRP_MJ_READ请求处于挂起状态。一般的方式卸载键盘过滤驱动基本都有IRP_MJ_READ请求处于挂起未确定状态。这时若执行卸载驱动操作那么在以后按键需要这个IRP时却找不到对应驱动,从而导致计算机蓝屏。所以必须处理好这个挂起状态的IRP。
实现动态卸载过滤的方法是在设备增加一个DeviceExtension,并添加一个u1IrpInQuene变量来记录。卸载驱动的时候先调用IoDetachDevice,取消附加键盘设备。一直循环判断u1IrpInQuene是否为0,若不未0则一直循环等待。直到用户手动按键就会在IRP中返回。由于不附加键盘设备栈,所以也不会有新的IRP_MJ_READ产生,此时的u1IrpInQuene的值是0,可以正确卸载。
卸载程序:

参考资料:

看雪论坛:通俗解析IRP和I/O设备栈在内核程序中的作用https://bbs.pediy.com/thread-111559.htm
《黑客免杀攻防》
《黑客编程技术详解》

#include "SSDTFunctionIndex.h"
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunctionIndex.h"
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunction.h"
 
 
// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
    UNICODE_STRING ustrDllFileName;
    ULONG ulSSDTFunctionIndex = 0;
    PVOID pFunctionAddress = NULL;
 
    RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    // 从 ntdll.dll 中获取 SSDT 函数索引号
    ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
 
    // 根据索引号, 从SSDT表中获取对应函数地址
    pFunctionAddress = (PVOID)KeServiceDescriptorTable.ServiceTableBase[ulSSDTFunctionIndex];
 
    // 显示
    DbgPrint("[%s][Index:%d][Address:0x%p]\n", pszFunctionName, ulSSDTFunctionIndex, pFunctionAddress);
 
    return pFunctionAddress;
}
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
 
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunction.h"
 
 
// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
    UNICODE_STRING ustrDllFileName;
    ULONG ulSSDTFunctionIndex = 0;
    PVOID pFunctionAddress = NULL;
 
    RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    // 从 ntdll.dll 中获取 SSDT 函数索引号
    ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
 
    // 根据索引号, 从SSDT表中获取对应函数地址
    pFunctionAddress = (PVOID)KeServiceDescriptorTable.ServiceTableBase[ulSSDTFunctionIndex];
 
    // 显示
    DbgPrint("[%s][Index:%d][Address:0x%p]\n", pszFunctionName, ulSSDTFunctionIndex, pFunctionAddress);
 
    return pFunctionAddress;
}
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
 
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunction.h"
 
 
// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
    UNICODE_STRING ustrDllFileName;
    ULONG ulSSDTFunctionIndex = 0;
    PVOID pFunctionAddress = NULL;
    PSSDTEntry pServiceDescriptorTable = NULL;
    ULONG ulOffset = 0;
 
    RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    // 从 ntdll.dll 中获取 SSDT 函数索引号
    ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
 
    // 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
    pServiceDescriptorTable = GetSSDTAddress();
 
    // 根据索引号, 从SSDT表中获取对应函数偏移地址并计算出函数地址
    ulOffset = pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex] >> 4;
    pFunctionAddress = (PVOID)((PUCHAR)pServiceDescriptorTable->ServiceTableBase + ulOffset);
 
    // 显示
    DbgPrint("[%s][SSDT Addr:0x%p][Index:%d][Address:0x%p]\n", pszFunctionName, pServiceDescriptorTable, ulSSDTFunctionIndex, pFunctionAddress);
 
    return pFunctionAddress;
}
 
 
// 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
PVOID GetSSDTAddress()
{
    PVOID pServiceDescriptorTable = NULL;
    PVOID pKiSystemCall64 = NULL;
    UCHAR ulCode1 = 0;
    UCHAR ulCode2 = 0;
    UCHAR ulCode3 = 0;
    // 注意使用有符号整型
    LONG lOffset = 0;
 
    // 获取 KiSystemCall64 函数地址
    pKiSystemCall64 = (PVOID)__readmsr(0xC0000082);
    // 搜索特征码 4C8D15
    for (ULONG i = 0; i < 1024; i++)
    {
        // 获取内存数据
        ulCode1 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i));
        ulCode2 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 1));
        ulCode3 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 2));
        // 判断
        if (0x4C == ulCode1 &&
            0x8D == ulCode2 &&
            0x15 == ulCode3)
        {
            // 获取偏移
            lOffset = *((PLONG)((PUCHAR)pKiSystemCall64 + i + 3));
            // 根据偏移计算地址
            pServiceDescriptorTable = (PVOID)(((PUCHAR)pKiSystemCall64 + i) + 7 + lOffset);
            break;
        }
    }
 
    return pServiceDescriptorTable;
}
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
 
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunction.h"
 
 
// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
    UNICODE_STRING ustrDllFileName;
    ULONG ulSSDTFunctionIndex = 0;
    PVOID pFunctionAddress = NULL;
    PSSDTEntry pServiceDescriptorTable = NULL;
    ULONG ulOffset = 0;
 
    RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    // 从 ntdll.dll 中获取 SSDT 函数索引号
    ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
 
    // 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
    pServiceDescriptorTable = GetSSDTAddress();
 
    // 根据索引号, 从SSDT表中获取对应函数偏移地址并计算出函数地址
    ulOffset = pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex] >> 4;
    pFunctionAddress = (PVOID)((PUCHAR)pServiceDescriptorTable->ServiceTableBase + ulOffset);
 
    // 显示
    DbgPrint("[%s][SSDT Addr:0x%p][Index:%d][Address:0x%p]\n", pszFunctionName, pServiceDescriptorTable, ulSSDTFunctionIndex, pFunctionAddress);
 
    return pFunctionAddress;
}
 
 
// 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
PVOID GetSSDTAddress()
{
    PVOID pServiceDescriptorTable = NULL;
    PVOID pKiSystemCall64 = NULL;
    UCHAR ulCode1 = 0;
    UCHAR ulCode2 = 0;
    UCHAR ulCode3 = 0;
    // 注意使用有符号整型
    LONG lOffset = 0;
 
    // 获取 KiSystemCall64 函数地址
    pKiSystemCall64 = (PVOID)__readmsr(0xC0000082);
    // 搜索特征码 4C8D15
    for (ULONG i = 0; i < 1024; i++)
    {
        // 获取内存数据
        ulCode1 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i));
        ulCode2 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 1));
        ulCode3 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 2));
        // 判断
        if (0x4C == ulCode1 &&
            0x8D == ulCode2 &&
            0x15 == ulCode3)
        {
            // 获取偏移
            lOffset = *((PLONG)((PUCHAR)pKiSystemCall64 + i + 3));
            // 根据偏移计算地址
            pServiceDescriptorTable = (PVOID)(((PUCHAR)pKiSystemCall64 + i) + 7 + lOffset);
            break;
        }
    }
 
    return pServiceDescriptorTable;
}
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
 
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunction.h"
 
 
// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
    UNICODE_STRING ustrDllFileName;
    ULONG ulSSDTFunctionIndex = 0;
    PVOID pFunctionAddress = NULL;
 
    RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    // 从 ntdll.dll 中获取 SSDT 函数索引号
    ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
 
    // 根据索引号, 从SSDT表中获取对应函数地址
    pFunctionAddress = (PVOID)KeServiceDescriptorTable.ServiceTableBase[ulSSDTFunctionIndex];
 
    // 显示
//    DbgPrint("[%s][Index:%d][Address:0x%p]\n", pszFunctionName, ulSSDTFunctionIndex, pFunctionAddress);
 
    return pFunctionAddress;
}
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }
    // 映射到内存
    status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hSection);
        ZwClose(hFile);
        KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
        return status;
    }
 
    // 返回数据
    *phFile = hFile;
    *phSection = hSection;
    *ppBaseAddress = pBaseAddress;
 
    return status;
}
 
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    // Dos Header
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
    // NT Header
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    // Export Table
    PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
    // 有名称的导出函数个数
    ULONG ulNumberOfNames = pExportTable->NumberOfNames;
    // 导出函数名称地址表
    PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
    PCHAR lpName = NULL;
    // 开始遍历导出表
    for (ULONG i = 0; i < ulNumberOfNames; i++)
    {
        lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
        // 判断是否查找的函数
        if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
        {
            // 获取导出函数地址
            USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
            ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
            PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
            // 获取 SSDT 函数 Index
#ifdef _WIN64
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
            ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
            break;
        }
    }
 
    return ulFunctionIndex;
}
#include "SSDTFunction.h"
 
 
// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
    UNICODE_STRING ustrDllFileName;
    ULONG ulSSDTFunctionIndex = 0;
    PVOID pFunctionAddress = NULL;
 
    RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    // 从 ntdll.dll 中获取 SSDT 函数索引号
    ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);
 
    // 根据索引号, 从SSDT表中获取对应函数地址
    pFunctionAddress = (PVOID)KeServiceDescriptorTable.ServiceTableBase[ulSSDTFunctionIndex];
 
    // 显示
//    DbgPrint("[%s][Index:%d][Address:0x%p]\n", pszFunctionName, ulSSDTFunctionIndex, pFunctionAddress);
 
    return pFunctionAddress;
}
 
 
// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
    ULONG ulFunctionIndex = 0;
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    PVOID pBaseAddress = NULL;
 
    // 内存映射文件
    status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("DllFileMap Error!\n"));
        return ulFunctionIndex;
    }
 
    // 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
    ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);
 
    // 释放
    ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
    ZwClose(hSection);
    ZwClose(hFile);
 
    return ulFunctionIndex;
}
 
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    HANDLE hSection = NULL;
    OBJECT_ATTRIBUTES objectAttributes = { 0 };
    IO_STATUS_BLOCK iosb = { 0 };
    PVOID pBaseAddress = NULL;
    SIZE_T viewSize = 0;
    // 打开 DLL 文件, 并获取文件句柄
    InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
        FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
        return status;
    }
    // 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
    status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
    if (!NT_SUCCESS(status))
    {
        ZwClose(hFile);
        KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
        return status;
    }

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 5
支持
分享
最新回复 (5)
雪    币: 8
活跃值: (104)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
为什么论坛翻来覆去发这些已经被人发烂了的帖子 感觉这都成立月经贴了
2020-11-17 00:35
0
雪    币: 183
活跃值: (6634)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
3
MRRighter 为什么论坛翻来覆去发这些已经被人发烂了的帖子 感觉这都成立月经贴了
因为我菜,刚学到,也没看见有别人发
2020-11-17 09:09
0
雪    币: 2674
活跃值: (2304)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4

代码规范!不错!虽然目前是64位主流,但32位系统还是有用户要用的。
64位上过PG,目前流行的有:Infinity Hook或者挂VT。在逆向分析版块拜读过楼主病毒分析的帖子,基础扎实!
以你的根基深入掌握这些东西,不是难事!


最后于 2021-1-3 22:46 被低调putchar编辑 ,原因:
2020-11-17 22:25
0
雪    币: 6124
活跃值: (4666)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
5
大二学生 因为我菜,刚学到,也没看见有别人发
因为写代码不是靠看别人发的贴子学会的,每个人把自己学习的成果分享一下有什么不对吗?
2020-12-9 17:08
2
雪    币: 79
活跃值: (59)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享,学到了新知识!
2022-11-13 09:52
0
游客
登录 | 注册 方可回帖
返回
//