首页
社区
课程
招聘
[原创]强制关闭进程的两种方法
2021-10-28 11:36 9139

[原创]强制关闭进程的两种方法

2021-10-28 11:36
9139

一.前言

实验平台是WIN XP sp3 x86。

要使用两种不同的方法来强制关闭进程。

二.通过PspTerminateProcess来关闭进程

在关闭进程的时候,PspTerminateProcess是一个比较底层的API。通过调用它来关闭进程可以绕过一些保护,该函数的定义如下

NTSTATUS 
PspTerminateProcess(
    EPROCESS pEprocess,
    NTSTATUS ExitCode);
参数含义
pEprocess要关闭的进程的EPROCESS
ExitCode进程的退出码

由于这个函数是未导出的,所以不能直接调用,要先在内存中找到这个函数才可以调用。这里选择找到这个函数的办法是通过内核模块遍历的办法来查找这个函数。

我们知道每一个内核模块都有一个DRIVER_OBJECT,该结构体的定义如下

typedef struct _DRIVER_OBJECT {
    CSHORT Type;
    CSHORT Size;
    PDEVICE_OBJECT DeviceObject;
    ULONG Flags;
    PVOID DriverStart;
    ULONG DriverSize;
    PVOID DriverSection;
    PDRIVER_EXTENSION DriverExtension;
    UNICODE_STRING DriverName;
    PUNICODE_STRING HardwareDatabase;
    PFAST_IO_DISPATCH FastIoDispatch;
    PDRIVER_INITIALIZE DriverInit;
    PDRIVER_STARTIO DriverStartIo;
    PDRIVER_UNLOAD DriverUnload;
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;

其中的第7个成员DriverSection,该成员指向的是一个LDR_DATA_TABLE_ENTRY,该结构体的定义如下

kd> dt _LDR_DATA_TABLE_ENTRY
nt!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY
   +0x008 InMemoryOrderLinks : _LIST_ENTRY
   +0x010 InInitializationOrderLinks : _LIST_ENTRY
   +0x018 DllBase          : Ptr32 Void
   +0x01c EntryPoint       : Ptr32 Void
   +0x020 SizeOfImage      : Uint4B
   +0x024 FullDllName      : _UNICODE_STRING
   +0x02c BaseDllName      : _UNICODE_STRING
   +0x034 Flags            : Uint4B
   +0x038 LoadCount        : Uint2B
   +0x03a TlsIndex         : Uint2B
   +0x03c HashLinks        : _LIST_ENTRY
   +0x03c SectionPointer   : Ptr32 Void
   +0x040 CheckSum         : Uint4B
   +0x044 TimeDateStamp    : Uint4B
   +0x044 LoadedImports    : Ptr32 Void
   +0x048 EntryPointActivationContext : Ptr32 Void
   +0x04c PatchInformation : Ptr32 Void

本实验要用到的几个关键成员

成员含义
InLoadOrderLinks双向链表,指向上一个或者下一个LDR_DATA_TABLE_ENTRY结构
DllBase该模块加载的基地址
SizeOfImage模块的大小

由于这个双向链表的存在,就可以找到内存中所有内核模块,在从这些内核模块中一一通过特征码匹配的方式就可以找到PspTerminateProcess函数地址。接下来就要从PspTerminateProcess中找到特征码了,首先查看PspTerminateProcess函数的内容

kd> u PspTerminateProcess L30
nt!PspTerminateProcess:
805d3482 8bff            mov     edi,edi
805d3484 55              push    ebp
805d3485 8bec            mov     ebp,esp
805d3487 56              push    esi
805d3488 64a124010000    mov     eax,dword ptr fs:[00000124h]
805d348e 8b7508          mov     esi,dword ptr [ebp+8]
805d3491 3b7044          cmp     esi,dword ptr [eax+44h]
805d3494 7507            jne     nt!PspTerminateProcess+0x1b (805d349d)
805d3496 b80d0000c0      mov     eax,0C000000Dh
805d349b eb5a            jmp     nt!PspTerminateProcess+0x75 (805d34f7)
805d349d 57              push    edi
805d349e 8dbe48020000    lea     edi,[esi+248h]
805d34a4 f6470120        test    byte ptr [edi+1],20h
805d34a8 7412            je      nt!PspTerminateProcess+0x3a (805d34bc)
805d34aa 8d8674010000    lea     eax,[esi+174h]
805d34b0 50              push    eax
805d34b1 56              push    esi
805d34b2 6854345d80      push    offset nt!NtTerminateProcess+0x14c (805d3454)
805d34b7 e8f2eeffff      call    nt!PspCatchCriticalBreak (805d23ae)
805d34bc 6a08            push    8
805d34be 58              pop     eax
805d34bf f00907          lock or dword ptr [edi],eax
805d34c2 6a00            push    0
805d34c4 56              push    esi
805d34c5 e8ca560000      call    nt!PsGetNextProcessThread (805d8b94)
805d34ca 8bf8            mov     edi,eax
805d34cc 85ff            test    edi,edi
805d34ce 741e            je      nt!PspTerminateProcess+0x6c (805d34ee)
805d34d0 ff750c          push    dword ptr [ebp+0Ch]
805d34d3 57              push    edi
805d34d4 e807fdffff      call    nt!PspTerminateThreadByPointer (805d31e0)
805d34d9 57              push    edi
805d34da 56              push    esi
805d34db e8b4560000      call    nt!PsGetNextProcessThread (805d8b94)
805d34e0 8bf8            mov     edi,eax
805d34e2 85ff            test    edi,edi
805d34e4 75ea            jne     nt!PspTerminateProcess+0x4e (805d34d0)
805d34e6 3986bc000000    cmp     dword ptr [esi+0BCh],eax
805d34ec 7406            je      nt!PspTerminateProcess+0x72 (805d34f4)
805d34ee 56              push    esi
805d34ef e86e05ffff      call    nt!ObClearProcessHandleTable (805c3a62)
805d34f4 33c0            xor     eax,eax
805d34f6 5f              pop     edi
805d34f7 5e              pop     esi
805d34f8 5d              pop     ebp
805d34f9 c20800          ret     8
805d34fc cc              int     3
805d34fd cc              int     3

从中挑选如下代码

805d3487 56              push    esi
805d3488 64a124010000    mov     eax,dword ptr fs:[00000124h]
805d348e 8b7508          mov     esi,dword ptr [ebp+8]
805d3491 3b7044          cmp     esi,dword ptr [eax+44h]
805d3494 7507            jne     nt!PspTerminateProcess+0x1b (805d349d)
805d3496 b80d0000c0      mov     eax,0C000000Dh
805d349b eb5a            jmp     nt!PspTerminateProcess+0x75 (805d34f7)
805d349d 57              push    edi

就可以提取出相应的特征码如下

UCHAR szSpecialCode[] = {0x56, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B, 
		     0x75, 0x08, 0x3B, 0x70, 0x44, 0x75, 0x07, 0xB8, 
			 0x0D, 0x00, 0x00, 0xC0, 0xEB, 0x5A, 0x57 };

接下来要做的就是遍历内核模块在用这个特征码找到相应的函数地址,随后在调用该函数来关闭进程

#include <ntifs.h>

typedef struct _LDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID DllBase;
	PVOID EntryPoint;
	UINT32 SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	UINT32 Flags;
	UINT16 LoadCount;
	UINT16 TlsIndex;
	LIST_ENTRY HashLinks;
	PVOID SectionPointer;
	UINT32 CheckSum;
	UINT32 TimeDateStamp;
	PVOID LoadedImports;
	PVOID EntryPointActivationContext;
	PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef NTSTATUS (*pfnPspTerminateProcess)(PEPROCESS pEprocess, NTSTATUS ExitCode);

VOID DriverUnload(IN PDRIVER_OBJECT driverObject);
PVOID SearchFunction(PUCHAR DllBase, UINT32 SizeOfImage);	// 查找模块中匹配特征码

ULONG g_uPID = 1700;	// 要关闭的进程PID
// 特征码
UCHAR g_szSpecialCode[] = {0x56, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B, 
	0x75, 0x08, 0x3B, 0x70, 0x44, 0x75, 0x07, 0xB8, 
	0x0D, 0x00, 0x00, 0xC0, 0xEB, 0x5A, 0x57 };
UINT32 g_uSpecialCodeLen = sizeof(g_szSpecialCode);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry = NULL;
	pfnPspTerminateProcess pPspTerminateProcess = NULL;
	PEPROCESS pEprocess = NULL;	
	
	DbgPrint("驱动加载完成\r\n");
	
	pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)driverObject->DriverSection;
	pLdrDataTableEntry = CONTAINING_RECORD(pLdrDataTableEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
	pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink;
	do 
	{
		pLdrDataTableEntry = CONTAINING_RECORD(pLdrDataTableEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
		if (pLdrDataTableEntry->DllBase)
		{
			pPspTerminateProcess = (pfnPspTerminateProcess)SearchFunction((PUCHAR)pLdrDataTableEntry->DllBase, pLdrDataTableEntry->SizeOfImage);
		}
		if (pPspTerminateProcess)	break;
		pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink;
	} while ((UINT32)pLdrDataTableEntry != (UINT32)driverObject->DriverSection);

	if (pPspTerminateProcess)
	{
		status = PsLookupProcessByProcessId((HANDLE)g_uPID, &pEprocess);
		if (NT_SUCCESS(status))
		{
			status = pPspTerminateProcess(pEprocess, 0);
			if (NT_SUCCESS(status))
			{
				DbgPrint("关闭进程成功, PID=%d\r\n", g_uPID);
			}
		}
		else
		{
			DbgPrint("PsLookupProcessByProcessId Error 0x%X\r\n", status);
		}
	}

	driverObject->DriverUnload = DriverUnload;
exit:
	return STATUS_SUCCESS;
}

VOID DriverUnload(IN PDRIVER_OBJECT driverObject)
{
	DbgPrint("驱动卸载完成\r\n");
}

PVOID SearchFunction(PUCHAR DllBase, UINT32 SizeOfImage)
{
	PVOID pFuncAddr = NULL;
	UINT32 uEnd = (UINT32)DllBase + SizeOfImage - g_uSpecialCodeLen, i = 0;
	BOOLEAN bOk = TRUE;
	
	while ((UINT32)DllBase <= uEnd)
	{
		bOk = TRUE;
		for (i = 0; i < g_uSpecialCodeLen; i++)
		{
			if (!MmIsAddressValid(&DllBase[i]) || DllBase[i] != g_szSpecialCode[i])
			{
				bOk = FALSE;
				break;
			}
		}

		if (bOk)
		{
			pFuncAddr = (PVOID)(DllBase - 5);	
			break;
		}
		DllBase++;
	}

	return pFuncAddr;
}

三.通过PspTerminateThreadByPointer函数来关闭进程

想要关闭进程,可以通过将进程中的所有线程全部关闭。因为当这个进程中的所有线程都被关闭的时候,这个进程就已经没有意义,等同于被关闭。Windows为程序员提供了一个导出函数PsTerminateSystemThread来关闭线程,但由于这个函数往往会被安全软件监控,所以这里选择更为底层的函数,也就是PspTerminateThreadByPointer函数来关闭进程。

该函数的定义如下

NTSTATUS 
PspTerminateThreadByPointer(PETHREAD pEThread,
                            NTSTATUS ntExitCode,
                            BOOLEAN bDirectTerminate);

这个函数在32位和64位中的区别仅仅是调用约定的不同

// 64 位
typedef NTSTATUS(__fastcall *pfnPspTerminateThreadByPointer) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);

// 32 位
typedef NTSTATUS(*pfnPspTerminateThreadByPointer) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);

要找到这个函数,这里就通过找到导出函数PsTerminateSystemThread,并通过特征码的方式找到目标函数。PsTerminateSystemThread函数的实现如下

kd> u PsTerminateSystemThread L10
nt!PsTerminateSystemThread:
805d3594 8bff            mov     edi,edi
805d3596 55              push    ebp
805d3597 8bec            mov     ebp,esp
805d3599 64a124010000    mov     eax,dword ptr fs:[00000124h]
805d359f f6804802000010  test    byte ptr [eax+248h],10h
805d35a6 7507            jne     nt!PsTerminateSystemThread+0x1b (805d35af)
805d35a8 b80d0000c0      mov     eax,0C000000Dh
805d35ad eb09            jmp     nt!PsTerminateSystemThread+0x24 (805d35b8)
805d35af ff7508          push    dword ptr [ebp+8]
805d35b2 50              push    eax
805d35b3 e828fcffff      call    nt!PspTerminateThreadByPointer (805d31e0)
805d35b8 5d              pop     ebp
805d35b9 c20400          ret     4

由上可知,选择0xE8作为特征码就可以找到目标函数。有了这个函数,就可以关闭线程。接下来只需要遍历所有的线程判断该线程是不是属于要关闭的进程,如果是的话就把它关掉。

具体代码如下

#include <ntifs.h>

typedef NTSTATUS(*pfnPspTerminateThreadByPointer)(PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);

VOID DriverUnload(IN PDRIVER_OBJECT driverObject);
PVOID FindTargetFunc();	// 寻找函数地址
PEPROCESS PsGetThreadProcess(PETHREAD pEThraed);	// 根据EPROCESS得到EPROCESS

ULONG g_uPID = 176;	// 要关闭的进程PID

NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	PETHREAD pEThread = NULL;
	PEPROCESS pEProcess = NULL, pThreadProcess = NULL;
	ULONG uThreadId = 0;
	pfnPspTerminateThreadByPointer PspTerminateThreadByPointer = NULL;
	PspTerminateThreadByPointer = (pfnPspTerminateThreadByPointer)FindTargetFunc();

	if (PspTerminateThreadByPointer == NULL)
	{
		goto exit;
	}

	//获取要关闭的进程的EPROCESS
	status = PsLookupProcessByProcessId((HANDLE)g_uPID, &pEProcess);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("PsLookupProcessByProcessId Error 0x%X\r\n", status);
		goto exit;
	}

	// 遍历所有线程
	for (uThreadId = 4; uThreadId < 0x8000; uThreadId += 4)
	{
		status = PsLookupThreadByThreadId((HANDLE)uThreadId, &pEThread);
		if (NT_SUCCESS(status))
		{
			// 获取线程对应的进程结构对象
			pThreadProcess = PsGetThreadProcess(pEThread);
			if (pThreadProcess == pEProcess)
			{
				PspTerminateThreadByPointer(pEThread, 0, 1);
				DbgPrint("成功关闭线程\r\n");
			}
			ObDereferenceObject(pEThread);
		}
	}
	ObDereferenceObject(pEProcess);
	driverObject->DriverUnload = DriverUnload;
exit:
	return STATUS_SUCCESS;
}

VOID DriverUnload(IN PDRIVER_OBJECT driverObject)
{
	DbgPrint("驱动卸载完成\r\n");
}

PVOID FindTargetFunc()
{
	PVOID pFunAddr = NULL;
	PUCHAR pPsTerminateSystemThreadAddr = NULL;
	UNICODE_STRING uStrFuncName = RTL_CONSTANT_STRING(L"PsTerminateSystemThread");

	pPsTerminateSystemThreadAddr = (PUCHAR)MmGetSystemRoutineAddress(&uStrFuncName);
	while (MmIsAddressValid(pPsTerminateSystemThreadAddr) && *pPsTerminateSystemThreadAddr != 0xC2)
	{
		if (*pPsTerminateSystemThreadAddr == 0xE8)
		{
			pFunAddr = (PVOID)((ULONG)pPsTerminateSystemThreadAddr + 5 + *(PULONG)(pPsTerminateSystemThreadAddr + 1));
			break;
		}
		pPsTerminateSystemThreadAddr++;
	}
	return pFunAddr;
}



[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2021-11-30 10:03 被1900编辑 ,原因:
收藏
点赞3
打赏
分享
最新回复 (3)
雪    币: 204
活跃值: (714)
能力值: ( LV9,RANK:195 )
在线值:
发帖
回帖
粉丝
palkiver 2021-10-28 17:47
2
0
WIN11都出来了,别整XP了
雪    币: 22395
活跃值: (25272)
能力值: ( LV15,RANK:910 )
在线值:
发帖
回帖
粉丝
1900 6 2021-10-28 19:54
3
0
palkiver WIN11都出来了,别整XP了
学习用的
雪    币: 52
活跃值: (227)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
听风飞雪 2021-10-30 18:33
4
0
游客
登录 | 注册 方可回帖
返回