测试环境:Windows 7
测试工具:VMWare + Windbg + IDA
首先下载漏洞的利用程序,在虚拟机中测试一下,发现程序可以正常运行:
C:/>whoami q-test/qever C:/>poc C:/>whoami nt authority/system
下面开始寻找漏洞的成因。
为了减少工作量,应该尽可能地确定漏洞产生的准确位置,在这里采用的方法是在poc的源代码的shellcode起始位置添加0xcc,对应的是"int 3"指令,这样shellcode一运行,就会立刻断下来,然后就可以进行分析了。
修改过程就不废话了,直接运行修改后的程序,当windbg断下来之后,查看调用堆栈,却发现调用堆栈被破坏了
kd> k ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong. 00000000 00000000 0x3d0000
此时可以通过对当前栈进行分析粗略估计出错位置。当然,还有一种比较好的方法,考虑到程序可以正常执行,故shellcode运行完毕后必定会返回调用位置,那么在shellcode返回位置下断,运行再次断下来之后查看堆栈可以得到
kd> k ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong. 92639d14 994bb8d0 0x3d0096 92639d28 83c7f42a win32k!GreEnableEUDC+0x7c 92639d28 772964f4 nt!KiFastCallEntry+0x12a
看到上面的信息,再结合poc源码中的漏洞触发代码,就能确定问题就是出现在win32k!GreEnableEUDC函数里面了,那么就从它开始分析查找漏洞成因吧!
为了减少工作量,这里采用了一种比较笨的方法,多次尝试来准确判定出错原因及位置。过程如下:
在win32k!GreEnableEUDC处下断点,运行修改后的程序,然后单步跟踪,直至触发shellcode中"int 3"指令,多次尝试之后可以确定如下调用信息:
win32k!GreEnableEUDC+0x77 : call win32k!BuildAndLoadLinkedFontRoutine+0xeb win32k!BuildAndLoadLinkedFontRoutine+0x19d : call win32k!bAppendSysDirectory+0x209 win32k!bAppendSysDirectory+0x334 : ret 8 //出错!
即在调用win32k!bAppendSysDirectory+0x209函数之后返回时跳入shellcode,同时在返回时查看堆栈可以发现返回地址被修改了,也就是说在该函数运行过程中栈空间被修改,即栈溢出。
结合网上的信息,多次尝试后可以确定整个漏洞的产生流程:
nt!KiFastCallEntry+0x128 : call ebx (win32k!GreEnableEUDC) win32k!GreEnableEUDC+0x77 : call win32k!BuildAndLoadLinkedFontRoutine+0xeb win32k!BuildAndLoadLinkedFontRoutine+0x19d : call win32k!bAppendSysDirectory+0x209 win32k!bAppendSysDirectory+0x2de : call dword ptr [win32k!_imp__RtlQueryRegistryValues (9972f104)] nt!RtlQueryRegistryValues+0x318 : call nt!RtlpCallQueryRegistryRoutine (83e2ab81) nt!RtlpCallQueryRegistryRoutine+0x290 : call nt!RtlpQueryRegistryDirect (83e33997) nt!RtlpQueryRegistryDirect+3D : call nt!memcpy (83c797a0) //溢出 win32k!bAppendSysDirectory+0x334 : ret 8 //出错!
那么只要分析上面所列出函数的行为,就应该能确定漏洞的成因了。
接下来我们挨个来分析以上函数,实际分析过程中是Windbg动态调试和IDA静态分析同时进行的,在此为了书写方便,仅对Windbg代码进行分析。
对于win32k!GreEnableEUDC,涉及到一些不知道什么意思的变量,不过并不影响分析过程。
win32k!GreEnableEUDC+0x37: 9956b88b 33f6 xor esi,esi //esi清零 9956b88d 46 inc esi //esi == 1 …… win32k!GreEnableEUDC+0x75: 9956b8c9 56 push esi //参数压栈 9956b8ca 56 push esi //参数压栈 9956b8cb e8b8faffff call win32k!BuildAndLoadLinkedFontRoutine+0xeb (9956b388)
在此只简单提一下,调用参数均为1,毕竟漏洞产生的原因并不在此。
win32k!BuildAndLoadLinkedFontRoutine+0xeb函数依旧不是重点,在此只贴出相关代码:
995cb393 be08020000 mov esi,208h 995cb398 56 push esi 995cb399 8d4dfc lea ecx,[ebp-4] 995cb39c e8a6030000 call win32k!MALLOCOBJ::MALLOCOBJ (995cb747) //生成MALLOCOBJ对象 …… 995cb3aa 8b5dfc mov ebx,dword ptr [ebp-4] …… 995cb434 6804010000 push 104h 995cb439 53 push ebx 995cb43a e8a0050000 call win32k!bAppendSysDirectory+0x209 (995cb9df)
关于win32k!MALLOCOBJ,个人感觉就像一个字符串的类,而在整个漏洞分析过程中,该对象也是扮演了一个字符串的角色,同时在内存起始位置记录了字符串信息。
下面这个函数就比较关键了,最终出错也是在这个函数当中,win32k!bAppendSysDirectory+0x209
win32k!bAppendSysDirectory+0x209: 9955b9df 8bff mov edi,edi 9955b9e1 55 push ebp 9955b9e2 8bec mov ebp,esp 9955b9e4 83ec20 sub esp,20h 9955b9e7 53 push ebx 9955b9e8 56 push esi 9955b9e9 57 push edi 9955b9ea be08020000 mov esi,208h 9955b9ef 56 push esi 9955b9f0 8d4df4 lea ecx,[ebp-0Ch] //ebp-0Ch为MALLOCOBJ对象指针 9955b9f3 e84ffdffff call win32k!MALLOCOBJ::MALLOCOBJ (9955b747) 9955b9f8 56 push esi 9955b9f9 8d4dfc lea ecx,[ebp-4] //ebp-4为MALLOCOBJ对象指针 9955b9fc e846fdffff call win32k!MALLOCOBJ::MALLOCOBJ (9955b747) 9955ba01 8b4df4 mov ecx,dword ptr [ebp-0Ch] 9955ba04 33f6 xor esi,esi //esi == 0 9955ba06 3bce cmp ecx,esi 9955ba08 0f84e6000000 je win32k!bAppendSysDirectory+0x31e (9955baf4) win32k!bAppendSysDirectory+0x238: 9955ba0e 8b7dfc mov edi,dword ptr [ebp-4] 9955ba11 3bfe cmp edi,esi 9955ba13 0f84db000000 je win32k!bAppendSysDirectory+0x31e (9955baf4) win32k!bAppendSysDirectory+0x243: 9955ba19 33c0 xor eax,eax 9955ba1b 8975f0 mov dword ptr [ebp-10h],esi 9955ba1e 8975ec mov dword ptr [ebp-14h],esi 9955ba21 668901 mov word ptr [ecx],ax 9955ba24 668907 mov word ptr [edi],ax 9955ba27 668945e0 mov word ptr [ebp-20h],ax 9955ba2b b804010000 mov eax,104h 9955ba30 50 push eax 9955ba31 8bd0 mov edx,eax 9955ba33 57 push edi 9955ba34 8975e8 mov dword ptr [ebp-18h],esi 9955ba37 668955e2 mov word ptr [ebp-1Eh],dx 9955ba3b 894de4 mov dword ptr [ebp-1Ch],ecx 9955ba3e e8d7feffff call win32k!GrePolyPolyline+0xa2 (9955b91a) //返回"/REGISTRY/USER/S-1-5-18/EUDC/936" 9955ba43 3bc6 cmp eax,esi 9955ba45 8945f8 mov dword ptr [ebp-8],eax 9955ba48 7c7c jl win32k!bAppendSysDirectory+0x2f0 (9955bac6) win32k!bAppendSysDirectory+0x274: 9955ba4a 8d45e8 lea eax,[ebp-18h] 9955ba4d 50 push eax 9955ba4e 8d45ec lea eax,[ebp-14h] 9955ba51 50 push eax 9955ba52 8d45f0 lea eax,[ebp-10h] 9955ba55 50 push eax 9955ba56 57 push edi 9955ba57 e850010000 call win32k!AutoResource<&ExFreePool>::~AutoResource<&ExFreePool>+0x177 (9955bbac) 9955ba5c 85c0 test eax,eax 9955ba5e 745f je win32k!bAppendSysDirectory+0x2e9 (9955babf) win32k!bAppendSysDirectory+0x28a: 9955ba60 3975e8 cmp dword ptr [ebp-18h],esi 9955ba63 745a je win32k!bAppendSysDirectory+0x2e9 (9955babf) win32k!bAppendSysDirectory+0x28f: 9955ba65 56 push esi 9955ba66 56 push esi 9955ba67 68e0887599 push offset win32k!SharedQueryTable (997588e0) 9955ba6c 57 push edi //"/REGISTRY/USER/S-1-5-18/EUDC/936" 9955ba6d 8d45e0 lea eax,[ebp-20h] 9955ba70 56 push esi 9955ba71 8935e0887599 mov dword ptr [win32k!SharedQueryTable (997588e0)],esi //0 9955ba77 c705e488759924000000 mov dword ptr [win32k!SharedQueryTable+0x4 (997588e4)],24h //24h 9955ba81 c705e888759964a67399 mov dword ptr [win32k!SharedQueryTable+0x8 (997588e8)],offset win32k!`string' (9973a664) //"SystemDefaultEUDCFont" 9955ba8b a3ec887599 mov dword ptr [win32k!SharedQueryTable+0xc (997588ec)],eax //指向函数栈的指针,最终出错也是因为这个参数 9955ba90 8935f0887599 mov dword ptr [win32k!SharedQueryTable+0x10 (997588f0)],esi //0 9955ba96 8935f4887599 mov dword ptr [win32k!SharedQueryTable+0x14 (997588f4)],esi //0 9955ba9c 8935f8887599 mov dword ptr [win32k!SharedQueryTable+0x18 (997588f8)],esi //0 9955baa2 8935fc887599 mov dword ptr [win32k!SharedQueryTable+0x1c (997588fc)],esi //0 9955baa8 893500897599 mov dword ptr [win32k!SharedQueryTable+0x20 (99758900)],esi //0 9955baae 893504897599 mov dword ptr [win32k!SharedQueryTable+0x24 (99758904)],esi //0 9955bab4 ff1504f17299 call dword ptr [win32k!_imp__RtlQueryRegistryValues (9972f104)]
关键为RtlQueryRegistryValues的调用,我们可以查到RtlQueryRegistryValues的定义:
NTSTATUS RtlQueryRegistryValues( IN ULONG RelativeTo, IN PCWSTR Path, IN PRTL_QUERY_REGISTRY_TABLE QueryTable, IN PVOID Context, IN PVOID Environment OPTIONAL );
结合反汇编的结果,RelativeTo为0,即RTL_REGISTRY_ABSOLUTE,为绝对路径,Path值为"/REGISTRY/USER/S-1-5-18/EUDC/936",QueryTable的类型为PRTL_QUERY_REGISTRY_TABLE其定义如下:
typedef struct _RTL_QUERY_REGISTRY_TABLE { PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; ULONG Flags; PWSTR Name; PVOID EntryContext; ULONG DefaultType; PVOID DefaultData; ULONG DefaultLength; } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
可能在Win7下对此结构有一定的扩充,不过并不影响分析。
Name值为"SystemDefaultEUDCFont",即要查询的内容。DefaultType会存储查询结果,其值为ebp-20h。其余参数为0。
事实上,对于了解RtlQueryRegistryValues函数的人来说,看到这里就已经知道问题所在了,但是作为一次漏洞分析,如果仅仅止步于此的话,并不足以说明问题,按就让我们接着看下去吧!
下面是RtlQueryRegistryValues函数,这个函数内容比较多,看代码:
kd> uf nt!RtlQueryRegistryValues nt!RtlQueryRegistryValues: 83e32d85 8bff mov edi,edi 83e32d87 55 push ebp 83e32d88 8bec mov ebp,esp 83e32d8a 83e4f8 and esp,0FFFFFFF8h 83e32d8d 83ec4c sub esp,4Ch 83e32d90 8b4d0c mov ecx,dword ptr [ebp+0Ch] //exc == Path 83e32d93 53 push ebx 83e32d94 56 push esi 83e32d95 8b7508 mov esi,dword ptr [ebp+8] //esi == RelativeTo 83e32d98 57 push edi 83e32d99 8d442420 lea eax,[esp+20h] //eax == ebp - 0x3c esp == 9240fc30 83e32d9d 50 push eax 83e32d9e 33ff xor edi,edi //edi == 0 83e32da0 57 push edi 83e32da1 8bd6 mov edx,esi //edx == RelativeTo 83e32da3 e89f0a0000 call nt!RtlpGetRegistryHandle (83e33847) //打开"/REGISTRY/USER/S-1-5-18/EUDC/936"返回,返回值放入[ebp - 0x3c](KeyHandle) 83e32da8 3bc7 cmp eax,edi //eax ntStatus 83e32daa 8944240c mov dword ptr [esp+0Ch],eax //ebp=9240fc8c esp=9240fc30 83e32dae 0f8cf7030000 jl nt!RtlQueryRegistryValues+0x426 (83e331ab) 0 nt!RtlQueryRegistryValues+0x2f: 83e32db4 8974242c mov dword ptr [esp+2Ch],esi // esp + 2c == ebp - 30 83e32db8 8164242c00000040 and dword ptr [esp+2Ch],40000000h 83e32dc0 8d442438 lea eax,[esp+38h] // esp + 38 == ebp - 24 83e32dc4 7505 jne nt!RtlQueryRegistryValues+0x46 (83e32dcb) nt!RtlQueryRegistryValues+0x41: 83e32dc6 ff750c push dword ptr [ebp+0Ch] 83e32dc9 eb01 jmp nt!RtlQueryRegistryValues+0x47 (83e32dcc) //nt!RtlQueryRegistryValues+0x46: //83e32dcb 57 push edi nt!RtlQueryRegistryValues+0x47: 83e32dcc 50 push eax //ebp - 24 83e32dcd e81661e4ff call nt!RtlInitUnicodeString (83c78ee8) //ebp - 24 == Unicode_String_Path 83e32dd2 8d44240c lea eax,[esp+0Ch] //eax == ebp-50 status 83e32dd6 50 push eax 83e32dd7 57 push edi 83e32dd8 8d74242c lea esi,[esp+2Ch] //esi == ebp-38 83e32ddc c744242c84000000 mov dword ptr [esp+2Ch],84h 83e32de4 e8d782ffff call nt!RtlpAllocDeallocQueryBuffer (83e2b0c0) //用esi传参,函数内执行ExAllocatePoolWithTag(1,0x84,0x76727152) 83e32de9 8bf0 mov esi,eax //esi指向申请空间首地址 83e32deb 3bf7 cmp esi,edi 83e32ded 7518 jne nt!RtlQueryRegistryValues+0x82 (83e32e07) nt!RtlQueryRegistryValues+0x82: 83e32e07 8b5d10 mov ebx,dword ptr [ebp+10h] //ebx == QueryTable 83e32e0a 897e08 mov dword ptr [esi+8],edi 83e32e0d 8b442420 mov eax,dword ptr [esp+20h] //eax == KeyHandle 83e32e11 c744242882000000 mov dword ptr [esp+28h],82h //ebp - 34 83e32e19 8944241c mov dword ptr [esp+1Ch],eax //ebp - 40 nt!RtlQueryRegistryValues+0x98: 83e32e1d 8b0b mov ecx,dword ptr [ebx] //ecx == QueryTable->QueryRoutine 83e32e1f 3bcf cmp ecx,edi 83e32e21 750a jne nt!RtlQueryRegistryValues+0xa8 (83e32e2d) nt!RtlQueryRegistryValues+0x9e: 83e32e23 f6430421 test byte ptr [ebx+4],21h // byte ptr [ebx+4] = 21h 83e32e27 0f8446030000 je nt!RtlQueryRegistryValues+0x3ee (83e33173) nt!RtlQueryRegistryValues+0xa8: 83e32e2d 8b4304 mov eax,dword ptr [ebx+4] 83e32e30 a820 test al,20h 83e32e32 7419 je nt!RtlQueryRegistryValues+0xc8 (83e32e4d) nt!RtlQueryRegistryValues+0xaf: 83e32e34 397b08 cmp dword ptr [ebx+8],edi 83e32e37 0f841b030000 je nt!RtlQueryRegistryValues+0x3d3 (83e33158) nt!RtlQueryRegistryValues+0xb8: 83e32e3d a801 test al,1 83e32e3f 0f8513030000 jne nt!RtlQueryRegistryValues+0x3d3 (83e33158) nt!RtlQueryRegistryValues+0xc0: 83e32e45 3bcf cmp ecx,edi 83e32e47 0f850b030000 jne nt!RtlQueryRegistryValues+0x3d3 (83e33158) nt!RtlQueryRegistryValues+0xc8: 83e32e4d a803 test al,3 83e32e4f 7418 je nt!RtlQueryRegistryValues+0xe4 (83e32e69) nt!RtlQueryRegistryValues+0xe4: 83e32e69 8b4b04 mov ecx,dword ptr [ebx+4] //ecx == QueryTable->Flags 83e32e6c 8b4308 mov eax,dword ptr [ebx+8] //eax == QueryTable->Name 83e32e6f f6c101 test cl,1 83e32e72 0f8438010000 je nt!RtlQueryRegistryValues+0x22b (83e32fb0) 1 nt!RtlQueryRegistryValues+0x22b: 83e32fb0 3bc7 cmp eax,edi 83e32fb2 0f8417010000 je nt!RtlQueryRegistryValues+0x34a (83e330cf) nt!RtlQueryRegistryValues+0x233: 83e32fb8 50 push eax 83e32fb9 8d442434 lea eax,[esp+34h] 83e32fbd 50 push eax 83e32fbe e8255fe4ff call nt!RtlInitUnicodeString (83c78ee8) 83e32fc3 897c2414 mov dword ptr [esp+14h],edi nt!RtlQueryRegistryValues+0x242: 83e32fc7 8b442414 mov eax,dword ptr [esp+14h] 83e32fcb ff442414 inc dword ptr [esp+14h] 83e32fcf 83f804 cmp eax,4 83e32fd2 0f8f8a010000 jg nt!RtlQueryRegistryValues+0x3dd (83e33162) nt!RtlQueryRegistryValues+0x253: 83e32fd8 8d442410 lea eax,[esp+10h] //eax == ebp-4c 83e32fdc 50 push eax //ebp - 4c 83e32fdd ff74242c push dword ptr [esp+2Ch] //0x82 83e32fe1 8d442438 lea eax,[esp+38h] // 83e32fe5 56 push esi //通过nt!RtlpAllocDeallocQueryBuffer申请空间的内存空间首地址 83e32fe6 6a01 push 1 //1 83e32fe8 50 push eax //ebp-2c 83e32fe9 ff742430 push dword ptr [esp+30h] //KeyHandle 83e32fed e86a9ee4ff call nt!ZwQueryValueKey (83c7ce5c) 83e32ff2 8944240c mov dword ptr [esp+0Ch],eax 83e32ff6 bf230000c0 mov edi,0C0000023h 83e32ffb 3d05000080 cmp eax,80000005h 83e33000 7504 jne nt!RtlQueryRegistryValues+0x281 (83e33006) nt!RtlQueryRegistryValues+0x281: 83e33006 33c0 xor eax,eax 83e33008 3944240c cmp dword ptr [esp+0Ch],eax 83e3300c 7d69 jge nt!RtlQueryRegistryValues+0x2f2 (83e33077) nt!RtlQueryRegistryValues+0x2f2: 83e33077 837e0407 cmp dword ptr [esi+4],7 83e3307b 750e jne nt!RtlQueryRegistryValues+0x306 (83e3308b) nt!RtlQueryRegistryValues+0x306: 83e3308b 8b442428 mov eax,dword ptr [esp+28h] 83e3308f ff7514 push dword ptr [ebp+14h] //Context == 0 83e33092 89442414 mov dword ptr [esp+14h],eax 83e33096 53 push ebx //QueryTable 83e33097 8d4c2418 lea ecx,[esp+18h] //ebp-4c == 0x82 83e3309b 8bc6 mov eax,esi //esi指向申请内存空间 83e3309d e8df7affff call nt!RtlpCallQueryRegistryRoutine (83e2ab81)
KeyHandle为打开键值的句柄。
后面的注释是在分析的时候简单做的记录,因为函数的起始位置有一个句内存对齐的代码,所以后面的变量都是利用esp加偏移量来定位的,这点为分析带来了很多不便,以上的数据是某一次调试时的具体数据,仅供参考。
根据nt!ZwQueryValueKey的参数,可以得知返回的信息为KEY_VALUE_FULL_INFORMATION结构,其定义如下:
typedef struct _KEY_VALUE_FULL_INFORMATION { ULONG TitleIndex; ULONG Type; ULONG DataOffset; ULONG DataLength; ULONG NameLength; WCHAR Name[1]; // Variable size } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
返回信息放入esi中,及在函数前面申请的大小为0x84的内存空间。
函数的主要内容就是对QueryTable中的内容做了一系列的检测,然后调用了nt!RtlpCallQueryRegistryRoutine,将两个参数QueryTable和Context分别压栈。但是事实上nt!RtlpCallQueryRegistryRoutine的参数不仅仅只有两个,还有一些参数是通过寄存器传递的,其内容在上面的代码中也都标注出来了。
下面是nt!RtlpCallQueryRegistryRoutine函数的主要内容。
nt!RtlpCallQueryRegistryRoutine+0x282: 83e2ae03 ff730c push dword ptr [ebx+0Ch] //QueryTable->EntryContext 83e2ae06 f6c120 test cl,20h 83e2ae09 7436 je nt!RtlpCallQueryRegistryRoutine+0x2c0 (83e2ae41) nt!RtlpCallQueryRegistryRoutine+0x28a: 83e2ae0b 8b5508 mov edx,dword ptr [ebp+8] //QueryTable 83e2ae0e 57 push edi //edi指向KEY_VALUE_FULL_INFORMATION结构中的Name 83e2ae0f 8bc6 mov eax,esi //esi指向KEY_VALUE_FULL_INFORMATION信息首地址偏移量为0xC的位置,即DataLength 83e2ae11 e8818b0000 call nt!RtlpQueryRegistryDirect (83e33997)
这个函数依旧是对参数做了简单的判断的护理,然后传递给nt!RtlpQueryRegistryDirect。
nt!RtlpQueryRegistryDirect函数的内容如下:
kd> uf nt!RtlpQueryRegistryDirect nt!RtlpQueryRegistryDirect: 83e33997 8bff mov edi,edi 83e33999 55 push ebp 83e3399a 8bec mov ebp,esp 83e3399c 53 push ebx 83e3399d 8b5d08 mov ebx,dword ptr [ebp+8] 83e339a0 56 push esi 83e339a1 8b750c mov esi,dword ptr [ebp+0Ch] //esi == QueryTable->EntryContext 83e339a4 57 push edi 83e339a5 83fa01 cmp edx,1 83e339a8 7445 je nt!RtlpQueryRegistryDirect+0x56 (83e339ef) nt!RtlpQueryRegistryDirect+0x13: 83e339aa 83fa02 cmp edx,2 83e339ad 7440 je nt!RtlpQueryRegistryDirect+0x56 (83e339ef) nt!RtlpQueryRegistryDirect+0x18: 83e339af 83fa07 cmp edx,7 83e339b2 743b je nt!RtlpQueryRegistryDirect+0x56 (83e339ef) nt!RtlpQueryRegistryDirect+0x1d: 83e339b4 83f804 cmp eax,4 83e339b7 770c ja nt!RtlpQueryRegistryDirect+0x2c (83e339c5) nt!RtlpQueryRegistryDirect+0x22: 83e339b9 3bf3 cmp esi,ebx 83e339bb 7476 je nt!RtlpQueryRegistryDirect+0x9a (83e33a33) nt!RtlpQueryRegistryDirect+0x26: 83e339bd 85c0 test eax,eax 83e339bf 7510 jne nt!RtlpQueryRegistryDirect+0x38 (83e339d1) nt!RtlpQueryRegistryDirect+0x2a: 83e339c1 eb70 jmp nt!RtlpQueryRegistryDirect+0x9a (83e33a33) nt!RtlpQueryRegistryDirect+0x2c: 83e339c5 8b0e mov ecx,dword ptr [esi] 83e339c7 85c9 test ecx,ecx 83e339c9 7d13 jge nt!RtlpQueryRegistryDirect+0x45 (83e339de) nt!RtlpQueryRegistryDirect+0x45: 83e339de 8d7808 lea edi,[eax+8] 83e339e1 3bcf cmp ecx,edi 83e339e3 725d jb nt!RtlpQueryRegistryDirect+0xa9 (83e33a42) nt!RtlpQueryRegistryDirect+0x4c: 83e339e5 8906 mov dword ptr [esi],eax //esi指向win32k!bAppendSysDirectory+0x209函数的栈空间 83e339e7 895604 mov dword ptr [esi+4],edx //溢出! 83e339ea 83c608 add esi,8 83e339ed ebe2 jmp nt!RtlpQueryRegistryDirect+0x38 (83e339d1) nt!RtlpQueryRegistryDirect+0x38: 83e339d1 50 push eax //esi指向KEY_VALUE_FULL_INFORMATION信息首地址偏移量为0xC的位置,即DataLength 83e339d2 53 push ebx //edx指向KEY_VALUE_FULL_INFORMATION结构中的Name 83e339d3 56 push esi //QueryTable->EntryContext + 8 83e339d4 e8c75de4ff call nt!memcpy (83c797a0) //溢出!
在前面说过,QueryTable->EntryContext指向了win32k!bAppendSysDirectory+0x209函数的栈空间,那么通过上面的代码可以看到,栈溢出了!