当前位置: 代码网 > 科技>操作系统>Windows > 驱动开发:内核中进程与句柄互转

驱动开发:内核中进程与句柄互转

2024年08月06日 Windows 我要评论
在内核开发中,经常需要进行进程和句柄之间的互相转换。进程通常由一个唯一的进程标识符(PID)来标识,而句柄是指对内核对象的引用。在Windows内核中,`EProcess`结构表示一个进程,而HANDLE是一个句柄。为了实现进程与句柄之间的转换,我们需要使用一些内核函数。对于进程PID和句柄的互相转换,可以使用函数如`OpenProcess`和`GetProcessId`。OpenProcess函数接受一个PID作为参数,并返回一个句柄。GetProcessId函数接受一个句柄作为参数,并返回该进程的P

在内核开发中,经常需要进行进程和句柄之间的互相转换。进程通常由一个唯一的进程标识符(pid)来标识,而句柄是指对内核对象的引用。在windows内核中,eprocess结构表示一个进程,而handle是一个句柄。

为了实现进程与句柄之间的转换,我们需要使用一些内核函数。对于进程pid和句柄的互相转换,可以使用函数如openprocessgetprocessid。openprocess函数接受一个pid作为参数,并返回一个句柄。getprocessid函数接受一个句柄作为参数,并返回该进程的pid。

对于进程pid和eprocess结构的互相转换,可以使用函数如psgetprocessidpsgetcurrentprocess。psgetprocessid函数接受一个eprocess结构作为参数,并返回该进程的pid。psgetcurrentprocess函数返回当前进程的eprocess结构。

最后,对于句柄和eprocess结构的互相转换,可以使用函数如obreferenceobjectbyhandle和psgetprocessid。obreferenceobjectbyhandle函数接受一个句柄和一个对象类型作为参数,并返回对该对象的引用。psgetprocessid函数接受一个eprocess结构作为参数,并返回该进程的pid。

掌握这些内核函数的使用,可以方便地实现进程与句柄之间的互相转换。在进行进程和线程的内核开发之前,了解这些转换功能是非常重要的。

进程pid与进程handle之间的互相转换: 进程pid转化为handle句柄,可通过zwopenprocess这个内核函数,传入pid传出进程handle句柄,如果需要将handle句柄转化为pid则可通过zwqueryinformationprocess这个内核函数来实现,具体转换实现方法如下所示;

在内核开发中,经常需要进行进程pid和句柄handle之间的互相转换。将进程pid转化为句柄handle的方法是通过调用zwopenprocess内核函数,传入pid作为参数,函数返回对应进程的句柄handle。具体实现方法是,定义一个object_attributes结构体和client_id结构体,将进程pid赋值给client_id结构体的uniqueprocess字段,调用zwopenprocess函数打开进程,如果函数执行成功,将返回进程句柄handle,否则返回null。

将句柄handle转化为进程pid的方法是通过调用zwqueryinformationprocess内核函数,传入进程句柄和信息类别作为参数,函数返回有关指定进程的信息,包括进程pid。具体实现方法是,定义一个process_basic_information结构体和一个ntstatus变量,调用zwqueryinformationprocess函数查询进程基本信息,如果函数执行成功,将返回进程pid,否则返回0。

其中zwqueryinformationprocess是一个未被导出的函数如需使用要通过mmgetsystemroutineaddress动态获取到,该函数的原型定义如下:

ntstatus zwqueryinformationprocess(
  handle           processhandle,
  processinfoclass processinformationclass,
  pvoid            processinformation,
  ulong            processinformationlength,
  pulong           returnlength
);

函数可以接受一个进程句柄processhandle、一个processinfoclass枚举类型的参数processinformationclass、一个用于存储返回信息的缓冲区processinformation、缓冲区大小processinformationlength和一个指向ulong类型变量的指针returnlength作为参数。

在调用该函数时,processinformationclass参数指定要获取的进程信息的类型。例如,如果要获取进程的基本信息,则需要将该参数设置为processbasicinformation;如果要获取进程的映像文件名,则需要将该参数设置为processimagefilename。调用成功后,返回的信息存储在processinformation缓冲区中。

在调用该函数时,如果processinformation缓冲区的大小小于需要返回的信息大小,则该函数将返回status_info_length_mismatch错误代码,并将所需信息的大小存储在returnlength指针指向的ulong类型变量中。

zwqueryinformationprocess函数的返回值为ntstatus类型,表示函数执行的结果状态。如果函数执行成功,则返回status_success,否则返回其他错误代码。

掌握这些转换方法可以方便地在内核开发中进行进程pid和句柄handle之间的互相转换。

#include <ntifs.h>

// 定义函数指针
typedef ntstatus(*pfnzwqueryinformationprocess)(
	__in handle processhandle,
	__in processinfoclass processinformationclass,
	__out_bcount(processinformationlength) pvoid processinformation,
	__in ulong processinformationlength,
	__out_opt pulong returnlength
);

pfnzwqueryinformationprocess zwqueryinformationprocess;

// 传入pid传出handle句柄
handle pidtohandle(ulong pid)
{
	handle hprocesshandle;
	object_attributes obj;
	client_id clientid;

	clientid.uniqueprocess = pid;
	clientid.uniquethread = 0;

	// 属性初始化
	initializeobjectattributes(&obj, 0, obj_case_insensitive | obj_kernel_handle, 0, 0);

	ntstatus status = zwopenprocess(&hprocesshandle, process_all_access, &obj, &clientid);
	if (status == status_success)
	{
		// dbgprint("[*] 已打开 \n");
		zwclose(&hprocesshandle);
		return hprocesshandle;
	}

	return 0;
}

// handle句柄转换为pid
ulong handletopid(handle handle)
{
	process_basic_information processbasicinfor;

	// 初始化字符串,并获取动态地址
	unicode_string utrzwqueryinformationprocessname = rtl_constant_string(l"zwqueryinformationprocess");
	zwqueryinformationprocess = (pfnzwqueryinformationprocess)mmgetsystemroutineaddress(&utrzwqueryinformationprocessname);

	// 调用查询
	zwqueryinformationprocess(
		handle,
		processbasicinformation,
		(pvoid)&processbasicinfor,
		sizeof(processbasicinfor),
		null);

	// 返回进程pid
	return processbasicinfor.uniqueprocessid;
}

void undriver(pdriver_object driver)
{
	dbgprint("[-] 驱动卸载 \n");
}

ntstatus driverentry(in pdriver_object driver, punicode_string registrypath)
{
	dbgprint("hello lyshark \n");

	// 将pid转换为handle
	handle ptr = pidtohandle(6932);
	dbgprint("[*] pid  --> handle = %p \n", ptr);

	// 句柄转为pid
	ulong pid = handletopid(ptr);

	dbgprint("[*] handle  --> pid = %d \n", pid);

	driver->driverunload = undriver;
	return status_success;
}

编译并运行如上这段代码片段,将把进程pid转为handle句柄,再通过句柄将其转为pid,输出效果图如下所示;

进程pid转换为eprocess结构: 通过pslookupprocessbyprocessid函数,该函数传入一个pid则可获取到该pid的eprocess结构体,具体转换实现方法如下所示;

本段代码展示了如何使用windows内核api函数pslookupprocessbyprocessid将一个pid(process id)转换为对应的eprocess结构体,eprocess是windows内核中描述进程的数据结构之一。

代码段中定义了一个名为pidtoobject的函数,该函数的输入参数是一个pid,输出参数是对应的eprocess结构体。

在函数中,通过调用pslookupprocessbyprocessid函数来获取对应pid的eprocess结构体,如果获取成功,则调用obdereferenceobject函数来减少eprocess对象的引用计数,并返回获取到的eprocess指针;否则返回0。

driverentry函数中,调用了pidtoobject函数将pid 6932转换为对应的eprocess结构体,并使用dbgprint函数输出了转换结果。最后设置了驱动程序卸载函数为undriver,当驱动程序被卸载时,undriver函数会被调用。

#include <ntifs.h>
#include <windef.h>

// 将pid转换为object or eprocess
peprocess pidtoobject(ulong pid)
{
	peprocess peprocess;

	ntstatus status = pslookupprocessbyprocessid((handle)pid, &peprocess);

	if (status == status_success)
	{
		obdereferenceobject(peprocess);
		return peprocess;
	}

	return 0;
}

void undriver(pdriver_object driver)
{
	dbgprint("[-] 驱动卸载 \n");
}

ntstatus driverentry(in pdriver_object driver, punicode_string registrypath)
{
	dbgprint("hello lyshark \n");

	// 将pid转换为peprocess
	peprocess ptr = pidtoobject(6932);
	dbgprint("[*] pid  --> peprocess = %p \n", ptr);

	driver->driverunload = undriver;
	return status_success;
}

编译并运行如上这段代码片段,将把进程pid转为eprocess结构,输出效果图如下所示;

进程handle与eprocess互相转换:handle转换为eprocess结构可使用内核函数obreferenceobjectbyhandle实现,反过来eprocess转换为handle句柄可使用obopenobjectbypointer内核函数实现,具体转换实现方法如下所示;

首先,将handle转换为eprocess结构体,可以使用obreferenceobjectbyhandle内核函数。该函数接受一个handle参数,以及对应的对象类型(这里为eprocess),并返回对应对象的指针。此函数会对返回的对象增加引用计数,因此在使用完毕后,需要使用obdereferenceobject将引用计数减少。

其次,将eprocess结构体转换为handle句柄,可以使用obopenobjectbypointer内核函数。该函数接受一个指向对象的指针(这里为eprocess结构体的指针),以及所需的访问权限和对象类型,并返回对应的handle句柄。此函数会将返回的句柄添加到当前进程的句柄表中,因此在使用完毕后,需要使用closehandle函数将句柄关闭,以避免资源泄漏。

综上所述,我们可以通过这两个内核函数实现handleeprocess之间的相互转换,转换代码如下所示;

#include <ntifs.h>
#include <windef.h>

// 传入pid传出handle句柄
handle pidtohandle(ulong pid)
{
	handle hprocesshandle;
	object_attributes obj;
	client_id clientid;

	clientid.uniqueprocess = pid;
	clientid.uniquethread = 0;

	// 属性初始化
	initializeobjectattributes(&obj, 0, obj_case_insensitive | obj_kernel_handle, 0, 0);

	ntstatus status = zwopenprocess(&hprocesshandle, process_all_access, &obj, &clientid);
	if (status == status_success)
	{
		// dbgprint("[*] 已打开 \n");
		zwclose(&hprocesshandle);
		return hprocesshandle;
	}

	return 0;
}

// 将handle转换为eprocess结构
peprocess handletoeprocess(handle handle)
{
	peprocess peprocess;

	ntstatus status = obreferenceobjectbyhandle(handle, generic_all, *psprocesstype, kernelmode, &peprocess, null);
	if (status == status_success)
	{
		return peprocess;
	}

	return 0;
}

// eprocess转换为handle句柄
handle eprocesstohandle(peprocess eprocess)
{
	handle hprocesshandle = (handle)-1;

	ntstatus status = obopenobjectbypointer(
		eprocess,
		obj_kernel_handle,
		0,
		0,
		*psprocesstype,
		kernelmode,
		&hprocesshandle
		);

	if (status == status_success)
	{
		return hprocesshandle;
	}

	return 0;
}

void undriver(pdriver_object driver)
{
	dbgprint("[-] 驱动卸载 \n");
}

ntstatus driverentry(in pdriver_object driver, punicode_string registrypath)
{
	dbgprint("hello lyshark \n");

	// 将handle转换为eprocess结构
	peprocess eprocess = handletoeprocess(pidtohandle(6932));
	dbgprint("[*] handle --> eprocess = %p \n", eprocess);

	// 将eprocess结构转换为handle
	handle handle = eprocesstohandle(eprocess);
	dbgprint("[*] eprocess --> handle = %p \n", handle);

	driver->driverunload = undriver;
	return status_success;
}

编译并运行如上这段代码片段,将把进程handleeprocess结构互转,输出效果图如下所示;

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com