恢复2k xp得win32k.sys得KeServiceDescriptorTableShadow

 

/**
* @file sdtreset.cpp
*
* @brief sdtreset.cpp, v 1.0.0 2005/10/25 11:48:42 sunwang
*
* details here.
* 草稿代码,命名混乱,重构时候使用java风格,getKiServiceTableAddrMM
* 其实找到了KeServiceDescriptorTable/Shadow的真实entry地址,直接调用就是了,没有必要去restore,
* restore的好处是禁止这个hooker干坏事如cnnic禁止别人的hooker
*
* @author sunwang <[email protected]>
*/
#include "oshack.h"       //common header
#include "krnlio.h"       //krnl file io
#include "fsdreset.h"      //pe analysis and fsd restore routine

PBYTE getKiServiceTableAddrMM()
{
return KeServiceDescriptorTable[0].ServiceTable;
}

//xp是KeServiceDescriptorTableShadow=KeServiceDescriptorTable-40h
//2k是KeServiceDescriptorTableShadow=KeServiceDescriptorTable+E0h
PBYTE getW32pServiceTableAddrMM()
{
PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTableShadow;

//for xp
if(gKernelVersion==WINXP)
   KeServiceDescriptorTableShadow=(PCHAR)KeServiceDescriptorTable-0x40;
//for 2k
else if(gKernelVersion==WIN2K)
   KeServiceDescriptorTableShadow=(PCHAR)KeServiceDescriptorTable+0xE0;
//noway here now,maybe WIN2K3
else
   return NULL;

return KeServiceDescriptorTableShadow[1].ServiceTable;
}

PBYTE getW32kBaseAddrMM()
{
return MyGetModuleBaseAddress("win32k.sys");
}

PBYTE getKernalBaseAddrMM()
{
return MyGetModuleBaseAddress("ntoskrnl.exe");
}

//xp下win32k并不是长驻内存的,直接用它的内存镜像分析PE有问题
//ntoskrnl.exe是长驻内存的,直接用它的内存镜像分析PE没问题
//问题不是这个,见下面老长的注释,读文件也可以,读内存也可以
//只要不读win32k
/*
Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA
The PAGE_FAULT_IN_NONPAGED_AREA bug check has a value of 0x00000050.
This indicates that invalid system memory has been referenced.
*/
/*
直接读硬盘文件算了,SizeOfHeaders<=0x380,我读个4k出来总可以了吧,4k=0x1000
然后分析头
*/
PBYTE getW32kBaseAddrHD(PBYTE imageRawAddrMM)
{
return GetDriverBaseAddrHD(imageRawAddrMM);
}

PBYTE getKernalBaseAddrHD(PBYTE imageRawAddrMM)
{
return GetDriverBaseAddrHD(imageRawAddrMM);
}

//id = *(导出函数的地址+1)
//内部函数的话,就只能手动填了,如NtUserSetWindowsHookEx,2k:1212,xp:1225
ULONG getServiceEntryAddrReal(ULONG id)
{
char imagePath[256];
int handle;
ULONG rawoffset,value,rva;
PBYTE imageBaseAddrMM,imageBaseAddrHD,serviceTableAddrMM,imageRawAddrMM;

//init
value=0;
RtlZeroMemory(imagePath,256);

//win32k
if((id&0x3fff)>>12 == 1)
{
   DebugPrint(("getAPIAddrReal of win32k/n"));

   //reloc后的baseAddr
   imageBaseAddrMM=getW32kBaseAddrMM();
   DebugPrint(("imageBaseAddrMM:0x%08x/n",imageBaseAddrMM));

   //reloc后的W32pServiceTable
   serviceTableAddrMM=getW32pServiceTableAddrMM(); //va,should change to raw-addr
   DebugPrint(("serviceTableAddrMM:0x%08x/n",serviceTableAddrMM));

   //reloc后的entry的rva,注意不是函数本身的rva
   rva=serviceTableAddrMM+(id&0xfff)*4-imageBaseAddrMM;//rva
   DebugPrint(("rva:0x%08x/n",rva));

   //读取文件头
   //MyGetModuleImageName("win32k.sys",imagePath);
   strcpy(imagePath,gSystemRoot);
   strcat(imagePath,"//system32//win32k.sys");
   DebugPrint(("imagePath:%s/n",imagePath));
   imageRawAddrMM=ExAllocatePool(NonPagedPool,0x1000);
   handle = krnl_open(imagePath,0,KernelMode);
   if(handle)
   {
    DebugPrint(("krnl_open ok/n"));
    krnl_read_offset(handle,imageRawAddrMM,0x1000,0);//va (related to imageBaseAddrHD)
    krnl_close(handle);
   }
   DebugPrint(("imageRawAddrMM:0x%08x/n",imageRawAddrMM));

   //下面遍历所有的section,看rva在哪个section,然后根据section的RVA-VirtualAddress(RVA)+PointerToRawData就
   //得到了rawoffset
   rawoffset=RVA2RawOffset(imageRawAddrMM,rva);
   DebugPrint(("rawoffset:0x%08x/n",rawoffset));

   //读取value,这是reloc前的va
   handle = krnl_open(imagePath,0,KernelMode);
   if(handle)
   {
    DebugPrint(("krnl_open ok/n"));
    krnl_read_offset(handle,&value,4,rawoffset);//va (related to imageBaseAddrHD)
    krnl_close(handle);
   }
   DebugPrint(("value va (related to imageBaseAddrHD):0x%08x/n",value));

   //reloc前的baseAddr
   imageBaseAddrHD=getW32kBaseAddrHD(imageRawAddrMM);
   DebugPrint(("imageBaseAddrHD:0x%08x/n",imageBaseAddrHD));

   //reloc后的地址
   value=value-(ULONG)imageBaseAddrHD;//rva
   DebugPrint(("value rva:0x%08x/n",value));
   value=value+(ULONG)imageBaseAddrMM;//va (relate to iamgeBaseAddrMM)
   DebugPrint(("value va (related to iamgeBaseAddrMM real):0x%08x/n",value));

   //下面这句有问题,直接读了serviceTableAddrMM的entry地址,真他妈妈的要命,why???
   //其实不用读什么硬盘文件,直接使用内存的文件头就是了
   //就是不能引用KeServiceDescriptorTableShadow中win32k的地址,我日
  
   /*
   Hello:

   I have a problem related to the theme you have been speaking of. I hook
   both KeServiceDescriptorTable and KeServiceDescriptorTableShadow because I
   need to monitorize some ntoskrnl and user/gdi services. The driver works
   fine until I tested it in WXP. The problem es that the second entry in
   KeServiceDescriptorTableShadow (that for NtUserxxx services for example)
   has an address (some similar to B79Fxxxx) and when I try to access this
   for patching the shadow service table, I get a Bug Check 0x50:
   PAGE_FAULT_IN_NONPAGED_AREA.

   I have disassembled Mark Russinovich's RegMon and I have tried to map that
   memory through and MDL and then MmBuildMdlForNonPagedPool and
   MmMapLockedPages as he does but I get the same bug check in
   MmBuildMdlForNonPagedPool. Does anybody how to acomplish this task? I have
   not the same problem when I map the index 0 table (NtXxxx services)... it
   works fine.

   Thanks in advance,
   Jose Vicente.
   */

   /*
   Try not mapping it in System process context, or any process context which does
   not use GDI/user interface. I believe the address is part of the session space.
   If you try mapping it in the process context of an app or service which uses
   user32 or gdi calls it works fine. Hope this helps you.
   */

   /*
   Thank you very much, Srin

   The only problem is that I don't know how to do that inside a driver. How
   can I ensure that I'm running within the context of a given application?

   Best regards,
   Jose Vicente.
   */

   /*
   Jose,
   I believe you have a service or app along with the driver in your
   product. When either of these is starting send an IOCTL to your driver and in
   the dispatch routine of this IOCTL do the required. As you are sending the
   IOCTL directly to your driver/device object, in the driver's dispatch routine
   you can be sure that you are executing in the process context which sent you
   the IOCTL.
  
   Have fun,
   Srin.
   */

   /*
   Srin,

   Thank you very much for your answer but I have found an alternative
   solution (in any case actually I haven't a helper application since my
   driver reads the configuration from system registry and that information is
   updated through domain policies). I have exploited the fact that I'm
   monitorizing the process creation/destruction and image loading to hook the
   loading of CSRSS process and thus touching the system services table at that
   moment.

   Best regards,
   Jose Vicente.
   */
   //PsSetCreateProcessNotifyRoutine / PsSetCreateThreadNotifyRoutine / PsSetLoadImageNotifyRoutine
   //并不需要映射,只要在上下文就可以了,奶奶的。
   {
    PCHAR tempEntry=serviceTableAddrMM+(id&0xfff)*4;
    if(MmIsAddressValid(tempEntry))
    {
     DebugPrint(("value va (related to iamgeBaseAddrMM now):0x%08x/n",*(ULONG*)tempEntry));
    }
    //并不需要映射,只要在上下文就可以了,奶奶的。
    else
    {
//     ULONG attachedGDIProcessID=1144;
//     EPROCESS attachedGDIProcess;
     PMDL mdl;
     PCHAR kernelVA;

     DebugPrint(("fuck,a page fault will occur for a read or write operation at a given virtual address"
      ":0x%08x/n",tempEntry));

     //AttachProcess这个方法可以,但是在DriverEntry里面不好测试,faint
/*
     if(NT_SUCCESS(PsLookupProcessByProcessId((PVOID)attachedGDIProcessID,&attachedGDIProcess)))
     {
      KeAttachProcess(&attachedGDIProcess);
      //
      // map
      //

      mdl=IoAllocateMdl(tempEntry,4,0,0,0);
      if(mdl)
      {
       DebugPrint(("IoAllocateMdl ok/n"));
       MmBuildMdlForNonPagedPool(mdl);
       kernelVA=MmMapLockedPages(mdl,KernelMode);
       if(kernelVA)
       {
        if(MmIsAddressValid(kernelVA))
        {
         DebugPrint(("value va (related to iamgeBaseAddrMM now):0x%08x/n",*(ULONG*)kernelVA));
        }
        else
        {
         DebugPrint(("fuck,a page fault will occur for a read or write operation at a given virtual address"
         ":0x%08x/n",kernelVA));
        }
        MmUnmapLockedPages(kernelVA,mdl);
       }
      }

      KeDetachProcess();
     }
*/
     //procmon,希望能成,测试成功.
     mdl=IoAllocateMdl(tempEntry,4,0,0,0);
     if(mdl)
     {
      DebugPrint(("IoAllocateMdl ok/n"));
      //如果不是gdi进程空间,一样死,fuck
      MmBuildMdlForNonPagedPool(mdl);
      kernelVA=MmMapLockedPages(mdl,KernelMode);
      if(kernelVA)
      {
       if(MmIsAddressValid(kernelVA))
       {
        DebugPrint(("value va (related to iamgeBaseAddrMM now):0x%08x/n",*(ULONG*)kernelVA));
       }
       else
       {
        DebugPrint(("fuck,a page fault will occur for a read or write operation at a given virtual address"
         ":0x%08x/n",kernelVA));
       }
       MmUnmapLockedPages(kernelVA,mdl);
      }
     }
    }
   }

   ExFreePool(imageRawAddrMM);
}
//ntoskrnl
else if((id&0x3fff)>>12 == 0)
{
   DebugPrint(("getAPIAddrReal of ntoskrnl/n"));

   //reloc后的baseAddr
   imageBaseAddrMM=getKernalBaseAddrMM();
   DebugPrint(("imageBaseAddrMM:0x%08x/n",imageBaseAddrMM));

   //reloc后的W32pServiceTable
   serviceTableAddrMM=getKiServiceTableAddrMM(); //va,should change to raw-addr
   DebugPrint(("serviceTableAddrMM:0x%08x/n",serviceTableAddrMM));

   //reloc后的entry的rva,注意不是函数本身的rva
   rva=serviceTableAddrMM+(id&0xfff)*4-imageBaseAddrMM;//rva
   DebugPrint(("rva:0x%08x/n",rva));

   //读取文件头
   strcpy(imagePath,gSystemRoot);
   strcat(imagePath,"//system32//ntoskrnl.exe");
   DebugPrint(("imagePath:%s/n",imagePath));
   imageRawAddrMM=ExAllocatePool(NonPagedPool,0x1000);
   handle = krnl_open(imagePath,0,KernelMode);
   if(handle)
   {
    DebugPrint(("krnl_open ok/n"));
    krnl_read_offset(handle,imageRawAddrMM,0x1000,0);//va (related to imageBaseAddrHD)
    krnl_close(handle);
   }
   DebugPrint(("imageRawAddrMM:0x%08x/n",imageRawAddrMM));

   //下面遍历所有的section,看rva在哪个section,然后根据section的RVA-VirtualAddress(RVA)+PointerToRawData就
   //得到了rawoffset
   rawoffset=RVA2RawOffset(imageRawAddrMM,rva);
   DebugPrint(("rawoffset:0x%08x/n",rawoffset));

   //读取value,这是reloc前的va
   handle = krnl_open(imagePath,0,KernelMode);
   if(handle)
   {
    DebugPrint(("krnl_open ok/n"));
    krnl_read_offset(handle,&value,4,rawoffset);//va (related to imageBaseAddrHD)
    krnl_close(handle);
   }
   DebugPrint(("value va (related to imageBaseAddrHD):0x%08x/n",value));

   //reloc前的baseAddr
   imageBaseAddrHD=getKernalBaseAddrHD(imageRawAddrMM);
   DebugPrint(("imageBaseAddrHD:0x%08x/n",imageBaseAddrHD));

   //reloc后的地址
   value=value-(ULONG)imageBaseAddrHD;//rva
   DebugPrint(("value rva:0x%08x/n",value));
   value=value+(ULONG)imageBaseAddrMM;//va (relate to iamgeBaseAddrMM)
   DebugPrint(("value va (related to iamgeBaseAddrMM real):0x%08x/n",value));
   //下面这句有问题,直接读了serviceTableAddrMM的entry地址,真他妈妈的要命,why???
   //其实不用读什么硬盘文件,直接使用内存的文件头就是了
   //就是不能引用KeServiceDescriptorTableShadow中win32k的地址,我日
   {
    PCHAR tempEntry=serviceTableAddrMM+(id&0xfff)*4;
    if(MmIsAddressValid(tempEntry))
    {
     DebugPrint(("value va (related to iamgeBaseAddrMM now):0x%08x/n",*(ULONG*)tempEntry));
    }
    else
    {
     DebugPrint(("fuck,a page fault will occur for a read or write operation at a given virtual address"
      ":%0x%08x/n",tempEntry));
    }
   }

   ExFreePool(imageRawAddrMM);
}

return value;
}

你可能感兴趣的:(恢复2k xp得win32k.sys得KeServiceDescriptorTableShadow)