• 一个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

  • 相关阅读:
    转:testlink 环境搭建(傻瓜版)
    转最简便安装python+selenium-webdriver环境方法
    转发 python中file和open有什么区别
    一面cvte
    org.apache.hadoop.security.AccessControlException: Permission denied:
    让hadoop-0.20.2自带的eclipse插件支持eclipse-3.5以上
    在VMWare中建立Hadoop虚拟集群的详细步骤(使用CentOS)
    第一天
    执行insmod提示invalidmodule format
    Linux Kernel中函数命名
  • 原文地址:https://www.cnblogs.com/kkindof/p/3193789.html
Copyright © 2020-2023  润新知