实现进程只能通过自己关闭,不能通过他人调用关闭,也就是实现所谓的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;
}