首页 网络安全 安全学院 查看内容

Anti SSDT Hook

2009-4-11 10:42 640 0

摘要: 前几天去当面膜拜了女王大牛,果然灰常淫荡呀。。灰常能扯。。这大鸡鸡,还让我等了一个来小时。。。后来和我去买了传说中放片子的硬盘。。 在xp中ntdll.dll的调用都是通过sysenter切换到内核的...
关键词: nbsp dword mov ptr return 函数 edi PMODULES IMAGE KeServiceDescrip

前几天去当面膜拜了女王大牛,果然灰常淫荡呀。。灰常能扯。。这大鸡鸡,还让我等了一个来小时。。。后来和我去买了传说中放片子的硬盘。。 在xp中ntdll.dll的调用都是通过sysenter切换到内核的,sysenter调用了KiFastCallEntry,而KiFastCallEntry函数则是在ssdt表找到相应的函数地址,然后call,所以只要伪造一张原始的ssdt表,并且欺骗过KiFastCallEntry函数,这样ssdt hook就无效了。。。先看KiFastCallEntry函数: 复制内容到剪贴板 代码:nt!KiFastCallEntry:80541790 b923000000      mov     ecx,23h80541795 6a30            push    30h80541797 0fa1            pop     fs80541799 8ed9            mov     ds,cx8054179b 8ec1            mov     es,cx8054179d 648b0d40000000  mov     ecx,dword ptr fs:[40h] 805417a4 8b6104          mov     esp,dword ptr [ecx+4]  805417a7 6a23            push    23h805417a9 52              push    edx  805417aa 9c              pushfd805417ab 6a02            push    2805417ad 83c208          add     edx,8 805417b0 9d              popfd805417b1 804c240102      or      byte ptr [esp+1],2805417b6 6a1b            push    1Bh805417b8 ff350403dfff    push    dword ptr ds:[0FFDF0304h]805417be 6a00            push    0805417c0 55              push    ebp805417c1 53              push    ebx805417c2 56              push    esi805417c3 57              push    edi//ebx=_KPCR.SelfPcr805417c4 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch] 805417cb 6a3b            push    3Bh//esi=_KPCR.PrcbData.CurrentThread805417cd 8bb324010000    mov     esi,dword ptr [ebx+124h]  805417d3 ff33            push    dword ptr [ebx]805417d5 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh   805417db 8b6e18          mov     ebp,dword ptr [esi+18h] 805417de 6a01            push    1805417e0 83ec48          sub     esp,48h805417e3 81ed9c020000    sub     ebp,29Ch805417e9 c6864001000001  mov     byte ptr [esi+140h],1805417f0 3bec            cmp     ebp,esp805417f2 758d            jne     nt!KiFastCallEntry2+0x49 (80541781)805417f4 83652c00        and     dword ptr [ebp+2Ch],0805417f8 f6462cff        test    byte ptr [esi+2Ch],0FFh805417fc 89ae34010000    mov     dword ptr [esi+134h],ebp80541802 0f8538feffff    jne     nt!Dr_FastCallDrSave (80541640)80541808 8b5d60          mov     ebx,dword ptr [ebp+60h]8054180b 8b7d68          mov     edi,dword ptr [ebp+68h]8054180e 89550c          mov     dword ptr [ebp+0Ch],edx80541811 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h80541818 895d00          mov     dword ptr [ebp],ebx8054181b 897d04          mov     dword ptr [ebp+4],edi8054181e fb              sti//eax为函数序号,但是在KeServiceDescriptorTableShadow时是函数序号+1000h,//所以在KeServiceDescriptorTableShadow经过下面运算ecx最终为10h,否则为08054181f 8bf8            mov     edi,eax80541821 c1ef08          shr     edi,880541824 83e730          and     edi,30h80541827 8bcf            mov     ecx,edi//KTHREAD.ServiceTable gdi32.dll和user32.dll调用时,//ServiceTable为KeServiceDescriptorTableShadow,//ntdll.dll调用时ServiceTable为KeServiceDescriptorTable//在KeServiceDescriptorTableShadow时+10正好得到win32.sys调用80541829 03bee0000000    add     edi,dword ptr [esi+0E0h]   8054182f 8bd8            mov     ebx,eax  //保留三个字节,得到正真的序号80541831 25ff0f0000      and     eax,0FFFh//和ssdt或shadow ssdt总共项数比较,eax大则跳80541836 3b4708          cmp     eax,dword ptr [edi+8] 80541839 0f8333fdffff    jae     nt!KiBBTUnexpectedRange (80541572)//判断是shadow ssdt还是ssdt,不跳则是shadow ssdt,跳则是ssdt8054183f 83f910          cmp     ecx,10h 80541842 751b            jne     nt!KiFastCallEntry+0xcf (8054185f)  80541844 648b0d18000000  mov     ecx,dword ptr fs:[18h]8054184b 33db            xor     ebx,ebx8054184d 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]80541853 740a            je      nt!KiFastCallEntry+0xcf (8054185f)80541855 52              push    edx80541856 50              push    eax80541857 ff1528c75580    call    dword ptr [nt!KeGdiFlushUserBatch (8055c728)]8054185d 58              pop     eax8054185e 5a              pop     edx8054185f 64ff0538060000  inc     dword ptr fs:[638h]80541866 8bf2            mov     esi,edx80541868 8b5f0c          mov     ebx,dword ptr [edi+0Ch]8054186b 33c9            xor     ecx,ecx8054186d 8a0c18          mov     cl,byte ptr [eax+ebx]//edi=KeServiceDescriptorTable->ServiceTableBase//在这里patch 把edi指向构造的ssdt80541870 8b3f            mov     edi,dword ptr [edi]  //得到真实地址,edi为KiServiceTable,eax为函数序号  80541872 8b1c87          mov     ebx,dword ptr [edi+eax*4] 80541875 2be1            sub     esp,ecx80541878 c1e902          shr     ecx,28054187a 8bfc            mov     edi,esp8054187c 3b3574f73ff4    cmp     esi,dword ptr ds:[0F43FF774h]80541882 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (80541a30)//把参数复制到内核80541888 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]//调用函数8054188a ffd3            call    ebx8054188c 8be5            mov     esp,ebp8054188e 648b0d24010000  mov     ecx,dword ptr fs:[124h]80541895 8b553c          mov     edx,dword ptr [ebp+3Ch]80541898 899134010000    mov     dword ptr [ecx+134h],edxKiFastCallEntry函数先通过fs寄存器的_KPCR得到了当前线程的ETHREAD,然后通过ETHREAD得到ServiceTable这个就是main SDT或者是shadow sdt,在shadow sdt中要保留24位得到函数序号,之后根据main sdt或者shadow sdt和函数序号得到函数地址,最后call这个函数。所以可以在 复制内容到剪贴板 代码:80541868 8b5f0c          mov     ebx,dword ptr [edi+0Ch]8054186b 33c9            xor     ecx,ecx8054186d 8a0c18          mov     cl,byte ptr [eax+ebx]//edi=KeServiceDescriptorTable->ServiceTableBase//在这里patch 把edi指向构造的ssdt80541870 8b3f            mov     edi,dword ptr [edi]  这里inline hook完整代码如下: 复制内容到剪贴板 代码:#include "kernelfun.h"#include <ntimage.h>#define SEC_IMAGE    0x01000000typedef struct {        WORD    offset:12;        WORD    type:4;} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;DWORD *oldssdt;DWORD patchAddress;DWORD nowSsdt;PVOID lpRet;//得到系统内核模块基址DWORD FoundSystemModule(BOOL bKernel,char *sysFileName){        DWORD    dwNeededSize,rc;        PMODULES    pModules=(PMODULES)&pModules;        PCHAR    pKernelName;        DWORD kernelBase;        DWORD i;        rc=ZwQuerySystemInformation(SystemModuleInformation,pModules,4,&dwNeededSize);        if (rc==STATUS_INFO_LENGTH_MISMATCH)         {                pModules=(MODULES *)ExAllocatePool(PagedPool,dwNeededSize);                rc=ZwQuerySystemInformation(SystemModuleInformation,pModules,dwNeededSize,NULL);                if (!NT_SUCCESS(rc))                {                        DbgPrint("ZwQuerySystemInformation failed");                        return 0;                }        }         else        {                DbgPrint("ZwQuerySystemInformation failed");                return 0;        }        if(bKernel)        {                pKernelName=pModules->smi[0].ModuleNameOffset+pModules->smi[0].ImageName;                strcpy(sysFileName,pKernelName);                kernelBase=(DWORD)pModules->smi[0].Base;                return kernelBase;        }        for (i=0;(pModules->dwNumberOfModules)>i;i++)        {                pKernelName=pModules->smi[i].ModuleNameOffset+pModules->smi[i].ImageName;                if(_stricmp(pKernelName,sysFileName)==0)                {                        kernelBase=(DWORD)pModules->smi[i].Base;                        return kernelBase;                }        }        return 0;}//得到并保存原始的ssdtBOOL SaveOldSddt(PVOID hModule,DWORD dwKSDT,DWORD dwKernelBase){        PDWORD    pService;        DWORD dwKiServiceTable;        IMAGE_DOS_HEADER *dosHeader;        IMAGE_NT_HEADERS *ntHeader;        PIMAGE_BASE_RELOCATION    pbr;        PIMAGE_FIXUP_ENTRY    pfe;          DWORD dwPointer;        DWORD point;        BOOL    bFirstChunk=TRUE;        DWORD i;        dosHeader=(IMAGE_DOS_HEADER*)hModule;        ntHeader=(IMAGE_NT_HEADERS*)((DWORD)hModule+dosHeader->e_lfanew);        pbr=(PIMAGE_BASE_RELOCATION )(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress+(DWORD)hModule);        pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));        while(bFirstChunk||pbr->VirtualAddress)        {                bFirstChunk=FALSE;                for (i=0;((pbr->SizeOfBlock-8)/2)>i;i++)                {                        if(pfe->type==IMAGE_REL_BASED_HIGHLOW)                        {                                dwPointer=pbr->VirtualAddress+pfe->offset;                                point=*(DWORD*)(dwPointer+(DWORD)hModule)-(DWORD)ntHeader->OptionalHeader.ImageBase;                                if(point==dwKSDT)                                {                                        if(*(USHORT*)(dwPointer+(DWORD)hModule-2)==0x05c7)                                        {                                                dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointer+4)-ntHeader->OptionalHeader.ImageBase;                                                i=0;                                                for (pService=(PDWORD)((DWORD)hModule+dwKiServiceTable);                                                        *pService-ntHeader->OptionalHeader.ImageBase<ntHeader->OptionalHeader.ImageBase;                                                        pService++,i++)                                                {                                                        oldssdt[i]=*pService-ntHeader->OptionalHeader.ImageBase+dwKernelBase;                                                }                                        }                                }                        }                        pfe++;                }                pbr=(PIMAGE_BASE_RELOCATION)((DWORD)pbr+pbr->SizeOfBlock);                pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));        }        return TRUE;}//计算mov [rem],rem的[rem]DWORD GetFlag(PVOID lpBase){        IMAGE_DOS_HEADER *dosHeader;        IMAGE_NT_HEADERS *ntHeader;        IMAGE_EXPORT_DIRECTORY* exportTable;        DWORD* pfunctionAddresses;        DWORD* pfunctionNames;        WORD* pfunctionOrdinals;        DWORD functionOrdinal;        DWORD Base, i, functionAddress;        DWORD dwKSDT;        char* functionName;        dosHeader=(IMAGE_DOS_HEADER*)lpBase;        ntHeader=(IMAGE_NT_HEADERS*)((DWORD)lpBase+dosHeader->e_lfanew);        exportTable=(IMAGE_EXPORT_DIRECTORY*)((DWORD)lpBase+ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);        pfunctionAddresses=(DWORD*)((DWORD)lpBase+exportTable->AddressOfFunctions);        pfunctionNames=(DWORD*)((DWORD)lpBase+exportTable->AddressOfNames);        pfunctionOrdinals=(WORD*)((DWORD)lpBase+exportTable->AddressOfNameOrdinals);        Base=exportTable->Base;        for(i=0;i<exportTable->NumberOfFunctions;i++)        {                functionName=(char*)((DWORD)lpBase+pfunctionNames[i]);                functionOrdinal=pfunctionOrdinals[i]+Base-1;                functionAddress = (DWORD)( (DWORD)lpBase + pfunctionAddresses[functionOrdinal]);                if(_stricmp(functionName,"KeServiceDescriptorTable")==0)                {                        dwKSDT=functionAddress-(DWORD)lpBase;                        return dwKSDT;                }        }        return 0;}//映射文件进内存得到ssdt并保存起来BOOL GetOldSsdt(PUNICODE_STRING kernelFileName,DWORD kernelBase) {        NTSTATUS status;        HANDLE  hSection, hFile;        DWORD dwKSDT;        PVOID BaseAddress = NULL;        SIZE_T size=0;        IO_STATUS_BLOCK iosb;        OBJECT_ATTRIBUTES oa = {sizeof oa, 0, kernelFileName, OBJ_CASE_INSENSITIVE};        status=ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);        if(!NT_SUCCESS(status))        {                DbgPrint("ZwOpenFile failed\n");                return FALSE;        }        oa.ObjectName = 0;        status=ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);        if(!NT_SUCCESS(status))        {                DbgPrint("ZwCreateSection failed\n");                return FALSE;        }        status=ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);         if(!NT_SUCCESS(status))        {                DbgPrint("ZwMapViewOfSection failed\n");                return FALSE;        }        ZwClose(hFile);        dwKSDT=GetFlag(BaseAddress);        if(dwKSDT==0)        {                DbgPrint("GetFlag failed\n");                return FALSE;        }        DbgPrint("dwKSDT:%x\n",dwKSDT);        if(!SaveOldSddt(BaseAddress,dwKSDT,kernelBase))        {                DbgPrint("GetOldSddt failed\n");                return FALSE;        }        ZwClose(hSection);        return TRUE;}//构建新的SsdtBOOL SetNewSsdt(){        UNICODE_STRING kernelFileName;        char systemFile[80];        DWORD kernelBase;        int count;        kernelBase=FoundSystemModule(TRUE,systemFile);        if(kernelBase==0)        {                DbgPrint("get kernel base failed\n");                return FALSE;        }         if(_stricmp(systemFile,"ntkrnlpa.exe")==0)        {                RtlInitUnicodeString(&kernelFileName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntkrnlpa.exe");        }        else if(_stricmp(systemFile,"ntoskrnl.exe")==0)        {                RtlInitUnicodeString(&kernelFileName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntoskrnl.exe");        }        else        {                return FALSE;        }        count=KeServiceDescriptorTable->NumberOfServices;        nowSsdt=(DWORD)KeServiceDescriptorTable->ServiceTableBase;        oldssdt=(DWORD*)ExAllocatePool(NonPagedPool,count*4);        if(oldssdt==NULL)        {                DbgPrint("allocate memory failed\n");                return FALSE;        }        KdPrint(("oldssdt:%X\n",oldssdt));        if(!GetOldSsdt(&kernelFileName,kernelBase))        {                DbgPrint("save ssdt failed\n");                return FALSE;        }        return TRUE;}__declspec(naked)void UseOldSsdt(){        _asm        {                pushfd ;                pushad ;                mov  eax,nowSsdt;                cmp eax,[edi];                jnz shadow;//判断是不是shadow ssdt                popad;                popfd;                mov     cl,byte ptr [eax+ebx];                mov     edi,oldssdt;                jmp [lpRet];        shadow:                popad;                popfd;                mov     cl,byte ptr [eax+ebx];                mov     edi,dword ptr [edi];                jmp [lpRet];        }        };BOOL HookKiFastCallEntry(BOOL bHook){        BYTE jmpCode[5]={0xe9,0x00,0x00,0x00,0x00};        BYTE oldCode[5]={0x8a,0x0c,0x18,0x8b,0x3f};        BYTE *functionAddress;        int i;        if(bHook)        {                _asm                {                        pushad;                        mov ecx, 0x176;                        rdmsr;                        mov functionAddress, eax;                        popad;                }                for(i=0;i<264;i++)                {                        if(memcmp(&functionAddress[i],oldCode,5)==0)                        {                                patchAddress=(DWORD)&functionAddress[i];                                KdPrint(("patch address:%X\n",patchAddress));                                break;                        }                }                if(i==264)                        return FALSE;                *(DWORD*)&jmpCode[1]=(DWORD)UseOldSsdt-(patchAddress+5);                lpRet=(PVOID)(patchAddress+5);                _asm                {                        CLI  ;                                         MOV    EAX, CR0  ;                            AND EAX, NOT 10000H ;                        MOV    CR0, EAX;                        }                memcpy((PVOID)patchAddress,jmpCode,5);                _asm                 {                        MOV    EAX, CR0;                                OR    EAX, 10000H;                                    MOV    CR0, EAX ;                                      STI;                                    }        }        else        {                _asm                {                        CLI  ;                                         MOV    EAX, CR0  ;                            AND EAX, NOT 10000H ;                        MOV    CR0, EAX;                        }                memcpy((PVOID)patchAddress,oldCode,5);                _asm                 {                        MOV    EAX, CR0;                                OR    EAX, 10000H;                                    MOV    CR0, EAX ;                                      STI;                                    }        }        return TRUE;}VOID OnUnload( IN PDRIVER_OBJECT DriverObject ){            HookKiFastCallEntry(FALSE);        DbgPrint("ROOTKIT: OnUnload called\n");}NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath ){        theDriverObject->DriverUnload = OnUnload;        if(SetNewSsdt())        {                HookKiFastCallEntry(TRUE);        }                return STATUS_SUCCESS;}假如要anit shadow ssdt hook 只要同时hook KiFastCallEntry和KiSystemService俩函数就可以了。。。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部