-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
# WindowInvestigator: a window manager investigation toolbox | ||
*Brought to you by [Etienne Dechamps][] - [GitHub][]* | ||
|
||
WindowInvestigator is a small set of highly specialized tools that can be used | ||
to investigate Windows window manager issues. It was developed with the goal of | ||
investigating the behaviour of a piece of internal Windows code called the Rude | ||
Window Manager; see [RudeWindowFixer][] for more background. However it might | ||
also be useful in other scenarios. | ||
|
||
For example, WindowInvestigator is what made it possible to come up with | ||
analyses like the following: | ||
|
||
![Firefox timeline](firefox-timeline.png) | ||
|
||
## WindowManagementLogging tracing | ||
|
||
Some of the internal Windows shell window management code, including Rude Window | ||
Manager code, uses an internal class called `WindowManagementLogging` to log | ||
various events and the results of computations. I found these logs to be | ||
extremely relevant to my investigation. | ||
|
||
`WindowManagementLogging` acts as an [Event Tracing for Windows (ETW)][] | ||
provider. Through binary reverse engineering, it has been determined that the | ||
provider GUID is `F84AA759-31D3-59BF-2C89-3748CF17FD7E`. | ||
|
||
You can use this GUID in event consumers to receive the log. For example you | ||
can enter the GUID directly in [TraceView][] for real time logging, or you can | ||
load the included [`WindowManagementLogging.wprp`][] [recording profile][] into | ||
the [Windows Performance Recorder (WPR)][] for a more thorough analysis. | ||
|
||
## WindowMonitor | ||
|
||
WindowMonitor is a command line tool that is aimed at investigating window | ||
states and how they change over time. If called without any command line | ||
arguments, it will: | ||
|
||
- Dump an initial list of all [visible windows][] to the standard output, along | ||
with the values of various window properties. | ||
- This is to provide the initial reference starting point. | ||
- Create a [message-only window][] that: | ||
- Registers and listens to [shell hook messages][]. | ||
- The message identifier for shell hook messages is typically `0xC029`, but | ||
that is not necessarily always the case. Look for the `Started` trace | ||
event to determine the actual message identifier. | ||
- Registers and listens to [appbar][] messages. | ||
- WindowMonitor uses `WM_USER` (`0x400`) as the identifier for appbar | ||
messages. | ||
- An appbar message to watch out for is [`ABN_FULLSCREENAPP`][] which | ||
is sent as a consequence of the monitor rudeness state changing. | ||
- Sends a [`WM_TIMER`][] (`0x113`) message to itself every 16 milliseconds. | ||
- Every time any message is received on the aforementioned window, WindowMonitor | ||
logs it through an [Event Tracing for Windows (ETW)][] provider. | ||
- The provider GUID is `500D9509-6850-440C-AD11-6EA625EC91BC`. You can enter | ||
that GUID directly in [TraceView][] for real time logging, or you can load | ||
the included [`WindowInvestigator.wprp`][] [recording profile][] into the | ||
[Windows Performance Recorder (WPR)][] for a more thorough analysis. | ||
- In addition to logging the message itself, every time a message is received, | ||
WindowMonitor will go through every visible window and log any changes that | ||
may have occurred to any of the watched window properties (e.g. styles, | ||
position) since the last message. | ||
- This also includes changes to the Z-order, which are determined by watching | ||
for changes in the order in which windows are returned from | ||
[`EnumWindows()`][]. | ||
|
||
WindowMonitor can also be called with a specific window handle as a command line | ||
argument (e.g. `WindowMonitor.exe 0x4242`). In that case, WindowMonitor will not | ||
listen for messages; instead, it will check the state of that window every 2 | ||
milliseconds and will log any changes. Note that Z-order changes are not | ||
reported in this mode. This single-window mode is useful when you need more | ||
precise timing information. | ||
|
||
Note: it is recommended to run WindowMonitor as Administrator; this will allow | ||
it to set the Real-Time [process priority class][] to achieve the most precise | ||
timing. | ||
|
||
Note: WindowMonitor might not run on some Windows versions because it retrieves | ||
a couple of undocumented window properties through reverse-engineered | ||
`user32.dll` Windows API entry points that might not exist in all versions. You | ||
might need to adjust the code to remove calls to these APIs. | ||
|
||
## DelayedPosWindow | ||
|
||
This extremely simple tool simply displays a standard window that has the | ||
particularity of injecting a customizable delay in the processing of | ||
[`WM_WINDOWPOSCHANGING`][] messages. This is useful to simulate applications | ||
that are slow to process these messages (e.g. Firefox), and to force latent race | ||
conditions to the surface. | ||
|
||
The delay is specified in milliseconds as a command line argument. For example, | ||
`DelayedPosWindow.exe 100` will make every [`WM_WINDOWPOSCHANGING`][] message | ||
take ~100 ms to process. | ||
|
||
Similar to WindowMonitor, DelayedWindowPos will trace every window message | ||
received, as well as details of `WM_WINDOWPOSCHANGING` messages. The trace | ||
provider details are the same as WindowMonitor. | ||
|
||
## TransparentFullscreenWindow | ||
|
||
This trivial tool simply displays a window that has the `WS_EX_LAYERED` and | ||
`WS_EX_TRANSPARENT` [extended window styles][]. It also makes the window full | ||
screen by setting its dimensions to be the same as the screen. This emulates | ||
a "sneaky" full screen window such as the GeForce Experience overlay window. | ||
|
||
Note that this tool has only been tested in a single-monitor setup. The | ||
dimensions of the window might be incorrect on a multi-monitor setup. | ||
|
||
## Other recommended tools | ||
|
||
- [GuiPropView][] is a nice tool for looking at window properties in general. | ||
- [Spy++][] is useful to monitor the messages that a given window is receiving. | ||
- Make sure to use the 64-bit version when monitoring a 64-bit process, | ||
otherwise no messages will be shown. | ||
- For reverse engineering Windows binaries, I used [Ghidra][]. | ||
- I found it to be quite effective, although the relevant code is littered | ||
with C++ virtual function calls which are sadly [very][ghidrav1] | ||
[painful][ghidrav2] to analyse in Ghidra. | ||
- Whatever software you use, do make sure to use the [public Microsoft | ||
symbols][] as these will make your life much easier! | ||
|
||
## Developer information | ||
|
||
[![.github/workflows/continuous-integration.yml](https://github.com/dechamps/WindowInvestigator/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/dechamps/WindowInvestigator/actions/workflows/continuous-integration.yml) | ||
|
||
WindowInvestigator is designed to be built using CMake within the Microsoft | ||
Visual C++ 2019 toolchain native CMake support. | ||
|
||
There are no dependencies besides the Windows SDK. | ||
|
||
[`ABN_FULLSCREENAPP`]: https://docs.microsoft.com/en-us/windows/win32/shell/abn-fullscreenapp | ||
[appbar]: https://docs.microsoft.com/en-us/windows/win32/shell/application-desktop-toolbars | ||
[Etienne Dechamps]: mailto:etienne@edechamps.fr | ||
[`EnumWindows()`]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumwindows | ||
[Event Tracing for Windows (ETW)]: https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing | ||
[extended window styles]: https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles | ||
[GitHub]: https://github.com/dechamps/WindowInvestigator | ||
[Ghidra]: https://ghidra-sre.org/ | ||
[ghidrav1]: https://github.com/NationalSecurityAgency/ghidra/issues/516 | ||
[ghidrav2]: https://github.com/NationalSecurityAgency/ghidra/issues/573 | ||
[GuiPropView]: https://www.nirsoft.net/utils/gui_prop_view.html | ||
[message-only window]: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows | ||
[process priority class]: https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities#priority-class | ||
[public Microsoft symbols]: https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/microsoft-public-symbols | ||
[recording profile]: https://docs.microsoft.com/en-us/windows-hardware/test/wpt/authoring-recording-profiles | ||
[RudeWindowFixer]: https://github.com/dechamps/RudeWindowFixer | ||
[shell hook messages]: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registershellhookwindow | ||
[TraceView]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/traceview | ||
[Spy++]: https://docs.microsoft.com/en-us/visualstudio/debugger/spy-increment-help | ||
[visible windows]: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#window-visibility | ||
[`WindowManagementLogging.wprp`]: WindowManagementLogging.wprp | ||
[`WindowInvestigator.wprp`]: WindowInvestigator.wprp | ||
[Windows Performance Recorder (WPR)]: https://docs.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-recorder | ||
[`WM_TIMER`]: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-timer | ||
[`WM_WINDOWPOSCHANGING`]: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-windowposchanging |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.