安全中国首页 > 文章中心 > 黑客编程
 
安全中国网友投稿专用上传FTP空间:
Ftp服务器:download.anqn.com
Ftp端口:21
用户名:anqn
密 码:anqn.com
 

简析利用调试寄存器实现内核函数的HOOK

更新时间:2008-3-6 1:17:38
责任编辑:阿loosen
热 点:


void PrintHook()
{
  DbgPrint(" Now Get In ZwCreateFile Hook: %d...Pid: %d...\n", g_HookNumber++, (DWORD)PsGetCurrentProcessId());
}

__declspec(naked) void NewZwCreateFile()
{
  __asm
  {   
    pushfd;                 // 仅仅适合于 XP 操作系统
    call PrintHook;
    popfd;
    mov eax,0x25;         
    jmp g_OldCreateFile;
  }
}

void SetHB()         // set hardware breakpoint 设置硬件断点
{
  __asm
  {
    mov eax, ZwCreateFile;     // 想要挂接的函数或者地址
    mov dr0, eax;
    mov eax, dr7;
    or eax, 0x2703;         // 也要修改 dr7:GD 位,以免DrX被操作系统或其他程序修改
    and eax, 0xfff0ffff;
    mov dr7, eax;
  }
}

__declspec(naked) void NewDBEntry()
{
  __asm
  {
    pushfd;
    push eax;

    mov eax, dr6;
    test eax, 0x2000;
    jz NOT_EDIT_DRX;

    // 以下是如果有对DRX的操作的简单处理,如有需要可以修改
    // 我只是简单的跳过这些指令
    and eax, 0xFFFFDFFF;
    mov dr6, eax;         // 清除DR6的标志

    cmp g_bExit, 0;
    jnz MY_DRV_EXIT;     // 驱动 Unload

    mov eax, [esp+8];     // 获取堆栈中的 EIP
    add eax, 3;           // 由于所有对 DRX 的操作全都是3个字节的
    mov [esp+8], eax;     // 修改 EIP ,跳过当前指令,返回时执行下条指令

    jmp MY_INT_END;

NOT_EDIT_DRX:

    mov eax, dr6;
    test eax, 0x1;
    jz SYS_INT;         // 如果不是Dr0 产生的中断,则跳回原系统中断

    mov eax, [esp+8];
    cmp eax, ZwCreateFile;   // 判断一下是不是 ZwCreateFile 的线性地址
    jnz SYS_INT;

    mov eax, NewZwCreateFile;
    mov [esp+8],eax;     // 修改堆栈中的 EIP ,实现返回时跳转


MY_INT_END:   

    mov eax, dr7;
    or eax, 0x2000;     // 恢复 GD 位
    mov dr7, eax;

MY_DRV_EXIT:             // 整个驱动 UnLoad 时,不恢复 Dr7

    pop eax;
    popfd;
    iretd;

SYS_INT:
    pop eax;
    popfd;
    jmp g_OldDBEntry;
    
  }
}

DWORD GetDBEntry()
{
  PIDTENTRY IdtEntry;
  DWORD Entry;

  __asm sidt g_IDTR;

  IdtEntry = (PIDTENTRY)(g_IDTR.IDTBase + 8);

  Entry = IdtEntry->HiOffset << 16;
  
  Entry |= IdtEntry->LowOffset;

  return Entry; 
}

void HookDBInt()
{
  DWORD NewEntry;
  PIDTENTRY IdtEntry;

  NewEntry = (DWORD)NewDBEntry;

  g_OldCreateFile = (DWORD)ZwCreateFile + 5;     // 新的要跳转过去的地址

  g_OldDBEntry = GetDBEntry();

  IdtEntry = (PIDTENTRY)(g_IDTR.IDTBase + 8);

  CliAndDisableWPBit();

  IdtEntry->LowOffset = (USHORT)NewEntry;

  IdtEntry->HiOffset = (USHORT)( NewEntry >> 16 );

  ReLoadCR0AndSti();

  SetHB();

  g_bExit = FALSE;

  return;
}

void UnHookDBInt()
{
  PIDTENTRY IdtEntry;
  DWORD Entry;
  
  __asm sidt g_IDTR;
  
  IdtEntry = (PIDTENTRY)(g_IDTR.IDTBase + 8);

  CliAndDisableWPBit();

  g_bExit = TRUE;

  __asm mov eax, dr7;           // 产生一次例外并且清除Dr7:GD

  if ( g_OldDBEntry != 0 )
  {
    IdtEntry->LowOffset = (USHORT)g_OldDBEntry;
    
    IdtEntry->HiOffset = (USHORT)( g_OldDBEntry >> 16 );     
  }

  ReLoadCR0AndSti();
  
  DbgPrint(" UnLoad drx hook..\n");

  return;
}

NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject)
{   
  UnHookDBInt();
  
  return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(
              IN PDRIVER_OBJECT DriverObject,
              IN PUNICODE_STRING RegistryPath
              )
{
  HookDBInt();
  
  DriverObject->DriverUnload = DriverUnload;

  DbgPrint("Load drxhook Driver Ok...\n");

  return STATUS_SUCCESS;
}
/***********************/

以上代码实现了简单的ZwCreateFile 函数的HOOK,可以拿DbgView查看效果.

由于本人水平有限,代码中难免有错误出现,希望指正.
同时也希望各位牛人来指点,yykingking@126.com




/**************下面是罗嗦几句********************/
1.这个方法呢首先不怎么实用,因为你用了调试寄存器后某些壳也想用,因此就冲突了,可能会使某些东西失效,不如传统的HOOK好用(据说利用缺页中断HOOK也比较好用,没试过)。还有人认为呢这个HOOK虽然是HOOK成功了,但是还得HOOK中断向量,没有必要。其实呢,只是多了种思路罢了,多给大家提供一些想法而已。
2.其次呢,这个方法是我在调试某ARK时想到的,这个ARK的作者说他们会恢复函数的inline hook然后才去调用(大面积的恢复,甚至是整个文件的恢复),于是我就用调试器在该函数上下断点,结果自然是没有断下了,因为下的 (0xcc)断点被恢复了。于是就索性下了个硬件断点,这下就断住了,然后呢就想到了拿这个东西来HOOK。然后就去网上搜资料,发现不少人还是稍微提到过这个方法的,包括 vxk,xikug,都说过。 

上一页 1 2 

 
相关文章
一日一文章
 
一日一软件
一日一动画