SSTD HOOK

文章讲述了如何通过钩子(Hook)技术修改系统服务描述表(SSDT)来阻止除自身之外的进程调用TerminateProcess函数关闭目标进程。通过编写驱动程序,作者实现了监控并保护特定进程不被其他程序关闭的功能,主要涉及NtTerminateProcess函数的替换以及页面保护机制的使用。
摘要由CSDN通过智能技术生成

实现进程只能通过自己关闭,不能通过他人调用关闭,也就是实现所谓的SSDT Hook,打开一个记事本,只能通过点击关闭按钮或者菜单退出可以,而不能通过其他程序调用TerminateProcess关闭它。首先我们得找到TerminateProcess真正调用的内核函数的函数编号(不知道函数编号的去看看SSTD : SystemServiceTable篇

// 自行IDA找到
; BOOL __stdcall TerminateProcess(HANDLE hProcess, UINT uExitCode)
                public _TerminateProcess@8
_TerminateProcess@8 proc near           ; CODE XREF: .text:7C839AB2↓j
                                        ; ConsoleIMERoutine(x)+102↓p
                                        ; DATA XREF: ...

.
.
.
.
.
.


; __stdcall ZwTerminateProcess(x, x)
                public _ZwTerminateProcess@8
_ZwTerminateProcess@8 proc near         ; CODE XREF: LdrpGenericExceptionFilter(x,x)+9107↓p
                                        ; ___report_gsfailure+E1↓p ...
                mov     eax, 101h       ; NtTerminateProcess //这里我们可以看到函数编号是 0x101
                mov     edx, 7FFE0300h
                call    dword ptr [edx]
                retn    8
_ZwTerminateProcess@8 endp

所以我们需要修改编号101H的函数的地址,更新为我们自己的函数地址

//自定义结构
struct ssdt_item
{
	PULONG funcTable;//函数地址表 
	ULONG count;//访问次数
	ULONG limit;//函数个数
	PUCHAR paramTable;//函数参数个数
};

//结束进程的函数的编号
#define TerminateProcessIndex 0x101

//SSDT位置 dd KeServiceDescriptorTable
extern struct ssdt_item* KeServiceDescriptorTable; 

但是,我们去修改该地址的值,有可能修改失败,页有可能是只读的,所以我们可以去修改该地址的PDPTE\PDE\PTE的属性,或者可以直接修改CR0寄存器的WP位


void PageProtectOn()
{
	__asm
	{
		mov eax, cr0;
		or eax, 10000h;
		mov cr0, eax;
		sti;
	}
}

void PageProtectOff()
{
	__asm
	{
		cli;
		mov eax, cr0;
		and eax, not 10000h;
		mov cr0, eax;
	}
}

驱动代码

#include <ntifs.h>
#include <wdm.h>
#include <ntddk.h>


//操作码:0x0-0x7FF 被保留,0x800-0xFFF 可用
#define HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define NOHOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)

struct ssdt_item
{
	PULONG funcTable;//函数地址表 
	ULONG count;//访问次数
	ULONG limit;//函数个数
	PUCHAR paramTable;//函数参数个数
};

//结束进程的函数的编号
#define TerminateProcessIndex 0x101

//SSDT位置
extern struct ssdt_item* KeServiceDescriptorTable;

//保护的进程
HANDLE protectedProcess = NULL;

//系统结束进程的函数
typedef  NTSTATUS(__stdcall* NtTerminateProcess)(HANDLE ProcessHandle, NTSTATUS ExitStatus);
NtTerminateProcess oldNtTerminateProcess = NULL;

typedef NTSTATUS(__stdcall* _PspTerminateProcess)(PEPROCESS pEprocess, NTSTATUS ExitCode);
_PspTerminateProcess pspTerminateProcess = NULL;

//设备对象
PDEVICE_OBJECT devObj;
//符号链接
UNICODE_STRING symbolLink;

NTSTATUS DEVICE_CONTROL_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DEVICE_CREATE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DEVICE_CLOSE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp);


void PageProtectOn()
{
	__asm
	{
		mov eax, cr0;
		or eax, 10000h;
		mov cr0, eax;
		sti;
	}
}

void PageProtectOff()
{
	__asm
	{
		cli;
		mov eax, cr0;
		and eax, not 10000h;
		mov cr0, eax;
	}
}

NTSTATUS __stdcall HookNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus)
{
	if (protectedProcess != NULL)
	{
		PEPROCESS pro = IoGetCurrentProcess();
		PEPROCESS p;
		if (ObReferenceObjectByHandle(ProcessHandle, NULL, *PsProcessType, KernelMode, &p, NULL) == STATUS_SUCCESS)
		{
			//只有自己才可以关闭自己
			if (p == protectedProcess && pro != protectedProcess)
			{
				//拒绝
				return STATUS_ACCESS_DENIED;
			}
		}
	}
	return oldNtTerminateProcess(ProcessHandle, ExitStatus);
}

void HookTerminateProcess()
{
	PageProtectOff();
	oldNtTerminateProcess = KeServiceDescriptorTable->funcTable[TerminateProcessIndex];
	KeServiceDescriptorTable->funcTable[TerminateProcessIndex] = HookNtTerminateProcess;
	PageProtectOn();
}


VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	//删除符号链接
	IoDeleteSymbolicLink(&symbolLink);
	//删除设备
	IoDeleteDevice(devObj);
	if (oldNtTerminateProcess != NULL)
	{
		//还原函数
		KeServiceDescriptorTable->funcTable[TerminateProcessIndex] = oldNtTerminateProcess;
		DbgPrint("还原函数成功!!!\n");;
	}
	DbgPrint("卸载成功!!!\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath)
{

	try {
		//unload
		pDriver->DriverUnload = DriverUnload;

		//
		UINT32 shellcode[] = {
		0x0124a164,0x758b0000,0x44703b08,0x0db80775,
		0xebc00000,0xbe8d575a,0x00000248,0x200147f6,
		0x868d1274,0x00000174,0xca685650,0xe88062f0
		};

		UINT32 shellcodeLength = sizeof(shellcode);

		UINT32 base = NULL;
		UINT32 baseSize = NULL;
		UNICODE_STRING baseName;

		LIST_ENTRY* current_entry = (LIST_ENTRY*)pDriver->DriverSection;

		UNICODE_STRING ntName;
		RtlInitUnicodeString(&ntName, L"ntoskrnl.exe");

		while (1)
		{
			base = *(UINT32*)((UINT32)current_entry + 0x18);
			baseSize = *(UINT32*)((UINT32)current_entry + 0x20);
			baseName = *(PUNICODE_STRING)((UINT32)current_entry + 0x2c);
			if (RtlCompareUnicodeString(&ntName, &baseName, TRUE) == 0)
			{
				for (int i = base; i < base + baseSize - shellcodeLength; i++)
				{
					if (RtlCompareMemory(shellcode, i, shellcodeLength) == shellcodeLength)
					{
						pspTerminateProcess = (_PspTerminateProcess)(i - 0x6);
						break;
					}
				}
				break;
			}
			current_entry = current_entry->Blink;
		}

		DbgPrint("dllbase : %08x\n", base);
		DbgPrint("dllbaseName : %wZ\n", ntName);
		DbgPrint("_PspTerminateProcess address is  : %08x\n", pspTerminateProcess);
		/

		//创建设备和3环通信
		UNICODE_STRING deviceName;
		RtlInitUnicodeString(&deviceName,L"\\Device\\firstDevice");
		NTSTATUS status = IoCreateDevice(
			pDriver,
			0,
			&deviceName,
			FILE_DEVICE_UNKNOWN,
			FILE_DEVICE_SECURE_OPEN,
			FALSE,
			&devObj
		);

		DbgPrint("创建设备 : %d~~\n", status);


		//创建符号链接 (3环需要这个符号链接才可以找到)
		RtlInitUnicodeString(&symbolLink,L"\\??\\MYKILLTOOL");
		IoCreateSymbolicLink(&symbolLink,&deviceName);

		//设置通信方式
		pDriver->Flags |= DO_BUFFERED_IO;

		//设置派遣函数
		pDriver->MajorFunction[IRP_MJ_CREATE] = DEVICE_CREATE_Dispatch;
		pDriver->MajorFunction[IRP_MJ_CLOSE] = DEVICE_CLOSE_Dispatch;
		pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DEVICE_CONTROL_Dispatch;

		//hook
		DbgPrint("TerminateProcess 的地址是 : %08x\n", KeServiceDescriptorTable->funcTable[TerminateProcessIndex]);
		HookTerminateProcess();
		DbgPrint("TerminateProcess 的地址是 : %08x\n", KeServiceDescriptorTable->funcTable[TerminateProcessIndex]);


	} __except(EXCEPTION_EXECUTE_HANDLER) {
		DbgPrint("run error~~\n");
		return STATUS_SUCCESS;
	}
	return STATUS_SUCCESS;
}

NTSTATUS DEVICE_CONTROL_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	//从3环获取的PROCESS ID
	UINT32 DATA;
	NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
	//获取PIRP的数据
	PIO_STACK_LOCATION psLocation = IoGetCurrentIrpStackLocation(pIrp);
	//获取控制码
	ULONG code = psLocation->Parameters.DeviceIoControl.IoControlCode;
	//获取缓冲区地址(输入和输出都是同一个)
	PVOID bufferAddress = pIrp->AssociatedIrp.SystemBuffer;
	//3环发送的数据字节数
	ULONG threeLength = psLocation->Parameters.DeviceIoControl.InputBufferLength;
	//0环发送的数据字节数
	ULONG zeroLength = psLocation->Parameters.DeviceIoControl.OutputBufferLength;

	switch (code) 
	{
	case HOOK :
		RtlMoveMemory(&DATA, bufferAddress,4);
		if (PsLookupProcessByProcessId((HANDLE)DATA,&protectedProcess) == STATUS_SUCCESS) //通过PID获取EPROCESS的地址
		{
			DbgPrint("PID : %d ,目前 EPROCESS 地址为:%08x\n", DATA,protectedProcess);
		}
		else
		{
			status = STATUS_INVALID_HANDLE;
		}
		break;
	case NOHOOK :
		protectedProcess = NULL;
		break;
	default:
		break;
	}


	DbgPrint("3环发送的数据长度 %d~~\n", threeLength);
	DbgPrint("0环发送的数据长度 %d~~\n", zeroLength);
	DbgPrint("关闭进程 : %08x~~\n", DATA);

	//设置返回状态,默认是失败的哦
	pIrp->IoStatus.Status = status;
	//返回给3环多少字节数据,没有填0
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;

}


NTSTATUS DEVICE_CREATE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	DbgPrint("CREATE  SUCCESS~~\n");

	//设置返回状态
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	//返回给3环多少字节数据,没有填0
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


NTSTATUS DEVICE_CLOSE_Dispatch(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	DbgPrint("CLOSE  SUCCESS~~\n");

	//设置返回状态
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	//返回给3环多少字节数据,没有填0
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

3环代码

在这里插入代码片// SSTDHOOK.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <winioctl.h>

#define symbolLinkName L"\\\\.\\MYKILLTOOL"
//操作码:0x0-0x7FF 被保留,0x800-0xFFF 可用
#define HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define NOHOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)

int main(int argc, char* argv[])
{
	
	//create device link
	HANDLE device = CreateFileW(
		symbolLinkName,//创建或打开的文件或设备的名称
		GENERIC_READ | GENERIC_WRITE,//请求对文件或设备的访问权限
		0,//文件或设备请求的共享模式,参数为零且 CreateFile 成功,则文件或设备无法共享,并且无法在文件或设备的句柄关闭之前再次打开
		0,//确定返回的句柄是否可以由子进程继承
		OPEN_EXISTING,//仅当文件或设备存在时,才打开该文件或设备
		FILE_ATTRIBUTE_NORMAL,
		NULL);


	if (device == INVALID_HANDLE_VALUE)
	{
		printf("device open error ......");
		system("pause");
		return 0;
	}

	DWORD pid;
    DWORD outBuffer;
	DWORD lbret;//actually out buffer size

    printf("请输入需要保护的程序的 PID :");
    scanf("%d",&pid);

	if (DeviceIoControl(device,HOOK,&pid,sizeof(pid),&outBuffer,sizeof(outBuffer),&lbret,NULL))
	{
		printf("HOOK success , please test......\n");
	}
	system("pause");
	CloseHandle(device);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值