I'm trying to find a WndProc from explorer.exe that is handling these messages, I've found with Spy++:

<000001> 00000000000B01C8 P message:0xC02B [Registered:"SHELLHOOK"] wParam:00000025 lParam:000F0184
<000002> 00000000000B01C8 P message:0xC02B [Registered:"SHELLHOOK"] wParam:00008006 lParam:000F0184

I'm trying to prevent explorer.exe from flashing the task bar button, it's ruining my Windows 10 experience. In Windows 10 the flashing task bar buttons appear in all desktops, and it's just maddening when focusing on a work on another virtual desktop. Not a feature I want. The above messages are sent to Task switcher in explorer.exe, if I can prevent them being handled I can beat this.

I've wealth of knowledge about the WndProc which I want to see, and modify from Spy++, following windows are Property Inspector of Spy++ (64 bit version):

(Note: the 32bit version of Spy++ does not show Window Proc at all, just (Unavailable)(Unicode)

Window Proc address?

Thread ID

And in x64dbg I have the thread open:

x64dbg open on the same thread

But I just can't figure out how can I find the Window Proc in x64dbg?

  • have you been able to find the answer for `x64dgb?
    – T.Todua
    Dec 1, 2018 at 11:09
  • @T.Todua yes, I have also written a AHK script that gets the WndProc address (see my script here it also does other things, but one part is WndProc). The correct solution below does work somewhat correctly.
    – Ciantic
    Dec 2, 2018 at 12:03

1 Answer 1


The spy++ is showing the wndproc in your screen shot (it is probably subclassed; you may need to trace but wndproc is shown in your screenshot as 361c9880 I don't know what the command is in x64 dbg but if you were on ollydbg you simply do ctrl+g (goto) key in the address as shown in spy++ and break and log the messages for filtering.

A screen shot of calc.exe -> backspace button windows wndproc in comctl32.dll (32 bits and 64 bits shouldn't matter much on concept level)

enter image description here

An entry by Raymond Chen talks about cookies being returned instead of wndproc.

If all else fails assemble GetWindowLongPtrW in place to fetch the actual WndProc

  • suspend the process (f12 or esc)
  • use ctrl+g to goto user32.GetWindowLongPtrW
  • right click set new origin here (save the rip prior this)
  • save the state of register somewhere
  • modify rcx and plop the handle into rcx (which was b01c8 in your screen shot)
  • use the latest window handle as shown by spy++
  • for the existing session do not put 0xb01c8
  • modify edx to hold -4 (index of GWLP_WNDPROC)
  • step through the Function
  • before the function returns rax should hold the actual WndProc
  • save or set a bp on the Wndproc
  • restore registers and rip to pristine state and continue exploring

I downloaded x64dbg and ran 64 bit calc.exe spy++ 32 bit doesn't show wndproc. I cooked a script to alloc a page in process memory of calc.exe and assembled a detour using the script language and fetched the actual WndProc.

A screenshot below:

enter image description here

The debuggee must be in a paused state.

The script allocates memory in the debuggee's address space using alloc; after tabbing once the status bar should show the newly allocated address. Also the variables $lastalloc $result should hold the newly allocated memory address; if you do d address a bunch of 00 00 should stare at you.

  • confirm the allocation
  • if the memory is allocated tab one step in the script
  • push rcx should be assembled in the newly allocated address
  • use d address or d $lastalloc to confirm
  • like wise assemble all the instruction
  • use the proper handle value in ecx (stale or reused window handles may provide incorrect information confirm you assemble mov rcx , HWND right
  • now you need to ensure you put the right address in eax the address should be of user32.GetWindowLongPtrW
  • assemble all the cleanup instructions
  • one you have done this
  • save the existing rip some where (write it down in a paper)
  • right click and select the first instruction in the newly allocated address and set it as origin ( new origin here) the rip will be changed to the newly allocated address
  • hit f8 and execute the instructions on by one
  • when call eax is done eax will hold the Wndproc
  • save this (write it in paper)
  • execute the cleanup instruction
  • hit ctrl+g and enter the old RIP
  • right click -> new origin here ( RIP will now point to the old value when you paused the debuggee

That is it; now you have Wndproc in a paper and you have returned to the original state.

This is a detour (making an intentional bypass in the code flow of debuggee to do some extra work and return back to the place where bypass was done as if nothing was done to continue the original flow).

Use bp to set a breakpoint in the wndproc you have on paper.

  • Awesome! Thanks again. Got it working with the script now I get solid result even if I change instances which I think must mean it worked: 00007FF6361C9880. Before this I must have run the 'raw' GetWindowLogPtrW incorrectly all the time. Deleting the messages again.
    – Ciantic
    Oct 31, 2015 at 18:40
  • i added details about how to use the script as a detour
    – blabb
    Oct 31, 2015 at 18:46
  • it's in the explorer.exe. And! I've first time prevented FlashWindow from doing it's evil thing in the Task Switcher! I just zeroed the message C02B each time it got there and boom! Now I'm investigating how to make a memory patch I can run on my computer so I can live patch my explorer.exe
    – Ciantic
    Oct 31, 2015 at 19:00
  • 1
    FYI, I'm chronicling the creation of in-memory patch here: ciantic.blogspot.fi/2015/10/…
    – Ciantic
    Oct 31, 2015 at 20:14
  • nice entry yes you can dump the script and assemble anywhere in the module itself if you don't need reuse
    – blabb
    Nov 2, 2015 at 9:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.