天堂W游戏内核驱动保护简单分析(五)

NP 双机调试分析


1. 调用了NtQuerySystemInformation(SystemKernelDebuggerInformation) 来检测os是否是调试模式的进程
    PROCESS ffff920744e6c300
        SessionId: 1  Cid: 1a34    Peb: bc82205000  ParentCid: 111c
        DirBase: 23c33c000  ObjectTable: ffffa90b3ffbbb40  HandleCount: 1098.
        Image: LineageR.exe


    PROCESS ffff920748ec8080
        SessionId: 1  Cid: 05f4    Peb: 00262000  ParentCid: 1a34
        DirBase: 20acef000  ObjectTable: ffffa90b40aae680  HandleCount: 391.
        Image: GameGuard.des

    PROCESS ffff9207489ef080
        SessionId: 1  Cid: 0c04    Peb: 00233000  ParentCid: 1a34
        DirBase: 1a4926000  ObjectTable: ffffa90b3ec27dc0  HandleCount: 469.
        Image: GameMon.des

    GameMon64.des
    PurpleLauncher.exe
    Purple.exe
    purple-agent.exe

2. NtQueryObject() -> DebugObject 未发现

3. 隐藏kdcom.dll和Dgbv.sys

4. 关闭 NtQuerySystemInformation(ProcessBasicInformation 和 ProcessDebugPort) 
        检测当前系统是否处于调试状态, 比如双机调试 
        SystemKernelDebuggerInformation->DebuggerEnabled = FALSE; (双机调试 )
        SystemKernelDebuggerInformation->DebuggerNotPresent = FALSE; (双机调试 )
        dt _KUSER_SHARED_DATA结构成员
            检测 KdDebuggerEnabled 值是否为1                         (双机调试 ) 只要这个为真,则np就会退出进程
            检测 KdEnteredDebugger 值是否为1                             (双机调试 ) 
            检测 KdDebuggerNotPresent 值是否为0,正常应该为1
        KiDebugRoutine = KdpStub 则不可调试, 可调试的是kdpTrap     (双机调试 ) 待测试

    np的保护检测 KdDebuggerEnabled 分析:
        首先将 KdDebuggerEnabled + 0x10 处的值设置为1, 然后把系统所有访问 KdDebuggerEnabled 的地方全部改为 KdDebuggerEnabled + 0x10, 启动游戏断下的就是游戏的驱动在访问了. 
        注意其中有几处mov指令的是保存 KdDebuggerEnabled指针的指针,只需要交里面的指针 + 0x10即可,而不是修改机器码
    fffff801`18cd1e6b 490fb70424     movzx   rax, word ptr [r12]
    fffff801`18cd1e70 488b09         mov     rcx, qword ptr [rcx]
    fffff801`18cd1e73 4889ea         mov     rdx, rbp
    fffff801`18cd1e76 4881c224000000 add     rdx, 24h 
    fffff801`18cd1e7d 0302           add     eax, dword ptr [rdx] // 这里就是在读 KdDebuggerEnabled, 代码应该是vmp混淆了
    fffff801`18cd1e7f 8a09           mov     cl, byte ptr [rcx]  // 这里的cl就是 KdDebuggerEnabled 的值
    fffff801`18cd1e81 0fb6f9         movzx   edi, cl
    fffff801`18cd1e84 418938         mov     dword ptr [r8], edi // 这里将KdDebuggerEnabled写入r8, 而r8又是KdDebuggerEnabled的地址
    fffff801`18cd1e87 4981c004000000 add     r8, 4
    fffff801`18cd1e8e 41c70000000000 mov     dword ptr [r8], 0
    代码附近有看到 0x7FFE0000 所以猜测是使用应用层的检测:
        通过读取 KUSER_SHARED_DATA.KdDebuggerEnabled 的值来检测内核模式调试器是否处于活动状态,
        KUSER_SHARED_DATA 始终位于每个进程的虚拟地址空间中地址 0x7FFE0000 的用户空间中, 偏移固定是0x2D4.
        参考: https://github.com/kyREcon/IsKernelDebuggerPresent

    np调用 MmGetSystemRoutineAddress 函数日志
    nt!_UNICODE_STRING
     "PsSuspendProcess"
       +0x000 Length           : 0x20
       +0x002 MaximumLength    : 0x22
       +0x008 Buffer           : 0xfffff801`6595a3d8  "PsSuspendProcess"
    nt!_UNICODE_STRING
     "PsResumeProcess"
       +0x000 Length           : 0x1e
       +0x002 MaximumLength    : 0x20
       +0x008 Buffer           : 0xfffff801`6595a408  "PsResumeProcess"
    nt!_UNICODE_STRING
     "PsGetThreadId"
       +0x000 Length           : 0x1a
       +0x002 MaximumLength    : 0x1c
       +0x008 Buffer           : 0xfffff801`6595a430  "PsGetThreadId"
    nt!_UNICODE_STRING
     "PsIsProtectedProcess"
       +0x000 Length           : 0x28
       +0x002 MaximumLength    : 0x2a
       +0x008 Buffer           : 0xfffff801`6595a458  "PsIsProtectedProcess"
    nt!_UNICODE_STRING
     "PsIsProtectedProcessLight"
       +0x000 Length           : 0x32
       +0x002 MaximumLength    : 0x34
       +0x008 Buffer           : 0xfffff801`6595a490  "PsIsProtectedProcessLight"
    nt!_UNICODE_STRING
     "ObReferenceObjectSafe"
       +0x000 Length           : 0x2a
       +0x002 MaximumLength    : 0x2c
       +0x008 Buffer           : 0xfffff801`6595a4d0  "ObReferenceObjectSafe"
    nt!_UNICODE_STRING
     "ObRegisterCallbacks"
       +0x000 Length           : 0x26
       +0x002 MaximumLength    : 0x28
       +0x008 Buffer           : 0xfffff801`6595a6c8  "ObRegisterCallbacks"
    nt!_UNICODE_STRING
     "ObUnRegisterCallbacks"
       +0x000 Length           : 0x2a
       +0x002 MaximumLength    : 0x2c
       +0x008 Buffer           : 0xfffff801`6595a6f0  "ObUnRegisterCallbacks"

    解决办法有以下几种: 
        1. 直接双机环境启动完成后,加载我们的驱动,然后将KdDebuggerEnabled的值写为0。
            这种情况下虽然无法在windbg里主动断下,但是使用irp请求通知驱动断下,或者监控进程启动,
            或者之前下的断点都是可以让windbg断下。
            > KdDebuggerEnabled 有两种方式,直接在代码里引用,则是使用导入表链接
            > KdDebuggerEnabled 另一种是使用MmGetSystemRoutine()来获取,这种可以hook EAT表或者直接hook这个函数解决,但要解决PG

        2. 修改KUSER_SHARED_DATA.KdDebuggerEnabled值失败,修改过后立即就被重置,
            尝试了从物理使用pte修改页面属性为可写,也还是会被写回去,
            尝试了使用MmGetPhysicalAddress()转换为物理地址后进行写入,也不能解决。
            其他猜测:
                使用 IoAllocateMdl 读取 KdDebuggerEnabled, 
                Hook KdpTrap 该函数无法断下,会导致虚拟机系统卡死
                而且infinity无法hook非ssdt和sssdt内的函数。
                使用IAT hook系统导出变量, (
                        经测试可行, 在PsCreateImageLoadNotify回调里拦截内核模块,然后IAT Hook KdDebuggerEnabled变量即可
                        但注意不能拦截进程,因为那个时候模块还没有加载,得到的导出RVA只是偏移,不是PE展开后的内存地址
                    )
            要想继续研究的话,可以考虑忽略或者干掉pg,直接使用inline hook KdpTrap等其他函数来检测反获取 KdDebuggerEnabled 的方式。
            干掉patchGuard过后,可以直接对访问KdDebuggerEnabled的系统函数进行位移0x10的访问, 即将KdDebuggerEnabled变量地址位移

5. 删除Purple开机启动的任务计划
    schtasks /delete /tn Purple /f
    
6. NP应用层的dll注入
    dll的注入和驱动的卸载都是由GameMon64.des来完成
    且被注入的npggnt64.des应该还有检测GameMon64.des进程是否存在的检测,不存在则自动卸载自己。


7. 经测试CE7.0能使用,CE7.2不能使用,由于CE的驱动只会加载,不会卸载,
    主要原因就是CE7.2的驱动会被检测到非法,不是驱动模块被发现,而是驱动内的问题.
    经过测试,就算不加载CE7.2的驱动,只开CE7.2也会被检测到, 
    说明有可能是应用层被检测到了, 经验证只加载驱动,可以正常游戏不会被检测到,
    那有可能是游戏驱动下使用KeAttachProcess()切换到用户进程空间检测到进程特征了, 可以尝试只让KeAttachProcess附加游戏目录下的进程.
    所以只有CE7.2的驱动加载过了,就必须重启系统或者手动卸载CE7.2的驱动. 
    总结CE7.2应该是窗口有特征被检测到了,因为使用手动编译CE源码改过的CE7.4都不会被检测到

逆向安全收徒中...

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

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

相关文章

【Linux】:进程切换

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux进程切换的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精…

PMP考试做对多少题才算及格?

2024年6月PMP考试即将来临,考生除了要复习好考试内容,也要提前了解考试后的成绩查询问题。顺利通过PMP考试是所有参加PMP认证考试考生的目标,那么2024年6月PMP考试怎么才算通过呢? PMP考试改版后试卷总共180道单选题多选题(改版前…

【AI副业教程】日赚5000+涨粉3000,自媒体新玩法!

​StartAI是一款专为设计师打造的基于Photoshop的AI工具,它提供了一系列强大的AI功能如:文生图、生成相似图、线稿上色、无损放大、局部重绘、扩图、艺术融合、提示词、智能擦除、风格选择等。https://www.istarry.com.cn/?sfromHGtsRq 你们能想象吗&a…

【Android安全】AOSP版本对应编号| AOSP版本适配Pixel或Nexus型号 | 驱动脚本下载地址

AOSP版本对应编号 https://source.android.com/docs/setup/about/build-numbers?hlzh-cn#source-code-tags-and-builds 例如android-8.1.0_r1 对应的编号是OPM1.171019.011 可以适配Pixel 2 XL AOSP驱动脚本下载 编译AOSP时,需要Google的驱动,后面才…

【分享】3种方法取消PPT的“限制保护”

PPT如果设置了有密码的“只读方式”,每次打开PPT,都会出现对话框,提示需要输入密码才能修改文件,否则只能以“只读方式”打开。 以“只读方式”打开的PPT就会被限制,无法进行编辑修改等操作。那如果后续不需要“限制保…

SpringBoot+layuimini实现角色权限菜单增删改查(layui扩展组件 dtree)

角色菜单 相关组件方法效果图代码实现资源菜单树组件实现权限树方法js这里我先主要实现权限树的整体实现方法,如果是直接查看使用的话可以只看这里! 后端代码Controlle层代码Service代码及实现类代码Service代码ServiceImpl代码 resourceMapper 代码role…

从零开始傅里叶变换

从零开始傅里叶变换 1 Overview2 傅里叶级数2.1 基向量2.2 三角函数系表示 f ( t ) f(t) f(t)2.2.1 三角函数系的正交性2.2.2 三角函数系的系数 2.3 复指数函数系表示 f ( t ) f(t) f(t)2.3.1 复指数函数系的系数2.3.2 复指数函数系的正交性 2.4 傅里叶级数总结 3 傅里叶变换…

新人学习笔记之(变量)

一、变量概述 1.什么是变量 (1)白话:变量就是一个装东西的盒子 (2)通俗:变量是用于存放数据的容器。我们通过变量获取数据,甚至数据可以修改 2.变量在内存中的储存 (1)本…

如何将手机中的音乐转移到 SD 卡上?轻松传输音乐

概括 如何将音乐从手机转移到 SD 卡?我们的智能手机可以充当个人点唱机,因此有效管理我们的音乐库变得至关重要。无论您是存储空间不足还是只是想整理您的音乐收藏,将音乐从手机传输到 SD 卡都是一个实用的解决方案。 在本指南中&#xff0…

目标检测YOLO实战应用案例100讲-【目标检测】机器视觉(五)

目录 算法原理 机器视觉硬件技术 一、镜头技术 二、摄像机技术 三、图像采集卡(Image Captu

二叉树的递归实现及例题

目录 遍历方式 示例 原理 前序遍历示例 二叉树的节点个数 原理 层序遍历 原理 这样做的目的是 判断完全二叉树 例题 ​编辑 思路 代码 遍历方式 二叉树的遍历方式可分为: 前序遍历:先访问根,访问左子树,在访问右子…

浏览器的下载行为基本原理

浏览器解析 在使用浏览器访问某些资源时,有些资源是直接下载有些资源是直接打开。例如前端的html,xml,css,图片等资源都是直接打开,而txt,excel等文件是直接下载。那么如何控制访问一个资源时是下载文件还…

App Inventor 2 如何接入ChatGPT:国内访问OpenAI的最佳方式

如何接入OpenAI 由于国内无法访问OpenAI,KX上网可选大陆及香港(被屏蔽)以外才行。因此对于大多数人来说,想体验或使用ChatGPT就不太便利,不过App Inventor 2 为我们提供了相对便利的一种方式,即“试验性质…

C# run Node.js

C# run nodejs Inter-Process Communication,IPC Process类 启动Node.js进程,通过标准输入输出与其进行通信。 // n.js// 监听来自标准输入的消息 process.stdin.on(data, function (data) {// 收到消息后,在控制台输出并回复消息console.l…

连锁服装门店补货一般怎样的流程

连锁服装门店的补货流程通常包括以下四个关键步骤: 分析销售数据和库存情况 首先,连锁服装门店需要定期分析销售数据和库存情况。通过销售数据可以了解各款商品的销售情况、热销款式和滞销款式等信息。同时,需要检查每个门店的库存情况&…

【代码随想录】day60

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、84柱状图中最大的矩形总结 一、84柱状图中最大的矩形 做完接雨水后,这题确实不难了 指针法(超时后根据没通过的样例过滤)&a…

JSON字符串到Map转换的深入探索:Jackson与Gson的实战比较

在现代软件开发中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,几乎无处不在。它以其易于阅读、编写的特性,以及高效的数据存储和传输能力,成为前后端交互、API设计等领域不可或缺的一部…

【MySQL精通之路】INFORMATION_SCHEMA库-INNODB_METRICS表

INNODB_METRICS表提供了各种各样的INNODB性能信息,补充了INNODB性能模式表的特定重点领域。通过简单的查询,您可以检查系统的整体运行状况。通过更详细的查询,您可以诊断诸如性能瓶颈、资源短缺和应用程序问题等问题。 每个监视器表示InnoDB…

06Django项目--用户管理系统--新增

对应视频链接点击直达 06Django项目--用户管理系统--新增 对应视频链接点击直达模块构思a,用户信息的构成(表结构设计)b,models里面的设计 用户新增页面设计a,先在模版里面选一个新增的样式b,然后删除该页面…

win32-鼠标消息、键盘消息、计时器消息、菜单资源

承接前文: win32窗口编程windows 开发基础win32-注册窗口类、创建窗口win32-显示窗口、消息循环、消息队列 本文目录 键盘消息键盘消息的分类WM_CHAR 字符消息 鼠标消息鼠标消息附带信息 定时器消息 WM_TIMER创建销毁定时器 菜单资源资源相关菜单资源使用命令消息的…