简介
对于 Windows
程序而言,其工作机制是基于消息基址实现的,而且系统会有一个系统消息队列用于接收所有进程的消息,通过窗口(控件)句柄分发给特定的进程。因此,我们可以通过消息机制,向特定进程发送消息,以实现进程间的通信。
但是,当我们通过句柄向特定进程发送系统定义的消息时, 目标进程中可能存在该消息的处理函数,其处理函数的逻辑必然与我们想要实现的不同,这同样无法达到我们的目的。
因此,我们可以通过自定义消息,这样就可以避免被目标进程按照其原本的逻辑处理。我们可以通过 Windows AIP
函数向目标进程中注入消息处理函数,以实现目标进程接收我们自定义的消息,并按照我们定义的消息处理函数进行消息处理。
通过自定义消息实现进程间的通信,我们就需要将自定义消息对应的消息处理函数注入到目标进程中。该函数就是 SetWindowsHookEx
,该函数用于设置全局钩子,其中有一个参数是指定注入目标线程。当 threadID
为0时,表示向操作系统注入全局钩子;但是当该参数是一个特定进程的 threadID
时,就可以实现对该线程的进程空间注入消息处理函数。
DLL代码
#include <windows.h>
#include <TlHelp32.h>
#include <stdio.h>
struct SharedMemory
{
DWORD dwBuffMax;
DWORD dwBuffLen;
LPSTR lpszBuff;
}*sm;
extern HMODULE g_hModuleOfDll;
HHOOK g_hHook;
BYTE szBuff[100];
HANDLE hMapObject;
LPVOID lpszSharedBuff;
BOOL CreateSharedMemory()
{
//创建FileMapping对象
hMapObject = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x1000,TEXT("shared"));
if(!hMapObject)
return FALSE;
//将FileMapping对象映射到自己的进程
lpszSharedBuff = MapViewOfFile(hMapObject,FILE_MAP_WRITE,0,0,0);
if(!lpszSharedBuff)
return FALSE;
sm = lpszSharedBuff;
sm->dwBuffMax = 0x100;
sm->lpszBuff = (LPSTR)((DWORD)lpszSharedBuff+12);
return TRUE;
}
BOOL Write(LPSTR lpszBuff, DWORD dwBuffLen)
{
if(sm->dwBuffMax < dwBuffLen)
return FALSE;
ZeroMemory(sm->lpszBuff, g_dwBuffMax);
memcpy(sm->lpszBuff, lpszBuff, dwBuffLen);
sm->dwBuffLen = dwBuffLen;
return TRUE;
}
DWORD Read(LPSTR lpszBuff, DWORD dwBuffLen)
{
if(dwBuffLen < sm->dwBuffLen)
return 0;
ZeroMemory(lpszBuff, dwBuffLen);
memcpy(lpszBuff, sm->lpszBuff, sm->dwBuffLen);
return sm->dwBuffLen;
}
DWORD GetWindowThreadID(LPSTR lpszWindowName)
{
// 初始化
HANDLE hProcess;
HANDLE hThreadSnap = NULL; // 模块快照
DWORD th32ThreadID = 0;
DWORD dwPid = 0x00;
THREADENTRY32 thread32 = {
0 };
BOOL bMoreOfThread;
//获取进程句柄
HWND hwnd = FindWindow(NULL, lpszWindowName);
if (!hwnd)
{
//printf("获取进程句柄失败!\n");
return FALSE;
}
GetWindowThreadProcessId(hwnd, &dwPid);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
//获取线程ID
thread32.dwSize = sizeof(thread32);
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
{
//printf("获取线程信息失败!\n");
return FALSE;
}
bMoreOfThread = Thread32First(hThreadSnap, &thread32);
while (bMoreOfThread)
{
if (thread32.th32OwnerProcessID == dwPid)
{
th32ThreadID = thread32.th32ThreadID;
break;
}
bMoreOfThread = Thread32Next(hThreadSnap, &thread32);
}
CloseHandle(hThreadSnap);
return th32ThreadID;
}
// 钩子回调函数
LRESULT MessageProc(
int nCode,
WPARAM wParam,
LPARAM lParam)
{
if (nCode == HC_ACTION)
{
PCWPSTRUCT pcw = (PCWPSTRUCT)lParam;
if (pcw->message == WM_USER + 0x1)
{
OutputDebugString("receive data: ");
OutputDebugString(sm->lpszBuff);
OutputDebugString("------\n");
ZeroMemory(szBuff, sizeof(szBuff));
sprintf(szBuff, "wParam: %d\nlParam: %d\nPID: %d\n", pcw->wParam, pcw->lParam,GetCurrentProcessId());
OutputDebugString(szBuff);
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// 设置全局钩子
BOOL SetGlobalHook(int idHook, LPSTR lpszWindowName)
{
DWORD threadID = GetWindowThreadID(lpszWindowName);
if(!threadID)
{
MessageBox(NULL, "获取目标进程PID失败!", "note", MB_OK);
return FALSE;
}
g_hHook = SetWindowsHookEx(idHook, (HOOKPROC)MessageProc, g_hModuleOfDll, threadID);
if (NULL == g_hHook)
{
return FALSE;
}
return TRUE;
}
// 卸载钩子
BOOL UnsetGlobalHook()
{
if (g_hHook)
{
UnhookWindowsHookEx(g_hHook);
return TRUE;
}
else
return FALSE;
}
## 测试程序
#include <Windows.h>
#include <stdio.h>
int main(int argc, CHAR* argv[])
{
typedef BOOL(*typedef_SetGlobalHook)(int idHook, LPSTR lpszWindowName);
typedef BOOL(*typedef_UnsetGlobalHook)();
typedef BOOL(*typedef_Write)(LPSTR lpszBuff, DWORD dwBuffLen);
typedef DWORD(*typedef_Read)(LPSTR lpszBuff, DWORD dwBuffLen);
typedef BOOL(*typedef_CreateSharedMemory)();
HMODULE hDll = NULL;
typedef_SetGlobalHook SetGlobalHook = NULL;
typedef_UnsetGlobalHook UnsetGlobalHook = NULL;
typedef_CreateSharedMemory CreateSharedMemory;
typedef_Write Write;
typedef_Read Read;
DWORD dwBuffLen;
BYTE szBuff[100] = {
0};
BOOL bRet = FALSE;
LPSTR lpszWindowName = "Win32App";
do
{
hDll = ::LoadLibrary("C:\\vc6++\\MyProjects\\GlobalHook\\Debug\\GlobalHook.dll");
if (NULL == hDll)
{
printf("LoadLibrary Error[%d]\n", ::GetLastError());
break;
}
SetGlobalHook = (typedef_SetGlobalHook)::GetProcAddress(hDll, "SetGlobalHook");
if (NULL == SetGlobalHook)
{
printf("GetProcAddress Error[%d]\n", ::GetLastError());
break;
}
bRet = SetGlobalHook(WH_CALLWNDPROC, lpszWindowName);
if (bRet)
{
printf("SetGlobalHook OK.\n");
}
else
{
printf("SetGlobalHook ERROR.\n");
}
//write buff
Write = (typedef_Write)GetProcAddress(hDll, "Write");
if (NULL == Write)
{
printf("GetProcAddress Error[%d]\n", GetLastError());
break;
}
bRet = Write("haha,walker!", 0x20);
if (bRet)
{
printf("write success.\n");
}
else
{
printf("write error.\n");
}
/*
// read buff
Read = (typedef_Read)GetProcAddress(hDll, "Read");
if (NULL == Read)
{
printf("GetProcAddress Error[%d]\n", GetLastError());
break;
}
dwBuffLen = sizeof(szBuff);
dwBuffLen = Read((LPSTR)szBuff, dwBuffLen);
if (dwBuffLen)
{
printf("Read data: %s\n", szBuff);
}
else
{
printf("Read error.\n");
}
*/
//获取进程句柄
HWND hwnd = FindWindow(NULL, lpszWindowName);
if (!hwnd)
{
//printf("获取进程句柄失败!\n");
return FALSE;
}
SendMessage(hwnd, WM_USER + 0x1, 0x1234, 0x5678);
UnsetGlobalHook = (typedef_UnsetGlobalHook)::GetProcAddress(hDll, "UnsetGlobalHook");
if (NULL == UnsetGlobalHook)
{
printf("GetProcAddress Error[%d]\n", ::GetLastError());
break;
}
bRet = UnsetGlobalHook();
if(bRet)
printf("UnsetGlobalHook OK.\n");
else
printf("UnsetGlobalHook falied.\n");
SendMessage(hwnd, WM_USER + 0x1, 0x1234, 0x5678);
}while(FALSE);
FreeLibrary(hDll);
return 0;
}
测试图如下:
存在的问题
该 DLL
中无法使用 MessageBox
,否则会引发被注入的进程崩溃。