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

Anti SSDT Hook

2009-6-27 11:23 491 0

摘要:   在xp中ntdll.dll的调用都是通过sysenter切换到内核的,sysenter调用了KiFastCallEntry,而KiFastCallEntry函数则是在ssdt表找到相应的  函数地...
关键词: 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,23h  80541795 6a30            push    30h  80541797 0fa1            pop     fs  80541799 8ed9            mov     ds,cx  8054179b 8ec1            mov     es,cx  8054179d 648b0d40000000  mov     ecx,dword ptr fs:[40h]  805417a4 8b6104          mov     esp,dword ptr [ecx+4]  805417a7 6a23            push    23h  805417a9 52              push    edx  805417aa 9c              pushfd  805417ab 6a02            push    2  805417ad 83c208          add     edx,8  805417b0 9d              popfd  805417b1 804c240102      or      byte ptr [esp+1],2  805417b6 6a1b            push    1Bh  805417b8 ff350403dfff    push    dword ptr ds:[0FFDF0304h]  805417be 6a00            push    0  805417c0 55              push    ebp  805417c1 53              push    ebx  805417c2 56              push    esi  805417c3 57              push    edi  //ebx=_KPCR.SelfPcr  805417c4 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]  805417cb 6a3b            push    3Bh  //esi=_KPCR.PrcbData.CurrentThread  805417cd 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    1  805417e0 83ec48          sub     esp,48h  805417e3 81ed9c020000    sub     ebp,29Ch  805417e9 c6864001000001  mov     byte ptr [esi+140h],1  805417f0 3bec            cmp     ebp,esp  805417f2 758d            jne     nt!KiFastCallEntry2+0x49 (80541781)  805417f4 83652c00        and     dword ptr [ebp+2Ch],0  805417f8 f6462cff        test    byte ptr [esi+2Ch],0FFh  805417fc 89ae34010000    mov     dword ptr [esi+134h],ebp  80541802 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],edx  80541811 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h  80541818 895d00          mov     dword ptr [ebp],ebx  8054181b 897d04          mov     dword ptr [ebp+4],edi  8054181e fb              sti  //eax为函数序号,但是在KeServiceDescriptorTableShadow时是函数序号+1000h,  //所以在KeServiceDescriptorTableShadow经过下面运算ecx最终为10h,否则为0  8054181f 8bf8            mov     edi,eax  80541821 c1ef08          shr     edi,8  80541824 83e730          and     edi,30h  80541827 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,跳则是ssdt  8054183f 83f910          cmp     ecx,10h  80541842 751b            jne     nt!KiFastCallEntry+0xcf (8054185f)  80541844 648b0d18000000  mov     ecx,dword ptr fs:[18h]  8054184b 33db            xor     ebx,ebx  8054184d 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]  80541853 740a            je      nt!KiFastCallEntry+0xcf (8054185f)  80541855 52              push    edx  80541856 50              push    eax  80541857 ff1528c75580    call    dword ptr [nt!KeGdiFlushUserBatch (8055c728)]  8054185d 58              pop     eax  8054185e 5a              pop     edx  8054185f 64ff0538060000  inc     dword ptr fs:[638h]  80541866 8bf2            mov     esi,edx  80541868 8b5f0c          mov     ebx,dword ptr [edi+0Ch]  8054186b 33c9            xor     ecx,ecx  8054186d 8a0c18          mov     cl,byte ptr [eax+ebx]  //edi=KeServiceDescriptorTable->ServiceTableBase  //在这里patch 把edi指向构造的ssdt  80541870 8b3f            mov     edi,dword ptr [edi]  //得到真实地址,edi为KiServiceTable,eax为函数序号  80541872 8b1c87          mov     ebx,dword ptr [edi+eax*4]  80541875 2be1            sub     esp,ecx  80541878 c1e902          shr     ecx,2  8054187a 8bfc            mov     edi,esp  8054187c 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    ebx  8054188c 8be5            mov     esp,ebp  8054188e 648b0d24010000  mov     ecx,dword ptr fs:[124h]  80541895 8b553c          mov     edx,dword ptr [ebp+3Ch]  80541898 899134010000    mov     dword ptr [ecx+134h],edx  KiFastCallEntry函数先通过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,ecx  8054186d 8a0c18          mov     cl,byte ptr [eax+ebx]  //edi=KeServiceDescriptorTable->ServiceTableBase  //在这里patch 把edi指向构造的ssdt  80541870 8b3f            mov     edi,dword ptr [edi]  这里inline hook  完整代码如下:  代码:  #include "kernelfun.h"  #include <ntimage.h>  #define SEC_IMAGE    0x01000000  typedef 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;  }  //得到并保存原始的ssdt  BOOL 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;  }  //构建新的Ssdt  BOOL 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俩函数就可以了。。。  又度过了一个没有情人的情人节了。。。。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部