首页 > 系统相关 >驱动开发:内核强制结束进程运行

驱动开发:内核强制结束进程运行

时间:2022-10-29 10:31:08浏览次数:42  
标签:PsTerminateSystemThread return pCurrentEprocess fffff802 内核 进程 驱动 强制 NULL

通常使用Windows系统自带的任务管理器可以正常地结束掉一般进程,而某些特殊的进程在应用层很难被结束掉,例如某些系统核心进程其权限是在0环内核态,但有时我们不得不想办法结束掉这些特殊的进程,当然某些正常进程在特殊状态下也会无法被正常结束,此时使用驱动前行在内核态将其结束掉就变得很有用了,驱动结束进程有多种方法。

  • 1.标准方法就是使用ZwOpenProcess打开进程获得句柄,然后使用ZwTerminateProcess这个内核API实现结束进程,最后使用ZwClose关闭句柄。
  • 2.第二种方法,通过动态定位的方式找到PspTerminateThreadByPointer这个内核函数地址,然后调用该函数结束掉进程中所有的线程,当线程为空则进程也就消亡了。
  • 3.第三种方法,我将其称作是内存清零法,其核心原理是通过打开进程,得到进程的基址,通过内存填充的方式将对端内存全部置0实现类似于结束的效果。

首先是第一种方法结束进程,封装实现KillProcess函数,用户传入lyshark.exe进程名,进程内执行PsGetProcessImageFileName判断是否是我们要结束的如果是则,调用ZwOpenProcess打开进程,并发送ZwTerminateProcess终止信号从而正常结束,其核心代码如下所示。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntifs.h>

NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);

// 根据进程ID返回进程EPROCESS结构体,失败返回NULL
PEPROCESS GetProcessNameByProcessId(HANDLE pid)
{
	PEPROCESS ProcessObj = NULL;
	NTSTATUS Status = STATUS_UNSUCCESSFUL;
	Status = PsLookupProcessByProcessId(pid, &ProcessObj);
	if (NT_SUCCESS(Status))
		return ProcessObj;
	return NULL;
}

// 根据ProcessName获取到进程的PID号
HANDLE GetPidByProcessName(char *ProcessName)
{
	PEPROCESS pCurrentEprocess = NULL;
	HANDLE pid = 0;
	for (int i = 0; i < 1000000000; i += 4)
	{
		pCurrentEprocess = GetProcessNameByProcessId((HANDLE)i);
		if (pCurrentEprocess != NULL)
		{
			pid = PsGetProcessId(pCurrentEprocess);
			if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
			{
				ObDereferenceObject(pCurrentEprocess);
				return pid;
			}
			ObDereferenceObject(pCurrentEprocess);
		}
	}
	return (HANDLE)-1;
}

// 传入进程名称,终止掉该进程
BOOLEAN KillProcess(PCHAR ProcessName)
{
	PEPROCESS pCurrentEprocess = NULL;
	HANDLE pid = 0;
	HANDLE Handle = NULL;
	OBJECT_ATTRIBUTES obj;
	CLIENT_ID cid = { 0 };
	NTSTATUS Status = STATUS_UNSUCCESSFUL;

	for (int i = 0; i < 10000000; i += 4)
	{
		pCurrentEprocess = GetProcessNameByProcessId((HANDLE)i);
		if (pCurrentEprocess != NULL)
		{
			pid = PsGetProcessId(pCurrentEprocess);

			// 判断当前镜像名称是否是需要结束的进程
			if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
			{
				ObDereferenceObject(pCurrentEprocess);

				// 找到后开始结束
				InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
				cid.UniqueProcess = (HANDLE)pid;
				cid.UniqueThread = 0;

				// 打开进程
				Status = ZwOpenProcess(&Handle, GENERIC_ALL, &obj, &cid);
				if (NT_SUCCESS(Status))
				{
					// 发送终止信号
					ZwTerminateProcess(Handle, 0);
					ZwClose(Handle);
				}
				ZwClose(Handle);
				return TRUE;
			}
			ObDereferenceObject(pCurrentEprocess);
		}
	}
	return FALSE;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驱动已卸载 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");

	BOOLEAN Retn;
	Retn = KillProcess("lyshark.exe");
	DbgPrint("结束状态: %d \n", Retn);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

我们运行这个驱动,当进程lyshark.exe存在时则可以看到结束效果,当然这种方式只是在内核层面调用了结束进程函数,其本质上还是正常结束,只是这种方式权限要大一些仅此而已。

第二种方法,其原理就是将进程内的线程全部结束掉从而让进程自动结束,由于PspTerminateThreadByPointer没有被导出,所以我们需要动态的这个内存地址,然后动态调用即可,这个寻找方法可以总结为以下步骤。

  • 1.寻找PsTerminateSystemThread函数地址,这个地址可以直接通过MmGetSystemRoutineAddress函数得到。
  • 2.在PsTerminateSystemThread函数地址内向下扫描特征e80cb6f6ff得到call nt!PspTerminateThreadByPointer地址。

根据《驱动开发:内核枚举LoadImage映像回调》中使用的SearchMemory函数实现搜索PspTerminateThreadByPointer内存地址。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntifs.h>

// 得到PspTerminateThreadByPointer内存地址
PVOID PspTerminateThreadByPointer()
{
	UNICODE_STRING ustrFuncName;
	PVOID pAddress = NULL;
	LONG lOffset = 0;
	PVOID pPsTerminateSystemThread = NULL;
	PVOID pPspTerminateThreadByPointer = NULL;

	// 获取 PsTerminateSystemThread 函数地址
	RtlInitUnicodeString(&ustrFuncName, L"PsTerminateSystemThread");
	pPsTerminateSystemThread = MmGetSystemRoutineAddress(&ustrFuncName);
	
	DbgPrint("pPsTerminateSystemThread = 0x%p \n", pPsTerminateSystemThread);
	if (NULL == pPsTerminateSystemThread)
	{
		return 0;
	}

	// 查找 PspTerminateThreadByPointer 函数地址

	/*
	1: kd> uf PsTerminateSystemThread
			nt!PsTerminateSystemThread:
			fffff802`254e6a90 4883ec28        sub     rsp,28h
			fffff802`254e6a94 8bd1            mov     edx,ecx
			fffff802`254e6a96 65488b0c2588010000 mov   rcx,qword ptr gs:[188h]
			fffff802`254e6a9f f7417400040000  test    dword ptr [rcx+74h],400h
			fffff802`254e6aa6 0f8444081100    je      nt!PsTerminateSystemThread+0x110860 (fffff802`255f72f0)  Branch

			nt!PsTerminateSystemThread+0x1c:
			fffff802`254e6aac 41b001          mov     r8b,1
			fffff802`254e6aaf e80cb6f6ff      call    nt!PspTerminateThreadByPointer (fffff802`254520c0)

			nt!PsTerminateSystemThread+0x24:
			fffff802`254e6ab4 4883c428        add     rsp,28h
			fffff802`254e6ab8 c3              ret

			nt!PsTerminateSystemThread+0x110860:
			fffff802`255f72f0 b80d0000c0      mov     eax,0C000000Dh
			fffff802`255f72f5 e9baf7eeff      jmp     nt!PsTerminateSystemThread+0x24 (fffff802`254e6ab4)  Branch
	*/

	UCHAR pSpecialData[50] = { 0 };
	ULONG ulSpecialDataSize = 0;

	// fffff802`254e6aaf e80cb6f6ff      call    nt!PspTerminateThreadByPointer (fffff802`254520c0)
	pSpecialData[0] = 0xE8;
	ulSpecialDataSize = 1;

	// 搜索地址 PsTerminateSystemThread --> PsTerminateSystemThread + 0xff 查找 e80cb6f6ff
	pAddress = SearchMemory(pPsTerminateSystemThread, (PVOID)((PUCHAR)pPsTerminateSystemThread + 0xFF), pSpecialData, ulSpecialDataSize);
	if (NULL == pAddress)
	{
		return 0;
	}

	// 先获取偏移,再计算地址
	lOffset = *(PLONG)pAddress;
	pPspTerminateThreadByPointer = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset);
	if (NULL == pPspTerminateThreadByPointer)
	{
		return 0;
	}

	return pPspTerminateThreadByPointer;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驱动已卸载 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");

	PVOID address = PspTerminateThreadByPointer();

	DbgPrint("PspTerminateThreadByPointer = 0x%p \n", address);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

运行驱动程序,首先得到PspTerminateThreadByPointer的内存地址,效果如下。

得到内存地址以后直接将地址typedef转为指针函数,调用并批量结束进程内的线程即可。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntifs.h>

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

VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驱动已卸载 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");

	PVOID pPspTerminateThreadByPointerAddress = 0xFFFFF802254520C0;
	HANDLE hProcessId = 6956;

	PEPROCESS pEProcess = NULL;
	PETHREAD pEThread = NULL;
	PEPROCESS pThreadEProcess = NULL;
	NTSTATUS status = STATUS_SUCCESS;
	ULONG i = 0;

	// 获取结束进程的进程结构对象EPROCESS
	status = PsLookupProcessByProcessId(hProcessId, &pEProcess);
	if (!NT_SUCCESS(status))
	{
		return status;
	}
	// 遍历所有线程, 并结束所有指定进程的线程
	for (i = 4; i < 0x80000; i = i + 4)
	{
		status = PsLookupThreadByThreadId((HANDLE)i, &pEThread);
		if (NT_SUCCESS(status))
		{
			// 获取线程对应的进程结构对象
			pThreadEProcess = PsGetThreadProcess(pEThread);

			// 结束进程中的线程
			if (pEProcess == pThreadEProcess)
			{
				((PSPTERMINATETHREADBYPOINTER)pPspTerminateThreadByPointerAddress)(pEThread, 0, 1);
				DbgPrint("结束线程: %d \n", i);
			}
			ObDereferenceObject(pEThread);
		}
	}
	ObDereferenceObject(pEProcess);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

循环结束进程6956内的所有线程信息,效果如下;

标签:PsTerminateSystemThread,return,pCurrentEprocess,fffff802,内核,进程,驱动,强制,NULL
From: https://blog.51cto.com/lyshark/5805754

相关文章

  • Linux内核设计与实现 第三版 电子书 pdf
    作者:[美]RobertLove出版社:机械工业出版社原作名:LinuxKernelDevelopment译者:陈莉君/康华 链接:Linux内核设计与实现第三版  本书详细描述了Linux内......
  • 奔跑吧Linux内核 电子书 pdf
    作者:张天飞出版社:人民邮电出版社链接:奔跑吧Linux内核  本书内容基于Linux4.x内核,主要选取了Linux内核中比较基本和常用的内存管理、进程管理、并发与同步,以及......
  • Linux内核完全注释 修正版 电子书 pdf
    作者:赵炯出版社:机械工业出版社 链接:Linux内核完全注释  Linux内核完全注释,ISBN:9787111149682,作者:赵炯编著......
  • 驱动开发:内核监控FileObject文件回调
    本篇文章与上一篇文章《驱动开发:内核注册并监控对象回调》所使用的方式是一样的都是使用ObRegisterCallbacks注册回调事件,只不过上一篇博文中LyShark将回调结构体OB_OPERATI......
  • 领域驱动设计(1)--概念与生命周期
    注:这本书曾经根本看不进去,但是在别人的提纲挈领的讲解下,突然觉得这一块可以进行一些阅读。一、主题领域模型就是对于业务的概念、概念间的关系以及概念本质的认知。为了控制......
  • 《领域驱动设计》:从领域视角深入仓储(Repository)的设计和实现
    简介: 《领域驱动设计》中的Repository(下面将用仓储表示)层实际上是极具有挑战性的,对于它的理解,也十分重要。本文讲大部分内容都在众多前辈理论基础上,从一个崭新的领域视觉......
  • 用户态和内核态
    那用户态和内核态又是啥呢?Linux系统的体系结构大家大学应该都接触过了,分为用户空间(应用程序的活动空间)和内核。我们所有的程序都在用户空间运行,进入用户运行状态也就是(用户......
  • 驱动开发:内核监控FileObject文件回调
    本篇文章与上一篇文章《驱动开发:内核注册并监控对象回调》所使用的方式是一样的都是使用ObRegisterCallbacks注册回调事件,只不过上一篇博文中LyShark将回调结构体OB_OPERAT......
  • win10 驱动无法安装 系统找不到指定文件
     在win10系统下的驱动安装出现“系统找不到指定文件”的错误,但禁用数字签名后仍然无法解决,事实上驱动文件是存在的,但我们可以通过查找报错文件来确定究竟是哪个文件找不......
  • Win11下强制使用IE11的方法
    因个别原因很多需要IE访问的页面,在edge中纵使打开ie模式也无法正常浏览。此时,无需安装任何插件即可打开原版IE11:1.设置edge浏览器的ie模式为从不强制使用edge打开ie页面2.......