先说一下大致思路
1.首先通过SharedUserData
成员NtSystemRoot
获取系统路径,进而组装成ntdll的全路径
2.接着通过MmCreateSection
、MmMapViewInSystemSpace
将ntdll加载到内存中,然后进行导出表搜索找到目标函数的服务号
3.然后通过内核导出的变量KeServiceDescriptorTable
进而找到SSDT表
4.最后通过在SSDT表修改目标函数地址为自定义地址即可
所有代码如下:
SSDT.h
#pragma once
#include <ntifs.h>
typedef struct _SsdtItem
{
PULONG funcTable;
ULONG_PTR totalCount;
ULONG_PTR funcMaxNumber;
PUCHAR paramTable;
}SsdtItem;
typedef struct _SsdtTable
{
SsdtItem ssdt;
SsdtItem sssdt;
}SsdtTable, * PSsdtTable;
tool.h
#pragma once
#include<ntifs.h>
PWCHAR GetSystemPath();
PVOID MapMemorry(PWCHAR systempath);
ULONG64 ExportTableFuncByName(char* pData, char* funcName);
VOID FuncDestroy();
VOID UmMapOfViewFile(PVOID mapBase);
ULONG GetFuncIndex();
VOID FuncInit();
VOID SSDTHook(char* funcName, PVOID FuncAddress);
extern PVOID address;
extern PUCHAR func;
tool.c
#include<ntifs.h>
#include<ntstrsafe.h>
#include<ntimage.h>
#include"SSDT.h"
#include<intrin.h>
#include"tool.h"
//导出服务表
extern PSsdtTable KeServiceDescriptorTable;
PVOID address = NULL;
PUCHAR func = NULL;
EXTERN_C NTSTATUS MmCreateSection(
__deref_out PVOID* SectionObject,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
__in PLARGE_INTEGER InputMaximumSize,
__in ULONG SectionPageProtection,
__in ULONG AllocationAttributes,
__in_opt HANDLE FileHandle,
__in_opt PFILE_OBJECT FileObject
);
//关闭写保护
ULONG wpOff()
{
ULONG cr0 = __readcr0();
_disable(); //关闭中断
__writecr0(cr0 & (~0x10000)); //关闭写保护
return cr0;
}
VOID wpOn(ULONG value)
{
__writecr0(value);
_enable();
}
PWCHAR GetSystemPath()
{
//获取系统目录
PWCH systempath = (PWCH)ExAllocatePool(PagedPool, PAGE_SIZE);
memset(systempath, 0, PAGE_SIZE);
//拼接完整的路径
RtlStringCbPrintfW(systempath, PAGE_SIZE, L"\\??\\%s\\system32\\ntdll.dll", SharedUserData->NtSystemRoot);
DbgPrintEx(77, 0, "[db]:%S\r\n", systempath);
return systempath;
}
PVOID MapMemorry(PWCHAR systempath)
{
UNICODE_STRING Psystempath = { 0 };
RtlInitUnicodeString(&Psystempath, systempath);
PHANDLE hFile;
OBJECT_ATTRIBUTES objAttributes;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
InitializeObjectAttributes(&objAttributes, &Psystempath, OBJ_CASE_INSENSITIVE, NULL, NULL);
NTSTATUS status = ZwCreateFile(&hFile, GENERIC_READ, &objAttributes, &IoStatusBlock, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, NULL);
if (!NT_SUCCESS(status))
{
NtClose(hFile);
}
//创建节区
PVOID hSection = NULL;
OBJECT_ATTRIBUTES sectionAddr;
InitializeObjectAttributes(§ionAddr, NULL, OBJ_CASE_INSENSITIVE, NULL, NULL);
LARGE_INTEGER InputMaximumSize = { 0 };
status = MmCreateSection(&hSection, SECTION_ALL_ACCESS, §ionAddr,
&InputMaximumSize, PAGE_EXECUTE_READWRITE, 0x1000000, hFile, NULL);
if (!NT_SUCCESS(status))
{
ZwClose(hFile);
return 0;
}
PVOID mapBase = NULL;
SIZE_T viewSize = { 0 };
status = MmMapViewInSystemSpace(hSection, &mapBase, &viewSize);
ObDereferenceObject(hSection);
ZwClose(hFile);
if (NT_SUCCESS(status))
{
return mapBase;
}
return 0;
}
ULONG64 ExportTableFuncByName(char* pData, char* funcName)
{
PIMAGE_DOS_HEADER pHead = (PIMAGE_DOS_HEADER)pData;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pData + pHead->e_lfanew);
int numberRvaAndSize = pNt->OptionalHeader.NumberOfRvaAndSizes;
PIMAGE_DATA_DIRECTORY pDir = (PIMAGE_DATA_DIRECTORY)&pNt->OptionalHeader.DataDirectory[0];
PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(pData + pDir->VirtualAddress);
ULONG64 funcAddr = 0;
for (int i = 0; i < pExport->NumberOfNames; i++)
{
int* funcAddress = pData + pExport->AddressOfFunctions;
int* names = pData + pExport->AddressOfNames;
short* fh = pData + pExport->AddressOfNameOrdinals;
int index = -1;
char* name = pData + names[i];
if (strcmp(name, funcName) == 0)
{
index = fh[i];
}
if (index != -1)
{
funcAddr = pData + funcAddress[index];
break;
}
}
if (!funcAddr)
{
KdPrint(("没有找到函数%s\r\n", funcName));
}
else
{
KdPrint(("找到函数%s addr %p\r\n", funcName, funcAddr));
}
return funcAddr;
}
VOID FuncInit()
{
PWCHAR path = GetSystemPath();
address = MapMemorry(path);
ExFreePool(path);
return TRUE;
}
ULONG GetFuncIndex(PVOID FuncAddress)
{
PUCHAR funcd = ExportTableFuncByName(address, FuncAddress);
if (funcd == NULL)
{
return -1;
}
return *(PULONG)(funcd + 1);
}
VOID UmMapOfViewFile(PVOID mapBase)
{
if (!mapBase) return;
MmUnmapViewInSystemSpace(mapBase);
}
VOID FuncDestroy()
{
if (!address)
{
return;
}
UmMapOfViewFile(address);
address = NULL;
}
PSsdtTable SsdtGet()
{
return (PSsdtTable)((PUCHAR)KeServiceDescriptorTable + 0x40);
}
VOID SSDTHook(char* funcName,PVOID FuncAddress)
{
//获取SSDT位置
PSsdtTable ssdtA = SsdtGet();
if (!ssdtA)
{
return;
}
ULONG index = GetFuncIndex(funcName);
if (index == -1)
{
return;
}
func = (PULONG)ssdtA->ssdt.funcTable[index];
ULONG wp = wpOff();
ssdtA->ssdt.funcTable[index] = FuncAddress;
wpOn(wp);
}
DriverEntry.c
#include<ntifs.h>
#include"SSDT.h"
#include<ntstrsafe.h>
#include"tool.h"
typedef NTSTATUS (NTAPI* OpenProcessProc)(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
);
NTSTATUS NTAPI MyZwOpenProcess
(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
)
{
DbgPrintEx(77, 0, "[db]:%s\r\n", __FUNCTION__);
OpenProcessProc fun = (OpenProcessProc)func;
return fun(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
};
VOID DriverUnload(_In_ struct _DRIVER_OBJECT* DriverObject)
{
SSDTHook("ZwOpenProcess", func);
FuncDestroy();
LARGE_INTEGER inTime = { 0 };
inTime.QuadPart = -10000 * 10000; //10s
KeDelayExecutionThread(KernelMode, FALSE, &inTime);
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
//映射ntdll并获取系统服务号
FuncInit();
SSDTHook("ZwOpenProcess", MyZwOpenProcess);
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}