hook WSARecv要注意的问题

来源:互联网 发布:有趣的品牌 知乎 编辑:程序博客网 时间:2024/05/29 11:28

如果直接在hook的函数中直接调用原始地址的话完全没有问题:

int WSAAPI hooked_WSARecv_ws232(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
{
return ((LPFN_WSARECV)(WSARecvHookerWS232.GetRawFunction()))(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine );
}

但是如果是在调用原函数后还进行了getsockname或者getpeername操作的话将导致网络操作失败。

这里如果需要截获实际接收的数据的话,当村的通过这个函数是很片面的,需要分几种情况说明:

1、如果lpOverlapped为NULL,那么是阻塞式的,直接在原函数返回后处理即可
2、如果lpOverlapped不为NULL,且lpCompletionRoutine不为NULL,那么需要使用自己的函数替换lpCompletionRoutine;并在调用后执行调用用户原函数。因为这时是完成例程通知。
3、如果lpOverlapped不为NULL,且lpCompletionRoutine为NULL,并且lpOverlapped的hEvent不为NULL,那么需要hook WSAGetOverlappedResult。因为这时是事件通知。
4、如果lpOverlapped不为NULL,且lpCompletionRoutine为NULL,并且lpOverlapped的hEvent为NULL,那么需要hook GetQueuedCompletionStatus,因为这时是完成端口的方式。

这里还有一个需要注意的地方:如果一个api hook的DLL强行卸载的话会导致调用堆栈出现返回地址错误。 比如GetQueuedCompletionStatus这样的函数, 在进行卸载时, 基本可以肯定程序在原始函数中阻塞,且返回地址为dll模块的地址, 如果这时候卸载HOOK和dll的话,将会导致该函数执行完成后跳到原来dll模块的函数地址, 这时内存已经清空,从而出现访问出错的异常。因此我们需要进行是否函数当前正在等待返回的判断。 如果还有在执行的,我们需要先等待他们返回。最好的方式是设计一个引用计数reference。

当然,除非必要,否则建议不要hook可能阻塞很久的函数,尤其是像GetQueuedCompletionStatus这样的函数,因为系统中很多情况下都会调用该函数,那么在卸载的时候基本可以肯定有两种情况:一是强行卸载,程序必死无疑;二是等待返回,这种情况也基本可以肯定是hook模块也不要想着卸载掉了 ;)

 

//其他参考:

1.http://www.cppblog.com/twzheng/archive/2007/04/16/21991.html;