吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7366|回复: 52
收起左侧

[游戏安全] 在win7 x64下做个简单的内核绘制

  [复制链接]
万剑归宗 发表于 2023-6-1 01:00
本帖最后由 万剑归宗 于 2023-6-1 12:25 编辑

2023/06/01:搬运我自己在某个司马论坛发过的帖子,以后有新帖会在52更新。

2018/11/08:
1.0
       本贴只针对win7 x64系统下的 32位D3D9程序,局限性太大,仅作为抛砖引玉 。

下面进入正题。


基本流程如下:

1:在内核中 hook相关shadowSSDT或SSDT函数

2:在目标进程申请内存,写入用于D3D9绘制的shellcode

3:利用APC的力量回到 用户模式,执行用于D3D9绘制的 shellcode。

1.1
       首先,如果我们要做一个hook D3D9的绘制。

自然是要编写dll,

注入到目标进程,

hook D3D9虚函数,

获取到D3D9设备,

执行绘制代码。


        时至今日,这种技术已经是基本操作了。

经历各大游戏厂商(代{过}{滤}理商)以及外挂作者们之间的斗争,

这种注入以及hook的方式已然不可取。


        那么是否有一种相对隐蔽的方式来完成这项工作呢?

答案是有的。(废话,没有你写这贴干嘛【滑稽】)

        从我们能想到的根本问题入手的话......

在应用层 hook D3D9虚函数以及直接注入dll会拉闸,

既然如此,我们在内核层做hook,代码全都以shellcode的形式

在目标进程里跑起来。

1.2
       在win7 x64下, 通过调试一个网上下载的D3D9示例Demo

仔细跟踪其 D3D9的Present函数,我们发现 Present 最终会调用

USER32.HungWindowFromGhostWindow+20处的代码

反汇编如下:

image.png

call fs:[000000C0]其实是call Wow64子系统的调用

经过Wow64子系统的包装,最终进入内核。


mov eax, 000012CF这句汇编代码

其中 000012CF代表的是 shadowSSDT 的索引值

了解过 SSDT&shadowsSSDT的朋友都知道

第一个4k页面指向的是SSDT函数

第二个4k页面指向的是shadowSSDT函数

另外两个页面未使用(这是题外话。)

00000012CF在第二个页面上,所以这个索引指向shadowSSDT函数。

我们减去 0x1000 就是它的真实索引值 0x02CF,十进制就是 719。


我们打开PChunter这款非常有用的软件, 我们可以看到索引719指向的

shadowSSDT函数名 NtUserHwndQueryRedirectionInfo

image.png


       接下来我们就hook这个函数并写好过滤

一般来说,这种shadowSSDT函数,只传进来一个参数(rcx), 保险起见我们写四个。

示例过滤函数如下:(自备shadowSSDT hook代码,本贴不会放完整代码,防止伸手)


image.png


       But, 光是这样是不够的, 我们还要在这里获取到D3D9的设备。

这就给我们出了一个难题,一般在应用层都是hook取设备的。

经过查资料,我们想到了一个好办法,利用栈回溯,找到最初调用

Present函数的地方, 并把第一个参数(也就是设备)取出来。

好在windows x86下的栈回溯是基于EBP来回溯的,原理相对简单,

我们可以手动编写一下。

1.3

       应用层在通过syscall进入内核之前,会把当前的TrapFrame保存

起来。在内核中当前_KTHREAD成员 TrapFrame 就是应用层保存的

TrapFrame 指针。


image.png

在win7 x64下,其结构偏移为 0x1D8。

       至此,我们可以顺利的获取应用层最后保存的RBP了。

image.png

接下来写栈回溯,具体原理我就不多做描述,大家可以移步这两个帖子看一下

https://blog.csdn.net/chenlycly/article/details/78144769

https://blog.csdn.net/wu330/article/details/29213201

示例代码如下:

image.png

笔者这里偷了个懒,直接判断call 地址是否小于 0x00500000

以此确定 当前帧就是call present的。

       当然,获取到设备的同时,得以确认,当前线程就是从

Present函数一直call 进内核的。下面就可以放心的执行绘制操作了。

2.0
      在内核中给当前进程申请内存,最方便的莫过于ZwAllocateVirtualMemory

申请内存成功之后,写入shell code。

比如直接call D3D9的 Clear函数,画个方块。

示例如下:

image.png

要注意的是,不要一直不停的申请内存,我想各位看官应该不会这么做[滑稽]。

3.0
      做完如上工作,接下来就可以想办法回到用户模式,执行shellcode了。

回到用户模式的方法有好几种,比如KeUserModeCallBack, APC。

其中 KeUserModeCallBack 需要在应用层中写好代{过}{滤}理分发,并且如果目标进程是

wow64进程,还需要多写一层代{过}{滤}理函数,着实麻烦。

      所以我们采用相对简单的 APC,利用APC机制回到用户模式。

代码如下:

image.png


注意这里的细节,如果目标进程是 wow64进程,起始地址需要 / -4。

然后就是常规的初始化APC,插入队列。

      由于我们是回到当前进程的应用层,所以初始化APC时,

KeInitializeApc第二个参数填 PsGetCurrentThread()。

最后利用KeTestAlertThread直接触发队列里的APC Routine。

3.1
放上效果图如下:

image.png

3.2
But
出现了新的问题
经过笔者测试,有些系统并不走 NtUserHwndQueryRedirectionInfo

而是另外的ShadowSSDT函数,不过我们依然有办法解决这种小问题。


在出问题的机器上,一通调试分析后,找到如下代码
image.png

图片可能有点模糊
命中断点位置的代码是cmp [esi+760],ebx   
其中 esi+760 = 0xC2D4118
然而地址 0xC2D4118的值为0,
所以代码会 je D3D9.DLL+7C47
抛开这里往下看
如果没有 je D3D9.DLL+7C47
代码会走进这里

image.png
一路跟进去
image.png
再跟

再跟

再跟

最终看到了熟悉的代码, 是  NtUserHwndQueryRedirectionInfo

NtUser

NtUser


3.3
然而直接走到 D3D9.DLL+7C47 肯定不会经过  NtUserHwndQueryRedirectionInfo
最简单的解决方式肯定是直接把 je D3D9.DLL+7C47 nop
测试结果如下

有效果

有效果


很明显
改了之后加载驱动可以直接绘制上这个 基佬色 的方块
然而还原之后

无效果

无效果

绘制效果消失了
而且在 USER32.HungWindowFromGhostWindow+20处
下断点是不会命中的(这不是废话吗)

4.0
梳理流程

流程图1

流程图1


判断函数主要判断 [esi+760] 是否为0

如果为0,直接走 D3D9.DLL+7C47,否则走 NtUserHwndQueryRedirectionInfo

这里我有必要提一下,不要想着锁定  [esi+760] 的值,这样做会导致D3D无限初始化Surface
虽然进了 NtUserHwndQueryRedirectionInfo,但是会一直在这里死循环,不再进行任何绘制。

而且修改代码段的内存来强行让他走 NtUserHwndQueryRedirectionInfo 恐怕也不是各位看官想要的结果.



4.1


摆在面前的有两条路

1: 在创建窗口->创建D3D设备 这个流程中仔细分析创建需要的参数,找出其原因.

2: 在这个绘制流程中,进入判断函数前 改掉 [esi+760] 的值,进入  NtUserHwndQueryRedirectionInfo 之后再改回来


由于时间有限,我姑且只讲一下第二种方式。

笔者重新理了一下执行流程

流程图2

流程图2

如图所示,我们只需要在 D3DKMTPresent 这个函数进入内核之后
改变其 [esp+760] 的值为1

在进入判断代码时,就会顺理成章的进入 NtUserHwndQueryRedirectionInfo

然后我们在  NtUserHwndQueryRedirectionInfo里把 [esp+760] 的值改成 0

这样走到后面的检测代码中,就不会无限获取D3D9主Surface导致死循环。


还有个很重要的问题 esp+760 如何获取,这个比较简单了,经过笔者指针扫描+瞎猜
这个值可以通过如下方式获得。

CE指针

CE指针

最后一级偏移为760,所得地址便是 esp+760 ,所得值便是 [esp+760]。



结语:

来自未来的时间(2023/06/01):

以后有空再对这类型内容做研究,届时依然在52更新

免费评分

参与人数 13威望 +2 吾爱币 +112 热心值 +9 收起 理由
cetl215430 + 1 我很赞同!
notifier + 1 + 1 我很赞同!
1MajorTom1 + 1 热心回复!
N1san + 1 + 1 热心回复!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
积积 + 1 + 1 别人号影响看雪先赚一个亿了,可不得被封么。感谢发布原创作品,吾爱破解论.
成熟的美羊羊 + 1 你怎么在看雪号被封了就喊看雪是司马论坛?没粟子啊。
sorryzzital + 1 + 1 谢谢@Thanks!
willJ + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zhczf + 1 我很赞同!
sam喵喵 + 1 谢谢@Thanks!
woyucheng + 1 + 1 热心回复!
blindcat + 1 + 1 虽然看不懂,但感觉很厉害的样子

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 万剑归宗 发表于 2023-6-1 12:37
本帖最后由 万剑归宗 于 2023-6-4 21:25 编辑

早期Demo
KernelDirect.zip (150.52 KB, 下载次数: 27)

2023/06/04
1111111111
tonyfeng 发表于 2024-2-1 17:25
大哥,你好,CAD2005注册机是32位程序,能在WIN7X64运行,也能在运行,但是不能在WIN10 11运行,你有办法让它直接在WIN10X64运行吗
tzblue 发表于 2023-6-5 08:22
离开3环进入0环,还好是Win7,从Win8开始就有云代码,修改内核行不通,除非搞到驱动签名,当然大牛会有更直接的方法。
陨落星辰 发表于 2023-6-1 12:29
Good.從某雪過來支持你
blindcat 发表于 2023-6-1 12:36
太高深了,一点都看不懂
Sm0key 发表于 2023-6-1 12:48
大牛,看不懂,膜拜就完了
内阁首辅 发表于 2023-6-1 14:48
字我都认识
apull 发表于 2023-6-1 16:23
这个厉害了,涨姿势了。
aonima 发表于 2023-6-1 17:41
感谢分享
lafa21 发表于 2023-6-1 20:32
字都认识,下一步做什么才好
moruye 发表于 2023-6-1 22:27
厉害厉害,感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-27 00:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表