win32k.sys not without cost, so the first thing to do is to look at the win32k!tagSHAREDINFO , which is answered by the symbol win32k!gSharedInfo , and also on the data type HWND , which is very closely associated with it.
gSharedInfo stores pointers to various window-related structures and, best of all, many of these structures are mapped into user space (put into the user-mode, in our opinion), and the corresponding user32!gSharedInfo symbol has user32!gSharedInfo for some time (or whist, either from the seven) became exported.
aheList - points to an array of win32k!_HANDLEENTRY type elements win32k!_HANDLEENTRY ;HeEntrySize - contains the size of the win32k!_HANDLEENTRY .HWND window handle are in fact the index in the gSharedInfo->aheList . For example, if we have a window variable that contains the HWND handle:

wUniq field of the win32k!_HANDLEENTRY contains the top 16 bits of the HWND descriptor and, apparently, serves the simple purpose of separating objects that occupy the same address in a given array at different time intervals. Thus, if an object is freed and later its place is taken, for example, by a new window with wUniq = 0x12 , then according to the old descriptor 0x0011024c it will be impossible to access it.bFlags and bType contain various flags and the type of object addressed by the phead field, respectively. In more detail possible values accepted by them can be looked in ReactOS .bType value bType :TYPE_WINDOW = 1phead field addresses the win32k!tagWND .
user32!gSharedInfo->aheList[…].phead stores the address belonging to the kernel. However, if you wish, you can get the address of its user mapping, but this is another story, so for details I refer you to the HWND window handle and the user32!ValidateHWND procedure that returns the tagWND* , or rather to the user32!HMValidateHandle .pOwner field of the win32k!_HANDLEENTRY pOwner structure not considered earlier contains a pointer to win32k!_W32THREAD stream to which the object belongs. Each thread stores this pointer in win32k!_KTHREAD->Win32Thread (why not in _ETHREAD ), and also, which is much more important in our case, in TEB!Win32ThreadInfo .
user32!gSharedInfo->aheList[…] , which:bType == TYPE_WINDOW ;pOwner == TEB!Win32ThreadInfo .wUniq 16 bits of the descriptor, and the upper 16 bits will be contained in the wUniq field.user32!FindWindow ? At the moment when we need it, neither the name nor the class will be filled in by the window.PEB!KernelCallbackTable .
kernel , but received their name because their client is usually win32k.sys , accessing them when it is necessary to perform an operation in the user space. The call is made via ntdll!KiUserCallbackDispatcher similar to exception scheduling .nt!KeUserModeCallback . The call is made on the kollbek index. Address resolving by index is done already in ntdll!KiUserCallbackDispatcher .user32!SetWindowLongPtr , and in fact - its execution in the form of win32k!xxxSetWindowData . We confine ourselves to only one case of interest - with the GWLP_WNDPROC parameter.win32k!xxxSetWindowData first performs various checks. For example, is the window owned by the process whose thread is trying to set the WndProc , and also whether this window is already destroyed ( FNID_DELETED_BIT bit).
WndProc parameter ( value_ in the screenshot), MapClientToServerPfn is MapClientToServerPfn . This simple and extremely useful function maps functions from win32k!gpsi->apfnClientW and win32k!gpsi->apfnClientA to the corresponding functions from win32k!gpsi-> aStoCidPfn :


WndProc possible, then the procedure call can be optimized by referring directly to the implementation of the function in the kernel, for example, win32k!xxxDefWindowProc , without wasting time switching to user mode to call the wrapper, for example, ntdll!NtdllDefWindowProc_A , which user32!DefWindowProcA is an end-to-end export.WFSERVERSIDEPROC flag is raised at the window, after which the mapped value is entered in its win32k!tagWND->lpfnWndProc .user32!SetWindowLongPtr , then the corresponding procedure from win32k.sys in kernel mode will actually be executed.win32k!xxxCreateWindowEx procedure is fully responsible for win32k!xxxCreateWindowEx . First, by calling win32k!HMAllocObject tagWND object is tagWND and information about it is entered into the gSharedInfo->aheList :
hex-rays takes a couple of thousand lines, so there is no point or opportunity to dwell on all the actions performed.SetWindowLongPtr(hwnd, GWLP_WNDPROC, DefWindowProc) on the window at the moment when it is already created, but it still has the lpfnWndProc field. After all, this field is filled from the class field, in which it is probably already stored mapped by MapClientToServerPfn , if such mapping is possible.SetWindowLongPtr to raise the WFSERVERSIDEPROC flag before the WndProc address is filled with the value from the class field. At the same time, this flag is not reset when the WndProc field is set, as the developers did not anticipate the possibility that it can be installed. There is only the logic of setting the flag for the window, if the corresponding class flag is raised.
SetWindowLongPtr at run time CreateWindowEx negligible, because you must first find the HWND windows in the user32!gSharedInfo->aheList , then the user32!SetWindowLongPtr -> … -> win32k!xxxSetWindowData chain user32!SetWindowLongPtr -> … -> win32k!xxxSetWindowData should work out the call chain what happens initialization of the tagWND fields in win32k!xxxCreateWindowEx . You can, of course, play with processor affinity and thread priorities. However, for Windows 7 and earlier versions, there is a simple way.win32k!xxxCreateWindowEx , all the information we are interested in fits into several hex-rays lines:
hIcon icon, but was not specified for the small hIconSm icon, then win32k!xxxCreateWindowEx copies the window, or rather, scales it, the window for filling the win32k!tagCLS->spicnSm field win32k!tagCLS->spicnSm . This action is performed by the win32k!xxxCreateClassSmIcon , which delegates the task to one of the above-described user so-called kernel callbacks :
user32!_ClientCopyImage . He performs the task.
win32k!xxxCreateWindowEx , the WndProc window is immediately filled from the WndProc class. Then, apparently, if the WFSERVERSIDEPROC flag WFSERVERSIDEPROC raised in the class, it is also raised for the window.

user32!_ClientCopyImage :
SetWindowLongPtr for the newly created window:



SetWindowLongPtr , which raises the bServerSideWindowProc flag in the appropriate window structure.
win32k!xxxCreateWindowEx overwrites lpfnWndProc value from the class field.



win32k!xxxCreateWindowEx installation of tagWND->lpfnWndProc and the call to win32k!xxxCreateClassSmIcon are in reverse order compared to earlier versions. Thus, the user32!_ClientCopyImage hook user32!_ClientCopyImage will not help.Source: https://habr.com/ru/post/257879/
All Articles