一个APC引起的折腾 之题外记

本篇blog的内核可能会杂乱无章,未成年禁止观看:)

一。首先对于内核插32bit user apc的情况,内核有一个导出但undoucmented的函数来处理的,如下:

nt!PsWrapApcWow64Thread:
fffff800`0291b020 65488b042588010000 mov rax,qword ptr gs:[188h]
fffff800`0291b029 488b4870 mov rcx,qword ptr [rax+70h]
fffff800`0291b02d 4883b92003000000 cmp qword ptr [rcx+320h],0
fffff800`0291b035 740d je nt!PsWrapApcWow64Thread+0x24 (fffff800`0291b044)

nt!PsWrapApcWow64Thread+0x17:
fffff800`0291b037 488b02 mov rax,qword ptr [rdx]
fffff800`0291b03a 48f7d8 neg rax
fffff800`0291b03d 48c1e002 shl rax,2
fffff800`0291b041 488902 mov qword ptr [rdx],rax

nt!PsWrapApcWow64Thread+0x24:
fffff800`0291b044 33c0 xor eax,eax
fffff800`0291b046 c3 ret

二。windbg查看查wow64栈

user mode或者内核调试中回到user mode的wow64环境中时,
无论在什么环境下,都可以试下下面2个命令查看堆栈
!wow64exts.k和.effmach x86

ps: .effmach . 可以回到x64栈环境


如下,此时在wow64环境
kd> k
Child-SP RetAddr Call Site
00000000`0009dfd0 00000000`7476cf87 wow64!whNtCreateFile+0x10f
00000000`0009e0a0 00000000`746f276d wow64!Wow64SystemServiceEx+0xd7
00000000`0009e960 00000000`7476d07e wow64cpu!ServiceNoTurbo+0x24
00000000`0009ea20 00000000`7476c549 wow64!RunCpuSimulation+0xa
00000000`0009ea70 00000000`770e84c8 wow64!Wow64LdrpInitialize+0x429
00000000`0009efc0 00000000`770e7623 ntdll!LdrpInitializeProcess+0x17e2
00000000`0009f4c0 00000000`770d308e ntdll! ?? ::FNODOBFM::`string'+0x2bea0
00000000`0009f530 00000000`00000000 ntdll!LdrInitializeThunk+0xe
kd> .effmach x86 //临时切换
Effective machine: x86 compatible (x86)
kd:x86> k //好像时栈显示x86的栈
ChildEBP RetAddr
001af500 7536b616 ntdll_77280000!ZwCreateFile+0x12
001af5a4 76b92345 KERNELBASE!CreateFileW+0x35e
001af5d0 00ef243b kernel32!CreateFileWImplementation+0x69
WARNING: Stack unwind information not available. Following frames may be wrong.
001af830 00ef5fff HipsTool+0x243b
001af840 00ef620e HipsTool+0x5fff
001af870 00ef57d5 HipsTool+0x620e
001af894 00efc07d HipsTool+0x57d5
001af8e4 00efc917 HipsTool+0xc07d

kd:x86> .effmach .//回到X64
Effective machine: x64 (AMD64)
kd> k //又回到wow64了
Child-SP RetAddr Call Site
00000000`0009dfd0 00000000`7476cf87 wow64!whNtCreateFile+0x10f
00000000`0009e0a0 00000000`746f276d wow64!Wow64SystemServiceEx+0xd7
00000000`0009e960 00000000`7476d07e wow64cpu!ServiceNoTurbo+0x24
00000000`0009ea20 00000000`7476c549 wow64!RunCpuSimulation+0xa
00000000`0009ea70 00000000`770e84c8 wow64!Wow64LdrpInitialize+0x429
00000000`0009efc0 00000000`770e7623 ntdll!LdrpInitializeProcess+0x17e2
00000000`0009f4c0 00000000`770d308e ntdll! ?? ::FNODOBFM::`string'+0x2bea0
00000000`0009f530 00000000`00000000 ntdll!LdrInitializeThunk+0xe

三。在wow64中查找x86的栈ESP

xxpointer = teb.TlsSlots[instruction_info_index];
xxpointer+0C8h=esp

kd> dt ntdll!_teb 000000007efd5000 TlsSlots.
+0x1480 TlsSlots : [64] //每个元素8字节

#define instruction_info_index 1


上面数值的找法如下
wow64cpu!CpuSetInstructionPointer:
00000000`746f1a04 65488b042530000000 mov rax,qword ptr gs:[30h]
00000000`746f1a0d 488b9088140000 mov rdx,qword ptr [rax+1488h] //TEB-0X1488偏移值
00000000`746f1a14 898abc000000 mov dword ptr [rdx+0BCh],ecx

0033:00000000`746f271e 67448b0424 mov r8d,dword ptr [esp]
0033:00000000`746f2723 458985bc000000 mov dword ptr [r13+0BCh],r8d
0033:00000000`746f272a 4189a5c8000000 mov dword ptr [r13+0C8h],esp //x86的ESP存在在这里,+c8处,r13就是上面的1488偏移的值

要是常规的push ebp开头函数,一定程度上,可以手工还原栈,因为我们知道这种情况下,返回地址和上级函数的ebp存放是相邻的,如[esp]=ret ip,[esp-4]=ebp

如上面的
kd:x86> k //好像时栈显示x86的栈
ChildEBP RetAddr
001af500 7536b616 ntdll_77280000!ZwCreateFile+0x12
001af5a4 76b92345 KERNELBASE!CreateFileW+0x35e
001af5d0 00ef243b kernel32!CreateFileWImplementation+0x69
WARNING: Stack unwind information not available. Following frames may be wrong.
001af830 00ef5fff HipsTool+0x243b
001af840 00ef620e HipsTool+0x5fff
001af870 00ef57d5 HipsTool+0x620e
001af894 00efc07d HipsTool+0x57d5
001af8e4 00efc917 HipsTool+0xc07d

通过上面方法,可以知道ESP为001af500

kd> dds 001af500
00000000`001af500 772a0066 ntdll_77280000!ZwCreateFile+0x12
00000000`001af504 7536b616 KERNELBASE!CreateFileW+0x35e
00000000`001af508 001af59c
00000000`001af50c c0100080
00000000`001af510 001af540
00000000`001af514 001af584
00000000`001af518 00000000
00000000`001af51c 00000000
00000000`001af520 00000003
00000000`001af524 00000001
00000000`001af528 00000060
00000000`001af52c 00000000
00000000`001af530 00000000
00000000`001af534 00000111
00000000`001af538 00f2a7b8 HipsTool+0x3a7b8
00000000`001af53c 00000001
00000000`001af540 00000018
00000000`001af544 00000000
00000000`001af548 001af57c
00000000`001af54c 00000040
00000000`001af550 00000000
00000000`001af554 001af568
00000000`001af558 00000000
00000000`001af55c 00000000
00000000`001af560 00000000
00000000`001af564 00000000
00000000`001af568 0000000c
00000000`001af56c 00000002
00000000`001af570 001a0101
00000000`001af574 76b923ed kernel32!BaseIsThisAConsoleName+0xc9
00000000`001af578 001af594
00000000`001af57c 021a0014
kd> dds
00000000`001af580 0062d630
00000000`001af584 dc9296c3
00000000`001af588 00000111
00000000`001af58c 00f2a7b8 HipsTool+0x3a7b8
00000000`001af590 00000000
00000000`001af594 0062d630
00000000`001af598 00000000
00000000`001af59c 00000000
00000000`001af5a0 00000001
00000000`001af5a4 001af5d0
00000000`001af5a8 76b92345 kernel32!CreateFileWImplementation+0x69 //这个才是合法地址,因为上面00000000`001af5a4存在的是EBP,里面的值和当前的栈值很相近

kd> dds 001af5d0 l5
00000000`001af5d0 001af830
00000000`001af5d4 00ef243b HipsTool+0x243b //上层返回地址,确实在上面k命令输出的列表中
00000000`001af5d8 00f29e68 HipsTool+0x39e68
00000000`001af5dc c0000000
00000000`001af5e0 00000003
kd> dds 001af830 l5
00000000`001af830 001af840
00000000`001af834 00ef5fff HipsTool+0x5fff// 上层返回地址,确实在上面k命令输出的列表中
00000000`001af838 00f2a7b8 HipsTool+0x3a7b8
00000000`001af83c 001afe28
00000000`001af840 001af870

其它的省略不找了

 


四。内核调试中使用teb命令
kd> !teb
Wow64 TEB32 at 000000007efd7000
ExceptionList: 0000000002c3ff70
StackBase: 0000000002c40000
StackLimit: 0000000002c3f000
SubSystemTib: 0000000000000000
FiberData: 0000000000001e00
ArbitraryUserPointer: 0000000000000000
Self: 000000007efd7000
EnvironmentPointer: 0000000000000000
ClientId: 0000000000000b88 . 00000000000006e4
RpcHandle: 0000000000000000
Tls Storage: 000000007efd702c
PEB Address: 000000007efde000
LastErrorValue: 0
LastStatusValue: c000000d
Count Owned Locks: 0
HardErrorMode: 0


Wow64 TEB at 000000007efd5000
ExceptionList: 000000007efd7000
StackBase: 0000000001f1fd20
StackLimit: 0000000001f1c000
SubSystemTib: 0000000000000000
FiberData: 0000000000001e00
ArbitraryUserPointer: 0000000000000000
Self: 000000007efd5000
EnvironmentPointer: 0000000000000000
ClientId: 0000000000000b88 . 00000000000006e4
RpcHandle: 0000000000000000
Tls Storage: 0000000000000000
PEB Address: 000000007efdf000
LastErrorValue: 0
LastStatusValue: 0
Count Owned Locks: 0
HardErrorMode: 0

此时显示2个TEB,上面的是x86的teb,下面的是wow64的teb,2者目前是相距0x2000,所以知道其一,也可得另一个

kd> dt ntdll!_teb 000000007efd5000 ClientId.
+0x040 ClientId :
+0x000 UniqueProcess : 0x00000000`00000b88 Void
+0x008 UniqueThread : 0x00000000`000006e4 Void

kd> dt ntdll_77280000!_teb 000000007efd7000 ClientId.
+0x020 ClientId :
+0x000 UniqueProcess : 0x00000000`00000b88 Void
+0x004 UniqueThread : 0x00000000`000006e4 Void

由于这wow64的teb和x86的TEB结构体不同(ClientId成员偏移不一样),所以可以用上面命令验证上面的说法

 

五。wow64怎么知道当前异常是wow64环境触发还是32bit

raymond的文章<WoW进程的异常分发过程>提到过,在异常分发时,Wow64PrepareForException会调用CpuResetToConsistentState ,下面是CpuResetToConsistentState 的部分代码

wow64!CpuResetToConsistentState (00000000`7478e084)

{
mov rdi,rcx
mov rdx,qword ptr [rdi+8]
cmp word ptr [rdx+38h],23h //在wow64里面本身发生异常的时候+38处偏移为33,就会跳走,所以可以看得出wow64还是能分得出是的什么环境下发生的异常的
jne wow64cpu!CpuResetToConsistentState+0x102 (00000000`746f18ba)
}

 

六.一种特殊情况

我们知道在closehandle时,有一种情况内核会抛出异常,0C0000235h(STATUS_HANDLE_NOT_CLOSABLE),在32bit调用closehandle时,肯定会经过wow64才会进入内核,那这时候就会产生一种有趣的情况了,32bit进程触发一个异常,但这个异常的触发点是wow64(选择子为33),栈自然也会是wow64的栈,ntdll64的kiuserexceptiondispatch的其中一个SEH filter函数会JMP到如下的位置 

kd> uf 0033:00000000`7478ea02
wow64!Wow64pLongJmp+0x682:
00000000`7478ea02 4055 push rbp
00000000`7478ea04 4883ec20 sub rsp,20h
00000000`7478ea08 488bea mov rbp,rdx
00000000`7478ea0b 48894d60 mov qword ptr [rbp+60h],rcx
00000000`7478ea0f 48894d28 mov qword ptr [rbp+28h],rcx
00000000`7478ea13 488b4528 mov rax,qword ptr [rbp+28h]
00000000`7478ea17 488b08 mov rcx,qword ptr [rax]
00000000`7478ea1a 448b01 mov r8d,dword ptr [rcx]
00000000`7478ea1d 488d159c62fdff lea rdx,[wow64!`string' (00000000`74764cc0)]
00000000`7478ea24 b902000000 mov ecx,2
00000000`7478ea29 e8cea2fdff call wow64!Wow64LogPrint (00000000`74768cfc)
00000000`7478ea2e 4c8b5d28 mov r11,qword ptr [rbp+28h]
00000000`7478ea32 498b03 mov rax,qword ptr [r11]
00000000`7478ea35 813803000080 cmp dword ptr [rax],80000003h //STATUS_BREAKPOINT
00000000`7478ea3b 7410 je wow64!Wow64pLongJmp+0x6cd (00000000`7478ea4d)

wow64!Wow64pLongJmp+0x6bd:
00000000`7478ea3d 8138080000c0 cmp dword ptr [rax],0C0000008h//STATUS_INVALID_HANDLE
00000000`7478ea43 7408 je wow64!Wow64pLongJmp+0x6cd (00000000`7478ea4d)

wow64!Wow64pLongJmp+0x6c5:
00000000`7478ea45 8138350200c0 cmp dword ptr [rax],0C0000235h//STATUS_HANDLE_NOT_CLOSABLE
00000000`7478ea4b 7509 jne wow64!Wow64pLongJmp+0x6d6 (00000000`7478ea56)

wow64!Wow64pLongJmp+0x6cd:
00000000`7478ea4d 488b4d28 mov rcx,qword ptr [rbp+28h]
00000000`7478ea51 e84adefdff call wow64!Pass64bitExceptionTo32Bit (00000000`7476c8a0)//

wow64!Wow64pLongJmp+0x6d6:
00000000`7478ea56 b801000000 mov eax,1
00000000`7478ea5b 4883c420 add rsp,20h
00000000`7478ea5f 5d pop rbp
00000000`7478ea60 c3 ret

可以发现,如果异常为STATUS_HANDLE_NOT_CLOSABLE的话,也会调用Pass64bitExceptionTo32Bit ,进行32bit环境的建立,可以看出,wow64是兼容这种情况的,在这种异常触发时,异常能回到32bit触发异常的位置

=================================
而当是23选择子发生异常时,会JMP到这来,可以看到无条件调用Pass64bitExceptionTo32Bit
kd> uf wow64!Wow64pLongJmp+0x652
wow64!Wow64pLongJmp+0x652:
00000000`7478e9d2 4055 push rbp
00000000`7478e9d4 4883ec20 sub rsp,20h
00000000`7478e9d8 488bea mov rbp,rdx
00000000`7478e9db 48894d30 mov qword ptr [rbp+30h],rcx
00000000`7478e9df 48894d28 mov qword ptr [rbp+28h],rcx

00000000`7478e9e3 488b4d28 mov rcx,qword ptr [rbp+28h]
00000000`7478e9e7 e8b4defdff call wow64!Pass64bitExceptionTo32Bit (00000000`7476c8a0)
00000000`7478e9ec c7452001000000 mov dword ptr [rbp+20h],1
00000000`7478e9f3 8b4520 mov eax,dword ptr [rbp+20h]
00000000`7478e9f6 4883c420 add rsp,20h
00000000`7478e9fa 5d pop rbp
00000000`7478e9fb c3 ret

 

posted @ 2013-07-16 17:22  kkindof  阅读(2080)  评论(0编辑  收藏  举报