跨进程API Hook(初稿)

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

API Hook 理论
通过对Win32 PE文件的分析(如果你还不熟悉PE文件格式,可以看看Iczelion的PE教程或者LUEVELSMEYER的<>)。我们知道在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大师的< >,也可以参考陈宽达先生的<>。

简而言之,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 
#include 
#include 
#include 
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;
&n   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

参考资料
< >, Jeffrey Richter, Microsoft Press

<>,陈宽达,华中科大出版社

<>, LUEVELSMEYER

<>, Iczelion

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

下载源代码

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

这是DLL的程序,Hook.dll
#include 
#include 
#include 
#include 
#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 (Get CurrentThreadId() != 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了!! HWND: 0x%08X Message: %s Caption: %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] ",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;
            }
  &n } 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);
}

跨进程 API hook相关推荐

  1. Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术

    catalogue 1. 引言 2. 使用注册表注入DLL 3. 使用Windows挂钩来注入DLL 4. 使用远程线程来注入DLL 5. 使用木马DLL来注入DLL 6. 把DLL作为调试器来注入 ...

  2. 进程隐藏之API HOOK

    // 在Windows中,用户进程的所有操作都是基于WIN32 API来实现的,例如使用任务管理器来查看进程等操作. // API HOOK技术是一种改变API执行结果的技术.// PS:ZwQuer ...

  3. 易语言api hook CreateProcessA 创建进程

    CreateProcessA我们非常熟悉,就是创建一个进程,这个API的函数hook非常实用,本课我们可以通过CreateProcessA来运行系统的计算器,或者记事本等等. CreateProces ...

  4. 用跨进程子类化技术实现对其它进程消息的拦载

    大家都知道每个窗口都有默认的窗口函数来进行对窗口消息的处理.   而子类化技术就是替换窗口的窗口函数为自己定义的函数的技术.例如下面的代码: var   Form1: TForm1;   OldWnd ...

  5. flutter_hybird_webview 跨进程渲染的实践技术分享

    theme: channing-cyan 前言 大家好,继 Flutter跨进程混合栈渲染的实践--子进程WebView 之后,利用业余时间对整个插件进行了完善和基础测试,诚然距离投入生产还有一段距离 ...

  6. 跨进程通信,到底用长连接还是短连接

    一个完整的软件系统大多数情况下是由多个进程共同协作进行的,哪怕它们在同一台服务器上.所以,进程之间如何进行高效的通信至关重要. 单个应用程序+单个数据库这套基础开发套餐我相信每个人都经历过,甚至在初期 ...

  7. 直接通过Binder的onTransact完成跨进程通信

    1.具体代码: 服务端实现: public class IPCService extends Service {private static final String DESCRIPTOR = &qu ...

  8. Linux 2.6 下通过 ptrace 和 plt 实现用户态 API Hook

    (转载兼整理)Linux 2.6 下通过 ptrace 和 plt 实现用户态 API Hook 这厮此文写的相当实用,不知道为啥不好好整理一下,得,我代劳了吧.作者:l04m33@gmail.com ...

  9. Android 跨进程通信基础

    2019独角兽企业重金招聘Python工程师标准>>> Android跨进程通信基础--Binder, BinderProxy, parcel, parcelable, Stub, ...

  10. (转载兼整理)Linux 2.6 下通过 ptrace 和 plt 实现用户态 API Hook

    这厮此文写的相当实用,不知道为啥不好好整理一下,得,我代劳了吧.作者:l04m33@gmail.com,原文.去看一眼就知道我干嘛干这个脏活儿了... 感觉这篇文章有上首页的素质,可惜不是我自己写的, ...

最新文章

  1. 一行代码轻松实现拖动效果
  2. SBB:土壤微生物群落的特征究竟由什么决定
  3. MySQL常见面试题解析
  4. 用Java模拟multipart形式的Http Post请求
  5. 在Mac上安装Hadoop
  6. python安装多少位_python安装流程
  7. 使用Spring Boot应用程序将代码管道化
  8. 数组中冒泡排序、直接选择排序、反序排序原理与区别
  9. 消息队列MQ夺命连环11问:kafka、rabbitmq、rocketmq、activemq
  10. return的用法 java_Java中return用法.
  11. Matlab中文注释乱码问题解决方案
  12. 用matlab辨识系统,Matlab系统辨识工具箱
  13. c语言messagebox多窗口,C语言messagebox用法
  14. 视频文件格式--视频封装格式--视频编码格式区分
  15. java生成随机数的函数_java生成随机数的常用方法分析
  16. 国开大学 C语言程序 形考任务4,[国家开放大学] 国开电大人体生理学形考任务4...
  17. 关于form与表单提交
  18. 转:各种文本格式转换的网站
  19. matlab r2017a安装 (分享缺少的“libmwlmgrimpl.dll”文件)刚刚解决error:-8 问题,使用中
  20. 如何进行批量导入通讯录,简单易学

热门文章

  1. U盘重新安装Mac OS系统教程
  2. 地统计学之变异函数深入理解与分析
  3. 预付费售电管理系统基础知识
  4. 学校预付费云平台系统 的设计与应用
  5. oracle标准正态分布函数,标准正态分布表 弄明白什么是标准正态分布
  6. python 图像模糊处理实现
  7. 计算机二级c语言选择题pdf,计算机二级c语言选择题库(带答案)[汇编].pdf
  8. 兄弟连关于PHP培训的声明
  9. 信用卡交易数据异常检测
  10. jQuery源码研究——怎么看源码