使用MDL读写内存的SSDT HOOK

85 篇文章 6 订阅
83 篇文章 10 订阅

X64下有patchguard,所以先讨论x86的

思路

首先找到函数地址,如果是导出函数,可以使用MmGetSystemRoutineAddress,如果未导出加载符号通过特征码

实现新新函数替换原函数

恢复函数

关于系统从应用层进入内核,xp前是int2e,之后32位是sysenter,64是syscall

https://bbs.pediy.com/thread-226254.htm

 

Ntdll封装了API的调用函数,Kernel32.dll中的API通过Ntdll.dll时完成参数的检查再调用一个中断,int2e,sysenter,syscall进入内核,服务号放在eax,栈放在eDx中(我记不请回头看下),根据存放在 EAX 中的索引值来在 SSDT 数组中调用指定的服务即Nt*系列函数

Zw*和NT*

在ntdll.dll这两函数完全一样,进入内核Ntosknl后一个做参数校验,一个不管,ssdt表放的是NT*,zw*是对Nt封装,zw是内核使用的函数,应用层直接去NT,Zw*会把Kthread中PreviousMode设置为KernelMode,再调用Nt*,所以不会参数检查。内核如果直接调用NT*,这里是userMode。

SSDTHOOK思路

第一行代码一般是索引号给eax(x64不在第一条,需要反汇编后定位指令),所以可以定位这个操作码,比如(mov eax,012h,eaxy一个字节,012h四个字节)。所以函数地址+1,就是下标,转换公式

索引号=*(DWORD*)((usigned char *)fun+1)

或者解析PE文件,找出导出表里这个函数下标。

x86下ssdt表存放的函数的绝对地址:

funaddr=KeSer*Des*+4*index

x64下存的是函数地址和ssdt表首地址的相对偏移,并且左移了4位。

funaddr=KeSer*Des+(KeSer*Des*+4*index)>>4

#pragma pack(1)typedef struct ServiceDescriptorEntry {
    unsigned int *ServiceTableBase;
    unsigned int *ServiceCounterTableBase; 
    unsigned int NumberOfServices;
    unsigned char *ParamTableBase;} ServiceDescriptorTableEntry_t,*PServiceDescriptorTableEntry_t;#pragma pack()

导入:
__declspec(dllimport)  ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
 

然后定义一个宏吧 给一个Zw的地址 返回它在SSDT对应函数的地址 
引用:    

——function是NT对应的Zw函数(zw+1就是指令地址号了)

#define SYSTEMSERVICE(_function)  KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]    

#define SDT     SYSTEMSERVICE

使用就是SDT(ZwCreatefile)

然后找到函数地址---保存原地址--替换地址 当然函数要与原始函数一致


typedef NTSTATUS (*ZWCREATESECTION)(

  	OUT PHANDLE            		SectionHandle,

  	IN ULONG                		DesiredAccess,

  	IN POBJECT_ATTRIBUTES  	ObjectAttributes OPTIONAL,

  	IN PLARGE_INTEGER     	 MaximumSize OPTIONAL,

          IN ULONG                		PageAttributess,

  	IN ULONG                		SectionAttributes,

 	IN HANDLE              		FileHandle OPTIONAL );

 //定义函数指针保存原函数地址,用于恢复

static ZWCREATESECTION            OldZwCreateSection;

 

NTSTATUS NTAPI HOOK_NtCreateSection(PHANDLE SectionHandle,

				  ACCESS_MASK DesiredAccess,

				  POBJECT_ATTRIBUTES ObjectAttributes,

				  PLARGE_INTEGER SectionSize,

				  ULONG Protect,

				  ULONG Attributes,

				  HANDLE FileHandle) 

{

	return OldZwCreateSection(SectionHandle,

				  DesiredAccess,

				  ObjectAttributes,

				  SectionSize,

				  Protect,

				  Attributes,

				  FileHandle);

}

进行HOOK

恢复Hook

移除HOOK 这部很容易蓝屏 建议还是使用DeviceIControl进行卸载 (写一个恢复函数 然后通过下发请求调用)

如果非要卸载可以使用引用计数。

关CRO对多核无效,应该使用MDL方式修改内存。

NTSTATUS RtlSuperCopyMemory(IN VOID UNALIGNED *Dst,
    IN CONST VOID UNALIGNED *Src,
    IN ULONG Length)
{
    //MDL是一个对物理内存的描述,负责把虚拟内存映射到物理内存
    PMDL pmdl = IoAllocateMdl(Dst, Length, 0, 0, NULL);//分配mdl
    if(pmdl==NULL)
        return STATUS_UNSUCCESSFUL;

    MmBuildMdlForNonPagedPool(pmdl);//build mdl
    unsigned int *Mapped = (unsigned int *)MmMapLockedPages(pmdl, KernelMode);//锁住内存
    if(!Mapped){
        IoFreeMdl(pmdl);
        return STATUS_UNSUCCESSFUL;
    }

    KIRQL kirql = KeRaiseIrqlToDpcLevel();
    RtlCopyMemory(Mapped, Src, Length);
    KeLowerIrql(kirql);

    MmUnmapLockedPages((PVOID)Mapped,pmdl);
    IoFreeMdl(pmdl);

    return STATUS_SUCCESS;
}
//安装:
OldZwLoadDriver = SDT(ZwLoadDriver);
ULONG hookAddr = (ULONG) Hook_ZwLoadDriver;
RtlSuperCopyMemory(&SDT(ZwLoadDriver), &hookAddr, 4);    
//卸载:
ULONG oldAddr = (ULONG)OldZwLoadDriver;
RtlSuperCopyMemory(&SDT(ZwLoadDriver), &oldAddr, 4);   

一个使用MDL的ssdtHOOK例子

#include <ntddk.h>
#include <ntimage.h>

#pragma pack(1)
typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase; //Used only in checked build
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()



__declspec(dllimport)  ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]
#define SDT     SYSTEMSERVICE
#define KSDT KeServiceDescriptorTable



typedef struct _DEVICE_EXTENSION
{
	PDEVICE_OBJECT DeviceObject;
	PKEVENT Event;

	BOOLEAN bPCreate;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;


//    全局设备对象
PDEVICE_OBJECT g_pDeviceObject;

UNICODE_STRING g_RegPath;

typedef NTSTATUS(*ZWCREATESECTION)(

	OUT PHANDLE            		SectionHandle,
	IN ULONG                		DesiredAccess,
	IN POBJECT_ATTRIBUTES  	ObjectAttributes OPTIONAL,
	IN PLARGE_INTEGER     	 MaximumSize OPTIONAL,
	IN ULONG                		PageAttributess,
	IN ULONG                		SectionAttributes,
	IN HANDLE              		FileHandle OPTIONAL);
//定义函数指针保存原函数地址,用于恢复

static ZWCREATESECTION            OldZwCreateSection;



NTSTATUS RtlSuperCopyMemory(IN VOID UNALIGNED *Dst,
	IN CONST VOID UNALIGNED *Src,
	IN ULONG Length)
{
	//MDL是一个对物理内存的描述,负责把虚拟内存映射到物理内存
	PMDL pmdl = IoAllocateMdl(Dst, Length, 0, 0, NULL);//分配mdl
	if (pmdl == NULL)
		return STATUS_UNSUCCESSFUL;

	MmBuildMdlForNonPagedPool(pmdl);//build mdl
	unsigned int *Mapped = (unsigned int *)MmMapLockedPages(pmdl, KernelMode);//锁住内存
	if (!Mapped) {
		IoFreeMdl(pmdl);
		return STATUS_UNSUCCESSFUL;
	}

	KIRQL kirql = KeRaiseIrqlToDpcLevel();
	RtlCopyMemory(Mapped, Src, Length);
	KeLowerIrql(kirql);

	MmUnmapLockedPages((PVOID)Mapped, pmdl);
	IoFreeMdl(pmdl);

	return STATUS_SUCCESS;
}



NTSTATUS NTAPI HOOK_NtCreateSection(PHANDLE SectionHandle,

	ACCESS_MASK DesiredAccess,
	POBJECT_ATTRIBUTES ObjectAttributes,
	PLARGE_INTEGER SectionSize,
	ULONG Protect,
	ULONG Attributes,
	HANDLE FileHandle)
{

	return OldZwCreateSection(SectionHandle,
		DesiredAccess,
		ObjectAttributes,
		SectionSize,
		Protect,
		Attributes,
		FileHandle);

}


void StartHook(void)

{

	//获取未导出的服务函数索引号

	OldZwCreateSection = SDT(ZwCreateSection);
	ULONG hookAddr = (ULONG)HOOK_NtCreateSection;
	RtlSuperCopyMemory(&SDT(ZwCreateSection), &hookAddr, 4);



	return;

}




void RemoveHook(void)
{
	ULONG oldAddr = (ULONG)OldZwCreateSection;
	RtlSuperCopyMemory(&SDT(ZwCreateSection), &oldAddr, 4);
	return;
}




void UnloadDriver(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING  uszDeviceString;
	NTSTATUS        ntStatus;


	//移除挂接
	RemoveHook();

	IoDeleteDevice(DriverObject->DeviceObject);

	RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\ITSys");
	IoDeleteSymbolicLink(&uszDeviceString);

}

NTSTATUS DispatchIoCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{

	NTSTATUS              ntStatus = STATUS_UNSUCCESSFUL;
	PIO_STACK_LOCATION    irpStack = IoGetCurrentIrpStackLocation(Irp);
	PDEVICE_EXTENSION    extension = DeviceObject->DeviceExtension;

	switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
	{
	default:
		break;
	}

	Irp->IoStatus.Status = ntStatus;

	// 设置返回给用户层程序的数据的字节数
	if (ntStatus == STATUS_SUCCESS)
		Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
	else
		Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return ntStatus;
}



NTSTATUS DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


NTSTATUS DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	NTSTATUS rc;

	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	rc = Irp->IoStatus.Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return rc;
}




NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT DriverObject,
	IN PUNICODE_STRING RegistryPath
)
{
	NTSTATUS        ntStatus;
	UNICODE_STRING  uszDriverString;
	UNICODE_STRING  uszDeviceString;
	UNICODE_STRING  uszEventString;

	PDEVICE_OBJECT    pDeviceObject;
	PDEVICE_EXTENSION extension;
	// 初始化设备对象名
	RtlInitUnicodeString(&uszDriverString, L"\\Device\\ITSys");
	// 创建并初始化对象
	ntStatus = IoCreateDevice(
		DriverObject,
		sizeof(DEVICE_EXTENSION),
		&uszDriverString,
		FILE_DEVICE_UNKNOWN,
		0,
		FALSE,
		&pDeviceObject
	);
	if (ntStatus != STATUS_SUCCESS)
		return ntStatus;
	extension = pDeviceObject->DeviceExtension;
	RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\ITSys");
	// 创建用户可见连接名称
	ntStatus = IoCreateSymbolicLink(&uszDeviceString, &uszDriverString);
	if (ntStatus != STATUS_SUCCESS)
	{
		// 创建失败,删除对象并返回错误值
		IoDeleteDevice(pDeviceObject);
		return ntStatus;
	}
	// 赋值全局设备对象指针

	// Assign global pointer to the device object for use by the callback functions
	g_pDeviceObject = pDeviceObject;
	// 设置所有可用的DeviceIoControl的处理IRP的函数

	DriverObject->DriverUnload = UnloadDriver;
	DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoCtrl;

#if DBG
	KdPrint(("RegistryPath : %ws\n", RegistryPath->Buffer));
#endif

	//SDT挂接
	StartHook();

	return ntStatus;
}

使用结果图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值