跨进程API Hook

用AIDL完成可跨进程通信的WebView框架 至今为止做过的项目里,H5和android的通信都是一个个方法写好,用注解标识,然后互相调用,而且还都写在同一个地方,甚至有些没把WebView放到另一个进程中去,而且方法多了,显得特别臃肿和混乱。之前写过一个可跨进程的WebView框架,经过学习之后做出了改进。虽然还有很多可优化的点,这就算先记录下来吧。 阅读详情
什么是“跨进程 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大师的<&lt rogramming 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
参考资料

<&lt rogramming 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(dllexport) BOOL 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(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");
}

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);
 
Android组件化跨进程通信框架Andromeda解析 作者2013年从java开发,转做Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。参与过不少面试,也当面试官 面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!我整理了一份阿里P7级别的最系统的Android开发主流技术,特别适合有3-5年以上经验的小伙伴深入学习提升。主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。 阅读详情

相关推荐

Android-安卓跨进程跨app通信框架

本框架实现了安卓跨进程跨app通信的方便调用和封装

Android Framework跨进程通信IPC之6——Binder框架

Android 从下而上分了内核层、硬件抽象层、系统服务层、Binder IPC 层、应用程序框架层Android 中"应用程序框架层"以 SDK 的形式开放给开发者使用,“系统服务层” 中的核心服务随系统启动而运行,通过应用层序框架层提供的 Manager 实时为应用程序提供服务调用。系统服务层中每一个服务运行在自己独立的进程空间中,应用程序框架层中的 Manager 通过 Binder IPC 的方式调用系统服务层中的服务。简单的说,Binder是Android平台上的一种跨进程通信技术。

Gaga246的博客 5448

浙大数值分析lab2

最可怕的一道题,题目是这样的 Root of a Polynomial A polynomial of degree nnn has the common form as p(x)=cnxn+cn−1xn−1+⋯+c1x+c0p(x)=c_n x^n + c_{n-1} x^{n-1} + \cdots + c_1 x + c_0p(x)=c​n​​x​n​​+c​n−1​​x​

yao_zou的博客 4797

Android跨进程通信二

1. Binder是什么 从机制上来说: Binder是Android中一种跨进程通信的方式 从Binder机制实现来说: Binder是一种虚拟的物理设备驱动 从Java层面来说: Binder是一个类,实现了IBinder接口。 2. Binder机制 2.1 背景知识 2.1.1 进程空间划分 一个进程空间分为 用户空间 & 内核空间(Kernel),即把进程内 用户 & 内...

吓成一坨兔子 3124

ESXI 7 :创建统信V20_1050d服务器系统虚拟机

记录一下在 X86 架构创建统信V20_1050d 虚拟机遇到的问题。已遇到的问题有①:常规服务器环境下网络连接失败重点:按照桌面版本,有问题处理简单。

guyuelin123的博客 1969

STM32F103 CAN通信避坑指南:从标准库配置到收发测试的完整流程

本文详细介绍了STM32F103 CAN通信的实现流程,从标准库配置到收发测试,帮助开发者避开常见陷阱。内容涵盖硬件连接、波特率计算、过滤器配置及错误处理等关键环节,提供实用的代码示例和调试技巧,确保CAN通信的稳定性和可靠性。

weixin_30627341的博客 325

跨进程hook api的资料

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

yaozhu88的专栏 1544

双目视觉入门实战:用Matlab标定相机,再到Python OpenCV完成测距的完整链路

本文详细介绍了双目视觉技术的完整实现流程,从Matlab相机标定到Python OpenCV测距的全链路实践。重点解析了Matlab与OpenCV的参数转换技巧,以及立体校正、视差计算等关键步骤的代码实现,帮助开发者快速掌握双目测距系统的搭建方法。

weixin_29166013的博客 447

跨进程 API hook

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

1783

DJI MobileSDK运行实例代码教程(保姆级)坑踩完了

其中比较重要的是PackageName也就是我们应用的包名,在这里我们可以直接使用官方文档中的包名,com.dji.ImportSDKDemo,appname为:ImportSDKDemo,其他的可以随意。在C盘中根据路径先找到 “用户/admin/.gradle”下的.gradle文件夹,然后依次打开wrapper/dists文件夹,找到我们刚刚要下载的gradle版本名的文件夹。在Androidstudio中打开,选在打开项目选择文件下载后的保存路径(解压之后的),在打开项目后会自动下载gradle。

k1121568的博客 2863

三态门Multisim电路仿真——硬件工程师笔记

三态门原理及应用摘要 三态门是具有高电平(1)、低电平(0)和高阻态(Z)三种输出的逻辑电路,通过使能端(EN)控制状态切换。高阻态时输出端等效断路,避免信号冲突。其核心应用包括: 总线系统:多设备共享总线时,仅使能选中设备的三态门,其余保持高阻态,防止干扰。 数据选择器:利用三态门切换多路输入信号,简化电路设计。 实现方式分两种: TTL三态门(三极管构成):低电平使能有效,仿真验证输出逻辑与高阻态。 MOS三态门(MOS管构成):高电平使能有效,仿真显示使能信号控制输出状态。 文中还附硬件工程师笔试面试

XU157303764的博客 2012

跨进程 API Hook

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

Delphizhou 的专栏 1272

基于LLaMA-action模型的文档摘要任务微调

文档摘要是指从长文档中提取关键信息,生成简短而准确的总结。抽取式摘要:从原文中直接抽取关键句子或短语组成摘要。生成式摘要:通过生成新的句子来表达原文的核心内容。混合式摘要:结合抽取式和生成式方法,既保留原文的关键句子,又生成新的内容。新闻网站:自动生成新闻摘要,帮助用户快速了解新闻要点。社交媒体:为用户提供新闻摘要,便于分享和传播。学术搜索引擎:为用户提供学术文献的摘要,帮助用户快速筛选相关文献。学术写作辅助:帮助研究人员快速生成文献综述部分。企业内部文档管理:自动生成文档摘要,便于员工快速了解文档内容。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 1432

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

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

梦的归宿 3289

lammps模拟技巧:高熵合金势函数设置三种方法

大家好,我是小马老师。 本文继续介绍lammps模拟中的势函数设置方法。 在前面的文章中,介绍过高熵合金的建模:高熵合金建模 高熵合金包含的原子数较多,势函数的设置相对复杂,在平时一对一的咨询中,这种问题也相对较多。 下面介绍三种高熵合金势函数设置方法。 1.下载专用势函数 下面的网站包含了大多数原子的势函数: https://www.ctcms.nist.gov/potentials/ 如需下载包含Fe原子的势函数,直接点Fe: 出现势函数列表: 比如Al-Co-Cr-Fe-Ni就是高熵合金AlCoC

lammps_jiayou的博客 8962

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

什么是“跨进程 API Hook”?

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

killcpp的专栏 792

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

跨进程API HOOK

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

zy122的专栏 731

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

zz - 跨进程API Hook

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

panda1987的专栏 972

跨进程API Hook(初稿)

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

songtao_01的专栏 835

Hook或者API高手请进-跨进程获取其他程序的DBGrid内容(其它人做的程序)

Hook或者API高手请进-跨进程获取其他程序的DBGrid内容(其它人做的程序) Delphi / Windows SDK/APIhttp://www.delphi2007.net/DelphiAPI/html/delphi_20061109101554271.html 假设有一个程序A是一个信息管理系统,它的界面上有一个DBGrid;我想写一个程序B来取A程序界面上的DBGrid...

aibi9196的博客 430
上一篇: 揭示win32 api拦截细节
下一篇: 绕过Raw模式文件系统I/O Rootkit探测
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值