7.4 Windows驱动开发:内核运用LoadImage屏蔽驱动

在笔者上一篇文章《内核监视LoadImage映像回调》LyShark简单介绍了如何通过PsSetLoadImageNotifyRoutine函数注册回调来监视驱动模块的加载,注意我这里用的是监视而不是监控之所以是监视而不是监控那是因为PsSetLoadImageNotifyRoutine无法实现参数控制,而如果我们想要控制特定驱动的加载则需要自己做一些事情来实现,如下LyShark将解密如何实现屏蔽特定驱动的加载。

要想实现驱动屏蔽其原理很简单,通过ImageInfo->ImageBase得到镜像基地址,然后调用GetDriverEntryByImageBase函数来得到程序的入口地址,找NT头的OptionalHeader节点,该节点里面就是被加载驱动入口,通过汇编在驱动头部写入ret返回指令,即可实现屏蔽加载特定驱动文件。

原理其实很容易理解,如果我们需要实现则只需要在《内核监视LoadImage映像回调》这篇文章的代码上稍加改进即可,当检测到lyshark.sys驱动加载时,直接跳转到入口处快速写入一个Ret让驱动返回即可,至于如何写出指令的问题如果不懂建议回头看看《内核CR3切换读写内存》文章中是如何读写内存的,这段代码实现如下所示。

#include <ntddk.h>
#include <intrin.h>
#include <ntimage.h>

PVOID GetDriverEntryByImageBase(PVOID ImageBase)
{
    PIMAGE_DOS_HEADER pDOSHeader;
    PIMAGE_NT_HEADERS64 pNTHeader;
    PVOID pEntryPoint;
    pDOSHeader = (PIMAGE_DOS_HEADER)ImageBase;
    pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)ImageBase + pDOSHeader->e_lfanew);
    pEntryPoint = (PVOID)((ULONG64)ImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint);
    return pEntryPoint;
}

VOID UnicodeToChar(PUNICODE_STRING dst, char *src)
{
    ANSI_STRING string;
    RtlUnicodeStringToAnsiString(&string, dst, TRUE);
    strcpy(src, string.Buffer);
    RtlFreeAnsiString(&string);
}

// 使用开关写保护需要在[C/C++]->[优化]->启用内部函数
// 关闭写保护
KIRQL  WPOFFx64()
{
    KIRQL  irql = KeRaiseIrqlToDpcLevel();
    UINT64  cr0 = __readcr0();
    cr0 &= 0xfffffffffffeffff;
    _disable();
    __writecr0(cr0);
    return  irql;
}

// 开启写保护
void  WPONx64(KIRQL  irql)
{
    UINT64  cr0 = __readcr0();
    cr0 |= 0x10000;
    _enable();
    __writecr0(cr0);
    KeLowerIrql(irql);
}

BOOLEAN DenyLoadDriver(PVOID DriverEntry)
{
    UCHAR fuck[] = "\xB8\x22\x00\x00\xC0\xC3";
    KIRQL kirql;
    /* 在模块开头写入以下汇编指令
    Mov eax,c0000022h
    ret
    */
    if (DriverEntry == NULL) return FALSE;
    kirql = WPOFFx64();
    memcpy(DriverEntry, fuck, sizeof(fuck) / sizeof(fuck[0]));
    WPONx64(kirql);
    return TRUE;
}

VOID MyLySharkComLoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ModuleStyle, PIMAGE_INFO ImageInfo)
{
    PVOID pDrvEntry;
    char szFullImageName[256] = { 0 };

    // MmIsAddress 验证地址可用性
    if (FullImageName != NULL && MmIsAddressValid(FullImageName))
    {
        // ModuleStyle为零表示加载sys
        if (ModuleStyle == 0)
        {
            pDrvEntry = GetDriverEntryByImageBase(ImageInfo->ImageBase);
            UnicodeToChar(FullImageName, szFullImageName);
            if (strstr(_strlwr(szFullImageName), "lyshark.sys"))
            {
                DbgPrint("[LyShark] 拦截SYS内核模块:%s", szFullImageName);
                DenyLoadDriver(pDrvEntry);
            }
        }
    }
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
    PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLySharkComLoadImageNotifyRoutine);
    DbgPrint("驱动卸载完成...");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
    DbgPrint("hello lyshark \n");

    PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)MyLySharkComLoadImageNotifyRoutine);
    DbgPrint("驱动加载完成...");
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

首先运行我们的驱动,然后我们接着加载lyshark.sys则你会发现驱动被拦截了。

我们看下驱动加载器,提示的信息是拒绝访问,因为这个驱动其实是加载了的,只是入口处被填充了返回而已。

除了使用Ret强制返回的方法意外,屏蔽驱动加载还可以使用另一种方式实现禁用模块加载,例如当驱动被加载首先回调函数内可以接收到,当接收到以后直接调用MmUnmapViewOfSection函数强制卸载掉即可,如果使用这种方法实现则这段代码需要改进成如下样子。

#include <ntifs.h>
#include <ntimage.h>
#include <intrin.h>

NTSTATUS MmUnmapViewOfSection(PEPROCESS Process, PVOID BaseAddress);
NTSTATUS SetNotifyRoutine();
NTSTATUS RemoveNotifyRoutine();

VOID LoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo);
NTSTATUS U2C(PUNICODE_STRING pustrSrc, PCHAR pszDest, ULONG ulDestLength);
VOID ThreadProc(_In_ PVOID StartContext);

// 拒绝加载驱动
NTSTATUS DenyLoadDriver(PVOID pImageBase);

// 拒绝加载DLL模块
NTSTATUS DenyLoadDll(HANDLE ProcessId, PVOID pImageBase);

typedef struct _MY_DATA
{
    HANDLE ProcessId;
    PVOID pImageBase;
}MY_DATA, *PMY_DATA;

// 设置消息回调
NTSTATUS SetNotifyRoutine()
{
    NTSTATUS status = STATUS_SUCCESS;
    status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine);
    return status;
}

// 关闭消息回调
NTSTATUS RemoveNotifyRoutine()
{
    NTSTATUS status = STATUS_SUCCESS;
    status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
    return status;
}

VOID LoadImageNotifyRoutine(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo)
{
    DbgPrint("PID: %d --> 完整路径: %wZ --> 大小: %d --> 基地址: 0x%p \n", ProcessId, FullImageName, ImageInfo->ImageSize, ImageInfo->ImageBase);

    HANDLE hThread = NULL;
    CHAR szTemp[1024] = { 0 };
    U2C(FullImageName, szTemp, 1024);
    if (NULL != strstr(szTemp, "lyshark.sys"))
    {
        // EXE或者DLL
        if (0 != ProcessId)
        {
            // 创建多线程 延时1秒钟后再卸载模块
            PMY_DATA pMyData = ExAllocatePool(NonPagedPool, sizeof(MY_DATA));
            pMyData->ProcessId = ProcessId;
            pMyData->pImageBase = ImageInfo->ImageBase;
            PsCreateSystemThread(&hThread, 0, NULL, NtCurrentProcess(), NULL, ThreadProc, pMyData);
            DbgPrint("[LyShark] 禁止加载DLL文件 \n");
        }
        // 驱动
        else
        {
            DenyLoadDriver(ImageInfo->ImageBase);
            DbgPrint("[LyShark] 禁止加载SYS驱动文件 \n");
        }
    }
}

// 拒绝加载驱动
NTSTATUS DenyLoadDriver(PVOID pImageBase)
{
    NTSTATUS status = STATUS_SUCCESS;
    PMDL pMdl = NULL;
    PVOID pVoid = NULL;
    ULONG ulShellcodeLength = 16;
    UCHAR pShellcode[16] = { 0xB8, 0x22, 0x00, 0x00, 0xC0, 0xC3, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 };
    PIMAGE_DOS_HEADER pDosHeader = pImageBase;
    PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
    PVOID pDriverEntry = (PVOID)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.AddressOfEntryPoint);

    pMdl = MmCreateMdl(NULL, pDriverEntry, ulShellcodeLength);
    MmBuildMdlForNonPagedPool(pMdl);
    pVoid = MmMapLockedPages(pMdl, KernelMode);
    RtlCopyMemory(pVoid, pShellcode, ulShellcodeLength);
    MmUnmapLockedPages(pVoid, pMdl);
    IoFreeMdl(pMdl);

    return status;
}

// 调用 MmUnmapViewOfSection 函数来卸载已经加载的 DLL 模块
NTSTATUS DenyLoadDll(HANDLE ProcessId, PVOID pImageBase)
{
    NTSTATUS status = STATUS_SUCCESS;
    PEPROCESS pEProcess = NULL;

    status = PsLookupProcessByProcessId(ProcessId, &pEProcess);
    if (!NT_SUCCESS(status))
    {
        return status;
    }

    // 卸载模块
    status = MmUnmapViewOfSection(pEProcess, pImageBase);
    if (!NT_SUCCESS(status))
    {
        return status;
    }
    return status;
}

VOID ThreadProc(_In_ PVOID StartContext)
{
    PMY_DATA pMyData = (PMY_DATA)StartContext;
    LARGE_INTEGER liTime = { 0 };

    // 延时 1 秒 负值表示相对时间
    liTime.QuadPart = -10 * 1000 * 1000;
    KeDelayExecutionThread(KernelMode, FALSE, &liTime);

    // 卸载
    DenyLoadDll(pMyData->ProcessId, pMyData->pImageBase);

    ExFreePool(pMyData);
}

NTSTATUS U2C(PUNICODE_STRING pustrSrc, PCHAR pszDest, ULONG ulDestLength)
{
    NTSTATUS status = STATUS_SUCCESS;
    ANSI_STRING strTemp;

    RtlZeroMemory(pszDest, ulDestLength);
    RtlUnicodeStringToAnsiString(&strTemp, pustrSrc, TRUE);
    if (ulDestLength > strTemp.Length)
    {
        RtlCopyMemory(pszDest, strTemp.Buffer, strTemp.Length);
    }
    RtlFreeAnsiString(&strTemp);

    return status;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
    PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)RemoveNotifyRoutine);
    DbgPrint("驱动卸载完成...");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
    DbgPrint("hello lyshark.ocm \n");

    PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)SetNotifyRoutine);
    DbgPrint("驱动加载完成...");
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

加载这段驱动程序,当有DLL文件被加载后,则会强制弹出,从而实现屏蔽模块加载的作用。

当然用LoadImage回调做监控并不靠谱,因为它很容易被绕过,其实系统里存在一个开关,叫做PspNotifyEnableMask如果它的值被设置为0,那么所有的相关操作都不会经过回调,所有回调都会失效。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[IIS服务]搭建unityWebGl项目服务器(用idea失败了,这次用IIS)

1、确认安装服务 没有安装的&#xff0c;点击安装&#xff0c;安装完成后下一步。 2、配置IIS服务&#xff08;很多小伙伴更新了windows找不到&#xff0c;可以使用cmd运行control admintools打开下图页面&#xff09; 打开管理器之后添加一个网站。 路径选择网站路径&#xf…

【JVM】一篇通关JVM类加载与字节码技术

目录 1. 类文件结构1-1. 魔数 版本 常量池 2. 字节码指令3. 编译期处理4. 类加载阶段5. 类加载器6. 运行期优化 类加载与字节码技术 1. 类文件结构 案例 // HelloWorld 示例 public class HelloWorld {public static void main(String[] args) {System.out.println("h…

策略模式与简单工厂模式:终结if-else混乱,让代码更清爽

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概4500多字&#xff0c;预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#x…

探索 Web API:SpeechSynthesis 与文本语言转换技术

一、引言 随着科技的不断发展&#xff0c;人机交互的方式也在不断演变。语音识别和合成技术在人工智能领域中具有重要地位&#xff0c;它们为残障人士和日常生活中的各种场景提供了便利。Web API 是 Web 应用程序接口的一种&#xff0c;允许开发者构建与浏览器和操作系统集成的…

记录 | photoshop移动选区

期望达到的效果&#xff1a; 选择一块区域&#xff0c;并移动它 操作&#xff1a; (1) 选择矩形选框工具&#xff0c; (2) 对区域进行选取&#xff0c; (3) 选择移动工具&#xff0c; (4) 移动选区&#xff0c;效果如下&#xff0c;

哪些AI软件有消除笔?这四款AI软件轻松消除水印

日常生活或工作中&#xff0c;离不开对图片的处理&#xff0c;AI已经对图片视频下手了&#xff0c;处理软件我们不必在用传统的PS来一点点扣了&#xff0c;AI能瞬间消除图片中多余的杂物&#xff0c;大大提高了打工人的工作效率&#xff0c;那么哪些AI软件有消除笔的功能呢&…

System.out.println隐藏字符串

昨天开发的时候遇到一个坑&#xff0c;这个坑几乎浪费了我一整天时间&#xff0c;我甚至现在都不知道其原因。 开发环境 macOS Ventura 13.4 IntelliJ IDEA 2023.1.2 现象 我用java的各种httpclient获取网络上的一个文本文件&#xff0c;获取的文本文件的内容使用System.ou…

软著项目推荐 深度学习手势识别算法实现 - opencv python

文章目录 1 前言2 项目背景3 任务描述4 环境搭配5 项目实现5.1 准备数据5.2 构建网络5.3 开始训练5.4 模型评估 6 识别效果7 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习手势识别算法实现 - opencv python 该项目较为新颖…

分享83个节日PPT,总有一款适合您

分享83个节日PPT&#xff0c;总有一款适合您 83个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1xX4tVpl3sSW-d2nlFzN-mg?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

《数字图像处理-OpenCV/Python》连载(50)非线性灰度变换

《数字图像处理-OpenCV/Python》连载&#xff08;50&#xff09;非线性灰度变换 本书京东优惠购书链接&#xff1a;https://item.jd.com/14098452.html 本书CSDN独家连载专栏&#xff1a;https://blog.csdn.net/youcans/category_12418787.html 第 7 章 图像的灰度变换 灰度变…

基于瑞芯微rk3588+寒武纪 | 38TOPS INT8算力的AI边缘计算盒子,智能安防、智慧工地、智慧城管、智慧油站

边缘计算盒子 瑞芯微rk3588寒武纪 | 38TOPS INT8算力 ● 采用 Big-Little 大小核架构&#xff0c;搭载四核 A76四核 A55&#xff0c;CPU主频高达 2.4GHz &#xff0c;提供1MB L2 Cache 和 3MB L3 &#xff0c;Cache提供更强的 CPU 运算能力。 ● 高性能四核 Mali-G610 GPU&a…

Tmux奇技淫巧

Tmux奇技淫巧 在日常的开发工作中&#xff0c;终端是我们最常用的工具之一。在终端中我们可以调用各种解释器&#xff0c;来执行命令&#xff0c;完成我们的工作。然而&#xff0c;对于只使用终端的默认功能的开发者来说&#xff0c;他们可能会错过一些强大的工具和技巧&#…

户外电力检测设备,如何实现远程数据实时互通?

北京某企业专注于电力设备的局部放电检测与监测技术的研究与实践应用&#xff0c;可提供局部放电开关柜检测、高频局部放电发电机检测、电力设备绝缘检测等方案。 在实际项目实施过程&#xff0c;企业工作人员需要在各地电力设施部署放电监测设备并进行检测。由于经常涉及户外的…

SLURM资源调度管理系统REST API服务配置,基于slurm22.05.9,centos9stream默认版本

前面给大家将了一下slurm集群的简单配置&#xff0c;这里给大家再提升一下&#xff0c;配置slurm服务的restful的api&#xff0c;这样大家可以将slurm服务通过api整合到桌面或者网页端&#xff0c;通过桌面或者网页界面进行管理。 1、SLURM集群配置 这里请大家参考&#xff1…

今天给大家分享一套Python入门基础测试题,大家看看都会做吗?

今天给大家分享一套Python入门基础测试题&#xff0c;大家看看都会做吗&#xff1f; 一、测试题 1. 正确下载Anaconda平台或Python安装包并成功安装。 2. 掌握Python注释与print()和input()两个函数的用法&#xff0c;并作答以下选择题&#xff08;不定项选择&#xff0c;正…

【UGUI】事件侦听EventSystem系统0学

前言介绍 EventSystem是Unity UGUI中的一个重要组件&#xff0c;用于处理用户输入事件&#xff0c;如点击、拖拽、滚动等。它负责将用户输入事件传递给合适的UI元素&#xff0c;并触发相应的事件回调函数&#xff08;就是你想要做的事情&#xff0c;自定义函数&#xff09;。 …

学生备考护眼灯哪个牌子好?值得入手的护眼台灯推荐

护眼台灯作为这几年人们很关注的电器产品&#xff0c;家里有孩子或者是经常面对电子设备的人士&#xff0c;相信都会对其有所了解并且购买了护眼台灯&#xff0c;但是还有些家长对护眼台灯的认知不够深&#xff0c;以至于还没有给孩子安排上护眼台灯&#xff0c;还在疑惑护眼台…

[ 蓝桥杯Web真题 ]-年度明星项目

目录 引入 介绍 准备 目标 效果 规定 思路 知识补充 解答参考 引入 hello&#xff0c;大家好&#xff01;我注意到了之前发的一篇蓝桥杯Web应用开发的文章是关注度最高的&#xff0c;可能大部分关注我的小伙伴对蓝桥杯Web应用开发比较感兴趣&#xff0c;或者想要参加…

利用Python中的Manim进行数学绘画和创作

相信很多同学就算没听过3Blue1Brown&#xff0c;也一定曾看过他们出品的视频&#xff0c;其从独特的视觉角度解说各种数学概念&#xff0c;内容包括线性代数、微积分、神经网络、傅里叶变换以及四元数等晦涩难懂的知识点。例如最火的《线性代数本质》系列视频。 那么这些视频是…

Fiddler抓包工具之fiddler的命令行窗口用法

fiddler的命令行窗口的相关命令 在fiddler官网有QuickExec使用教程&#xff0c;地址是QuickExec Reference - Fiddler Classic QuickExec 命令行窗口位于fiddler左下角黑色输入框&#xff0c;如下图&#xff1a; 按ALT Q&#xff0c;将焦点快速设置到QuickExec框。如果Fiddl…