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

news2024/12/25 9:33:59

在内核开发中,经常需要进行进程和句柄之间的互相转换。进程通常由一个唯一的进程标识符(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结构互转,输出效果图如下所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/676083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【跑实验04】CLIP安装报错,setup.py如何安装,图像编码器(image_encoder)的使用(含源代码)

文章目录 一、如何解决CLIP安装报错二、setup.py如何安装&#xff1f;三、图像编码器(image_encoder)的使用 一、如何解决CLIP安装报错 我第一次尝试安装CLIP&#xff0c;采用的方法是pip的方法&#xff1a; pip install clip但是安装后&#xff0c;无法使用&#xff1a; 明确…

代码随想录二刷 day31 | 贪心之 理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和

day31 理论基础什么是贪心贪心算法的套路一般解题步骤 455.分发饼干376. 摆动序列情况一&#xff1a;上下坡中有平坡情况二&#xff1a;数组首尾两端情况三&#xff1a;单调坡度有平坡 53. 最大子序和 理论基础 什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从…

vue3基础 ---- 上

目录 一.vue3介绍 1. 官网初识 2.环境搭建 2-1 线上尝试 2-2 CDN使用 2-3 Vue CLI 2-4 Vite 二.vue3基础 1.模板语法 1-1 我的第一个vue应用 1-2 应用背后的真相 1-3 模板语法-新的皮肤来了 1-4 Todolist-来个案例 1-5 点击变心案例 - 是变色 1-6 v-html- 模板…

【libdatachannel】pycharm运行streamer的信令服务及streamer与js客户端本机联调2

后面与ws服务器一直有ping pong2023-06-23 10:30:27.915 VERB [24456] [rtc::impl::PollService::runLoop@178] Entering poll, timeout=10000ms 2023-06-23 10:30:27.916 VERB [24456] [rtc::impl::PollServ

有了电脑怎么搞?我有办法(第一部分)-涵子的个人想法

上一次会选电脑后&#xff0c;今天我们来学习一下电脑的整理方法。今天满满的都是干货&#xff0c;请仔细阅读&#xff01;注意粗体内容。 目录 一、磁盘太乱咋整&#xff1f; 1.1.磁盘是个啥&#xff1f;为啥乱&#xff1f; 1.2.分区怎么分&#xff1f; 1.3.还是分不清怎…

Java类加载机制:从字节码到对象的奇妙之旅

目录 什么是类加载机制&#xff1f; 类加载顺序 类加载顺序图 双亲委派模型 双亲委派模型示意图 如何打破双亲委派模型&#xff1f; 要想学好java&#xff0c;首先得知道它是什么&#xff0c;怎么运行的&#xff0c;怎么加载的&#xff0c;运行的是个什么东西&#xff0c…

JVM内存模型及JAVA程序运行原理

文章目录 JVM简介JVM的内存结构方法区堆栈程序计数器 JAVA程序在JVM内是如何执行的 JVM简介 JVM------Java Virtual Machine.JVM是Java平台的基础&#xff0c;与实际机器一样&#xff0c;它有自己的指令集&#xff08;类似CPU通过指令操作程序运行&#xff09;&#xff0c;并在…

Temu、shopee、Lazada、Newegg、美客多销量增长黑科技!

在跨境电商的激烈竞争环境下&#xff0c;2023年伴随着疫情的解封&#xff0c;电商业务重新焕发生机。卖家们不应该只在一个平台投放所有资源&#xff0c;而应多元化地进行平台选择。实际上&#xff0c;许多小型电商平台如Wish、敦煌等也能带来大量业务&#xff0c;而且竞争压力…

如何保证API接口的安全性

API接口的安全性是非常重要的&#xff0c;以下是一些保证API接口安全性的措施&#xff1a; 用户认证、授权&#xff1a;接口的调用者必须提供有效的身份认证信息&#xff0c;包括用户名、密码、密钥等&#xff0c;以保证接口的调用者的身份有效性。同时&#xff0c;需要在接口的…

亚马逊云科技中国峰会:Amazon DeepRacer——因构建 而可见

文章目录 一、前言二、 亚马逊云科技中国峰会大会亮点三、Amazon DeepRacer 赛事火热开启四、Amazon DeepRacer 深度体验五、2023亚马逊云科技中国峰会——Amazon DeepRacerAmazon DeepRacer 中国峰会总决赛Girls in Tech Show高校联动&#xff0c;寻找未来“生力军”Amazon De…

电赛汇总(三):常用传感器电路模块设计

电赛汇总(三)&#xff1a;常用传感器电路模块设计 这一章节主要详细记录各种常用的传感器的电子芯片型号、设计原理与思想&#xff0c;以便随时查看翻阅。这部分内容出自黄根春等学者著的《全国大学生电子设计竞赛教程》一书中&#xff0c;感兴趣的朋友可以购买翻阅。 文章目…

Debian12编译安装R软件

1.解压源码包 2.运行./configure --prefix/usr/local/R-4.3 报错&#xff0c;没有安装fortran编译器 3.运行./configure --prefix/usr/local/R-4.3 4.运行./configure --prefix/usr/local/R-4.3 5.运行./configure --prefix/usr/local/R-4.3 6.运行./configure --pref…

厦门大学计算机考研分析

关注我们的微信公众号 姚哥计算机考研 更多详情欢迎咨询 厦门大学&#xff08;B&#xff09;考研难度&#xff08;☆☆☆☆☆&#xff09; 厦门大学计算机考研主要招生学院有信息学院、人工智能研究院、医学院和电影学院。目前均已出拟录取名单。 厦门大学信息学院&#xff…

14. WebGPU 透视投影

在上一篇文章中&#xff0c;介绍了如何制作 3D &#xff0c;但 3D 没有任何透视效果。它使用的是所谓的“正交”视图&#xff0c;它有其用途&#xff0c;但通常不是人们说“3D”时想要的。 现在&#xff0c;需要添加透视图。究竟什么是透视&#xff1f;基本特征就是离得越远的…

牛客网基础语法71~80题

牛客网基础语法71~80题&#x1f618;&#x1f618;&#x1f618; &#x1f4ab;前言&#xff1a;今天是咱们第八期刷牛客网上的题目。 &#x1f4ab;目标&#xff1a;可以掌握循环嵌套&#xff0c;可以采用一些数组来解决问题&#xff0c;对循环知识掌握熟练&#xff0c;对数学…

H5套壳微信小程序跳转H5以及配置服务器接口域名和业务域名

一、H5套壳微信小程序跳转H5 基本语法&#xff1a; <web-view src"https://你的域名"></web-view> 1. 其中&#xff0c;url必须在管理后台加进业务域名&#xff0c;并且是https开头的。 使用了web-view&#xff0c;页面将不能放置其他元素&#xff0c…

【深度学习】RepVGG解析和学习体会,结构重参数化的后的速度比较,代码实现

文章目录 前言0. Vgg1.RepVGG Block 详解 前言 论文名称&#xff1a;RepVGG: Making VGG-style ConvNets Great Again 论文下载地址&#xff1a;https://arxiv.org/abs/2101.03697 官方源码&#xff08;Pytorch实现&#xff09;&#xff1a;https://github.com/DingXiaoH/RepV…

linux动态监控进程懂了没?

这里写目录标题 top交互模式监控网络状态 top top与ps类似&#xff0c;他们都是用来显示正在执行的进程。 两者最大的不同之处就是top在执行一段时间可以更新正在运行的进程。 基本语法&#xff1a; top 选项 选项功能-d 秒数指定top指令每隔几秒更新&#xff0c;默认为3秒-i…

【新星计划·2023】Linux图形、字符界面介绍与区别

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 前言 本文将介绍图形界面与命令行界面以及它们的区别&#xff0c;登录方法。 目录 一、图形界面与命令行界面介绍 1、图形界面 2、命令行…

Oracle单机版升级(11.2.0.3升级到11.2.0.4)

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…