tmxklab

[Volatility] 커널 공간 후킹 탐지 본문

Security/Volatility

[Volatility] 커널 공간 후킹 탐지

tmxk4221 2021. 5. 7. 18:10

후킹의 목적은 정상 API 호출을 차단하여 API에 전달되는 파라미터를 모니터링하거나 API에서 반환되는 값을 필터하는 것이다. 공격자가 악성 커널 드라이버를 설치하여 커널 공간에서 후킹을 시도할 수 있다. 커널 컴포넌트가 시스템 작동에 매우 중요한 역할을 하기 때문에 커널 공간에서 후킹은 유저 공간에서 후킹하는 것보다 강력하다. 따라서, 커널 공간에서 이루어지는 다양한 후킹 기술과 탐지 방법을 살펴보자

 

1. SSDT 후킹

커널 공간에 존재하는 SSDT(System Service Descriptor Table)은 커널 익스큐티브(ntoskrnl.exe, ntkrnlpa.exe 등)에서 export한 서비스 루틴의 포인터를 포함한다. 

 

Window API 호출 흐름

0. 목차 1. 커널 메모리 내용 2. 유저모드, 커널모드 3. Window API 호출 흐름 1. 커널 메모리 내용 커널 메모리는 OS와 장치 드라이버를 포함한다. 커널 메모리는 다음 주요 컴포넌트로 이루어져 있다.

rninche01.tistory.com

위 링크에서는 유저 단에서 API를 호출했을 때 커널 단까지의 흐름을 살펴볼 수 있다. API함수를 호출했을 때 스레드를 커널 모드로 전환하는 ntdll.dll의 스텁 코드를 호출하게 된다. 이후에 커널 모드에서 실행 중인 스레드는 ntoskrnl.exe에 구현된 실제 함수 Nt??()의 주소를 찾아야되는데 여기서 SSDT라는 커널 공간의 테이블을 참조해 실제 주소를 파악한다.

일반적으로 ntoskrnl.exe는 NtWriteFile(), NtReadFile() 등과 같은 핵심 커널 API 함수를 익스포트한다.

x86이나 x64시스템 모두 SSDT를 통해 특정 함수의 주소를 파악하는 개념은 동일하지만 조금의 차이가 존재한다.

x86에서는 커널 함수 포인터를 SSDT에 직접 저장하지만 x64에서는 포인터를 SSDT에 저장하지 않고 커널 함수의 주소를 파악하기 위해 디코딩되는 인코딩 정수를 저장한다. SSDT와 유사한 테이블인 SSDT Shaodw 테이블이 존재하는데 이 테이블은 win32k.sys가 익스포트한 GUI관련 함수의 포인터를 저장한다. 

 

SSDT 플러그인

  • SSDT[0] : 기본 SSDT 테이블을 나타냄
  • SSDT[1] : SSDT Shadow 테이블을 나타냄

SSDT 후킹의 경우 SSDT테이블에 등록된 정상 함수의 포인터 대신에 악의적인 함수의 주소로 변경할 수 있다. 따라서, SSDT 후킹을 탐지하고자 ntoskrnl.exe 또는 win32k.sys 안의 주소를 가리키지 않는 SSDT 항목을 살펴봐야 한다. 하지만, SSDT 후킹의 경우 쉽게 탐지되고 x64환경에서는 PatchGuard로 알려진 커널 패치보호 메커니즘을 통해 SSDT 후킹을 차단하게 된다. 또한, SSDT 항목은 윈도우 버전마다 다르고 최신 버전에서 변경되므로 신뢰성 높은 루트킷을 작성하기가 어렵다.

 


2. IDT 후킹

IDT(Interrupt Descriptor Table)은 ISR(Interrupt Service Routines or Interrupt handlers)로 알려진 함수의 주소를 저장하며 이들 함수는 인터럽트와 프로세스 예외를 처리한다. 위에서 설명한 SSDT 후킹과 비슷하게 IDT에 있는 항목을 후킹하여 악성 함수로 리다이렉트시키는 방법이다. 

 

idt 플러그인

  • idt 항목 표시

위 그림에서 보면 INT 62, 63항목에서 정상적인 Module을 가리키는 것이 아닌 알려지지 않은 UNKNOWN 모듈의 주소를 가리키고 있다. 즉 후킹된 항목이 ntoskrnl.exe 모듈의 바깥쪽에 위치한다. 

 


3. 인라인 커널 후킹

인라인 커널 후킹을 사용하여 커널 함수와 기존 커널 드라이버의 함수를 jmp 명령어로 수정함으로써 실행 흐름을 악성 코드로 재설정할 수 있다. 이전에 API 후킹을 탐지하기 위해 apihooks 플러그인을 사용하였다. apihooks 플러그인을 사용하면 kernel, user mode 둘 다 탐지할 수 있다. 

vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> apihooks -P

-P옵션을 지정해주면 커널 공간에 있는 후킹만 스캔할 수 있다.


4. IRP(I/O Request Packet) 함수 후킹

루트킷은 MajorFunction(디스패치 루틴 배열)의 항목을 수정하여 악의적인 모듈에 있는 루틴을 가리키도록 할 수 있다. MajorFunction[28]은 드라이버 객체의 구조체(DRIVER_OBJECT)에 있는 배열로 I/O 유형에 따라 다르게 처리할 수 있도록 각 인덱스마다 특정 함수 포인터가 존재한다.

 

만약, IRP_MJ_WRITE과 연관된 주소를 변경하여 데이터를 가로채거나 리다이렉션하여 악성코드를 실행할 수 있다. 따라서, 탐지하기 위해 driverirp 플러그인을 사용하여 알려지지 않은 모듈(UNKNOWN)인지 확인한다.

 

하지만 이런 경우는 쉽게 탐지되므로 의심을 피하기 위해 간접적인 IRP 후킹을 사용한다. 예를 들면, 주요 IRP함수포인터가 정상적인 모듈을 가리키지만 해당 모듈을 디스어셈블해보면 외부로 JMP하는 경우가 있다. 이러한 경우 깨끗한 시스템에서 실행시켰을 때와 비교하여 IRP함수포인터가 가리키는 모듈 이름을 비교해봐야 한다.

 


+) 위에서 설명한 표준후킹방식은 탐지하는 것이 매우 간단하다. (ntoskrnl.exe/win32k.sys를 가리키지 않는 SSDT 항목, 다른 곳을 가리키는 IRP함수, jmp명령어 등) 공격자는 이러한 탐지를 회피하기 위해 호출 테이블 항목을 유지하면서 후킹을 구현하거나 jmp명령어를 코드 내부 깊숙이 배치하지만 이를 위해 시스템 모듈 또는 서드파티 드라이버를 패치해야 한다. 하지만, 패치하게 되면 PatchGuard가 호출 테이블과 핵심 시스템 모듈의 패치를 보호하게 된다. 따라서, 공격자들은 보호 메커니즘을 우회하거나 정상 드라이버와 혼함해 악성코드를 실행하고 탐지를 회피한다.

  

+) 대충 이런 흐름으로 후킹을 하는구나 정도만 파악하고 SSDT나 후킹 기술에 대해서는 따로 정리하도록 하자.  

+) 추가로 보호 메커니즘(PatchGuard 등)과 보호 메커니즘을 우회하는 기술에 대해서도 공부해서 정리하자

Comments