进程之驱动保护

最近在分析某度盘加速软件的时候会发现,我开的代理或者工作的时候使用的抓包软件会莫名其妙的掉,比如Proxifer 什么的,当时很纳闷。后经过资料查找发现,这个软件不单单做代理分流用,还可以用于软件的https抓包……所以一切都是那么显然了,遂很好奇抓抓玩一玩了。

开始

其实感觉过这东西应该没啥难度,修改一下名字就完事了,或者某些不是用时钟做进程监控的,打开程序再打开代理就行。然后主要想练练驱动开发,就小记一下驱动开发的代码,主要是进程对象的回调。

首先注册一下自己的回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 设置进程回调函数
NTSTATUS SetProcessCallbacks()
{
NTSTATUS status = STATUS_SUCCESS;
OB_CALLBACK_REGISTRATION obCallbackReg = { 0 };
OB_OPERATION_REGISTRATION obOperationReg = { 0 };
RtlZeroMemory(&obCallbackReg, sizeof(OB_CALLBACK_REGISTRATION));
RtlZeroMemory(&obOperationReg, sizeof(OB_OPERATION_REGISTRATION));
// 设置 OB_CALLBACK_REGISTRATION
obCallbackReg.Version = ObGetFilterVersion();
obCallbackReg.OperationRegistrationCount = 1;
obCallbackReg.RegistrationContext = NULL;
RtlInitUnicodeString(&obCallbackReg.Altitude, L"321000");
obCallbackReg.OperationRegistration = &obOperationReg;
// 设置 OB_OPERATION_REGISTRATION
// Thread 和 Process 的区别所在
obOperationReg.ObjectType = PsProcessType;
obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
// Thread 和 Process 的区别所在
obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ProcessPreCall);
// 注册回调函数
status = ObRegisterCallbacks(&obCallbackReg, &g_obProcessHandle);
if (!NT_SUCCESS(status))
{
DbgPrint("ObRegisterCallbacks Error[0x%X]\n", status);
return status;
}
return status;
}

这里的Altitude一定不能为空。

然后我们实现一下当操作进程句柄的时候,产生回调的处理办法。当结束一个进程,肯定要获取进程句柄,此时,我们可以给他进行降低权限,这样想结束进程的这个进程就会发现权限不够结束失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 进程回调函数
OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo)
{
// 判断对象类型
if (*PsProcessType != pObPreOperationInfo->ObjectType)
{
return OB_PREOP_SUCCESS;
}

//获取进程名称
HANDLE pid = PsGetProcessId((PEPROCESS)pObPreOperationInfo->Object);
char szProcName[16] = { 0 };
UNREFERENCED_PARAMETER(RegistrationContext);
strcpy(szProcName, GetProcessNameByProcessID(pid));

// 判断是否是保护进程, 若是, 则拒绝结束进程
if (!_stricmp(szProcName, "Proxifier.exe"))
{
// 操作类型: 创建句柄
if (OB_OPERATION_HANDLE_CREATE == pObPreOperationInfo->Operation)
{
if (1 == (1 & pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess))
{
pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess = 0;
}
}
// 操作类型: 复制句柄
else if (OB_OPERATION_HANDLE_DUPLICATE == pObPreOperationInfo->Operation)
{
if (1 == (1 & pObPreOperationInfo->Parameters->DuplicateHandleInformation.OriginalDesiredAccess))
{
pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess = 0;
}
}
}
return OB_PREOP_SUCCESS;
}

主要就是判断一下,操作的那个进程,是不是要保护的,是的话就提示权限不足,不然所有进程都结束不了感觉有点影响正常操作了。

另外补充一小小的工具函数

1
2
3
4
5
6
7
8
9
10
11
12
13
char* GetProcessNameByProcessID(HANDLE pid)
{
NTSTATUS status;
PEPROCESS EProcess = NULL;
status = PsLookupProcessByProcessId(pid, &EProcess);

if (!NT_SUCCESS(status))
{
return FALSE;
}
ObDereferenceObject(EProcess);
return (char*)PsGetProcessImageFileName(EProcess);
}

该函数就是在内核状态下,通过PID获取进程的名称,这样一边我们判断是否是保护函数。

自黑

但是,该保护方式有个缺陷,并不是所有进程都走回调函数的,所以像一些内存清空大法,甚至使用

1
2
3
4
5
BOOL EndTask(
HWND hWnd,
BOOL fShutDown,
BOOL fForce
);

就可以轻松绕过该回调拦截。