본문 바로가기
Programming/WDK

SSDT 후킹

by bbolmin 2014. 2. 22.






[ref - SSDT_Hooking.pdf - Written by 백구]




Native API의 호출과정은 위의 그림과 같다.


1. INT 0x2E나 SYSENTER 같은 시스템 콜이 호출된다. (XP 이후는 SYSENTER를 사용)

http://luckey.tistory.com/86 <- INT 0x2E와 SYSENTER의 대해서 참고.


2. 시스템 콜이 호출되면 커널에서 KiSystemService(시스템 서비스 디스패처)를 호출한다.

- EAX에서 시스템 콜 번호를 읽어 SSDT의 인덱스로 사용

- EDX는 인자를 유저모드 스택에서 커털 모드 스택으로 복사한 곳을 가리킴


3. EAX에서 받은 시스템 콜 번호에 맞게 KeServiceDescriptorTable(SSDT)를 참조하여 Native API를 호출한다. 

- [SSDT+EAX*4]와 같이 참조


4. 시스템 콜 종료하고 유저 모드로 복귀한다

- INT 0x2E의 경우 iretd(인터럽트 복귀 명령) 사용.

- SYSENTER의 경우 SYSEXIT 사용.






[ 시스템 콜 & KeServiceDescriptorTable 구조]



위의 호출 과정을 따라서 좀더 상세하게 분석해보자.


1. 먼저 INT 0x2E와 SYSENTER의 경우에 (KiSystemService)시스템 서비스 디스패처를 호출하는데 약간의 차이가 있다.


kd> !idt 2e


Dumping IDT:


2e: 8053f481 nt!KiSystemService



kd> rdmsr 176                    //SYSENTER_EIP_MSR : 0x176

msr[176] = 00000000`8053f540

kd> ln 00000000`8053f540

(8053f540)   nt!KiFastCallEntry   |  (8053f649)   nt!KiServiceExit

Exact matches:

    nt!KiFastCallEntry = <no type information>



INT 0x2E의 경우에는 KiSystemService를 바로 호출하지만 SYSENTER의 경우에는 KiFastCallEntry를 먼저 호출한 후에 다시 KiSystemService를 호출한다.


- INT 0x2E -> KiSystemService

- SYSENTER -> KIFastCallEntry -> KiSystemService



[ref - http://luckey.tistory.com/86]




2. KeServiceDescriptorTable에 대해서 자세히 살펴보겠다. KeServiceDescriptorTable는 커널에서 제공하는 테이블로 SDE 구조체를 묶어놓은 SDT 구조체이다. SDE 구조체에 SSDT, SSPT가 들어있으며 아래와 같은 구조를 가진다.



typedef struct ServiceDescriptorEntry      

{

 unsigned int *ServiceTableBase;       

 unsigned int *ServiceCounterTableBase;     

 unsigned int NumberOfServices;       

 unsigned char *ParamTableBase;      

} SERVICE_DESCRIPTOR_ENTRY, *PSSERVICE_DESCRIPTOR_ENTRY;



1. SSDT 포인터

2. 함수의 호출 개수를 저장하는 테이블 포인터(Windows의 Checked 빌드버전에서만 사용)

3. 이 서비스 테이블에 저장되어 있는 서비스의 개수

4. SSPT 포인터



[*] SSDT, SSPT


SSDT(System Service Dispatch Table) : 시스템 콜을 처리하기 위한 함수를 찾을 때 사용.

SSPT(System Service Parameter Table) : 각 서비스에서 사용되는 인자의 크기가 몇 바이트인지 알려줌.




[*] windbg로 KeServiceDescriptorTable 내용확인


kd> dd KeServiceDescriptorTable

80554fa0  80503b8c 00000000 0000011c 80504000

80554fb0  00000000 00000000 00000000 00000000

80554fc0  00000000 00000000 00000000 00000000


kd> d 80503b8c 

80503b8c  8059b948 805e8db6 805ec5fc 805e8de8

80503b9c  805ec636 805e8e1e 805ec67a 805ec6be

80503bac  8060ddfe 8060eb50 805e41b4 805e3e0c


kd> u 8059b948 

nt!NtAcceptConnectPort:

8059b948 689c000000      push    9Ch

8059b94d 6838b14d80      push    offset nt!_real+0x128 (804db138)


kd> u 805e8db6 

nt!NtAccessCheck:

805e8db6 8bff            mov     edi,edi

805e8db8 55              push    ebp

805e8db9 8bec            mov     ebp,esp


...








[ SSDT에 쓰기 권한 주기 ]




WIndows XP 이상에서 SSDT가 Read Only로 되어 있는데 SSDT 후킹을 하기 위해서는 쓰기 권한이 필요하다.

이를 우회하여 쓰기 권한을 주는 두가지 방법은 아래와 같다.




1. CR0 레지스터의 WP(Write Protect) bit


- 0이면 메모리 보호기능 해제

- 1이면 메모리 보호 활성화



--------- CODE ---------

// 메모리 보호 기능 OFF

__asm

{

push eax

mov eax, CR0

and eax, 0FFFEFFFFh

mov CR0, eax

pop eax

}



// 메모리 보호 기능 ON

__asm

{

push eax

mov eax, CR0

or eax, NOT 0FFFEFFFFh

mov CR0, eax

pop eax

}








[ SSDT 후킹 ]



간단히 Native API함수들의 주소가 들어 있는 SSDT에 후킹할 함수의 주소가 있는 index 번째에 새롭게 만든 함수 주소를 덮어버리면 SSDT 후킹이 이루어진다. 



[ZwQuerySystemInformation 후킹을 통한 Process Hiding.]







[ REF ]


http://luckey.tistory.com/86

SSDT_Hooking.pdf - Written by 백구

- 루트킷 (커널조작의 미학)






'Programming > WDK' 카테고리의 다른 글

가상주소-선형주소-물리주소 변환  (0) 2014.01.25
메모리 접근  (0) 2014.01.19
WDK빌드 환경 ( + Visual Studio )  (0) 2014.01.13