Win10下一个有意思的驱动引起可能性的拒绝服务攻击
liebian365 2024-10-20 09:59 28 浏览 0 评论
在一次排查系统的驱动的目录system32/driver目录文件时,看到一个名字为ProcLaunchMon.sys的驱动
数字签名微软官方的
该驱动带入的时间是2019?年?12?月?7?日,??17:08:33,文件描述是Time Travel Debugging Process Launch Monitor大致明白了就是一个调试工具实事记录进程活动的驱动。微软的这个官方页面有讲述了什么是Time Travel Debugging,
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/time-travel-debugging-overview
本篇的文章的目的是主要研究这个驱动到底做了什么?
接下来就祭出逆向工具ida
微软对这个模块是有部分符号文件的,左侧的Function windows可以看到他是用c++写的驱动有一些类名显示
主要的类名就是ProcessLaunchMonitorClient 、ProcessLaunchMonitorDevice、LegacyDevice
然后再看看导入表有哪些函数,函数并不多主要就两类: 进程函数和事件函数
PsSetCreateProcessNotifyRoutine
ZwCreateEvent
PsSuspendProcess
PsResumeProcess
ZwDuplicateObject
等等
分析完表面这些明显的地方,下面就从驱动的入口点分析
最开始的时候会构建一个device 类 LegacyDevice::LegacyDevice
LegacyDevice::LegacyDevice类的大小是0x38,因为驱动,所以一般用c++写驱动的时候都会用动态内存分配全局结构,ProcessLaunchMonitorDevice::`vftable 是该类的基类,在驱动的虚表rdata节里可以看到该基类的定义
前面第一个是构造与析构函数,后面四个是IO 例程函数DispatchRoutine、DispatchCreate、DispatchClose、DispatchBufferedIoctl
内存构造结束了,就直接调用LegacyDevice::LegacyDevice的构造函数
首先会构造设备名字的字符串
然后创建设备和设备连接
注意该驱动使用的是
WdmlibIoCreateDeviceSecure来创建设备,该函数创建的设备是管理权限才能打开设备。
最后构造函数里会填充MajorFunction结构体,用StaticDispatchRoutine函数覆盖。
memset64(a2->MajorFunction, (unsigned __int64)LegacyDevice::StaticDispatchRoutine, 0x1Cui64);
自此这个构造类结束。
构造了这个全局类LegacyDevice::LegacyDevice,后接下来就是调用注册进程回调通知
回调函数是ProcessCreationNotifyRoutine
到这里入口函数就结束,其实过程很简单,但是精华却在例程函数里。
要控制利用驱动,首先我们必须CreateFile一个驱动,这是会进入驱动的IRP_MJ_CREATE例程,接下来看上面的提到的StaticDispatchRoutine函数
这个函数很简单,可能很多人一下子看不懂,从设备信息中获得DeviceExtension结构然后call v4 + 8的函数,这到底是什么呢,
秘密在刚才那个构造函数里。
在之前的LegacyDevice::LegacyDevice的构造函数里有这么句代码
(_QWORD )(*DeviceObject)->DeviceExtension = this;
就是把LegacyDevice::LegacyDevice这个全局类的this指针赋值给DeviceObject)->DeviceExtension的结构中,现在明白了这个DeviceExtension里的值是什么了把,对他就是LegacyDevice::LegacyDevice的地址值,那么
((void (fastcall **)(int64, _QWORD ))((_QWORD )v4 + 8i64))(v4, v7);
的代码的意思就是调用LegacyDevice::LegacyDevice的基类的第二个函数DispatchRoutine
继续分析进入DispatchRoutine 函数
IRP_MJ_CREATE 会进入第一个函数
ProcessLaunchMonitorDevice::DispatchCreate(this, ((struct _FILE_OBJECT *)iocode + 6));
ProcessLaunchMonitorDevice::DispatchCreate函数里会为每一个Client创建该设备的对象生成一个ProcessLaunchMonitorClient::ProcessLaunchMonitorClient(v6, v7, &v15),该类的内存大小为0x70.
这个类的构造函数一个最主要的功能就是生成一个进程间通讯的Event,赋值给了
v3 = (PVOID )((char )this + 56);的便宜的位置。
最后会把这个Process
赋值给了
ProcessLaunchMonitorDevice这个全局类的v10 = ((_QWORD )this + 6);的位置的LIST_ENTRY的链表里。以及当前设备的文件对象的FsContext的上下文里。
打开了设备之后,我们就要通过IRP_MJ_DEVICE_CONTROL IO控制码是14的之类的去给驱动发IO命令,那么就会经过驱动的
然后再进入ProcessLaunchMonitorDevice::DispatchBufferedIoctl函数
首先该函数会先从之前的我们讲的文件对象的FsContext结构中取出之前创建的ProcessLaunchMonitorClient的指针。
接下来会看到里面有一个IO code
Case : 0x224040 恢复进程
Case 0x224044 关闭 ProcessLaunchMonitorClient 并且清楚恢复所有被悬挂的进程
Case 0x2240048 获取之前ProcessLaunchMonitorClient里创建的进程间通讯的事件。
等等
这些主要的IRP例程的函数大致的逻辑就分析完毕,那该驱动的进程回调函数有什么用呢?这个问题很好,下面就来分析回调通知里的逻辑
当一个进程启动后就会进入该驱动回调通知
然后就会进入
ProcessLaunchMonitorDevice::HandleProcessCreatedOrDestroyed(gLegacyDevice::gLegacyDevice, Create != 0, v4, v6);
这个函数是主要的处理逻辑
然后就会进入
进入这个函数SuspendResumeProcessById(a4, v13)后就会把进程悬挂起来
可以看到
If(a2)
{
v5 = PsSuspendProcess(Object);
}
如果a2这个参数是1的话,直接就悬挂了,然后外面给的参数就是1,那就是只要驱动功能起来了,就直接悬挂了新起来的进程(这个驱动太霸道了), 如果你不发之前我们看到那个IO: 0x224040的控制码的话,它就一直被悬挂,起不来了,或者这个驱动被关闭也能自动恢复所有被悬挂的进程。
其他一些小的附加的结构体的处理不在具体分析,以上就是该驱动的最主要的功能,当然分析完毕就是验证我们的分析结果。
主要代码如下:(具体的iocode 我模糊处理了,避免被恶意乱用)
int main()
{
TCHAR szDriverKey[MAX_PATH] = { 0 };
GetSystemDirectory(szDriverKey,MAX_PATH);
StringCchCat(szDriverKey, MAX_PATH, _T("\\dirver\\ProcLaunchMon.sys"));
if (TRUE)
{
//install driver
LoadDriver(szDriverKey);
}
BOOL CheckServiceOk = FALSE;
if (SUCCEEDED(StringCchPrintf(
szDriverKey,
MAX_PATH,
_T("\\\\.\\%s"),
_T("com_microsoft_xxxxx_ProcLaunchMon")))) //
{
HANDLE hObjectDrv = CreateFile(
szDriverKey,
GENERIC_READ |
GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hObjectDrv != INVALID_HANDLE_VALUE)
{
DWORD dwProcessId = -1;
BYTE OutBuffer[4002] = { 0 };
ULONG BytesReturned = 0;
DWORD sendrequest = 0xxabsdd;
if (DeviceIoControl(
hObjectDrv,
sendrequest,//,
&dwProcessId,
4,
&dwProcessId,
4,
&BytesReturned, 0))
{
ULONG64 Request = 0;
sendrequest = 0xa2XXXX;
ULONG64 KeyHandle = 0;
if (DeviceIoControl(
hObjectDrv,
sendrequest,//
&Request,
8,
&KeyHandle,
8,
&BytesReturned, 0))
{
//Get the kernel process event and wait for the kernel setting event
if (WaitForSingleObject((HANDLE)KeyHandle, INFINITE) == WAIT_OBJECT_0)
{
// int nI = 0;
// nI++;
}
while (TRUE)
{
sendrequest = 0x125a3X;
typedef struct _GetPidBuffer
{
LARGE_INTEGER Pid;
ULONG32 Other;
}GetPidBuffer;
GetPidBuffer ProcessPid = {0};
if (DeviceIoControl(
hObjectDrv,
sendrequest,
&Request,
8,
&ProcessPid,
12,
&BytesReturned,
0))
{
if (BytesReturned && ProcessPid.Pid.LowPart > 0)
{
printf("curent run pid:%d", ProcessPid.Pid.HighPart);
//If the process is not recovered, it will cause denial of service attack. For example,
//if it is security software, it will cause security software failure
sendrequest = 0x224040;
if (DeviceIoControl(
hObjectDrv,
sendrequest,
&ProcessPid.Pid.HighPart,
8,
&ProcessPid.Pid.HighPart,
8,
&BytesReturned, 0))
{
}
Sleep(100);
BytesReturned = 0;
}
else
{
if (WaitForSingleObject((HANDLE)KeyHandle, INFINITE) == WAIT_OBJECT_0)
{
}
}
}
}
}
}
CloseHandle(hObjectDrv);
hObjectDrv = NULL;
}
}
return 0;
}
1. 加载驱动成功
2. 打开设备成功
3. 开启功能
后记: 这个曾经上报给微软的msrc,对方承认是个有待改进的问题的驱动,但是并非是个漏洞,至今已经过去了四个月了,可以到了公布的时间了,如果一个恶意进程已经攻击进入一个系统后,,并且已经有了管理员权限,他就可以利用这个驱动去控制安全软件的启动,甚至失效,这也是很危险的驱动。
相关推荐
- 看黑客是如何获取你电脑最高权限的,一定要看
-
在渗透过程中,通过各种方式获取到一枚cmdshell,但是这个shell的权限比较低,无法让我们做我们想要做的一些操作,比如说获取系统密码,获取数据库信息,又或者比如说拿到服务器中的另一个站点的权限,...
- 是50个常用的Visual Basic代码示例:
-
以下是50个常用的VisualBasic代码示例:1.声明变量```vb...
- 电脑系统型号怎么看版本(如何看电脑系统型号)
-
有时候我们会需要进行查看电脑上安装的windows系统版本及系统版本号,但对于不懂电脑知识的小白来说要怎么查看电脑系统版本信息呢?别着急,有小编在接下来,就将查看电脑系统版本的教程来分享给你们,希望对...
- dos命令systeminfo,查看系统启动时间。电脑卡慢,win10怎么了?
-
最近一段时间,有几个反应电脑卡慢的,都是windows10的系统。询问得知每天电脑有关机,打开任务管理器,内存使用量达到百分之九十多,而程序只打开微信、wps、360浏览器。cmd窗口运行命令syst...
- systeminfo命令:全面解析系统信息!
-
你是否曾想过,仅凭一条简单的命令,就能深入了解计算机的"内心世界"?是不是有点不可思议?那么,让我们一起探寻这个神奇的命令,揭开它背后的奥秘吧!它能提供的信息超乎你的想象,从操作系统到硬件配置,再到驱...
- 电脑序列号怎么查询?只需两行命令一键查询
-
当我们的电脑出问题需要保修的时候,需要查询到电脑的型号和序列号才更便于进行下一步的操作,有包装盒的朋友还可以在包装盒上查询,笔记本用户可以在电脑底部标签上查询,没有包装盒和标签破损的用户就无从下手了。...
- 快速显示系统信息:Systeminfo命令详解
-
Systeminfo命令是windows系统中显示系统信息的命令,此命令可以显示出计算机的操作系统的详细配置信息,包括操作系统配置、安全信息、产品ID和硬件属性(如RAM、磁盘空间和网卡)。使用...
- dos命令systeminfo图文教程,显示操作系统配置信息msinfo32
-
大家好,我是老盖,首先感谢观看本文,本篇文章做的有视频,视频讲述的比较详细,也可以看我发布的视频。今天我们学习systeminfo命令,该工具显示本地或远程机器(包括服务包级别)的操作系统配置的信息,...
- 基于uniapp+vue3跨端仿制chatgpt实例uniapp-chatgpt
-
#夏日生活打卡季#...
- 原创新作uniapp+vue3+pinia2高仿微信App聊天
-
前段时间有给大家分享一个flutter3.x桌面端os系统。今天再分享一款最新原创之作uniapp-vue3-wechat聊天实例。uni-vue3-wechat采用...
- UniApp开发的设备适配(uniapp服务器配置)
-
UniApp是一个跨平台开发框架,支持多端应用(如H5、小程序、iOS、Android等)。由于不同设备的屏幕尺寸、分辨率、操作系统等存在差异,设备适配是开发过程中需要重点关注的问题。以下是Uni...
- 如何用服务器搭建自己的个人网站(自己服务器怎么做网站)
-
这篇教程主要是告诉大家如何利用TCP和HTTP协议来完成网站的搭建。首先你需要有C/C++语言基础,且有服务器、客户端概念,如果你了解TCP或者HTTP协议的话,那么将会帮助你更快的学会如何搭建个人网...
- 大话C语言:字符数组(c语言字符数组教学视频)
-
1字符数组概述C语言中没有字符串这种数据类型,可以通过char的数组来替代。数字0(和字符'\0'等价)结尾的char数组就是一个字符串,字符串是一种特殊的char的数组。...
- 源码分享:在pdf上加盖电子签章(pdf怎么加电子签章)
-
在pdf上加盖电子签章,并不是只是加个印章图片,。而是要使用一对密钥中的私钥对文件进行签字。为啥要用私钥呢?很简单,因为公钥是公开的,其他人才可以用公钥为你证明,这个文件是你签的。这就是我们常说的:私...
- C语言wcstombs函数详解:宽字符字符串到多字节的「翻译官」
-
核心定位wcstombs是C语言中用于将宽字符字符串转换为多字节字符串的「翻译官」,它能将宽字符(wchar_t)转换为多字节字符(如UTF-8编码的中文)。就像一位翻译官,它能将一种语言(宽字符...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)