wn32拦截ExtTextOut屏幕取词

在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;
}

=================================================

效果截图:

wn32拦截ExtTextOut屏幕取词_第1张图片

wn32拦截ExtTextOut屏幕取词_第2张图片

wn32拦截ExtTextOut屏幕取词_第3张图片

wn32拦截ExtTextOut屏幕取词_第4张图片

你可能感兴趣的:(wn32拦截ExtTextOut屏幕取词)