[内核编程]进程操作

1. 进程枚举


首先来介绍2个重要函数:

PCHAR PsGetProcessImageFileName(IN PEPROCESS pProcess)

这个函数是从内核导出的,声明后可以直接使用

作用是可以通过EPROCESS的指针获取对应进程映像名。实际上直接从EPROCESS结构内自己获取也可以。

 该函数在ntifs.h内有声明,包含后就可以直接使用。

作用是通过PID获取对应进程的EPROCESS结构。

看一个例子:

NTSYSCALLAPI PCHAR PsGetProcessImageFileName(IN PEPROCESS pProcess);

VOID EnumProcess()
{
	ULONG64 iPID = 0;
	PEPROCESS EProcess = NULL;
	NTSTATUS Status = STATUS_SUCCESS;

    // 由于进程号都是以4为倍数的
	for (iPID = 4; iPID < 20000; iPID += 4)
	{
		Status = PsLookupProcessByProcessId(iPID, &EProcess);
		if (NT_SUCCESS(Status))
		{
			KdPrint(("%d\t%s\r\n", iPID, PsGetProcessImageFileName(EProcess)));
		}
	}
}

直接调用这个函数就可以列出进程列表。

2. 进程挂起与调度


在Ring3下Windows没有直接可以挂起进程的API,但是内核下却是有的。

挂起进程函数:

NTSTATUS PsSuspendProcess(PEPROCESS Process)

其可以通过进程的EPROCESS结构来挂起对应进程

调度进程函数:

NTSTATUS PsResumeProcess(PEPROCESS Process)

其可以通过进程的EPROCESS结构来继续对应进程

来看一下对应的功能代码:

/****************************
* 这些函数从内核导出但未声明	*
****************************/
// 从EPROCESS结构获取对应的进程映像名
NTSYSCALLAPI PCHAR PsGetProcessImageFileName(IN PEPROCESS pProcess);
// 进程挂起与调度内核函数
NTSYSCALLAPI NTSTATUS PsSuspendProcess(PEPROCESS Process);
NTSYSCALLAPI NTSTATUS PsResumeProcess(PEPROCESS Process);

VOID R0ProcessOpa(ULONG64 ulPID, BOOLEAN fHang)
{
	PEPROCESS Process;
	NTSTATUS status;
	HANDLE hPID = (HANDLE)ulPID;

	status = PsLookupProcessByProcessId(hPID, &Process);
	if (!NT_SUCCESS(status))
	{
		return;
	}
	if (fHang)
	{
		PsSuspendProcess(Process);
	}
	else
	{
		PsResumeProcess(Process);
	}
}

值的注意的是,我在Win7及以上版本(X64)发现这两个函数在内核中是导出的。只要声明即可

但是在XP(X86)下实验时发现内核没导出。实际上可以通过暴利搜索搜到函数起始位置

这里我使用硬编码的方式来获取:

 在我的XP版本下PsSuspendProcess地址是: 0x805cbdf8

 在我的XP版本下PsResumeProcess地址是: 0x805cbcaa

接下来实现代码:

/****************************
* 这些函数从内核导出但未声明	*
****************************/
// 从EPROCESS结构获取对应的进程映像名
NTSYSCALLAPI PCHAR PsGetProcessImageFileName(IN PEPROCESS pProcess);
// 进程挂起与调度内核函数
NTSYSCALLAPI NTSTATUS PsSuspendProcess(PEPROCESS Process);
NTSYSCALLAPI NTSTATUS PsResumeProcess(PEPROCESS Process);

// 定义对应函数指针
typedef NTSTATUS(NTAPI *pfnPsSuspendProcess)(PEPROCESS Process);
typedef NTSTATUS (NTAPI *pfnPsResumeProcess)(PEPROCESS Process);

VOID R0ProcessOpa(ULONG64 ulPID, BOOLEAN fHang)
{
	PEPROCESS Process;
	NTSTATUS status;
	HANDLE hPID = (HANDLE)ulPID;
	// 通过获取硬编码函数地址
	pfnPsResumeProcess PsResumeProcess = (pfnPsResumeProcess)0x805cbcaa;
	pfnPsSuspendProcess PsSuspendProcess = (pfnPsSuspendProcess)0x805cbdf8;

	status = PsLookupProcessByProcessId(hPID, &Process);
	if (!NT_SUCCESS(status))
	{
		return;
	}
	if (fHang)
	{
		PsSuspendProcess(Process);
	}
	else
	{
		PsResumeProcess(Process);
	}
}

3. 杀死进程


杀死进程主要使用:

NTSTATUS ZwTerminateProcess (_In_opt_ HANDLE ProcessHandle, _In_ NTSTATUS ExitStatus)

该函数使用方法非常简单,传入要杀死进程的句柄以及写入一个状态码就行。

在获取目标进程的句柄时需要用到ZwOpenProcess。需要传入的是ClientId中的UniqueProcess项。传给它目标进程PID。

NTSTATUS 
ZwOpenProcess(
    __out PHANDLE  ProcessHandle,
    __in ACCESS_MASK  DesiredAccess,
    __in POBJECT_ATTRIBUTES  ObjectAttributes,
    __in_opt PCLIENT_ID  ClientId
    );

实例代码:

BOOLEAN TerminateProcess(ULONG64 ProcessId)
{
	CLIENT_ID Client = { 0 };
	HANDLE hProcess = NULL;
	NTSTATUS status;
	OBJECT_ATTRIBUTES oa = { 0 };

	Client.UniqueProcess = ProcessId;
	InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打开目标进程
	status = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, &Client);
	if (!NT_SUCCESS(status))
	{
		return(FALSE);
	}
	status = ZwTerminateProcess(hProcess, 0);
	ZwClose(hProcess);
	if (NT_SUCCESS(status))
	{
		return(TRUE);
	}

	return(FALSE);
}

(完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值