Tag Archive for 'Debug'

[생활속의 Debugging] sptd.sys 는 왜 Registry를 감시 ??

데몬 Tools를 설치하게 되면 sptd.sys라는 녀석도 함께 설치됩니다. 이녀석은 머하는 녀석이지 ??
일단 무슨 함수를 Hooking하고 있을까 ?? dds 명령으로 KiServiceTable을 체크해 봤습니다.

804e6948 805b1900 nt!NtCreateIoCompletion
804e694c 805e72ca nt!NtCreateJobObject
804e6950 80638053 nt!NtCreateJobSet
804e6954 f750bb3a*** ERROR: Module load completed but symbols could not be loaded for sptd.sys
sptd+0×5b3a // nt!NtCreateKey

804e6958 805e898a nt!NtCreateMailslotFile
804e695c 8057dccd nt!NtCreateMutant
804e6960 805891c8 nt!NtCreateNamedPipeFile
….
804e69c4 8057e101 nt!NtDuplicateToken
804e69c8 8064ff97 nt!NtSetBootOptions
804e69cc f750bc7e sptd+0×5c7e // nt!NtEnumerateKey
804e69d0 8064ff6f nt!NtEnumerateSystemEnvironmentValuesEx
804e69d4 f750bff6 sptd+0×5ff6 // nt!NtEnumerateValueKey
804e69d8 8062d9b9 nt!NtExtendSection

804e6a84 806216bb nt!NtOpenIoCompletion
804e6a88 806382ab nt!NtOpenJobObject
804e6a8c f750ba18 sptd+0×5a18//nt!NtOpenKey
804e6a90 8057dd7b nt!NtOpenMutant
804e6a94 805b2aa6 nt!NtOpenObjectAuditAl

804e6b28 806510bb nt!NtQueryIntervalProfile
804e6b2c 8062177c nt!NtQueryIoCompletion
804e6b30 f750c0c0 sptd+0×60c0//nt!NtQueryKey
804e6b34 80655cc4 nt!NtQueryMultipleValueKey
804e6b38 80650a42 nt!NtQueryMutant

804e6b6c 805b1436 nt!NtQueryTimer
804e6b70 8058bb31 nt!NtQueryTimerResolution
804e6b74 f750bf58 sptd+0×5f58 // nt!NtQueryValueKey
804e6b78 80583657 nt!NtQueryVirtualMemory
804e6b7c 8057f676 nt!NtQueryVolumeInformationFile

804e6c84 805ec4ff nt!NtSetTimerResolution
804e6c88 805e2051 nt!NtSetUuidSeed
804e6c8c f750c148 sptd+0×6148 // nt!NtSetValueKey
804e6c90 80622901 nt!NtSetVolumeInformationFile
804e6c94 8064e983 nt!NtShutdownSystem

nt!NtCreateKey, nt!NtEnumerateKey, nt!NtEnumerateValueKey, nt!NtOpenKey, nt!NtQueryKey, nt!NtSetValueKey
레지스트 Key 관련 함수들을 주루룩 Hooking하고 있군요.. 무슨 이유에서인지 .. 설마 ?? Process도 감시하고 있나 ??

lkd> dd nt!PspCreateProcessNotifyRoutine
8056a6e0 e18312d7 e229edef e19f3057 e3270597
8056a6f0 00000000 00000000 00000000 00000000
8056a700 00000004 00000000 8a1fcec8 8814f7b8
8056a710 8a3d5f18 8a3d5030 8a3d5e00 00000000
8056a720 00000000 00000000 00000000 00000000
8056a730 00000000 00000000 00000000 00000000
8056a740 00000000 6d6f7441 00000000 00000001
8056a750 00000000 00000000 00000000 00000000
lkd> dd e18312d0
e18312d0 00000010 f75159ac 00000000 00590052
e18312e0 00020803 61564d43 e1028820 e10281f8
e18312f0 0c020802 6944624f e1012930 e18235b8
e1831300 0c020802 6944624f e2004688 8a2db338
e1831310 0c030802 6d4e624f 00300030 00300030
e1831320 00300030 00610034 0c030803 75737050
e1831330 00750061 00730064 00750074 00000062
e1831340 00010803 61564d43 0c050801 7346744e

lkd> u f75159ac
sptd+0xf9ac:

f75159ac 55 push ebp
f75159ad 8bec mov ebp,esp
f75159af 807d1000 cmp byte ptr [ebp+10h],0
f75159b3 0f85e8000000 jne sptd+0xfaa1 (f7515aa1)
f75159b9 56 push esi
f75159ba 57 push edi
f75159bb 33ff xor edi,edi
f75159bd ff154c6052f7 call dword ptr [sptd+0x2004c (f752604c)]

역시나 Process Notify를 등록하고 있군요 .  설마 File System도 Hooking 하는건 아닐까 ???

lkd> !drvobj ntfs 2
Driver object (8a312380) is for:
\FileSystem\Ntfs
DriverEntry: f7bd7184 Ntfs!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: f752a95e sptd
AddDevice: 00000000
Dispatch routines:
[00] IRP_MJ_CREATE 8a37c0e8 +0×8a37c0e8
[01] IRP_MJ_CREATE_NAMED_PIPE 804fb709 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE 8a37c0e8 +0×8a37c0e8
[03] IRP_MJ_READ 8a37c0e8 +0×8a37c0e8
[04] IRP_MJ_WRITE 8a37c0e8 +0×8a37c0e8
[05] IRP_MJ_QUERY_INFORMATION 8a37c0e8 +0×8a37c0e8
[06] IRP_MJ_SET_INFORMATION 8a37c0e8 +0×8a37c0e8
[07] IRP_MJ_QUERY_EA 8a37c0e8 +0×8a37c0e8
[08] IRP_MJ_SET_EA 8a37c0e8 +0×8a37c0e8
[09] IRP_MJ_FLUSH_BUFFERS 8a37c0e8 +0×8a37c0e8
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION 8a37c0e8 +0×8a37c0e8
[0b] IRP_MJ_SET_VOLUME_INFORMATION 8a37c0e8 +0×8a37c0e8
[0c] IRP_MJ_DIRECTORY_CONTROL 8a37c0e8 +0×8a37c0e8
[0d] IRP_MJ_FILE_SYSTEM_CONTROL 8a37c0e8 +0×8a37c0e8
[0e] IRP_MJ_DEVICE_CONTROL 8a37c0e8 +0×8a37c0e8

[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL 804fb709 nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN 8a37c0e8 +0×8a37c0e8
[11] IRP_MJ_LOCK_CONTROL 8a37c0e8 +0×8a37c0e8
[12] IRP_MJ_CLEANUP 8a37c0e8 +0×8a37c0e8

[13] IRP_MJ_CREATE_MAILSLOT 804fb709 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY 8a37c0e8 +0×8a37c0e8
[15] IRP_MJ_SET_SECURITY 8a37c0e8 +0×8a37c0e8

[16] IRP_MJ_POWER 804fb709 nt!IopInvalidDeviceRequest
[17] IRP_MJ_SYSTEM_CONTROL 804fb709 nt!IopInvalidDeviceRequest
[18] IRP_MJ_DEVICE_CHANGE 804fb709 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA 8a37c0e8 +0×8a37c0e8
[1a] IRP_MJ_SET_QUOTA 8a37c0e8 +0×8a37c0e8
[1b] IRP_MJ_PNP 8a37c0e8 +0×8a37c0e8

Fast I/O routines:
FastIoCheckIfPossible f7b8beda Ntfs!NtfsFastIoCheckIfPossible
FastIoRead f7b72b57 Ntfs!NtfsCopyReadA
FastIoWrite f7b91448 Ntfs!NtfsCopyWriteA
FastIoQueryBasicInfo f7b7848e Ntfs!NtfsFastQueryBasicInfo
FastIoQueryStandardInfo f7b76f7e Ntfs!NtfsFastQueryStdInfo
FastIoLock f7b920f2 Ntfs!NtfsFastLock
FastIoUnlockSingle f7b921f8 Ntfs!NtfsFastUnlockSingle
FastIoUnlockAll f7bcb6ae Ntfs!NtfsFastUnlockAll
FastIoUnlockAllByKey f7bcb7f3 Ntfs!NtfsFastUnlockAllByKey
AcquireFileForNtCreateSection f7b7283a Ntfs!NtfsAcquireForCreateSection
ReleaseFileForNtCreateSection f7b72881 Ntfs!NtfsReleaseForCreateSection
FastIoQueryNetworkOpenInfo f7bb9e1d Ntfs!NtfsFastQueryNetworkOpenInfo
AcquireForModWrite f7b7ea10 Ntfs!NtfsAcquireFileForModWrite
MdlRead f7bb9f31 Ntfs!NtfsMdlReadA
MdlReadComplete 805322b8 nt!FsRtlMdlReadCompleteDev
PrepareMdlWrite f7bba2ab Ntfs!NtfsPrepareMdlWriteA
MdlWriteComplete 8061d1db nt!FsRtlMdlWriteCompleteDev
FastIoQueryOpen f7b76db8 Ntfs!NtfsNetworkOpenCreate
AcquireForCcFlush f7b726e2 Ntfs!NtfsAcquireFileForCcFlush
ReleaseForCcFlush f7b72708 Ntfs!NtfsReleaseFileForCcFlush

역시나 sptd가 Major Function들을 과함하게 Hook 하고 있군요.  과연 이 녀석의 정체는 도대체 멀까요 ?? ㅜ.ㅜ
( 귀찮아서 리버싱은 ㅜ.ㅜ )

[NT Inside Study] Kernel To User Callback 3 - KiUserExceptionDispatcher

KiUserExceptionDispatcher 은 UserMode에서 Exception이 발생했을때 실행되는 Callback 입니다. KiUserExceptionDispatcher의 실행은 IDT -> KiTrapXX ->CommonDispatchException -> KiDispatchException -> KiUserExceptionDispatcher 와 같은 Flow를 지닙니다. 

lkd> uf nt!CommonDispatchEsception
... 중략
nt!CommonDispatchException+0x3e:
804e03f4 83e001 and eax,1
804e03f7 6a01 push 1
804e03f9 50 push eax
804e03fa 55 push ebp
804e03fb 6a00 push 0
804e03fd 51 push ecx
804e03fe e89ac70100 call nt!KiDispatchException (804fcb9d)
804e0403 8be5 mov esp,ebp
804e0405 e91ffeffff jmp nt!Kei386EoiHelper (804e0229

KiDispatcheException는 발생한 Exception을 User Mode 와 Kernel Mode 로 분해 하여 Dispatch 합니다. 또한 User Level에서 사용하는 RaiseException Function 같은 경우도 내부적으로 KiDispatcherException을 사용하여 Exception을 Dispatch 합니다.

lkd> uf nt!KiDispatchException
...
// KernelMode Exception, UserMode Exception
nt!KiDispatchException+0×101:
804fcc34 807d1400 cmp byte ptr [ebp+14h],0

804fcc38 0f8524a30000 jne nt!KiDispatchException+0×16c (80506f62)

KernelMode Exception일 경우

nt!KiDispatchException+0x107:
804fcc3e 807d1801 cmp byte ptr [ebp+18h],1
804fcc42 0f8592720200 jne nt!KiDispatchException+0×142 (80523eda)
nt!KiDispatchException+0x10d:
804fcc48 a164345680 mov eax,dword ptr [nt!KiDebugRoutine (80563464)]
804fcc4d 3bc7 cmp eax,edi
804fcc4f 0f84b1680100 je nt!KiDispatchException+0×131 (80513506)

nt!KiDispatchException+0×116:
804fcc55 57 push edi
804fcc56 57 push edi
804fcc57 8d8d18fdffff lea ecx,[ebp-2E8h]
804fcc5d 51 push ecx
804fcc5e 56 push esi
804fcc5f ffb510fdffff push dword ptr [ebp-2F0h]
804fcc65 53 push ebx
804fcc66 ffd0 call eax
804fcc68 84c0 test al,al
804fcc6a 0f8496680100 je nt!KiDispatchException+0×131 (80513506)

nt!KiDispatchException+0×131:
80513506 8d8518fdffff lea eax,[ebp-2E8h]
8051350c 50 push eax
8051350d 56 push esi
8051350e e805befeff call nt!RtlDispatchException (804ff318)
80513513 e9ba090100 jmp nt!KiDispatchException+0×13e (80523ed2)
… 중략

UserMode Exception일 경우
nt!KiDispatchException+0x16c:
80506f62 807d1801 cmp byte ptr [ebp+18h],1 // Is FirstCance
80506f66 0f8544d00100 jne nt!KiDispatchException+0×374 (80523fb0)
nt!KiDispatchException+0x176:
80506f6c 393d64345680 cmp dword ptr [nt!KiDebugRoutine (80563464)],edi
80506f72 7436 je nt!KiDispatchException+0×1eb (80506faa)

nt!KiDispatchException+0×1eb:
80506faa 57 push edi
80506fab 6a01 push 1
80506fad 56 push esi
80506fae e8e2d20700 call nt!DbgkForwardException (80584295) // Debug Port 또는 Subsystem Exception Port 로 Forward
80506fb3 84c0 test al,al
80506fb5 0f85d15cffff jne nt!KiDispatchException+0×1db (804fcc8c)

nt!KiDispatchException+0×1f8:
80506fbb 89bd60fcffff mov dword ptr [ebp-3A0h],edi
80506fc1 897dfc mov dword ptr [ebp-4],edi
80506fc4 837b7823 cmp dword ptr [ebx+78h],23h
80506fc8 0f8553cf0100 jne nt!KiDispatchException+0×20d (80523f21)

nt!KiDispatchException+0×207:
80506fce f6437202 test byte ptr [ebx+72h],2
80506fd2 0f8549cf0100 jne nt!KiDispatchException+0×20d (80523f21)

nt!KiDispatchException+0×22f:
80506fd8 b8cc020000 mov eax,2CCh
80506fdd 898504fdffff mov dword ptr [ebp-2FCh],eax
80506fe3 8bbddcfdffff mov edi,dword ptr [ebp-224h]
80506fe9 83e7fc and edi,0FFFFFFFCh
80506fec 2bf8 sub edi,eax
80506fee 89bd0cfdffff mov dword ptr [ebp-2F4h],edi
80506ff4 6a04 push 4
80506ff6 50 push eax
80506ff7 57 push edi
80506ff8 e8f4880600 call nt!ProbeForWrite (8056f8f1)
80506ffd b9b3000000 mov ecx,0B3h
80507002 8db518fdffff lea esi,[ebp-2E8h]
80507008 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8050700a 8b8514fdffff mov eax,dword ptr [ebp-2ECh]
80507010 8b7010 mov esi,dword ptr [eax+10h]
80507013 8d34b517000000 lea esi,[esi*4+17h]
8050701a 83e6fc and esi,0FFFFFFFCh
8050701d 89b504fdffff mov dword ptr [ebp-2FCh],esi
80507023 8bbd0cfdffff mov edi,dword ptr [ebp-2F4h]
80507029 2bfe sub edi,esi
8050702b 89bd00fdffff mov dword ptr [ebp-300h],edi
80507031 6a04 push 4
80507033 8d4608 lea eax,[esi+8]
80507036 50 push eax
80507037 8d47f8 lea eax,[edi-8]
8050703a 50 push eax
8050703b e8b1880600 call nt!ProbeForWrite (8056f8f1)
80507040 8bce mov ecx,esi
80507042 8bb514fdffff mov esi,dword ptr [ebp-2ECh]
80507048 8bc1 mov eax,ecx
8050704a c1e902 shr ecx,2
8050704d f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8050704f 8bc8 mov ecx,eax
80507051 83e103 and ecx,3
80507054 f3a4 rep movs byte ptr es:[edi],byte ptr [esi]
80507056 8b8d0cfdffff mov ecx,dword ptr [ebp-2F4h]
8050705c 8b8500fdffff mov eax,dword ptr [ebp-300h]
80507062 8948fc mov dword ptr [eax-4],ecx
80507065 8d50f8 lea edx,[eax-8]
80507068 8902 mov dword ptr [edx],eax
8050706a 6a20 push 20h
8050706c 53 push ebx
8050706d e8971ffeff call nt!KiSegSsToTrapFrame (804e9009)
80507072 52 push edx
80507073 53 push ebx
80507074 e8db1ffeff call nt!KiEspToTrapFrame (804e9054)
80507079 8b4514 mov eax,dword ptr [ebp+14h]
8050707c 8ac8 mov cl,al
8050707e f6d9 neg cl
80507080 1bc9 sbb ecx,ecx
80507082 83e103 and ecx,3
80507085 83c118 add ecx,18h
80507088 894b6c mov dword ptr [ebx+6Ch],ecx
8050708b 8ac8 mov cl,al
8050708d f6d9 neg cl
8050708f 1bc9 sbb ecx,ecx
80507091 83e103 and ecx,3
80507094 83c120 add ecx,20h
80507097 894b38 mov dword ptr [ebx+38h],ecx
8050709a 894b34 mov dword ptr [ebx+34h],ecx
8050709d f6d8 neg al
8050709f 1bc0 sbb eax,eax
805070a1 83e003 and eax,3
805070a4 83c038 add eax,38h
805070a7 894350 mov dword ptr [ebx+50h],eax
805070aa 83633000 and dword ptr [ebx+30h],0
805070ae a170345680 mov eax,dword ptr [nt!KeUserExceptionDispatcher (80563470)]
805070b3 894368 mov dword ptr [ebx+68h],eax
805070b6 834dfcff or dword ptr [ebp-4],0FFFFFFFFh
805070ba e9cd5bffff jmp nt!KiDispatchException+0×1db (804fcc8c)

nt!KiDispatchException는 KernelMode일 경우 RtlDispatchException을 수행하여 BugCheck를 발생시키고 UserMode일 경우 UserMode Statck을 조작하여 KeUserExceptionDispatcher를 발생시켜 줍니다. 이러한 과정을 거치면서 UserMode에서 아래와 같은 스택이 완성됩니다.


00 0013ff28 00412da8 00400000 00000000 00020934 ntdll!KiUserExceptionDispatcher (FPO: [2,0,0]) (CONTEXT @ 0013fb64)
01 0013ff28 004144cf 00400000 00000000 00020934 ExceptionTest!wWinMain+0×68 (FPO: [Non-Fpo]) (CONV: stdcall) [e:\per\exceptiontest\exceptiontest\exceptiontest.cpp @ 28]
02 0013ffc0 7c816fd7 019bf6f2 019bf766 7ffd4000 ExceptionTest!__tmainCRTStartup+0×176 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\crt0.c @ 324]
03 0013fff0 00000000 00411de8 00000000 78746341 kernel32!BaseProcessStart+0×23 (FPO: [Non-Fpo])

KiUserExceptionDispatcher는 Exception이 발생했을때 종종 스택상에서 나타 나며 Kernel Debugging 시에 User Exception이 발생하게 되면 스택상에 나타나게 됩니다.  ( Kernel Debugging시에는  KiUserExceptionDispatcher는 보이지만 그외의 Kernel Stack 들이 보이지 않는 경우도 있으니 참고하시길… )

[NT Inside Study] Kernel To User Callback 2 - KiUserCallbackDispatcher

본 내용은 정확한 Windows의 구조중 일부라 장담 할 수 없으면 특정 동작의 개인적인 추정을 바탕으로 작성한 글입니다.

Win32 의 GDI 프로그래밍을 하다보면 KiUserCallbackDispatcher 라는 녀석이 스택에 떡하니 있는걸 간혹 볼수 있습니다. ( 사실 거의 보이지 않지만 … )


00 0013f380 77cf84c6 77d0e355 0000001d 5a4b139c ntdll!KiUserCallbackDispatcher (FPO: [0,0,0])
01 0013f3bc 5a4848c3 0000001f 00000000 0013f500 USER32!NtUserCallNoParam+0xc

02 0013f48c 5a484860 00000000 5a4b10b0 0013f4c0 uxtheme!CInternalNonclientMetrics::Acquire+0×29 (FPO: [Non-Fpo])
03 0013f49c 5a48a6d4 00000000 00000000 5a4b1088 uxtheme!NcGetNonclientMetrics+0×37 (FPO: [Non-Fpo])
04 0013f4b0 5a48bacb 00000001 00000000 0013f4e4 uxtheme!AcquireNcThemeMetrics+0×30 (FPO: [0,0,0])
05 0013f4c0 5a48be53 00010002 00000000 5a48b06d uxtheme!NewThemeCheck+0×52 (FPO: [Non-Fpo])
06 0013f4cc 5a48b06d 5a480000 00000000 5a48af15 uxtheme!OnHooksEnabled+0×13 (FPO: [0,0,0])
07 0013f4e4 77d0e33d 00000000 0013f500 5a480000 uxtheme!ThemeInitApiHook+0×1af (FPO: [Non-Fpo])
08 0013f568 77d0dc0f 5a48af15 0000af15 ffff0000 USER32!InitUserApiHook+0×2c (FPO: [Non-Fpo])
09 0013f590 7c93eae3 0013f5a0 00000068 00000068 USER32!__ClientLoadLibrary+0×46 (FPO: [Non-Fpo])
0a 0013f604 77cffe13 77cffdd9 00050101 00008002 ntdll!KiUserCallbackDispatcher+0×13 (FPO: [0,0,0])
0b 0013faa8 77d042e9 00050101 00008002 0013fb0c USER32!NtUserCreateWindowEx+0xc

0c 0013fb80 77d04704 00400000 00008002 00000108 USER32!InternalCreateDialog+0×5bc (FPO: [Non-Fpo])
0d 0013fba4 77d1f002 00400000 00428e78 00000000 USER32!CreateDialogIndirectParamAorW+0×33 (FPO: [Non-Fpo])
0e 0013fbc4 7839df34 00400000 00428e78 00000000 USER32!CreateDialogIndirectParamW+0×1b (FPO: [Non-Fpo])
0f 0013fc8c 7839e650 00428e78 00000000 00400000 MFC80UD!CWnd::CreateDlgIndirect+0×2a4 (FPO: [Non-Fpo])
10 0013fd00 0041295e 9e4d6e2b 02e3f6f2 02e3f75a MFC80UD!CDialog::DoModal+0×1a0 (FPO: [Non-Fpo])
11 0013fecc 78375512 cccccccc cccccccc cccccccc ThreadTest!CThreadTestApp::InitInstance+0×1fe (FPO: [Non-Fpo]) (CONV: thiscall) [e:\per\threadtest\threadtest\threadtest.cpp @ 153]
12 0013fef0 004177a8 00400000 00000000 00020914 MFC80UD!AfxWinMain+0×82 (FPO: [Non-Fpo])
13 0013ff08 00413d79 00400000 00000000 00020914 ThreadTest!wWinMain+0×18 (CONV: stdcall) [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\appmodul.cpp @ 33]

CreateDialogIndirectParam->NtUserCreateWindowEx->xxxCreateWindowEx 라는 기본 메커니즘은 누구나 알고 계실겁니다. 과연 그렇다면 KiUserCallbackDispatcher라는 Kernel Mode Callback은 어떻게 추가되는 것일까 ?

ntdll!KiUserCallbackDispatcher:
7c93ead0 83c404 add esp,4
7c93ead3 5a pop edx
7c93ead4 64a118000000 mov eax,dword ptr fs:[00000018h]
7c93eada 8b4030 mov eax,dword ptr [eax+30h]
7c93eadd 8b402c mov eax,dword ptr [eax+2Ch]
7c93eae0 ff1490 call dword ptr [eax+edx*4]
7c93eae3 33c9 xor ecx,ecx
7c93eae5 33d2 xor edx,edx
7c93eae7 cd2b int 2Bh
7c93eae9 cc int 3
….

KiUserCallbackDispatcher 는 기본적으로 Teb를 통해서 PEB를 얻어 KernelCallbackTable에 등록된 Function를 호출해주는 역할을 합니다. NtUserCreateWindowEx나 NtUserCallNoParam은 어떤 메커니즘으로 KiUserCallbackDispatcher를 호출하게 된것인가 ? NtUserCreateWindowEx는 내부적으로 xxxCreateWindowEx를 호출하고 Windows를 초기화 하게 된다. xxxCreateWindowEx이러한 초기화 과정이 끝나게 되면 내부적으로 초기화가 완료되었음을 알리는 Callback을 User Mode로 보내기 위해서 xxxWindowEvent를 호출하게 됩니다.

PWND xxxCreateWindowEx(
DWORD dwExStyle,
PLARGE_STRING cczpstrClass,
PLARGE_STRING cczpstrName,
DWORD style,
int x,
int y,
int cx,
int cy,
PWND pwndParent,
PMENU pMenu,
HANDLE hInstance,
LPVOID lpCreateParams,
DWORD dwExpWinVerAndFlags)
{
//Initialize Windows

win32k!xxxCreateWindowEx+0xc03:
bf845896 804b1b80 or byte ptr [ebx+1Bh],80h
bf84589a 33f6 xor esi,esi
bf84589c 56 push esi
bf84589d 56 push esi
bf84589e 56 push esi
bf84589f 53 push ebx
bf8458a0 6800800000 push 8000h
bf8458a5 e8b62dfcff call win32k!xxxWindowEvent (bf808660)
bf8458aa f6431410 test byte ptr [ebx+14h],10h
bf8458ae 753c jne win32k!xxxCreateWindowEx+0xc59 (bf8458ec)

}


VOID
xxxWindowEvent(
DWORD event,
PWND pwnd,
LONG idObject,
LONG idChild,
DWORD dwFlags)
{
...
win32k!xxxWindowEvent+0x177:
bf8087cd f60102 test byte ptr [ecx],2
bf8087d0 0f8563ffffff jne win32k!xxxWindowEvent+0×185 (bf808739)
win32k!xxxWindowEvent+0x17c:
bf8087d6 50 push eax
bf8087d7 e8a14f1100 call win32k!xxxProcessNotifyWinEvent (bf91d77d)
bf8087dc 89450c mov dword ptr [ebp+0Ch],eax
bf8087df e955ffffff jmp win32k!xxxWindowEvent+0×185 (bf808739)

}


PEVENTHOOK
xxxProcessNotifyWinEvent(PNOTIFY pNotify)
{
...
win32k!xxxProcessNotifyWinEvent+0xa2:
bf91d81f 8b4624 mov eax,dword ptr [esi+24h]
bf91d822 eb06 jmp win32k!xxxProcessNotifyWinEvent+0xad (bf91d82a)
win32k!xxxProcessNotifyWinEvent+0xa7:
bf91d824 56 push esi
bf91d825 e8c6feffff call win32k!xxxGetEventProc (bf91d6f0)
win32k!xxxProcessNotifyWinEvent+0xad:
bf91d82a 85c0 test eax,eax
bf91d82c 7408 je win32k!xxxProcessNotifyWinEvent+0xb9 (bf91d836)
...
}


WINEVENTPROC
xxxGetEventProc(PEVENTHOOK pEventOrg)
{
...
win32k!xxxGetEventProc+0x2b:
bf91d71b a138ac9abf mov eax,dword ptr [win32k!gptiCurrent (bf9aac38)]
bf91d720 8b402c mov eax,dword ptr [eax+2Ch]
bf91d723 33d2 xor edx,edx
bf91d725 42 inc edx
bf91d726 d3e2 shl edx,cl
bf91d728 8590a4000000 test dword ptr [eax+0A4h],edx
bf91d72e 750a jne win32k!xxxGetEventProc+0×4a (bf91d73a)
win32k!xxxGetEventProc+0x40:
bf91d730 51 push ecx
bf91d731 e89968f4ff call win32k!xxxLoadHmodIndex (bf863fcf)
bf91d736 85c0 test eax,eax
bf91d738 7414 je win32k!xxxGetEventProc+0×5e (bf91d74e)

}


HANDLE xxxLoadHmodIndex(
int iatom,
BOOL bWx86KnownDll)
{
...
win32k!xxxLoadHmodIndex+0x34:
bf863ff5 53 push ebx
bf863ff6 6804010000 push 104h
bf863ffb 8d85f4fdffff lea eax,[ebp-20Ch]
bf864001 50 push eax
bf864002 33c0 xor eax,eax
bf864004 668b0475e0919abf mov ax,word ptr win32k!aatomSysLoaded (bf9a91e0)[esi*2]
bf86400c 50 push eax
bf86400d e85c4bfcff call win32k!UserGetAtomName (bf828b6e)
bf864012 8d85f4fdffff lea eax,[ebp-20Ch]
bf864018 50 push eax
bf864019 8d85ecfdffff lea eax,[ebp-214h]
bf86401f 50 push eax
bf864020 ff1580c998bf call dword ptr [win32k!_imp__RtlInitUnicodeString (bf98c980)]
bf864026 8bc6 mov eax,esi
bf864028 2b0554ab99bf sub eax,dword ptr [win32k!gihmodUserApiHook (bf99ab54)]
bf86402e f7d8 neg eax
bf864030 1bc0 sbb eax,eax
bf864032 f7d0 not eax
bf864034 230504ac9abf and eax,dword ptr [win32k!goffPfnInitUserApiHook (bf9aac04)]
bf86403a 50 push eax
bf86403b 8d85ecfdffff lea eax,[ebp-214h]
bf864041 50 push eax
bf864042 e84efeffff call win32k!ClientLoadLibrary (bf863e95)
bf864047 8bd8 mov ebx,eax
bf864049 85db test ebx,ebx
bf86404b 7511 jne win32k!xxxLoadHmodIndex+0×8c (bf86405e)

}

xxxWindowEvent 는 다시 xxxProcessNotifyWinEvent, xxxGetEventProc, xxxLoadHmodIndex, ClientLoadLibrary 를 순서로 호출하게 되고 ClientLoadLibrary에서는 실제로 UserModeCallback에서 이루어질 Function인 __ClientLoadLibrary를 호출할 수 있도록 해주는 Function Index와 함께 KeUserModeCallback를 호출하게 됩니다. KeUserModeCallback에서는 새로운 UserModeStack을 구성하고 KiCallUserMode를 호출함 으로써 새로 구성된 Stack을 바탕으로 User Mode를 Call하게 되죠


NTSTATUS
KeUserModeCallback (
IN ULONG ApiNumber,
IN PVOID InputBuffer,
IN ULONG InputLength,
OUT PVOID *OutputBuffer,
IN PULONG OutputLength
)
{
...
nt!KeUserModeCallback:
805701cc 6a30 push 30h
805701ce 68e8994e80 push offset nt!KiDebugRegisterContextOffsets+0x24 (804e99e8)
805701d3 e8ab4cf7ff call nt!_SEH_prolog (804e4e83)
805701d8 e8d76cf7ff call nt!KiGetUserModeStackAddress (804e6eb4)

80570218 8943fc mov dword ptr [ebx-4],eax
8057021b 895bf8 mov dword ptr [ebx-8],ebx
8057021e 8b4508 mov eax,dword ptr [ebp+8]
80570221 8943f4 mov dword ptr [ebx-0Ch],eax
80570224 83c3f0 add ebx,0FFFFFFF0h
80570227 832300 and dword ptr [ebx],0
8057022a 8bcb mov ecx,ebx
8057022c 894ddc mov dword ptr [ebp-24h],ecx
8057022f 64a124010000 mov eax,dword ptr fs:[00000124h]
80570235 8945c8 mov dword ptr [ebp-38h],eax
80570238 8b7020 mov esi,dword ptr [eax+20h]
8057023b 8975c4 mov dword ptr [ebp-3Ch],esi
8057023e 8b3e mov edi,dword ptr [esi]
80570240 897dc0 mov dword ptr [ebp-40h],edi
80570243 8b5de4 mov ebx,dword ptr [ebp-1Ch]
80570246 890b mov dword ptr [ebx],ecx
80570248 ff7518 push dword ptr [ebp+18h]
8057024b ff7514 push dword ptr [ebp+14h]
8057024e e8cd6af7ff call nt!KiCallUserMode (804e6d20)
80570253 8945d4 mov dword ptr [ebp-2Ch],eax
80570256 893e mov dword ptr [esi],edi
80570258 834dfcff or dword ptr [ebp-4],0FFFFFFFFh
8057025c 33c0 xor eax,eax
8057025e 40 inc eax
...
}


nt!KiCallUserMode:
804e6d20 55 push ebp
804e6d21 53 push ebx
804e6d22 56 push esi
804e6d23 57 push edi
804e6d24 648b1d24010000 mov ebx,dword ptr fs:[124h] //Current Thread Address를 얻음
804e6d2b 8d842400d0ffff lea eax,[esp-3000h] // Bottom Address 계산
804e6d32 3b431c cmp eax,dword ptr [ebx+1Ch] // Stack Limit와 비교
804e6d35 7317 jae nt!KiCallUserMode+0×2e (804e6d4e)
nt!KiCallUserMode+0x17:
804e6d37 54 push esp
804e6d38 e8774e0100 call nt!MmGrowKernelStack (804fbbb4) // Kernel Stack Grow
804e6d3d 0bc0 or eax,eax
804e6d3f 0f85dc000000 jne nt!KiCallUserMode+0x101 (804e6e21)
nt!KiCallUserMode+0x25:
804e6d45 8b431c mov eax,dword ptr [ebx+1Ch] //새로운 Stack Limit를 얻음
804e6d48 64a308000000 mov dword ptr fs:[00000008h],eax // Stack Limit Set
nt!KiCallUserMode+0x2e:
804e6d4e ffb32c010000 push dword ptr [ebx+12Ch] //Save Callback address
804e6d54 8b9334010000 mov edx,dword ptr [ebx+134h] //Current Trap Frame을 얻는다.
804e6d5a 52 push edx //Save Trap Frame
804e6d5b 8b7318 mov esi,dword ptr [ebx+18h] //Initialize Stack Address
804e6d5e 56 push esi //Save Stack Address
804e6d5f 89a32c010000 mov dword ptr [ebx+12Ch],esp //Save Callback Stack Addresss
804e6d65 83e4f0 and esp,0FFFFFFF0h
804e6d68 8bfc mov edi,esp //새로운 Initialize Stack Set
804e6d6a 81ec10020000 sub esp,210h //NPX Status 관련 코드
804e6d70 81ee10020000 sub esi,210h
804e6d76 fa cli //Disable Interrupt
804e6d77 8b0e mov ecx,dword ptr [esi] //
804e6d79 890c24 mov dword ptr [esp],ecx
804e6d7c 8b4e04 mov ecx,dword ptr [esi+4]
804e6d7f 894c2404 mov dword ptr [esp+4],ecx
804e6d83 8b4e08 mov ecx,dword ptr [esi+8]
804e6d86 894c2408 mov dword ptr [esp+8],ecx
804e6d8a 8b4e18 mov ecx,dword ptr [esi+18h]
804e6d8d 894c2418 mov dword ptr [esp+18h],ecx
804e6d91 8b8e0c020000 mov ecx,dword ptr [esi+20Ch]
804e6d97 898c240c020000 mov dword ptr [esp+20Ch],ecx
804e6d9e 648b3540000000 mov esi,dword ptr fs:[40h] // TSS의 Address를 얻는다.
804e6da5 897b18 mov dword ptr [ebx+18h],edi // Reset Stack Address
804e6da8 64892504000000 mov dword ptr fs:[4],esp // Set Stack Base Address
804e6daf 8bcc mov ecx,esp // Set Kernel Entry Stack Addresss
804e6db1 83ec10 sub esp,10h
804e6db4 f7427000000200 test dword ptr [edx+70h],20000h
804e6dbb 7502 jne nt!KiCallUserMode+0×9f (804e6dbf)
nt!KiCallUserMode+0x9d:
804e6dbd 8bcc mov ecx,esp
nt!KiCallUserMode+0x9f:
804e6dbf 894e04 mov dword ptr [esi+4],ecx
804e6dc2 83ec7c sub esp,7Ch // Trap Frame할당
804e6dc5 8bec mov ebp,esp // Set Trap Frame
804e6dc7 b90b000000 mov ecx,0Bh
804e6dcc 8d7c2450 lea edi,[esp+50h] // Trap Frame 정보 복사
804e6dd0 8d7250 lea esi,[edx+50h]
804e6dd3 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
804e6dd5 f6432cff test byte ptr [ebx+2Ch],0FFh
804e6dd9 7536 jne nt!KiCallUserMode+0xf1 (804e6e11)

nt!KiCallUserMode+0xbb:
// Callback의 Start Address
804e6ddb a174345680 mov eax,dword ptr [nt!KeUserCallbackDispatcher (80563474)]
804e6de0 89442468 mov dword ptr [esp+68h],eax
804e6de4 64a100000000 mov eax,dword ptr fs:[00000000h] // SEH 관련 코드
804e6dea 8944244c mov dword ptr [esp+4Ch],eax
804e6dee 8b4248 mov eax,dword ptr [edx+48h]
804e6df1 89442448 mov dword ptr [esp+48h],eax
804e6df5 fb sti // Interrupt Enable
804e6df6 8b5d60 mov ebx,dword ptr [ebp+60h]
804e6df9 8b7d68 mov edi,dword ptr [ebp+68h]
804e6dfc 89550c mov dword ptr [ebp+0Ch],edx // KiServiceExit 호출
804e6dff c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
804e6e06 895d00 mov dword ptr [ebp],ebx
804e6e09 897d04 mov dword ptr [ebp+4],edi
804e6e0c e9a08bffff jmp nt!KiServiceExit (804df9b1)

nt!KiCallUserMode+0xf1:
804e6e11 b906000000 mov ecx,6
804e6e16 8d7c2418 lea edi,[esp+18h]
804e6e1a 8d7218 lea esi,[edx+18h]
804e6e1d f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
804e6e1f ebba jmp nt!KiCallUserMode+0xbb (804e6ddb)

nt!KiCallUserMode+0×101:
804e6e21 5f pop edi
804e6e22 5e pop esi
804e6e23 5b pop ebx
804e6e24 5d pop ebp
804e6e25 c20800 ret 8

stdENDP _KiCallUserMode


이러한 과정을 통해서 NtUserCreateWindowEx의 System Stub 호출후 KiUserCallbackDispatcher와 __ClientLoadLibrary가 나타나게 됩니다.

정리하게 되면
NtUserCreateWindowEx -> xxxCreateWindowEx -> xxxWindowEvent -> xxxProcessNotifyWinEvent -> xxxGetEventProc -> xxxLoadHmodIndex -> ClientLoadLibrary ->KeUserModeCallback -> _KiCallUserMode -> KiUserCallbackDispatcher -> __ClientLoadLibrary 의 순으로 CallStack이 구성됩니다.
KiUserCallbackDispatcher의 정체는 User Stack 및 EIP를 조작함으로서 Kernel Mode에서 User Mode로의 Callback을 가능하게 되고 이러한 Callback의 실제 수행 매개체로 추정 할 수 있습니다. 실제로 이러한 Stack은 Win32 GDI Api를 사용하다 보면 종종 만날 수 있으며 Win32k.sys로의 System Stub Code가 호출됬을 때 주로 발생하게 됩니다.