首页
论坛
课程
招聘
[求助]替换ssdt表遇到的问题
2011-12-8 16:03 5597

[求助]替换ssdt表遇到的问题

2011-12-8 16:03
5597
本来想替换ssdt表来达到反ssdt hook 和shadow ssdt的目的。 可是发现测试后发现替换了ssdt表,系统会反映超迟钝,跟假死一样。 我很不明白  就是访问的地址换了一下,为什么会造成这样的结果。下边给出代码。(注意,代码只能在单核电脑上测试,多核复制ssdt表的时候容易切换线程造成数据复制不完整或出错,代码存在很多问题,纯粹是先为了实现)

#define BYTE UCHAR

extern "C" UCHAR* PsGetProcessImageFileName( IN PEPROCESS Process );
extern "C" ULONG KeServiceDescriptorTable;

PULONG pSHADOWSSDT = NULL;
PULONG pSSDT = NULL;
ULONG ulSSDTCount = 0;
ULONG ulSHADOWSSDTCount = 0;
ULONG g_Cr0 = 0;
ULONG ulHookAddr = 0;
ULONG ulRet = 0;
BYTE  bJmpCode[5] = {0xe9,0,0,0,0};
BYTE  bSource[5] = {0x8b,0x3f,0x8b,0x1c,0x87};

#pragma code_seg("PAGE")
__declspec(naked) VOID Filter()
{
        //这个函数比较重要  是替换的关键
        __asm
        {
           pushad
           pushfd
           cmp eax,ulSSDTCount
           jb  SSDTProxy    //先仅仅对ssdt hook 全部屏蔽
           jmp Pass

SSDTProxy:
           popfd
           popad
           mov edi,pSSDT //就是这里,假如是原来的mov edi,[edi] 完全没问题。可是替换为自己的表就“假死”了
           mov ebx,[edi + eax*4]
           jmp [ulRet]
Pass:
           popfd
           popad
           mov edi,[edi]
           mov ebx,[edi + eax*4]
           jmp [ulRet]
        }
}

#pragma code_seg("PAGE")
VOID WPOFF()
{
   __asm
   {
      cli
          push eax
                  mov eax,cr0
                  mov g_Cr0,eax
                  and  eax,not 0x10000
                  mov cr0,eax
                  pop eax
   }
}

#pragma code_seg("PAGE")
VOID WPON()
{
   __asm
   {
      push eax
                  mov eax,g_Cr0
                  mov cr0,eax
                  pop eax
                  sti
   }
}
#pragma code_seg("PAGE")
VOID bingleFunction()
{
   NTSTATUS status;
   ULONG pKeServiceDescriptorTableShadow = 0;
   pSHADOWSSDT = (PULONG)ExAllocatePool(NonPagedPool,0x1000);
   if(pSHADOWSSDT == NULL)
   {
       KdPrint(("分配空间失败了\n"));
           return ;
   }

   //获取keservicedescriptorTableShadow的地址  特征码搜索
   UNICODE_STRING strFuncName;
   ULONG  ulScan = 0;
   RtlInitUnicodeString(&strFuncName,L"KeAddSystemServiceTable");
   ulScan = (ULONG)MmGetSystemRoutineAddress(&strFuncName);

   for(ULONG i=0;i<200;i++)
   {
      if(*(PUSHORT)ulScan== 0x888d && *(PUCHAR)(ulScan+6)== 0x83)
          {
                  pKeServiceDescriptorTableShadow = *(PULONG)(ulScan+2);
                  KdPrint(("找到KeServiceDescriptorTableShadow:0x%x\n",pKeServiceDescriptorTableShadow));
                  break;
          }
      ulScan++;
   }

   //接下来做的是复制ShadowSSDT表的操作了
   PEPROCESS pEprocess = NULL;
   PKAPC_STATE pApcState = (PKAPC_STATE)ExAllocatePool(NonPagedPool,sizeof(KAPC_STATE));
   PsLookupProcessByProcessId((HANDLE)604,&pEprocess);  //挂靠的时csrss.exe
   if(MmIsAddressValid(pEprocess) != TRUE)
   {
     KdPrint(("获取指定的进程失败了\n"));
         return;
   }
   KeStackAttachProcess((PKPROCESS)pEprocess,pApcState);

   PULONG ulTable = (PULONG)*(PULONG)(pKeServiceDescriptorTableShadow+0x10);
   ulSHADOWSSDTCount = (ULONG)*(PULONG)(pKeServiceDescriptorTableShadow+0x18);
   for(ULONG i=0;i<700;i++)
   {
     pSHADOWSSDT [i]= ulTable[i];
   }

   KeUnstackDetachProcess(pApcState);
   ExFreePool(pApcState);
   KdPrint(("pSHADOWSSDT:0x%x\n",pSHADOWSSDT));

   //接下来获取的是SSDT表
   PULONG ulTable1 = (PULONG)*(PULONG)(pKeServiceDescriptorTableShadow);
   ulSSDTCount = (ULONG)*(PULONG)(pKeServiceDescriptorTableShadow + 8);
   pSSDT = (PULONG)ExAllocatePool(NonPagedPool,0x500);
   
   RtlZeroMemory(pSSDT,0x500);
   KIRQL kIrql;
   kIrql = KeRaiseIrqlToDpcLevel();
   for(ULONG i=0;i<300;i++)
   {
      pSSDT[i] = ulTable1[i];
   }
   KeLowerIrql(kIrql);
   KdPrint(("pSSDT:0x%x\n",pSSDT));
   //两张表都复制完了

   //接下来是hook动作了
   
   //首先特征码寻找hook地址
   ULONG ulKiFastCallEntry = 0;
   __asm
   {
      pushad
                  pushfd
                  mov ecx,0x176
                  rdmsr
                  mov ulKiFastCallEntry,eax
                  popfd
                  popad
   }

   KdPrint(("kifastcallentry:0x%x\n",ulKiFastCallEntry));

   //804df7d0 8b3f            mov     edi,dword ptr [edi]
   //804df7d2 8b1c87          mov     ebx,dword ptr [edi+eax*4]

   ulScan = ulKiFastCallEntry;
   for(ULONG i=0;i<300;i++)
   {
      if(*(PULONG)ulScan == 0x1c8b3f8b && *(PUCHAR)(ulScan+4)== 0x87)
          {
                  KdPrint(("找到了,ulHookAddr:0x%x\n",ulScan));
                  break;
          }
      ulScan++;
   }

   ulHookAddr = ulScan;
   ulRet = ulScan+5;

   ULONG ulOffset = (ULONG)Filter - ulHookAddr - 5;
   *(PULONG)&bJmpCode[1] = ulOffset;

   WPOFF();

   RtlCopyMemory((PUCHAR)ulHookAddr,(PUCHAR)bJmpCode,5);

   WPON();
}

#pragma code_seg("PAGE")
VOID bingleUnload(PDRIVER_OBJECT pDriverObject)
{
        ExFreePool(pSSDT);
        ExFreePool(pSHADOWSSDT);

        WPOFF();

        RtlCopyMemory((PUCHAR)ulHookAddr,(PUCHAR)bSource,5);

        WPON();
}

主要问题就是存在于下边的代码中
           __asm
        {
           pushad
           pushfd
           cmp eax,ulSSDTCount
           jb  SSDTProxy    //先仅仅对ssdt hook 全部屏蔽
           jmp Pass

SSDTProxy:
           popfd
           popad
           mov edi,pSSDT //就是这里,假如是原来的mov edi,[edi] 完全没问题。可是替换为自己的表就“假死”了
           mov ebx,[edi + eax*4]
           jmp [ulRet]
Pass:
           popfd
           popad
           mov edi,[edi]
           mov ebx,[edi + eax*4]
           jmp [ulRet]
        }

现象描述: 系统会反映很迟钝,跟假死一样,系统的桌面不能刷新。驱动加载工具能够使用,但反应速度很慢。  非蓝屏。。  找不到原因,不是仅仅替换地址,读取ssdt表中函数的地址,没有涉及到其他的东西呀。。  了解的人给指导一下。。

[注意] 欢迎加入看雪团队!base上海,招聘安全工程师、逆向工程师多个坑位等你投递!

收藏
点赞0
打赏
分享
最新回复 (9)
雪    币: 208
活跃值: 活跃值 (24)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
何健hj 活跃值 2011-12-8 16:33
2
0
你意思是复制一份ssdt表,然后调用的是新的SSDT表中的地址码?
雪    币: 504
活跃值: 活跃值 (837)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
wuaiwu 活跃值 3 2011-12-8 16:58
3
0
是的是的。。  代码中已经将原来的替换掉了呀
雪    币: 727
活跃值: 活跃值 (60)
能力值: ( LV9,RANK:380 )
在线值:
发帖
回帖
粉丝
Winker 活跃值 8 2011-12-8 18:33
4
0
请判断下这个表是 ssdt 还是shadowssdt再替换~~
雪    币: 504
活跃值: 活跃值 (837)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
wuaiwu 活跃值 3 2011-12-8 19:12
5
0
cmp eax,ulSSDTCount
           jb  SSDTProxy    //先仅仅对ssdt hook 全部屏蔽
           jmp Pass
我的判断。。   我现在突然有疑问啦。。

源码是mov edi,[edi]  ,edi的来源是线程的ServiceTable,而ServiceTable 指向的或者是
KeServiceDescriptorTable 或者是KeServiceDescriptorTableShadow表,而
KeServiceDescriptorTableShadow表里边的第一张表就是KeServiceDescriptorTable,这么说edi一定指向的是KeServiceDescriptorTable

我理解你的意思是我的cmp eax,ulSSDTCount不能作为SSDT表判断的依据,那么应该怎么判断呢?
雪    币: 504
活跃值: 活跃值 (837)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
wuaiwu 活跃值 3 2011-12-8 20:38
6
0
问题已经解决了。。  嘿嘿。。  测试通过。。  秒杀所有的ssdt hook 和shadow SSDT hook。 替换两张表都成功了  哇咔咔。。
雪    币: 208
活跃值: 活跃值 (24)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
何健hj 活跃值 2011-12-8 21:08
7
0
我觉得内核重加载 或者 自己实现内核函数来的更直接。。
雪    币: 504
活跃值: 活跃值 (837)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
wuaiwu 活跃值 3 2011-12-8 21:13
8
0
那个是过 inline  hook   我过的是SSDT hook  和Shadow SSDT hook。嘿嘿。。  理论上控制了 kifastcallentry  就能过掉所有的SSDT hook  和Shadow SSDT hook
雪    币: 208
活跃值: 活跃值 (24)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
何健hj 活跃值 2011-12-8 21:52
9
0
你尝试过自己实现SSDT里面函数吗?或者说在SSDT里面的函数调用更深的函数中HOOK马
雪    币: 71
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tyTYtyTYTY 活跃值 2011-12-8 22:37
10
0
mark! 方便上传一份源码
游客
登录 | 注册 方可回帖
返回