본문 바로가기
Security/Windows System

Windows x64커널 진입 : 커널모드편

by Winduck 2018. 4. 14.
반응형

 

x64에서 커널진입이후, 동작을 알아보기 위해 ntdll!ZwCreateFile의 경우를 알아보자.


ntdll!ZwCreateFile내부를 보자.


ntdll!ZwCreateFile:

0033:00000000`77b91860 4c8bd1          mov     r10,rcx        ; 첫번째 인수를 r10 백업시킨다. 이는 syscall이후 반환주소가 rcx 전달되기 때문

0033:00000000`77b91863 b852000000      mov     eax,52h        ; ServiceNumber를 eax로 전달

0033:00000000`77b91868 0f05            syscall                ; 커널진입

0033:00000000`77b9186a c3              ret

 

Syscall명령어를 통해 커널에 진입하게 되는데 eax 통해 ServiceNumber 전달하는것은 동일하다. 다른 점이 있다면 r10 첫번째 인수인 rcx 저장하는데 이는 커널진입 이후에 실행될 복귀주소인 77b9186a 전달되기 때문이다. 또한 x86때는 sysenter 통하여 커널에 진입한 반면 x64 syscall명령어를 쓰는데 이를 알아보기 위하여 intel문서를 참조하였다.



설명이 부족하여 자세한 설명을 보면 이렇다.


SYSCALL invokes an OS system-call handler at privilege level 0. It does so by loading RIP from the IA32_LSTAR MSR(0xc0000082) by Intel Doc


말인 즉슨 커널 진입시 가장 먼저 실행되는 코드의 주소인 rip IA32_LSTAR MSR(0xc0000082)로부터 가져온다 말이다. (x86에서는 0x176읽었었었드렜는데… ) 그래서 해당 주소를 확인해보았다.

 

 

해당 주소는 nt!KiSystemCall64였다.  해서 nt!KiSystemCall bp 걸고 진행해보았다. 근데…..계속 멈춘다….. 검색해보니 욕시 앞서 삽질하실분들이 있군...그렇다면 시키는대로 그래서 명령어인 swapgs 몇줄밑에 bp 걸고 진행해보니 잘되는 것을 있었다.  이제 차분히 nt!KiSystemCall64를 분석해본다


Nt!KiSystemCall64:

fffff800`02e8c640 0f01f8          swapgs                                                                                                        ; GS 레지스터의 값을 MSR address 0xC0000102H주소의 값으로 바꾼다.

fffff800`02e8c643 654889242510000000 mov   qword ptr gs:[10h],rsp               ; KPCR.UserRsp = gs:[0x10] User모드 rsp백업

fffff800`02e8c64c 65488b2425a8010000 mov   rsp,qword ptr gs:[1A8h]              ; KPCR.KPRCB.RspBase = gs:[1A8h] rsp로 저장

fffff800`02e8c655 6a2b            push    2Bh

fffff800`02e8c657 65ff342510000000 push    qword ptr gs:[10h]                   ; PUSH KPCR.UserRsp

fffff800`02e8c65f 4153            push    r11

fffff800`02e8c661 6a33            push    33h

fffff800`02e8c663 51              push    rcx

fffff800`02e8c664 498bca          mov     rcx,r10

fffff800`02e8c667 4883ec08        sub     rsp,8

fffff800`02e8c66b 55              push    rbp

fffff800`02e8c66c 4881ec58010000  sub     rsp,158h

fffff800`02e8c673 488dac2480000000 lea     rbp,[rsp+80h]

fffff800`02e8c67b 48899dc0000000  mov     qword ptr [rbp+0C0h],rbx

fffff800`02e8c682 4889bdc8000000  mov     qword ptr [rbp+0C8h],rdi

fffff800`02e8c689 4889b5d0000000  mov     qword ptr [rbp+0D0h],rsi

fffff800`02e8c690 c645ab02        mov     byte ptr [rbp-55h],2

fffff800`02e8c694 65488b1c2588010000 mov   rbx,qword ptr gs:[188h]             ; nt!KPCR._KPCB.CurrentThread

fffff800`02e8c69d 0f0d8bd8010000  prefetchw [rbx+1D8h]                         ; Store nt!_KTHREAD._KTRAP_FRAME in the Cache

fffff800`02e8c6a4 0fae5dac        stmxcsr dword ptr [rbp-54h]                  ; Store mxcsr 

fffff800`02e8c6a8 650fae142580010000 ldmxcsr dword ptr gs:[180h]               ; load nt!_KPCB.MxCsr into MxCsr

fffff800`02e8c6b1 807b0300        cmp     byte ptr [rbx+3],0                   ; nt!KPCR._KPCB.CurrentThread.

fffff800`02e8c6b5 66c785800000000000 mov   word ptr [rbp+80h],0                ; nt!_ETHREAD._KTHREAD._DISPATCHER_HEADER.DebugActive

fffff800`02e8c6be 0f848c000000    je      nt!KiSystemCall64+0x110 (fffff800`02e8c750)

 ========================================================================================

fffff800`02e8c750 fb              sti

fffff800`02e8c751 48898be0010000  mov     qword ptr [rbx+1E0h],rcx            ; store parameter1 in the nt!KTHREAD.FirstArgument

fffff800`02e8c758 8983f8010000    mov     dword ptr [rbx+1F8h],eax            ; store Service Number in the nt!KTHREAD.systemcallNumber

nt!KiSystemServiceStart:

fffff800`02e8c75e 4889a3d8010000  mov     qword ptr [rbx+1D8h],rsp            ; nt!_KTHREAD._KTRAP_FRAME

fffff800`02e8c765 8bf8            mov     edi,eax

fffff800`02e8c767 c1ef07          shr     edi,7

fffff800`02e8c76a 83e720          and     edi,20h

fffff800`02e8c76d 25ff0f0000      and     eax,0FFFh                           ; Service Table Index

nt!KiSystemServiceRepeat:

fffff800`02e8c772 4c8d15c7202300  lea     r10,[nt!KeServiceDescriptorTable (fffff800`030be840)]

fffff800`02e8c779 4c8d1d00212300  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff800`030be880)]

fffff800`02e8c780 f7830001000080000000 test dword ptr [rbx+100h],80h          ; Check GUI Thread

fffff800`02e8c78a 4d0f45d3        cmovne  r10,r11                             ; Check Service Table(cmpare SSDT or ShadowSSDT)

fffff800`02e8c78e 423b441710      cmp     eax,dword ptr [rdi+r10+10h]         ; ServiceNumber > ServiceTable Limit?

fffff800`02e8c793 0f83e9020000    jae     nt!KiSystemServiceExit+0x1a7 (fffff800`02e8ca82)

fffff800`02e8c799 4e8b1417        mov     r10,qword ptr [rdi+r10]             ; Get nt!KiServiceTable

fffff800`02e8c79d 4d631c82        movsxd  r11,dword ptr [r10+rax*4]           ; Get Service Offset X86이랑 다르게 DWORD로 저장되어 있음

fffff800`02e8c7a1 498bc3          mov     rax,r11

fffff800`02e8c7a4 49c1fb04        sar     r11,4                               ; Service Offset >>4

fffff800`02e8c7a8 4d03d3          add     r10,r11                             ; Get Service VA

fffff800`02e8c7ab 83ff20          cmp     edi,20h

fffff800`02e8c7ae 7550            jne     nt!KiSystemServiceGdiTebAccess+0x49 (fffff800`02e8c800)

fffff800`02e8c7b0 4c8b9bb8000000  mov     r11,qword ptr [rbx+0B8h]

nt!KiSystemServiceGdiTebAccess:

==============================================================================================

fffff800`02e8c800 83e00f          and     eax,0Fh

fffff800`02e8c803 0f84b7000000    je      nt!KiSystemServiceCopyEnd (fffff800`02e8c8c0)

fffff800`02e8c809 c1e003          shl     eax,3

fffff800`02e8c80c 488d642490      lea     rsp,[rsp-70h]

fffff800`02e8c811 488d7c2418      lea     rdi,[rsp+18h]

fffff800`02e8c816 488bb500010000  mov     rsi,qword ptr [rbp+100h]

fffff800`02e8c81d 488d7620        lea     rsi,[rsi+20h]

fffff800`02e8c821 f685f000000001  test    byte ptr [rbp+0F0h],1

fffff800`02e8c828 7416            je      nt!KiSystemServiceGdiTebAccess+0x89 (fffff800`02e8c840)

fffff800`02e8c82a 483b35cf172300  cmp     rsi,qword ptr [nt!MmUserProbeAddress (fffff800`030be000)]

fffff800`02e8c831 480f4335c7172300 cmovae  rsi,qword ptr [nt!MmUserProbeAddress (fffff800`030be000)]

fffff800`02e8c839 0f1f8000000000  nop     dword ptr [rax]

fffff800`02e8c840 4c8d1d79000000  lea     r11,[nt!KiSystemServiceCopyEnd (fffff800`02e8c8c0)]

fffff800`02e8c847 4c2bd8          sub     r11,rax

fffff800`02e8c84a 41ffe3          jmp     r11                                                                                           ; Call Service


x86과 다른부분은  x86의 경우 KiServiceTable에 VA값을 가지고 있다 하지만~~x64의 경우, DWORD 값을 가지고 있고  별도의 계산과정을 통해 함수 주소를 가져온다.  계산의 원활함을 위해 테이블이 가지고 값을 Serviceoffset이라고 겠다.

간단히 Service주소를 가져오는 것을 보겠다.

Service주소 계산 : KiServiceTable + ( Serviceoffset>>4 )
위 산식을 통해 서비스주소를 가져오고 ffff800`02e8c84a 41ffe3에서 서비스를 호출한다.


몇일동안 디버깅하면서 자료들 찾아가며 확인했던 x64내용들을 마무리합니다. 많이 바뀌어서 어렵기도하지만 재미있네요... 혹시나 틀린내용이 있다면 댓글로나 말씀해주시면 감사하겠습니다.


반응형

'Security > Windows System' 카테고리의 다른 글

NT / Zw Native API 차이  (0) 2019.04.05
I/O Control Code를 정의하는 CTL_CODE  (0) 2018.07.31
x64 Calling Convention(Windows)  (0) 2018.04.14
64 Windows커널 진입 차이 : 유저모드편  (0) 2018.04.12
kernel32 vs kernelbase  (0) 2018.04.05

댓글