在网上看到一段驱动代码.有个地方怎么也没有看得懂...*******************************************************
*标题:【原创】SSDT Hook的妙用-对抗ring0 inline hook   *
*作者:堕落天才                                         *
*日期:2007年3月10号                                    *
*声明:本文章的目的仅为技术交流讨论                     *
*******************************************************
***************************************************************************************************************************
#include<ntddk.h>typedef struct _SERVICE_DESCRIPTOR_TABLE
{
   PVOID    ServiceTableBase;
   PULONG   ServiceCounterTableBase;
   ULONG    NumberOfService;
   ULONG    ParamTableBase;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; //由于KeServiceDescriptorTable只有一项,这里就简单点了
extern PSERVICE_DESCRIPTOR_TABLE     KeServiceDescriptorTable;//KeServiceDescriptorTable为导出函数/////////////////////////////////////
VOID Hook();
VOID Unhook();
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
//////////////////////////////////////
ULONG JmpAddress;//跳转到NtOpenProcess里的地址
ULONG OldServiceAddress;//原来NtOpenProcess的服务地址
//////////////////////////////////////
__declspec(naked) NTSTATUS __stdcall MyNtOpenProcess(PHANDLE ProcessHandle,
                ACCESS_MASK DesiredAccess,
                POBJECT_ATTRIBUTES ObjectAttributes,
                PCLIENT_ID ClientId) 
{    //不懂的地方就在这.定义NtOpenProcess函数的原型之后,下面这段内嵌的汇编是什么意思.他怎么得到的.如果知道的能不能知知有下.如果我想换成NtWriteVirtuaMemory应该如何去做...
   DbgPrint("NtOpenProcess() called");
   __asm{
     push     0C4h
     push     804eb560h   //共十个字节
     jmp      [JmpAddress]     
   }
}
///////////////////////////////////////////////////
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
   DriverObject->DriverUnload = OnUnload;
   DbgPrint("Unhooker load");
   Hook();
   return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
   DbgPrint("Unhooker unload!");
   Unhook();
}
/////////////////////////////////////////////////////
VOID Hook()
{
   ULONG   Address;
   Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;//0x7A为NtOpenProcess服务ID
   DbgPrint("Address:0x%08X",Address);   OldServiceAddress = *(ULONG*)Address;//保存原来NtOpenProcess的地址
   DbgPrint("OldServiceAddress:0x%08X",OldServiceAddress);   DbgPrint("MyNtOpenProcess:0x%08X",MyNtOpenProcess);   JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了
   DbgPrint("JmpAddress:0x%08X",JmpAddress);
    
   __asm{//去掉内存保护
     cli
          mov   eax,cr0
     and   eax,not 10000h
     mov   cr0,eax
   }   *((ULONG*)Address) = (ULONG)MyNtOpenProcess;//HOOK SSDT   __asm{//恢复内存保护  
           mov   eax,cr0
     or    eax,10000h
     mov   cr0,eax
     sti
   }
}
//////////////////////////////////////////////////////
VOID Unhook()
{
   ULONG   Address;
   Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;//查找SSDT   __asm{
     cli
           mov   eax,cr0
     and   eax,not 10000h
     mov   cr0,eax
   }   *((ULONG*)Address) = (ULONG)OldServiceAddress;//还原SSDT   __asm{  
          mov   eax,cr0
     or    eax,10000h
     mov   cr0,eax
     sti
   }   DbgPrint("Unhook");
}
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
  //不懂的地方就在这.定义NtOpenProcess函数的原型之后,下面这段内嵌的汇编是什么意思.他怎么得到的.如果知道的能不能知知有下.如果我想换成NtWriteVirtuaMemory应该如何去做...
   DbgPrint("NtOpenProcess() called");
   __asm{
     push     0C4h
     push     804eb560h   //共十个字节
     jmp      [JmpAddress]     
   }
希望知道的人帮我解释一下.这串东西是怎么计算出来的.不胜感激.如果懂了之后我再加分...谢谢...

解决方案 »

  1.   

    你运行过这个程序吗?按我看,这段代码纯粹是乱写,如果要调用原函数,应该jmp OldServiceAddress。
      

  2.   

    运行是没问题的..
     关键是哪段内嵌汇编我不懂...程序的意思就是自己定义一个NtOpenProcess的原形出来.然后指定一个固定的地址...之后程序自己跳到自己的函数去...
      

  3.   

    刚刚反汇编看了一下XP系统(SP2)的NtOpenProcess函数,入口的前两条执行就是:
    push    0C4h
    push    804eb560h
    刚好10字节,明白了吧。
    这样的代码建议你还是不要看了。
      

  4.   

    哦..似乎明白了...谢谢哈...好像是进入api之后执行完前10个字节之后又跳到一个地方.然后以前的一些东西就被改变而失去效果了.是吧?我不知道我理解得正确不?看了下面这句才免费理解一些... JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了还有谢谢cnzdgs的提醒.只不过不接触一下子真是什么都不懂..呵呵..再次感谢一下回贴的..在放放吧...明后天再结...
      

  5.   

    XP系统(SP2)的NtOpenProcess函数入口处的前两条指令是上面提到的两条push立即数指令,每条指令的代码长度是5字节,两条合起来10字节,JmpAddress = (ULONG)NtOpenProcess + 10就是第3条指令的位置,作者把这两条指令改到了自己的代码中执行,然后再跳转过去从第3条指令开始执行,这样所执行的指令与直接调用NtOpenProcess是一样的。
    估计是作者原本修改了NtOpenProcess入口处的指令(用Detours的方法Hook),后来又改成了Hook SSDT,而这个部分没有跟着一起改。这种做法的兼容性极差,如同直接在代码中写函数地址,软件开发中绝不可取,换个环境可能就蓝屏了。
    另外,Hook内核服务是过时的技术,在64位Vista系统中已经禁止使用,系统会定时检查,一旦发现内核代码或数据被修改,立即蓝屏。
      

  6.   

    我编过类似的代码,但是不是汇编写的(不懂汇编),功能是一样的,都是让程序跳到自己的函数,所以比较之下这两部分的意思是
       __asm{
         cli
               mov   eax,cr0
         and   eax,not 10000h
         mov   cr0,eax
       }
    因为操作系统内存是受保护的,外部进程是不允许修改或者读取其他进程的数据的,因此在你需要提升该块内存的读写权限(这样才能读写这块内存),在修改了读写权限后你就可以修改该地址值让程序跳向你指定的函数地址了,所以这段代码应该时修改内存权限。
    JmpAddress = (ULONG)NtOpenProcess + 10;//此处修改地址让程序跳向你指定的代理函数
       __asm{//恢复内存保护  
               mov   eax,cr0
         or    eax,10000h
         mov   cr0,eax
         sti
       }
    再你修改了值之后应该恢复以前该块内存的访问权限,所以这段代码时恢复该块内存的读写权限。
      

  7.   

    __asm{ 
        push    0C4h 
        push    804eb560h  //共十个字节 

    上面的应该是将参数压入堆栈    jmp      [JmpAddress]    这里跳到函数执行
      } 
      

  8.   

    嗯.谢谢大家了...
      基本上明白了...特别感谢...cnzdgs.Thanks...