VC 如何读取第三方软件ListView控件(外挂篇之一)

一、VC 如何读取第三方软件ListView控件

        

        写下这篇文章前,我想先对我的导师崔Sir说声:感谢!因为没有他的指导,其中一个Bug我是很难解决的。

        因项目需要,需要开发外挂对第三方软件进行操作并获取ListView控件内的内容。

        一般来说,要解决此问题大家肯定跟我初始想法一样,直接发送 LVM_GETITEM 消息给第三方软件ListView控件。事实上,有些消息直接发送可以获取到想要的结果,如 LVM_GETITEMCOUNT。但是,并不是所有的消息直接发送后都可以获取到对应的结果,譬如,LVM_GETITEM。 

        查阅各种资料,解决办法详细步骤如下:

        1. 根据窗口句柄获取该窗口的进程 ID:GetWindowThreadProcessId

        2. 打开指定 ID 的进程:OpenProcess

        3. 在该进程空间分配:VirtualAllocEx

        4. 写入数据:WriteProcessMemory

        5. ListView 相关消息 / 宏:LVM_GETITEM、LVM_GETITEMTEXT (ListView_GetItemText)

        6.读取数据:ReadProcessMemory

        7.在该进程空间释放内存:VirtualFreeEx

        8.关闭进程句柄

        结合上面的步骤,我以获取任务管理器进程ListView控件内进程信息为例,并使用VS2010写下如下代码:

#define _AFXDLL
#include <afx.h>
#include <iostream>
#include <iomanip>
#include <Windows.h>
#include <string>

int main()
{
	//获取窗口句柄
	HWND hTaskMsgWnd = ::FindWindow("#32770", "Windows 任务管理器");
	HWND hProcWnd = ::FindWindowEx(hTaskMsgWnd, NULL, "#32770", "Processes");
	HWND hProcListView = ::FindWindowEx(hProcWnd, NULL, "SysListView32", NULL);
	HWND hHeaderWnd = (HWND)::SendMessage(hProcListView, LVM_GETHEADER, 0, 0);

	//获取行数与列数
	int rows = (int)::SendMessage(hProcListView, LVM_GETITEMCOUNT, 0, 0);
	int cols = (int)::SendMessage(hHeaderWnd, HDM_GETITEMCOUNT, 0, 0);

	//获取窗口线程与进程ID
	DWORD dwProcID = 0;
	::GetWindowThreadProcessId(hProcListView, &dwProcID);

	//打开进程
	//注意, 如果你的电脑是64位系统, 那么"任务管理器"进程则是64位的, 使用OpenProcess实际返回的是一个64位的句柄值
	//如果, 你的程序是采用W32编译器, 那么定义的进程句柄变量实际上是一个32位的句柄变量
	//现在, 如果你用32位的句柄变量来保存64位的句柄值, 它实际上是保存了一个被截取后的64位的句柄值, 这个值是错误的
	//这时, 你必须把编译器也调整为64位, 使句柄值内存长度统一
	HANDLE hProcess = NULL;
	hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcID);

	//进程空间的虚拟内存分配
	void* pVirBuf = ::VirtualAllocEx(hProcess, NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	for (int iRowIdx = 0; iRowIdx < rows; iRowIdx++)
	{
		for (int iColIdx = 0; iColIdx < cols; iColIdx++)
		{
			//填充单个子项的相关参数
			LVITEM item;
			item.mask = LVIF_TEXT;
			item.iItem = iRowIdx;
			item.iSubItem = iColIdx;
			item.cchTextMax = 256;
			item.pszText = (LPSTR)((int)pVirBuf + sizeof(LVITEM));

			//将单个子项的数据写入至进程虚拟内存空间pVirBuf内
			//注意, X64位下不要使用DWORD, DWORD=4BYTE, SIZE_T=8BYTE
			//如果使用DWORD, 会报错 "Run-Time Check Failure #2 - Stack around the variable 'xxx' was corrupted.", 一般由变量越界导致
			LONGLONG dwWriteByte = 0;
			::WriteProcessMemory(hProcess, pVirBuf, &item, sizeof(LVITEM), (SIZE_T*)&dwWriteByte);

			//发送获取项目的Windows消息
			::SendMessage(hProcListView, LVM_GETITEM, 0, (LPARAM)pVirBuf);

			//将虚拟内存第sizeof(LVITEM)之后的数据读出, 保存至变量内
			LONGLONG dwReadByte = 0;
			std::string content(256, '\0');
			::ReadProcessMemory(hProcess, (LPCVOID)((int)pVirBuf + sizeof(LVITEM)), const_cast<char*>(content.c_str()), 255, (SIZE_T*)&dwReadByte);

			//输出
			std::cout << content.c_str() << " ";
		}
		std::cout << std::endl;
	}
	//释放虚拟内存
	::VirtualFreeEx(hProcess, pVirBuf, 4096, MEM_RELEASE);
	::CloseHandle(hProcess);

	return 0;
}

        然而,我遇到2个问题:(以上代码是在X32下编译的,我的操作系统是X64的)

        1.不管我怎么修改我的代码,都没办法获取到ListView控件内的值?

         因为我的电脑是64位系统, 那么"任务管理器"进程则是64位的, 使用OpenProcess实际返回的是一个64位的句柄值。如果, 你的程序是采用W32编译器, 那么定义的进程句柄变量实际上是一个32位的句柄变量。现在, 如果你用32位的句柄变量来保存64位的句柄值, 它实际上是保存了一个被截取后的64位的句柄值, 这个值是错误的。由于保存了一个被截取后的64位的句柄值而不是NULL,所以没办法检查出句柄值是错误的。这时, 你必须把编译器也调整为64位, 或者使用其他方法使句柄值内存长度统一。

        

        2.程序结束时,会报错"Run-Time Check Failure #2 - Stack around the variable 'xxx' was corrupted."

        A.造成此报错的原因一般是内存越界

        B.这里造成的原因是:WriteProcessMemory/ReadProcessMemory第5个参数在X32下要传入DWORD类型,在X64下要传入SIZE_T类型。DWORD无论在X32/X64下均占用4BYTE,而SIZE_T在X64下占用8BYTE。如果,在X64下你传入DWORD,所以会报内存越界的错误,即使用强制转换。X64下解决办法即是考虑与SIZE_T占相同内存的LONGLONG类型或其他类型代替即可。


二、附录

int main()  
{  
	int i = 0;  
	i = sizeof(int);            // x86:4        x64:4  
	i = sizeof(long);           // x86:4        x64:4  
	i = sizeof(void*);          // x86:4        x64:8  
	i = sizeof(short);          // x86:2        x64:2  
	i = sizeof(float);          // x86:4        x64:4  
	i = sizeof(double);         // x86:8        x64:8  
	i = sizeof(int*);           // x86:4        x64:8  
	i = sizeof(WORD);           // x86:2        x64:2  
	i = sizeof(DWORD);          // x86:4        x64:4  
	i = sizeof(LONGLONG);       // x86:8        x64:8  
	i = sizeof(HANDLE);         // x86:4        x64:8  
	i = sizeof(HWND);           // x86:4        x64:8  
	i = sizeof(bool);           // x86:1        x64:1  
	i = sizeof(char);           // x86:1        x64:1  

	return 0;  
} 






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

l357630798

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值