驱动反调试----点softice死穴
       为表达对看雪论坛的支持,特把这两天研究驱动的一点心得变成文字,以作留念。实事求是地讲,这是我写得第一个驱动,希望大家喜欢。
     作为一个驱动菜鸟,首先恶补了一些驱动理论,像《Windows驱动开发技术详解》、《软件调试》、《从汇编语言到windows内核编程》等电子书网上都能下到。看书就要看好书,我可不想一上来就被误导,当然书上的东西我们还是不能全信。
     其次初步熟悉了驱动开发环境和各种调试工具的使用,windbg、softice我是都装电脑里了,就差熟练使用了。编译驱动,我是一键编译(ddk),当然只有懒人才想得出来。在论坛上我写过一篇相关文章,如果感兴趣的话,可以找出来看看。用vc++6.0编译也很简单,照《Windows驱动开发技术详解》一书里设置一下编译、调试选项即可,根本不需要装什么乱七八糟的软件。再用个能显示行号的记事本编辑源文件就ok了,有行号便于由编译出错信息中提示的行号定位源文件中出错的地方。用windbg的open crash dump菜单看看蓝屏后的系统生成的*.dmp文件也可以快速找到错误(默认不保存*.dmp文件,当然你要在windows里先设置一下)。
    
     

     废话这么多,下面讲点softice死穴。在调试驱动过程中,我发现了softice的一个敏感穴位,在这里我就不保密了。Softice对键盘中断进行了hook,见图hook,jpg,先push中断服务的真正入口,然后jmp到 softice的处理代码。在处理的开始先读取60端口的scan code
而后保存到某处。这里就是关键,如果这里不保存,那么将不会回显键盘输入的字符,其效果就是键盘无法输入。这样就可以被我们用来反调试,当我们的内核代码检测到softice后就把该处替换成垃圾指令,那么键盘就不起作用了,当然就无法继续调试。原理很简单,具体实现如下:
   
     
  
#include "ntddk.h"
#include <stdio.h>
#define MAKELONG(a, b) ((unsigned long) (((unsigned short) (a)) | ((unsigned long) ((unsigned short) (b))) << 16)) 
int  kb_int = 0;
#pragma pack(1)
typedef struct
{
  unsigned short LowOffset;
  unsigned short selector;
  unsigned char unused_lo;
  unsigned char segment_type:4;   
  unsigned char system_segment_flag:1;
  unsigned char DPL:2;   
  unsigned char P:1; 
  unsigned short HiOffset;
} IDTENTRY;

typedef struct
{
  unsigned short IDTLimit;
  unsigned short LowIDTbase;
  unsigned short HiIDTbase;
} IDTINFO;

typedef struct
{
  unsigned char  E9_BYTE;
  unsigned long  JMP_ADDR;
} MYPATCH;

#pragma pack()
unsigned long ISR_pointer,tt;  
unsigned char ss,Sice_Protected;
MYPATCH*   k;

int irq1_svcnumber()
{
  unsigned char *pIoRegSel;
  unsigned char *pIoWin;
  unsigned char ch;
  PHYSICAL_ADDRESS  phys;
  PVOID        pAddr;
  phys.u.LowPart = 0xFEC00000;  
  pAddr = MmMapIoSpace(phys, 0x14, MmNonCached);//读0x14字节即可,最后一个dword就是I/O WINDOW REGISTER
  if (pAddr == NULL)
    return 0;
  pIoRegSel = (unsigned char *)pAddr;
  pIoWin = (unsigned char *)(pAddr) + 0x10;

  *pIoRegSel = 0x12;   
  ch = *pIoWin;
  MmUnmapIoSpace(pAddr, 0x14);
  return (int)ch;
}
/*
The PIIX3 decodes the 82093AA(IOAPIC) in memory space.
Memory Address: FEC0xy00h (xy=See APICBASE Register in the PIIX3)
Typically, IOREGSEL Register is at 00h and IOWIN Register is at 10h.
interl 82093AA has 24 I/O Redirection Table entry registers.  IOREDTBL[0]-IOREDTBL[23]
Each register is a dedicated entry for each interrupt input.
IOREDTBL[1] is the entry for keyboard interrupt (IRQ1), which address offset is 12-13h. 
Here IOWIN Register is used to read vector from the IOAPIC register(IOREDTBL[1])
specified by 0x12 which was written to the IOREGSEL Register.
Redirection table entries的低8位就是vector
*/
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{          
   if (Sice_Protected==1) { 
       __asm  cli
       k->E9_BYTE=ss;
       k->JMP_ADDR=tt;
       __asm sti
      DbgPrint("Anti_Softice end.");   
   };
      DbgPrint("Welcome! by 天易love 2010-1-10");  
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
  IDTINFO    idt_info;     
  IDTENTRY*  idt_entries;   
  unsigned long   addr;
  unsigned long* addr1;  
  unsigned char*  ch;
  
  Sice_Protected=0;
   
  theDriverObject->DriverUnload  = OnUnload; 
  kb_int = irq1_svcnumber();
  DbgPrint("kb_int = 0x%02X\n", kb_int);
  
  __asm  sidt  idt_info
  idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);
  ISR_pointer = MAKELONG(idt_entries[kb_int].LowOffset,idt_entries[kb_int].HiOffset);

    ch=(unsigned  char*)(ISR_pointer);  //68 表示push指令
    if (*ch!=0x68) {                       //判断是否运行softice 有无hook
      DbgPrint("There is no Softice.");
      return STATUS_SUCCESS;
     }
      addr1=(unsigned  long*)(ISR_pointer+6);
      
        __asm{              //定位patch的地方 
      cli
      mov  eax,addr1 
    mov  eax,[eax] 
    add  eax,addr1
    add  eax,0x3d  
    mov  addr,eax  //     
      };
    
     k = (MYPATCH*) addr;
     ss=k->E9_BYTE;     //unload时需要
     tt=k->JMP_ADDR;
    
    k->E9_BYTE=0x83;         //83C0 00         ADD EAX,0  填上垃圾指令
    k->JMP_ADDR=0xc08b00c0; //8BC0           MOV EAX,EAX
       __asm sti
    Sice_Protected=1;
  DbgPrint("0x%08X is the address patched  within sice",addr);
    DbgPrint("Anti_Softice start....");
  return STATUS_SUCCESS;
}

     

代码在灵想技术GHOSTXPSP3电脑城装机版 V7.0 Build 20090820下测试通过,截图留念。
     
     
代码有些地方你不一定能看懂,必须要通过调试才有感性认识,我就不详细注释了。注意中断服务号即vector的取得也不是很简单,我参考了资料一并奉上。
最后感谢大家!
                                              By 天易love  2010-1-10

上传的附件 antisice.rar