您的位置:首页 > 运维架构

HOOK SSDT NtOpenProcess 保护进程

2013-12-03 11:31 369 查看
感谢众大神分享的技术,因为几乎没直接用别人的源码,所以就标题原创

但是因为这个技术肯定是前辈们搞出来的,所以就特意说明下,此乃转载耶

模板用的张帆大牛的

记录一下,以后备用

有些许疑惑,不过都解决了:/article/10015553.html


//本来只是测试MmGetSystemRoutineAddresss函数的,然后发现直接用函数名就可以得到这个地址
//然后就像SSDT HOOK简单测试一下函数地址,
//然后HOOK之后就想简单的实现进程保护
//就这样越多了


#ifdef _cplusplus
extern "C"
{
#endif
#include <ntddk.h>
#ifdef _cplusplus
}
#endif

//定义代码段分页标志
#define PAGEDCODE	code_seg("PAGE")
#define LOCKEDCODE	code_seg()
#define INITCODE	code_seg("INIT")

//定义数据段分页标志
#define PAGEDDATA	code_seg("PAGE")
#define LOCKEDDATA	code_seg()
#define INITDATA	code_seg("INIT")

//定义求数组个数的宏定义
#define arraysize(p)	(sizeof(p) / sizeof((p)[0]))

//定义设备扩展
typedef struct _DEVICE_EXTENSION{
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName;		//设备名称
UNICODE_STRING ustrSymLinkName;		//符号链接名
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

//函数声明//
//初始化时创建设备和符号
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);
//驱动卸载例程
VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject);
//驱动默认分派例程
NTSTATUS DispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);

typedef NTSTATUS ( *pfnNtOpenProcess)(
PHANDLE,
ACCESS_MASK,
POBJECT_ATTRIBUTES,
PCLIENT_ID);
pfnNtOpenProcess OldNtOpenProcess;

NTSTATUS MyNtOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesireAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientID);

typedef struct _SERVICE_DESCRIPTOR_TABLE {
PVOID 	ServiceTableBase;//System Service Dispatch Table 的基地址
PVOID 	ServiceCounterTableBase;//包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新
ULONG	NumberOfServices;//由 ServiceTableBase 描述的服务的数目
PUCHAR	ParamTableBase;//包含每个系统服务参数字节数表的基地址-系统服务参数表
}SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;

extern "C"{
__declspec(dllimport) SERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
}


//看了下调用MmGetSystemRoutineAddress查看函数地址
//顺便SSDT HOOK NtOpenProcess
//注释全是测试用
//貌似标准做法是在DriverEntry中int 3
//然后再下断点双机调试
//以后不能用这个打印查看了。。。说不定一下就看见蓝精灵了

#include "Driver.h"

NTSTATUS MyNtOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesireAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientID)
{
//在这了实现进程保护的吧, 话说本来打算根据ObjectName来判断进程名的,但是貌似全是null值
//只能用pid了
//KdPrint(("SSDT HOOK NtOpenProcess Successful!"));
NTSTATUS status = STATUS_SUCCESS;
//要保护的进程PID
LONG pid = 3780;
//KdPrint(("ClientID->UniqueProcess = %ld\n", ClientID->UniqueProcess));
//PsLookupProcessByProcessId(IN HANDLE ProcessId, OUT PEPROCESS *Process)可获得EPROCESS结构
if((long)ClientID->UniqueProcess == pid)
{
//KdPrint(("Protected PID: %ld\n", pid));
return STATUS_ACCESS_DENIED;
}
//UNICODE_STRING szProtect;
//RtlInitUnicodeString(&szProtect, L"1.exe");
//PUNICODE_STRING szProtect = (PUNICODE_STRING)ExAllocatePool(PagedPool,sizeof(UNICODE_STRING));
//RtlInitUnicodeString(szProtect, L"1.exe");
//_asm int 3;
//__try
//{
//ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), 4);
//KdPrint(("%wZ\n", ObjectAttributes->ObjectName));
//if(!RtlCompareUnicodeString(ObjectAttributes->ObjectName, &szProtect, FALSE))
//{	//ExFreePool(((PVOID)szProtect));
//	return STATUS_UNSUCCESSFUL;
//}
//}
//__except(EXCEPTION_EXECUTE_HANDLER)
//{
status = OldNtOpenProcess(ProcessHandle, DesireAccess, ObjectAttributes, ClientID);
//}
return status;
//ExFreePool((PVOID)szProtect);
}
//禁用写保护,wp=0
VOID PROTECT()
{
__asm
{
cli ;
mov eax, cr0
and  eax, ~0x10000
mov cr0, eax
}
}
//启用写保护,wp=1
VOID UN_PROTECT()
{
__asm
{
mov  eax, cr0
or     eax, 0x10000
mov  cr0, eax
sti ;
}
}

PVOID HookSSDTFunction(PVOID OldFunction, PVOID HookFunction)
{
KdPrint(("Enter HookSSDTFunction\n"));
//KdPrint(("KeServiceDescriptorTable.ServiceTableBase=0x%X\n",KeServiceDescriptorTable.ServiceTableBase));
//KdPrint(("KeServiceDescriptorTable.NumberOfServices=0x%X\n",KeServiceDescriptorTable.NumberOfServices));
//PROTECT();	It is sure that if we use PROTECT function, we must change other code too;
//我勒个去,我也用英语装逼一下,O(∩_∩)O哈哈~
PMDL pMdl = MmCreateMdl(
NULL,
KeServiceDescriptorTable.ServiceTableBase,
KeServiceDescriptorTable.NumberOfServices*4);
if(!pMdl)
{
KdPrint(("Hook SSDT Failed!\n"));
return 0;
}
MmBuildMdlForNonPagedPool(pMdl);
pMdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
PLONG pMdlLocked = (PLONG)MmMapLockedPages(pMdl, KernelMode);
//KdPrint(("ServiceTableBase Locked page 0X%X", pMdlLocked));
//网上HOOK 系列都是用的这个来获得和修改地址,原因见下
//OldZwOpenProcess = (ZWOPENPROCESS)(KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PBYTE)ZwOpenProcess+1)])
//lkd> u ZwOpenProcess
//nt!ZwOpenProcess:
//805016b4 b87a000000      mov     eax,7Ah
//805016b9 8d542404        lea     edx,[esp+4]
for(ULONG i = 0; i<KeServiceDescriptorTable.NumberOfServices; i++)
{
if((LONG)pMdlLocked[i] == (LONG)OldFunction)
{
//KdPrint(("修改前: HOOK Func addr=0X%X", (LONG)HookFunction));
//KdPrint(("修改前: Need Hook addr=0X%X", (LONG)pMdlLocked[i]));
InterlockedExchange(&pMdlLocked[i], (LONG)HookFunction);
//KdPrint(("修改后: Need Hook addr=0X%X", (LONG)pMdlLocked[i]));
break;
}
}
MmUnmapLockedPages(pMdlLocked, pMdl);
IoFreeMdl(pMdl);
//UN_PROTECT()
KdPrint(("Leave HookSSDTFunction\n"));
return OldFunction;
}

VOID Test(PCWSTR sz)
{
UNICODE_STRING strToFind;
RtlInitUnicodeString(&strToFind, sz);
PVOID AddrToFind = MmGetSystemRoutineAddress(&strToFind);
if (!AddrToFind);
//KdPrint(("MmGetSystemRoutineAddress: %S address is not fount\n", sz));
else;
//KdPrint(("Hook之前调用MmGetSystemRoutineAddress: 0x%X\n", AddrToFind));
KdPrint(("Hook之后直接用NtOpenProcess名 %X\n", NtOpenProcess));
//直接用函数名获得的NtOpenProcess的地址和用MmGetSystemRoutineAddress获得的地址一样
//HookSSDTFunction(AddrToFind, MyNtOpenProcess);
OldNtOpenProcess = (pfnNtOpenProcess)HookSSDTFunction(NtOpenProcess, MyNtOpenProcess);
AddrToFind = MmGetSystemRoutineAddress(&strToFind);
//KdPrint(("Hook之后调用MmGetSystemRoutineAddress: 0x%X\n", AddrToFind));
//KdPrint(("Hook之后直接用NtOpenProcess名 %X\n", NtOpenProcess));
}

/************************************************************************
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动对象
pRegistryPath:驱动程序在注册表的中的路径
* 返回 值:返回初始化驱动状态
*************************************************************************/
#pragma INITCODE
extern "C" NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status;
KdPrint(("Enter DriverEntry\n"));
//注册其他驱动调用函数
pDriverObject->DriverUnload = DriverUnload;

status = CreateDevice(pDriverObject);

Test(L"NtOpenProcess");

KdPrint(("Leave DriverEntry\n"));
return status;
}

/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动对象
* 返回 值:返回初始化状态
*************************************************************************/
#pragma INITCODE
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;

//创建设备名称
UNICODE_STRING devName;
UNICODE_STRING symLinkName;
RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");

//创建设备
status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION),
&devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);
if(!NT_SUCCESS(status))
return status;
pDevObj->Flags |= DO_BUFFERED_IO;
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->pDevice = pDevObj;
pDevExt->ustrDeviceName = devName;
//创建符号链接
RtlInitUnicodeString(&symLinkName, L"\\??\\MyDDKDevice");
pDevExt->ustrSymLinkName = symLinkName;
status = IoCreateSymbolicLink(&symLinkName, &devName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pDevObj);
return status;
}

return status;
}

/************************************************************************
* 函数名称:DriverUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
KdPrint(("Enter DriverUnload"));
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload"));
pNextObj = pDriverObject->DeviceObject;
while(pNextObj != NULL)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;

//删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
IoDeleteSymbolicLink(&pLinkName);
pNextObj = pNextObj->NextDevice;
IoDeleteDevice(pDevExt->pDevice);
}
KdPrint(("Leave DriverUnload"));

HookSSDTFunction(MyNtOpenProcess, OldNtOpenProcess);
KdPrint(("Leave DriverUnload"));
}

/************************************************************************
* 函数名称:DispatchRoutine
* 功能描述:对读IRP进行处理
* 参数列表:
pDevObj:功能设备对象
pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS DispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("Enter DispatchRoutine"));
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("Leave DispatchRoutine"));
return status;
}


dbgview

Enter DriverEntry

Hook之前调用MmGetSystemRoutineAddress: 0x805CC3FC

Hook之后直接用NtOpenProcess名 805CC3FC

Enter HookSSDTFunction

修改前: HOOK Func addr=0XF7CC2490

修改前: Need Hook addr=0X805CC3FC

修改后: Need Hook addr=0XF7CC2490

Leave HookSSDTFunction

Hook之后调用MmGetSystemRoutineAddress: 0x805CC3FC

Hook之后直接用NtOpenProcess名 805CC3FC

Leave DriverEntry

Enter DriverUnload

Enter DriverUnload

Leave DriverUnload

Enter HookSSDTFunction

修改前: HOOK Func addr=0X805CC3FC

修改前: Need Hook addr=0XF7CC2490

修改后: Need Hook addr=0X805CC3FC

Leave HookSSDTFunction

Leave DriverUnload

得出的结论就是貌似只有调用Zw*函数才会用SSDT表哎。。。。Nt*号函数都是直接用的地址来着
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: