MHOOK的使用

Home / Article MrLee 2014-12-17 8536

之前写外挂都用的是网上的帖子HOOK目标程序的send和recv,然后采用WriteProcessMemory替换我们的函数和Windows API函数,不断的来回切换,这个其实数据密集的时候容易出错也不稳定,不提倡!并且代码输写很容易出错。这里我贴出我自己写过的HOOK库,用过攻城略地和大皇帝等等游戏,均通过测试,非常之稳定。 把MHOOK封装成动态链接库,直接调用DLL文件进行HOOK目标函数,也可以实现远程注入。并且不会被游戏反外挂发觉。动态链接库代码如下:
//Copyright (c) 2007-2008, Marton Anka
//
//Permission is hereby granted, free of charge, to any person obtaining a
//copy of this software and associated documentation files (the "Software"),
//to deal in the Software without restriction, including without limitation
//the rights to use, copy, modify, merge, publish, distribute, sublicense,
//and/or sell copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included
//in all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//IN THE SOFTWARE.
#ifdef _M_IX86
#define _M_IX86_X64
#elif defined _M_X64
#define _M_IX86_X64
#endif
BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction);
BOOL Mhook_Unhook(PVOID *ppHookedFunction);
#define MHOOKS_MAX_SUPPORTED_HOOKS 64

我这里只针对HOOK socket的send和recv
// mk.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "mhook-lib/mhook.h"
extern mhook_func _msend;
extern mhook_func _mrecv;
extern mhook_func _mwsend;
extern mhook_func _mwrecv;
//ppSystemFunction为系统API,pHookFunction为自己定义的API
BOOL t001(PVOID *ppSystemFunction, PVOID pHookFunction)
{
return Mhook_SetHook(ppSystemFunction,pHookFunction);
}
//pHookFunction为自己定义的API
BOOL t002(PVOID *ppHookedFunction)
{
return Mhook_Unhook(ppHookedFunction);
}
//设置1.0函数地址
BOOL t003(mhook_func pHookSendFunc,mhook_func pHookRecvFuc)
{
_msend = pHookSendFunc;
_mrecv = pHookRecvFuc;
return TRUE;
}
//设置2.0函数地址
BOOL t004(mhook_func pHookSendFunc,mhook_func pHookRecvFuc)
{
_mwsend = pHookSendFunc;
_mwrecv = pHookRecvFuc;
return TRUE;
}

DLL入口文件
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include "mhook-lib/mhook.h"
#include
//////////////封包函数//////////////
static void GT_WriteReleaseLog(char* str,char* path="C:\mk.log")
{
HANDLE hFile = CreateFileA(path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == NULL)
return;
//设置文件中进行读写的当前位置
_llseek((HFILE)hFile,0, SEEK_END);
DWORD dw;
WriteFile(hFile,str,strlen(str),&dw,NULL);
_lclose((HFILE)hFile);
}
HMODULE hMod = LoadLibraryA("Ws2_32");
//1.0
typedef int (WINAPI *_send)(SOCKET s, const char *buf, int len, int flags);
typedef int (WINAPI *_recv)(SOCKET s, char *buf, int len, int flags);
_send g_trueSend = (_send)GetProcAddress(hMod,"send");
_recv g_trueRecv = (_recv)GetProcAddress(hMod,"recv");
//2.0
typedef int (WINAPI *_wsend)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
typedef int (WINAPI *_wrecv)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
_wsend g_trueWSend = (_wsend)GetProcAddress(hMod,"WSASend");
_wrecv g_trueWRecv = (_wrecv)GetProcAddress(hMod,"WSARecv");
mhook_func _msend = NULL;
mhook_func _mrecv = NULL;
mhook_func _mwsend = NULL;
mhook_func _mwrecv = NULL;
/**
参数描述:
SOCKET s 发送端套接字描述符
const char *buf 应用程序要发送的数据的缓冲区(想要发送的数据)
int len 实际要发送的字节数
int flags 一般置为0即可
如果没有错误发生,send将返回的总字节数发送
*/
int WINAPI hook_send(SOCKET s, const char *buf, int len, int flags)
{
int ret = g_trueSend(s,buf,len,flags);
if (ret > 0)
{
char *temp = new char[ret];
memcpy_s(temp,ret,buf,ret);
if(_msend != NULL)
_msend(s,temp,ret);
delete temp;
}
return ret;
}
/**
参数描述:
SOCKET s 发送端套接字描述符
const char *buf 应用程序存放接收的数据的缓冲区
int len buf的长度
int flags 一般置为0即可
如果没有错误发生,recv返回的字节数的接收
*/
int WINAPI hook_recv(SOCKET s, char *buf, int len, int flags)
{
int ret = g_trueRecv(s,buf,len,flags);
if (ret > 0)
{
char *temp = new char[ret];
memcpy_s(temp,ret,buf,ret);
if(_msend != NULL)
_mrecv(s,temp,ret);
delete temp;
}
return ret;
}
/*
s:标识一个已连接套接口的描述字。
lpBuffers:一个指向WSABUF结构数组的指针。每个WSABUF结构包含缓冲区的指针和缓冲区的大小。
dwBufferCount:lpBuffers数组中WSABUF结构的数目。
lpNumberOfBytesSent:如果发送操作立即完成,则为一个指向所发送数据字节数的指针。
dwFlags:标志位。
lpOverlapped:指向WSAOVERLAPPED结构的指针(对于非重叠套接口则忽略)。
lpCompletionRoutine:一个指向发送操作完成后调用的完成例程的指针。(对于非重叠套接口则忽略)。
若无错误发生且发送操作立即完成,则WSASend()函数返回0
*/
int WINAPI hook_wsend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
int ret = g_trueWSend(s,lpBuffers,dwBufferCount,lpNumberOfBytesSent
,dwFlags,lpOverlapped,lpCompletionRoutine);
DWORD len = *lpNumberOfBytesSent;
if (len > 0)
{
char *temp = new char[len];
memcpy_s(temp,len,lpBuffers->buf,len);
if(_mwsend != NULL)
_mwsend(s,temp,len);
delete temp;
}
return ret;
}
int WINAPI hook_wrecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
int ret = g_trueWRecv(s,lpBuffers,dwBufferCount,lpNumberOfBytesRecvd,lpFlags
,lpOverlapped,lpCompletionRoutine);
DWORD len = *lpNumberOfBytesRecvd;
if (len > 0)
{
char *temp = new char[len];
memcpy_s(temp,len,lpBuffers->buf,len);
if(_mwrecv != NULL)
_mwrecv(s,temp,len);
delete temp;
}
return ret;
}
BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//直接在这里HOOK SEND和RECV函数
Mhook_SetHook((LPVOID*)&g_trueSend,hook_send);
Mhook_SetHook((LPVOID*)&g_trueRecv,hook_recv);
Mhook_SetHook((LPVOID*)&g_trueWSend,hook_wsend);
Mhook_SetHook((LPVOID*)&g_trueWRecv,hook_wrecv);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
//直接在这里UNHOOK SEND和RECV函数)
Mhook_Unhook((LPVOID*)&g_trueSend);
Mhook_Unhook((LPVOID*)&g_trueRecv);
Mhook_Unhook((LPVOID*)&g_trueWSend);
Mhook_Unhook((LPVOID*)&g_trueWRecv);
if(hModule != NULL)
FreeLibrary(hModule);
break;
}
return TRUE;
}

最后加上DEF文件
LIBRARY
EXPORTS
; 此处可以是显式导出
t001 @1
t002 @2
t003 @3
t004 @4

MHOOK代码网上有下载,这里我就不贴出来了。
看我写的工具抓的包,如图

20141217223605

本文链接:https://www.it72.com/456.htm

推荐阅读
最新回复 (10)
  • LouellaShackelfo 2016-1-14
    引用 2
    extern mhook_func _msend; extern mhook_func _mrecv; extern mhook_func _mwsend; extern mhook_func _mwrecv; 这个 mhook_func是怎么定义的,大神 代码里没有呢
  • kkae8643158 2016-5-3
    引用 3
    typedef void (WINAPI *mhook_func)(char *buf, int len);
  • Darlene54I 2016-5-3
    引用 4
    函数t003,t004是做什么使用的呢?并没有看见调用,还是说blog里边只是一部分代码呢
  • dasong 2016-5-4
    引用 5
    3是hook 1.0的函数,4是hook2.0的函数。分别是send,recv,wsend,wrecv
  • wssssss 2016-5-4
    引用 6
    好的,那代码中使用的hMod应该也要做释放处理吧
  • bsam 2016-5-4
    引用 7
    你自己看下,我很久没看代码了。 之前是随便封装下,不写Hook字段是避免有些杀毒软件检测关键字,比如360这垃圾。
  • amirassari2002 2016-5-4
    引用 8
    这篇文章对我很有用,谢谢。或者可以 _send g_trueSend = (_send)GetProcAddress(GetModuleHandle(L"Ws2_32"),"send"); 额,我不太会使用Windows的函数,,,如果错了,额,那就回复告诉我一声,最近在找拦截API出现异常崩溃的原因,如果有这方面经验,求分享,先谢谢你了。
  • uleven 2016-5-4
    引用 9
    好的,谢谢
  • Will40877336781 2016-5-4
    引用 10
    多查阅下资料就知道了。这是获取系统的真实api函数地址,我们要在这个函数之前处理一些数据,最后调用这个函数。
  • haidemeng 2016-7-8
    引用 11
    楼上能不能分享下C# 跨进程调用此DLL的方法。
返回