名称:win32子系统之三:ValidateHwnd函数分析
作者:mengwuji
时间:2013.5.28 18:32
链接:http://mengwuji.net/forum.php?mod=viewthread&tid=99&extra=page%3D1
win32k!NtUserQueryWindow:
92dbe20a mov edi,edi
92dbe20c push ebp
92dbe20d mov ebp,esp
92dbe20f push esi
92dbe210 push edi
//分析过EnterSharedCrit函数的用处,主要是为了让当前线程获取对系统资源的控制权
92dbe211 call win32k!EnterSharedCrit (92dd3141)
//ecx = hwnd
92dbe216 mov ecx,dword ptr [ebp+8]
//这个函数是验证传入窗口句柄的有效性,那么我们可以看看系统如何判断一个窗口句柄的有效性的(好吧,看来想明白NtUserQueryWindow原理还要等一段时间了。中间调用的函数都够我分析老半天了)
92dbe219 call win32k!ValidateHwnd (92dd90c0)
............
win32k!ValidateHwnd:
92dd90c0 mov edi,edi
92dd90c2 push ebp
92dd90c3 mov ebp,esp
92dd90c5 sub esp,0Ch
//edx = [gpsi] gpsi以前分析过,是个成员为tagSERVERINFO结构的数组,这个结构信息量很多,下面遇到的时候再说
92dd90c8 mov edx,dword ptr [win32k!gpsi (92f2255c)]
92dd90ce push ebx
//和用户层一样的,取句柄低2字节,实际是个下标
92dd90cf movzx eax,cx
92dd90d2 push esi
92dd90d3 push edi
//先保存下句柄,后面还会用到
92dd90d4 mov dword ptr [ebp-8],ecx
//tagSERVERINFO偏移4的位置是cHandleEntries,这个应该是窗口句柄的最大个数
92dd90d7 cmp eax,dword ptr [edx+4]
//大于cHandleEntries就出错了,然后跳到错误处理
92dd90da jae win32k!ValidateHwnd+0x15a (92dd921a)
//gSharedInfo是个tagSHAREDINFO结构(以前分析定时器的时候研究过),偏移+8的位置是HeEntrySize,这个应该是描述窗口句柄关联的一个对象尺寸
92dd90e0 mov esi,dword ptr [win32k!gSharedInfo+0x8 (92f22448)]
//定位到当前句柄所在句柄关联的对象数组里面的偏移
92dd90e6 imul esi,eax
//gSharedInfo+4是aheList,说明aheList是系统中窗口句柄关联的一个对象数组基址。通过它可以定位到具体句柄关联的对象,句柄关联的对象是HANDLEENTRY结构
92dd90e9 add esi,dword ptr [win32k!gSharedInfo+0x4 (92f22444)]
//下面开始取窗口句柄的高2字节
92dd90ef mov eax,ecx
92dd90f1 shr eax,10h
//现在的esi经过上面的计算已经知道是个HANDLEENTRY结构,+a位置是wUniq。比较窗口句柄的高2字节和这个值
92dd90f4 cmp ax,word ptr [esi+0Ah]
//相等跳转
92dd90f8 je win32k!ValidateHwnd+0x4d (92dd910d)
//不相等比较句柄高两字节是否为零
92dd90fa test ax,ax
//为零跳转
92dd90fd je win32k!ValidateHwnd+0x4d (92dd910d)
//比较句柄高两字节是够为ffff
92dd90ff mov ecx,0FFFFh
92dd9104 cmp ax,cx
//不等于ffff,到这里说明出错了。那么就执行错误处理
92dd9107 jne win32k!ValidateHwnd+0x15a (92dd921a)
//HANDLEENTRY的bType是句柄的类型,这个类型和1比较
92dd910d cmp byte ptr [esi+8],1
//不等于1说明出错了,跳到错误处理
92dd9111 jne win32k!ValidateHwnd+0x15a (92dd921a)
//接下来调用PsGetCurrentThreadWin32Thread函数,这个函数很简单,三句代码。我直接放到下面来分析
------------------------------------------------>
//PsGetCurrentThreadWin32Thread
81e9d498 mov eax,dword ptr fs:[00000124h] //eax得到当前线程对象
81e9d49e mov eax,dword ptr [eax+18Ch] //+18c位置是Win32Thread
81e9d4a4 ret
<------------------------------------------------
//上面的只是得到当前线程对象的Win32Thread成员,这个成员是个_W32THREAD结构,但是它不够全面描述一个线程gui信息。实际还有一个tagTHREADINFO结构,也是描述Win32Thread这个成员的,tagTHREADINFO结构的信息才是全面的,大家可以用windbg看看(这些结构是之前分析定时器的时候发现的,这里不重复分析具体分析过程)
92dd9117 call dword ptr [win32k!_imp__PsGetCurrentThreadWin32Thread (92ef4034)]
//ebx = phead,是个句柄关联对象的头
92dd911d mov ebx,dword ptr [esi]
//保存当前线程的tagTHREADINFO结构
92dd911f mov edi,eax
//保存句柄管理的对象头
92dd9121 mov dword ptr [ebp-4],ebx
92dd9124 test ebx,ebx
//对象头等于0跳转,说明发生错误,跳到错误处理位置
92dd9126 je win32k!ValidateHwnd+0x15a (92dd921a)
//比较句柄关联对象的bFlags成员第0位是否为真
92dd912c test byte ptr [esi+9],1
//所关联对象头是个_HEAD结构,但是这个结构貌似也表示的不全面,所以+8位置的值现在还不能确定是什么
92dd9130 mov eax,dword ptr [ebx+8]
//保存+8位置的值
92dd9133 mov dword ptr [ebp-0Ch],eax
//bFlags&0x1为真的话就跳转,跳到错误处理
92dd9136 jne win32k!ValidateHwnd+0x15a (92dd921a)
//上面不知道对象头+8位置是什么东西,下面的比较就暴露了是什么了。是这个对象关联的gui线程的tagTHREADINFO结构,这里进行比较是判断我们传入的句柄,是否是我们这条线程本身创建的窗口
92dd913c cmp eax,edi
//是的话就跳转
92dd913e je win32k!ValidateHwnd+0xac (92dd916c)
//对象头+c,我们看下一句就能明白这个地方是什么了
92dd9140 mov ecx,dword ptr [ebx+0Ch]
//tagTHREADINFO+0xC8位置是rpdesk成员,它是一个tagDESKTOP对象,是桌面相关的数据结构,那么上面的对象头+c位置就是这个句柄所在的桌面了,下面这个比较就是比较这个句柄是否在当前桌面(因为windows支持多个桌面的!)
92dd9143 cmp ecx,dword ptr [edi+0C8h]
//是当前桌面的句柄,就跳转
92dd9149 je win32k!ValidateHwnd+0xac (92dd916c)
//如果不是当前桌面的句柄,就比较看看tagTHREADINFO的TIF_flags第三位是否为真
92dd914b test byte ptr [edi+0D8h],4
92dd9152 jne win32k!ValidateHwnd+0xac (92dd916c)
//tagTHREADINFO的ppi成员,这个成员是一个tagPROCESSINFO对象,这个对象是当前线程所在进程关联的tagPROCESSINFO对象
92dd9154 mov edx,dword ptr [edi+0B8h]
//push rpdesk
92dd915a push ecx
//push ppi
92dd915b push edx
//call GetDesktopView,我们在下面看看GetDesktopView的流程,很简单所以直接放到这里看!
-------------------------------------------------------------->
//GetDesktopView
92dcf9aa mov edi,edi
92dcf9ac push ebp
92dcf9ad mov ebp,esp
92dcf9af mov eax,dword ptr [ebp+8] //ppi
//pdvList,是个tagDESKTOPVIEW结构,这个结构是系统所有桌面组成的一个单链表
92dcf9b2 mov eax,dword ptr [eax+154h]
92dcf9b8 jmp win32k!GetDesktopView+0x1a (92dcf9c4) //这里进行一个简单的循环
92dcf9ba mov ecx,dword ptr [eax+4]
92dcf9bd cmp ecx,dword ptr [ebp+0Ch]
92dcf9c0 je win32k!GetDesktopView+0x1e (92dcf9c8)
92dcf9c2 mov eax,dword ptr [eax]
92dcf9c4 test eax,eax
92dcf9c6 jne win32k!GetDesktopView+0x10 (92dcf9ba)
92dcf9c8 pop ebp
92dcf9c9 ret 8
<--------------------------------------------------------------
//GetDesktopView函数进行一下简单的遍历工作,找到传入句柄所关联的一个tagDESKTOPVIEW对象,实际调用此函数的目的只是为了证明这个句柄是在某个桌面中的,如果一个桌面都没有这个窗口,那么肯定就出错了
92dd915c call win32k!GetDesktopView (92dcf9aa)
92dd9161 test eax,eax
//比较查找的是够为零,是的话,就出错了,然后退出
92dd9163 je win32k!ValidateHwnd+0x15a (92dd921a)
//epb-c保存的是当前句柄关联线程的tagTHREADINFO结构
92dd9169 mov eax,dword ptr [ebp-0Ch]
//一个全局标记,目前不知道做什么
92dd916c cmp byte ptr [win32k!gbValidateHandleForIL (92f21f38)],0
根据这个值执行不同两个流程
92dd9173 je win32k!ValidateHwnd+0x10f (92dd91cf)
//句柄关联的tagTHREADINFO为零跳转
92dd9175 test eax,eax
92dd9177 je win32k!ValidateHwnd+0x10f (92dd91cf)
//ebx = 传入句柄的ppi
92dd9179 mov ebx,dword ptr [eax+0B8h]
//eax = 当前线程的ppi
92dd917f mov eax,dword ptr [edi+0B8h]
//ecx = 传入句柄的pvwplWndGCList
92dd9185 mov ecx,dword ptr [ebx+1ACh]
//edx = 当前线程的pvwplWndGCList
92dd918b mov edx,dword ptr [eax+1ACh]
92dd9191 push ecx
92dd9192 push edx
//这个函数比较简单,我们在下面直接分析
--------------------------------------------------------->
win32k!CheckAccessForIntegrityLevel:
92dd9232 mov edi,edi
92dd9234 push ebp
92dd9235 mov ebp,esp
92dd9237 cmp dword ptr [win32k!gbEnforceUIPI (92f21f3c)],0 //未知的全局变量
92dd923e jne win32k!CheckAccessForIntegrityLevel+0x13 (92dd9245)
//到这里的话就返回1
92dd9240 xor eax,eax
92dd9242 inc eax
92dd9243 jmp win32k!CheckAccessForIntegrityLevel+0x1c (92dd924e)
92dd9245 mov eax,dword ptr [ebp+8] //当前线程的pvwplWndGCList
92dd9248 cmp eax,dword ptr [ebp+0Ch] //传入句柄的pvwplWndGCList,相等cf为1,不相等cf为0
92dd924b sbb eax,eax //如果相等,后面的操作执行后返回零,否则返回1
92dd924d inc eax
92dd924e pop ebp
92dd924f ret 8
<---------------------------------------------------------
//这个函数比较传入的两个参数是否相等,不相等的话返回零,相等的话返回一
92dd9193 call win32k!CheckAccessForIntegrityLevel (92dd9232)
92dd9198 test eax,eax
92dd919a jne win32k!ValidateHwnd+0x10c (92dd91cc)
//eax = 传入句柄的进程对象
92dd919c mov eax,dword ptr [ebx]
//比较这个进程对象是不是csrss.exe进程的
92dd919e cmp eax,dword ptr [win32k!gpepCSRSS (92f225ec)]
//是的话跳转
92dd91a4 je win32k!ValidateHwnd+0x10c (92dd91cc)
//下面直到92dd91cb都是错误处理,我也懒得看了
92dd91a6 movzx ecx,byte ptr [esi+8]
92dd91aa mov edx,dword ptr [ebp-8]
92dd91ad mov eax,dword ptr [edi+0B8h]
92dd91b3 push ecx
92dd91b4 push edx
92dd91b5 push ebx
92dd91b6 push eax
92dd91b7 call win32k!EtwTraceUIPIHandleValidationError (92e588d8)
92dd91bc push 5
92dd91be call win32k!UserSetLastError (92d9769d)
92dd91c3 pop edi
92dd91c4 pop esi
92dd91c5 xor eax,eax
92dd91c7 pop ebx
92dd91c8 mov esp,ebp
92dd91ca pop ebp
92dd91cb ret
//传入句柄关联的那个对象头给ebx
92dd91cc mov ebx,dword ptr [ebp-4]
//+D8是当前线程的TIF_flags
92dd91cf test dword ptr [edi+0D8h],20000000h
//根据比较后选择跳转
92dd91d9 je win32k!ValidateHwnd+0x151 (92dd9211)
//ecx = 当前线程的ppi
92dd91db mov ecx,dword ptr [edi+0B8h]
//edx = 当前进程的pW32Job
92dd91e1 mov edx,dword ptr [ecx+170h]
//eax = 当前进程pW32JOB的restrictions
92dd91e7 mov eax,dword ptr [edx+0Ch]
//看第零位是否存在
92dd91ea and eax,1
//存在就返回
92dd91ed je win32k!ValidateHwnd+0x151 (92dd9211)
//eax是传入的句柄
92dd91ef mov eax,dword ptr [ebp-8]
//esi是句柄关联的对象
92dd91f2 push esi
92dd91f3 push eax
//调用IsHandleEntrySecure函数,这个函数是检测句柄的安全性,具体我也不分析了,有兴趣的人可以看看。
92dd91f4 call win32k!IsHandleEntrySecure (92e38dc2)
92dd91f9 test eax,eax
92dd91fb jne win32k!ValidateHwnd+0x151 (92dd9211)
92dd91fd push 578h
92dd9202 call win32k!UserSetLastError (92d9769d)
92dd9207 mov dword ptr [ebp-4],0
92dd920e mov ebx,dword ptr [ebp-4]
92dd9211 pop edi
92dd9212 pop esi
92dd9213 mov eax,ebx
92dd9215 pop ebx
92dd9216 mov esp,ebp
92dd9218 pop ebp
92dd9219 ret
92dd921a push 578h
92dd921f call win32k!UserSetLastError (92d9769d)
92dd9224 pop edi
92dd9225 pop esi
92dd9226 xor eax,eax
92dd9228 pop ebx
92dd9229 mov esp,ebp
92dd922b pop ebp
92dd922c ret
//ValidateHwnd这个函数无非检测句柄的合法性,通过各种判断然后确定传入的句柄是否有效。至于怎么判断的,汇编代码里面有详细的注释了。值得注意的是tagTHREADINFO是关于gui线程的一个数据结构,tagPROCESSINFO是关于gui进程的一个数据结构。然后遍历窗口句柄实际可以通过gSharedInfo全局结构来遍历,还能得到关于这个句柄对应的线程进程信息,和句柄所对应的句柄对象都可以。总之,这里面涉及的一些数据结构能掌握或者了解就相当不错了。
希望大家耐心看看,我不想在这里反汇编成c代码是因为提升效率。因为这个函数分析完成只是开始,后面还有更加多的内容在等待着我们。
我只起一个引导作用,接下来就看大家各自发挥吧......
ps:www.mengwuji.net
作者:mengwuji
时间:2013.5.28 18:32
链接:http://mengwuji.net/forum.php?mod=viewthread&tid=99&extra=page%3D1
win32k!NtUserQueryWindow:
92dbe20a mov edi,edi
92dbe20c push ebp
92dbe20d mov ebp,esp
92dbe20f push esi
92dbe210 push edi
//分析过EnterSharedCrit函数的用处,主要是为了让当前线程获取对系统资源的控制权
92dbe211 call win32k!EnterSharedCrit (92dd3141)
//ecx = hwnd
92dbe216 mov ecx,dword ptr [ebp+8]
//这个函数是验证传入窗口句柄的有效性,那么我们可以看看系统如何判断一个窗口句柄的有效性的(好吧,看来想明白NtUserQueryWindow原理还要等一段时间了。中间调用的函数都够我分析老半天了)
92dbe219 call win32k!ValidateHwnd (92dd90c0)
............
win32k!ValidateHwnd:
92dd90c0 mov edi,edi
92dd90c2 push ebp
92dd90c3 mov ebp,esp
92dd90c5 sub esp,0Ch
//edx = [gpsi] gpsi以前分析过,是个成员为tagSERVERINFO结构的数组,这个结构信息量很多,下面遇到的时候再说
92dd90c8 mov edx,dword ptr [win32k!gpsi (92f2255c)]
92dd90ce push ebx
//和用户层一样的,取句柄低2字节,实际是个下标
92dd90cf movzx eax,cx
92dd90d2 push esi
92dd90d3 push edi
//先保存下句柄,后面还会用到
92dd90d4 mov dword ptr [ebp-8],ecx
//tagSERVERINFO偏移4的位置是cHandleEntries,这个应该是窗口句柄的最大个数
92dd90d7 cmp eax,dword ptr [edx+4]
//大于cHandleEntries就出错了,然后跳到错误处理
92dd90da jae win32k!ValidateHwnd+0x15a (92dd921a)
//gSharedInfo是个tagSHAREDINFO结构(以前分析定时器的时候研究过),偏移+8的位置是HeEntrySize,这个应该是描述窗口句柄关联的一个对象尺寸
92dd90e0 mov esi,dword ptr [win32k!gSharedInfo+0x8 (92f22448)]
//定位到当前句柄所在句柄关联的对象数组里面的偏移
92dd90e6 imul esi,eax
//gSharedInfo+4是aheList,说明aheList是系统中窗口句柄关联的一个对象数组基址。通过它可以定位到具体句柄关联的对象,句柄关联的对象是HANDLEENTRY结构
92dd90e9 add esi,dword ptr [win32k!gSharedInfo+0x4 (92f22444)]
//下面开始取窗口句柄的高2字节
92dd90ef mov eax,ecx
92dd90f1 shr eax,10h
//现在的esi经过上面的计算已经知道是个HANDLEENTRY结构,+a位置是wUniq。比较窗口句柄的高2字节和这个值
92dd90f4 cmp ax,word ptr [esi+0Ah]
//相等跳转
92dd90f8 je win32k!ValidateHwnd+0x4d (92dd910d)
//不相等比较句柄高两字节是否为零
92dd90fa test ax,ax
//为零跳转
92dd90fd je win32k!ValidateHwnd+0x4d (92dd910d)
//比较句柄高两字节是够为ffff
92dd90ff mov ecx,0FFFFh
92dd9104 cmp ax,cx
//不等于ffff,到这里说明出错了。那么就执行错误处理
92dd9107 jne win32k!ValidateHwnd+0x15a (92dd921a)
//HANDLEENTRY的bType是句柄的类型,这个类型和1比较
92dd910d cmp byte ptr [esi+8],1
//不等于1说明出错了,跳到错误处理
92dd9111 jne win32k!ValidateHwnd+0x15a (92dd921a)
//接下来调用PsGetCurrentThreadWin32Thread函数,这个函数很简单,三句代码。我直接放到下面来分析
------------------------------------------------>
//PsGetCurrentThreadWin32Thread
81e9d498 mov eax,dword ptr fs:[00000124h] //eax得到当前线程对象
81e9d49e mov eax,dword ptr [eax+18Ch] //+18c位置是Win32Thread
81e9d4a4 ret
<------------------------------------------------
//上面的只是得到当前线程对象的Win32Thread成员,这个成员是个_W32THREAD结构,但是它不够全面描述一个线程gui信息。实际还有一个tagTHREADINFO结构,也是描述Win32Thread这个成员的,tagTHREADINFO结构的信息才是全面的,大家可以用windbg看看(这些结构是之前分析定时器的时候发现的,这里不重复分析具体分析过程)
92dd9117 call dword ptr [win32k!_imp__PsGetCurrentThreadWin32Thread (92ef4034)]
//ebx = phead,是个句柄关联对象的头
92dd911d mov ebx,dword ptr [esi]
//保存当前线程的tagTHREADINFO结构
92dd911f mov edi,eax
//保存句柄管理的对象头
92dd9121 mov dword ptr [ebp-4],ebx
92dd9124 test ebx,ebx
//对象头等于0跳转,说明发生错误,跳到错误处理位置
92dd9126 je win32k!ValidateHwnd+0x15a (92dd921a)
//比较句柄关联对象的bFlags成员第0位是否为真
92dd912c test byte ptr [esi+9],1
//所关联对象头是个_HEAD结构,但是这个结构貌似也表示的不全面,所以+8位置的值现在还不能确定是什么
92dd9130 mov eax,dword ptr [ebx+8]
//保存+8位置的值
92dd9133 mov dword ptr [ebp-0Ch],eax
//bFlags&0x1为真的话就跳转,跳到错误处理
92dd9136 jne win32k!ValidateHwnd+0x15a (92dd921a)
//上面不知道对象头+8位置是什么东西,下面的比较就暴露了是什么了。是这个对象关联的gui线程的tagTHREADINFO结构,这里进行比较是判断我们传入的句柄,是否是我们这条线程本身创建的窗口
92dd913c cmp eax,edi
//是的话就跳转
92dd913e je win32k!ValidateHwnd+0xac (92dd916c)
//对象头+c,我们看下一句就能明白这个地方是什么了
92dd9140 mov ecx,dword ptr [ebx+0Ch]
//tagTHREADINFO+0xC8位置是rpdesk成员,它是一个tagDESKTOP对象,是桌面相关的数据结构,那么上面的对象头+c位置就是这个句柄所在的桌面了,下面这个比较就是比较这个句柄是否在当前桌面(因为windows支持多个桌面的!)
92dd9143 cmp ecx,dword ptr [edi+0C8h]
//是当前桌面的句柄,就跳转
92dd9149 je win32k!ValidateHwnd+0xac (92dd916c)
//如果不是当前桌面的句柄,就比较看看tagTHREADINFO的TIF_flags第三位是否为真
92dd914b test byte ptr [edi+0D8h],4
92dd9152 jne win32k!ValidateHwnd+0xac (92dd916c)
//tagTHREADINFO的ppi成员,这个成员是一个tagPROCESSINFO对象,这个对象是当前线程所在进程关联的tagPROCESSINFO对象
92dd9154 mov edx,dword ptr [edi+0B8h]
//push rpdesk
92dd915a push ecx
//push ppi
92dd915b push edx
//call GetDesktopView,我们在下面看看GetDesktopView的流程,很简单所以直接放到这里看!
-------------------------------------------------------------->
//GetDesktopView
92dcf9aa mov edi,edi
92dcf9ac push ebp
92dcf9ad mov ebp,esp
92dcf9af mov eax,dword ptr [ebp+8] //ppi
//pdvList,是个tagDESKTOPVIEW结构,这个结构是系统所有桌面组成的一个单链表
92dcf9b2 mov eax,dword ptr [eax+154h]
92dcf9b8 jmp win32k!GetDesktopView+0x1a (92dcf9c4) //这里进行一个简单的循环
92dcf9ba mov ecx,dword ptr [eax+4]
92dcf9bd cmp ecx,dword ptr [ebp+0Ch]
92dcf9c0 je win32k!GetDesktopView+0x1e (92dcf9c8)
92dcf9c2 mov eax,dword ptr [eax]
92dcf9c4 test eax,eax
92dcf9c6 jne win32k!GetDesktopView+0x10 (92dcf9ba)
92dcf9c8 pop ebp
92dcf9c9 ret 8
<--------------------------------------------------------------
//GetDesktopView函数进行一下简单的遍历工作,找到传入句柄所关联的一个tagDESKTOPVIEW对象,实际调用此函数的目的只是为了证明这个句柄是在某个桌面中的,如果一个桌面都没有这个窗口,那么肯定就出错了
92dd915c call win32k!GetDesktopView (92dcf9aa)
92dd9161 test eax,eax
//比较查找的是够为零,是的话,就出错了,然后退出
92dd9163 je win32k!ValidateHwnd+0x15a (92dd921a)
//epb-c保存的是当前句柄关联线程的tagTHREADINFO结构
92dd9169 mov eax,dword ptr [ebp-0Ch]
//一个全局标记,目前不知道做什么
92dd916c cmp byte ptr [win32k!gbValidateHandleForIL (92f21f38)],0
根据这个值执行不同两个流程
92dd9173 je win32k!ValidateHwnd+0x10f (92dd91cf)
//句柄关联的tagTHREADINFO为零跳转
92dd9175 test eax,eax
92dd9177 je win32k!ValidateHwnd+0x10f (92dd91cf)
//ebx = 传入句柄的ppi
92dd9179 mov ebx,dword ptr [eax+0B8h]
//eax = 当前线程的ppi
92dd917f mov eax,dword ptr [edi+0B8h]
//ecx = 传入句柄的pvwplWndGCList
92dd9185 mov ecx,dword ptr [ebx+1ACh]
//edx = 当前线程的pvwplWndGCList
92dd918b mov edx,dword ptr [eax+1ACh]
92dd9191 push ecx
92dd9192 push edx
//这个函数比较简单,我们在下面直接分析
--------------------------------------------------------->
win32k!CheckAccessForIntegrityLevel:
92dd9232 mov edi,edi
92dd9234 push ebp
92dd9235 mov ebp,esp
92dd9237 cmp dword ptr [win32k!gbEnforceUIPI (92f21f3c)],0 //未知的全局变量
92dd923e jne win32k!CheckAccessForIntegrityLevel+0x13 (92dd9245)
//到这里的话就返回1
92dd9240 xor eax,eax
92dd9242 inc eax
92dd9243 jmp win32k!CheckAccessForIntegrityLevel+0x1c (92dd924e)
92dd9245 mov eax,dword ptr [ebp+8] //当前线程的pvwplWndGCList
92dd9248 cmp eax,dword ptr [ebp+0Ch] //传入句柄的pvwplWndGCList,相等cf为1,不相等cf为0
92dd924b sbb eax,eax //如果相等,后面的操作执行后返回零,否则返回1
92dd924d inc eax
92dd924e pop ebp
92dd924f ret 8
<---------------------------------------------------------
//这个函数比较传入的两个参数是否相等,不相等的话返回零,相等的话返回一
92dd9193 call win32k!CheckAccessForIntegrityLevel (92dd9232)
92dd9198 test eax,eax
92dd919a jne win32k!ValidateHwnd+0x10c (92dd91cc)
//eax = 传入句柄的进程对象
92dd919c mov eax,dword ptr [ebx]
//比较这个进程对象是不是csrss.exe进程的
92dd919e cmp eax,dword ptr [win32k!gpepCSRSS (92f225ec)]
//是的话跳转
92dd91a4 je win32k!ValidateHwnd+0x10c (92dd91cc)
//下面直到92dd91cb都是错误处理,我也懒得看了
92dd91a6 movzx ecx,byte ptr [esi+8]
92dd91aa mov edx,dword ptr [ebp-8]
92dd91ad mov eax,dword ptr [edi+0B8h]
92dd91b3 push ecx
92dd91b4 push edx
92dd91b5 push ebx
92dd91b6 push eax
92dd91b7 call win32k!EtwTraceUIPIHandleValidationError (92e588d8)
92dd91bc push 5
92dd91be call win32k!UserSetLastError (92d9769d)
92dd91c3 pop edi
92dd91c4 pop esi
92dd91c5 xor eax,eax
92dd91c7 pop ebx
92dd91c8 mov esp,ebp
92dd91ca pop ebp
92dd91cb ret
//传入句柄关联的那个对象头给ebx
92dd91cc mov ebx,dword ptr [ebp-4]
//+D8是当前线程的TIF_flags
92dd91cf test dword ptr [edi+0D8h],20000000h
//根据比较后选择跳转
92dd91d9 je win32k!ValidateHwnd+0x151 (92dd9211)
//ecx = 当前线程的ppi
92dd91db mov ecx,dword ptr [edi+0B8h]
//edx = 当前进程的pW32Job
92dd91e1 mov edx,dword ptr [ecx+170h]
//eax = 当前进程pW32JOB的restrictions
92dd91e7 mov eax,dword ptr [edx+0Ch]
//看第零位是否存在
92dd91ea and eax,1
//存在就返回
92dd91ed je win32k!ValidateHwnd+0x151 (92dd9211)
//eax是传入的句柄
92dd91ef mov eax,dword ptr [ebp-8]
//esi是句柄关联的对象
92dd91f2 push esi
92dd91f3 push eax
//调用IsHandleEntrySecure函数,这个函数是检测句柄的安全性,具体我也不分析了,有兴趣的人可以看看。
92dd91f4 call win32k!IsHandleEntrySecure (92e38dc2)
92dd91f9 test eax,eax
92dd91fb jne win32k!ValidateHwnd+0x151 (92dd9211)
92dd91fd push 578h
92dd9202 call win32k!UserSetLastError (92d9769d)
92dd9207 mov dword ptr [ebp-4],0
92dd920e mov ebx,dword ptr [ebp-4]
92dd9211 pop edi
92dd9212 pop esi
92dd9213 mov eax,ebx
92dd9215 pop ebx
92dd9216 mov esp,ebp
92dd9218 pop ebp
92dd9219 ret
92dd921a push 578h
92dd921f call win32k!UserSetLastError (92d9769d)
92dd9224 pop edi
92dd9225 pop esi
92dd9226 xor eax,eax
92dd9228 pop ebx
92dd9229 mov esp,ebp
92dd922b pop ebp
92dd922c ret
//ValidateHwnd这个函数无非检测句柄的合法性,通过各种判断然后确定传入的句柄是否有效。至于怎么判断的,汇编代码里面有详细的注释了。值得注意的是tagTHREADINFO是关于gui线程的一个数据结构,tagPROCESSINFO是关于gui进程的一个数据结构。然后遍历窗口句柄实际可以通过gSharedInfo全局结构来遍历,还能得到关于这个句柄对应的线程进程信息,和句柄所对应的句柄对象都可以。总之,这里面涉及的一些数据结构能掌握或者了解就相当不错了。
希望大家耐心看看,我不想在这里反汇编成c代码是因为提升效率。因为这个函数分析完成只是开始,后面还有更加多的内容在等待着我们。
我只起一个引导作用,接下来就看大家各自发挥吧......
ps:www.mengwuji.net