极难!hook大师刘麻子请进:hookapi的重入问题。 ( 积分: 300 )

  • 主题发起人 主题发起人 hzm7512
  • 开始时间 开始时间
H

hzm7512

Unregistered / Unconfirmed
GUEST, unregistred user!
我现在用hookapi的技术hook了SHFileOperationW这个系统api函数。当处理(copy,Rename等)一个小文件时拦截是没问题的。但是当copy一个大文件期间,在处理其它文件时,就拦截不到了,我查了资料,说是hookapi的重入问题,要用临界区或互斥量来解决,但是我从来没搞过这些东西,请问大侠该如何解决呢?谁有这方面的资料,给小弟看看。小弟感激涕零。
 
我现在用hookapi的技术hook了SHFileOperationW这个系统api函数。当处理(copy,Rename等)一个小文件时拦截是没问题的。但是当copy一个大文件期间,在处理其它文件时,就拦截不到了,我查了资料,说是hookapi的重入问题,要用临界区或互斥量来解决,但是我从来没搞过这些东西,请问大侠该如何解决呢?谁有这方面的资料,给小弟看看。小弟感激涕零。
 
老兄,我现在也再研究这个问题,还是一头雾水,你是怎么拦截copy文件的?怎么抓到拷贝的源文件和目标文件名呢?
 
摘抄一段:<br> &nbsp;使用陷阱式APIHook要避免“重入”(即同一时刻被调用两次或两次以上)的问题,由于陷阱式APIHook是采用“拆东墙补西墙”的流程来实现的,当在多线程或多个不同的进程“同时”进入自定义函数中时,会出现不可预料的结果,也可能死机。此时可以这些处理:一,对于有可能会出现重入的,如listen,send等winsock函数,可以使用临界区,互斥对象来避免重入。二,确保该函数是不会重入的。
 
to langzizheng:<br>你看看《delphi下深入windows核心编程》这本书,对你有帮助。
 
to hzm7512:<br>这本书我有,挺好的,但我还不知道怎么实时对拷贝的文件流进行处理,比如说拷贝的时候对文件流加密
 
9x下用Mutex互斥对象,NT内核系统用CriticalSection关键区,保证一个调用正在处理时,其他调用处于等待状态,要注意每个被hook函数用一个,如:<br>EnterCriticalSection(csSHFileOperationW);<br>try<br> &nbsp;RestoreAPI;<br> &nbsp;Call API;<br> &nbsp;HookAPI;<br>finally<br> &nbsp;LeaveCriticalSection(csSHFileOperationW);<br>end;
 
to :lichengbin 我试试不行,在Hookapi时也许不行。我将你给的代码写上了,在copy500M大小文件的2分钟内,我在copy其它文件时,拦截不到这些文件。<br>var<br>g_CriticalSection : TRTLCriticalSection;<br>.....<br>function NewSHFileOperationW(var lpFileOp: TSHFileOpStructW): Integer; stdcall;<br>type<br> &nbsp;SHFileOperationW = function(const lpFileOp: TSHFileOpStructW): Integer; stdcall;<br>var<br> &nbsp;str &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : string;<br> &nbsp;p &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : PWidechar;<br> &nbsp;PInfo &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : PSHFileOpStructW;<br>begin<br> &nbsp;EnterCriticalSection(g_CriticalSection);<br> &nbsp;try<br> &nbsp; &nbsp;Hook[fSHFileOperationW].Restore;//RestoreAPI;<br> &nbsp; &nbsp;P := lpFileOp.pFrom;//Call API;<br> &nbsp; &nbsp;while p^ &lt;&gt; '' do begin<br> &nbsp; &nbsp; &nbsp;str := str + p + ';';<br> &nbsp; &nbsp; &nbsp;inc(DWORD(p), (length(p) + 1) * 2);<br> &nbsp; &nbsp;end;//取文件名<br> &nbsp; &nbsp;case lpFileOp.wFunc of<br> &nbsp; &nbsp; &nbsp;FO_MOVE: begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;str := 'SHFileOperationW Move :from: &nbsp;' + str + ' &nbsp;to: &nbsp;' + lpFileOp.pTo;<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp;FO_COPY: begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;str := 'SHFileOperationW Copy :from: &nbsp;' + str + ' &nbsp;to: &nbsp;' + lpFileOp.pTo;<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp;FO_DELETE: begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;str := 'SHFileOperationW Delete :from: &nbsp;' + str;<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp;FO_RENAME: begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;str := 'SHFileOperationW Rename :from: &nbsp;' + str + ' &nbsp;to: &nbsp;' + lpFileOp.pTo;<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp;end;<br> &nbsp; &nbsp;result := SHFileOperationW(hook[fSHFileOperationW].OldFunction)(lpFileOp);<br> &nbsp; &nbsp;if not lpFileOp.fAnyOperationsAborted then begin<br> &nbsp; &nbsp; &nbsp;if result = 0 then<br> &nbsp; &nbsp; &nbsp; &nbsp;str := str + ' ' + '成功!'<br> &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp;str := str + ' ' + '失败!';<br> &nbsp; &nbsp;end<br> &nbsp; &nbsp;else begin<br> &nbsp; &nbsp; &nbsp;str := str + ' ' + '用户取消了操作!'<br> &nbsp; &nbsp;end;<br> &nbsp; &nbsp;hook[fSHFileOperationW].Change;//HookAPI;<br> &nbsp;finally<br> &nbsp; &nbsp;LeaveCriticalSection(g_CriticalSection);<br> &nbsp;end;<br>end;<br>......<br>initialization<br>InitializeCriticalSection(g_CriticalSection);<br>finalization<br>DeleteCriticalSection(g_CriticalSection);<br>...
 
在陷阱式拦截api,如何处理并发操作。大侠救救我。在线等,一有答案立即放分。
 
to :lichengbin 在copy500M大小文件的2分钟内,我在copy其它文件时,我进行调试,在这2分钟之内,拦截不到SHFileOperationW这个函数,也就说hookapi在同一时刻只能拦截同一个函数一次吗?如何处理在一个时间段里多次调用像SHFileOperationW这样的函数?
 
这个不是什么重入问题,是因为你把API入口代码恢复了,然后调用原来的API的,既然恢复了,哪里还能截获呢?如果还能截获,那岂不是又进入了你的这个NewSHFileOperationW函数,那还得了?岂不是要无穷无尽递归下去而堆栈耗尽出错啦?陷阱式的API截获本身就有这个弱点而会导致一些漏截的,改用引入表方式截获吧,不过那种方式又有它自己的不足。具体分析参见此贴 http://www.delphibbs.com/delphibbs/dispq.asp?LID=2795211
 
to :lichengbin :茅舍顿开,高手,分析的很有道理。<br>在你的大作里有这样一段话:<br> &nbsp;修改引入表的API Hook方法,不存在上面所说的问题,因为它们的Hook实现的机制不同,<br> &nbsp;它不需要在截获到API调用后,恢复、调用原API、再更改代码,它只是简单地将进程的<br> &nbsp;引入表中该API的地址指向替代函数,在替代函数内部,直接调用原API即可。既然没有<br> &nbsp;更改API入口代码的过程,也就不会有更改代码时的多线程同步问题。也不会有前面提<br> &nbsp;到的漏截问题,因为没有恢复的过程,API引入表始终指向替代函数。<br> &nbsp;但这种方法,对95内核的系统是不适用的。Win95是16/32位代码混合的系统,16位的<br> &nbsp;DLL并没有32位PE格式的引入表概念。另外,需要处理动态调用的问题,而且对截获之<br> &nbsp;前已经加载并用GetProcAddress获取到地址的DLL中的函数,无法进行截获。<br>如果改为引用表时,替代函数在处理完主要信息以后,如果我还想用回原来的函数怎么办?因为“API引入表始终指向替代函数”这个函数是不是又调用回来了,造成死循环?
 
不会的,在替代函数内部,你不要直接用SHFileOperationW这样的函数名称来调用API,这种静态链接DLL的API函数的地址是引入表中所列的地址,并不是API在实际装载DLL中的绝对地址,而是使用GetModuleHandle/LoadLibrary、GetProcAddress获得的API函数的入口地址,再进行动态调用,这个入口地址的代码并不会因为你修改引入表而修改,这也是我为什么说修改引入表式APIHook不需要“恢复、调用原API、再更改代码进行截获”的原因。<br>引入表SHFileOperationW -&gt; shell32.dll SHFileOperationW<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ^<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br> &nbsp; &nbsp; NewSHFileOperationW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | p<br> ---------------------------------------------<br>| &nbsp;h := GetModuleHandle('shell32.dll') &nbsp; &nbsp; &nbsp; &nbsp;|<br>| &nbsp;p := GetProcAddress(h, 'SHFileOperationW') |<br> ---------------------------------------------
 
to lichengbin:根据你的讲法我把陷阱式的改成引入表式的,结果引入表式的拦截不到shell32.dll的api但是windows里的api是可以拦截的.<br>我再试试.多谢lichengbin,300分一定是你的了,等我做完后放分.
 
要想采用引入表式hook,GetProcAddress的函数,必须在目标GetProcAddress前修改dll的导出表,可参见:<br>http://www.delphibbs.com/delphibbs/dispq.asp?lid=3163568<br>大多数情况下是没有条件做到的。还是用陷阱式的吧
 
看看我的源程序:<br>unit APIHook;<br>interface<br>uses<br> &nbsp;SysUtils,<br> &nbsp;Windows, shellapi, Dialogs;<br>type<br> &nbsp;//要HOOK的API函数定义<br> &nbsp;TFileoperate = function(var lpFileOp: TSHFileOpStructW): Integer; stdcall;<br> &nbsp;PJmpCode = ^TJmpCode;<br> &nbsp;TJmpCode = packed record<br> &nbsp; &nbsp;OrderCode: BYTE;<br> &nbsp; &nbsp;Address: TFileoperate;<br> &nbsp; &nbsp;MovEAX: array[0..2] of BYTE;<br> &nbsp;end;<br> &nbsp;//--------------------函数声明---------------------------<br>procedure HookAPI;<br>procedure UnHookAPI;<br>var<br> &nbsp;OldSHFileOperationW: TFileoperate; &nbsp; &nbsp;//原来的API地址<br> &nbsp;OldProc,NewProc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : TJmpCode;<br> &nbsp;Add_SHFileOperationW: pointer; &nbsp; &nbsp; &nbsp; &nbsp;//API地址<br> &nbsp;TmpJmp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: TJmpCode;<br> &nbsp;ProcessHandle &nbsp; &nbsp; : THandle;<br>implementation<br><br>function MySHFileOperationW(var lpFileOp: TSHFileOpStructW):<br> &nbsp;Integer; stdcall;<br>var<br> &nbsp;dwSize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: cardinal;<br>begin<br> &nbsp;showmessage('dd');<br> &nbsp;WriteProcessMemory(ProcessHandle, Add_SHFileOperationW, @OldProc, 8,<br> &nbsp; &nbsp;dwSize);<br> &nbsp;Result := OldSHFileOperationW(lpFileOp);<br> &nbsp;NewProc.Address := @MySHFileOperationW;<br> &nbsp;WriteProcessMemory(ProcessHandle, Add_SHFileOperationW, @NewProc, 8,<br> &nbsp; &nbsp;dwSize);<br>end;<br>{------------------------------------}<br>{过程功能:HookAPI<br>{过程参数:无<br>{------------------------------------}<br><br>procedure HookAPI;<br>var<br> &nbsp;DLLModule &nbsp; &nbsp; &nbsp; &nbsp; : THandle;<br> &nbsp;dwSize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: cardinal;<br>begin<br> &nbsp;ProcessHandle := GetCurrentProcess;<br> &nbsp;DLLModule := LoadLibrary('shell32.dll');<br> &nbsp;Add_SHFileOperationW := GetProcAddress(DLLModule, 'SHFileOperationW'); //取得API地址<br> &nbsp;NewProc.OrderCode := $B8;<br> &nbsp;NewProc.MovEAX[0] := $FF;<br> &nbsp;NewProc.MovEAX[1] := $E0;<br> &nbsp;NewProc.MovEAX[2] := 0;<br> &nbsp;ReadProcessMemory(ProcessHandle, Add_SHFileOperationW, @OldProc, 8,<br> &nbsp; &nbsp;dwSize);<br> &nbsp;NewProc.Address := @MySHFileOperationW;<br> &nbsp;WriteProcessMemory(ProcessHandle, Add_SHFileOperationW, @NewProc, 8,<br> &nbsp; &nbsp;dwSize);<br> &nbsp;OldSHFileOperationW := MySHFileOperationW;<br>end;<br>{------------------------------------}<br>{过程功能:取消HOOKAPI<br>{过程参数:无<br>{------------------------------------}<br><br>procedure UnHookAPI;<br>var<br> &nbsp;dwSize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: Cardinal;<br>begin<br> &nbsp;WriteProcessMemory(ProcessHandle, Add_SHFileOperationW, @OldProc, 8,<br> &nbsp; &nbsp;dwSize);<br>end;<br>end.
 
在《delphi下深入windows核心编程》中有屏幕取词的hookapi,我改了改,使用引入表hookapi只能hook到Windows里的api,不能hook,shell32的api,不知道为什么.
 
to tt.t :&quot;必须在目标GetProcAddress前修改dll的导出表&quot; 具体是什么意思?
 
load到内存中后,dll的导出表保存了指向导出函数的指针,GetProcAddress不过是查询dll的导出表,返回函数地址。<br>在调用GetProcAddress前修改dll的导出表,使导出表中的指针指向新函数地址,这样GetProcAddress就会返回新函数地址
 
to tt.t:我认为的引入表式的hookapi是这样的,在系统启动时,系统会自动加载必要的dll,同时系统api的地址也会注入到内存里去,用GetProcAddress查询旧的api地址,用WriteProcessMemory修改旧的api地址所指向函数的地址使这个内存地址指向的函数由原来的api变到新的我们自己定义的函数.
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
I
回复
0
查看
676
import
I
后退
顶部