我想弄清楚GetWindowText背后的系统调用是什么。我编写了一个简单的程序来调用GetWindowText,该程序在另一个过程中带有窗口的句柄。
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MessageBox(0,"Attach debugger and set bp","on GetWindowTextA",0);
HWND winmine = FindWindow(NULL,"Minesweeper");
if(winmine != NULL)
{
char buf[255] = "";
GetWindowTextA(winmine, buf, 254);
MessageBox(0,buf,"Found",0);
}
else
{
MessageBox(0,"?","Found nothing",0);
}
return 0;
}
我连接了调试器,并逐步完成了GetWindowTextA调用,手动完成了除这些API调用以外的所有操作(按顺序):
这些API调用似乎都不能读取调用进程不拥有的内存中的字符串。我使用了一个用户模式调试器,因此在步入实现时我当然并没有陷入内核模式。这意味着GetWindowText无需执行上下文切换即可获取窗口名称。这似乎意味着存在的每个窗口的文本都可以在没有上下文切换的情况下进行访问..这是不对的,因为Windows无法为系统上每个窗口/控件的每个窗口/控件保留文本的副本。单进程。
我读过this article。它提到了窗口名称存储在引号“特殊位置”中,但是没有说明如何在不进行系统调用/上下文切换的情况下从不同的进程访问该“特殊位置”。
因此,我正在寻找有关此操作方式的任何解释。您可以提供的任何信息都将不胜感激。
最佳答案
此信息存储在内存中,该内存在所有使用user32.dll
的进程之间共享。您可以尝试在进程的虚拟空间中搜索其他进程窗口的unicode名称。
它在user32.dll
加载期间被映射到进程地址空间。涉及到一些内核结构/部分:win32k!gSharedInfo
,win32k!ghSectionShared
,win32k!gpsi
和其他(我不知道)。
实际上,HWND
的低16位代表基址为*(&user32!gSharedInfo + 1)
的窗口信息数组的索引。该窗口信息的第一个字段是包含所有共享窗口信息的另一个结构的内核地址。减去该节的内核地址与其用户空间映射(存储在TEB!Win32ClientInfo
中)之间的差异,您可以获得相关信息。user32!ValidateHwnd
是将窗口句柄转换为该地址的函数,内部user32
函数(例如user32!DefWindowProcWorker
)可以使用该地址。GetWindowTextW
的伪代码如下所示(不包括错误处理):
GetWindowTextW(HWND hwnd, wchar_t* buf, int size)
{
inner_hwnd = ValidateHwnd(hwnd);
if (TestWindowProcess(inner_hwnd))
SendMessageWorker(inner_hwnd, WM_GETTEXT, size, buf, FALSE);
else
DefWindowProcWorker(inner_hwnd, WM_GETTEXT, size, buf, FALSE);
}
在您的情况下使用
DefWindowProcWorker
调用的WM_GETTEXT
只会解析inner_hwnd
引用的结构,并将窗口的名称复制到buf
中。我从来不知道存储在其中的所有信息,尽管不使用各种
user
/gdi
参数污染进程的虚拟空间似乎是一个不错的选择。此外,较低完整性的过程不应能够获得较高完整性的过程敏感信息。关于windows - GetWindowText如何在没有syscall读取该进程的内存的情况下获取另一个进程拥有的窗口的名称?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21508662/