64Bit OS 에서의 SYSCALL / SDT
Intel 의 32bit CPU / 최근의 OS 에서는
시스템 프로시져 호출을 위해 SYSENTER 명령을 사용합니다.
http://sysenter.tistory.com/entry/SYSENTER
AMD 에서는 SYSCALL 명령을 사용하구요...
그런데, 64비트에서는 x64 명령어셋에 대해 AMD 가 주도하다 보니,
SYSCALL 으로 통일되었나봅니다. 아닌가? ㅡㅡㅋ
어쨋든~
64bit VISTA 를 분석하다보니,
SYSENTER 가 아닌, SYSCALL 을 호출합니다.
AMD Processor 도 INTEL Processor 도 마찬가지입니다.
AMD 의 SYSCALL and SYSRET Instruction Specification 을 보면
SYSCALL/SYSRET Target Address Register (STAR) are copied into the EIP register.
(The STAR register is Model-Specific Register C000_0081h.
대충 보면, Instructuon Point 가 MSR C000_0081 에 지정되는것 같습니다.
아... 이것 때문에 삽질 겁나 했습니다.
인터넷 아무리 뒤져봐도, SYSCALL 은 MSR C000_0081h 로 나오는데...
잘은 모르지만, 이건 32Bit OS 일 때, 이야기인것 같습니다.
AMD BIOS and Kernel Developer’s Guide (BKDG) 를 확인하니,
Reset: X.
Bits Description
63:0 LSTAR: long mode target address. Read-write. Target address for 64-bit mode calling programs.
The address stored in this register must be in canonical form (if not canonical, a #GP fault occurs).
64Bit 모드에서는 MSR C000_0082 에 타겟 주소가 지정된다고 합니다.
하아... C000_0081 때문에, 하루를 삽질했는데...
뭐쨋든 확인해보면,
msr[c0000082] = fffff800`018aec00
0: kd> u fffff800`018aec00
nt!KiSystemCall64:
fffff800`018aec00 0f01f8 swapgs
fffff800`018aec03 654889242510000000 mov qword ptr gs:[10h],rsp
fffff800`018aec0c 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h]
fffff800`018aec15 6a2b push 2Bh
fffff800`018aec17 65ff342510000000 push qword ptr gs:[10h]
fffff800`018aec1f 4153 push r11
fffff800`018aec21 6a33 push 33h
fffff800`018aec23 51 push rcx
KiSystemCall64 의 주소가 지정되어있는 것을 알 수 있습니다.
ㅡㅡa
NT kernel 에서 KiFastCallEntry 가 안나오길래 의아했었는데,
64Bit 는 저 함수가 처리하나봅니다.
아, 32Bit Intel OS 에서는
ntdll 의 KiFastSystemCall 이라는 루틴을 통해서 커널모드로 들어가는데,
64Bit OS 에서는 이 루틴을 통하지 않습니다.
OpenProcess 를 통해 동작을 비교해보면,
32Bit Intel OS
↓
ntdll!ZwOpenProcess
↓
ntdll!KiFastSystemCall
↓
↓
nt!NtOpenProcess
64Bit OS
↓
ntdll!ZwOpenProcess
↓
↓
nt!NtOpenProcess
위와 같죠.
재밌는건..
64Bit 에서도 유저모드의 kernel32 모듈 이름이 동일합니다.
은근히... kernel64, user64 를 기대하기도 했는데 말이죠..
KiSystemCall64 의 심볼을 보면
KiSystemServiceStart 와 같은 이름을 볼 수 있는데,
구글링해보면, 이 함수가 시스템 서비스를 호출하는 본체로 설명되어있습니다.
정확히 본다면,
SDT 를 참조하는 부분은
nt!KiSystemServiceRepeat 이고,
실제 호출하는 부분은
nt!KiSystemServiceCopyEnd 입니다.흠.. 위의 두 심벌은 함수는 아닌것 같습니다. 스택 정리 관련 명령이 내부에 없어서...
GOTO 문에 사용된 심벌인가? ㅡㅡa 잘 모릅니다 저런거...
SDT 는...
fffff800`01a31980 fffff800`01860d00 nt!KiServiceTable
fffff800`01a31988 00000000`00000000
fffff800`01a31990 00000000`00000187
fffff800`01a31998 fffff800`0186193c nt!KiArgumentTable
fffff800`01a319a0 00000000`00000000
fffff800`01a319a8 00000000`00000000
fffff800`01a319b0 00000000`00000000
fffff800`01a319b8 00000000`00000000
fffff800`01a319c0 fffff800`01860d00 nt!KiServiceTable
fffff800`01a319c8 00000000`00000000
fffff800`01a319d0 00000000`00000187
fffff800`01a319d8 fffff800`0186193c nt!KiArgumentTable
fffff800`01a319e0 fffff960`00103100 win32k!W32pServiceTable
fffff800`01a319e8 00000000`00000000
fffff800`01a319f0 00000000`00000306
fffff800`01a319f8 fffff960`00104c3c win32k!W32pArgumentTable
32bit 에서 구했던 것 처럼 쉽게 확인 가능합니다.
ㅡㅡa 그런데, win32k!W32pServiceTable 이 바로 나오네요. 32도 그랬나? '.'?
서비스 테이블은
nt 함수들과 1:1 매칭이 되지 않습니다.
아마 패치가드인가 그것 때문인것 같은데
이게, 전체 모양이 다 안나오는게 아니라
fffff800`018b2d00 02780a00`03969f00
fffff800`018b2d08 02668005`fff69d00
fffff800`018b2d10 0289e905`029b2206
fffff800`018b2d18 02728700`026aeb01
fffff800`018b2d20 023a5e00`023a5c40
.....
fffff800`018b3908 fffff800`01c210c0 nt!NtWaitForDebugEvent
fffff800`018b3910 fffff800`01ad7658 nt!NtWaitForKeyedEvent
fffff800`018b3918 fffff800`018caabc nt!NtWaitForWorkViaWorkerFactory
fffff800`018b3920 fffff800`01c16a40 nt!NtWaitHighEventPair
fffff800`018b3928 fffff800`01c16ad0 nt!NtWaitLowEventPair
fffff800`018b3930 fffff800`018ed34c nt!NtWorkerFactoryWorkerReady
한, 반정도는 안나오고 나머지 반정도는 나오네요.
패치가드때문에, SDT 훅이 안된다고 하던데,
된다하더라도 저 숨은 Quad Word 의 비밀을 풀어야할 것 같습니다.
그나저나, SDT 훅이 안되니...
-_ㅡa 뭔 수로 후킹을 하지...
MSR 값 변조로 KiSystemCall 후킹, 아니면 CALL r10 후킹... 되려나...