用DEP实现BreakOnExecute


以前抄过OllyBone,但不大好用,很多时候停不下来,似乎在PTE上做的手脚没起作用。后来看到
DEP,这不就是我想要的功能么,又重新试了一次。

打开DEP后,系统工作在PAE下,PTE为64位。不过改了以后,还是存在拦不住的情况,用SoftIce跟了一下,
PTE的确被动过。Hook KeInterlockedSwapPte就可以了,估计OllyBone不好用也是同样道理。

前段时间写的东西,细节已经记不起来了。反正代码都贴出来了。功能跟OllyBone一样的。在xp sp2/sp3下测试可以用。


代码:
#define MiGetPteAddressPAE(va)   ((PMMPTE)(PTE_BASE + ((((ULONG)(va)) >> 12) << 3)))

typedef struct _HARDWARE_PTE_X86PAE {
    union {
        struct {
        ULONGLONG Valid : 1;
        ULONGLONG Write : 1;
        ULONGLONG Owner : 1;
        ULONGLONG WriteThrough : 1;
        ULONGLONG CacheDisable : 1;
        ULONGLONG Accessed : 1;
        ULONGLONG Dirty : 1;
        ULONGLONG LargePage : 1;
        ULONGLONG Global : 1;
        ULONGLONG CopyOnWrite : 1;   // software field
        ULONGLONG Prototype : 1;     // software field
        ULONGLONG reserved0 : 1;    // software field
        ULONGLONG PageFrameNumber : 26;
        //ULONGLONG reserved1 : 26;    // software field
  ULONGLONG reserved1 : 25;    // software field
  ULONGLONG ExecuteDisable : 1;  // 这个
        };
        struct {
            ULONG LowPart;
            ULONG HighPart;
        };
    };
} HARDWARE_PTE_X86PAE, *PHARDWARE_PTE_X86PAE;


VOID HookMemory(ULONG address, ULONG size)
{
  ULONG i;

  g_HookMem = TRUE;
  g_HookStart = address;
  g_HookEnd = address + size;

  g_PteStart = (ULONG)MiGetPteAddressPAE(g_HookStart);
  g_PteEnd   = (ULONG)MiGetPteAddressPAE(g_HookEnd);

  //DbgPrint("PteStart = %08X, PteEnd = %08X", g_PteStart, g_PteEnd);
  
  KeAttachProcess(g_ObjProc);

  for (i = address; i < address+size; i += PAGE_SIZE) //4KB Pages only
    HookPage((PUCHAR)i);
  
  KeDetachProcess();
}


VOID HookPage(PUCHAR Page)
{
  
  PHARDWARE_PTE_X86PAE PointerPte;
    
  
  __try {

    __asm {  
      mov   eax, Page  
      mov   eax, [eax]
    }
    
    PointerPte = (PHARDWARE_PTE_X86PAE)MiGetPteAddressPAE(Page);

    if (PointerPte->Valid == 1) {
      PointerPte->ExecuteDisable = 1;
      DbgPrint("HookPage = %08X", Page);
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER) {
    DbgPrint("Exception captured while hooking page");
  }
}


VOID UnhookPage(PUCHAR Page)
{
  PHARDWARE_PTE_X86PAE PointerPte;

  __try {
    
    __asm {
      mov  eax, Page  
      mov  eax, [eax]
    }

    PointerPte = (PHARDWARE_PTE_X86PAE)MiGetPteAddressPAE(Page);

    if (PointerPte->Valid == 1) {
      PointerPte->ExecuteDisable = 0;
    }
  } 
  __except(EXCEPTION_EXECUTE_HANDLER) {
    DbgPrint("Exception captured while unhooking page");
  }
}


VOID UnhookMemory(ULONG address, ULONG size)
{
  ULONG i;

  KeAttachProcess(g_ObjProc);
  
  for (i = address; i < address+size; i += PAGE_SIZE)
    UnhookPage((PUCHAR)i);
  
  KeDetachProcess();
}


NTSTATUS FindSwapPte(ULONG ntosbase, PULONG result)
{
  //
  // Search KeInterlockedSwapPte in kernel space:)
  // there are some lock cmpxchg8b, but this is the only one followed 
  // by a jnz 
  //

  UCHAR code[] = { 0xF0, 0x0F, 0xC7, 0x0E,  // lock cmpxchg8b qword ptr [esi]
       0x75, 0xFA,      // jnz     short loc_46EC60
       0x5E,        // pop     esi
       0x5B,        // pop     ebx
       0xC2, 0x08, 0x00    // retn    8
      };


  NTSTATUS status = STATUS_UNSUCCESSFUL;
  PIMAGE_DOS_HEADER mz;
  PIMAGE_NT_HEADERS pe;
  ULONG current, end, i;
  SIZE_T size = sizeof(code);
  
  mz = (PIMAGE_DOS_HEADER)ntosbase;
  pe = (PIMAGE_NT_HEADERS)((ULONG)ntosbase + mz->e_lfanew);

  *result = 0;
  current = ntosbase;
  end = ntosbase + pe->OptionalHeader.SizeOfImage - sizeof(code);

  

  __try {
    while (current < end) {

      if (RtlCompareMemory((PVOID)current, code, size) == size) {
      
        
        // WARNING!
        // the hook func CAN'T work in Win2K3! refer to wrk,
        // the ULONG64 was pushed in stack instead of the pointer
        //

        for (i = 0; i < 32; i++) {

          if (*(PUSHORT)(current - i) == 0x5653) {
            *result = current - i;
            
            DbgPrint("KeInterlockedSwapPte = %08X", *result);
            status = STATUS_SUCCESS;
            break;
          }
        }
      }
      current++;
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER) {
    DbgPrint("Failed to retrive KeInterlockedSwapPte");
    *result = 0;
    return STATUS_FAIL_GET_KESWAPPTE;
  }

  return status;
}


VOID HookKeInterlockedSwapPte()
{
  
  ULONG  func = g_KeInterlockedSwapPte;
  ULONG  newlowpart, newhighpart;
  UCHAR  opcode[8] = {0x90};

  opcode[0] = 0xE9;
  *(PULONG)&opcode[1] = (ULONG)KeInterlockedSwapPte - (func+5);

  newlowpart  = *(PULONG)&opcode[0];
  newhighpart = *(PULONG)&opcode[4];

  DisableWP
  
  
  __asm {
    pushad

    mov   esi, func
    
    mov   edi, offset g_SavedSwapPte
    mov   edx, [esi+4]
    mov   [edi+4], edx  // save the old opcode
    mov   eax, [esi]
    mov   [edi], eax

    mov   ecx, newhighpart
    mov   ebx, newlowpart

__swapagain:
    lock  cmpxchg8b qword ptr [esi]
    jne   __swapagain  
    
    popad
  }

  EnableWP
    
  DbgPrint("Hook KeInterlockedSwapPte OK");
}


VOID __declspec(naked) KeInterlockedSwapPte()
{

  //
  // 这里的代码适用于xp,WRK压栈的是ULONG64,不是指针,要修改
  //

  //   ; ULONGLONG
  //   ; InterlockedExchangePte (
  //   ;     IN OUT PMMPTE Destination,
  //   ;     IN ULONGLONG Exchange
  //   ;     )
  // 
  //   push    ebx
  //    push    esi
  //   mov     ebx, [esp] + 16         ; ebx = NewPteContents lowpart
  //   mov     ecx, [esp] + 20         ; ecx = NewPteContents highpart
  //   mov     esi, [esp] + 12         ; esi = PtePointer


  __asm 
  {
    push    ebx
    push    esi
    mov     ebx, dword ptr [esp+10h]  // ebx = pointer to Exchange
    mov     esi, dword ptr [esp+0Ch]  // esi = PtePointer
    mov     ecx, dword ptr [ebx+4]    // ecx = NewPteContents highpart
    mov     ebx, dword ptr [ebx]    // ebx = NewPteContents lowpart
    mov     edx, dword ptr [esi+4]    // edx = OldPteContents highpart
    mov     eax, dword ptr [esi]    // eax = OldPteContents lowpart, return old contents in edx:eax
      
  __swapagain:

    lock  cmpxchg8b qword ptr [esi]
    jne  __swapagain      // if z clear, exchange failed
      
    pushad          // if debuggee, fuck up nx
    call    dword ptr [IoGetCurrentProcess]
    cmp  eax, g_ObjProc
    jne  __end

    cmp  esi, g_PteStart
    jb  __end
    cmp  esi, g_PteEnd
    ja  __end

    or  dword ptr [esi+4], 80000000h  //管用的就是这句

  __end:
    popad
    pop     esi
    pop     ebx
    ret     8
  }
}


volatile __declspec(naked) void NewInt0E_PAE()
{
  // 
  //  - Interrupt 0E Handler -
  //
  //  offset   | contains
  //  ---------+-----------------------------
  //  esp      : Error Code
  //  esp + 4  : EIP Context
  //  esp + 8  : CS  Context
  //  esp + C  : EFLAGS
  //

  __asm 
  {
    pushad
    push    fs
    push    ds
    push    es
    mov     eax, 30h
    mov     fs, ax
    mov     eax, 23h
    mov     ds, ax
    mov     es, ax

    call  dword ptr [IoGetCurrentProcess]
    cmp  eax, g_ObjProc     // debuggee?
    jne  __oldint0e
      
    mov  eax, [esp+20h+0Ch]  // error code
    test  eax, 1      // not present
    je  __oldint0e

    test  eax, 4
    je  __oldint0e    // skip kernel mode page fault

      
    cmp  g_HookMem, 0
    je  __oldint0e

    mov  eax, cr2    // the faulting address
    cmp  eax, g_HookStart
    jb  __oldint0e

    cmp  eax, g_HookEnd
    jae  __oldint0e

    cmp  eax, [esp+20h+0Ch+4]  // eip
    jne  __oldint0e    // because of execution
      
    pop     es
    pop     ds
    pop     fs
              popad
    add  esp, 4      // discard error code
    jmp  g_KiTrap01    // fuck up int1

__oldint0e:
    pop     es
            pop     ds
          pop     fs
          popad
          jmp  g_KiTrap0E
      
  }
}
最后感谢风月,把他的VMX代码给我。有时间再学习啦,我现在时间都耗在聊天上了哈。