拦截的API,留下记号 不指定

青色咖啡 , 2011/04/12 19:21 , 转载文章 , 评论(1) , 阅读(415) , Via 本站原创

要拦截的API如下:

   MessageBoxA、MessageBoxW、MessageBeep 和 OpenProcess 。

   首先,大家都知道要在整个系统范围中拦截,需要使用Dll来完成。现在我们打开Delphi 2009,新建一个Dll工程:hookDll。需要说明的是,Delphi是完全面向对象的编程语言,所以我们不要浪费,这个Dll打算用类的方式完成。于是,在新建的DLL工程中在添加一个Unit Pas,命名为unitHook, 用来写拦截类的处理。unitHook.pas中的代码如下:

unit unitHook;interfaceuses  Windows, Messages, Classes, SysUtils;type  //NtHook类相关类型  TNtJmpCode=packed record  //8字节    MovEax:Byte;    Addr:DWORD;    JmpCode:Word;    dwReserved:Byte;  end;  TNtHookClass=class(TObject)  private    hProcess:THandle;    NewAddr:TNtJmpCode;    OldAddr:array[0..7] of Byte;    ReadOK:Boolean;  public    BaseAddr:Pointer;    constructor Create(DllName,FuncName:string;NewFunc:Pointer);    destructor Destroy; override;    procedure Hook;    procedure UnHook;  end;implementation//==================================================//NtHOOK 类开始//==================================================constructor TNtHookClass.Create(DllName: string; FuncName: string;NewFunc:Pointer);var  DllModule:HMODULE;  dwReserved:DWORD;begin  //获取模块句柄  DllModule:=GetModuleHandle(PChar(DllName));  //如果得不到说明未被加载  if DllModule=0 then DllModule:=LoadLibrary(PChar(DllName));  //得到模块入口地址(基址)  BaseAddr:=Pointer(GetProcAddress(DllModule,PChar(FuncName)));  //获取当前进程句柄  hProcess:=GetCurrentProcess;  //指向新地址的指针  NewAddr.MovEax:=$B8;  NewAddr.Addr:=DWORD(NewFunc);  NewAddr.JmpCode:=$E0FF;  //保存原始地址  ReadOK:=ReadProcessMemory(hProcess,BaseAddr,@OldAddr,8,dwReserved);  //开始拦截  Hook;end;//释放对象destructor TNtHookClass.Destroy;begin  UnHook;  CloseHandle(hProcess);  inherited;end;//开始拦截procedure TNtHookClass.Hook;var  dwReserved:DWORD;begin  if (ReadOK=False) then Exit;  //写入新的地址  WriteProcessMemory(hProcess,BaseAddr,@NewAddr,8,dwReserved);end;//恢复拦截procedure TNtHookClass.UnHook;var  dwReserved:DWORD;begin  if (ReadOK=False) then Exit;  //恢复地址  WriteProcessMemory(hProcess,BaseAddr,@OldAddr,8,dwReserved);end;end.

至此,unitHook.pas的代码OK了,其中加了详细的注释,在此就不再多做解释。现在切换到Dll的代码页,写入以下代码:
 
library hookdll;uses  SysUtils, Windows,  Classes,  unitHook in 'unitHook.pas';{$R *.res}const  HOOK_MEM_FILENAME  =  'tmp.hkt';var  hhk: HHOOK;  Hook: array[0..3] of TNtHookClass;  //内存映射  MemFile: THandle;  startPid: PDWORD;   //保存PID{--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--}//拦截 MessageBoxAfunction NewMessageBoxA(_hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;type  TNewMessageBoxA = function (_hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;begin  lpText := PAnsiChar('已经被拦截 MessageBoxA');  Hook[0].UnHook;  Result := TNewMessageBoxA(Hook[0].BaseAddr)(_hWnd, lpText, lpCaption, uType);  Hook[0].Hook;end;//拦截 MessageBoxWfunction NewMessageBoxW(_hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT): Integer; stdcall;type  TNewMessageBoxW = function (_hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT): Integer; stdcall;begin  lpText := '已经被拦截 MessageBoxW';  Hook[2].UnHook;  Result := TNewMessageBoxW(Hook[2].BaseAddr)(_hWnd, lpText, lpCaption, uType);  Hook[2].Hook;end;//拦截 MessageBeepfunction NewMessageBeep(uType: UINT): BOOL; stdcall;type  TNewMessageBeep = function (uType: UINT): BOOL; stdcall;begin  Result := True;end;//拦截 OpenProcess , 防止关闭function NewOpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;type  TNewOpenProcess = function (dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;begin  if startPid^ = dwProcessId then begin    result := 0;    Exit;  end;  Hook[3].UnHook;  Result := TNewOpenProcess(Hook[3].BaseAddr)(dwDesiredAccess, bInheritHandle, dwProcessId);  Hook[3].Hook;end;{--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--}//安装API Hookprocedure InitHook;begin  Hook[0] := TNtHookClass.Create('user32.dll', 'MessageBoxA', @NewMessageBoxA);  Hook[1] := TNtHookClass.Create('user32.dll', 'MessageBeep', @NewMessageBeep);  Hook[2] := TNtHookClass.Create('user32.dll', 'MessageBoxW', @NewMessageBoxW);  Hook[3] := TNtHookClass.Create('kernel32.dll', 'OpenProcess', @NewOpenProcess);end;//删除API Hookprocedure UninitHook;var  I: Integer;begin  for I := 0 to High(Hook) do  begin    FreeAndNil(Hook[I]);  end;end;{--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--}//内存映射共想procedure MemShared();begin  MemFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS,False, HOOK_MEM_FILENAME);   //打开内存映射文件  if MemFile = 0 then begin  //打开失败则衉c2建内存映射文件    MemFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,                              4, HOOK_MEM_FILENAME);  end;  if MemFile <> 0 then    //映射文件到变量    startPid := MapViewOfFile(MemFile,FILE_MAP_ALL_ACCESS,0,0,0);end;//传递消息function HookProc(nCode, wParam, lParam: Integer): Integer; stdcall;begin  Result := CallNextHookEx(hhk, nCode, wParam, lParam);end;//开始HOOKprocedure StartHook(pid: DWORD); stdcall;begin  startPid^ := pid;  hhk := SetWindowsHookEx(WH_CALLWNDPROC, HookProc, hInstance, 0);end;//结束HOOKprocedure EndHook; stdcall;begin  if hhk <> 0 then    UnhookWindowsHookEx(hhk);end;//环境处理procedure DllEntry(dwResaon: DWORD);begin  case dwResaon of    DLL_PROCESS_ATTACH: InitHook;   //DLL载入    DLL_PROCESS_DETACH: UninitHook; //DLL删除  end;end;exports  StartHook, EndHook;begin  MemShared;  { 分配DLL程序到 DllProc 变量 }  DllProc := @DllEntry;  { 调用DLL加载处理 }  DllEntry(DLL_PROCESS_ATTACH);end.

     这样,我们用来hook API 的 Dll 就完工了。 在Dll中,我们还使用到了内存映射,用来实现在拦截全局时的内存共享,如这个例子中需要保存调用此hook的进程句柄,以防止通过任务管理器关闭示例程序。

   编译生成 hookdll.dll 文件,就可以使用了。现在我们再来建立一个测试用的程序。

     如附图所示,画3个按钮,分别为"Hook"、"UnHook"、"MessageBox",前两个用来安装和删除钩子,第三个用来显示一个消息框,你将会看到被Hook后的情况。测试工程的代码如下:
unit FMain;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls;type  TfrmMain = class(TForm)    btnHook: TButton;    btnUnhook: TButton;    Button1: TButton;    procedure btnHookClick(Sender: TObject);    procedure btnUnhookClick(Sender: TObject);    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;var  frmMain: TfrmMain;  procedure StartHook(pid: DWORD); stdcall; external 'hookdll.dll';  procedure EndHook; stdcall; external 'hookdll.dll';implementation{$R *.dfm}procedure TfrmMain.btnHookClick(Sender: TObject);begin  StartHook(GetCurrentProcessId);end;procedure TfrmMain.btnUnhookClick(Sender: TObject);begin  EndHook;end;procedure TfrmMain.Button1Click(Sender: TObject);begin  MessageBox(0, 'abdfadfasdf', nil, 0);end;procedure TfrmMain.FormCreate(Sender: TObject);beginend;end.
 
    完成后运行,先不点击"hook"按钮,直接点击MessageBox,你会发现现在已经被拦截了。为什么我们还没有安装钩子就被拦截了呢?程序出错了吗?呵呵。当然没有出错。反过来看看DLL中的一处代码:
.............//环境处理procedure DllEntry(dwResaon: DWORD);begin  case dwResaon of    DLL_PROCESS_ATTACH: InitHook;   //DLL载入    DLL_PROCESS_DETACH: UninitHook; //DLL删除  end;end;............begin  MemShared;  { 分配DLL程序到 DllProc 变量 }  DllProc := @DllEntry;  { 调用DLL加载处理 }  DllEntry(DLL_PROCESS_ATTACH);end.
 
   可以看到,在DLL装入内存的时候其实就已经调用了InitHook,将要拦截的API拦截了。这时候看看任务管理器能不能关闭我们的程序,试一下就知道还可以,因为我们还没有调用StartHook来传入我们程序的PID,所以还可以被关闭。
  
   到此这篇文章就结束了, 本人从小语文没及过格(^_^),文章写的不太好,不过源代码都贴上了,有详细的注释,相信大家也能看明白。如果你发现有什么错误的地方,要记得告诉我哦!

   最后感谢 cxwr(菜新)大大的支持,能完成这篇文章少不了他的功劳。
分页: 1/1 第一页 1 最后页 [ 显示模式: 摘要 | 列表 ]