这里借尸还魂用初赛的程序来当成dwm做测试
看到决赛题目加了个驱动,盲猜:功能肯定在驱动里面~
无花无壳,IDA之!
注册了一个FirmwareTableCallback
驱动主要逻辑功能在14A0中,主要看截图函数和说明吧
找到需要的函数之后,解密shellcode
通过mdl方式hook和unhook
FixVad的时候成功之后没有减去引用计数[BUG](没事,反正没用到驱动)
patch一下,修复此bug,增加引用计数的释放
没看,因为没用到...
看完驱动逻辑之后发现主要实现已经给出,所以exe不需要看了。
命题的实现方法:
笔者的实现方式:
找到 dwm.exe 的 D3DCOMPILER_47.dll 和 dxgi.dll:
D3DCOMPILER_47.dll 和 dxgi.dll 是系统share类型dll,故而全局进程内的模块地址都应该一致的,通过process hacker证实。
定位到 D3DCompile 函数和 PresentMultiplaneOverlay 函数
由1得知,既然一致,那直接写个demo程序,LoadLibrary此两个dll,通过模拟驱动获取模块的逻辑,也是一样的效果
解密 shellcode 并且注入到 dwm.exe 进程里面
解密shellcode的代码逻辑可以直接从驱动反汇编里面扣出来。但是,特征码代码太巨型,怎么办?这里使用mapfile方式将驱动加到进程模块列表当中,那就等于访问普通dll方式来访问了!
映射完驱动文件之后,通过扣驱动的获取PresentMultiplaneOverlay地址的特征搜索代码实现获取对应函数
扣驱动的shellcode解密和生成hook跳的代码
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
直接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处
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-4-30 22:22
被z许编辑
,原因: 错别字