How does GetWindowText get the name of a window owned by another process without a syscall to read that process's memory?

system-calls, winapi, windows

Solution

`GetWindowText` got the window name without performing a context switch. Which seems to imply that the text for every window that exists is accessible without a context switch.

This info is stored in memory that is shared between all the processes that use `user32.dll`. You may try to search virtual space of your process for unicode names of other processes' windows.

It gets mapped into the process address space during `user32.dll` loading. There are some kernel structures/sections involved: `win32k!gSharedInfo`, `win32k!ghSectionShared`, `win32k!gpsi` and others (which I don't know of).

Actually, the lower 16 bits of `HWND` represents index into window info array with base address `*(&user32!gSharedInfo + 1)`. The first field of this window info is the kernel address of another structure which contains all the shared window information. Subtracting the difference between kernel address of the section and its user-space mapping (which is stored in `TEB!Win32ClientInfo`) you can get relevant info.

`user32!ValidateHwnd` is the function that converts window handle into this address which can be used by inner `user32` functions like `user32!DefWindowProcWorker`.

Pseudocode of `GetWindowTextW` looks like (excluding error-handling):

    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` which is called in your case with `WM_GETTEXT` will just parse the structure referenced by `inner_hwnd` and copy window's name into `buf`.

it seems that the text for EDITTEXT controls are not stored in this manner

I never knew all the info that was stored in there though it seems like a good choice to not pollute processes' virtual space with all kinds of `user`/`gdi` params. Besides, lower integrity processes should not be able to get higher integrity processes sensitive information.

Problem

I wanted to figure out what the syscalls behind GetWindowText are. I wrote a simple program to call GetWindowText with a handle to a window in a different process. ``` 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; } ``` I attached a debugger and stepped through the GetWindowTextA call, manually stepping through everything except these API calls (in order): - GetWindowThreadProcessId (in GetWindowLong) - InterlockedIncrement - WCSToMBEx (which is basically WideCharToMultiByte) - InterlockedDecrement None of these API calls seem to be able to read a string in memory not owned by the calling process. I used a usermode debugger so I certainly didn't end up in kernelmode while stepping without realizing it. This means that GetWindowText got the window name without performing a context switch. Which seems to imply that the text for every window that exists is accessible without a context switch.. and that can't be right because there's no way Windows keeps a copy of the text for every single window/control on the system, on every single process. I have read this Raymond Chen blog post The secret life of GetWindowText archive. It mentions that window names are stored in quote "a special place", but does not explain how this "special place" can be accessed from a different process without a syscall/context switching. So I'm looking for any explanations as to how this is done. Any information you can provide is greatly appreciated.

Original source