陷阱式API HOOK及重入问题的解决

    技术2022-05-11  76

     小弟最近研究API Hook,参考了许多资料,阅读了很多高手的文章之后终于做好了,颇有心得,写出来以免自己以后忘记API HOOK主要由陷阱式和改引入表式,二者各有局限,改引入表式则复杂,需要一定的PE知识,他要遍历当前所有的模块,然后还要遍历模块中的IAT(引入地址表),看是否有对于某个函数的调用,而且还有两个问题:就是当前进程建立一个新的线程的时候,我们必须重新这个工作,而且,如果程序采用GetProcAddress函数来得到地址的话,我们的方法就没有用,所以还得钩住GetProcAddress函数,而陷阱式在9X系统下很难实现,因为Delphi不能像VC那样指定一个DLL加载的参考地址,因此需要用一些其他的很复杂的办法才能实现,但他的代码在win2000/XP/Vista下很简单,不管多少模块对他进行调用(一个DLL只会在进程中映象一次),也不管以后是否有新建立的线程有对它的调用,或者对方使用GetProcAddress函数,都不会需要我们使用更多的操作,因此,虽然丧失了一点兼容性,但我个人认为它比改引入表式更具优势。(具体见《Delphi深入下Windows核心编程》第10章,www.2ccc.com有下载,以及网友sundytu的文章http://www.blogcn.com/user35/sundytu/blog/21666280.html)

    说说原理吧(只是我个人理解的,不一定正确,欢迎大家批评指正):在调用一个API时,API的入口一般是这样的:mov EAX,$1234 //$1234是我乱写的地址,函数的真正功能就从这里开始jmp EAX因此,我们只要能够把$1234该为我们自己编写的代替函数的地址就可以了,所以,我们定义一个这样的结构

    Tjump=packed record    Mov:Byte;    addr:Dword;    JmpEAX:Word;    reservedbyte:Byte;//为了CPU的效率,所以补充一个直接来使整个结构为8字节end;然后用WriteProcessMemory来修改入口为我们的结构即可,当然修改前要记住保存原来的结构以便卸载钩子。另外,陷阱式HookAPI有一个重入的问题,即同一时间有两个进程同时使用某一API时可能会给我们带来很大的麻烦,比如我HOOK CopyFile函数,然后要用CopyFile来Copy一个很大的文件,这样按一般的方法我暂时恢复原入口地址,那么此时如果我同时再去复制其他的文件那这些复制操作我就Hook不到了.这怎么办呢?为了解决这个为题我想了很久,终于想出一个办法:用createfilemapping来申请到一块与之大小合适的空间,然后用CopyMemory来把CopyFile函数的代码给全部拷贝到申请的空间中去,然后在HookAPI中将CopyFile入口指向我用我申请到的空间入口不就可以了么?但是如何把CopyFile的代码给拷贝出去的问题我始终没能解决,所以,我现在用是一种折中的办法:把整个要Hook的函数所在的Dll都拷出去,浪费点内存。不知哪位高手知道如何只拷贝CopyFile的代码,小弟诚心求教,原理就是这些了,代码如下:DLL的pas文件:unit Unit4;

    interfaceuses  Windows,PsAPI;

    type  mymsgboxa=function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;  Tjump=packed record    Mov:Byte;    addr:mymsgboxa;    JmpEAX:Word;    reservedbyte:Byte;  end;procedure HookEnd;procedure HookApi;var  old,jmp:Tjump;//old:原函数入口结构,jmp:用来替换的结构  processhandle:THandle;  oldmsgboxa:PChar;//为什么用pchar?因为pointer不能直接进行加减运算,但pchar可以,这是原函数的地址  hookhd:THandle;  mi:TModuleInfo;procedure load;implementationfunction mybox(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;var  maphd:THandle;  mapaddr:PChar;//为什么用pchar?因为pointer不能直接进行加减运算,但pchar可以  myfunc:mymsgboxa;begin  maphd:=OpenFileMapping(FILE_MAP_ALL_ACCESS,true,'syfunc');  mapaddr:=MapViewOfFile(maphd,FILE_MAP_ALL_ACCESS,0,0,0);  @myfunc:=oldmsgboxa - mi.lpBaseOfDll + mapaddr;//拷贝之后的函数地址是这样算出来的  Result:=myfunc(hWnd,'HookAPI暂时成功了,谢谢大家','Hook',uType);end;

    procedure HookApi;var  DllMoudle:THandle;  dwsize:DWORD;begin  processhandle:=GetCurrentProcess;  DllMoudle:=GetModuleHandle('user32.dll');  oldmsgboxa:=GetProcAddress(DllMoudle,'MessageBoxA');  if oldmsgboxa<>nil then  begin    GetModuleInformation(GetCurrentProcess,DllMoudle,@mi,SizeOf(tmoduleinfo));    jmp.Mov:=$B8;    jmp.addr:=@mybox;    jmp.JmpEAX:=$E0FF;    ReadProcessMemory(processhandle,oldmsgboxa,@old,8,dwsize);    WriteProcessMemory(processhandle,oldmsgboxa,@jmp,8,dwsize);  end;end;procedure HookEnd;var  dwsize:DWORD;begin  WriteProcessMemory(processhandle,oldmsgboxa,@old,8,dwsize);end;function msghook(ncode,wparam,lparam:Integer):LRESULT;stdcall;begin  hookapi;  Result:=CallNextHookEx(hookhd,ncode,wparam,lparam);end;procedure load;begin  hookhd:=SetWindowsHookEx(WH_GETMESSAGE,@msghook,HInstance,0);end;

    end.

    ============================================================Dll的dpr文件:library Project4;

    { Important note about DLL memory management: ShareMem must be the  first unit in your library's USES clause AND your project's (select  Project-View Source) USES clause if your DLL exports any procedures or  functions that pass strings as parameters or function results. This  applies to all strings passed to and from your DLL--even those that  are nested in records and classes. ShareMem is the interface unit to  the BORLNDMM.DLL shared memory manager, which must be deployed along  with your DLL. To avoid using BORLNDMM.DLL, pass string information  using PChar or ShortString parameters. }

    uses  Unit4 in 'Unit4.pas';

    {$R *.res}exports  load;beginend.============================================================EXE文件:unit t;

    interface

    uses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls,PsAPI;

    type

      TForm1 = class(TForm)    Button1: TButton;    Button2: TButton;    Button3: TButton;    procedure Button1Click(Sender: TObject);    procedure Button3Click(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;

    var  Form1: TForm1;procedure load;external 'project4.dll';implementation

    {$R *.dfm}

    procedure TForm1.Button1Click(Sender: TObject);var  maphd,msghd:THandle;  msgaddr,naddr:Pointer;  mdinfo:TModuleInfo;begin  msghd:=LoadLibrary('user32.dll');  msgaddr:=GetProcAddress(msghd,'MessageBoxA');  GetModuleInformation(GetCurrentProcess,msghd,@mdinfo,SizeOf(mdinfo));  maphd:=CreateFileMapping($ffffffff,nil,PAGE_EXECUTE_READWRITE,0,mdinfo.SizeOfImage,'syfunc');  naddr:=MapViewOfFile(maphd,FILE_MAP_ALL_ACCESS,0,0,0);  CopyMemory(naddr,mdinfo.lpBaseOfDll,mdinfo.SizeOfImage);  load;end;

    procedure TForm1.Button3Click(Sender: TObject);beginMessageBoxA(0,'ffffff','fffffff',0);end;

    end.==========================================================以上代码在D7+Vista环境下测试通过,这个程序还不是很完整哦!没写卸载的部分

     


    最新回复(0)