我写了一个钩子的类,用bc6编译和调用的时候遇到点问题,用bc2010编译变成了局部钩子,大家帮忙看下,谢谢!
这是在头文件声明的THOOK类
- C/C++ code
class THOOK{ FARPROC fp; FARPROC newfp; HMODULE hModule; BYTE OldCode[5]; BYTE NewCode[5]; DWORD OldFnID; DWORD NewFnID; public: int flag; bool bHook; THOOK *next; THOOK(); void HookOn(); void HookOff(); bool init(char *dllname,char *prname,FARPROC MyP); ~THOOK();};THOOK::THOOK(){ flag=-1; bHook=false; for(int i=0;i<5;i++) { OldCode[i]=0xe9; NewCode[i]=0; } fp=NULL; newfp=NULL; hModule=NULL; OldFnID=0; NewFnID=0; next=NULL;}THOOK::~THOOK(){ flag=-1; if(bHook) HookOff(); delete(OldCode); delete(NewCode); fp=NULL; newfp=NULL; hModule=NULL;//用BC6编译时如果调用出错在这里或是构造函数里任意地方添加空行再编译,调用就会成功//这也就是我的第一个问题,用BC2010编译就不会出现调用错误; OldFnID=0; NewFnID=0; if(next) { delete(next); next=NULL; }}bool THOOK::init(char *dllname,char *prname,FARPROC MyP){ hModule=GetModuleHandle(dllname); fp=GetProcAddress(hModule,prname); if(fp==NULL) return false; Move(fp,OldCode,5); newfp=MyP; NewCode[0]=0Xe9; DWORD *addr; addr=(DWORD *)(NewCode+1); *addr=DWORD(newfp)-DWORD(fp)-5; NewFnID=GetCurrentProcessId(); OldFnID=NewFnID; HookOn(); return true;}void THOOK::HookOn(){ OldFnID=NewFnID; HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS,0,OldFnID); VirtualProtectEx(hProc,fp,5,PAGE_READWRITE,&OldFnID); WriteProcessMemory(hProc,fp,NewCode,5,0); VirtualProtectEx(hProc,fp,5,OldFnID,&OldFnID); bHook=true;}void THOOK::HookOff(){ OldFnID=NewFnID; HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS,0,OldFnID); VirtualProtectEx(hProc,fp,5,PAGE_READWRITE,&OldFnID); WriteProcessMemory(hProc,fp,OldCode,5,0); VirtualProtectEx(hProc,fp,5,OldFnID,&OldFnID); bHook=false;}下面是动态链接库程序
- C/C++ code
//---------------------------------------#include <vcl.h>#include <stdio.h>#include <windows.h>#include <winsock2.h>#include "THOOK.h"#pragma hdrstop#pragma argsusedHHOOK g_hHook;HINSTANCE g_hinstDll;THOOK *THookHandle;bool bHooked=false;//--------------------------添加函数需修改部分一------------------------------------const int countP=4;int WINAPI MyRecv(SOCKET s, char FAR* buf, int len, int flags); //---1int WINAPI MySend(SOCKET s, char FAR* buf, int len, int flags); //---2int WINAPI MyConnect( SOCKET s, const struct sockaddr FAR* name, int namelen); //---3int WINAPI MyBind( SOCKET s, const struct sockaddr FAR* name, int namelen); //---4//--------------------------------------------LRESULT WINAPI HookProc(int nCode,WPARAM wParam,LPARAM lParam){ return (CallNextHookEx(g_hHook,nCode,wParam,lParam));}extern "C" bool _declspec(dllexport) _stdcall InstallHook(HWND hWnd){ if(!g_hHook) g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)HookProc,g_hinstDll,0); if(!g_hHook) return false; THOOK *p; p=THookHandle; while(p) { if(!p->bHook) { p->HookOn(); } p=p->next; } bHooked=true; return true;}extern "C" bool _declspec(dllexport) _stdcall UninstallHook(){ bool result=false; if(g_hHook) { result=UnhookWindowsHookEx(g_hHook); if(bHooked) { THOOK *p; p=THookHandle; while(p) { if(p->bHook) p->HookOff(); p=p->next; } bHooked=false; } SendMessage(HWND_BROADCAST,WM_SETTINGCHANGE,0,0); } g_hHook=NULL; return result;}void WINAPI checksum(char FAR* buf ){ int size=20; unsigned long cksum=0; while(size >1) { cksum+=*buf++; size -=sizeof(USHORT); } if(size ) cksum += *(UCHAR*)buf; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); cksum=~cksum; buf[10]=char(cksum&0x00ff); buf[11]=char(cksum>>8);}//--------------------------添加函数需修改部分二------------------------------------int WINAPI MyRecv(SOCKET s, char FAR* buf, int len, int flags){ int res; THOOK *p; p=THookHandle; while(p&&p->flag!=1) { p=p->next; } p->HookOff(); res=recv(s,buf,len,flags); p->HookOn(); return res;}int WINAPI MySend(SOCKET s, char FAR* buf, int len, int flags){ int res; THOOK *p; p=THookHandle; while(p&&p->flag!=2) { p=p->next; } p->HookOff(); res=send(s,buf,len,flags); p->HookOn(); return res;}int WINAPI MyConnect( SOCKET s, const struct sockaddr FAR* name,int namelen){ int res; THOOK *p; p=THookHandle; while(p&&p->flag!=3) { p=p->next; } SOCKADDR_IN Newsin; memcpy(&Newsin,name,namelen); Newsin.sin_family=AF_INET; sendiphdr.destIP=0x0701a8c0; Newsin.sin_port=htons(10026); //for(int i=0;i<8;i++) Newsin.sin_zero[i]=0;这里如果用0填充,端口就会变成10791,ip修改没问题 p->HookOff(); res=connect(s,(LPSOCKADDR)&Newsin, namelen); p->HookOn(); if(res<0) { int err=WSAGetLastError(); String rlt=IntToStr(err); MessageBoxA(NULL,rlt.c_str(),"ERRO",MB_OK); } return res;}int WINAPI MyBind( SOCKET s, const struct sockaddr FAR* name, int namelen){ int res; THOOK *p; p=THookHandle; while(p&&p->flag!=4) { p=p->next; } p->HookOff(); res=MyBind(s,name,namelen); p->HookOn(); MessageBoxA(NULL,"挂钩bind成功!","OK",MB_OK); return res;}//-------------------------------------------#pragma argsusedint WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved){ g_hinstDll=hinst; THOOK *p; switch(reason) { case DLL_PROCESS_ATTACH: { bool hooked[countP]; p=THookHandle; int countnow=0; while(!p&&countnow<countP) { countnow++; if(!THookHandle) { THookHandle=new(THOOK); p=THookHandle; } else { p=THookHandle; while(p->next) { p=p->next; } p->next=new(THOOK); p=p->next; } switch(countnow) {//--------------------------添加函数需修改部分三------------------------------------ case 1: hooked[countnow-1]=p->init("ws2_32.dll","recv",(FARPROC )MyRecv); break; case 2: hooked[countnow-1]=p->init("ws2_32.dll","send",(FARPROC )MySend); break; case 3: hooked[countnow-1]=p->init("ws2_32.dll","connect",(FARPROC )MyConnect); break; case 4: hooked[countnow-1]=p->init("ws2_32.dll","bind",(FARPROC )MyBind); break;//----------------------------------------------- } if(hooked[countnow-1]) { p->flag=countnow; } if(p->flag<countP) p=p->next; //MessageBoxA(NULL,"成功!","OK",MB_OK); } for(int i=0;i<countP;i++) { hooked[0]=hooked[0]&&hooked[i]; hooked[countP-1]=hooked[countP-1]|hooked[i]; } if(!hooked[countP-1]) { MessageBoxA(NULL,"初始化函数错误!","ERROR",MB_OK); return (false); } if(!hooked[0]) { MessageBoxA(NULL,"部分函数无法初始化!","ERROR",MB_OK); return (false); } } break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: if(bHooked&&THookHandle) { delete(THookHandle); } break; } return true;}//---------------------------------------
遇到的问题主要有几点:
1、用BC6编译,钩子是全局的,用BC2010编译钩子是局部的;
2、用BC2010编译调用时不会出错,用BC6编译调用时经常会出错,但是头文件里加减一空行再编译错误就消除了;
3、在钩子卸掉后会导致一些程序出错,比如IE,卸载的时候复原工作也没看出什么问题啊;
4、SOCKADDR_IN结构中的sin_zero[8]在修改ip和port后填0,修改的ip正常,但是port却还是原来的
重点还是第2、3个问题,我想了很久没想明白,是我的编译器有问题还是在哪里疏漏了什么,,哪位大侠能指导下,谢谢!
[解决办法]
感觉不对哦, 你 HookOff HookOn 函数实际上并没有执行同步保护。
想想, 目标程序多线程调用 Socket 函数, 假如现在一个线程刚进入你的 MyRecv 函数,你在函数中调用了 HookOff , 然后调用实际的 recv 功能, 由于 recv 功能耗时, 在recv 函数还没有返回的时候,
注意,这个时候第二个线程也开始调用你的 MyRecv 函数, 也执行 HookOff 功能了, 想想是否混乱了?
[解决办法]
也不对, 应该创建一个同步区段来控制, HookOff 中加锁, 其他线程调用 HookOff 会阻塞, 直到前一个线程调用 HookOn 解锁之后, 其他线程被阻塞的 HookOff 才能继续
[解决办法]
这个判断语句 while(!bHook){}
也不是一个线程安全的操作。 想想: 两个线程, 第一个发现 bHook 为 false, 那么它就会去执行一些操作, 然后设置 bHook 为 true. 关键是, 在它执行操作的过程中, bHook 仍然为 false , 此时另一个线程发现是 false 也会去执行相关的操作。