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

在内核开发中,经常需要进行进程和句柄之间的互相转换。进程通常由一个唯一的进程标识符(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。

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

4.1.1 进程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);// 返回进程PIDreturn ProcessBasicInfor.UniqueProcessId;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint("[-] 驱动卸载 \n");
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello LyShark \n");// 将PID转换为HANDLEHANDLE ptr = PidToHandle(6932);DbgPrint("[*] PID  --> HANDLE = %p \n", ptr);// 句柄转为PIDULONG pid = HandleToPid(ptr);DbgPrint("[*] HANDLE  --> PID = %d \n", pid);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

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

4.1.2 进程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转换为PEPROCESSPEPROCESS ptr = PidToObject(6932);DbgPrint("[*] PID  --> PEPROCESS = %p \n", ptr);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

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

4.1.3 进程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结构转换为HandleHANDLE handle = EprocessToHandle(eprocess);DbgPrint("[*] EProcess --> HANDLE = %p \n", handle);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 如何实现外观设计模式?什么是 Facade 外观设计模式?Python 设计模式示例代码

什么是&#xff08;Facade&#xff09;外观设计模式&#xff1f; 外观&#xff08;Facade&#xff09;设计模式是一种结构型设计模式&#xff0c;它提供了一个简化复杂系统接口的高级接口&#xff0c;使得系统更容易使用。外观模式通过定义一个高层接口&#xff0c;隐藏了系统…

2023年中国恒温蜡疗仪发展趋势分析:应用前景存有很大发展与探索空间[图]

恒温电蜡疗仪可将蜡熔化&#xff0c;利用蜡自身特点&#xff0c;能阻止热的传导、散热慢、气体和水分不易消失&#xff0c;保温性能优越。利用蜡能紧密贴于体表的可塑性&#xff0c;可加入其他药物协同进行治疗&#xff0c;也可将中药与蜡疗有机地结合在一起&#xff0c;产生柔…

【Linux】Linux进程间通信(二)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…

《QT从基础到进阶·三十》QVariant的基础用法

很多时候&#xff0c;需要几种不同的数据类型需要传递&#xff0c;如果用结构体&#xff0c;又不大方便&#xff0c;容器保存的也只是一种数据类型&#xff0c;而QVariant则可以统统搞定。 QVariant可以保存QT和C常用类型&#xff0c;如果是自定义类型&#xff0c;比如struct,c…

什么是PWA(Progressive Web App)?它有哪些特点和优势?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

2023年中国逆流式冷却塔性能特点、应用领域及市场规模分析[图]

按冷却塔热交换时气流和水流方向不同的配置&#xff0c;机力通风冷却塔又可分为横流式冷却塔、逆流式冷却塔&#xff0c;目前主流的冷却塔型式为逆流式冷却塔&#xff0c;逆流式冷却塔&#xff08;counterflowcoolingtower&#xff09;是指水流在塔内垂直落下&#xff0c;气流方…

【C++学习手札】模拟实现string

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;缶ビール—みゆな 0:41━━━━━━️&#x1f49f;──────── 2:52 &#x1f504; ◀️ ⏸ ▶️ ☰ &…

linux进程间通信之管道通信

Linux 进程间通信机制分三类&#xff1a;数据交互&#xff0c;同步&#xff0c;信号。理解了这些机制才能灵活运用操作系统提供的 IPC 工具。 一.管道 管道是一种文件形式&#xff0c;是内核的一块缓冲区。匿名管道只能用于具有亲缘关系的进程间通信&#xff0c;命名管道可以用…

在Linux上安装Oracle 数据库 11g (含静默方式安装)

好久没碰11g了&#xff0c;今天&#xff08;2023年11月16日&#xff09;因为有个需求又装了一遍。 在OCI上安装了一个Oracle Linux 6实例&#xff1a; $ uname -a Linux instance-20231116-1239-db11g 4.1.12-124.80.1.el6uek.x86_64 #2 SMP Mon Oct 9 02:32:10 PDT 2023 x86…

多维度梳理 MySQL 锁

多维度梳理 MySQL 锁 1、并发问题的解决方案2、MySQL的各类型锁2.1、从数据操作的类型划分 (读锁、写锁)2.2、从数据操作的粒度划分2.2.1、表锁2.2.1.1、表级别的S 锁、X 锁2.2.1.2、意向锁&#xff08;IS、IX&#xff09;2.2.1.3、自增锁2.2.1.4、元数据锁 2.2.2、行锁2.2.2.1…

华为eNSP综合实验考试

VLAN信息表 设备名称 端口 链路类型 VLAN 参数 HZ-HZCampus-Agg01-S5731 GE0/0/1 Trunk PVID:1 Allow-pass&#xff1a;10 20 Eth-trunk1&#xff08;GE0/0/2,0/0/3,0/0/23&#xff09; Trunk PVID:1 Allow-pass&#xff1a;10 20 GE0/0/24 Access PVID&#xf…

AttributeError: module ‘gradio‘ has no attribute ‘ClearButton‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…