FindWindow

函数功能:

函数检索处理顶级窗口的类名和窗口名称匹配指定的字符串,这个函数不搜索子窗口。
第一个是要找的窗口的类,第二个是要找的窗口的标题

函数声明:

WINUSERAPI
HWND
WINAPI
FindWindowW(
    _In_opt_ LPCWSTR lpClassName,
    _In_opt_ LPCWSTR lpWindowName);

在搜索的时候不一定两者都知道,但至少要知道其中的一个。

第一个参数

lpClassName,输入参数,指向一个以null结尾的、用来指定类名的字符串或一个可以确定类名字符串的原子。如果这个参数是一个原子,那么它必须是一个在调用此函数前已经通过GlobalAddAtom函数创建好的全局原子。这个原子(一个16bit的值),必须被放置在lpClassName的低位字节中,lpClassName的高位字节置零。

如果该参数为null时,将会寻找任何与lpWindowName参数匹配的窗口。

第二个参数

指向一个以null结尾的、用来指定窗口名(即窗口标题)的字符串。如果此参数为NULL,则匹配所有窗口名

返回值

如果函数执行成功,则返回值是拥有指定窗口类名或窗口名的窗口的句柄

如果函数执行失败,则返回值为NULL。可以通过调用GetLastError函数获得更加详细的错误信息

注意:

如果要搜索的外部程序的窗口标题比较容易得到,问题是比较简单的。可如果窗口的标题不固定或者根本就没有标题,怎么得到窗口的类呢?这时我们可使用Microsoft Spy++,运行Spy++,按ALT+F3,在弹出的界面中拖动目标图标到程序上即可。
举例:
在调用时使用如下语句:
hwndCalc = FindWindow(0&, “计算器”)
这里的0&就表示忽略类名。需要注意的是FindWindow(0&, “计算器”)和FindWindow("", “计算器”)有两种完全不同的含义,前者表示忽略窗口的类,而后者表示窗口的类是个空串

在搜索的时候不一定两者都知道,但至少要知道其中的一个。有的窗口的标题是比较容易得到的,如"计算器",所以搜索时应使用标题进行搜索。但有的软件的标题不是固定的,如"记事本",如果打开的文件不同,窗口标题也不同,这时使用窗口类搜索就比较方便。如果找到了满足条件的窗口,这个函数返回该窗口的句柄,否则返回0
举例:

	HWND hwnd = FindWindow(NULL, "计算器");
	if (hwnd != NULL)
	{
		MessageBox(NULL,"来吧","找到计算器窗口",MB_OK);
	}
	else
	{
		MessageBox(NULL, "来吧", "未找到计算器窗口", MB_OK);
	}
	hwnd = FindWindow("Notepad", NULL);
	if (hwnd != NULL)
	{
		MessageBox(NULL, "来吧", "找到记事本窗口", MB_OK);
	}
	else
	{
		MessageBox(NULL, "来吧", "没有找到记事本窗口", MB_OK);
	}

注意,此时我打开记事本文件名字叫做01.txt - 记事本,即第二个参数

HWND hwnd = FindWindow(NULL, "计算器");
	if (hwnd != NULL)
	{
		MessageBox(NULL,"来吧","找到计算器窗口",MB_OK);
	}
	else
	{
		MessageBox(NULL, "来吧", "未找到计算器窗口", MB_OK);
	}
	hwnd = FindWindow(NULL, "01.txt - 记事本");
	if (hwnd != NULL)
	{
		MessageBox(NULL, "来吧", "找到记事本窗口", MB_OK);
	}
	else
	{
		MessageBox(NULL, "来吧", "没有找到记事本窗口", MB_OK);
	}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

GetWindowThreadProcessId

函数功能

该函数返回创建指定窗口线程的标识和创建窗口的进程的标识符,后一项是可选的。得到窗口句柄后我们可以通过GetWindowThreadProcessId来获得窗口所属进程ID线程ID从而判断创建窗口的进程和线程。

函数声明

WINUSERAPI
DWORD
WINAPI
GetWindowThreadProcessId(
    _In_ HWND hWnd,
    _Out_opt_ LPDWORD lpdwProcessId);

第一个参数:

输入参数,hWnd,窗口句柄。

第二个参数:

输出参数,lpdwProcessld,接收进程标识的32位值的地址。如果这个参数不为NULL,GetWindwThreadProcessld将进程标识拷贝到这个32位值中,否则不拷贝,输出参数是进程ID地址

返回值

返回值为创建窗口的线程标识,返回的是窗口所属线程ID

代码实现

  HWND hWnd; DWORD ProcessID, ThreadID;
    hWnd=FindWindow(NULL, L"计算器");
    if (hWnd == NULL)
        return 0;
    ThreadID = GetWindowThreadProcessId(hWnd, &ProcessID);
    printf("%d\n%d", ProcessID, ThreadID);

在这里插入图片描述

OpenProcess

函数功能:

开一个已存在的进程对象,并返回进程的句柄。

函数声明:

WINBASEAPI
HANDLE
WINAPI
OpenProcess(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL bInheritHandle,
    _In_ DWORD dwProcessId
    );

第一个参数:

输入参数,dwDesiredAccess: 想拥有的该进程访问权限。

  • PROCESS_ALL_ACCESS //所有能获得的权限
  • PROCESS_CREATE_PROCESS //需要创建一个进程
  • PROCESS_CREATE_THREAD //需要创建一个线程
  • PROCESS_DUP_HANDLE //重复使用DuplicateHandle句柄
  • PROCESS_QUERY_INFORMATION //获得进程信息的权限,如它的退出代码、优先级
  • PROCESS_QUERY_LIMITED_INFORMATION /*获得某些信息的权限,如果获得
  • PROCESS_QUERY_INFORMATION,也拥有PROCESS_QUERY_LIMITED_INFORMATION权限*/
  • PROCESS_SET_INFORMATION //设置某些信息的权限,如进程优先级
  • PROCESS_SET_QUOTA //设置内存限制的权限,使用SetProcessWorkingSetSize
  • PROCESS_SUSPEND_RESUME //暂停或恢复进程的权限
  • PROCESS_TERMINATE //终止一个进程的权限,使用TerminateProcess
  • PROCESS_VM_OPERATION //操作进程内存空间的权限(可用VirtualProtectEx和WriteProcessMemory)
  • PROCESS_VM_READ //读取进程内存空间的权限,可使用ReadProcessMemory
  • PROCESS_VM_WRITE //读取进程内存空间的权限,可使用WriteProcessMemory
  • SYNCHRONIZE //等待进程终止

第二个参数:

输入参数,bInheritHandle: 表示所得到的进程句柄是否可以被继承

第三个参数:

输入参数,dwProcessId:被打开进程的PID

返回值:

如果函数调用成功将返回一个进程句柄值,否则将返回NULL
注意:在使用完所获得的进程句柄后一定要调用CloseHandle(handle)来关闭进程的句柄。

代码实现:

  HWND hWnd; DWORD ProcessID, ThreadID;
    hWnd=FindWindow(NULL, L"计算器");
    if (hWnd == NULL)
        return 0;
    ThreadID = GetWindowThreadProcessId(hWnd, &ProcessID);
    HANDLE handle=OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessID);
    printf("%d", handle);
    CloseHandle(handle);

在这里插入图片描述

ReadProcessMemory

函数功能:

函数声明:

WINBASEAPI
_Success_(return != FALSE)
BOOL
WINAPI
ReadProcessMemory(
    _In_ HANDLE hProcess, // 被读取进程的句柄;
    _In_ LPCVOID lpBaseAddress,, // 读的起始地址;
    _Out_writes_bytes_to_(nSize,*lpNumberOfBytesRead) LPVOID lpBuffer,// 存放读取数据缓冲区;
    _In_ SIZE_T nSize, // 一次读取的字节数;
    _Out_opt_ SIZE_T* lpNumberOfBytesRead// 实际读取的字节数;
    );

第一个参数:

[in] Handle to the process whose memory is being read.

In Windows CE, any call to OpenProcess returns a process handle with the proper access rights.
输入参数,远程进程句柄。被读取者

第二个参数:

[in] Pointer to the base address in the specified process to be read.

Before data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access. If so, the function proceeds; otherwise, the function fails.
输入参数,远程进程中内存地址。从具体何处读取(关键,因为不是随便取一个就能读出来的)

第三个参数:

[out] Pointer to a buffer that receives the contents from the address space of the specified process.
输出参数,本地进程中内存地址.函数将读取的内容写入此处

第四个参数:

[in] Specifies the requested number of bytes to read from the specified process.
输入参数,要传送的字节数。要写入多少

第五个参数:

[out] Pointer to the number of bytes transferred into the specified buffer.

If lpNumberOfBytesRead is NULL, the parameter is ignored.
输出参数,实际传送的字节数. 函数返回时报告实际写入多少

返回值:

If the function succeeds, the return value is nonzero.
如果成功,返回非0。

If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.
如果失败,返回0,错误可通过GetLastError获得

The function fails if the requested read operation crosses into an area of the process that is inaccessible.
重点:当操作进入了进程不可读取的部分时会失败,大多数人犯的错误。

代码实现:

大家需要用CE进行一系列操作,然后找到一个可以有读写权限的地址,别猜,


    HWND hWnd; DWORD ProcessID, ThreadID;
    DWORD nSize;
    unsigned char gamedata[24] = { 0 };
    hWnd=FindWindow(NULL, L"计算器");
    if (hWnd == NULL)
        return 0;
    ThreadID = GetWindowThreadProcessId(hWnd, &ProcessID);
    HANDLE handle=OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessID);
    printf("%d", handle);

    int a=ReadProcessMemory(handle, (LPCVOID)0x14D56107798, &gamedata, MAX_PATH, &nSize);
    if (a == 0)
        return 0;
    printf("%d", gamedata);
    CloseHandle(handle);

在这里插入图片描述
在这里插入图片描述

练手题目

看完之后就去练练手吧,前往这篇博客,这里能理解的话,那么接下来将会对你有更大的提升:
https://blog.csdn.net/CSNN2019/article/details/112035707

插入一个提示(vs如何打开MSDN帮助文档)

比如要查看float的特征。
在vs中输入float,然后按F1键,会在默认浏览器上打开帮助文档。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐