首页
论坛
课程
招聘
[原创]2022腾讯游戏安全决赛PC端解题
2022-4-30 22:01 6089

[原创]2022腾讯游戏安全决赛PC端解题

2022-4-30 22:01
6089

运行效果

这里借尸还魂用初赛的程序来当成dwm做测试
图片描述

详细分析

驱动逻辑

看到决赛题目加了个驱动,盲猜:功能肯定在驱动里面~
图片描述
无花无壳,IDA之!
注册了一个FirmwareTableCallback
图片描述

 

驱动主要逻辑功能在14A0中,主要看截图函数和说明吧
图片描述

 

找到需要的函数之后,解密shellcode
图片描述

 

通过mdl方式hook和unhook
图片描述

 

FixVad的时候成功之后没有减去引用计数[BUG](没事,反正没用到驱动)
图片描述

 

patch一下,修复此bug,增加引用计数的释放
图片描述

用户层逻辑

没看,因为没用到...
看完驱动逻辑之后发现主要实现已经给出,所以exe不需要看了。

思路总结

命题的实现方法:

  1. 找到 dwm.exe 的 D3DCOMPILER_47.dll 和 dxgi.dll
  2. 定位到 D3DCompile 函数和 PresentMultiplaneOverlay 函数
  3. 解密 shellcode 并且注入到 dwm.exe 进程里面
  4. hook PresentMultiplaneOverlay 跳转到 shellcode 执行

笔者的实现方式:

  1. 找到 dwm.exe 的 D3DCOMPILER_47.dll 和 dxgi.dll:
    D3DCOMPILER_47.dll 和 dxgi.dll 是系统share类型dll,故而全局进程内的模块地址都应该一致的,通过process hacker证实。
    图片描述

  2. 定位到 D3DCompile 函数和 PresentMultiplaneOverlay 函数
    由1得知,既然一致,那直接写个demo程序,LoadLibrary此两个dll,通过模拟驱动获取模块的逻辑,也是一样的效果
    图片描述

  3. 解密 shellcode 并且注入到 dwm.exe 进程里面
    解密shellcode的代码逻辑可以直接从驱动反汇编里面扣出来。但是,特征码代码太巨型,怎么办?这里使用mapfile方式将驱动加到进程模块列表当中,那就等于访问普通dll方式来访问了!
    图片描述

    映射完驱动文件之后,通过扣驱动的获取PresentMultiplaneOverlay地址的特征搜索代码实现获取对应函数
    图片描述

    扣驱动的shellcode解密和生成hook跳的代码
    图片描述

  4. hook PresentMultiplaneOverlay 跳转到 shellcode 执行
    最后是hook和unhook,一样的扣驱动代码
    图片描述
    图片描述

调试问题

问题:
因为是直接注入到dwm进程实现的功能,那么在调试shellcode的时候,就会有一个很大的问题:dwm不能卡住啊!卡住了你界面都没法动了。

 

解决方法:
既然驱动都能借尸还魂,那么dwm能不能也借一下?
回过头看了一眼初赛题,哎~这不巧了!这就是一具嗷嗷待借的尸啊!
注: 初赛.exe没有D3DCOMPILER_47.DLL,只有D3DCOMPILER_43.DLL。但不碍事。

 

代码逻辑不变,将进程改成初赛.exe,完美实现将shellcode注入到了进程中,这不就可以直接当作普通进程一样进行shellocde动态调试了么!

 

hook 初赛shellcode + 0x420 jmp到决赛shellcode + 0x420
图片描述

虚拟机shellcode分析

直接F5 shellcode的话,笔者的IDA没法还原真正的伪代码逻辑
图片描述

 

参考调试问题的解决方法,F5动态调试的代码,不就可以还原更友好的伪代码了么!(F5赛高!)
图片描述
通过上图可以明显看出,动态调试之后的代码识别比静态时候更友好(也可能是笔者静态分析时候不懂用ida去patch,望赐教)

 

直接扣IDA动态调试时候生成的F5伪代码,将shellcode + 0x420的函数,也就是虚拟机抠出来。通过直接调用。
虚拟机命令码解密需要跑6次,第7次呢跑出来的就是最后绘图的所有点信息
图片描述

 

虚拟机主体逻辑跟初赛类似:
生成坐标对应key
图片描述

 

经过调试发现,点其实都全部画了,只是前面11个点的坐标被赋值成了负值,也就是flag被设置成了负值坐标
图片描述

 

负值如何产生?虚拟机里的sub就成了最大的嫌疑
图片描述

 

通过对sub添加输出信息,明显发现前11个点存在着异常sub数据,分别减去了1000和500,从12点开始数据就正常了。前面11个点?那不恰好是flag么~
图片描述

 

直接将1000和500的数值去掉,可以获取到flag的真实坐标
图片描述

 

可是画出来的很多不能显示
图片描述

 

既然坐标是对的,还不能显示,那只能说明是key不对,如下图:
第11个点:
decrypt -> x key = 0xc42d8b, y key = 0x38f0f
draw -> x key = 0x38f0f, y key = 0xc42d8b

 

第12个点:
decrypt -> x key = 0xeabf17, y key = 0x8f7323
draw -> x key = 0xeabf17, y key = 0x8f7323

 

对比发现,第11个点的key在draw时候被翻转了。
图片描述

 

笔者在琢磨着怎么解决翻转问题的时候,突然灵光一闪,哎?等会!
既然decrypt是只执行一次的,并且此时数据是正确的
而最终的draw也是只执行一次,并且根据正确的数值去画图
那么,decrypt之后,直接调用draw的话,那不就已经是正确的数据了么?!
图片描述

思路总结

1.patch虚拟机的sub处理,发现等于1000和500的时候直接sub 0
2.patch虚拟机的key生成部分,生成之后直接调用draw画图

实现

1.patch sub处理
shellcode + 0x627 处是sub处理, hook之
图片描述

 

判断是否是1000和500,是的话不处理
图片描述

 

2.patch decrypt key处理
shellcode + 0x7a5 处是decrypt key处理,在处理结尾处hook之
图片描述

 

将算出来的坐标key,直接保存成draw的参数位置,然后jmp回draw函数
图片描述

 

红色箭头位置是调用draw函数的地方
图片描述

 

well done~!
图片描述

截图部分

先看看hook PresentMultiplaneOverlay处,通过push mov ret方式写入一个x64 long jmp, 跳到shellcode + 0x860处
图片描述

 

shellcode + 0x860 处是hook了CDXGISwapChain::PresentMultiplaneOverlay的目标函数,最终会调用回之前的函数,前面部分函数内容没截图。
图片描述

 

再来看看回调旧函数,也就是图片里面的retCallback函数,其实就是将旧函数头补回去,然后x64 long jmp
图片描述

思路

1.能否直接利用retCallback之后的那个GetBuffer之后,调用D3DX11SaveTextureToFile保存成文件呢?此函数的所有参数在这段shellcode里面都有提供到。

实现

未实现...
大家五一国际劳动节快乐!!!!!(放假啦还写啥代码[狗头])


[2022夏季班]《安卓高级研修班(网课)》月薪三万班招生中~

最后于 2022-4-30 22:22 被z许编辑 ,原因: 错别字
上传的附件:
收藏
点赞2
打赏
分享
最新回复 (1)
雪    币: 5980
活跃值: 活跃值 (1999)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
黑洛 活跃值 1 2022-5-2 21:55
2
0
很吊
游客
登录 | 注册 方可回帖
返回