首页
社区
课程
招聘
[原创]Win8 32位中SSDT Shadow Hook的实现方法
发表于: 2013-12-9 17:31 58850

[原创]Win8 32位中SSDT Shadow Hook的实现方法

2013-12-9 17:31
58850
收藏
免费 5
支持
分享
最新回复 (61)
雪    币: 97
活跃值: (43)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
我就当一把沙发吧,虽然看不懂,但是顶起来吧
2013-12-9 17:43
0
雪    币: 49
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
还没见过win8啥样子了
下个 学习下新系统的HOOK
2013-12-9 17:43
0
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
4
没装过win8系统的飘过...
2013-12-9 17:50
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
5
粗看一下没明白。
win32k.sys因为会话空间的原因直接在非GUI线程下访问可能未在地址空间中被映射到问题是老生常谈了,XP下也得这样处理呀
2013-12-9 19:46
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
但是在使用KeAddSystemServiceTable函数搜索shadow地址在win8中不成功了。
这个方法是全新的,根据系统定位shadow方法,搜索线程来定位shadow。全新方法。
2013-12-9 19:51
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
7
粗看一下没明白。就是取SSDT Shadow的方式不一样。
而且……规范的做法是通过调试符号寻找win32k!W32pServiceTable

win32k.sys因为会话空间的原因直接在非GUI线程下访问可能未在地址空间中被映射到问题是老生常谈了,XP下也得这样处理呀
2013-12-9 19:54
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
我在KiFastCallEntry函数中看系统是,查找KTHREAD!ServiceTable成员得到shadow地址的。
我这个方法模仿了系统的查找方法。
2013-12-9 19:58
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
9
额,一开始看标题还以为win8 32位里有PG还是啥的
2013-12-9 21:27
0
雪    币: 623
活跃值: (40)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
mark
2013-12-9 21:50
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
11
从线程KTHREAD里找服务表的方法早就有了啊,只不过大家一般都用别的方法了,这种用得少而已,XP里也是这么干的,真不是什么新方法。。。。至少四年前在DebugMan就看过了

还有win32k.sys访问的问题,与GUI无关,是Session的原因,只要不是smss.exe或System,其它进程都可以访问的
2013-12-9 22:34
0
雪    币: 213
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感谢楼主分享好方法!
2013-12-10 08:12
0
雪    币: 293
活跃值: (287)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
粗略的看了下,说了KeServiceDescriptorTableShadow 在win8 x86中位置变了。不过有多少人用win8  x86呢?
2013-12-10 08:44
0
雪    币: 84
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
从GUI ethread的ServiceTable取这个方法不是一直都有??只不过在之前的系统上。。不如搜索出来的好罢了。。ethread的servicetable毕竟是可以被很简单的就改了的。。
2013-12-10 08:50
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
这个是我自己研究的,从来没看见谁公布过。系统取SSDT或者ssdt shadow 基地址 并不是搜索KeAddSystemServiceTable函数。 哈哈
2013-12-10 09:31
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
为什么我在同一个session下,换一个带GUI的线程就可以在内存空间中访问到Win32k?
看来session不是必要条件,带GUI的进程,线程才是必要条件。
系统在查找Shadow时,也是先看KTHREAD的 Win32Thread成员,确定其是否是gui线程。然后才取得ServiceTable成员。
非GUI线程的Win32Thread成员是0,当然ServiceTable指向的是SSDT,而非Shadow。   这个可以请各位自行验证。
2013-12-10 09:37
0
雪    币: 458
活跃值: (306)
能力值: ( LV12,RANK:400 )
在线值:
发帖
回帖
粉丝
17
顶大牛
2013-12-10 10:45
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
18
这个我早就验证过了,不然不会随便说这些~
你确定你切换进程之前不是在System进程里? 要不你切换到csrss看看? 切换到lsass看看? 或者随便哪个你认为没有GUI的看看? 看到底能不能访问?
2013-12-10 11:54
0
雪    币: 225
活跃值: (144)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
19
我以前也在这方面有疑惑,能详细介绍一下Session吗
2013-12-10 12:01
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
20
另外你说的系统取服务表的过程,跟GUI不GUI的只不过是巧合而已吧,因为System和smss这两个Session之外的进程根本不会调用Shadow表里的服务,而其它进程的线程才区分这两种情况,但是那都是在Session内的进程~  另外,我觉得系统完全可以不必要在KTHREAD里区分SSDT和SSDT Shadow,统一换成SSDT Shadow就可以了,反正调用的时候有索引可以判断来使用哪张表~
2013-12-10 12:02
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
21
刚又看了下KiFastCallEntry的代码,证实了我刚才的说法~

一、系统创建线程时,默认Thread->ServiceTable填充的都是KeServiceDescriptorTable,具体可参考KeInitThread函数
二、在KeFastCallEntry中,系统根本不是在判断这个线程是不是GUI线程,它只是判断这个服务的Index是不是超出了SSDT表的范围而已,因为SSDT Shadow的服务项数比SSDT多,所以如果发现服务的Index超出了SSDT表的范围,就认为这是一个SSDT Shadow的调用,然后调用PsConvertToGuiThread把Thread->ServiceTable切换为KeServiceDescriptorTableShadow,另外就是切换一下内核栈,使线程可以使用更大的内核栈空间,就这两个动作~

所以,理论上来讲,如果系统创建线程的时候就把Thread->ServiceTable填充为KeServiceDescriptorTableShadow并且使用更大的内核栈,完全不会有问题,因为GUI线程和非GUI线程需要的条件都满足了~  只不过这样做会消耗更大的内核空间,所以才做了GUI线程和非GUI线程的区分,只给GUI线程以必要的资源,但是对于访问win32k.sys这个,GUI和非GUI并没有不同~~

所以,你首先确认下win32k.sys的访问问题,到底是除smss和System外的所有进程都可以访问,还是只有GUI进程可以访问,这个不难吧?
2013-12-10 12:35
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
22
发现几篇不错的文章,关于Session Space的

http://www.cnblogs.com/kkindof/archive/2012/07/01/2571538.html

http://www.cnblogs.com/kkindof/archive/2012/07/01/2571782.html

http://www.cnblogs.com/kkindof/archive/2012/07/01/2571799.html

http://www.blogbus.com/debug-sai-logs/109178332.html

初始情况下,smss不属于任何session,然后它自己创建了一个Session,然后创建csrss和winlogon继承了该Session,之后加载win32k.sys,最后又调用NtSetSystemInformation从Session中Detach了,而win32k.sys加载的位置是在MmSessionSpace范围内的(32位系统的SessionSpace范围是bc000000到c0000000,这就是为什么win32k.sys的默认基址是bf800000),所以从Session中脱离之后就访问不到SessionSpace范围内的内存了~~

由于SmpStartCsr是在SmpApiLoop中被调用的,所以从理论上分析,smss继续创建一个新的Session的时候(比如另一个用户登录到系统),依然会重复“创建Session”->"启动csrss、winlogon和加载win32k.sys"->“从Session中脱离”这个动作,只不过win32k.sys也是有加载记数的,后面再加载和卸载的时候只会改变记数(这是MmLoadSystemImage内部处理的),从Session中脱离的时候就会把SessionSpace对应的PTE清零,所以访问不到win32k了~

以下是xp的smss.exe中的部分代码:

int __stdcall SmpStartCsr(int a1, int a2, int a3)
{
  signed int v3; // ebx@1
  int v4; // esi@1
  int v5; // ecx@1
  int v6; // eax@1
  int v8; // eax@3
  int v9; // edi@3
  __int16 *v10; // eax@5
  int v11; // eax@7
  CHAR *v12; // [sp-Ch] [bp-34h]@4
  int v13; // [sp-8h] [bp-30h]@4
  char v14; // [sp+8h] [bp-20h]@3
  __int16 v15; // [sp+10h] [bp-18h]@1
  __int16 v16; // [sp+12h] [bp-16h]@1
  int v17; // [sp+14h] [bp-14h]@1
  int v18; // [sp+18h] [bp-10h]@12
  int v19; // [sp+1Ch] [bp-Ch]@3
  int v20; // [sp+20h] [bp-8h]@7
  int v21; // [sp+24h] [bp-4h]@7

  v4 = a1;
  v5 = *(_DWORD *)(a1 + 32);
  v3 = 0;
  v15 = *(_WORD *)(a1 + 36);
  v16 = v15;
  v6 = a1 + 40;
  a1 = v5;
  v17 = v6;
  if ( !v5 )
  {
    *(_DWORD *)(v4 + 300) = SmpWindowsSubSysProcessId;
    *(_DWORD *)(v4 + 296) = SmpInitialCommandProcessId;
    return 0;
  }
  v19 = 0;
 //下面这个函数启动csrss等进程和加载win32k.sys
  [COLOR="Red"]v8 = SmpLoadSubSystemsForMuSession(&a1, (int)&v19, (int)&v14);[/COLOR]
  v9 = v8;
  if ( v8 )
  {
    v13 = v8;
    v12 = "SMSS: SmpStartCsr, SmpLoadSubSystemsForMuSession Failed. Status=%x\n";
  }
  else
  {
    v10 = (__int16 *)&v14;
    if ( v15 )
      v10 = &v15;
    v11 = SmpExecuteInitialCommand(a1, v10, &v21, &v20);
    v9 = v11;
    if ( v11 >= 0 )
    {
      NtClose(v21);
      *(_DWORD *)(v4 + 296) = v20;
      *(_DWORD *)(v4 + 300) = v19;
      *(_DWORD *)(v4 + 32) = a1;
      goto LABEL_11;
    }
    v13 = v11;
    v3 = 1;
    v12 = "SMSS: SmpStartCsr, SmpExecuteInitialCommand Failed. Status=%x\n";
  }
  DbgPrint(v12, v13);
LABEL_11:
  if ( AttachedSessionId != -1 )
  {
    [COLOR="red"]if ( SmpAcquirePrivilege(10, &v18) >= 0 )
    {
      if ( NtSetSystemInformation(48, &AttachedSessionId, 4) >= 0 )
        AttachedSessionId = -1;
      SmpReleasePrivilege(v18);
    }[/COLOR]
  }
  if ( v3 == 1 )
    SmpTerminateCSR(a1);
  return v9;
}

2013-12-10 12:53
0
雪    币: 155
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
你这个方法,至少6年前debugman上就公布了,我记得当时公布了大概有3~4种方法取shadow table。

你这个方法也不是什么大不了的东西,Ida看一下交叉引用3秒内就能想出来的。

另外,代码搜索法也不是不行,按版本换个特征码就可以了,更简单
2013-12-10 13:45
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
首先你说的那个帖子我没有看到过。你可以找出来看看它是怎么讲得?
2013-12-10 15:08
0
雪    币: 101
活跃值: (82)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
25
win8 32不会PG吗?我还以为win7 64之后都不能再用ssdt了。
2013-12-10 15:13
0
游客
登录 | 注册 方可回帖
返回
//