This post is the story of an unuseful fuzzer that became an unuseful but funny PoC. These days I have been playing with window messages and I would like to share some notes about the behavior of some messages, such as WM_SETTEXT or WM_COPYDATA, and a tiny PoC to execute code into explorer.exe process by using these messages and SetThreadContext. This is not about a bug or vulnerability, these window messages work as expected. It is only some ideas about using these messages in a tricky way to put our data into the address space of some target processes.
I started writting a tiny fuzzer to enumerate all the windows in the system and send random messages with random data to them. Nothing happy and fun happened with my fuzzer, like a crash in some application, etc… I noticed my fuzzer was totally unuseful but, before burying it forever, I decided to add an additional code to search the strings/data sent with these window messages through all of the memory regions of all the processes running in the machine.
I found the data that I was sending with the messages, it stayed in the address space of some processes. It is not a surprise. For example, If you set the text of a window with WM_SETTEXT, probably the thread associated with the window could be storing that text in some buffer, keeping it for more or less time, etc… Probably something similar to this could be happening with other APIs, not only window messages.
WM_COPYDATA message is more interesting. We can send binary data and this data could be stored in the address space of some processes.
I did some test in a windows 10 x64 machine. After sending WM_SETTEXT and WM_COPYDATA to all windows owned by explorer.exe, the string sent with WM_SETTEXT appeared in the address space of explorer.exe (in wide char), and the binary data sent with WM_COPYDATA appeared there too.
PoC Code: Inject Explorer.exe Process
I decided to transform my totally unuseful fuzzer into a (not very useful) Proof of Concept to execute code into explorer.exe with WM_SETTEXT + WM_COPYDATA + SetThreadContext, and here you can find the Frankestein:
In this PoC I inject a path to notepad.exe with WM_SETTEXT and a very simple ROP string with WM_COPYDATA (this tiny ROP will cause a call to CreateProcess to launch notepad.exe and a call to ExitProcess), into the address space of explorer.exe. After this, I choose an explorer’s thread, and I use SetThreadContext to point RSP to my data copied with WM_COPYDATA and RIP to a “weird” code at ntdll (Ntdll version 10.0.16299.64 x64):
This ntdll code is very nice because it let us to set all the volatile registers necesary for Microsoft x64 calling convention (rcx, rdx, r8, r9). SetThreadContext doesn’t let us to set these volatile registers (we need to set them because the first 4 arguments for the APIs are stored there).
I hope u enjoy it!