跨进程API Hook

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

跨进程API Hook(初稿)

detrox

什么是“跨进程 API Hook”?

众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。

API Hook 理论

通过对Win32 PE文件的分析(如果你还不熟悉PE文件格式,可以看看Iczelion的PE教程或者LUEVELSMEYER的<<The PE File Format>>)。我们知道在PE文件中的IMPORT TABLE内存储着API函数的很多信息。其中包括API的函数名,调用地址等等。而操作系统在执行PE文件时会先将其映射到内存中。在映射的同时还会把当前版本操作系统中API函数的入口地址写入IMPORT TABLE中一组与API调用相关的结构体内,用于该应用程序的API调用。 当应用程序调用API时,他会在自己内存映像里寻找API的入口地址,然后执行CALL指令。如此一来,我们通过修改应用程序内存映像的IMPORT TABLE中API函数的入口地址,就可以达到重定向API的目的。将API地址改为我们自己函数的地址,这样我们的函数就可以完成对API的监视和控制了。

API Hook 的实现

/* 1 */HANDLE hCurrent = GetModuleHandle(NULL);
/* 2 */IMAGE_DOS_HEADER *pidh;
/* 3 */IMAGE_NT_HEADERS *pinh;
/* 4 */IMAGE_DATA_DIRECTORY *pSymbolTable;
/* 5 */IMAGE_IMPORT_DESCRIPTOR *piid;
 
/* 6 */pidh = (IMAGE_DOS_HEADER *)hCurrent; 
/* 7 */pinh = (IMAGE_NT_HEADERS *)((DWORD)hCurrent + pidh->e_lfanew);
/* 8 */pSymbolTable = &pinh->OptionalHeader.DataDirectory[1];
/* 9 */piid =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)hCurrent +  pSymbolTable->VirtualAddress);
/*10 */do {
/*11 */    IMAGE_THUNK_DATA *pitd,*pitd2;
/*12 */    pitd = (IMAGE_THUNK_DATA *)((DWORD)hCurrent + piid->OriginalFirstThunk);
/*13 */    pitd2 = (IMAGE_THUNK_DATA *)((DWORD)hCurrent + piid->FirstThunk);
/*14 */    do {
/*15 */ IMAGE_IMPORT_BY_NAME *piibn;
/*16 */ piibn = (IMAGE_IMPORT_BY_NAME *)((DWORD)hCurrent +  *((DWORD *)pitd));
/*17 */ PROC *ppfn = (PROC *)(pitd2->u1.Function);
/*18 */ if (!strcmp("MessageBoxW",(char *)piibn->Name)) {
/*19 */     oldMsg = (MsgBoxType)(ppfn);
/*20 */     DWORD addr = (DWORD)MyMessage;
/*21 */     DWORD written = 0;
      /* 改变内存读写状态 */
/*22 */     DWORD oldAccess;
/*23 */     VirtualProtect(&pitd2->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
/*24 */     APIAddress = (DWORD)&pitd2->u1.Function;
      /* 向内存映像写入数据 */
/*25 */     WriteProcessMemory(GetCurrentProcess(),&pitd2->u1.Function, &addr,sizeof(DWORD), &written);
/*26 */ }
/*27 */ pitd++;pitd2++;
/*28 */    } while (pitd->u1.Function);
 
/*29 */    piid++;
/*30 */} while (piid->FirstThunk + piid->Characteristics 
  + piid->ForwarderChain + piid->Name + piid->TimeDateStamp);

分析:

寻觅IMPORT TALBE

在/*1*/中我们使用GetModuleHandle(NULL)来返回当前进程在内存中映像的基地址。但这个值在文档中仅仅被描述为"a module handle for the specified module",虽然他确实是进程内存映像的基地址。如果你不太放心的话也可以使用,GetModuleInformation函数来获得基地址,只不过你要额外包含psapi.h和psapi.lib了(这个库在VC6里没有,所以我就没有用这个函数了)。在/* 6 */里我们先找到IMAGE_DOS_HEADER结构,他的起始地址就是映像的基地址。/*7*/通过IMAGE_DOS_HEADER给出的PE文件头的偏移量,找到IMAGE_NT_HEADERS结构。顺藤摸瓜,IMAGE_NT_HEADERS里的OptionalHeader中的DataDirectory数组里的第二个元素正是指向我们想要的IMPORT TABLE的地址。在/*9*/中我们将其转化为一个IMAGE_IMPORT_DESCRIPTOR的结构指针存入piid中。

替换的API函数入口地址

在/*12*/和/*13*/中我们分别取得OriginalFirstThunk和FirstThunk结构,用于以后得到API函数的名称和入口地址。/*10*/的do循环让我们遍历每一个IMAGE_IMPORT_DESCRIPTOR结构也就是应用程序引用的每个DLL。在/*14*/的循环中我们遍历DLL中的IMAGE_THUNK_DATA结构来一一查询API的信息。/*16*/中我们将OriginalFirstThunk转换为IMAGE_IMPORT_BY_NAME结构用于获得API函数的名称进行比对。在/*18*/我们找到MessageBoxW函数之后,在/*19*/保存其原始入口地址便于以后恢复时使用。在/*23*/我们需要用VirtualProtect改变一下内存区域的读写性,因为一般应用程序的映像都是只读的,直接写入会造成一个非法访问的异常出现。在/*25*/我们写入自己函数的地址。

这样就基本完成一个API函数的重定向。

其他

恢复函数的API入口地址相对比较简单。只要把保存的值再写回去就可以了。上面的程序中/*24*/我用APIAddress保存了存有MessageBoxW入口地址的地方的地址,便于以后调用WriteProcessMemory恢复时使用。

跨进程理论

我们要用自己的函数来替代别人程序里的API函数,但我们的函数与别人的程序处于不同的进程空间内啊。不同的进程空间是不能相互调用函数的。因此我们要想办法把自己的函数放入别人的进程空间去。这时我们就需要使用DLL injection技术了。如果你对她还不是十分熟悉的话,建议看看Jeffrey Richter大师的<<Programming Applications for Microsoft Windows>>,也可以参考陈宽达先生的<<C++ Builder深度历险>>。

简而言之,DLL injection就是想办法让对方的进程加载我们的一个DLL程序,把需要替换的函数放在我们这个DLL里。如此一来,我们的函数就进入了别人的进程空间了。DLL injection方法很多,Richter大师在书中对各方法利弊有详细解释,陈宽大先生的书中也有深入的分析。我在这里使用SetWindowsHookEx函数来达到目的。主要有这几个原因: 1, 不用重新启动系统,调试方便。2, 可以利用消息循环机制进行两个进程之间的通信,可以较好的掌握Hook的状态。便于安装与卸载。

SetWindowsHookEx之所以能完成DLL injection是因为它要给一个应用程序某个环节加上一个Hook,而Hook就要有Hook Procedure也就是Hook函数。如果这个Hook函数在一个DLL中,那么系统就会把这个DLL加载到SetWindowsHookEx的目标进程上。从而也就达到了我们DLL injection的目的了。当然这里我们会用WH_GETMESSAGE的Hook进行injection,因为这个Hook可以用来监视目标进程的消息循环方便我们的进程与目标进程通信。

跨进程的实现和几点注意

/* DllPart.Dll */
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef (WINAPI *MsgBoxType)(HWND,LPCWSTR,LPCWSTR,UINT); 
MsgBoxType oldMsg;  /*API原入口地址*/
DWORD APIAddress; /*存储API入口地址的地方的地址*/
int WINAPI  MyMessage(HWND hWnd ,LPCWSTR M1,LPCWSTR M2, UINT M3) {
 /* 这是用来替换的函数 */
 return oldMsg(hWnd,buf,M2,MB_OK);
}
const char szApp[] = "DllPart.dll";
HHOOK hHook; /*Hook的句柄*/
HMODULE hInst; /*DLL 模块句柄,用于SetWindowsHookEx函数*/
HWND hTarget; /*目标窗口句柄*/
/*DLL 入口*/
BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID lpvReserved)
{
    hInst = inst;
    switch (reason) {
 case DLL_PROCESS_ATTACH:
     /*调试信息,表示DLL已经加载*/
     MessageBox(NULL,"DLL_PROCESS_ATTACH",szApp,MB_OK);
     break;
 case DLL_PROCESS_DETACH:
     /*调试信息,表示DLL已经卸载*/
     MessageBox(NULL,"DLL_PROCESS_DETACH",szApp,MB_OK);
     break;
    }
    return true;
}
/*显示GetLastError的信息*/
void showerr(const char *m) {
    char message[255];
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError()
 ,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,255, 0);
    MessageBox(NULL,message,m,MB_OK);
}
//-----------------------
void UnHookApi() {
 /*卸载API Hook用*/
}
void HookApi() {
 /*加载API Hook同上面介绍的函数一样*/
}
//-----------------------
/*用于WH_GETMESSAGE的Hook Procedure*/
LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam) {
 if (nCode == HC_ACTION) {
     MSG *msg = (MSG *)lParam;
     if (msg->message == WM_CHAR) {
      if (msg->wParam == 'h') HookApi();
      if (msg->wParam == 'u') UnHookApi();
     }
 }
    return CallNextHookEx(hHook,nCode,wParam,lParam);
}
extern "C" __declspec(dllexport) SetAPIHook(HWND handle) {
    DWORD ThreadId = GetWindowThreadProcessId(handle, NULL);
    hTarget = handle;
    MessageBox(NULL, "Enabling CallWndProc Hook", szApp, MB_OK);
    hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,ThreadId); 
    if (hHook) {
 MessageBox(NULL,"Hook OK!", szApp, MB_OK);
    } else {
 showerr("SetWindowsHookEx");
    }
}
extern "C" __declspec(dllexport) UnHookAPIHook() {
    MessageBox(NULL, "Disenabling CallWndProc Hook", szApp, MB_OK);
    if (UnhookWindowsHookEx(hHook)) {
        MessageBox(NULL,"UnHook OK!", szApp, MB_OK); 
    } else {
 showerr("UnHookWindowsHookEx");
    }
}

分析

几个需要注意的问题

SetAPIHook和UnHookAPIHook是我们自己进程调用的用来加载WH_GETMESSAGE Hook的函数。由于我们的程序要用LoadLibrary加载这个Dll因此这两个函数要用__declspec(dllexport)修饰,使其成为导出函数,才能被GetAddressProc函数找到。加上 extern "C"是让编译器使用C语言编码方式。因为C++编译器会进行Dynamic Binding(C++函数重载的实现),将函数的参数类型附加到名称上。是函数的导出名看起来像SetAPIHook@XYTZX之类的,不利于GetAddressProc进行引用。因此使用extern "C"让编译器不使用Dynamic Binding,自然使用extern"C"的函数也就不能被重载了。

不要忘记在GetMsgProc最后要调用CallNextHookEx函数,保证Hook链的完整性。

一定要在Hook Procedure中调用HookApi和UnHookApi函数,因为保存API入口地址的地方在目标进程中,你必须在目标进程的进程空间内完成卸载操作,不能在UnHookAPIHook或是SetAPIHook函数中调用,因为UnHookAPIHook是我们的进程调用的,因此在我们的进程空间中。在这里使用UnHookApi会造成一个非法访问的错误。而使用HookApi会给自己的DLL加上API Hook。

SetWindowsHookEx的最后参数是ThreadId不是Handle,因此要通过调用GetWindowThreadProcessId转换一下。

在跨进程API HOOK时可能用到的其他技术

主进程与目标进程的信息交互和共享

由于使用了WH_GETMESSAGE钩子我们可以利用Windows消息机制实现进程间通讯。需要注意的是应该使用PostThreadMessage来发送让WH_GETMESSAGE得到的消息而不是SendMessage或者PostMessage,因为后两个是用来给窗口发送消息的。而我们的WH_GETMESSAGE是Hook在线程上面的,因此需使用PostThreadMessage.

传递不太大的数据可以使用WM_COPYDATA消息来进行。同样也应该注意,如果使用MFC的窗口过程获得消息就需要用SendMessage发送了。WM_COPYDATA的使用相对简单可以参考MSDN的文档。也可以参考附录里的程序Hook.cpp的showerr函数部分。

如果传递较大的数据或者希望数据共享比较方便可以开辟共享内存来进行数据共享。这里简单分析一下使用共享内存的代码

HANDLE hMap;
switch (reason) {
    case DLL_PROCESS_ATTACH:
    /*创建/打开共享内存区域*/
    hMap = CreateFileMapping((HFILE *)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);
    pg_data = (GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0 ,0 ,0);
    if (!pg_data) {
 MessageBox(NULL,"无法建立共享内存,程序终止!",szApp,MB_OK);
 if (hMap) {
     CloseHandle(hMap);
     hMap = NULL;
     return 0;
       }
    }
    pg_data->hInst = hInst;
    showerr("共享内存映像文件");
    showerr("DLL装载中...",FALSE);
    break;
    case DLL_PROCESS_DETACH:
    if (pg_data) {
        UnmapViewOfFile(pg_data);
 pg_data = NULL;
    }
    if (hMap) {
 CloseHandle(hMap);
 hMap = NULL;
     }
    break;
}
上面的代码通过CreateFileMapping建立共享区域。将其第一个参数设置为0xFFFFFFFF使其能创建一个内存共享区域而不是文件。并标记为可读写的(PAGE_READWRITE).其大小为我们定义的结构体GLOBALDATA的大小。最后的ID_MAP是一个用来标示这个区域的字符串。打开或者创建完共享区域后,我们用MapViewOfFile来获得这个区域的地址。之后就可以直接使用pg_data来操作共享区域了。不要忘记在DLL退出的时候安全的删除共享区域释放内存。
消息等待与安全卸载

在我们卸载WH_GETMESSAGE钩子之前必须先把目标程序的API调用恢复正常。我们不能再调用UnHookApi之后就立刻调用UnhookWindowsHookEx,因为很有可能UnHookApi还没来得急完成API入口地址的恢复操作,WH_GETMESSAGE钩子就已经被卸载了。因此需要等待一段时间,等UnHookApi完成了恢复操作在调用UnhookWindowsHookEx。以防错误发生。

extern "C" __declspec(dllexport) void UnHookAPIHook() {
    /*向目标线程发送消息进行API UNHOOK*/
    PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
    showerr("WM_DISABLEAPIHOOK");
    /*等待目标进程返回WM_UNHOOKOK消息,确认可以将WH_GETMESSAGE的HOOK去掉*/
    
    MSG Msg;
    do {
        GetMessage(&Msg,NULL,0,0);
    }while(Msg.message !=  WM_UNHOOKOK);
    UnhookWindowsHookEx(pg_data->hHook);
    PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);
    showerr("UnHookWindowsHookEx");
}
上面的代码中我们使用一个含有GetMessage的循环来等待消息的到达,一旦UnHookApi完成他就会发送WM_UNHOOKOK消息。等我们接收到消息确认一切安全了在来卸载WH_GETMESSAGE钩子。
弄清消息对象

我们一定要清楚代码是在主程序进程空间中执行的还是在目标程序进程空间中执行的。像上面的UnHookAPIHook函数就是通过主程序调用的,因此在主程序进程空间中执行。这样一来用来恢复目标程序API信息的UnHookApi完成后就应该向主程序发送消息,而不是目标程序。

目标进程加载了其他DLL

如果目标进程动态加载了其他的DLL文件,我们必须监视LoadLibrary函数。保证DLL中的API入口地址也被正确修改。防止出现混乱的情况。我从LoadLibrary获得DLL的路径用于GetModuleHandle来取得他的ImageBase的地址。

不知道文章写的如何,希望大家能多给些批评意见。发现问题我马上改正

Email: detrox@yang.com.cn

参考资料

<<Programming Applications for Microsoft Windows>>, Jeffrey Richter, Microsoft Press

<<C++ Builder 深度历险>>,陈宽达,华中科大出版社

<<The PE File Format>>, LUEVELSMEYER

<<Iczelion's PE Tutorial>>, Iczelion

附:跨进程APIHook的例子

先打开一个记事本程序并输入几个字符,运行下面的程序,加载APIHook.之后在记事本的文件菜单中选择新建就会看到API Hook将MessageBoxW 函数Hook的结果了.
代码在WinXP SP1 + VC6.0测试成功。

下载源代码

(特别感谢老罗的代码着色器,比我自己那个好多了)

这是DLL的程序,Hook.dll
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mydef.h"

const char szApp[] = "Hook.dll"/*应用程序名称*/
HANDLE hMap;/*在共享内存映像的句柄*/
GLOBALDATA *pg_data; /*在共享内存中的全局数据*/
LRESULT CALLBACK GetMsgProc(int,WPARAM, LPARAM);

/*显示GetLastError指出的错误*/
void showerr(const char *m, BOOL GetError = TRUE) {
    char message[127];
    char buf[255];
    COPYDATASTRUCT cds;
    if (GetError) 
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0
  ,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,127, 0);
    else 
        *message = 0;
    if (GetCurrentThreadId() != pg_data->idMain)
        sprintf(buf,"目标程序空间DLL: %-30s [%-40s]",m, message);
    else
        sprintf(buf,"主程序空间DLL  : %-30s [%-40s]",m, message);
    cds.lpData = buf;
    cds.cbData = sizeof(buf);
    cds.dwData = 0;
 
    SendMessage(pg_data->hWndMain,WM_COPYDATA,(WPARAM)pg_data->hWndTarget,(LPARAM)&cds);
  
    SetLastError(0);
}
int WINAPI MyMessageBoxW(HWND hWnd ,LPCWSTR M1,LPCWSTR M2, UINT M3) {
    wchar_t buf[255];
    swprintf(buf,L"!!这个窗口的API被Hook了!!/nHWND: 0x%08X/nMessage: %s/nCaption: %s"
        ,(DWORD *)hWnd
        , M1
        , M2);
    pg_data->oldAPIFunction(hWnd,buf,M2,MB_OK);
    return pg_data->oldAPIFunction(hWnd,M1,M2,M3);
}

/*DLL 入口函数*/
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason,LPVOID lpvReserved)
{
    switch (reason) {
    case DLL_PROCESS_ATTACH:
        /*创建/打开共享内存区域*/
        hMap = CreateFileMapping((HFILE *)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);
        pg_data = (GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0 ,0 ,0);
        if (!pg_data) {
           MessageBox(NULL,"无法建立共享内存,程序终止!",szApp,MB_OK);
           if (hMap) {
               CloseHandle(hMap);
               hMap = NULL;
               return 0;
            }
        }
        pg_data->hInst = hInst;
        showerr("共享内存映像文件");
        showerr("DLL装载中...",FALSE);
        break;
    case DLL_PROCESS_DETACH:
        showerr("DLL卸载中...",FALSE);
        if (pg_data) {
            UnmapViewOfFile(pg_data);
            pg_data = NULL;
        }
        if (hMap) {
            CloseHandle(hMap);
            hMap = NULL;
        }
        break;
    }
    return true;
}
/*卸载API Hook*/
void UnHookApi() {
    DWORD written = 0;
    DWORD oldaddrAPIFunction = (DWORD)pg_data->oldAPIFunction;
    WriteProcessMemory(GetCurrentProcess(),(DWORD *)pg_data->addrAPIEntryPoint
        , &oldaddrAPIFunction,sizeof(DWORD), &written);
    showerr("WriteProcessMemory on UnHook");
    /*向主线程发送 API UNHOOK 处理完毕的消息*/
    PostThreadMessage(pg_data->idMain,WM_UNHOOKOK,0,0);
}

/*加载API Hook*/
void HookApi(const char* szApiName, tAPIFunction newAddr, DWORD ImageBase) {
    /*这段代码请参考文章中的分析*/
    IMAGE_DOS_HEADER *pidh;
    IMAGE_NT_HEADERS *pinh;
    IMAGE_DATA_DIRECTORY *pSymbolTable;
    IMAGE_IMPORT_DESCRIPTOR *piid;
  
    pidh = (IMAGE_DOS_HEADER *)ImageBase;    
    pinh = (IMAGE_NT_HEADERS *)((DWORD)ImageBase + pidh->e_lfanew);
    pSymbolTable = &pinh->OptionalHeader.DataDirectory[1];
    piid =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)ImageBase +  pSymbolTable->VirtualAddress);

    do {
        IMAGE_THUNK_DATA *pitd_org,*pitd_1st;
        pitd_org = (IMAGE_THUNK_DATA *)((DWORD)ImageBase + piid->OriginalFirstThunk);
        pitd_1st = (IMAGE_THUNK_DATA *)((DWORD)ImageBase + piid->FirstThunk);
        do {
            IMAGE_IMPORT_BY_NAME *piibn;
            piibn = (IMAGE_IMPORT_BY_NAME *)((DWORD)ImageBase +  *((DWORD *)pitd_org));
            PROC *pAPIFunction = (PROC *)(pitd_1st->u1.Function);
            if (!strcmp(szApiName,(char *)piibn->Name)) {
                DWORD addrNewAPIFunction = (DWORD)MyMessageBoxW;
                DWORD written = 0;
                DWORD oldAccess;

                pg_data->oldAPIFunction = (tAPIFunction)(pAPIFunction);
                /*Change Memeory State*/
                VirtualProtect(&pitd_1st->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
                showerr("VirtualProtect");
                pg_data->addrAPIEntryPoint = (DWORD)&pitd_1st->u1.Function;
                /*Write Process Memory*/
                WriteProcessMemory(GetCurrentProcess(),&pitd_1st->u1.Function
                    , &addrNewAPIFunction,sizeof(DWORD), &written);
                showerr("WriteProcessMemory on Hook");
            }
            pitd_org++;
            pitd_1st++;
        } while (pitd_1st->u1.Function);
       
        piid++;
    } while (piid->FirstThunk + piid->Characteristics 
 + piid->ForwarderChain + piid->Name + piid->TimeDateStamp);
}

//-----------------------
extern "C" __declspec(dllexportBOOL SetAPIHook(HWND _target) {
    pg_data->hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,pg_data->hInst,pg_data->idTarget);    
    showerr("SetWindowsHookEx");
    /*向目标线程发送消息进行API HOOK*/
    if (pg_data->hHook) {
        PostThreadMessage(pg_data->idTarget,WM_ENABLEAPIHOOK,0,0);
    } else {
        return FALSE;
    }
    showerr("WM_ENABLEAPIHOOK");
    return TRUE;
}

extern "C" __declspec(dllexportvoid UnHookAPIHook() {
    /*向目标线程发送消息进行API UNHOOK*/
    PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
    showerr("WM_DISABLEAPIHOOK");
    /*等待目标进程返回WM_UNHOOKOK消息,确认可以将WH_GETMESSAGE的HOOK去掉*/
    MSG Msg;
    do {
        GetMessage(&Msg,NULL,0,0);
    }while(Msg.message !=  WM_UNHOOKOK);

    UnhookWindowsHookEx(pg_data->hHook);
    PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);
    showerr("UnHookWindowsHookEx");
}

LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION) {
        MSG *msg = (MSG *)lParam;
     
        if (msg->message == WM_ENABLEAPIHOOK) {
            HookApi("MessageBoxW",MyMessageBoxW,(DWORD)GetModuleHandle(NULL));
        }
        if (msg->message == WM_DISABLEAPIHOOK) {
            UnHookApi();
        }
        if (msg->message == WM_DESTROY) {
            showerr("目标进程退出!",FALSE);
        }
    }
    return CallNextHookEx(pg_data->hHook,nCode,wParam,lParam);
}
 
这个是主程序的关键部分 HookGui.cpp

用MFC建立一个窗口程序,包含两个按钮和一个ListBox

typedef void (*PUnHookAPIHook)();
typedef BOOL (*PSetAPIHook)(HWND);
HMODULE hDll = NULL;
HWND hNotePad = NULL;
PSetAPIHook SetAPIHook;
PUnHookAPIHook UnHookAPIHook;
GLOBALDATA *pg_data; /*在共享内存中的全局数据*/
HANDLE hMap; /*在共享内存映像的句柄*/
int CHookGUIDlg::showerr(const char* m) {
    char message[127];
    char buf[255];
    int errId = GetLastError();
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0
 ,errId,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,127, 0);
    sprintf(buf,"主程序         : %-30s [%-40s]/n",m, message);
    c_List1.InsertString(c_List1.GetCount(),buf);
    UpdateData(FALSE);
    return errId;
}

void CHookGUIDlg::OnSetapihook() 
{
    // TODO: Add your control notification handler code here
    hDll = LoadLibrary("Hook.dll");
    showerr("LoadLibrary");
    hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,ID_MAP);
    showerr("OpenFileMapping");    
    pg_data = (GLOBALDATA *)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
    showerr("MapViewOfFile");    
    if (!pg_data) {
        MessageBox("不能打开共享内存程序终止!");
        return;
    }
    SetAPIHook = (PSetAPIHook)GetProcAddress(hDll,"SetAPIHook");
    showerr("GetProcAddress-SetAPIHOOK");
   
    pg_data->hWndTarget = ::FindWindow("NotePad",NULL);
    pg_data->hWndMain = m_hWnd;
    pg_data->idMain = GetWindowThreadProcessId(m_hWnd,NULL);
    pg_data->idTarget = GetWindowThreadProcessId(pg_data->hWndTarget,NULL);
    if (!showerr("FindWindow")) {
        if (SetAPIHook) { 
            if (SetAPIHook(hNotePad))
                PostThreadMessage(pg_data->idTarget
   , WM_SETCALLERID,(LPARAM)GetCurrentThreadId(),0);
            else {
                MessageBox("SetWindowHookEx时出错,程序终止!");
                return;
            }
        } else {
            MessageBox("无法取得SetAPIHook函数!程序终止!");                    
        }
    } else {
            MessageBox("内存中没有找到NOTEPAD.EXE");            
    }
    c_SetApiHook.EnableWindow(FALSE);
    c_UnsetApiHook.EnableWindow();
}

void CHookGUIDlg::OnUnsetapihook() 
{
    // TODO: Add your control notification handler code here
    if (hDll) {
        if ( !IsWindow(pg_data->hWndTarget)) {
            MessageBox("目标进程不在内存中");
            return;
        }
        UnHookAPIHook = (PUnHookAPIHook)GetProcAddress(hDll,"UnHookAPIHook");
        showerr("GetProcAddress-UnHookAPIHook");
        if (UnHookAPIHook) 
            UnHookAPIHook();
        FreeLibrary(hDll);
        showerr("FreeLibrary");
        hDll = NULL;
    } else {
        MessageBox("请先加载DLL");
    }
    c_SetApiHook.EnableWindow();
    c_UnsetApiHook.EnableWindow(FALSE);
}

void CHookGUIDlg::OnOK() 
{
    // TODO: Add extra validation here
    if (hDll) {
        OnUnsetapihook();
    }
    CDialog::OnOK();
}

BOOL CHookGUIDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 
{
    // TODO: Add your message handler code here and/or call default
    c_List1.InsertString(c_List1.GetCount(),(char *)pCopyDataStruct->lpData);
    return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}
C#中键盘与鼠标钩子的应用实例解析 在计算机程序中,"钩子(Hook)"是一种特殊的代码,用于拦截操作系统或应用程序中的某种事件或消息。钩子允许开发者在事件处理流程中插入自定义逻辑,用以监视或修改事件数据。键盘与鼠标钩子分别关注于键盘和鼠标的输入事件,它们在安全监控、辅助工具、自动化测试等领域具有广泛的应用。P/Invoke(Platform Invocation Services)是.NET Framework中的一个特性,它允许C#程序调用Windows平台下的非托管代码。 阅读详情

相关推荐

PostThreadMessage和_beginthreadex使用示例

PostThreadMessage、_beginthreadex和PeekMessage使用示例,以及WaitForSingleObject事件机制示例。

PostThreadMessage发送进程间消息

函数原型BOOL PostThreadMessage( DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam );The PostThreadMessage function posts a message to the message queue of the specified thread. It ret

Hisin Wang的专栏 4182

Window下跨进程发消息(命名消息)

C++实现跨进程发消息的简单Demo(命名消息),简单便捷的进程间通讯方式,适用于Window环境下。

Windows挂钩的简单使用

原贴地址:http://blog.sina.com.cn/s/blog_56dee71a010007h1.html 最近手机上的短信存储器快满了,应该删除一些短信以留出一些空间,但是有好多短信是各个MM发过来的,舍不得就这么删除了,想导出到电脑里面保存起来。万一哪天MM成了我女朋友了,有机会的时候可以给她看看,说明我是这么珍惜跟她相关的点点滴滴。^_^于是用数据线把手机连接到电脑上,打开E

djimon的专栏 2042

SendMessage、SendMessageTimeout、PostMessage、PostThreadMessage

  SendMessage函数将指定的消息发送到一个或多个窗口,消息会直接发送到窗口过程而不经过消息队列,且直到消息处理完成后,SendMessage才返回。函数返回值指定消息处理的结果,依赖于所发送的消息。函数原型:   LRESULT WINAPI SendMessage( HWND hWnd, UINT Msg, WPARAM wPara...

milanleon的专栏 2129

跨进程hook api的资料

 什么是“跨进程   API   Hook”?     众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API   Hook就是给系统的API附加上一段小程序,它能监视甚至控       制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。         API   Hook   理论     通过对Win32   PE文件的分析(如果

yaozhu88的专栏 1543

跨进程 API hook

跨进程API Hook(初稿) 什么是“跨进程 API Hook”? 众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制

1782

跨进程 API Hook

跨进程API Hook(1)  跨进程API Hook作者:detrox 什么是“跨进程 API Hook”?众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。API Hook 理论通过对Win32 PE文件

Delphizhou 的专栏 1269

[转]跨进程API Hook(初稿)

[转-收藏]跨进程API Hook(初稿)作者: detrox什么是“跨进程 API Hook”?众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。API Hook 理论通过对Win32 PE文件的分析(如果你还不熟悉PE文

梦的归宿 3285

什么是“跨进程 API Hook”?

什么是“跨进程 API Hook”?Org:http://blog.csdn.net/detrox/archive/2004/01/29/17511.aspx众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。API Hook

killcpp的专栏 787

跨进程API HOOK

什么是“跨进程 API Hook”?众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。API Hook 理论通过对Win32 PE文件的分析(如果你还不熟悉PE文件格式,可以看看Iczelion的PE教程或者LU

zy122的专栏 730

zz - 跨进程API Hook

 原文出处: http://dev.csdn.net/article/23/23766.shtm跨进程API Hook(初稿)detrox什么是“跨进程 API Hook”?众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API Hook就是给系统的API附加上一段小程序,它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人

panda1987的专栏 970
上一篇: 用PHP人工使网页过期
下一篇: 函数调用的底层机制
detrox
博客等级 码龄24年 10粉丝 34原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值