주변에서 이전에 우연히 x64시스템에서 x86 API호출 과정에 대해 이야기가 나왔고 한번 찾아봐야지 하다가 이제야 작성하게 됐다.
먼저 Windows on Windows64 (일명 WoW64)는 쉽게 말해 x64시스템에서 x86프로그램을 실행시키기 위해 개발된 방법이다.
기본 x86시스템에서는 기본 자료처리를 4바이트로 하지만 x64경우 기본 8바이트 자료처리를 하기 때문에 실행을 위해이에 대한 호환이 필요하다. 따라서 본 글에서는 해당 과정에 대해서 확인하고자 한다.
테스트 환경은 Windows 10 x64 ver.1803에서 실행되었으며 x86으로 빌드된 프로그램은 파라미터로 받은 프로세스를 실행시키는 방식(CreateProcessA)으로 진행하였다.
먼저, x86과 동일하게 KERNELBASE!CreateProcessA -> KERNELBASE!CreateProcessInternalA -> KERNELBASE!CreateProcessInternalW -> ntdll!NtCreateUserProcess까지는 동일하다.
하지만 NtCreateUserProcess내부에서 달라진다. 본래 x86에서는 KiFastSystemCall이 호출되는데
x64에서는 ntdll!Wow64SystemServiceCall가 호출된다.
이후 ntdll!Wow64SystemServiceCall은 wow64cpu!KiFastSystemCall를 호출하는데 이 모듈부터 x64로 진입한다.
wow64cpu!KiFastSystemCall -> wow64cpu!CpupReturnFromSimulatedCode를 호출한다.
CpupReturnFromSimulatedCode 내부에 ServiceNoTurbo가 호출되고 _wow64!Wow64SystemServiceEx 를 호출한다.
아래는 CpupReturnFromSimulatedCode실행흐름이다.
wow64cpu!CpupReturnFromSimulatedCode: 00000000`77d618d2 4987e6 xchg rsp,r14 00000000`77d618d5 458b06 mov r8d,dword ptr [r14] 00000000`77d618d8 4983c604 add r14,4 00000000`77d618dc 4589453c mov dword ptr [r13+3Ch],r8d 00000000`77d618e0 45897548 mov dword ptr [r13+48h],r14d 00000000`77d618e4 4d8d5e04 lea r11,[r14+4] 00000000`77d618e8 41897d20 mov dword ptr [r13+20h],edi 00000000`77d618ec 41897524 mov dword ptr [r13+24h],esi 00000000`77d618f0 41895d28 mov dword ptr [r13+28h],ebx 00000000`77d618f4 41896d38 mov dword ptr [r13+38h],ebp 00000000`77d618f8 9c pushfq 00000000`77d618f9 4158 pop r8 00000000`77d618fb 45894544 mov dword ptr [r13+44h],r8d wow64cpu!TurboDispatchJumpAddressStart: 00000000`77d618ff 8bc8 mov ecx,eax ; Service Index Info 00000000`77d61901 c1e910 shr ecx,10h 00000000`77d61904 41ff24cf jmp qword ptr [r15+rcx*8] ; Jmp ServiceNoTurbo wow64cpu!ServiceNoTurbo: 00000000`77d61908 8bc8 mov ecx,eax ; param1 ( Service Index Info) 00000000`77d6190a 498bd3 mov rdx,r11 ; param2 ( Parmeter Info ) 00000000`77d6190d ff157d280000 call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (00000000`77d64190)] ds:00000000`77d64190={wow64!Wow64SystemServiceEx (00000000`77df77c0)} 00000000`77d61913 41894534 mov dword ptr [r13+34h],eax 00000000`77d61917 e9c3feffff jmp wow64cpu!RunSimulatedCode+0x2f (00000000`77d617df) |
위 내용을 설명하자면 Wow64SystemServiceEx내부를 확인해보았다.
x64 fastcall에서 파라미터 각각 1,2를 rcx와 rdx로 ServiceNoTurbo에서 'mov ecx,eax'를 수행하는데 이는 서비스 인덱스 정보이다.
또한 CpupReturnFromSimulatedCode에서 r11로 옮겨졌던 rdx로 전달하여 Wow64SystemServiceEx 호출한다
(x86시스템에서 커널모드 진입 KiFastSystemCall호출시 eax에 서비스 테이블 인덱스를 담는데 x64에서는 유저 레벨 서비스 테이블 인덱스 정보로 사용한다.)
Wow64SystemServiceEx의 역할은 서비스 테이블에서 서비스 주소를 가져오고 이를 호출하는 역할을 수행한다.
Index연산방식은 x86에서 eax로 전달받은 4바이트에서 상위 1바이트와 하위 3바이트를 나누어 서비스 접근을 수행한다. 연산방법은 아래와 같다.
Index = (indexinfo >> 0xC) & 3; offset = indexinfo & 0xFFF; *(*&ServiceTables[3 * v4] + 8 * v5); ServiceAddress = *(*&ServiceTables[3 * Index ] + 8 * offset ); |
이처럼 수행하여 서비스 주소를 가져와 파라미터 정보를 전달하여 wow64!whNtCreateUserProcess 를 호출한다.
최종 호출 스택 정보는 다음과 같다.
0:000> k Child-SP RetAddr Call Site 00000000`0063db68 00000000`77e0310d ntdll!NtCreateUserProcess 00000000`0063db70 00000000`77e02854 wow64!Wow64NtCreateUserProcess+0xe1 00000000`0063dc40 00000000`77df7913 wow64!whNtCreateUserProcess+0x4a4 00000000`0063df20 00000000`77d61913 wow64!Wow64SystemServiceEx+0x153 00000000`0063e7e0 00000000`77d61389 wow64cpu!ServiceNoTurbo+0xb 00000000`0063e890 00000000`77dfcec6 wow64cpu!BTCpuSimulate+0x9 00000000`0063e8d0 00000000`77dfcdb0 wow64!RunCpuSimulation+0xa |
이렇게 진입된 NtCreateUserProcess에서는 아래와 같은 코드로 커널모드에 진입한다.
ntdll!NtCreateUserProcess: 00007ffb`d3e5c1c0 4c8bd1 mov r10,rcx 00007ffb`d3e5c1c3 b8c2000000 mov eax,0C2h 00007ffb`d3e5c1c8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 00007ffb`d3e5c1d0 7503 jne ntdll!NtCreateUserProcess+0x15 (00007ffb`d3e5c1d5) 00007ffb`d3e5c1d2 0f05 syscall 00007ffb`d3e5c1d4 c3 ret |
이상으로 글을 마칩니다.
틀린내용있다면 말씀해주시면 감사하겠습니다~!!
'Security > Windows System' 카테고리의 다른 글
Kernel API Prefix (0) | 2020.05.28 |
---|---|
NT / Zw Native API 차이 (0) | 2019.04.05 |
I/O Control Code를 정의하는 CTL_CODE (0) | 2018.07.31 |
Windows x64커널 진입 : 커널모드편 (1) | 2018.04.14 |
x64 Calling Convention(Windows) (0) | 2018.04.14 |
댓글