分析完了数据,我们开始写程序了
首先我们创建一个MFC的解决方案,然后在解决方案中添加一个dll新项目
名称大家可以自拟
Dll中我们写hook函数,MFC作为交互窗体
首先我们开始写dll
经过分析游戏所需协议,发现我们需要hook的只是socket中TCP的send和recv两个函数
我们先创建一个IPPackLib.h的头文件,这个文件我们保存的是数据存放类型和自定义信息
看一些源码,应该不难懂的
#ifndef __IPPACKLIB_H__
#define __IPPACKLIB_H__
struct CMessageData//数据类型
{
intnDataLength;
TCHAR* data()
{ return(TCHAR*)(this+1); }//真正的数据在这个类型所占内存的后边
};
enum HOOK_MESSAGE//自定信息,作用是告诉MFC有新的HOOK消息
{
HM_RECEIVE = WM_USER + 100,
};
#endif
然后我们在新建一个ShareMemory.h的头文件,作用是共享内存到MFC,共享内存是一种不同线程间传递信息的方式。效率很高的, 注释很详细,我们看一下源码,具体共享内存是怎样实现的,读者可以百度一下,鉴于字数要求,我就不copy过来了
#ifndef __SHAREMEMORY_H__
#define __SHAREMEMORY_H__
class CShareMemory
{
public:
// 构造函数和析构函数
CShareMemory(constchar * pszMapName, intnFileSize = 0, BOOL bServer = FALSE);
~CShareMemory();
// 属性
LPVOID GetBuffer() const{ return m_pBuffer; }
// 实现
private
HANDLE m_hFileMap;
LPVOID m_pBuffer;
};
inline CShareMemory::CShareMemory(constchar *pszMapName,
intnFileSize, BOOL bServer) : m_hFileMap(NULL), m_pBuffer(NULL)
{
if(bServer)
{
// 创建一个内存映射文件对象
m_hFileMap =CreateFileMapping(INVALID_HANDLE_VALUE,
NULL, PAGE_READWRITE, 0, nFileSize,pszMapName);
}
else
{
// 打开一个内存映射文件对象
m_hFileMap =OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, pszMapName);
}
// 映射它到内存,取得共享内存的首地址
m_pBuffer = (LPBYTE)MapViewOfFile(m_hFileMap,FILE_MAP_ALL_ACCESS,0,0,0);
}
inline CShareMemory::~CShareMemory()
{
// 取消文件的映射,关闭文件映射对象句柄
UnmapViewOfFile(m_pBuffer);
CloseHandle(m_hFileMap);
}
#endif// __SHAREMEMORY_H__
在新建一个ULHook.h的头文件
Hook一个函数其实就是把应用程序调用的函数的前8字节内存修改,从而使那个函数转到自己写的函数上来,所以这里我写了一个类来保存原函数的地址,新函数的地址和实现挂钩等功能的类
#ifndef __ULHOOK_H__
#define __ULHOOK_H__
#include<windows.h>
class CULHook
{
public:
CULHook(LPSTR pszModName, LPSTR pszFuncName,PROC pfnHook,bool ifbegin);
~CULHook();
// 取消挂钩
voidUnhook();
// 重新挂钩
voidRehook();
protected:
PROC m_pfnOrig; // 目标API函数的地址
BYTE m_btNewBytes[8]; // 新构建的8个字节
BYTE m_btOldBytes[8]; // 原来8个字节
HMODULE m_hModule;
};
#endif// __ULHOOK_H__
这样,我们的头文件就完成了,接下来我们开始源文件的编写
新建一个IPPackLib.cpp的源文件,实现新函数的储存和挂钩等功能
应该可以读懂的,时间要求,直接上源码了
///////////////////////////////////////////
//IPHookLib.cpp文件
#include<Winsock2.h>
#include"ShareMemory.h"
#include"ULHook.h"
#include"IPPackLib.h"
#pragmacomment(lib, "WS2_32")
// 共享数据区
HWND g_hWndCaller =NULL;
HHOOK g_hHook =NULL;
#pragmadata_seg()
char* StringToJinZhi16(char*Date,int BegPos,intEndPos);
void SndMsg(char*Msg);
extern CULHook g_recv;
extern CULHook g_send;
int WINAPI hook_recv(SOCKET s, char *buf, int len, int flags)
{
// 调用原来的函数,接受数据,设置参数
g_recv.Unhook();
//将信息给被hook的应用程序发过去
int nRet =recv(s, buf, len, flags);
if (len <50 && strcmp(StringToJinZhi16(buf,0,4),"1140 01 00 "))
{
CShareMemory sm("IPPACK_RECEIVE",sizeof(CMessageData) + len, TRUE);
CMessageData *pData =(CMessageData*)sm.GetBuffer();
memcpy(pData->data(),buf,nRet);
pData->nDataLength = nRet;
// 通知主窗口,进行过滤
SendMessage(g_hWndCaller, HM_RECEIVE, 0,0);
}
g_recv.Rehook();
return nRet;
}
int WINAPI hook_send(SOCKET s, constchar* buf, int len, int flags)
{
// 申请指定长度的共享内存空间
CShareMemory sm("IPPACK_RECEIVE",sizeof(CMessageData) + len, TRUE);
// 取得指向共享内存的指针
CMessageData *pData =(CMessageData*)sm.GetBuffer();
pData->nDataLength = len;
memcpy(pData->data(), buf,pData->nDataLength);
// 通知主窗口,进行过滤
::SendMessage(g_hWndCaller, HM_RECEIVE, 0,0);
// 调用原来的函数,发送数据
g_send.Unhook();
int nRet =::send(s, pData->data(), pData->nDataLength, flags);
if(!strcmp(StringToJinZhi16((char*)buf,0,3),"0140 01 ")){
SndMsg("ss2");
g_recv.Rehook();
}
else
g_send.Rehook();
return nRet;
}
void SndMsg(char*Msg)
{
// 申请指定长度的共享内存空间
CShareMemory sm("IPPACK_RECEIVE",sizeof(CMessageData) + 3, TRUE);
// 取得指向共享内存的指针
CMessageData *pData =(CMessageData*)sm.GetBuffer();
pData->nDataLength = 3;
memcpy(pData->data(), Msg,pData->nDataLength);
// 通知主窗口,进行过滤
::SendMessage(g_hWndCaller, HM_RECEIVE, 0,0);
}
char* StringToJinZhi16(char*Date,int BegPos,intEndPos)
{
char* pBuf =newchar[(EndPos- BegPos)*3];
// 转化截获的数据为16进制字符串的形式
char* pTemp= pBuf;
char* psz =Date;
psz+=BegPos;
for(int i=BegPos; i<EndPos; i++, psz++)
{
wsprintf(pTemp, "%02x", (BYTE)(*psz));
pTemp += 3;
}
return pBuf;
}
CULHook g_send("Ws2_32.dll", "send",(PROC)hook_send,true);
CULHook g_recv("Ws2_32.dll", "recv",(PROC)hook_recv,false);
////////////////////////////////////////////
static HMODULE ModuleFromAddress(PVOID pv)
{
MEMORY_BASIC_INFORMATION mbi;
if(::VirtualQuery(pv,&mbi, sizeof(mbi)) != 0)
{
return(HMODULE)mbi.AllocationBase;
}
else
{
returnNULL;
}
}
static LRESULT WINAPI GetMsgProc(int code, WPARAM wParam, LPARAM lParam)
{
return::CallNextHookEx(g_hHook, code, wParam, lParam);
}
BOOL WINAPISetHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller)
{
BOOL bOk;
g_hWndCaller = hWndCaller;
if(bInstall)
{
g_hHook =::SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc,
ModuleFromAddress(GetMsgProc),dwThreadId);
bOk = (g_hHook != NULL);
SndMsg("ss1");
}
else
{
bOk = ::UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
return bOk;
}
之后我们写一个IPPackLib.def的附加文件
EXPORTS
SetHook
DEF文件就是将DLL的函数入口导出,使程序可以正确访问
然后我们添加ULHook.CPP文件,一看名字就知道是完成ULHook.h功能的源文件,不多说,上源码
///////////////////////////////////////////
//ULHook.cpp文件
#include"ULHook.h"
CULHook::CULHook(LPSTRpszModName, LPSTR pszFuncName, PROC pfnHook,boolifbegin)
{
BYTE btNewBytes[8] = { 0xB8, 0x00, 0x00,0x40, 0x00, 0xFF, 0xE0, 0x00 }; //这个翻译成汇编的功能就是函数跳转
memcpy(m_btNewBytes, btNewBytes, 8);
*(DWORD *)(m_btNewBytes + 1) =(DWORD)pfnHook;
// 加载指定模块,取得API函数地址
m_hModule = ::LoadLibrary(pszModName);
if(m_hModule== NULL)
{
m_pfnOrig = NULL;
return;
}
m_pfnOrig = ::GetProcAddress(m_hModule,pszFuncName);
// 修改原API函数执行代码的前8个字节,使它跳向我们的函数
if(m_pfnOrig!= NULL)
{
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
::VirtualQuery( m_pfnOrig, &mbi, sizeof(mbi) );
::VirtualProtect(m_pfnOrig, 8, PAGE_READWRITE,&dwOldProtect);
// 保存原来的执行代码
memcpy(m_btOldBytes, m_pfnOrig, 8);
// 写入新的执行代码
::WriteProcessMemory(::GetCurrentProcess(),(void *)m_pfnOrig,
m_btNewBytes, sizeof(DWORD)*2, NULL);
::VirtualProtect(m_pfnOrig, 8,mbi.Protect, 0);
}
if(!ifbegin)
{
Unhook();
}
}
CULHook::~CULHook()
{
Unhook();
if(m_hModule!= NULL)
::FreeLibrary(m_hModule);
}
void CULHook::Unhook()
{
if(m_pfnOrig!= NULL)
{
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
::VirtualQuery(m_pfnOrig, &mbi, sizeof(mbi));
::VirtualProtect(m_pfnOrig, 8,PAGE_READWRITE, &dwOldProtect);
// 写入原来的执行代码
::WriteProcessMemory(::GetCurrentProcess(),(void *)m_pfnOrig,
m_btOldBytes, sizeof(DWORD)*2, NULL);
::VirtualProtect(m_pfnOrig, 8,mbi.Protect, 0);
}
}
void CULHook::Rehook()
{
// 修改原API函数执行代码的前8个字节,使它跳向我们的函数
if(m_pfnOrig!= NULL)
{
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
::VirtualQuery( m_pfnOrig, &mbi, sizeof(mbi) );
::VirtualProtect(m_pfnOrig, 8,PAGE_READWRITE, &dwOldProtect);
// 写入新的执行代码
::WriteProcessMemory(::GetCurrentProcess(),(void *)m_pfnOrig,
m_btNewBytes, sizeof(DWORD)*2, NULL);
::VirtualProtect(m_pfnOrig, 8,mbi.Protect, 0);
}
}
好了,编译DLL就可以了
因为时间要求,教程比较粗略,如果有错误请指出,如果有问题,可以留言。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
http://wuqinzhong.blog.163.com/blog/static/4522231200932542020736/