在windows下,要实现屏幕取词,可以通过拦截 ExtTextOutA,ExtTextOutW,TextOutA,TextOutW,这4个API来实现,另外4个DrawTextExA,DrawTextExW,DrawTextA,DrawTextW 貌似是调用前面4个去实现的,具体我没有去验证过。
本文示例为通过拦截 ExtTextOutW 这个API可以实现屏幕取词的部分功能。
它的函数定义为:
BOOL WINAPI ExtTextOutW(HDC hdc, int x, int y, UINT options, CONST RECT * lprect, LPCWSTR lpString, UINT c, CONST INT * lpDx);
其中lpString参数包含了字符串地址信息,我们只需要到目标进程拦截这个API,然后读取lpString里面的字符数据,然后显示到一个文本框里面,就行了。
要实现这个功能,需要做两件事:
1. 安装一个全局鼠标钩子,拦截WM_MOUSEMOVE消息。
2. 如果检查到鼠标在屏幕的某处停留时间超过1秒,则在鼠标所在的窗口进程挂上API钩子,取得所需信息后,立即摘掉API钩子。
注意:该程序必须在Release版本下运行,如果是DeBug版本的话,因为编译器没做优化和加了一些debug代码,所以会内存读写报错
===========================================
下面是生成mousehook.dll的代码:
// dllmain.cpp : 定义 DLL 的初始化例程。
//
#include "stdafx.h"
#include
#include
#include "MyMouseHook.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
extern HINSTANCE hInstanceHook;
static AFX_EXTENSION_MODULE MouseHookDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// 如果使用 lpReserved,请将此移除
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("MouseHook.DLL 正在初始化!\n");
// 扩展 DLL 一次性初始化
if (!AfxInitExtensionModule(MouseHookDLL, hInstance))
return 0;
// 将此 DLL 插入到资源链中
// 注意: 如果此扩展 DLL 由
// MFC 规则 DLL (如 ActiveX 控件)隐式链接到,
// 而不是由 MFC 应用程序链接到,则需要
// 将此行从 DllMain 中移除并将其放置在一个
// 从此扩展 DLL 导出的单独的函数中。使用此扩展 DLL 的
// 规则 DLL 然后应显式
// 调用该函数以初始化此扩展 DLL。否则,
// CDynLinkLibrary 对象不会附加到
// 规则 DLL 的资源链,并将导致严重的
// 问题。
new CDynLinkLibrary(MouseHookDLL);
hInstanceHook=hInstance;
// WM_MY_MOUSEMOVE=RegisterWindowMessage(WM_MY_MOUSEMOVE_MSG);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("MouseHook.DLL 正在终止!\n");
// 在调用析构函数之前终止该库
AfxTermExtensionModule(MouseHookDLL);
}
return 1; // 确定
}
//MyMouseHook.h
//
#pragma once
#define WM_MY_MOUSEMOVE (WM_USER+10)
// CMyMoueHook 命令目标
class AFX_EXT_CLASS CMyMouseHook : public CObject
{
public:
CMyMouseHook();
virtual ~CMyMouseHook();
public:
BOOL StartHook(HWND hWnd); //安装钩子函数
BOOL StopHook(HWND hWnd); //卸载钩子函数
};
// MyMoueHook.cpp : 实现文件
//
#include "stdafx.h"
#include "MyMouseHook.h"
#pragma data_seg("mydata")
HWND hWnd_Mouse=NULL; //设置需要捕获鼠标消息的窗口句柄,即所有鼠标消息都会另外发送一份消息到该窗口
#pragma data_seg()
#pragma comment(linker,"/SECTION:mydata,RWS")
HHOOK hHook=NULL; //鼠标钩子句柄
HINSTANCE hInstanceHook=NULL; //插入保存DLL实例句柄
extern "C" LRESULT WINAPI MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)
{
CallNextHookEx(hHook, nCode, wParam, lParam);
return 0;
}
if(nCode>=0)
{
LPMSG msg=(LPMSG)lParam;
if(msg->message==WM_MOUSEMOVE || msg->message==WM_NCMOUSEMOVE)
{
PostMessage(hWnd_Mouse, WM_MY_MOUSEMOVE, 0, 0);
// PostMessage(hWnd_Mouse, WM_MOUSEMOVE, 0, 0);
}
}
return CallNextHookEx(hHook,nCode,wParam,lParam); //继续传递钩子信息
}
// CMyMoueHook
CMyMouseHook::CMyMouseHook()
{
}
CMyMouseHook::~CMyMouseHook()
{
// StopHook();
}
// CMyMoueHook 成员函数
BOOL CMyMouseHook::StartHook(HWND hWnd)
{
if(hHook==NULL)
{
hHook=SetWindowsHookExW(WH_GETMESSAGE,(HOOKPROC)MouseProc,hInstanceHook,0);
if(hHook!=NULL)
{
hWnd_Mouse=hWnd; //设置需要捕获鼠标消息的窗口句柄
return TRUE;
}
}else
{
if(hWnd_Mouse!=NULL)
{
if(hWnd_Mouse==hWnd)
{
return FALSE; //该窗口句柄已经hook了
}else
{
hWnd_Mouse=hWnd; //设置需要捕获鼠标消息的窗口句柄,这样将会覆盖前一个句柄
return TRUE;
}
}
}
return FALSE; //failed to set hook
}
BOOL CMyMouseHook::StopHook(HWND hWnd)
{
if(hWnd!=hWnd_Mouse || hWnd==NULL){return FALSE;}
BOOL bResult=UnhookWindowsHookEx(hHook);
if(bResult){hWnd_Mouse=NULL;hHook=NULL;}
return bResult;
}
下面是实现屏幕取词的代码:
// pingmuquciDlg.h : 头文件
//
#pragma once
#include "afxwin.h"
#include "../mousehook/MyMouseHook.h"
#define WM_HOOK_TEXTOUT (WM_USER+101)
typedef struct _RemoteParam
{
DWORD dwTextOut;
DWORD dwExtTextOut;
DWORD dwPostMessage;
DWORD dwSendMessage;
DWORD dwGetCurrentProcess;
DWORD dwWriteProcessMemory;
DWORD dwMessageBox;
unsigned char oldCode[10];
unsigned char newCode[10];
DWORD FunAddr;
BOOL bHookAlready; //是否挂上API钩子
HWND hwnd; //安放钩子的那个窗口句柄
LPCWSTR lpString; //专门用于保存TextOut的字符串地址
wchar_t info[260];
} RemoteParam, * pRemoteParam;
// CpingmuquciDlg 对话框
class CpingmuquciDlg : public CDialogEx
{
// 构造
public:
CpingmuquciDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_PINGMUQUCI_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CMyMouseHook m_mouse_hook;
CEdit m_edit;
BOOL is_quci_open;
CString m_edit_str;
HWND m_hwnd_hook;
BOOL bHookAlready; //是否挂钩子的标志
unsigned char oldcode[10]; //用来保存API的原始代码
unsigned char newcode[10]; //用来保存API修改后的代码
DWORD dwFunAddr;
DWORD dwPramaAddr;
HANDLE m_hProcess;
DWORD m_dwProcessId;
int size_Func;
int size_Pramam;
RemoteParam m_RParam;
public:
BOOL enableDebugPriv(); //提升进程访问权限
DWORD processNameToId(LPCTSTR lpszProcessName); //根据进程名称得到进程ID,如果有多个运行实例的话,返回第一个枚举到的进程的ID
BOOL ClearHook(HANDLE hProcess); //清理钩子代码
BOOL HookOn(HANDLE hProcess); //挂上API钩子
BOOL HookOff(HANDLE hProcess); //摘掉API钩子
BOOL InitHook(HANDLE hProcess); //初始化API钩子
public:
afx_msg void OnBnClickedButton1(); //开启屏幕取词
afx_msg void OnBnClickedButton2(); //关闭屏幕取词
afx_msg void OnTimer(UINT_PTR nIDEvent);
protected:
afx_msg LRESULT OnHookTextout(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnMyMousemove(WPARAM wParam, LPARAM lParam);
};
//
//拦截 ExtTextOut(...),并实现一个粗糙的屏幕取词功能
//
//作者:过客
//邮箱:[email protected]
//日期:2014.04.27
//
// pingmuquciDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "pingmuquci.h"
#include "pingmuquciDlg.h"
#include "afxdialogex.h"
#include
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define TIME_ID_1 1
#pragma comment(lib,"../Debug/mousehook.lib")
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CpingmuquciDlg 对话框
CpingmuquciDlg::CpingmuquciDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CpingmuquciDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
is_quci_open=FALSE;
m_edit_str=_T("");
m_hwnd_hook=NULL;
bHookAlready=FALSE;
dwFunAddr=NULL;
dwPramaAddr=NULL;
m_hProcess=NULL;
m_dwProcessId=NULL;
size_Func=0;
size_Pramam=0;
::memset(oldcode,0,10);
::memset(newcode,0,10);
}
void CpingmuquciDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT1, m_edit);
}
BEGIN_MESSAGE_MAP(CpingmuquciDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CpingmuquciDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CpingmuquciDlg::OnBnClickedButton2)
ON_MESSAGE(WM_HOOK_TEXTOUT, &CpingmuquciDlg::OnHookTextout)
ON_WM_TIMER()
ON_MESSAGE(WM_MY_MOUSEMOVE, &CpingmuquciDlg::OnMyMousemove)
END_MESSAGE_MAP()
// CpingmuquciDlg 消息处理程序
BOOL CpingmuquciDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CpingmuquciDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CpingmuquciDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CpingmuquciDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
//==========================================================================
//typedef HANDLE (__stdcall * PFN_CREATEFILE)(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCWSTR, LPCWSTR, DWORD);
typedef BOOL (__stdcall * PFN_WRITEPROCESSMEMORY)(HANDLE,LPVOID,LPCVOID,SIZE_T,SIZE_T*);
typedef HANDLE (__stdcall * PFN_GETCURRENTPROCESS)(void);
//typedef BOOL (__stdcall * PFN_TEXTOUT)(HDC, int, int, LPCSTR, int);
typedef BOOL (__stdcall * PFN_TEXTOUT)(HDC, int, int, LPCWSTR, int);
//typedef BOOL (__stdcall * PFN_EXTTEXTOUT)(HDC, int, int, UINT, CONST RECT*, LPCSTR, UINT, CONST INT*);
typedef BOOL (__stdcall * PFN_EXTTEXTOUT)(HDC, int, int, UINT, CONST RECT*, LPCWSTR, UINT, CONST INT*);
typedef BOOL (__stdcall * PFN_POSTMESSAGE)(HWND, UINT, WPARAM, LPARAM);
typedef BOOL (__stdcall * PFN_SENDMESSAGE)(HWND, UINT, WPARAM, LPARAM);
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCWSTR, LPCWSTR, DWORD);
void HookTextOut(LPVOID lParam)
{
RemoteParam* pRP=(RemoteParam*)lParam;
DWORD dwParamaAddr=0; //自定义结构体的地址
DWORD NextIpAddr=0; //CPU下一个IP地址
HDC hdc=NULL; //设备描述表句柄,画图用的
int x=0; //字符串的开始位置 x坐标
int y=0; //字符串的开始位置 y坐标
UINT options=0;
CONST RECT *lprect=NULL;
LPCWSTR lpString=NULL; //字符串指针
int c=0; //字符串中字符的个数
CONST INT * lpDx=NULL;
BOOL Res=FALSE; //API TextOut 的返回值
//下面的汇编代码是将TextOut(...)里面的6个参数和另外两个变量(dwParamaAddr和NextIpAddr)保存到变量中,以便后面调用
__asm
{
MOV EAX,[EBP+8] //注意是[EBP+8],而不是[EBP+4]
MOV [dwParamaAddr], EAX
MOV EAX,[EBP+12]
MOV [NextIpAddr], EAX
MOV EAX,[EBP+16]
MOV [hdc], EAX
MOV EAX,[EBP+20]
MOV [x], EAX
MOV EAX,[EBP+24]
MOV [y], EAX
MOV EAX,[EBP+28]
MOV [options], EAX
MOV EAX,[EBP+32]
MOV [lprect], EAX
MOV EAX,[EBP+36]
MOV [lpString], EAX
MOV EAX,[EBP+40]
MOV [c], EAX
MOV EAX,[EBP+44]
MOV [lpDx], EAX
}
PFN_GETCURRENTPROCESS pfnGetCurrentProcess=(PFN_GETCURRENTPROCESS)pRP->dwGetCurrentProcess;
PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory=(PFN_WRITEPROCESSMEMORY)pRP->dwWriteProcessMemory;
PFN_TEXTOUT pfnTextOut=(PFN_TEXTOUT)pRP->dwTextOut;
PFN_EXTTEXTOUT pfnExtTextOut=(PFN_EXTTEXTOUT)pRP->dwExtTextOut;
PFN_POSTMESSAGE pfnPostMessage=(PFN_POSTMESSAGE)pRP->dwPostMessage;
PFN_SENDMESSAGE pfnSendMessage=(PFN_SENDMESSAGE)pRP->dwSendMessage;
PFN_MESSAGEBOX pfnMessageBox=(PFN_MESSAGEBOX)pRP->dwMessageBox;
//恢复API原来的样子,即摘掉API钩子
pfnWriteProcessMemory(pfnGetCurrentProcess(), (LPVOID)pfnExtTextOut, (LPCVOID)pRP->oldCode, 10, NULL);
//调用正常的TextOut
// Res=pfnTextOut(hdc, x, y, lpString, c);
Res=pfnExtTextOut(hdc, x, y, options, lprect, lpString, c, lpDx);
//下面的代码是将TextOut里面的lpString悄悄发送给我们挂钩子的windows应用程序
if(pRP->hwnd!=NULL)
{
pRP->lpString=lpString;
// pfnPostMessage(pRP->hwnd, WM_HOOK_TEXTOUT, MAKELONG(0,0), MAKELONG(0,0)); //进程间通信
pfnSendMessage(pRP->hwnd, WM_HOOK_TEXTOUT, MAKELONG(0,0), MAKELONG(0,0)); //进程间通信
}
// int allowFlag = pfnMessageBox(NULL, lpString, pRP->info, MB_ICONWARNING | MB_YESNO);
//下面代码是善后工作,这个非常重要,如果没有的话,EIP将回不到调用TextOut(...)的下一条命令,这条命令在"notepad.exe"的领空
//而不是kernel32.dll的领空,要切记。
__asm
{
POP EDI
POP ESI
POP EBX
MOV EDX, [NextIpAddr] //调用TextOut(...)这一命令的下一条命令地址
MOV EAX, [Res] //函数返回值要放到EAX寄存器里,这一句可省略,原因是pfnTextOut(...)会自动将结果存入EAX
MOV ESP, EBP
POP EBP
// MOV ESP, EBP
ADD ESP, 11*4 //此处为了平衡栈,可以进一步优化
PUSH EDX
RET //ret指令用栈中的数据(即edx里面的地址),修改IP的内容,注意不修改CS的内容,retf才是
}
}
BOOL CpingmuquciDlg::enableDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return FALSE;
}
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
{
CloseHandle(hToken);
return FALSE;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //特权启用
if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) //启用指定访问令牌的特权
{
CloseHandle(hToken);
return FALSE;
}
return TRUE;
}
DWORD CpingmuquciDlg::processNameToId(LPCTSTR lpszProcessName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if(!Process32First(hSnapshot, &pe))
{
MessageBox(_T("The frist entry of the process list has not been copyied to the buffer"), _T("Notice"), MB_ICONINFORMATION | MB_OK);
return 0;
}
while(Process32Next(hSnapshot, &pe)) //循环查找下一个进程
{
if(!strcmp(lpszProcessName, pe.szExeFile)) //找到了
{
return pe.th32ProcessID;
}
}
return 0;
}
BOOL CpingmuquciDlg::InitHook(HANDLE hProcess)
{
//提升进程访问权限
if(!enableDebugPriv())
{
printf("提升进程访问权限 Error!\n");
return -1;
}
//定义线程体的大小,实际分配的内存大小是页内存大小的整数倍
size_Func=1024*8;
dwFunAddr = (DWORD)VirtualAllocEx(hProcess, NULL, size_Func, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if((LPVOID)dwFunAddr == NULL)
{
printf("申请线程内存失败!\n");
CloseHandle(hProcess);
return FALSE;
}
size_Pramam=sizeof(RemoteParam);
dwPramaAddr = (DWORD)VirtualAllocEx(hProcess, NULL, size_Pramam, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if((LPVOID)dwPramaAddr == NULL)
{
printf("申请参数内存失败!\n");
CloseHandle(hProcess);
return FALSE;
}
// RemoteParam m_RParam;
ZeroMemory(&m_RParam, sizeof(m_RParam));
HMODULE hKernel32 = LoadLibrary("kernel32.dll");
HMODULE hUser32 = LoadLibrary("user32.dll");
HMODULE hGdi32 = LoadLibrary("gdi32.dll");
m_RParam.dwTextOut = (DWORD)GetProcAddress(hGdi32, "TextOutW");
m_RParam.dwExtTextOut = (DWORD)GetProcAddress(hGdi32, "ExtTextOutW");
m_RParam.dwGetCurrentProcess = (DWORD)GetProcAddress(hKernel32, "GetCurrentProcess");
m_RParam.dwWriteProcessMemory = (DWORD)GetProcAddress(hKernel32, "WriteProcessMemory");
m_RParam.dwPostMessage = (DWORD)GetProcAddress(hUser32, "PostMessageW");
m_RParam.dwSendMessage = (DWORD)GetProcAddress(hUser32, "SendMessageW");
m_RParam.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxW");
m_RParam.bHookAlready=TRUE;
m_RParam.hwnd=m_hwnd_hook;
m_RParam.lpString=NULL;
wchar_t str2[]={L"我拦截API成功了,哈哈^o^"};
::wmemcpy_s(m_RParam.info,sizeof(m_RParam.info),str2,sizeof(str2));
for(int i=15; i<31; i++){m_RParam.info[i]=L'\0';}
// unsigned char oldcode[10];
// unsigned char newcode[10];
int praadd = (int)dwPramaAddr;
int threadadd = (int)dwFunAddr;
newcode[4] = praadd>>24;
newcode[3] = (praadd<<8)>>24;
newcode[2] = (praadd<<16)>>24;
newcode[1] = (praadd<<24)>>24;
newcode[0] = 0x68; //0x68: push newcode[1..4],参数先压栈
int offsetaddr = threadadd - (int)m_RParam.dwExtTextOut - 10 ;
newcode[9] = offsetaddr>>24;
newcode[8] = (offsetaddr<<8)>>24;
newcode[7] = (offsetaddr<<16)>>24;
newcode[6] = (offsetaddr<<24)>>24;
newcode[5] = 0xE8; //0xE8: call newcode[6..9],然后调用函数
for(int i = 0; i < 10; i++){m_RParam.newCode[i]=newcode[i];}
CString str_oldcode;
str_oldcode="m_RParam.NewCode: ";
for(int i = 0; i< 10; i++){CString str;str.Format("0x%.2x ", m_RParam.newCode[i]);str_oldcode+=str;}
str_oldcode+="\r\n";
DWORD dwRead = 0;
if(!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)m_RParam.dwExtTextOut, oldcode, 10, &dwRead))
{
printf("read error");
CloseHandle(hProcess);
FreeLibrary(hKernel32);
FreeLibrary(hUser32);
FreeLibrary(hGdi32);
return FALSE;
}
strcat((char*)m_RParam.oldCode, (char*)oldcode);
m_RParam.FunAddr = dwFunAddr;
str_oldcode+="m_RParam.OldCode: ";
for(int i = 0; i< 10; i++){CString str;str.Format("0x%.2x ", m_RParam.oldCode[i]);str_oldcode+=str;}
str_oldcode+="\n";
DWORD dwWrite = 0;
if(!WriteProcessMemory(hProcess, (LPVOID)dwFunAddr, (LPVOID)&HookTextOut, size_Func, &dwWrite))
{
printf("WriteRemoteProcessesMemory Error 1 !\n");
CloseHandle(hProcess);
FreeLibrary(hKernel32);
FreeLibrary(hUser32);
FreeLibrary(hGdi32);
return FALSE;
}
if(!WriteProcessMemory(hProcess, (LPVOID)dwPramaAddr, (LPVOID)&m_RParam, sizeof(RemoteParam), &dwWrite))
{
printf("WriteRemoteProcessesMemory Error 2 !\n");
CloseHandle(hProcess);
FreeLibrary(hKernel32);
FreeLibrary(hUser32);
FreeLibrary(hGdi32);
return FALSE;
}
FreeLibrary(hKernel32);
FreeLibrary(hUser32);
FreeLibrary(hGdi32);
CString str;
str.Format("m_RParam.dwExtTextOut:%.8x\r\nRParam.dwMessageBox:%.8x\r\nRParam.dwGetCurrentProcess:%.8x\r\nRParam.dwWriteProcessMemory:%.8x\r\nRParam.FunAddr:%.8x\r\ndwPramaAddr=%.8x\r\n",
m_RParam.dwExtTextOut, m_RParam.dwMessageBox, m_RParam.dwGetCurrentProcess, m_RParam.dwWriteProcessMemory, m_RParam.FunAddr, dwPramaAddr);
str+=str_oldcode;
m_edit.SetWindowText(str);
return TRUE;
}
BOOL CpingmuquciDlg::ClearHook(HANDLE hProcess)
{
HookOff(m_hProcess);
VirtualFreeEx(m_hProcess, (LPVOID)dwFunAddr, 0, MEM_RELEASE); //MEM_DECOMMIT仅标示内存空间不可用,内存页还将存在。MEM_RELEASE完全回收。
VirtualFreeEx(m_hProcess, (LPVOID)dwPramaAddr, 0, MEM_RELEASE); //MEM_DECOMMIT仅标示内存空间不可用,内存页还将存在。MEM_RELEASE完全回收。
dwFunAddr=NULL;
dwPramaAddr=NULL;
m_hProcess=NULL;
return TRUE;
}
BOOL CpingmuquciDlg::HookOn(HANDLE hProcess)
{
DWORD dwWrite=0;
if(!WriteProcessMemory(hProcess, (LPVOID)m_RParam.dwExtTextOut, (LPVOID)newcode, 10, &dwWrite)) //挂上API钩子
{
printf("WriteRemoteProcessesMemory Error 4 !\n");
return FALSE;
}
return TRUE;
}
BOOL CpingmuquciDlg::HookOff(HANDLE hProcess)
{
DWORD dwWrite=0;
if(!WriteProcessMemory(hProcess, (LPVOID)m_RParam.dwExtTextOut, (LPVOID)oldcode, 10, &dwWrite)) //摘掉API钩子
{
printf("WriteRemoteProcessesMemory Error 5 !\n");
return FALSE;
}
return TRUE;
}
void CpingmuquciDlg::OnBnClickedButton1() //打开API钩子
{
m_hwnd_hook=this->GetSafeHwnd(); //将对话框设置为安装API钩子的元凶
m_mouse_hook.StartHook(m_hwnd_hook); //开启全局鼠标钩子
}
void CpingmuquciDlg::OnBnClickedButton2() //关闭API钩子
{
m_mouse_hook.StopHook(m_hwnd_hook); //关闭全局鼠标钩子
}
afx_msg LRESULT CpingmuquciDlg::OnHookTextout(WPARAM wParam, LPARAM lParam)
{
wchar_t str[200];
ZeroMemory(str, sizeof(str)/sizeof(wchar_t));
RemoteParam RParam;
ZeroMemory(&RParam, sizeof(RParam));
DWORD dwRead=0;
if(!ReadProcessMemory(m_hProcess, (LPCVOID)dwPramaAddr, &RParam, sizeof(RParam), &dwRead))
{
printf("read error");
CloseHandle(m_hProcess);
return 1;
}
if(!ReadProcessMemory(m_hProcess, (LPCVOID)RParam.lpString, str, sizeof(str), &dwRead))
{
printf("read error");
CloseHandle(m_hProcess);
return 1;
}
char sss[400];
ZeroMemory(sss, sizeof(sss)/sizeof(char));
int len=WideCharToMultiByte(CP_ACP,0,str,-1,NULL,0,NULL,NULL);
WideCharToMultiByte(CP_ACP,0,str,-1,sss,len,NULL,NULL); //宽字符转多字节字符
m_edit.SetWindowText(sss); //将截取来的字符串显示到对话框的文本框里面
return 0;
}
void CpingmuquciDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(nIDEvent==TIME_ID_1)
{
this->KillTimer(TIME_ID_1);
POINT pt;
GetCursorPos(&pt);
CWnd* pWnd=WindowFromPoint(pt);
if(pWnd!=NULL)
{
HWND hwnd=pWnd->GetSafeHwnd();
DWORD dwProcessId=NULL;
GetWindowThreadProcessId(hwnd, &dwProcessId); //获取进程ID
if(dwProcessId!=NULL)
{
if(m_dwProcessId!=dwProcessId)
{
if(m_hProcess!=NULL){ClearHook(m_hProcess);}
m_hProcess=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwProcessId);
m_dwProcessId=dwProcessId;
InitHook(m_hProcess);
}
HookOn(m_hProcess); //挂上API钩子
RECT rc;
rc.left=pt.x-2;
rc.right=pt.x+2;
rc.top=pt.y;
rc.bottom=pt.y+4;
pWnd->ScreenToClient(&rc);
pWnd->InvalidateRect(&rc); //使矩形区域失效,放入WM_PAINT消息
pWnd->UpdateWindow(); //强制更新
HookOff(m_hProcess); //摘掉API钩子
}
}
}
CDialogEx::OnTimer(nIDEvent);
}
afx_msg LRESULT CpingmuquciDlg::OnMyMousemove(WPARAM wParam, LPARAM lParam)
{
this->KillTimer(TIME_ID_1);
this->SetTimer(TIME_ID_1,1000,NULL); //设置鼠标在屏幕某处停留1秒的时钟
return 0;
}
效果截图: