吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6675|回复: 39
收起左侧

[系统底层] Wow64系统调用分析以及ServiceTableHook

  [复制链接]
oxygen1a1 发表于 2022-11-12 10:10
本帖最后由 oxygen1a1 于 2022-11-15 16:19 编辑

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-> 天堂之门
[Asm] 纯文本查看 复制代码
77CA2D50  NtOpenProcess   B8 26 00 00 00                         mov  eax,0x00000026                                    
77CA2D55                  BA 40 8B CB 77                         mov  edx,ntdll.77CB8B40                                
77CA2D5A                  FF D2                                  call  edx                                             
77CA2D5C                  C2 10 00                               retn  0x0010                                          


可以看到,他直接还是eax SSDT Index
然后call edx,这是win10下的,win7直接是call 三环fs:[0xC0]的地方
也就是_TEB32.
//0x1000 bytes (sizeof)
[Asm] 纯文本查看 复制代码
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[26];                                               //0x44
    ULONG UserReserved[5];                                                  //0xac
    ULONG WOW32Reserved;                                                    //0xc0
    ULONG CurrentLocale;                                                    //0xc4
    ULONG FpSoftwareStatusRegister;                                         //0xc8
    ULONG ReservedForDebuggerInstrumentation[16];                           //0xcc
    ULONG SystemReserved1[26];                                              //0x10c
    CHAR PlaceholderCompatibilityMode;                                      //0x174
    UCHAR PlaceholderHydrationAlwaysExplicit;                               //0x175
    CHAR PlaceholderReserved[10];                                           //0x176
    ULONG ProxiedProcessId;                                                 //0x180
    struct _ACTIVATION_CONTEXT_STACK32 _ActivationStack;                    //0x184
    UCHAR WorkingOnBehalfTicket[8];                                         //0x19c
    LONG ExceptionCode;                                                     //0x1a4
    ULONG ActivationContextStackPointer;                                    //0x1a8
    ULONG InstrumentationCallbackSp;                                        //0x1ac
    ULONG InstrumentationCallbackPreviousPc;                                //0x1b0
    ULONG InstrumentationCallbackPreviousSp;                                //0x1b4
    UCHAR InstrumentationCallbackDisabled;                                  //0x1b8
    UCHAR SpareBytes[23];                                                   //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[62];                                              //0x6cc
    ULONG glDispatchTable[233];                                             //0x7c4
    ULONG glReserved1[29];                                                  //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[261];                                         //0xc00
    ULONG DeallocationStack;                                                //0xe0c
    ULONG TlsSlots[64];                                                     //0xe10
    struct LIST_ENTRY32 TlsLinks;                                           //0xf10
    ULONG Vdm;                                                              //0xf18
    ULONG ReservedForNtRpc;                                                 //0xf1c
    ULONG DbgSsReserved[2];                                                 //0xf20
    ULONG HardErrorMode;                                                    //0xf28
    ULONG Instrumentation[9];                                               //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 far  0x0033 : 0x77C27009                           
77C27007                  00 00                                  add  byte ptr ds:[eax],al                              
77C27009                  41                                     inc  ecx                                               
77C2700A                  FF A7 F8 00 00 00                      jmp  dword ptr ds:[edi+0x000000F8]                     
[/mw_shl_code]
我们打开Windbg查看gdt表
在这个里面,0x33作为段选择子,跨段跳转。
0x33==0y00110011
没切之前,CS==0x23==0y00100011
也就是一个的第4个,另一个是第6个
image.png
我们可以看到,第四个,明显不是64的段,因为他有段界限。第六个也是个代码段,这个时候一旦切换就处于64位模式下了。
这个就是所谓的天堂之门.
我们跳转之后,就到了Wow64Cpu.dll模块
实际上就是在这个函数的这个里面 也就是WOW64CPU.DLL的RunSimulatedCode
[Asm] 纯文本查看 复制代码
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, [r12+1488h]
.text:000000006B101688                 add     r13, 80h
.text:000000006B10168F
.text:000000006B10168F resume_common_reg:                      ; CODE XREF: RunSimulatedCode+167↓j
.text:000000006B10168F                 btr     dword ptr [r13-80h], 0 ; 恢复通用非易失寄存器
.text:000000006B101695                 jb      short resume_segment_reg
.text:000000006B101697                 mov     edi, [r13+20h]
.text:000000006B10169B                 mov     esi, [r13+24h]
.text:000000006B10169F                 mov     ebx, [r13+28h]
.text:000000006B1016A3                 mov     ebp, [r13+38h]
.text:000000006B1016A7                 mov     eax, [r13+34h]
.text:000000006B1016AB                 mov     r14, rsp
.text:000000006B1016AE                 mov     dword ptr [rsp+0A8h+var_A8+4], 23h
.text:000000006B1016B6                 mov     r8d, 2Bh
.text:000000006B1016BC                 mov     ss, r8d
.text:000000006B1016BF                 mov     r9d, [r13+3Ch]
.text:000000006B1016C3                 mov     dword ptr [rsp+0A8h+var_A8], r9d
.text:000000006B1016C7                 mov     esp, [r13+48h]
.text:000000006B1016CB                 jmp     fword ptr [r14]
.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                 movaps  xmm0, xmmword ptr [r13+0F0h] ; "地狱之门" 构建iretq的返回数据
.text:000000006B101704                 movaps  xmm1, xmmword ptr [r13+100h]
.text:000000006B10170C                 movaps  xmm2, xmmword ptr [r13+110h]
.text:000000006B101714                 movaps  xmm3, xmmword ptr [r13+120h]
.text:000000006B10171C                 movaps  xmm4, xmmword ptr [r13+130h]
.text:000000006B101724                 movaps  xmm5, xmmword ptr [r13+140h]
.text:000000006B10172C                 mov     ecx, [r13+30h]
.text:000000006B101730                 mov     edx, [r13+2Ch]
.text:000000006B101734                 and     dword ptr [r13-80h], 0FFFFFFFFh
.text:000000006B101739                 mov     edi, [r13+20h]
.text:000000006B10173D                 mov     esi, [r13+24h]
.text:000000006B101741                 mov     ebx, [r13+28h]
.text:000000006B101745                 mov     ebp, [r13+38h]
.text:000000006B101749                 mov     eax, [r13+34h]
.text:000000006B10174D                 mov     r14, rsp
.text:000000006B101750                 mov     word ptr [rsp+8], 23h ; Cs
.text:000000006B101757                 mov     word ptr [rsp+20h], 2Bh ; SS
.text:000000006B10175E                 mov     r8d, [r13+44h]
.text:000000006B101762                 and     dword ptr [r13+44h], 0FFFFFEFFh
.text:000000006B10176A                 mov     [rsp+10h], r8d  ; ELAGS
.text:000000006B10176F                 mov     r8d, [r13+48h]
.text:000000006B101773                 mov     [rsp+18h], r8   ; ESP
.text:000000006B101778                 mov     r8d, [r13+3Ch]
.text:000000006B10177C                 mov     [rsp], 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, [r14]      ; 返回地址
.text:000000006B101788                 add     r14, 4
.text:000000006B10178C                 mov     [r13+3Ch], r8d  ; r13==TEB64的一个值 这个值里面保存这CONTEXT32环境
.text:000000006B10178C                                         ; 方便以后会x86跳转
.text:000000006B101790                 mov     [r13+48h], r14d
.text:000000006B101794                 lea     r11, [r14+4]    ; 可以看到 把x86的参数指针传过来了
.text:000000006B101798                 mov     [r13+20h], edi
.text:000000006B10179C                 mov     [r13+24h], esi  ; 保存其他非易失寄存器
.text:000000006B1017A0                 mov     [r13+28h], ebx
.text:000000006B1017A4                 mov     [r13+38h], ebp
.text:000000006B1017A8                 pushfq                  ; 保存eflags
.text:000000006B1017A9                 pop     r8
.text:000000006B1017AB                 mov     [r13+44h], 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] ; 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     [r13+34h], eax
.text:000000006B1017C7                 jmp     resume_common_reg ; 执行完返回

可以看到,他并不是跳到函数的头部,而是跳到CpuReturnFromSimulatedCode这个标号处。
然后这个地方保存了环境。调用了Wow64SystemServiceEx
这个是wow64.dll的函数。
我们用YzDbg动态跟踪
在这个里面,我们会发现,有一个真正指向ntdll.OpenProcess的地方
image.png

可以看到,这是真正的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来查看
[Asm] 纯文本查看 复制代码
__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[/mw_shl_code]
前面我们跟踪了,是位于Jmp的这个Wow64Transition就是天堂之门,因此我们在Wow64CPu中找到这个函数

我们可以看到,是位于Wow64Cpu的 KiFastSystemCall,这是个硬编码,但是不难看出确实是一样的。
然后他直接就跳转到了CpuReturnFromSimulatedCode哪里
在这个函数中,其实就是保存了各种寄存器,交换堆栈(x86->x64),然后调用
不过这个保存的寄存器位于(gs)TEB64.特定位置
位于WOW64.dll(非GDI系统调用)__imp_Wow64SystemServiceEx这个函数
[Asm] 纯文本查看 复制代码
text:000000006B101782                                         ; DATA XREF: BTCpuResetToConsistentState+96↓o ...
.text:000000006B101782                 xchg    rsp, r14        ; r14保存的是堆栈 交换x64 x86堆栈
.text:000000006B101785                 mov     r8d, [r14]      ; 返回地址
.text:000000006B101788                 add     r14, 4
.text:000000006B10178C                 mov     [r13+3Ch], r8d  ; r13==TEB64的一个值 这个值里面保存这CONTEXT32环境
.text:000000006B10178C                                         ; 方便以后会x86跳转
.text:000000006B101790                 mov     [r13+48h], r14d
.text:000000006B101794                 lea     r11, [r14+4]    ; 可以看到 把x86的参数指针传过来了
.text:000000006B101798                 mov     [r13+20h], edi
.text:000000006B10179C                 mov     [r13+24h], esi  ; 保存其他非易失寄存器
.text:000000006B1017A0                 mov     [r13+28h], ebx
.text:000000006B1017A4                 mov     [r13+38h], ebp
.text:000000006B1017A8                 pushfq                  ; 保存eflags
.text:000000006B1017A9                 pop     r8
.text:000000006B1017AB                 mov     [r13+44h], 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] ; 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     [r13+34h], 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执行完毕之后,开始根据之前保存的寄存器 回复环境
ext:000000006B10168F                 btr     dword ptr [r13-80h], 0 ; 恢复通用非易失寄存器
.text:000000006B101695                 jb      short resume_segment_reg
.text:000000006B101697                 mov     edi, [r13+20h]
.text:000000006B10169B                 mov     esi, [r13+24h]
.text:000000006B10169F                 mov     ebx, [r13+28h]
.text:000000006B1016A3                 mov     ebp, [r13+38h]
.text:000000006B1016A7                 mov     eax, [r13+34h]
.text:000000006B1016AB                 mov     r14, rsp
.text:000000006B1016AE                 mov     dword ptr [rsp+0A8h+var_A8+4], 23h
.text:000000006B1016B6                 mov     r8d, 2Bh
.text:000000006B1016BC                 mov     ss, r8d
.text:000000006B1016BF                 mov     r9d, [r13+3Ch]
.text:000000006B1016C3                 mov     dword ptr [rsp+0A8h+var_A8], r9d
.text:000000006B1016C7                 mov     esp, [r13+48h]
.text:000000006B1016CB                 jmp     fword ptr [r14]
.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的返回堆栈来进行"地狱之门的返回的"
[Asm] 纯文本查看 复制代码
.text:000000006B1016FC                 movaps  xmm0, xmmword ptr [r13+0F0h] ; "地狱之门" 构建iretq的返回数据
.text:000000006B101704                 movaps  xmm1, xmmword ptr [r13+100h]
.text:000000006B10170C                 movaps  xmm2, xmmword ptr [r13+110h]
.text:000000006B101714                 movaps  xmm3, xmmword ptr [r13+120h]
.text:000000006B10171C                 movaps  xmm4, xmmword ptr [r13+130h]
.text:000000006B101724                 movaps  xmm5, xmmword ptr [r13+140h]
.text:000000006B10172C                 mov     ecx, [r13+30h]
.text:000000006B101730                 mov     edx, [r13+2Ch]
.text:000000006B101734                 and     dword ptr [r13-80h], 0FFFFFFFFh
.text:000000006B101739                 mov     edi, [r13+20h]
.text:000000006B10173D                 mov     esi, [r13+24h]
.text:000000006B101741                 mov     ebx, [r13+28h]
.text:000000006B101745                 mov     ebp, [r13+38h]
.text:000000006B101749                 mov     eax, [r13+34h]
.text:000000006B10174D                 mov     r14, rsp
.text:000000006B101750                 mov     word ptr [rsp+8], 23h ; Cs
.text:000000006B101757                 mov     word ptr [rsp+20h], 2Bh ; SS
.text:000000006B10175E                 mov     r8d, [r13+44h]
.text:000000006B101762                 and     dword ptr [r13+44h], 0FFFFFEFFh
.text:000000006B10176A                 mov     [rsp+10h], r8d  ; ELAGS
.text:000000006B10176F                 mov     r8d, [r13+48h]
.text:000000006B101773                 mov     [rsp+18h], r8   ; ESP
.text:000000006B101778                 mov     r8d, [r13+3Ch]
.text:000000006B10177C                 mov     [rsp], r8       ; eip
.text:000000006B101780                 iretq                   ; 构建iretq远调用返回

0x3-2 Wow64.Wow64SystemServiceEx
自此,一个WOW64CPU.dll调用的流程就分析完了,但是如果真的想要了解到底是怎么根据调用号,最终找到的函数(ntdllx64里面的),毫无疑问,我们需要去逆向以下这个函数
总的来说,这个函数也是很简单,他的作用就有一个,根据WOW64专属的ServiceTable,找到要中转的函数(这个函数里面在进行参数整合之后,最后会调用x64ntdll真正的处理函数)。
[Asm] 纯文本查看 复制代码
text:0000000180008EC0 ; __unwind { // __GSHandlerCheck_SEH
.text:0000000180008EC0                 mov     [rsp+arg_10], 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     [rsp+8B8h+var_28], rax
.text:0000000180008EE2                 mov     r14, rdx
.text:0000000180008EE5                 mov     edx, ecx
.text:0000000180008EE7                 mov     rax, gs:30h
.text:0000000180008EF0                 mov     rcx, [rax+14E0h]
.text:0000000180008EF7                 mov     [rsp+8B8h+var_880], rcx
.text:0000000180008EFC                 xor     edi, edi
.text:0000000180008EFE                 mov     [rsp+8B8h+var_878], edi
.text:0000000180008F02                 mov     rax, gs:30h
.text:0000000180008F0B                 lea     rcx, [rsp+8B8h+var_880]
.text:0000000180008F10                 mov     [rax+14E0h], 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, [r8+r8*2]
.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, [r10+r9*8+10h]
.text:0000000180008F3B                 ja      loc_18001CED2   ; 比较是否越界

而他是这样找到代{过}{滤}理函数的
[Asm] 纯文本查看 复制代码
text:0000000180008FB1                 mov     rax, [r10+r9*8] ; 找到函数表
.text:0000000180008FB5                 mov     rsi, [rax+rdx*8] ; 根据sysindex直接找到代{过}{滤}理函数
.text:0000000180008FB9                 mov     [rsp+8B8h+var_860], r8d
.text:0000000180008FBE                 mov     [rsp+8B8h+var_85C], edx



也就是sysindex*8+ServiceTable.FuncTable
0x3-2-1 Wow64.ServiceTable以及其应用


我们可以看到,他直接根据ServiceTable找到一个函数,然后调用,为此,我们必须去看看ServiceTable究竟保存了什么。(表太长,没用截全)
[Asm] 纯文本查看 复制代码
.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, [rsp+68h+var_38]
.text:0000000180010948                 mov     edx, r14d
.text:000000018001094B                 mov     rcx, rdi
.text:000000018001094E                 call    cs:__imp_NtOpenProcess ; 直接调用x64ntdll的OpenProcess
.text:0000000180010955                 nop     dword ptr [rax+rax+00h]
.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
[C] 纯文本查看 复制代码
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 [ecx+4], 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, [g_oWow64OpenProcess_] //mov rax,&target
        __emit 0x0
        __emit 0x0
        __emit 0x0
        __emit 0x0
        
        __emit 0x48       //mov rax,[rax]
        __emit 0x8b
        __emit 0x00

        __emit 0xff //jmp rax
        __emit 0xe0

    }
}

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

正常OpenProcess,可以读成功

image.png

而Hook之后
image.png

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


最后,纯小白,希望有错误大佬不吝赐教!

https://github.com/Oxygen1a1/Wow64HookServiceTable/tree/master


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

免费评分

参与人数 8吾爱币 +9 热心值 +8 收起 理由
peiwithhao + 2 + 1 热心回复!
wangyu2009 + 1 + 1 我很赞同!
xingkongyongye + 1 + 1 用心讨论,共获提升!
lee602201 + 1 用心讨论,共获提升!
杨辣子 + 1 + 1 我很赞同!
忆魂丶天雷 + 2 + 1 我很赞同!
ycj255999 + 1 + 1 我很赞同!
Ll001 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2022-11-15 11:23
oxygen1a1 发表于 2022-11-12 20:38
感谢大佬认可,我是先学习记到笔记里面了,然后直接复制发帖,所以排版不太好 就先凑活着看

用代码框处理一下代码就好了,我看你前面有一个位置尾部加了,头部怎么少了?
 楼主| oxygen1a1 发表于 2022-11-12 20:38
Panel 发表于 2022-11-12 20:32
排版一下应该是个好文章

感谢大佬认可,我是先学习记到笔记里面了,然后直接复制发帖,所以排版不太好 就先凑活着看

点评

用代码框处理一下代码就好了,我看你前面有一个位置尾部加了,头部怎么少了?  详情 回复 发表于 2022-11-15 11:23
akillking 发表于 2022-11-12 12:20
myxyvip 发表于 2022-11-12 12:58
感谢大佬分享
podehui 发表于 2022-11-12 13:58
感谢分享 进来学习
miraak 发表于 2022-11-12 15:33
, 多謝分享
metoo2 发表于 2022-11-12 15:45
学习了,感谢
Dokhyi 发表于 2022-11-12 15:59

学习了,感谢
xingkongyongye 发表于 2022-11-12 16:04
分析的很透彻,又学到了
宋雨鹏 发表于 2022-11-12 16:37


学习了,感谢
BurkeX 发表于 2022-11-12 16:57
分析极其透彻。萌新表示易懂。非常感谢大佬!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-27 02:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表