重写部分调试体系的DebugPort隐藏

news2025/1/17 4:08:29

背景

逛世界上最大的交友网站的时候发现了一个开源的vt调试器,抱着学习的心态,下载下来学习学习。但是呢,实际编译出来的程序和release发布的有很大的区别,而且源码很乱,release版本的驱动至少能调试程序,但是源码编译之后的驱动还有各种bug,你还不如只放一个bin上去。

就很生气,于是呢!想着自己重写一份吧,但是我又很菜,又很懒,调试体系需要实现的函数也很多。于是在经过不断左右摇摆和尝试之后替换几个api之后完成对debugport的隐藏。==>点我前往<==

调试体系

各位都是大佬,基本都是倒背调试体系的能人,弟弟就不在这里卖弄了,但是呢!还是有必要提一下。

调试主要还是两种,附加和创建调试。

创建:处理是在创建成功之后清零debugport和PS_PROCESS_FLAGS_NO_DEBUG_INHERIT标志位,并且记录调试的目标进程到链表中

if (NT_SUCCESS(status) && ProcessHandle != NULL)
    {
        PDebugInfomation TmpDebuginfo = NULL;
        BOOLEAN isDebug = FALSE;
        KIRQL OldIrql = { 0 };
        KeAcquireSpinLock(&g_DebugLock, &OldIrql);
        for (PLIST_ENTRY pListEntry = g_Debuginfo.List.Flink; pListEntry != &g_Debuginfo.List; pListEntry = pListEntry->Flink)
        {
            PDebugInfomation pDebuginfo = CONTAINING_RECORD(pListEntry, DebugInfomation, List);
            if (pDebuginfo->SourceProcessId == PsGetCurrentProcessId())
            {
                TmpDebuginfo = pDebuginfo;
                isDebug = TRUE;
                break;
            }
        }
        KeReleaseSpinLock(&g_DebugLock, OldIrql);

        if (isDebug)
        {
            PEPROCESS temp_process = NULL;
            status = ObReferenceObjectByHandle(*ProcessHandle, 0x0400, *PsProcessType, ExGetPreviousMode(), (void**)& temp_process, NULL);
            if (!NT_SUCCESS(status))
                return status;

            HANDLE target_pid = PsGetProcessId(temp_process);
            TmpDebuginfo->TargetProcessId = target_pid;
            PVOID DebugPort__ = GetProcess_DebugPort(temp_process);
            *(ULONG64 *)(DebugPort__) = 0;
            DbgkpMarkProcessPeb(temp_process);

            PVOID Flags = GetProcess_ProcessFlags(temp_process);
            *(PULONG64)Flags &= ~PS_PROCESS_FLAGS_NO_DEBUG_INHERIT;

            return status;
        }
    }

附加:没什么特别需要处理的,记录调记录调试的目标进程到链表中

    CurrentProcess = (PEPROCESS)PsGetCurrentProcess();
    status = ObReferenceObjectByHandle(
        DebugObjectHandle,
        0x2,
        *g_DbgkDebugObjectType,
        PreviousMode,
        (PVOID*)& DebugObject,
        NULL);

    KIRQL OldIrql = { 0 };
    KeAcquireSpinLock(&g_DebugLock, &OldIrql);
    for (PLIST_ENTRY pListEntry = g_Debuginfo.List.Flink; pListEntry != &g_Debuginfo.List; pListEntry = pListEntry->Flink)
    {
        PDebugInfomation pDebuginfo = CONTAINING_RECORD(pListEntry, DebugInfomation, List);
        if (pDebuginfo->SourceProcessId == PsGetCurrentProcessId())
        {
            DebugObject = pDebuginfo->DebugObject;
            pDebuginfo->TargetProcessId = PsGetProcessId(Process);
            break;
        }
    }
    KeReleaseSpinLock(&g_DebugLock, OldIrql);

代码的结构

代码总体分未两部分,应用层负责加载dbg api的符号,内核层负责替换调试类型的值和hook函数,主要支持了win7(sp1)和win10(20h2),因为这里部分Eprocess和Ethread的结构体数据是需要自己去定位的。

#ifdef WIN7
#define  Thread_CrossThreadFlags 0x448
#define  Thread_RundownProtect 0x430
#define  Process_DebugPort 0x1f0
#define  Process_RundownProtect 0x178
#define  ProcessFlagS 0x440
#define  ProcessSectionObject 0x268
#define  ProcessSectionBaseAddress 0x270
#define  ThreadStartAddress 0x388
#else
#define  Thread_CrossThreadFlags 0x510
#define  Thread_RundownProtect 0x4f8
#define  Process_DebugPort 0x578
#define  Process_RundownProtect 0x458
#define  ProcessFlagS 0x464
#define  ProcessSectionObject 0x518
#define  ProcessSectionBaseAddress 0x520
#define  ThreadStartAddress 0x450
#endif

应用层

利用sym api从http://msdl.microsoft.com/download/symbols下载符号到本地,然后将对应的api函数地址传输到驱动中

BOOLEAN isSuccess = FALSE;
    do
    {
        HMODULE hNtdll = GetModuleHandle("ntdll.dll");
        if (!hNtdll)
            break;
        g_ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
        if (!g_ZwQuerySystemInformation)
            break;
        Module_INFO Module = { 0 };
        GetKernelModuleInfo(&Module);
        if (!InitSymHandler())
            break;

        HMODULE hDll = LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
        char SymFile1[MAX_PATH] = { "" };
        char szFile[MAX_PATH], SymFile[MAX_PATH] = { "" };
        GetModuleFileNameA(hDll, szFile, sizeof(szFile) / sizeof(szFile[0]));
        if (!SymGetSymbolFile((HANDLE)-1, NULL, szFile, sfPdb, SymFile, MAX_PATH, SymFile1, MAX_PATH))
            break;

        char FileName[MAX_PATH];
        GetSystemDirectoryA(FileName, sizeof(FileName));
        strcat_s(FileName, "\\");
        strcat_s(FileName, Module.KernelName);
        HANDLE hFile = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            break;

        DWORD dwfilesize = GetFileSize(hFile, NULL);
        DWORD64 BaseOfDll = SymLoadModule64((HANDLE)-1, hFile, FileName, NULL, (DWORD64)Module.KernelBass, dwfilesize);
        CloseHandle(hFile);
        if (!BaseOfDll)
            break;

        if (!SymEnumSymbols((HANDLE)-1, BaseOfDll, 0, (PSYM_ENUMERATESYMBOLS_CALLBACK)& EnumAllSymbolsCallBack, CallBack))
            break;
        isSuccess = TRUE;
    } while (FALSE);
    return isSuccess;

会用到的api

typedef struct _SYMBOLS_DATA{
    PVOID NtCreateDebugObject;
    PVOID PsGetNextProcessThread;
    PVOID DbgkpPostFakeThreadMessages;
    PVOID DbgkpWakeTarget;
    PVOID DbgkpSetProcessDebugObject;
    PVOID DbgkCreateThread;
    PVOID DbgkpQueueMessage;
    PVOID PsCaptureExceptionPort;
    PVOID DbgkpSendApiMessage;
    PVOID DbgkpSendApiMessageLpc;
    PVOID DbgkpSendErrorMessage;
    PVOID DbgkForwardException;
    PVOID DbgkpSuppressDbgMsg;
    PVOID DbgkpSectionToFileHandle;
    PVOID DbgkUnMapViewOfSection;
    PVOID DbgkpPostFakeProcessCreateMessages;
    PVOID NtDebugActiveProcess;
    PVOID DbgkpMarkProcessPeb;
    PVOID KiDispatchException;
    PVOID NtCreateUserProcess;
    PVOID DbgkDebugObjectType;
    PVOID ObTypeIndexTable;
    PVOID NtTerminateProcess;
    PVOID DbgkMapViewOfSection;
    PVOID DbgkSendSystemDllMessages;
}SYMBOLS_DATA, * PSYMBOLS_DATA;

内核

初始化记录debugport对象的链表,替换部分使用到debugport的函数和DbgkDebugObjectType,其中这里的hook使用了airhv版本和ShotHv版本的vt,ShotHv版本的是放到源代码中的,并且ShotHv也比较适合学习,只handle必要的vmexit和ept

    //初始化调试对象的链表和锁
    InitializeListHead(&g_Debuginfo.List);
    KeInitializeSpinLock(&g_DebugLock);

    //这里开始hook函数
#ifdef WINVM
    PHHook(g_SymbolsData.DbgkCreateThread, DbgkCreateThread, (PVOID*)&OriginalDbgkCreateThread);
    PHHook(g_SymbolsData.DbgkpQueueMessage, DbgkpQueueMessage, (PVOID*)&OriginalDbgkpQueueMessage);
    PHHook(g_SymbolsData.NtTerminateProcess, NtTerminateProcess, (PVOID*)&OrignalNtTerminateProcess);
    PHHook(g_SymbolsData.NtCreateUserProcess, NtCreateUserProcess, (PVOID*)&OrignalNtCreateUserProcess);
    PHHook(g_SymbolsData.KiDispatchException, KiDispatchException, (PVOID*)&OrignalKiDispatchException);
    PHHook(g_SymbolsData.NtCreateDebugObject, NtCreateDebugObject, (PVOID*)&OriginalNtCreateDebugObject);
    PHHook(g_SymbolsData.NtDebugActiveProcess, NtDebugActiveProcess, (PVOID*)&OriginalNtDebugActiveProcess);
    PHHook(g_SymbolsData.DbgkForwardException, DbgkForwardException, (PVOID*)&OriginalDbgkForwardException);
    PHHook(g_SymbolsData.DbgkMapViewOfSection, DbgkMapViewOfSection, (PVOID*)&OriginalDbgkMapViewOfSection);
    PHHook(g_SymbolsData.DbgkUnMapViewOfSection, DbgkUnMapViewOfSection, (PVOID*)&OriginalDbgkUnMapViewOfSection);
    PHHook(g_SymbolsData.DbgkpSetProcessDebugObject, DbgkpSetProcessDebugObject, (PVOID*)&OriginalDbgkpSetProcessDebugObject);
    PHActivateHooks();
#else
    hook_function(g_SymbolsData.DbgkCreateThread, DbgkCreateThread, (PVOID*)&OriginalDbgkCreateThread);
    hook_function(g_SymbolsData.DbgkpQueueMessage, DbgkpQueueMessage, (PVOID*)&OriginalDbgkpQueueMessage);
    hook_function(g_SymbolsData.NtTerminateProcess, NtTerminateProcess, (PVOID*)&OrignalNtTerminateProcess);
    hook_function(g_SymbolsData.NtCreateUserProcess, NtCreateUserProcess, (PVOID*)&OrignalNtCreateUserProcess);
    hook_function(g_SymbolsData.KiDispatchException, KiDispatchException, (PVOID*)&OrignalKiDispatchException);
    hook_function(g_SymbolsData.NtCreateDebugObject, NtCreateDebugObject, (PVOID*)&OriginalNtCreateDebugObject);
    hook_function(g_SymbolsData.NtDebugActiveProcess, NtDebugActiveProcess, (PVOID*)&OriginalNtDebugActiveProcess);
    hook_function(g_SymbolsData.DbgkForwardException, DbgkForwardException, (PVOID*)&OriginalDbgkForwardException);
    hook_function(g_SymbolsData.DbgkMapViewOfSection, DbgkMapViewOfSection, (PVOID*)&OriginalDbgkMapViewOfSection);
    hook_function(g_SymbolsData.DbgkUnMapViewOfSection, DbgkUnMapViewOfSection, (PVOID*)&OriginalDbgkUnMapViewOfSection);
    hook_function(g_SymbolsData.DbgkpSetProcessDebugObject, DbgkpSetProcessDebugObject, (PVOID*)&OriginalDbgkpSetProcessDebugObject);
#endif

    if (!HookDbgkDebugObjectType())
        return FALSE;

hook函数的说明

需要处理的函数大概就是下面所罗列的,但是由于有懒人所以并没有都处理。

/*
    win7-win10下
    会用到debugport的函数
    PsGetProcessDebugPort       //获取debugport的值,不处理
    DbgkpSetProcessDebugObject  //这里不将debugport的值写到eprocess的debugport字段,也不调用DbgkpMarkProcessPeb
    DbgkpMarkProcessPeb         //DbgkClearProcessDebugObject、DbgkpCloseObject(objectType的CloseProcedure,这里直接不实现)和DbgkpSetProcessDebugObject中会调用
    DbgkCreateThread            //简单实现内部有点长,不实现线程回调
    PspExitThread                 //不实现,不要线程退出消息
    DbgkExitThread              //PspExitThread会调用DbgkExitThread,上面都不实现
    DbgkpQueueMessage            //实现比较简单
    KiDispatchException           //可以不实现,但内核调试器会先捕获到异常需要gn,不方便内核调试,而且不处理过不了int 2d
    DbgkForwardException        //调用了三个原函数
    NtQueryInformationProcess     //不处理
    DbgkClearProcessDebugObject //不实现 
    DbgkpCloseObject            //不实现  
    DbgkMapViewOfSection        //调用了两个原函数
    DbgkUnMapViewOfSection        //调用了两个原函数
    DbgkExitProcess                //不实现
*/

KiDispatchException

可以不处理,但是不处理就过不了int 2d

    if (PreviousMode != KernelMode)
    {
        BOOLEAN isDebug = FALSE;
        KIRQL OldIrql = { 0 };
        KeAcquireSpinLock(&g_DebugLock, &OldIrql);
        for (PLIST_ENTRY pListEntry = g_Debuginfo.List.Flink; pListEntry != &g_Debuginfo.List; pListEntry = pListEntry->Flink)
        {
            PDebugInfomation pDebuginfo = CONTAINING_RECORD(pListEntry, DebugInfomation, List);
            if (pDebuginfo->TargetProcessId == PsGetCurrentProcessId())
            {
                isDebug = TRUE;
                break;
            }
        }
        KeReleaseSpinLock(&g_DebugLock, OldIrql);

        if (isDebug)
        {
            if ((TrapFrame->SegCs & 0xfff8) == KGDT64_R3_CMCODE)
            {
                switch (ExceptionRecord->ExceptionCode)
                {
                case STATUS_BREAKPOINT:
                    ExceptionRecord->ExceptionCode = STATUS_WX86_BREAKPOINT;
                    break;
                case STATUS_SINGLE_STEP:
                    ExceptionRecord->ExceptionCode = STATUS_WX86_SINGLE_STEP;
                    break;
                }
            }

            if (DbgkForwardException(ExceptionRecord, TRUE, FALSE))
            {
                //int 2d 不返回,直接下发异常到异常处理
                if (*(PUSHORT)((ULONG64)(TrapFrame->Rip) - 3) != 0x2DCD)//int 2d
                    return;
            }

            if ((TrapFrame->SegCs & 0xfff8) == KGDT64_R3_CMCODE)
            {
                switch (ExceptionRecord->ExceptionCode)
                {
                case STATUS_WX86_BREAKPOINT:
                    ExceptionRecord->ExceptionCode = STATUS_BREAKPOINT;
                    break;
                case STATUS_WX86_SINGLE_STEP:
                    ExceptionRecord->ExceptionCode = STATUS_SINGLE_STEP;
                    break;
                }
            }
        }
    }

    OrignalKiDispatchException(ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
    return;

NtTerminateProcess

主要是进程结束之后删除记录,避免出现调试器不重启不能调试的情况

    NTSTATUS st;
    PEPROCESS Process = NULL;
    if (ProcessHandle)
    {
        st = ObReferenceObjectByHandle(ProcessHandle,
            PROCESS_TERMINATE,
            *PsProcessType,
            ExGetPreviousMode(),
            (PVOID*)& Process,
            NULL);
    }
    else
    {
        Process = PsGetCurrentProcess();
    }

    if (Process)
    {
        KIRQL OldIrql = { 0 };
        KeAcquireSpinLock(&g_DebugLock, &OldIrql);
        for (PLIST_ENTRY pListEntry = g_Debuginfo.List.Flink; pListEntry != &g_Debuginfo.List; pListEntry = pListEntry->Flink)
        {
            PDebugInfomation pDebuginfo = CONTAINING_RECORD(pListEntry, DebugInfomation, List);
            if (pDebuginfo->TargetProcessId == PsGetProcessId(Process))
            {
                RemoveEntryList(&pDebuginfo->List);
                ExFreePool(pDebuginfo);
                break;
            }
        }
        KeReleaseSpinLock(&g_DebugLock, OldIrql);


        if (ProcessHandle)
            ObDereferenceObject(Process);
    }

    return OrignalNtTerminateProcess(ProcessHandle,ExitStatus);

最后的结果

能正常调试vmp和se,并且没有debugport的痕迹(如果你想调试某游戏,我的评价是我不知道,因为我不玩)。

al-khaser_x86下除了父进程和watch memory,debug的痕迹都没有了(当然检测的方式还有窗口名和进程名的方式,这里并没有处理,你可以参考hyperhiden把这些也加上),NtYieldExecution在当前开了vt的虚拟机下就是bad(不管)。

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

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

相关文章

文件IO操作

日升时奋斗&#xff0c;日落时自省 目录 1、文件基本认知 1.1、文件路径 1.2、相对路径 1.3、文件类型 2、Java的文件操作 2.1、文件操作类File 3、数据流读写 3.1字节流读文件 3.2、字节流写文件 3.3、字符流读操作 3.4、字符流写操作 4、文件操作案例 4.1、删除…

【自学Python】Python类型转换

Python类型转换 Python类型转换教程 虽然 Python 是弱类型编程语言&#xff0c;不需要像 Golang 或 C/C 语言那样还要在使用 变量 前声明变量的类型&#xff0c;但在一些特定场景中&#xff0c;仍然需要用到类型转换。 对 Python 内置的数据类型进行转换时&#xff0c;可以使…

valgrind callgrind使用

valgrind --toolcallgrind --dump-instryes ./foo # ,这里会运行很久,执行完毕后会生成一个callgrind.out.1266511如果你调试的程序是多线程&#xff0c;你也可以在命令行中加一个参数 -separate-threadsyes。这样就会为每个线程单独生成一个性能分析文件。如下&#xff1a;val…

好玩的小游戏系列 (一)基于html+js 原生贪吃蛇

一朵花如果只被用来观赏那只呈现出它的外在意义只是它生命的一部分若是不能够将其内在更实质的美发挥出来充其量也不过就是一朵死的花而已。 目录 一、前言 二、代码介绍 三、效果显示 四、编码实现 index.html jquery-1.10.2.js 五、获取源码 获取源码&#xff1f;私信…

【vue2】组件进阶与插槽(匿名·具名·作用域插槽详解)

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;v-modedl表单双向绑定、ref|$ref操作dom、dynamic动态组件、$nextTick同步、匿名插槽、具…

Java常用开发工具有哪些

本节介绍一下 Java 常用的几个开发工具。下面这些工具或许功能和作用不同&#xff0c;但是有着一个共同的主旨&#xff0c;那就是——它们都是为了给 Java 编码和开发提供卓越的支持。 常用源码编辑工具介绍 Java 源代码本质上其实就是普通的文本文件&#xff0c;所以理论上来…

【阶段三】Python机器学习16篇:机器学习项目实战:集成模型介绍、随机森林模型的基本原理与随机森林分类模型

本篇的思维导图: 集成模型介绍 集成学习模型使用一系列弱学习器(也称为基础模型或基模型)进行学习,并将各个弱学习器的结果进行整合,从而获得比单个学习器更好的学习效果。集成学习模型的常见算法有Bagging算法和Boosting算法两种。 算法类型 模型名称

lua 入门

安装 linux 下安装方式 curl -R -O http://www.lua.org/ftp/lua-5.4.4.tar.gz tar zxf lua-5.4.4.tar.gz cd lua-5.4.4 # 编译并测试没有问题 make all test make install卸载 cd lua-5.4.4 # 删除相关配置,之后可以删除 lua-5.4.4 make uninstall执行 文件以 .lua 结尾 方…

Flume第一章:环境安装

系列文章目录 Flume第一章&#xff1a;环境安装 文章目录系列文章目录前言一、Flume是什么&#xff1f;二、环境安装1.文件下载2.环境安装3.官方案例三、几个案例1.实时监控 Hive 日志&#xff0c;并上传到 HDFS 中2.使用 Flume 监听整个目录的文件&#xff0c;并上传至 HDFS3…

【构造】Codeforces Round #843 (Div. 2) B Gardener and the Array

Problem - B - Codeforces题意&#xff1a;给定一个序列&#xff0c;让你判断是否存在两个子序列使得这两个子序列或起来相等思路&#xff1a;设两个子序列是a和b两个子序列凭空出现&#xff0c;那肯定考虑构造满足的条件是&#xff1a;a!bf(a)f(b)如果只考虑第二个条件&#x…

java系列文章之反射

文章目录一、动态语言二、反射机制概念三、反射的应用场合1. 编译时类型和运行时类型2. 编译时类型无法获取具体方法四、 反射 API五、反射使用步骤六、获取 Class 对象的 3 种方法七、创建对象的两种方法总结一、动态语言 动态语言&#xff0c;是指程序在运行时可以改变其结构…

读书:《5%的改变》

《5%的改变》 我们并不需要100%的改变&#xff0c;彻底推翻以前的旧习惯&#xff0c;对于绝大多数人来说&#xff0c;并不太现实&#xff0c;不如考虑一下只改变5%。 一天结束&#xff0c;22:00&#xff0c;开始为睡觉做准备&#xff0c;反思一下&#xff0c;发现今天好像什…

Pytorch LSTM实现中文单词预测(附完整训练代码)

Pytorch LSTM实现中文单词预测(附完整训练代码) 目录 Pytorch LSTM实现中文单词预测(词语预测 附完整训练代码) 1、项目介绍 2、中文单词预测方法&#xff08;N-Gram 模型&#xff09; 3、训练词嵌入word2vec&#xff08;可选&#xff09; 4、文本预处理 &#xff08;1&…

Java面向对象之继承

目录继承概述、使用继承的好处总结继承的设计规范、内存运行原理总结继承的特点总结继承后&#xff1a;成员变量、成员方法的访问特点总结继承后&#xff1a;方法重写继承后&#xff1a;子类构造器的特点总结继承后&#xff1a;子类构造器访问父类有参构造器总结this、super使用…

k8s之DaemonSet

写在前面 假定现在有一个这样的需求&#xff0c;需要收集每个Node的运行状态信息&#xff0c;并进行上报&#xff0c;假设有4个节点&#xff0c;我们可以使用Deployment 来实现吗&#xff1f;好像是可以的&#xff0c;我们只需要将repliacas设置为4不就行了&#xff0c;但是de…

怎样让公司全员贡献结构化内容?

- 1 - 问题 一个朋友在一个生产型企业的文档团队负责产品文档&#xff0c;他们使用DITA来编写各类文档&#xff0c;比如&#xff1a;公司管理文档、产品介绍、产品使用说明、产品安装手册等。 DITA 是基于XML的体系结构&#xff0c;用于编写、制作、交付面向主题的信息类型…

【NI Multisim 14.0 操作实例——音量控制电路】

目录 序言 一、音量控制电路 &#x1f34a;1.设置工作环境 &#x1f34a; 2.设置原理图图纸 &#x1f34a; 3.设置图纸的标题栏 &#x1f34a; 4.放置元器件 &#x1f34a; 5.编辑元器件属性 &#x1f34a; 6. 布局元器件 序言 NI Multisim最突出的特点之一就是用户界面…

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 (一)四选一多路器

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 &#xff08;一&#xff09;四选一多路器 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN博客 &#x1f9e8;未经作者允许&#xff0c;禁止转载 &#x1f511;系列专栏&#xff1a; &#x…

Mercurius <11.5.0 存在拒绝服务漏洞(CVE-2023-22477)

漏洞描述 Mercurius 是NPM仓库中的开源组件&#xff0c;用作于 Fastify Web 框架的 GraphQL 适配器。 11.5.0 之前版本的 Mercurius 开启“订阅”功能时&#xff0c;任何 Mercurius 用户都可以通过 WebSocket 向 /graphql 端点&#xff08;如&#xff1a;ws://127.0.0.1:1337…

【屏幕驱动移植】点亮OLED屏幕并播放视频

写在前面 硬件软件准备: 名称备注屏幕SSD1106本文章所使用的的屏幕型号&#xff0c;仅仅作为驱动移植示例&#xff0c;其他型号的都可以按照本文的方法推广树莓派3B用于驱动屏幕&#xff0c;树莓派2B3B4B等型号都可以ESP32开发板用于驱动屏幕&#xff0c;具体是ESP32还是ESP32…