天天看點

C++ 在Ring3下的通用API HOOK

說道API HOOK ,這已經是老掉牙的技術了,但是它的實用性卻是不能忽視的。雖然在網上這類的文章很多,但大多數的實作方法是将一個函數的前5位元組直接改為 jmp XXXX 。這種方法雖然簡單可行,但是不通用,因為一些特殊函數的前5位元組不是完整的,如果直接修改,就會截斷指令,導緻出錯。以前在一個論壇上看到過一個用反彙編引擎實作的通用例子,感覺想法很好,于是自己也寫了一個。其中用到了一個頭檔案LDasm.h(裡面實際就是一個輕量級的反彙編引擎,網上可以下載下傳到)。

#include "stdafx.h"
#include "LDasm.h"
#include <windows.h>

DWORD proxyFunction;
void* HookFunc(char* ModuleName,char* FuncName,void* NewFunc)
{
  void* proxyFunction = 0;
  unsigned char* OpCode = 0;
  ULONG BackupLength = 0;
  unsigned char JmpCode[6]={0x68,0x00,0x00,0x00,0x00,0xc3};
  unsigned char JmpBackCode[6]={0x68,0x00,0x00,0x00,0x00,0xc3};
  /*
  原代碼用的是GetModuleHandle(ModuleName);這要成功的
  前提是:隻有欲擷取的子產品已映射到調用該函數的程序内,才會正确得到子產品句柄。
  常用子產品映射函數:LoadLibrary(..)
  */
  HMODULE hMod = GetModuleHandle(ModuleName);
  void* sourFunc = GetProcAddress(hMod,FuncName);

  if(!sourFunc)
    return NULL;

  *(ULONG*)(&JmpCode[1])=(ULONG)NewFunc;

  while(BackupLength<6)
  {
    BackupLength += SizeOfCode((void*)((ULONG)sourFunc+BackupLength),&OpCode);
  }

  proxyFunction = VirtualAlloc(NULL,BackupLength + 6,MEM_RESERVE| MEM_COMMIT,PAGE_EXECUTE_READWRITE);
  if (!proxyFunction)
    return NULL;

  *(ULONG*)((ULONG)JmpBackCode + 1) = (ULONG)sourFunc + BackupLength;
  RtlCopyMemory(proxyFunction,sourFunc,BackupLength);
  RtlCopyMemory((PVOID)((ULONG)proxyFunction + BackupLength),JmpBackCode, 6);
  FlushInstructionCache((HANDLE) - 1,proxyFunction,BackupLength + 6);
  DWORD OldProtect = 0;
  VirtualProtect(sourFunc, 6,PAGE_EXECUTE_READWRITE, &OldProtect);
  RtlCopyMemory(sourFunc,JmpCode, 6);
  VirtualProtect(sourFunc, 6,OldProtect, &OldProtect);
  FlushInstructionCache((HANDLE) -1,sourFunc, 6);
  return proxyFunction;
}

int audit()
{
  static int cnt;
  DWORD Lab1Offset;

  __asm
  {
    mov eax,Lab1;
    mov Lab1Offset,eax;
  }
  DWORD OldProtect = 0;
  VirtualProtect((void*)Lab1Offset, 4,PAGE_EXECUTE_READWRITE, &OldProtect);

  cnt++;
  //跳轉前要繞過_chkesp
  __asm
  {
    pop edi;
    pop esi;
    pop ebx;
    mov esp,ebp;
    pop ebp;
  }

  __asm
  {
    mov eax,proxyFunction;
    mov ebx,Lab1;
    mov [ebx],eax;
    _emit 0x68;
Lab1:
    _emit 0x90;
    _emit 0x90;
    _emit 0x90;
    _emit 0x90;
    ret;
  }
  return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
  proxyFunction = (DWORD)HookFunc("user32.dll","MessageBoxA",audit);

  MessageBox(NULL,"","",MB_OK);
  return 0;
}