免費論壇 繁體 | 簡體
Sclub交友聊天~加入聊天室當版主
分享
返回列表 发帖

Shadow SSDT

A、Shadow SSDT表基址定位
   B、Shadow SSDT表结构
   C、Shadow SSDT HOOK
课时:45

KeServiceDescriptorTable //系统描述符表 extern
KeServiceDescriptorTableShadow //影子系统描述符表  win32k.sys
bp win32k!NtUserPostMessage
bp win32k!NtUserShowWindow
bp win32k!NtUserFindWindow
bp win32k!NtUserDestroyWindow

bp win32k!NtUserPostMessage
Shadow SSDT表基址定位
系统只提供了KeServiceDescriptorTable导出
KeServiceDescriptorTableShadow是个未导出结构
dd poi(KeServiceDescriptorTable-0x40+0x10)  //XP

RtlGetVersion
PsGetVersion
Windows 2000:      dwMajorVersion = 5 dwMinorVersion = 0
Windows XP:        dwMajorVersion = 5 dwMinorVersion = 1
Windows 2003:      dwMajorVersion = 5 dwMinorVersion = 1
Windows Vista:      dwMajorVersion = 6

Operating system        Version number        dwMajorVersion        dwMinorVersion        Other
Windows 7        6.1        6        1        OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2008 R2        6.1        6        1        OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows Server 2008        6.0        6        0        OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows Vista        6.0        6        0        OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2003 R2        5.2        5        2        GetSystemMetrics(SM_SERVERR2) != 0
Windows Home Server        5.2        5        2        OSVERSIONINFOEX.wSuiteMask & VER_SUITE_WH_SERVER
Windows Server 2003        5.2        5        2        GetSystemMetrics(SM_SERVERR2) == 0
Windows XP Professional x64 Edition        5.2        5        2        (OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION) && (SYSTEM_INFO.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
Windows XP        5.1        5        1        Not applicable
Windows 2000        5.0        5        0        Not applicable


DWORD Get_KeServiceDescriptorTableShadow_Addr()
{   DWORD KeServiceDescriptorTableShadow=0;
        DWORD Version=GetVersion();
        switch (Version  )
        {
        case VERSION_2K:
                          KeServiceDescriptorTableShadow=(DWORD)KeServiceDescriptorTable+0xE0;
                    break;
                case VERSION_2K3:
                    break;
                case VERSION_XP:
                          KeServiceDescriptorTableShadow=(DWORD)KeServiceDescriptorTable-0x40;
                    break;
                default:
                        break;
                 
        }
        return KeServiceDescriptorTableShadow;

}

dd poi(KeServiceDescriptorTableShadow+10) ///SSDT Shadow Base

NtUserDestroyWindow  //ZwTerminateProcess
NtUserFindWindowEx
NtUserSetWindowLong
NtUserPostMessage
NtUserGetForegroundWindow

#define VERSION_2K          50

#define VERSION_XP          51

#define VERSION_2K3         52
#define VERSION_XP64        52
#define VERSION_2K3_R2      52

#define VERSION_VISTA       60
#define VERSION_SERVER2008  60

#define VERSION_WIN7            61
#define VERSION_SERVER2008_R2   61
#pragma PAGECODE
DWORD GetVersion()
{  ULONG rtn=0;
        ULONG MajorVersion,MinorVersion,BuildNumber;
        PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);//系统版本.参数1主版本,参数2副版本,参数3时间序号,参数4字串
        rtn=MajorVersion;
        rtn=rtn *10;                                       
        rtn+=MinorVersion;                        //主版本+副版本
        return rtn;
}

#pragma PAGECODE
DWORD Get_KeServiceDescriptorTableShadow_Addr()
{   DWORD KeServiceDescriptorTableShadow=0;
        DWORD Version=GetVersion();
        switch (Version  )
        {
        case VERSION_2K:
                          KeServiceDescriptorTableShadow=(DWORD)KeServiceDescriptorTable+0xE0;
                    break;
                case VERSION_2K3:
                    break;
                case VERSION_XP:
                          KeServiceDescriptorTableShadow=(DWORD)KeServiceDescriptorTable-0x40;//XP系统的影子描述表是-0X40
                    break;
                default:
                        break;
                 
        }
        return KeServiceDescriptorTableShadow;

}
#pragma PAGECODE
VOID Show_SSDTShadowList()
{
        KdPrint(("Entry  Show_SSDTShadowList \n"));
         
        DWORD TableBase=Get_KeServiceDescriptorTableShadow_Addr();
        TableBase=TableBase+0x10;                                        //取表基址
        DWORD TableCount=TableBase+8;                        //偏移8是数量
        DWORD count=*((PDWORD)TableCount);        //读出数量
        KdPrint(("SSDT_Shadow Base=%x Count=%x\n",TableBase,count));
        //__asm  int 3
    PDWORD CFun_Addr=PDWORD(TableBase);
        CFun_Addr=PDWORD(*CFun_Addr);
        for (DWORD i=0;i<count;i++)                                //以数量遍历出列表
        {   
                 KdPrint(("\n %d=%x\n",i,*CFun_Addr ));
                CFun_Addr++;
                //__asm int 3
                 
        }
         
}
HWND myh;
typedef BOOL (__stdcall *PNtUserDestroyWindow)(HWND hwnd);
//定义原有和当前地址
PNtUserDestroyWindow Old_NtUserDestroyWindow,Cur_NtUserDestroyWindow;
#pragma PAGECODE
BOOL __stdcall My_NtUserDestroyWindow(HWND h)        //造假函数
{
        KdPrint(("h=%x \n",h));
        if (h==myh)
        {
                KdPrint(("被保护窗口h=%x \n",h));                                        //准备HOOK
                return FALSE;
        }else        return Old_NtUserDestroyWindow(h);                        //放过保护
}


#pragma PAGECODE
VOID SSDT_HOOK_NtUserDestroyWindow() //355
{ KdPrint(("Entry  Show_SSDTShadowList \n"));

DWORD TableBase=Get_KeServiceDescriptorTableShadow_Addr();
TableBase=TableBase+0x10;                                                //列表基址
DWORD TableCount=TableBase+8;                                //函数数量


DWORD count=*((PDWORD)TableCount);
KdPrint(("SSDT_Shadow Base=%x Count=%x\n",TableBase,count));
//__asm  int 3
PDWORD CFun_Addr=PDWORD(TableBase);
CFun_Addr=PDWORD(*CFun_Addr);                        //列表首
CFun_Addr+=355;                                                                //要HOOK地址
Old_NtUserDestroyWindow=(PNtUserDestroyWindow)(*CFun_Addr);//保存
KdPrint(("\n NtUserDestroyWindow当前地址=%x,%x \n",CFun_Addr,*CFun_Addr));
__asm //去掉页面保护
{
        cli
                mov eax,cr0
                and eax,not 10000h //and eax,0FFFEFFFFh
                mov cr0,eax

}

*CFun_Addr=(DWORD)(&My_NtUserDestroyWindow);                //指向HOOK地址
KdPrint(("\n NtUserDestroyWindow HOOK后地址=%x,%x \n",CFun_Addr,*CFun_Addr));

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

}



#pragma PAGECODE
VOID SSDT_UNHOOK_NtUserDestroyWindow() //还原HOOK
{
        KdPrint(("Entry  Show_SSDTShadowList \n"));

DWORD TableBase=Get_KeServiceDescriptorTableShadow_Addr();
TableBase=TableBase+0x10;
DWORD TableCount=TableBase+8;


DWORD count=*((PDWORD)TableCount);
KdPrint(("SSDT_Shadow Base=%x Count=%x\n",TableBase,count));
//__asm  int 3
PDWORD CFun_Addr=PDWORD(TableBase);
CFun_Addr=PDWORD(*CFun_Addr);
CFun_Addr+=355;                //NtUserDestroyWindow偏移,DWORD每加为4
*CFun_Addr=(DWORD)(Old_NtUserDestroyWindow);
}


===========================================

笔记:
本节课又是基础理论课.先打开虚拟机,在WINDBG里看一下系统描述符表和影子描述表(教案),这两个表的前面一行都是相同的,第二行不同,我们通过第一行当作特征码来查找第二行;我们还有另外一个简单的办法,一般来讲在同一个操作系统中这两个表之间的偏移大小是相同的,所以直接计算即可,比如这里就是0X40大小.那么我们怎么查找里面数据呢?在WINDBG下输入命令
Dd poi(KeServiceDescriptorTable-0x40+0x10)
但是全是????  我们必须通过下断bp win32k!NtUserPostMessage
,再重新载入符号,输入命令.reload ,断下来之后再用命令显示一下列表就出来了,这样就取出了影子表.
以28课代码为例,加入已经写好代码函数来遍历整个表,因为必须要在GUI里查找,所以必须要在EXE中进行传递参数.打开Kernel Detective查看一下列表.

将已写好的代码解释之后,讲到影子表是不能直接访问的,是属于system进程,而我们之所以能查出是在不同的EXE进程中访问的.写好代码后在虚拟机里进行测试,然后就遍历出了所有函数列表,对比一下667个函数全部正确.读取地址已经正确了,那么我们对其进行替换,这就是SSDT HOOK了,比如我们HOOK一下NtUserDestroyWindow函数,也就是索引号355.

老师又将代码进行详解.在SYS中与EXE进行连接,通过查找窗口传递进程ID在SYS中的myh进行保护,禁止关闭窗口.而当我们关闭EXE的时候则将保护卸载掉.在虚拟机中测试一下,记事本果然关不掉了,而当我们关掉自己的EXE时则记事本可以正确的关闭掉了,当然如果强行关闭也是可以的,因为那是另外一个函数.

这两个系统描述表一个是可以导出的,另一个是不可以导出的.

返回列表