首页
社区
课程
招聘
[原创]实现关闭进程函数,杀掉pchunter
发表于: 2018-3-24 15:46 11045

[原创]实现关闭进程函数,杀掉pchunter

2018-3-24 15:46
11045
    前段时间包同学到一家公司去面试,面试官问他如果不用TerminateProcess如何实现关闭进程。
现在问题摆在面前,如何解决这个问题,想了想最好的方法就是直接看操作系统怎么实现 TerminateProcess 的自己实现个就好了,在一定程度上就可以阻止别人通过hook技术来拦截.
    这段代码很早就写好了,但是帖子什么的一直没什么时间写(薛老师今天讲的壳还没有脱),写完这篇帖子去脱壳了
    另外: 本人小菜,大神们轻点喷

    开始吧!下面截图的代码都是win2000的代码,在看源码的同时有时候需要用ida打开win7的ntoskrnl.exe对比着看,所幸的是虽然经过很多版本更迭,但是这块的基本原理没啥变化,所以就尽量不贴ida反汇编的图了(可读性差)

    NtTerminateProcess的函数实现,其中最关键的 如图:

   

  

  这个函数主要干的事情就是遍历进程的线程,然后对每个线程执行PspTerminateThreadByPointer


    再分析下 PspTerminateThreadByPointer 函数的实现

     这个函数是分两种情况的:

     情况一,是线程自己关闭自己:直接执行PspExitThread

       

        PspExitThread这个函数太庞杂简单说下它的作用:

        1. 执行了一大堆清理代码,主要清理当前线程Ethread的资源

        2. 从调度链表和等待链表中去掉它

        3. 如果是进程的最后一个线程,直接清理进程空间

        4. 执行KiSwapThread切换到一个新线程去

         

    情况二,关闭掉别的线程:在对方线线程中插入一个内核apc,这个内核apc最后会调用PspExitThread函数

        

        


    

       PspTerminateThreadByPointer 和NtTerminateProcess分析总结:

       1. 所谓杀死进程,其实只要把每个线程杀死就好了,最后一个线程会负责收尸的

       2. 线程不能被杀死,只能自杀.所以如果想杀掉线程最好让它自己执行自杀代码,内核apc(后面会简单讲下内核apc,没法深入再讲就错题了)是个不错的选择


      内核Apc执行的时机(讲的不对请指正哈):

     1. 中断和异常返回,下面是ReatOs的代码(贴代码为证,避免别人说我瞎哔哔O(∩_∩)O哈哈~)

       

    2. 高irql转到第irql,这块直接看win732逆向的代码:KfLowerIrql

       

         主要关注: HalpCheckForSoftwareInterrrupt

         

          执行apc的地方就是KiDeliverApc

         

      3. 线程切换的时候,还是直接贴win2000的代码

        

       



        原理讲完了,现在直接贴效果图了:

        杀掉之前,写好进程id:

        


    执行完杀掉的代码:

 


另外直接附上代码:

 Entry.c

 

#include <KrTypeDef.h>
#include <ntddk.h>


//需要杀死的进程id
#define PCHUNTER_ID   3232

VOID DriverUnload(PDRIVER_OBJECT pDriver);
PEPROCESS LookupProcess(HANDLE hPid);
PETHREAD LookupThread(HANDLE hTid);
VOID KillProcess(PEPROCESS pEProcess);
ULONG GetPspTerminateThreadByPointer();
ULONG GetPspExitThread(ULONG PspTerminateThreadByPointer);
VOID SelfTerminateThread(
	KAPC *Apc,
	PKNORMAL_ROUTINE *NormalRoutine,
	PVOID *NormalContext,
	PVOID *SystemArgument1,
	PVOID *SystemArgument2);

fpTypePspExitThread g_fpPspExitThreadAddr = NULL;

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath)
{
	DbgBreakPoint();
	pDriver->DriverUnload = DriverUnload;

	//提前把函数查找出来
	ULONG uPspTerminateThreadByPointerAddr =  GetPspTerminateThreadByPointer();
	if (0 == uPspTerminateThreadByPointerAddr)
	{
		KdPrint(("查找PspTerminateThreadByPointerAddr地址出错\n"));
		return STATUS_SUCCESS;
	}
	g_fpPspExitThreadAddr = (fpTypePspExitThread)GetPspExitThread(uPspTerminateThreadByPointerAddr);
	if (NULL == g_fpPspExitThreadAddr)
	{
		KdPrint(("查找PspExitThread地址出错\n"));
		return STATUS_SUCCESS;
	}

	//
	PEPROCESS pProcess = LookupProcess((HANDLE)PCHUNTER_ID);
	if (NULL == pProcess)
	{
		KdPrint((("没有在PsCidTable中找到进程,尼玛不会隐藏了吧\n")));
	}
	else
	{
		KillProcess(pProcess);
	}

	return STATUS_SUCCESS;
}


VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	KdPrint(("驱动退出\n"));
}

PEPROCESS LookupProcess(HANDLE hPid)
{
	PEPROCESS pEProcess = NULL;
	if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &pEProcess)))
		return pEProcess;
	return NULL;
}

VOID KillProcess(PEPROCESS pEProcess)
{
	PEPROCESS pEProc = NULL;
	PETHREAD  pEThrd = NULL;
	ULONG i = 0;

	for (i = 4; i < 0x25600; i += 4)
	{
		pEThrd = LookupThread((HANDLE)i);
		if (!pEThrd)  continue;
		pEProc = IoThreadToProcess(pEThrd);
		if (pEProc == pEProcess)
		{
			PKAPC pApc = NULL;
			pApc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
			if (NULL == pApc) return;
			//插入内核apc
			KeInitializeApc(pApc, (PKTHREAD)pEThrd, OriginalApcEnvironment, (PKKERNEL_ROUTINE)&SelfTerminateThread, NULL, NULL, 0, NULL);
			KeInsertQueueApc(pApc, NULL, 0, 2);

		}
		ObDereferenceObject(pEThrd);
	}
}


PETHREAD LookupThread(HANDLE hTid)
{
	PETHREAD pEThread = NULL;
	if (NT_SUCCESS(PsLookupThreadByThreadId(hTid, &pEThread)))
		return pEThread;
	return NULL;
}


VOID SelfTerminateThread(
	KAPC *Apc, 
	PKNORMAL_ROUTINE *NormalRoutine, 
	PVOID *NormalContext, 
	PVOID *SystemArgument1, 
	PVOID *SystemArgument2)
{
	ExFreePool(Apc);
	g_fpPspExitThreadAddr(STATUS_SUCCESS);
}

ULONG GetPspTerminateThreadByPointer()
{
	UNICODE_STRING funcName;
	RtlInitUnicodeString(&funcName, L"PsTerminateSystemThread");
	ULONG step = 0;
	ULONG targetFunAddr = 0;
	ULONG baseFunAddr = (ULONG)MmGetSystemRoutineAddress(&funcName);
	for (step = baseFunAddr; step < (baseFunAddr + 1024); step++)
	{
		//searching for 0x50,0xe8
		if (((*(PUCHAR)(UCHAR*)(step - 1)) == 0x50) && ((*(PUCHAR)(UCHAR*)(step)) == 0xe8))
		{
			ULONG offset = *(PULONG)(step + 1);
			targetFunAddr = step + 5 + offset;
			break;
		}
	}
	return targetFunAddr;
} //PspExitThread stamp code:0x0c 0xe8

ULONG GetPspExitThread(ULONG PspTerminateThreadByPointer)
{
	ULONG step = 0;
	ULONG targetFunAddr = 0;
	ULONG baseFunc = PspTerminateThreadByPointer;
	for (step = baseFunc; step < (baseFunc + 1024); step++)
	{
		//searching for 0x0c,0xe8
		if (((*(PUCHAR)(UCHAR*)(step - 1)) == 0x0c) && ((*(PUCHAR)(UCHAR*)(step)) == 0xe8))
		{
			ULONG m_offset = *(PULONG)(step + 1);
			targetFunAddr = step + 5 + m_offset;
			break;
		}
	}
	return targetFunAddr;
} 

 KrTypeDef.h
#pragma  once
#include <ntifs.h>
#include <ntddk.h>
#pragma warning(disable:4189 4100)

typedef enum _KAPC_ENVIRONMENT
{
	OriginalApcEnvironment,
	AttachedApcEnvironment,
	CurrentApcEnvironment,
	InsertApcEnvironment
} KAPC_ENVIRONMENT;

typedef VOID (*PKNORMAL_ROUTINE) (
	IN PVOID NormalContext,
	IN PVOID SystemArgument1,
	IN PVOID SystemArgument2
	);

typedef VOID(*PKKERNEL_ROUTINE) (
	IN struct _KAPC *Apc,
	IN OUT PKNORMAL_ROUTINE *NormalRoutine,
	IN OUT PVOID *NormalContext,
	IN OUT PVOID *SystemArgument1,
	IN OUT PVOID *SystemArgument2
	);

typedef VOID(*PKRUNDOWN_ROUTINE) (
	IN struct _KAPC *Apc
	);

VOID NTAPI KeInitializeApc(__in PKAPC 	Apc,
	__in PKTHREAD 	Thread,
	__in KAPC_ENVIRONMENT 	TargetEnvironment,
	__in PKKERNEL_ROUTINE 	KernelRoutine,
	__in_opt PKRUNDOWN_ROUTINE 	RundownRoutine,
	__in PKNORMAL_ROUTINE 	NormalRoutine,
	__in KPROCESSOR_MODE 	Mode,
	__in PVOID 	Context
	);


BOOLEAN  NTAPI KeInsertQueueApc(IN PKAPC Apc,
	IN PVOID SystemArgument1,
	IN PVOID SystemArgument2,
	IN KPRIORITY PriorityBoost);



typedef VOID(NTAPI *fpTypePspExitThread)(
	IN NTSTATUS ExitStatus
	);

#define OFFSET(type, f) ((SIZE_T) \
	((char *)&((type *)0)->f - (char *)(type *)0))


ps:代码有处bug,就是假设在杀线程的同时创建线程怎么办?


最后谢谢大家!

               

   

  

[课程]FART 脱壳王!加量不加价!FART作者讲授!

最后于 2019-5-10 10:48 被又出bug了编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (14)
雪    币: 775
活跃值: (2292)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
学习了 
2018-3-24 15:50
0
雪    币: 160
活跃值: (245)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
厉害
2018-3-24 16:02
0
雪    币: 310
活跃值: (2227)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2018-3-24 16:54
0
雪    币: 10
活跃值: (36)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
厉害
2018-3-24 23:21
0
雪    币: 1176
活跃值: (1234)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
6
让进程crash就行了…    上啥驱动 
2018-3-25 12:00
0
雪    币: 9210
活跃值: (1871)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
实验环境不是15pb-win7,差评,哈哈
2018-3-25 12:24
0
雪    币: 683
活跃值: (622)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
不错
2018-3-25 12:58
0
雪    币: 1050
活跃值: (1208)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
前段时间包同学到一家公司去面试,面试官问他如果不用TerminateProcess如何实现关闭进程,作为一个快要毕业的人来说对这个问题很敏感,毕竟也要面对这关.

TerminateProcess这明显不是问的R3下面怎么杀吗?R0有什么好说的?
2018-3-26 18:03
0
雪    币: 10
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
非常感谢教学    谢谢    学习了
2018-3-26 21:45
0
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
2018-3-26 23:42
0
雪    币: 81
活跃值: (40)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
12
实际应用中,内核NtTerminateProcess基本上都能结束掉,包括杀软,
2018-3-27 11:04
0
雪    币: 171
活跃值: (509)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
内存清零就好了,,,,,,
2018-3-27 13:12
0
雪    币: 3700
活跃值: (3817)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
感谢分享!
2018-3-28 09:25
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
Lthis 内存清零就好了,,,,,,
同感
2018-3-28 20:43
0
游客
登录 | 注册 方可回帖
返回
//