oxygen1a1 发表于 2022-11-12 10:00

Wow64调用全景分析以及ServiceTableHook

0x1 前言我们学过x64的系统调用,是非常简单的,直接syscall,找SSDT表,然后复制参数,调用就行了。
和x86架构基本是完全一样的。
但是Wow64是完全不一样的,他是要经过天堂之门的。 也就是jmp far 33:xx
0x2 WOW64调用分析流程0x2-1 x86下的OpenProcess的 NtOpenProcess比如我们随便下个OpenProcess断点,
首先他是kernel32中,在x64中,kernel32都不干事,直接是去kernelbase的OpenProcess
kernel32.OpenProcess->kernelbase.OpenProcess->ntdll.OpenProcess call edx(常量)->ntdll.Wow64Transtaion-> 天堂之门
77CA2D50NtOpenProcess   B8 26 00 00 00                         moveax,0x00000026                                    
77CA2D55                  BA 40 8B CB 77                         movedx,ntdll.77CB8B40                              
77CA2D5A                  FF D2                                  calledx                                             
77CA2D5C                  C2 10 00                               retn0x0010                                          


可以看到,他直接还是eax SSDT Index
然后call edx,这是win10下的,win7直接是call 三环fs:的地方
也就是_TEB32.
//0x1000 bytes (sizeof)
struct _TEB32
{
    struct _NT_TIB32 NtTib;                                                 //0x0
    ULONG EnvironmentPointer;                                             //0x1c
    struct _CLIENT_ID32 ClientId;                                           //0x20
    ULONG ActiveRpcHandle;                                                //0x28
    ULONG ThreadLocalStoragePointer;                                        //0x2c
    ULONG ProcessEnvironmentBlock;                                          //0x30
    ULONG LastErrorValue;                                                   //0x34
    ULONG CountOfOwnedCriticalSections;                                     //0x38
    ULONG CsrClientThread;                                                //0x3c
    ULONG Win32ThreadInfo;                                                //0x40
    ULONG User32Reserved;                                             //0x44
    ULONG UserReserved;                                                //0xac
    ULONG WOW32Reserved;                                                    //0xc0
    ULONG CurrentLocale;                                                    //0xc4
    ULONG FpSoftwareStatusRegister;                                       //0xc8
    ULONG ReservedForDebuggerInstrumentation;                           //0xcc
    ULONG SystemReserved1;                                              //0x10c
    CHAR PlaceholderCompatibilityMode;                                    //0x174
    UCHAR PlaceholderHydrationAlwaysExplicit;                               //0x175
    CHAR PlaceholderReserved;                                           //0x176
    ULONG ProxiedProcessId;                                                 //0x180
    struct _ACTIVATION_CONTEXT_STACK32 _ActivationStack;                  //0x184
    UCHAR WorkingOnBehalfTicket;                                       //0x19c
    LONG ExceptionCode;                                                   //0x1a4
    ULONG ActivationContextStackPointer;                                    //0x1a8
    ULONG InstrumentationCallbackSp;                                        //0x1ac
    ULONG InstrumentationCallbackPreviousPc;                              //0x1b0
    ULONG InstrumentationCallbackPreviousSp;                              //0x1b4
    UCHAR InstrumentationCallbackDisabled;                                  //0x1b8
    UCHAR SpareBytes;                                                   //0x1b9
    ULONG TxFsContext;                                                      //0x1d0
    struct _GDI_TEB_BATCH32 GdiTebBatch;                                    //0x1d4
    struct _CLIENT_ID32 RealClientId;                                       //0x6b4
    ULONG GdiCachedProcessHandle;                                           //0x6bc
    ULONG GdiClientPID;                                                   //0x6c0
    ULONG GdiClientTID;                                                   //0x6c4
    ULONG GdiThreadLocalInfo;                                             //0x6c8
    ULONG Win32ClientInfo;                                              //0x6cc
    ULONG glDispatchTable;                                             //0x7c4
    ULONG glReserved1;                                                //0xb68
    ULONG glReserved2;                                                      //0xbdc
    ULONG glSectionInfo;                                                    //0xbe0
    ULONG glSection;                                                      //0xbe4
    ULONG glTable;                                                          //0xbe8
    ULONG glCurrentRC;                                                      //0xbec
    ULONG glContext;                                                      //0xbf0
    ULONG LastStatusValue;                                                //0xbf4
    struct _STRING32 StaticUnicodeString;                                 //0xbf8
    WCHAR StaticUnicodeBuffer;                                       //0xc00
    ULONG DeallocationStack;                                                //0xe0c
    ULONG TlsSlots;                                                   //0xe10
    struct LIST_ENTRY32 TlsLinks;                                           //0xf10
    ULONG Vdm;                                                            //0xf18
    ULONG ReservedForNtRpc;                                                 //0xf1c
    ULONG DbgSsReserved;                                                 //0xf20
    ULONG HardErrorMode;                                                    //0xf28
    ULONG Instrumentation;                                             //0xf2c
    struct _GUID ActivityId;                                                //0xf50
    ULONG SubProcessTag;                                                    //0xf60
    ULONG PerflibData;                                                      //0xf64
    ULONG EtwTraceData;                                                   //0xf68
    ULONG WinSockData;                                                      //0xf6c
    ULONG GdiBatchCount;                                                    //0xf70
    union
    {
      struct _PROCESSOR_NUMBER CurrentIdealProcessor;                     //0xf74
      ULONG IdealProcessorValue;                                          //0xf74
      struct
      {
            UCHAR ReservedPad0;                                             //0xf74
            UCHAR ReservedPad1;                                             //0xf75
            UCHAR ReservedPad2;                                             //0xf76
            UCHAR IdealProcessor;                                           //0xf77
      };
    };
    ULONG GuaranteedStackBytes;                                             //0xf78
    ULONG ReservedForPerf;                                                //0xf7c
    ULONG ReservedForOle;                                                   //0xf80
    ULONG WaitingOnLoaderLock;                                              //0xf84
    ULONG SavedPriorityState;                                             //0xf88
    ULONG ReservedForCodeCoverage;                                          //0xf8c
    ULONG ThreadPoolData;                                                   //0xf90
    ULONG TlsExpansionSlots;                                                //0xf94
    ULONG MuiGeneration;                                                    //0xf98
    ULONG IsImpersonating;                                                //0xf9c
    ULONG NlsCache;                                                         //0xfa0
    ULONG pShimData;                                                      //0xfa4
    ULONG HeapData;                                                         //0xfa8
    ULONG CurrentTransactionHandle;                                       //0xfac
    ULONG ActiveFrame;                                                      //0xfb0
    ULONG FlsData;                                                          //0xfb4
    ULONG PreferredLanguages;                                             //0xfb8
    ULONG UserPrefLanguages;                                                //0xfbc
    ULONG MergedPrefLanguages;                                              //0xfc0
    ULONG MuiImpersonation;                                                 //0xfc4
    union
    {
      volatile USHORT CrossTebFlags;                                    //0xfc8
      USHORT SpareCrossTebBits:16;                                        //0xfc8
    };
    union
    {
      USHORT SameTebFlags;                                                //0xfca
      struct
      {
            USHORT SafeThunkCall:1;                                       //0xfca
            USHORT InDebugPrint:1;                                          //0xfca
            USHORT HasFiberData:1;                                          //0xfca
            USHORT SkipThreadAttach:1;                                    //0xfca
            USHORT WerInShipAssertCode:1;                                 //0xfca
            USHORT RanProcessInit:1;                                        //0xfca
            USHORT ClonedThread:1;                                          //0xfca
            USHORT SuppressDebugMsg:1;                                    //0xfca
            USHORT DisableUserStackWalk:1;                                  //0xfca
            USHORT RtlExceptionAttached:1;                                  //0xfca
            USHORT InitialThread:1;                                       //0xfca
            USHORT SessionAware:1;                                          //0xfca
            USHORT LoadOwner:1;                                             //0xfca
            USHORT LoaderWorker:1;                                          //0xfca
            USHORT SkipLoaderInit:1;                                        //0xfca
            USHORT SpareSameTebBits:1;                                    //0xfca
      };
    };
    ULONG TxnScopeEnterCallback;                                          //0xfcc
    ULONG TxnScopeExitCallback;                                             //0xfd0
    ULONG TxnScopeContext;                                                //0xfd4
    ULONG LockCount;                                                      //0xfd8
    LONG WowTebOffset;                                                      //0xfdc
    ULONG ResourceRetValue;                                                 //0xfe0
    ULONG ReservedForWdf;                                                   //0xfe4
    ULONGLONG ReservedForCrt;                                             //0xfe8
    struct _GUID EffectiveContainerId;                                    //0xff0
};
可以看到,他是Call的Wow32Reserved,这个里面本质就是放了个天堂之门的Call.
77C27000                  EA 09 70 C2 77 33 00                   jmp far0x0033 : 0x77C27009                           
77C27007                  00 00                                  addbyte ptr ds:,al                              
77C27009                  41                                     incecx                                             
77C2700A                  FF A7 F8 00 00 00                      jmpdword ptr ds:                     

我们打开Windbg查看gdt表
在这个里面,0x33作为段选择子,跨段跳转。
0x33==0y00110011
没切之前,CS==0x23==0y00100011
也就是一个的第4个,另一个是第6个

我们可以看到,第四个,明显不是64的段,因为他有段界限。第六个也是个代码段,这个时候一旦切换就处于64位模式下了。
这个就是所谓的天堂之门.
我们跳转之后,就到了Wow64Cpu.dll模块
实际上就是在这个函数的这个里面 也就是WOW64CPU.DLL的RunSimulatedCode
000000006B101660 RunSimulatedCode proc near            ; CODE XREF: BTCpuSimulate:loc_6B1011B4↑p
.text:000000006B101660                                       ; DATA XREF: .pdata:000000006B106084↓o
.text:000000006B101660
.text:000000006B101660 var_A8          = qword ptr -0A8h
.text:000000006B101660 var_A0          = word ptr -0A0h
.text:000000006B101660 var_98          = dword ptr -98h
.text:000000006B101660 var_90          = qword ptr -90h
.text:000000006B101660 var_88          = qword ptr -88h
.text:000000006B101660 var_80          = qword ptr -80h
.text:000000006B101660 var_78          = qword ptr -78h
.text:000000006B101660 var_70          = qword ptr -70h
.text:000000006B101660 var_68          = qword ptr -68h
.text:000000006B101660 var_60          = qword ptr -60h
.text:000000006B101660 var_58          = qword ptr -58h
.text:000000006B101660 var_50          = dword ptr -50h
.text:000000006B101660 var_48          = dword ptr -48h
.text:000000006B101660
.text:000000006B101660 ; __unwind { // CpupSimulateHandler
.text:000000006B101660               push    r15
.text:000000006B101662               push    r14
.text:000000006B101664               push    r13
.text:000000006B101666               push    r12
.text:000000006B101668               push    rbx
.text:000000006B101669               push    rsi
.text:000000006B10166A               push    rdi
.text:000000006B10166B               push    rbp
.text:000000006B10166C               sub   rsp, 68h
.text:000000006B101670               mov   r12, gs:30h
.text:000000006B101679               lea   r15, TurboThunkDispatch
.text:000000006B101680               mov   r13,
.text:000000006B101688               add   r13, 80h
.text:000000006B10168F
.text:000000006B10168F resume_common_reg:                      ; CODE XREF: RunSimulatedCode+167↓j
.text:000000006B10168F               btr   dword ptr , 0 ; 恢复通用非易失寄存器
.text:000000006B101695               jb      short resume_segment_reg
.text:000000006B101697               mov   edi,
.text:000000006B10169B               mov   esi,
.text:000000006B10169F               mov   ebx,
.text:000000006B1016A3               mov   ebp,
.text:000000006B1016A7               mov   eax,
.text:000000006B1016AB               mov   r14, rsp
.text:000000006B1016AE               mov   dword ptr , 23h
.text:000000006B1016B6               mov   r8d, 2Bh
.text:000000006B1016BC               mov   ss, r8d
.text:000000006B1016BF               mov   r9d,
.text:000000006B1016C3               mov   dword ptr , r9d
.text:000000006B1016C7               mov   esp,
.text:000000006B1016CB               jmp   fword ptr
.text:000000006B1016CE ; ---------------------------------------------------------------------------
.text:000000006B1016CE
.text:000000006B1016CE resume_segment_reg:                     ; CODE XREF: RunSimulatedCode+35↑j
.text:000000006B1016CE               mov   ecx, 2Bh
.text:000000006B1016D3               mov   ds, ecx
.text:000000006B1016D5               assume ds:nothing
.text:000000006B1016D5               mov   es, ecx
.text:000000006B1016D7               assume es:nothing
.text:000000006B1016D7               mov   gs, ecx
.text:000000006B1016D9               assume gs:nothing
.text:000000006B1016D9               test    byte ptr ds:7FFE028Ah, 0FFh
.text:000000006B1016E1               jnz   short loc_6B1016EE
.text:000000006B1016E3               mov   r8d, 53h
.text:000000006B1016E9               mov   fs, r8d
.text:000000006B1016EC               jmp   short hells_door ; "地狱之门" 构建iretq的返回数据
.text:000000006B1016EE ; ---------------------------------------------------------------------------
.text:000000006B1016EE
.text:000000006B1016EE loc_6B1016EE:                           ; CODE XREF: RunSimulatedCode+81↑j
.text:000000006B1016EE               mov   r8, gs:0
.text:000000006B1016F7               wrfsbase r8
.text:000000006B1016FC
.text:000000006B1016FC hells_door:                           ; CODE XREF: RunSimulatedCode+8C↑j
.text:000000006B1016FC               movapsxmm0, xmmword ptr ; "地狱之门" 构建iretq的返回数据
.text:000000006B101704               movapsxmm1, xmmword ptr
.text:000000006B10170C               movapsxmm2, xmmword ptr
.text:000000006B101714               movapsxmm3, xmmword ptr
.text:000000006B10171C               movapsxmm4, xmmword ptr
.text:000000006B101724               movapsxmm5, xmmword ptr
.text:000000006B10172C               mov   ecx,
.text:000000006B101730               mov   edx,
.text:000000006B101734               and   dword ptr , 0FFFFFFFFh
.text:000000006B101739               mov   edi,
.text:000000006B10173D               mov   esi,
.text:000000006B101741               mov   ebx,
.text:000000006B101745               mov   ebp,
.text:000000006B101749               mov   eax,
.text:000000006B10174D               mov   r14, rsp
.text:000000006B101750               mov   word ptr , 23h ; Cs
.text:000000006B101757               mov   word ptr , 2Bh ; SS
.text:000000006B10175E               mov   r8d,
.text:000000006B101762               and   dword ptr , 0FFFFFEFFh
.text:000000006B10176A               mov   , r8d; ELAGS
.text:000000006B10176F               mov   r8d,
.text:000000006B101773               mov   , r8   ; ESP
.text:000000006B101778               mov   r8d,
.text:000000006B10177C               mov   , r8       ; eip
.text:000000006B101780               iretq                   ; 构建iretq远调用返回
.text:000000006B101782 ; ---------------------------------------------------------------------------
.text:000000006B101782
.text:000000006B101782 CpupReturnFromSimulatedCode:            ; CODE XREF: KiFastSystemCall2+18↓j
.text:000000006B101782                                       ; DATA XREF: BTCpuResetToConsistentState+96↓o ...
.text:000000006B101782               xchg    rsp, r14      ; r14保存的是堆栈 交换x64 x86堆栈
.text:000000006B101785               mov   r8d,       ; 返回地址
.text:000000006B101788               add   r14, 4
.text:000000006B10178C               mov   , r8d; r13==TEB64的一个值 这个值里面保存这CONTEXT32环境
.text:000000006B10178C                                       ; 方便以后会x86跳转
.text:000000006B101790               mov   , r14d
.text:000000006B101794               lea   r11,     ; 可以看到 把x86的参数指针传过来了
.text:000000006B101798               mov   , edi
.text:000000006B10179C               mov   , esi; 保存其他非易失寄存器
.text:000000006B1017A0               mov   , ebx
.text:000000006B1017A4               mov   , ebp
.text:000000006B1017A8               pushfq                  ; 保存eflags
.text:000000006B1017A9               pop   r8
.text:000000006B1017AB               mov   , r8d
.text:000000006B1017AF ; Exported entry   9. TurboDispatchJumpAddressStart
.text:000000006B1017AF
.text:000000006B1017AF               public TurboDispatchJumpAddressStart
.text:000000006B1017AF TurboDispatchJumpAddressStart:          ; DATA XREF: .rdata:off_6B104798↓o
.text:000000006B1017AF               mov   ecx, eax
.text:000000006B1017B1               shr   ecx, 10h
.text:000000006B1017B4               jmp   qword ptr ; r15这个函数上面进行了初始化,是函数指针数组,rcx*8 跳转
.text:000000006B1017B8 ; ---------------------------------------------------------------------------
.text:000000006B1017B8 ; Exported entry   8. TurboDispatchJumpAddressEnd
.text:000000006B1017B8
.text:000000006B1017B8               public TurboDispatchJumpAddressEnd
.text:000000006B1017B8 TurboDispatchJumpAddressEnd:            ; CODE XREF: RunSimulatedCode+26B↓j
.text:000000006B1017B8                                       ; RunSimulatedCode+31B↓j
.text:000000006B1017B8                                       ; DATA XREF: ...
.text:000000006B1017B8               mov   ecx, eax      ; ecx==系统索引号
.text:000000006B1017BA               mov   rdx, r11      ; rdx==参数指针
.text:000000006B1017BD               call    cs:__imp_Wow64SystemServiceEx ; 这个是在WOW64中
.text:000000006B1017C3               mov   , eax
.text:000000006B1017C7               jmp   resume_common_reg ; 执行完返回
可以看到,他并不是跳到函数的头部,而是跳到CpuReturnFromSimulatedCode这个标号处。
然后这个地方保存了环境。调用了Wow64SystemServiceEx
这个是wow64.dll的函数。
我们用YzDbg动态跟踪
在这个里面,我们会发现,有一个真正指向ntdll.OpenProcess的地方

可以看到,这是真正的x64的OpenProcess,然后syscall,直接进入内核。
Wow其实就是给x86架构模拟执行用的,Wow64有很多dll,比如Wow64,Wow64Cpu,Wow64Win。
其实就是模拟x64下 x86的执行。这三个dll关系是
wow64Cpu是管派发的,因为系统调用有可能是在GDI SSDT也就是ShadowSSDT。
细节性的东西我们就不看了,总体来说就是模拟x86,然后转到真正的ntdll的系统调用,去syscall。
0x3 Wow64系统调用细节分析0x3-1 Wow64Cpu保存与恢复环境我们直接打开32位的ntdll的ZwOpenProcess来查看
; __stdcall ZwOpenProcess(x, x, x, x)
.text:4B2F2D50               public _ZwOpenProcess@16
.text:4B2F2D50 _ZwOpenProcess@16 proc near             ; CODE XREF: RtlQueryProcessDebugInformation(x,x,x)+129↓p
.text:4B2F2D50                                       ; RtlQueryProcessDebugInformation(x,x,x)+1D7↓p ...
.text:4B2F2D50               mov   eax, 26h      ; NtOpenProcess
.text:4B2F2D55               mov   edx, offset _Wow64SystemServiceCall@0 ; Wow64SystemServiceCall()
.text:4B2F2D5A               call    edx ; Wow64SystemServiceCall() ; Wow64SystemServiceCall()
.text:4B2F2D5C               retn    10h
.text:4B2F2D5C _ZwOpenProcess@16 endp
可以看到,直接call edx,这个edx是跳到了Wow64Transition
; _DWORD __stdcall Wow64SystemServiceCall()
_Wow64SystemServiceCall@0 proc near
jmp   ds:_Wow64Transition
_Wow64SystemServiceCall@0 endp
前面我们跟踪了,是位于Jmp的这个Wow64Transition就是天堂之门,因此我们在Wow64CPu中找到这个函数

我们可以看到,是位于Wow64Cpu的 KiFastSystemCall,这是个硬编码,但是不难看出确实是一样的。
然后他直接就跳转到了CpuReturnFromSimulatedCode哪里
在这个函数中,其实就是保存了各种寄存器,交换堆栈(x86->x64),然后调用
不过这个保存的寄存器位于(gs)TEB64.特定位置
位于WOW64.dll(非GDI系统调用)__imp_Wow64SystemServiceEx这个函数
.text:000000006B101782                                       ; DATA XREF: BTCpuResetToConsistentState+96↓o ...
.text:000000006B101782               xchg    rsp, r14      ; r14保存的是堆栈 交换x64 x86堆栈
.text:000000006B101785               mov   r8d,       ; 返回地址
.text:000000006B101788               add   r14, 4
.text:000000006B10178C               mov   , r8d; r13==TEB64的一个值 这个值里面保存这CONTEXT32环境
.text:000000006B10178C                                       ; 方便以后会x86跳转
.text:000000006B101790               mov   , r14d
.text:000000006B101794               lea   r11,     ; 可以看到 把x86的参数指针传过来了
.text:000000006B101798               mov   , edi
.text:000000006B10179C               mov   , esi; 保存其他非易失寄存器
.text:000000006B1017A0               mov   , ebx
.text:000000006B1017A4               mov   , ebp
.text:000000006B1017A8               pushfq                  ; 保存eflags
.text:000000006B1017A9               pop   r8
.text:000000006B1017AB               mov   , r8d
.text:000000006B1017AF ; Exported entry   9. TurboDispatchJumpAddressStart
.text:000000006B1017AF
.text:000000006B1017AF               public TurboDispatchJumpAddressStart
.text:000000006B1017AF TurboDispatchJumpAddressStart:          ; DATA XREF: .rdata:off_6B104798↓o
.text:000000006B1017AF               mov   ecx, eax
.text:000000006B1017B1               shr   ecx, 10h
.text:000000006B1017B4               jmp   qword ptr ; r15这个函数上面进行了初始化,是函数指针数组,rcx*8 跳转
.text:000000006B1017B8 ; ---------------------------------------------------------------------------
.text:000000006B1017B8 ; Exported entry   8. TurboDispatchJumpAddressEnd
.text:000000006B1017B8
.text:000000006B1017B8               public TurboDispatchJumpAddressEnd
.text:000000006B1017B8 TurboDispatchJumpAddressEnd:            ; CODE XREF: RunSimulatedCode+26B↓j
.text:000000006B1017B8                                       ; RunSimulatedCode+31B↓j
.text:000000006B1017B8                                       ; DATA XREF: ...
.text:000000006B1017B8               mov   ecx, eax      ; ecx==系统索引号
.text:000000006B1017BA               mov   rdx, r11      ; rdx==参数指针
.text:000000006B1017BD               call    cs:__imp_Wow64SystemServiceEx ; 这个是在WOW64中
.text:000000006B1017C3               mov   , eax
.text:000000006B1017C7               jmp   resume_common_reg ; 执行完返回
.text:000000006B1017C7 ; ---------------------------------------------------------------------------
.text:000000006B1017CC ThunkNone       db 0CCh               ; DATA XREF: .rdata:000000006B104760↓o

如上图,而我们可以看他是如何返回的,也就是下面那个Jmp 到resume_common_reg
在WOW64.Wow64SystemServiceEx执行完毕之后,开始根据之前保存的寄存器 回复环境
text:000000006B10168F               btr   dword ptr , 0 ; 恢复通用非易失寄存器
.text:000000006B101695               jb      short resume_segment_reg
.text:000000006B101697               mov   edi,
.text:000000006B10169B               mov   esi,
.text:000000006B10169F               mov   ebx,
.text:000000006B1016A3               mov   ebp,
.text:000000006B1016A7               mov   eax,
.text:000000006B1016AB               mov   r14, rsp
.text:000000006B1016AE               mov   dword ptr , 23h
.text:000000006B1016B6               mov   r8d, 2Bh
.text:000000006B1016BC               mov   ss, r8d
.text:000000006B1016BF               mov   r9d,
.text:000000006B1016C3               mov   dword ptr , r9d
.text:000000006B1016C7               mov   esp,
.text:000000006B1016CB               jmp   fword ptr
.text:000000006B1016CE ; ---------------------------------------------------------------------------
.text:000000006B1016CE
.text:000000006B1016CE resume_segment_reg:                     ; CODE XREF: RunSimulatedCode+35↑j
.text:000000006B1016CE               mov   ecx, 2Bh
.text:000000006B1016D3               mov   ds, ecx
.text:000000006B1016D5               assume ds:nothing
.text:000000006B1016D5               mov   es, ecx
.text:000000006B1016D7               assume es:nothing
.text:000000006B1016D7               mov   gs, ecx
.text:000000006B1016D9               assume gs:nothing
.text:000000006B1016D9               test    byte ptr ds:7FFE028Ah, 0FFh
.text:000000006B1016E1               jnz   short loc_6B1016EE
.text:000000006B1016E3               mov   r8d, 53h
.text:000000006B1016E9               mov   fs, r8d
.text:000000006B1016EC               jmp   short hells_door ; "地狱之门" 构建iretq的返回数据
.
0x3-1-1 地狱之门的iretq返回值得一提的是,wow64返回的时候,是构造iretq的返回堆栈来进行"地狱之门的返回的"
.text:000000006B1016FC               movapsxmm0, xmmword ptr ; "地狱之门" 构建iretq的返回数据
.text:000000006B101704               movapsxmm1, xmmword ptr
.text:000000006B10170C               movapsxmm2, xmmword ptr
.text:000000006B101714               movapsxmm3, xmmword ptr
.text:000000006B10171C               movapsxmm4, xmmword ptr
.text:000000006B101724               movapsxmm5, xmmword ptr
.text:000000006B10172C               mov   ecx,
.text:000000006B101730               mov   edx,
.text:000000006B101734               and   dword ptr , 0FFFFFFFFh
.text:000000006B101739               mov   edi,
.text:000000006B10173D               mov   esi,
.text:000000006B101741               mov   ebx,
.text:000000006B101745               mov   ebp,
.text:000000006B101749               mov   eax,
.text:000000006B10174D               mov   r14, rsp
.text:000000006B101750               mov   word ptr , 23h ; Cs
.text:000000006B101757               mov   word ptr , 2Bh ; SS
.text:000000006B10175E               mov   r8d,
.text:000000006B101762               and   dword ptr , 0FFFFFEFFh
.text:000000006B10176A               mov   , r8d; ELAGS
.text:000000006B10176F               mov   r8d,
.text:000000006B101773               mov   , r8   ; ESP
.text:000000006B101778               mov   r8d,
.text:000000006B10177C               mov   , r8       ; eip
.text:000000006B101780               iretq                   ; 构建iretq远调用返回

0x3-2 Wow64.Wow64SystemServiceEx自此,一个WOW64CPU.dll调用的流程就分析完了,但是如果真的想要了解到底是怎么根据调用号,最终找到的函数(ntdllx64里面的),毫无疑问,我们需要去逆向以下这个函数
总的来说,这个函数也是很简单,他的作用就有一个,根据WOW64专属的ServiceTable,找到要中转的函数(这个函数里面在进行参数整合之后,最后会调用x64ntdll真正的处理函数)。
.text:0000000180008EC0 ; __unwind { // __GSHandlerCheck_SEH
.text:0000000180008EC0               mov   , rbx
.text:0000000180008EC5               push    rsi             ; 进入这个函数之前,rcx==sysindex,rdx==参数列表
.text:0000000180008EC6               push    rdi
.text:0000000180008EC7               push    r14
.text:0000000180008EC9               sub   rsp, 8A0h
.text:0000000180008ED0               mov   rax, cs:__security_cookie ; 堆栈检查
.text:0000000180008ED7               xor   rax, rsp
.text:0000000180008EDA               mov   , rax
.text:0000000180008EE2               mov   r14, rdx
.text:0000000180008EE5               mov   edx, ecx
.text:0000000180008EE7               mov   rax, gs:30h
.text:0000000180008EF0               mov   rcx,
.text:0000000180008EF7               mov   , rcx
.text:0000000180008EFC               xor   edi, edi
.text:0000000180008EFE               mov   , edi
.text:0000000180008F02               mov   rax, gs:30h
.text:0000000180008F0B               lea   rcx,
.text:0000000180008F10               mov   , rcx
.text:0000000180008F17               mov   r8d, edx
.text:0000000180008F1A               shr   r8d, 0Ch
.text:0000000180008F1E               and   r8d, 3
.text:0000000180008F22               and   edx, 0FFFh
.text:0000000180008F28               lea   r9,
.text:0000000180008F2C               add   r9, r9          ; (index>>12 & 3)*6 ServiceTable是6*Stride的大小,Stride==8
.text:0000000180008F2C                                       ; 下面会看到,所以ServiceTable的大小是48 0x30
.text:0000000180008F2F               lea   r10, ServiceTables ; 找到ServiceTable
.text:0000000180008F36               cmp   edx,
.text:0000000180008F3B               ja      loc_18001CED2   ; 比较是否越界
.

而他是这样找到代理函数的
text:0000000180008FB1               mov   rax, ; 找到函数表
.text:0000000180008FB5               mov   rsi, ; 根据sysindex直接找到代理函数
.text:0000000180008FB9               mov   , r8d
.text:0000000180008FBE               mov   , edx


也就是sysindex*8+ServiceTable.FuncTable
0x3-2-1 Wow64.ServiceTable以及其应用我们可以看到,他直接根据ServiceTable找到一个函数,然后调用,为此,我们必须去看看ServiceTable究竟保存了什么。(表太长,没用截全)
.rdata:000000018003A640 sdwhnt32JumpTable dq offset whNtAccessCheck
.rdata:000000018003A648               dq offset whNtWorkerFactoryWorkerReady
.rdata:000000018003A650               dq offset whNtAcceptConnectPort
.rdata:000000018003A658               dq offset whNtMapUserPhysicalPagesScatter
.rdata:000000018003A660               dq offset whNtWaitForSingleObject
.rdata:000000018003A668               dq offset whNtCallbackReturn
.rdata:000000018003A670               dq offset whNtReadFile
.rdata:000000018003A678               dq offset whNtDeviceIoControlFile
.rdata:000000018003A680               dq offset whNtWriteFile
.rdata:000000018003A688               dq offset whNtRemoveIoCompletion
.rdata:000000018003A690               dq offset whNtReleaseSemaphore
.rdata:000000018003A698               dq offset whNtReplyWaitReceivePort
.rdata:000000018003A6A0               dq offset whNtReplyPort
.rdata:000000018003A6A8               dq offset whNtSetInformationThread
.rdata:000000018003A6B0               dq offset whNtSetEvent
.rdata:000000018003A6B8               dq offset whNtClose
.rdata:000000018003A6C0               dq offset whNtQueryObject
.rdata:000000018003A6C8               dq offset whNtQueryInformationFile
.rdata:000000018003A6D0               dq offset whNtOpenKey
.rdata:000000018003A6D8               dq offset whNtEnumerateValueKey
.rdata:000000018003A6E0               dq offset whNtFindAtom
.rdata:000000018003A6E8               dq offset whNtQueryDefaultLocale
.rdata:000000018003A6F0               dq offset whNtQueryKey
.rdata:000000018003A6F8               dq offset whNtQueryValueKey
.rdata:000000018003A700               dq offset whNtAllocateVirtualMemory
.rdata:000000018003A708               dq offset whNtQueryInformationProcess
.rdata:000000018003A710               dq offset whNtWaitForMultipleObjects
.rdata:000000018003A718               dq offset whNtWriteFileGather
.rdata:000000018003A720               dq offset whNtSetInformationProcess
.rdata:000000018003A728               dq offset whNtCreateKey
.rdata:000000018003A730               dq offset whNtFreeVirtualMemory
.rdata:000000018003A738               dq offset

其实ServiceTable的第一个成员就是这个表(刚刚逆向中有体会),这个就是sdwhnt32JumpTable,因此我们只需要Hook这个地方,就可以达到R3层最隐蔽的Hook,而这个函数其实是个代理函数,他的作用是中转。
他会把x86传进来的参数指针转换成x64系统调用的形式,比如我们随便点进去看看。
mov   r8,
.text:0000000180010948               mov   edx, r14d
.text:000000018001094B               mov   rcx, rdi
.text:000000018001094E               call    cs:__imp_NtOpenProcess ; 直接调用x64ntdll的OpenProcess
.text:0000000180010955               nop   dword ptr
.text:000000018001095A               test    esi, esi
0x4 替换ServiceTable达到对32位程序最隐蔽的ApiHook经过前面的分析,我们可以知道,Wow64(32位)进程所有的API或者说是系统调用,都是要经过ServiceTable的。
常规的API Hook一般是Hook Api函数本身,在头部用E9 或者FF 25进行Jmp,从而达到拦截过滤的效果。
这种方法虽然简单,但是缺点也很明显,容易被检测,而且不会拦截到更深层次的调用。
比如我调用MessageBoxA,直接Hook,拦截不到直接调用MessageBoxTimeOutA,但是程序最终执行的结果是一样的。
如果是通过替换ServiceTable来进行Hook的话,可以这样说,只要不是Shellcode+sysindex+syscall+heavendoor的方式进行调用,x86进程调用任何api都是可以被我们拦截的。
这种替换函数表的形式非常像SSDT Hook,区别是SSDT Hook会PG,全局,而且不限程序架构是x64还是x86。
比如下面我用一个最简单的替换ServiceTable的Hook进行示范
Hook的函数是OpenProcess,hook方式是向32位进程注入64位Dll
因为是最简单的,所以ServiceTable是直接通过偏移拿到的,因此不通用。仅作演示
我用到了开源的Wow64Ext来获取那4个Wow64Dll
void __declspec(naked) HkOpenProcess() {


    //_rcx = 0;


   


    __asm {
      

      __emit 0x51 //push rcx
      __emit 0x56 //push rsi
      __emit 0x57 //push rdi
      __emit 0x53 //push rbx
      __emit 0x52 //push rdx
      __emit 0x54 //push rsp
      __emit 0x55 //push rbp

    }

    HellDoor();


    //修改参数 降权
    __asm {
      xor eax,eax
      mov , eax

    }

    HeavenDoor();
   
        __asm {
      __emit 0x5d //pop rbp
      __emit 0x5c //pop rsp
      __emit 0x5a //pop rdx
      __emit 0x5b
                __emit 0x5f
                __emit 0x5e
                __emit 0x59

   
    }




    __asm {

      __emit 0x48
      mov eax, //mov rax,&target
      __emit 0x0
      __emit 0x0
      __emit 0x0
      __emit 0x0
      
      __emit 0x48       //mov rax,
      __emit 0x8b
      __emit 0x00

      __emit 0xff //jmp rax
      __emit 0xe0

    }
}
上面函数的作用是降低打开进程的权限为0
我们只需要替换上面的函数到ServiceTable对应的值即可,我们来看Hook降权前后对比

正常OpenProcess,可以读成功,Hook之后





最后,ServiceTableHook是半成品,不过开下源吧,可以自己找下ServiceTable 我是直接根据偏移获取的

**** Hidden Message *****


参考:
1.火哥内核视频
2.https://www.anquanke.com/post/id/222243
3.https://www.dazhuanlan.com/vctzdb/topics/975681

咖啡茶 发表于 2022-11-12 13:21

{:5_117:}学习一下

WolfKing 发表于 2022-11-12 13:58

支持一下师兄的教程,辛苦了,一起加油

lies 发表于 2022-11-12 21:09

谢谢分享!

温九 发表于 2022-11-12 23:45

看下隐藏内容~~

ffirefoxABC 发表于 2022-11-13 07:43

谢谢分享!!!!!!!!!!!!!

acaidipan 发表于 2022-11-13 09:30

学习下,谢谢分享

459121520 发表于 2022-11-13 10:42

号高深的样子,整不动

Cerolluo 发表于 2022-11-21 20:10

感谢楼主,支持一下!

别管我了行 发表于 2022-11-23 17:40

页: [1] 2
查看完整版本: Wow64调用全景分析以及ServiceTableHook