Abstract 본문서는 Rootkit에의해숨겨진 process를찾는기술에대해정리한것입니다. 최신기술은아니지만여러 Rootkit와 Anti-Rootkit에적용되어있는 process를감추고발견하는기술들에대해서정리해보았으며가급적이면다음에언제보더라도쉽게이해할수있도록쓸려고노력

Similar documents
Microsoft Word - [Windows Hook] 6.HideProcess.doc

6주차.key

chap 5: Trees

C# Programming Guide - Types

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

untitled

Deok9_Exploit Technique

Chapter #01 Subject

PCServerMgmt7

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

API 매뉴얼

<B1E2BCFAB9AEBCAD28C0CCB5BFBCF6295F F6F6B696E672E687770>


Chap06(Interprocess Communication).PDF

Sharing Memory Between Drivers and Applications

<B1E2BCFAB9AEBCAD28C0CCB5BFBCF6295F F6F6B696E672E687770>

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

<4D F736F F F696E74202D20BBB7BBB7C7D15F FBEDFB0A3B1B3C0B05FC1A638C0CFC2F72E BC8A3C8AF20B8F0B5E55D>

목차 BUG offline replicator 에서유효하지않은로그를읽을경우비정상종료할수있다... 3 BUG 각 partition 이서로다른 tablespace 를가지고, column type 이 CLOB 이며, 해당 table 을 truncate

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

Chapter 4. LISTS

PowerPoint 프레젠테이션

UI TASK & KEY EVENT

1217 WebTrafMon II

Microsoft Word - FunctionCall

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

API 매뉴얼

어댑터뷰

Embeddedsystem(8).PDF

11장 포인터

11장 포인터

제11장 프로세스와 쓰레드

UI TASK & KEY EVENT

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

10주차.key

UI TASK & KEY EVENT

JVM 메모리구조

BMP 파일 처리

13주-14주proc.PDF

슬라이드 1

Microsoft PowerPoint - o8.pptx

Microsoft PowerPoint APUE(Intro).ppt

1. What is AX1 AX1 Program은 WIZnet 사의 Hardwired TCP/IP Chip인 iinchip 들의성능평가및 Test를위해제작된 Windows 기반의 PC Program이다. AX1은 Internet을통해 iinchip Evaluation

Frama-C/JESSIS 사용법 소개

슬라이드 1

Microsoft PowerPoint - chap06-2pointer.ppt

Microsoft PowerPoint - ch07 - 포인터 pm0415

Microsoft PowerPoint - 알고리즘_5주차_1차시.pptx

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

MAX+plus II Getting Started - 무작정따라하기

Microsoft PowerPoint - a10.ppt [호환 모드]

Chapter 4. LISTS

¨ìÃÊÁ¡2

No Slide Title

Microsoft PowerPoint - 04-UDP Programming.ppt

Microsoft PowerPoint - polling.pptx

Remote UI Guide

Deok9_PE Structure

Lab 3. 실습문제 (Single linked list)_해답.hwp

PowerPoint 프레젠테이션

(Asynchronous Mode) ( 1, 5~8, 1~2) & (Parity) 1 ; * S erial Port (BIOS INT 14H) - 1 -

untitled

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

<C0CCBCBCBFB52DC1A4B4EBBFF82DBCAEBBE7B3EDB9AE2D D382E687770>

API - Notification 메크로를통하여어느특정상황이되었을때 SolidWorks 및보낸경로를통하여알림메시지를보낼수있습니다. 이번기술자료에서는메크로에서이벤트처리기를통하여진행할예정이며, 메크로에서작업을수행하는데유용할것입니다. 알림이벤트핸들러는응용프로그램구현하는데있어

윤성우의 열혈 TCP/IP 소켓 프로그래밍

iii. Design Tab 을 Click 하여 WindowBuilder 가자동으로생성한 GUI 프로그래밍환경을확인한다.

RVC Robot Vaccum Cleaner

Chapter 4. LISTS

Something that can be seen, touched or otherwise sensed

PowerPoint Presentation

Microsoft PowerPoint - chap10-함수의활용.pptx

rmi_박준용_final.PDF

Lab 4. 실습문제 (Circular singly linked list)_해답.hwp

1. Execution sequence 첫번째로 GameGuard 의실행순서는다음과같습니다 오전 10:10:03 Type : Create 오전 10:10:03 Parent ID : 0xA 오전 10:10:03 Pro

<4D F736F F F696E74202D B3E22032C7D0B1E220C0A9B5B5BFECB0D4C0D3C7C1B7CEB1D7B7A1B9D620C1A638B0AD202D20C7C1B7B9C0D320BCD3B5B5C0C720C1B6C0FD>

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

설계란 무엇인가?

Figure 5.01

디지털영상처리3

Microsoft PowerPoint - ch10 - 이진트리, AVL 트리, 트리 응용 pm0600

10.

Microsoft PowerPoint - System Programming Lab Week1.ppt [호환 모드]

컴파일러

C++ Programming

Chap 6: Graphs

학습목차 2.1 다차원배열이란 차원배열의주소와값의참조

슬라이드 1

1

Microsoft PowerPoint - chap06-5 [호환 모드]

adfasdfasfdasfasfadf

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

슬라이드 1

Microsoft Word doc

MPLAB C18 C

<C1A4C8B8BFF8C6F2B0A15FB1E2BCFAB9AEBCAD5F444B4F4D5FC0CCB5BFBCF62E687770>

원형연결리스트에대한설명중틀린것은 모든노드들이연결되어있다 마지막에삽입하기가간단한다 헤더노드를가질수있다 최종노드포인터가 NULL이다 리스트의 번째요소를가장빠르게찾을수있는구현방법은무엇인가 배열 단순연결리스트 원형연결리스트 이중연결리스트 단순연결리스트의노드포인터 가마지막노드를

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

Transcription:

Find Process Last Update: 2008 년 8 월 6 일오후 8 시 46 분 Written by Jerald Lee Contact Me: lucid78@gmail.com 1

Abstract 본문서는 Rootkit에의해숨겨진 process를찾는기술에대해정리한것입니다. 최신기술은아니지만여러 Rootkit와 Anti-Rootkit에적용되어있는 process를감추고발견하는기술들에대해서정리해보았으며가급적이면다음에언제보더라도쉽게이해할수있도록쓸려고노력하였습니다. 본문서는읽으시는분들이어느정도 Windows API를알고있다는가정하에쓰여졌습니다. 제시된코드들은 Windows XP Professional, Service Pack 3, Windows DDK build 6000 에서테스 트되었습니다. 문서의내용중틀린곳이나수정할곳이있으면연락해주시기바랍니다. 2

목차 1. BACKGROUND...7 1.1. HANDLES AND OBJECTS...8 1.2. USER OBJECT...13 1.3. GDI OBJECT...14 1.4. KERNEL OBJECT...15 1.5. WINDOWS KERNEL-MODE OBJECT MANAGER...18 1.6. SUMMARY...20 2. PROCESS HIDING METHOD...21 2.1. SSDT HOOK...22 2.2. DKOM: FU...25 2.3. DKOM: PHIDE2...28 2.4. DKOM: FUTO...37 2.5. SUMMARY...41 3. DETECT METHOD OF HIDDEN PROCESS...42 3.1. VICE...43 3.2. KLISTER...51 3.3. BLACKLIGHT...60 3.4. SUMMARY...63 4. CONCLUSION...64 5. 참고자료...65 3

그림목차그림 1. CREATEWINDOW...13 그림 2. DESTORYWINDOW...13 그림 3. CREATEEVENT...15 그림 4. OPENEVENT...16 그림 5. CLOSEHANDLE...16 그림 6. MULTIPLE FILE OBJECT FOR FILE ON DISK...17 그림 7. MULTIPLE FILE HANDLE FOR FILE OBJECT...17 그림 8. SSDT HOOK...22 그림 9. EPROCESS...22 그림 10. NEWNTQUERYSYSTEMINFORMATION...23 그림 11. HIDE PROCESS WITH SSDT HOOK...24 그림 12. HIDE NOTEPAD.EXE...24 그림 13. HIDE PROCESS WITH DKOM...25 그림 14. FU ROOTKIT...26 그림 15. FU EXECUTE...27 그림 16. THREAD SCHEDULING STATES...28 그림 17. THREAD SCHEDULING 1...30 그림 18. THREAD SCHEDULING 2...31 그림 19. PROCESSHIDE-1...33 그림 20. PROCESSHIDE-2...33 그림 21. WANTEDSYMBOLS...34 그림 22. PROCESSHIDE-3...34 그림 23. PROCESSHIDE-4...35 그림 24. PROCESSHIDE-5...35 그림 25. VICESYS.SYS 1...46 그림 26. VICESYS.SYS 2...46 그림 27. SSDT DETECT WITH VICE...47 그림 28. FALSE POSITIVE OF VICE...48 그림 29. FU...49 그림 30. VICE WITH FU ROOTKIT...50 그림 31. STATE OF THREAD...51 그림 32. PRIORITY OF THREAD...52 그림 33. KIDISPATCHERREADYLISTHEAD...52 그림 34. OS 버전별주소값...53 그림 35. 디바이스생성...53 4

그림 36. DEVICEIOCONTROL-1...54 그림 37. IOCTL_KLISTER_INIT...55 그림 38. DEVICEIOCONTROL-2...56 그림 39. IOCTL_KLISTER_LISTPROC...56 그림 40. CREATEPROCLIST()...57 그림 41. INSERTSERVTABLE()...58 그림 42. INSERTPROC()...58 그림 43. PSLOOKUPPROCESSBYPROCESSID...60 그림 44. HIDE CMD.EXE WITH FU...61 그림 45. BALCKLIGHT 결과 1...61 그림 46. BLACKLIGHT 결과 2...62 5

표목차표 1. OBJECT MANAGER가수행하는작업...8 표 2. OBJECT에대한작업...9 표 3. HANDLE의상속 / 복제가능한 OBJECT...10 표 4. USER OBJECT...11 표 5. GDI OBJECT...11 표 6. KERNEL OBJECT...12 표 7. USER HANDLE 개수수정레지스트리...13 표 8. GDI HANDLE 개수조정레지스트리...14 표 9. WINDOWS OBJECTS...18 표 10. OBJECT 관리를위한 TASK...18 표 11. KLISTER_PROCINFO, SERVICETABLEINFO 구조체...56 표 12. PROCESSOBJECT()...57 표 13. SERVICETABLEINFO 구조체...58 표 14. KLISTER_PROCINFO 구조체...59 6

1. Background 이번절에서는기본지식들에대해알아봅니다. Handle에대한주제는 Windows Programmer라면반드시알고있어야만하는매우기초적인부분이면서도난해한주제라고할수있습니다. Handle과 Object 부분은 Microsoft Internals forth edition과는다른부분이있으니반드시읽어보길바랍니다. 이절은 [3] 을초벌번역한것입니다. 원문과의미가다를수도있으니반드시원문과비교해가며읽으시기바랍 니다. 초벌번역인지라반말로쓴것에대해양해를구합니다. 7

1.1. Handles and Objects Object는 file, thread, graphic image와같은 system resource들을나타내는 Data Structure들을말한다. Application은 object로나타내어진 object data나 system resource에직접접근할수없으며만약이들을수정하거나사용해야할경우 object handle을얻어야만한다. 각 Handle은내부적으로유지되는테이블의 entry를가지고있으며이 entry들은 resource의주소와 resource type을식별하는방법을포함한다. Windows system은 system resource에대한접근을통제하기위해 object와 handle을사용하는데크게두가지의이유를가지고있다. 1 object의사용은 Microsoft가시스템을안전하게업데이트할수있도록하고가능한한오랫동안 original object interface를유지할수있도록해준다. 시스템의새로운버전이 release 되면아주적은노력으로 object만업데이트하면된다. 2 object의사용은 Windows security의이점을이용할수있도록해준다. 각 object들은자신만의 access-control list(acl) 을가지고있으며이 ACL은 object에서 process가수행할수있는행동을정의하고있다. 시스템은 application이 object에대한 handle을생성할때마다 object의 ACL을검사한다. Object는 standard header와 object-specific attribute로구성되어있다. 모든 object들은동일한구조를가지고있기때문에하나의 object manager가모든 object들을관리한다. Object header는 object name과같은아이템들을포함하고있기때문에다른 process들이이름이나 security descriptor를이용해서 object를참조할수있으며 object manager는 system resource에접근하는 process들을제어한다. object manager가수행하는작업은다음과같다. object 생성 process가 object에대해올바른권한을가지고있는지를검사 object handle을생성하고호출자에게 return resource quota를유지 duplicate handle 생성 object의 handle 닫기표 1. Object Manager가수행하는작업 Windows가지원하는 object에대한작업은다음과같다. object 생성 object handle 가져오기 object의정보가져오기 object의정보설정하기 8

object 의 handle 닫기 object 파괴 표 2. Object 에대한작업 위의작업들중의일부는각 object 단위로필요한것이아니라임의의 object들을위해결합된형태로동작한다. 예를들어한 application이 event object를생성한후다른 application이이 event object의 unique handle을얻기위해 event를열수있다. 각 application은이 event의사용이끝나면 object에대한 handle을닫게된다. event object에대해열려있는 handle이남아있지않을때시스템은이벤트 object를파괴한다. 반대로 application은현재존재하고있는윈도우 object에대한 handle을얻을수도있는데윈도우 object가더이상필요하지않을경우 application은 object를반드시파괴해야만하고이작업은윈도우 handle을무효로만들게된다. 때때로, object는모든 object handle이닫힌후에도메모리에남아있을수있다. 예를들어 thread 는 event object를생성하고 event handle을얻어대기한다. 이 thread가대기하는동안다른 thread가동일한 event object handle을닫을수있다. 이때 event object는상태신호가설정되고 wait operation이완료될때까지어떤 event object handle도없는상태로메모리에남게된다. Handle과 object들은메모리를소비하기때문에시스템성능을보전하기위해서는더이상사용할필요가없는 handle과 object를닫고삭제해야한다. 만약이렇게하지않을경우에는 paging file의과도한사용으로인해 application이시스템의성능을해칠수있다. Process가종료될때시스템은자동으로 process에의해생성된 handle을닫고 object를삭제한다. 그러나 thread가종료될때시스템은다음의경우를제외하고는일반적으로 handle을닫거나 object 를삭제하지는않는다. window, hook, windows position, dynamic data exchange(dde) conversation object 들은생성한 thread가종료될때파괴된다. 몇몇 object들은한번에오직하나의 handle만을지원한다. 시스템은 application이 object를생성할때 handle을공급하고 application이 object를소멸할때 handle을무효화한다. 나머지다른 object들은하나의 object에대해여러개의 handle을지원한다. 운영체제는 object를가리키는마지막 handle이닫힌후에자동으로메모리에서 object를삭제한다. 시스템의열린 handle의총합은사용가능한메모리의양에의존한다. 어떤 object 타입은세션당또는 process당 handle 수를제한한다. 자식 process튼부모 process로부터 handle을상속받을수있다. 상속된 handle은오직자식 process의 context 안에서만유효하다. DuplicateHandle 함수는현재 process에사용되고있는 handle을다른 process로복제하는기능을가지고있다. 만약 application이다른 process에게 handle을복제했다면, 복제된 handle은오직다른 process의 context 안에서만유효하다. 복제되거나상속된 handle은유일한값이지만원본 handle처럼같은 object를가리킨다. process는 9

아래타입의 object에대해 handle을상속하거나복제할수있다. Access Token Communications device Console input Console screen buffer Desktop Directory Event File File mapping Job Mailslot Mutex Pipe Process Registry key Semaphore Socket Thread Timer Window station 표 3. Handle의상속 / 복제가능한 Object 다른모든 object 들은자신을생성한 process 에대해 private 이며그들의 object handle 은복제되거 나상속될수없다. 시스템은세가지종류의 object들을제공한다. User, graphics device interface (GDI), kernel. 시스템은윈도우관리를위해 user object를, 그래픽을지원하기위해 GDI object를, 메모리관리, process 실행, Interprocess communications (IPC) 를위해 kernel object를사용한다. 각 object 들을나열하면아래와같다. User object Accelerator table Caret Cursor DDE conversation Hook 0

Icon Menu Window Windows position 표 4. User Object GDI object Bitmap Brush DC Enhanced metafile Enhanced-metafile DC Font Memory DC Metafile Metafile DC Palette Pen and extended pen Region 표 5. GDI Object Kernel object Access token Change notification Communications device Console input Console screen buffer Desktop Event Event log File File mapping Heap Job Mailslot Module 1

Mutex Pipe Process Semaphore Socket Thread Timer Timer queue Timer-queue timer Update resource Window station 표 6. Kernel Object 2

1.2. User Object User interface object는 object 당하나의 handle만을지원한다. Process들은 user object의 handle을상속하거나복제할수없으며한세션안의 Process들은다른세션의 user handle을참조할수없다. 이론적으로하나의세션당 65,536개의 user handle을가질수있다. 그러나하나의세션당열수있는 user handle의최대개수는사용가능한메모리에의해영향을받기때문에일반적으로이보다작다. Process 당 user handle의수도역시제한되어있다. 이값을변경하려면아래의레지스트리값을 200에서 18,000 사이의값으로수정하면된다. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERProcessHandleQuota 표 7. User Handle 개수수정레지스트리 User object의 handle은모든 process들에대해 public 하다. 즉, object에대해보안접근을가지는조건을만족하는어떤 process도 user object handle을사용할수있다. 아래는 application이 window object를생성하는것을보여준다. CreateWindow 함수는 window object를생성하고 object handle를반환한다. 그림 1. CreateWindow Window object가생성된후 application은 window를보여주거나변화시키기위해 window handle 을사용할수있다. Handle은 window object가파괴되기전까지유효하다. 아래는 application이 window object를파괴하는것을보여준다. DestoryWindow 함수는메모리로부터 window object를제거하고 window handle를무효로처리한다. 그림 2. DestoryWindow 3

1.3. GDI Object GDI object는 object 당하나의 handle만을지원한다. GDI object의 handle들은 process에대해 private하다. 즉, GDI object를생성한 Process만이 object handle을사용할수있다. 이론적으로하나의세션당 65,536개의 GDI handle을가질수있다. 그러나하나의세션당열수있는 GDI handle의최대개수는사용가능한메모리에의해영향을받기때문에일반적으로이보다작다. Windows 2000은 16,384개로제한되어있다. Process 당 GDI handle의수도역시제한되어있다. 이값을변경하려면아래의레지스트리값을 256에서 65,536 사이의값으로수정하면된다. (Windows 2000은이값을 256에서 16,384사이의값으로수정한다 ) HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota 표 8. GDI Handle 개수조정레지스트리 4

1.4. Kernel Object Kernel object handle들은 process와특별한관계에있다. 즉, process는 kernel object handle을얻기위해 object를생성하거나존재하는 object를열어야만한다. 한개의 process 당 kernel handle의수는 2^24개로제한되어있다. 그러나 handle은 paged pool에저장되기때문에생성가능한실제 handle의수는사용가능한메모리에의존한다. 32비트 windows에서생성가능한 handle의수는 2^24개보다작다. object의이름을알고있고 object에대해보안접근을가지는조건을만족하는어떤 process도존재하는 kernel object( 비록다른 process에의해생성된것이라할지라도 ) 에대해새로운 handle을생성할수있다. Kernel object handle은 process에허가되거나거절될수있는행동을나타내는접근권한을가지고있다. Application은 object를생성하거나존재하는 object handle을얻을때접근권한을열거한다. 각타입의 kernel object는자신의접근권한집합을제공한다. 예를들어 event handle은 set 또는 wait access( 또는둘다 ) 를가지고 file handle은 read 또는 write( 또는둘다 ) 를가지는식이다. 더자세한정보는 msdn의 Securable Objects를참고하라. 아래는 application 이 event object 를생성하는것을보여준다. CreateEvent 함수는 event object 를생성하고 object handle 을반환한다. 그림 3. CreateEvent Event object가생성된후 application은 event를 set 또는 wait하는 event handle을사용할수있다. Handle은 application이닫거나파괴하기전까지유효한상태를유지한다. 대부분의 kernel object들은하나의 object에대해여러개의 handle을지원한다. 예를들어앞의그림의 application은 OpenEvent 함수를사용하여추가적으로 event object handle를얻을수있으며다음그림은이것을보여준다. 5

그림 4. OpenEvent 이방법은 application이서로다른접근권한이설정된 handle들을가지는것을가능하게한다. 예를들어 handle1은 event에대해 set과 wait access를가지고있고, handle2는오직 wait access 만을가지고있다. 만약다른 Process가 event name을알고 object에대해보안접근을가지고있을경우 OpenEvent 함수를사용하여 object handle를생성할수있다. Application은 DuplicateHandles 함수를사용해서같은 Process 또는다른 Process 내의 handle을복제할수있다. Object는적어도하나의 object handle이존재하는동안메모리안에서유지된다. 다음은 application이 CloseHandle 함수를사용하여 event object handle을닫는것을보여준다. 어떤 event handle도없을때, 시스템은메모리로부터 object를제거하며아래그림은이것을보여주고있다. 그림 5. CloseHandle 시스템은다른 kernel object로부터다소다르게 file object를관리한다. File object는 file 안을읽거나쓸다음바이트를가리키는 file pointer를포함하고있다. Application이새로운 file handle을생성할때마다, 시스템은새로운 file object를생성한다. 따라서 disk의한개 file에대해하나이상의 file object가참조할수있으며아래는이것을보여준다. 6

그림 6. Multiple File Object for File on Disk 오직복제나상속을통해서만동일한 file object 에대해하나이상의 file handle 가참조할수있으며 다음은이것을보여준다. 그림 7. Multiple File Handle for File Object 7

1.5. Windows Kernel-Mode Object Manager Windows Kernel-mode object manager은 Kernel mode에서 object로표현되는파일, 디바이스, 동기화매커니즘, 레지스트리키와같은 object들을관리하며각 object들은 header( 이름, 종류, 위치와같은 object에대한정보를포함하는 ) 와 body(object의각 type에의해구분되는형식안에포함된정보를가지는 ) 를가진다. Windows는 25개이상의 object 종류를가지며그중의일부는아래와같다. Files Devices Threads Processes Events Mutexes Semaphores Registry keys Jobs Sections Access tokens Symbolic links 표 9. Windows Objects Object manager는아래의중요한 task들을수행함으로써 Windows 내의 object들을관리한다. Object들의생성과파괴를관리 Object 정보트래킹을위한 object 네임스페이스데이터베이스유지 각 Process에매치된 resource들의 track 유지 보안제공을위한특정 object들에대한접근권한트래킹 Object가자동으로 resource space 재순환을위해 object가자동으로파괴될때 object의생명주기를관리 / 결정표 10. Object 관리를위한 task 더자세한내용은 Device Objects and Device Stacks 를참고한다. (http://msdn.microsoft.com/en-us/library/ms794703.aspx) Object manager 에 direct interface 를제공하는 routine 들은 ObGetObjectSecurity 와같이일반적 으로 Ob 로시작된다. Object manager routine 들의목록을 Object Manager Routines 에서확인할 수있다.( http://msdn.microsoft.com/en-us/library/ms802946.aspx) 8

Windows는 object를 resource들의추상적인개념으로써사용한다. 그러나 Windows는전통적인 C++ 에서추상화가의미하는것처럼객체지향적인것은아니다. Windows의객체기반의의미가무엇인지에대한정보는 Object-Based에서확인할수있다. (http://msdn.microsoft.com/en-us/library/ms795051.aspx) 9

1.6. Summary 1 장에서는 Window Object 와 Window Handle 의개념과그관계에대해알아보았습니다. 1 장의내 용을요약하면아래와같습니다. 1 Windows에서제공하는 System Resource들은 Object로구성되어있다. 2 Object는 header와 body로구성되어있으며모든 object들은동일한구조를가지고있기때문에하나의 object manager가모든 object들을관리한다. 3 Object Manager는 System Resource에접근하는 Process들을제어하며여러 task들을이용해서 Windows 내의 object들을관리한다. 4 Windows는 User object, GDI object, Kernel object의 3가지종류의 object들을지원한다. 5 Application은 object에직접접근할수없으며반드시 object handle을이용해야만한다. 0

2. Process Hiding Method 이번절에서는 Process를사용자로부터감추기위해서일반적으로사용되는방법에대해알아봅니다. 실행중인 Process를감추기위한여러방법들이있지만일반적으로 SSDT Hook과 DKOM을이용한방법이널리사용되고있습니다. 1

2.1. SSDT Hook SSDT는 System Service Dispatch Table의약자로서 Windows에서이용가능한모든시스템서비스들의주소를가지고있습니다. 시스템서비스를사용하려는인터럽트가발생하면 Windows는이테이블을참고하여적절한결과값을돌려주게됩니다. SSDT Hook을이용하는 RootKit은아래그림과같이중간에서함수호출을가로채어특정명령을실행한후원래의함수를다시실행시키는것을그원리로하고있습니다. 그림 8. SSDT Hook Windows는현재시스템에서실행되고있는 Process들의목록을 Linked List 형태로관리하고있으며 EProcess 라는구조체를사용하여 Process들을관리합니다. EPROCESS의 ActiveProcessLinks 필드는 _LIST_ENTRY 구조체로되어있습니다. 이 _LIST_ENTRY 구조체의필드를이용하여 Process들의 List를만들어관리합니다. 아래의그림 9는 EProcess 구조체가가지고있는 Process 의목록들이 Linked List로연결되어있는모습을보여줍니다. 그림 9. EProcess SSDT Hook Rootkit은 NtQuerySystemInformation API를 Hook 합니다. 해당함수는 Process 리스트에서현재실행중인 Process들의리스트를불러올때사용되는함수이며 Rootkit은이함수를임의의함수로바꿔치기합니다. 아래그림은바꿔치기한 NewNtQuerySystemInformation 함수의내용입니다. 2

그림 10. NewNtQuerySystemInformation ZwQuerySystemInformation 호출이성공한후에해당 API로넘어온변수값들중 SystemInformationClass 값이 SystemProcessInformation(5) 일경우 SystemInformation 변수에 _SYSTEM_PROCESS 구조체정보가넘어오게됩니다. 해당구조체의 ProcessName 변수를검색하여특정 Process의이름이발견되면 Linked List의포인터를조작하게됩니다. 해당 Process의이름을숨긴후전체 CPU 시간의합이 100이되도록조절합니다. 아래그림은 Linked List의포인터조작을통해 Process를감추는것을보여줍니다. 3

그림 11. Hide Process with SSDT Hook SSDT Hook 을이용한 Process 감추기의자세한내용및소스는 [6] 을참고하시기바랍니다. 아래는성공적으로 notepad.exe Process 를 Process 리스트에서감추는화면입니다. 그림 12. Hide notepad.exe 4

2.2. DKOM: FU DKOM은 Direct Kernel Object Modify Manipulation의약자로써직접 Kernel Object를수정하는것을의미합니다. DKOM은 [2] 에의하면제 3세대 Rootkit 기술에속하는데이기술을사용한유명한 Rootkit 프로그램으로써 FU Rootkit이있습니다. [2] 의저자중한사람인 Butler가제작한프로그램입니다. 이 FU Rootkit이 Process를감추기위해사용하는기술은 2.1 절에서살펴보았던기술과동일합니다. 그림 13. Hide Process with DKOM 차이점이있다면 2.1은 SSDT Hook을통해 ZwQuerySystemInformation 함수가호출될때마다전달된 _SYSTEM_PROCESS 구조체의포인터를조작하지만 FU는직접 _SYSTEM_PROCESS 구조체의포인터 (PsActiveProcessList) 를조작해버립니다. 즉단한번만의실행으로임의의 Process를숨길수있습니다. FU Rootkit의여러기능들중 Process를숨기는코드는아래와같습니다. 5

그림 14. FU Rootkit 아래는 FU Rootkit 을사용하여 notepad.exe Process 를감추는화면입니다. 6

그림 15. FU Execute 빨간사각형박스안에표시되어있던 notepad.exe 가작업관리자에서도, fu 의 Process List 에서도 사라졌음을볼수있습니다. 7

2.3. DKOM: PHide2 PHide2는 90210 이라는해커에의해만들어진 Rootkit이며 Klister v0.4를우회하기위한목적으로제작되었습니다. 3.2절에서소개될 Klister v0.4의제작자인 Joanna Rutkowska은모든 Thread 들은 CPU Time을얻어야만하므로 OS는이를위한 List를가지고있어야한다고생각하였습니다. 즉, 이 List에포함되지않는 Thread는 CPU Time을얻을수없다라는것이기본적인생각이었습니다. 하지만 90210은숨겨진 Thread를위한자체 Thread Scheduler를실행함으로써 Klister v0.4를우회할수있음을증명하였습니다. 이이론의결과물이바로 PHide2 입니다. 먼저 3.2절의 Klister 를읽어보시기를권해드립니다. PHide2 를이해하기위해서는먼저 NT Scheduler 에대한지식이필요합니다. 아래는 Thread Scheduling States 를나타내는그림입니다. 그림 16. Thread Scheduling States 8

NTOSKRNL.exe의 Phase1 initialization[13] 의중간쯤에서 MmInitSystem은두개의 Thread 즉, KeBalanceSetManager과 KeSwapProcessOrStack를실행시키는데이중 KeSwapProcessOrStack 은 Process Swap Event 내에서무한루프를시작합니다 [8]. Swap Event는 KiSwapEvent에의해신호화되는데아래의 4가지종류가있습니다. outswap kernel stack: Boolean형 KiStackOutSwapRequest에의해열거됨 outswap processes: KiProcessOutSwapListHead 안에저장된 outswapping이필요한 Process들 inswap processes: KiProcessInSwapListHead 안에저장된 inswapping이필요한 Process들 inswap kernel stacks: KiStackInSwapListHead 안에저장된 inswapping이필요한스레드들 KeBalanceSetManager 역시무한루프를돌면서 MmWorkingSetManagerEvent( 메모리가충분하지않아 working set을조절할필요가있을때발생하는이벤트 ) 나 Timer 이벤트를기다립니다. Timer Event Handler는주기적으로 KiStackOutSwapRequest 값을 TRUE로설정하고오랜시간 wait 상태에있던 Thread들의 kernel stack을 outswap 해야함을 KeSwapProcessOrStack에게알리기위해서 KiSwapEvent 신호를보냅니다. 또 KeBalanceSetManager는 Ready Queue(KiDispatcherReadyListHead array) 내 Thread의우선순위를높이는 KiScanReadyQueues 를호출합니다. 이렇게우선순위가높아진각 Thread를위해 KiReadyThread가호출되고 PRCB.NextThread 1 는즉시우선순위가높아진 Thread로설정됩니다 (KiReadyThread는원래의 NextThread를선점합니다 ). /****** Balance Set Manager의역할은 Ready 대기열을검사하여, Ready 상태에서약 4초이상가만히있는채실행되지못하고있는 Thread가있는지를검사하여해당 Thread의우선순위를올립니다. 실제 Balance Set Manager가동작할때마다모든 Ready 상태의 Thread를검사하지는않고 CPU 사용을최소화하기위해 16개씩만검사하고, 한번에열개의 Thread만우선순위를올립니다. ******/ 1 PRCB: 중지된프로세서에대한프로세서컨텍스트 9

그림 17. Thread Scheduling 1 KeUpdateSystemTime 은 Timer interrupt handler 에의해 hal 로부터직접적으로호출됩니다. 그리 고바로현재 Thread 의실행시간및현재 Thread 의 Process 실행시간을업데이트하고현재 Thread 의 퀀텀 (quantum) 2 을감소시키기위해서 KeUpdateRunTime 을호출합니다. KeUpdateRunTime이실행되어현재 Thread가 Idle Thread가아니고, 퀀텀도다소비하게될때 Dispatch interrupt 해제에의해 Thread는퀀텀종료를요청합니다. KiDispatchInterrupt는퀀텀종료가요청되고 PRCB.NextThread가이미선택되었는지검사합니다. 만약그렇다면, KiDispatchInterrupt는 PRCB.CurrentThread를 PRCB.NextThread로, PRCB.NextThread를 0으로설정하고 KiReadyThread를호출함으로써 PRCB.CurrentThread의실행을기다립니다. KiReadyThread는 Thread의 Process 상태를검사하고만약 Process가 outswap 되었다면해당 Process의메모리를 inswap 합니다 (KiProcessInSwapListHead에 Process를삽입하고 KiSwapEvent 신호를보냅니다 ). 만약 Thread의 Kernel Stack이상주하고있지않다면, KiReadyThread는해당 Thread를 KiStackInSwapListHead에넣고 Thread의 Kernel Stack을 inswap 하기위해 KiSwapEvent 신호를보냅니다. 만약 Thread의 Process memory와 Thread의 Kernel Stack이상주하고있지않다면, KiReadyThread는 Idle Processor를찾습니다. 그리고만약적어도한개의 Idle Processor가있다면 KiReadyThread는각 PRCB의 NextThread를 specified Thread로설정합니다. 만약여러개의 Idle Processor가있다면가장적합한것이 Thread의이상적인 Processor로주어지게됩니다. 만약어떤 Idle Processor도없다면 IdelProcessorPRCB.NextThread의우선권을검사합니다. 만약 IdelProcessorPRCB.NextThread를선점할수있다면 (specified Thread는높은우선순위를가지고있습니다 ), KiReadyThread는 IdelProcessorPRCB.NextThread를 specified Thread로설정합니다. 만약 IdelprocessorPRCB.NectThread가설정되어있지않다면 KiReadyThread는 IdelProcessorPRCB.CurrentThread가선점할수있는지를검사합니다. 만약가능하다면, 2 퀀텀 (Quantum): Windows 가같은우선순위의다른 Thread 가실행되기를기다리고있는지를확인할때까지 Thread 가실행되도록주어진시간단위를뜻함 0

NextThread는 specified Thread로설정되고 Dispatch Interrupt는재요청됩니다. 만약어떤 Thread도선점할수없다면 KiReadyThread는 Thread를해당 Thread의우선순위에의해선택된 dispatcher queue(kidispatcherreadylisthead) 에넣고이우선순위배열이비어있지않음을가리키기위해각각의 KiReadySummary bit를수정합니다. Thread가준비완료된후에 KiDispatchInterrupt는 SwapContext를호출하고 SwapContext는한 Thread에서다음 Thread로 Context를 Swap 하게됩니다. 그림 18. Thread Scheduling 2 지금까지 NT Scheduler의 Scheduling에대한내용을간단히설명하였습니다. 다시 PHide2로돌아가보면 PHide2는 Klister v0.4가검사하는 KiWaitInListHead, KiWaitOutListHead, KiDispatcherReadyListHead로부터임의의 Thread를제외시키는것을목적으로하고있습니다. 하지만 Thread를제외시켰을경우 Quantum을주기위해 KiReadyThread를호출한다면여러가지문제를발생시키게됩니다. PHide2는새로운 Thread List를생성하여제외시킨 Thread를새로운 List 로이동시키고이 Thread들을관리하기위해원본스케쥴러의복사본인새로운스케쥴러를생성합니다. 또 Quantum을조정하기위해 NtYieldExecution을수정하고 Hidden Thread의 Kernel Stack을 inswap하는것을제어하기위해 Balance Manager도수정합니다. 위의목적을달성하기위해아래의포인터들은 NtYieldExecution, KeBalanceSetManager, KeSwapProcessOrStack 내의실행트리내에서패치되어야만합니다. 1

( 괄호안은해당포인터의자료형을나타냅니다. Windows 2000 의자료형을기준으로하였습니다. XP 는 [8] 을참고하시기바랍니다.) KiDispatcherReadyListHead (32개의 LIST_ENTRY 배열, Flink와 Blink를패치 ) KiWaitInListHead (LIST_ENTRY) KiWaitOutListHead (LIST_ENTRY) KiStackInSwapListHead (LIST_ENTRY) KiProcessInSwapListHead (LIST_ENTRY) KiProcessOutSwapListHead (LIST_ENTRY) KiReadySummary (ULONG) KiReadyQueueIndex (ULONG) KiStackOutSwapRequest (BOOLEAN) KiSwapEvent (KEVENT) KiSwappingThread (PTHREAD) 또, 새로운스케쥴러를온라인이되도록하기위해아래의 4가지추가작업이필요합니다. KeBalanceSetManager 패치 KeSwapProcessOrStack 패치 주기적으로 Hidden Object(Thread 혹은 Process) 를원본리스트로부터제거하여새로운리스트에삽입 Hidden Thread에 Quantum을할당하기위해주기적으로패치된 NtYieldExecution을호출 아래는 PHide2 소스중 Process 를감추는함수입니다. 2

그림 19. ProcessHide-1 ProcessHide 함수는 ISPROCESSHIDDEN_CALLBACK 형변수를전달받는데이변수를이용하여숨길 Process의 EPROCESS 구조체의포인터를전달합니다. 그리고 KeInitalizeEvent로 Kernel Mode Event Object를하나생성합니다. 일반적으로 Driver에서는 NotificationEvent Type의이벤트를생성합니다. 해당함수의자세한내용은 MSDN(http://msdn.microsoft.com/en-us/library/ms801952.aspx) 을참고하시기바랍니다. 이벤트생성후 KeInitializeTimer 함수를사용하여두개의타이머객체를초기화합니다. 바로아래의 PrepareOsSpecificStuff() 함수는프로그램을실행한 OS 버전을탐지하여각버전별맞는 EPROCESS, ETHREAD 필드의 offset을설정합니다. 그림 20. ProcessHide-2 MapNtoskrnlImage() 함수는 VICE 와동일하게 Module List 에서 ntoskrnl.exe 를찾습니다. 이함수 3

는 pallout.c에정의되어있는데 Module List에서 ntoskrnl.exe의시작주소와 Page Section을읽어옵니다. 이후얻어온 Page Section을이용해 KiReadyQueueIndex, PsLists, NtYieldExecution, KiReadyQueueIndex, PsLists, BalmgrThreads 등의필요한 Symbol 찾는 FindWantedSymbols() 함수를실행합니다. 찾아야할 Symbol은 phide2.c에아래와같이정의되어있습니다. 그림 21. WantedSymbols 이제찾아야할각 Symbol 의정보를 Import, ListsRVAs 배열에저장합니다. OS Version 에맞게적 당한정보를저장합니다. 그림 22. ProcessHide-3 다음으로새로운스케쥴러 Thread 를생성하고실행시킵니다. 4

그림 23. ProcessHide-4 이후앞에서구해진 Code Section 의 KeBalanceSetManager Thread 와 KeSwapProcessOrStack Thread 를실행시킵니다. 그림 24. ProcessHide-5 좀더자세하게소스설명을하고싶지만소스분석이저의능력을벗어나버려서이정도에서마쳐야 할것같습니다. PHide2 의타겟인 Klister 가 Windows 2000 에서만작동하기때문에실제로 Klister 5

를우회하는지에대한테스트는실행해보지못하였습니다.(Windows 2000 이없습니다 -_-;) PHide2 는바이너리파일을제공하지않고 API 형태로쓸수있도록소스를제공하고있습니다. 소스 내 samples 디렉토리에자세한사용법이나와있으니참고하시기바랍니다. 6

2.4. DKOM: FUTo FUTo는유명한 CHAOS 그룹의 Peter Silberman이개발한 Rootkit으로서기존 FU의후속버전입니다. FU의 DKOM 기술을이용한 Rootkit들을탐지하기위한방법들이 Blacklight나 IceSword에탑재되자이들을다시우회하기위해만들어진것이바로 FUTo입니다. FUTo 부분을읽기전에먼저 3.4 절의 Blacklight 부분을읽어보실것을권합니다. 3.4절에서볼수있듯이 FU는 PsActiveProcessList를조작하여 Process를숨기지만 Blacklight는모든 Process의정보를가지고있는또다른 Table인 PspCidTable을이용하여 Hidden Process를찾아냅니다. FUTo는 PspCidTable에서도임의의 Process를제거하여 Blacklight를우회하는방법을사용합니다. PspCidTable은 non-exported symbol이지만 exported symbol인 ExMapHandleToPointer API의첫번째파라미터로전달되기때문에이를이용해서접근하는것이가능합니다. 다른방법으로 Opc0de가제시한 KDDEBUGGER_DATA32 구조체를이용할수있습니다. 해당구조체에는 PspCidTable, PspActiveProcessHead 등많은유용한변수들이정의되어있습니다. 해당변수들을사용하기위한예제코드는아래와같습니다. (http://forum.sysinternals.com/forum_posts.asp?tid=11004&pid=75859) FORCEINLINE PKDDEBUGGER_DATA32 NTAPI KeGetCurrentDBGKD (VOID) { PKPCR p1 = KeGetPcr(); if (p1) return (PKDDEBUGGER_DATA32)p1->KdVersionBlock; }; void ListDbgData(PVOID param) { printf("currentprocessornumber %lx", KeGetCurrentProcessorNumber()); PKDDEBUGGER_DATA32 p1 = KeGetCurrentDBGKD(); printf("kdversiondata -> %p", p1); if (p1 && MmIsAddressValid(p1)) { printf("no. of CPU's -> %ld", KeNumberProcessors); printf("kernbase -> %p", p1->kernbase); printf("psloadedmodulelist -> %p", p1->psloadedmodulelist); printf("psactiveprocesshead -> %p", p1->psactiveprocesshead); printf("pspcidtable -> %p", p1->pspcidtable); }; }; 7

typedef struct _DBGKD_DEBUG_DATA_HEADER32 { LIST_ENTRY32 List; ULONG OwnerTag; ULONG Size; } DBGKD_DEBUG_DATA_HEADER32, *PDBGKD_DEBUG_DATA_HEADER32; typedef struct _KDDEBUGGER_DATA32 { // unknown 제외 ULONG Unknown1[12]; DBGKD_DEBUG_DATA_HEADER32 Header; ULONG KernBase; ULONG BreakpointWithStatus; // address of breakpoint ULONG SavedContext; USHORT ThCallbackStack; // offset in thread data USHORT NextCallback; // saved pointer to next callback frame USHORT FramePointer; // saved frame pointer USHORT PaeEnabled:1; ULONG KiCallUserMode; // kernel routine ULONG KeUserCallbackDispatcher; // address in ntdll ULONG PsLoadedModuleList; ULONG PsActiveProcessHead; ULONG PspCidTable; ULONG ExpSystemResourcesList; ULONG ExpPagedPoolDescriptor; ULONG ExpNumberOfPagedPools; ULONG KeTimeIncrement; ULONG KeBugCheckCallbackListHead; ULONG KiBugcheckData; ULONG IopErrorLogListHead; ULONG ObpRootDirectoryObject; ULONG ObpTypeObjectType; ULONG MmSystemCacheStart; ULONG MmSystemCacheEnd; ULONG MmSystemCacheWs; ULONG MmPfnDatabase; ULONG MmSystemPtesStart; ULONG MmSystemPtesEnd; ULONG MmSubsectionBase; ULONG MmNumberOfPagingFiles; ULONG MmLowestPhysicalPage; ULONG MmHighestPhysicalPage; ULONG MmNumberOfPhysicalPages; 8

ULONG MmMaximumNonPagedPoolInBytes; ULONG MmNonPagedSystemStart; ULONG MmNonPagedPoolStart; ULONG MmNonPagedPoolEnd; ULONG MmPagedPoolStart; ULONG MmPagedPoolEnd; ULONG MmPagedPoolInformation; ULONG MmPageSize; ULONG MmSizeOfPagedPoolInBytes; ULONG MmTotalCommitLimit; ULONG MmTotalCommittedPages; ULONG MmSharedCommit; ULONG MmDriverCommit; ULONG MmProcessCommit; ULONG MmPagedPoolCommit; ULONG MmZeroedPageListHead; ULONG MmFreePageListHead; ULONG MmStandbyPageListHead; ULONG MmModifiedPageListHead; ULONG MmModifiedNoWritePageListHead; ULONG MmAvailablePages; ULONG MmResidentAvailablePages; ULONG PoolTrackTable; ULONG NonPagedPoolDescriptor; ULONG MmHighestUserAddress; ULONG MmSystemRangeStart; ULONG MmUserProbeAddress; ULONG KdPrintCircularBuffer; ULONG KdPrintCircularBufferEnd; ULONG KdPrintWritePointer; ULONG KdPrintRolloverCount; ULONG MmLoadedUserImageList; } KDDEBUGGER_DATA32, *PKDDEBUGGER_DATA32; 이렇게 PspCidTable에접근한후이제임의의 Process를해당 Table에서제외시켜야하는데, PspCidTable에저장되는 Process들의정보는 HANDLE_ENTRY형구조체이므로해당구조체가 NULL로대치됩니다. 이로인해 Hidden Process가닫힐때문제가발생하게됩니다. System이 Process를닫으려고시도할때 System은 PspCidTable을참조하여 NULL object를 Dereference 하려는시도를하게되고이것은 Blue Screen의원인이됩니다. FUTo는이를해결하기위해 PsSetCreateProcessNotifyRoutine를사용합니다. 이 API는 Process가생성되거나삭제될때 9

callback 됩니다. 즉 Hidden Process 가 Termination 되기전에 callback 됩니다. 따라서 FUTo 는 HANDLE_ENTRY 의값을저장해놓은뒤 Process 가 close 되기전이값을복구하여정상적으로 dereference 가되도록하는방법을사용합니다. 0

2.5. Summary 2 장에서는 Process 를감추는기술과해당기술을이용하는몇몇잘알려진 Rootkit 에대하여알아보 았습니다. 2 장에소개된 Process 를감추는기술과 Rootkit 을요약하면아래와같습니다. 1 Process를감추는기술에는여러가지종류가있으나최근에는 SSDT Hook과 DKOM을이용한 Kernel Level에서의조작기술이많이사용되고있다. 2 FU는 DKOM을이용하여 _SYSTEM_PROCESS 구조체의포인터를조작함으로써 Process를감추는방법을사용한다. 3 PHide2는새로운스케쥴러와스레드리스트를만들어 Process를감추는방법을사용하여 Klister 를우회한다. 4 FUTo는 PspCidTable에서 Process를제외함으로써 Blacklight, icesword를우회한다. 1

3. Detect Method of Hidden Process RootKit에의해숨겨진 Process를탐지하는방법역시여러가지입니다. Anti-Rootkit이등장함에따라이를우회하기위해발전된여러 Rootkit이개발되게됩니다. 여러유명한 Anti-Rootkit 프로그램들중몇개의동작원리를알아보겠습니다. 2

3.1. VICE VICE는 James Butler가제작한 Hook Detector 도구로써 DKOM 공격기법이활성화되기전제작되었으며 IAT, SSDT, IRP, Inline Function Hook을탐지합니다. VICE는아쉽게도 Source Code를제공하지않지만 [2] 에제시된 Code가 SSDT Hook을 Detect 하는코드와유사할것이라고추측할수있습니다. [2] 에제시된 SSDT Hook Detect Code는아래와같습니다. #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; unsigned int NumberOfServices; unsigned char *ParamTableBase; } SDTEntry_t; typedef struct _NTOSKRNL { DWORD Base; DWORD End; } NTOSKRNL, *PNTOSKRNL; typedef struct _MODULE_INFO { DWORD d_reserved1; DWORD d_reserved2; PVOID p_base; DWORD d_size; DWORD d_flags; WORD w_index; WORD w_rank; WORD w_loadcount; WORD w_nameoffset; WORD a_bpath[maximum_filename_length]; } MODULE_INFO, *PMODULE_INFO, **PPMODULE_INFO; typedef struct _MODULE_LIST { int d_modules; MODULE_INFO a_modules []; } MODULE_LIST, *PMODULE_LIST, **PPMODULE_LIST; #pragma pack() PMODULE_LIST g_pml; NTOSKRNL g_ntoskrnl; // Import KeServiceDescriptorTable from notskrnl.exe declspec(dllimport) SDTEntry_t KeServiceDescriptorTable; 3

PMODULE_LIST GetListOfModules(void); void IdentifySSDTHooks(void); NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { int count; g_pml = NULL; g_ntoskrnl.base = 0; g_ntoskrnl.end = 0; g_pml = GetListOfModules(); if(!g_pml) return STATUS_UNSUCCESSFUL; for(count=0; count < g_pml->d_modules; count++) { // ntoskrnl.exe를찾는다 if(_stricmp("ntoskrnl.exe", g_pml->a_modules[count].a_bpath + g_pml- >a_modules[count].w_nameoffset) == 0) { g_ntoskrnl.base = (DWORD)g_pml->a_Modules[count].p_Base; g_ntoskrnl.end = ((DWORD)g_pml->a_Modules[count].p_Base + g_pml- >a_modules[count].d_size); } } ExFreePool(g_pml); if(g_ntoskrnl.base!= 0) return STATUS_SUCCESS; else return STATUS_UNSUCCESSFUL; } PMODULE_LIST GetListOfModules(void) { ULONG ul_neededsize; ULONG *pul_modulelistaddress = NULL; NTSTATUS ns; PMODULE_LIST pml = NULL; // 모듈정보를저장하기위한메모리크기를구하는호출 ZwQuerySystemInformation(SystemModuleInformation, &ul_neededsize, 0, &ul_neededsize); pul_modulelistaddress = (ULONG *)ExAllocatePool(PagedPool, ul_neededsize); 4

if(!pul_modulelistaddress) return (PMODULE_LIST)pul_ModuleListAddress; ns = ZwQuerySystemInformation(SystemModuleInformation, pul_modulelistaddress, ul_neededsize, 0); if(ns!= STATUS_SUCCESS) { // 할당한커널메모리를해제한다 ExFreePool((PVOID)pul_ModuleListAddress); return NULL; } pml = (PMODULE_LIST)pul_ModuleListAddress; } return pml; void IdentifySSDTHooks(void) { int i; for(i=0; i < KeServiceDescriptorTable.NumberOfServices; i++) { if( (KeServiceDescriptorTable.ServiceTableBase[i] < g_ntoskrnl.base) (KeServiceDescriptorTable.ServiceTableBase[i] > g_ntoskrnl.end)) { DbgPrint("System call %d is hooked at address %x!\n", i, KeServiceDescriptorTable.ServiceCounterTableBase[i]); } } } 먼저 DriverEntry에서 GetListOfModules() 함수를이용해로드된모듈리스트를 g_pml 변수에받아옵니다. GetListOfModules() 함수는모듈리스트를얻기위해 ZwQuerySystemInformation() 함수에 SystemModuleInformation 인자를사용합니다. g_pml 변수에저장된로드된모듈의리스트들에서 ntoskrnl.exe를찾은다음해당모듈의시작주소와끝주소를저장합니다. 이후 IdentifySSDTHooks() 함수에서 SSDT의각함수들의 Base 주소가 ntoskrnl.exe의주소범위내에있는지를탐색합니다. 아래는 VICE의 Driver 파일인 VICESYS.sys를리버싱한화면입니다. 5

그림 25. VICESYS.sys 1 그림에서볼수있듯이 notskrnl.exe 를 Module List 에서찾습니다. Ntoskrnl.exe 를찾으면 loc_11538 로 jump 합니다. 아래는 loc_11538 부분입니다. 그림 26. VICESYS.sys 2 위그림은 ntoskrnl.exe 의 Base 주소와 End 주소를저장하는것을나타냅니다. 여기까지보면 VICE 가앞장에제시된소스코드와동일한기능을한다는것을알수있습니다. 아래는 [6] 의 SSDT Hook 을이용해 notepad.exe Process 를감춘후 VICE 로탐지하는것을나타내 는그림입니다. 6

그림 27. SSDT Detect with VICE 그림에서볼수있듯이 VICE 는 Rootkit 에대한상세한정보를가능한한자세히제공함으로써관리 자들이 Rootkit 을제거하기쉽도록하고있습니다. 하지만아래그림에서볼수있듯이 False Positive 가많은편입니다. 아래는아무것도설치되지않은상태에서 VICE 를실행한화면입니다. 7

그림 28. False Positive of VICE 또 FU Rootkit 처럼 DKOM 을이용한 Rootkit 은탐지하지못함을아래에서확인할수있습니다. 8

그림 29. FU 위의그림은 FU 를이용해서 notepad.exe Process 를숨긴화면입니다. 9

그림 30. VICE with FU Rootkit 위의그림에서볼수있듯이 VICE 는 DKOM Rootkit 을탐지할수없습니다. 0

3.2. Klister Klister는 PatchFinder를제안한 Joanna Rutkowska의또다른 Anti-Rootkit 도구입니다 (Joanna Rutkowska는요즘 Bluepill이라는 Virtualization Rootkit Project를진행하고있습니다 ). Klister는 2.2에서소개한 FU Rootkit 같이 DKOM을이용하는 Rootkit을탐지하기위한목적으로제작되었습니다. Process를감추기위하여 DKOM을조작하는 Rootkit들은일반적으로 PsActiveProcessList에서특정 Process의 EProcess를 unlink 하는방법을사용합니다. Joanna Rutkowska는 Process List 에서특정 Process에대한 link를제거했음에도불구하고해당 Process가정상적으로작동하는것에착안을하였습니다 ( 사실은 Klister v0.3에서의실수입니다 ). Process는 Resource와 Context만제공할뿐실제로실행되는것은 Process가아닌 Thread라고봐도무방하므로이 Thread들은실행상태로진입하기위해반드시 OS로부터 CPU Time을할당받아야만합니다. 즉, OS Dispatcher는 Process List에관계없이 Thread들을 Scheduling 하기위한 List를가지고있으며이 Thread를이용해서 Process List를재구성할수있을것이다라는것이 Joanna Rutkowska의생각이었습니다. 그러므로 PsActiveProcessList에의해구성된 Process List와 Thread로부터재구성된 Process List 를비교하면 Rootkit에의해숨겨진 Process를탐지하는것이가능해집니다. Klister는오직 Windows 2000에서만사용할수있는데 KiWaitInListHead, KiWaitOutListHead, KiDispatcherReadyListHead 자료구조로부터존재하는 Thread를목록화하기때문입니다. (XP에는 KiWaitListHead, KiDispatcherReadyListHead 두개의자료구조만이존재합니다 [12]) KiDispatcherReadyListHead Windows 2000 에서 Thread 는아래그림과같이 7 개의상태를가지게됩니다. 그림 31. State of Thread 또한 Thread는 Windows가제공하는 0부터 31까지의총 32개의우선순위를가지며아래그림과같이각각의값은 3개로구분됩니다. - 16개의실시간수준 : 16 ~ 31-15개의가변수준 : 1 ~ 15 1

- 하나의시스템수준 : 0 ( 제로페이지 Thread 를위해예약됨 ) 그림 32. Priority of Thread 다음그림과같이 KiDispatcherReadyListHead 는 Ready 상태의 Thread 가가질수있는우선순 위순위 32 개에대한각각의 table 로이루어져있으며어느 Thread 를실행시키고선점시킬지를 빠르게결정하기위해 KiReadySummary 라불리는 32 비트의비트마스크를유지합니다. 그림 33. KiDispatcherReadyListHead KiReadySummary 의각각의비트가 Set 되어있다는것은이우선순위단계에하나이상의 Thread 가실행을위해대기중이라는것을의미하게됩니다. KiWaitInListHead, KiWaitOutListHead 2

이두개의자료구조는 Scheduler 가 ETHREAD 구조체의리스트를얻기위해사용되며 Wait 상 태인 Thread 의리스트를유지합니다. 이들은 export 되어있지않지만 KeWaitForSingleObject() 를이용하여주소를얻을수있습니다. 이제 Klister v0.4 의소스를살펴보겠습니다. 아래그림은 targets.h 에정의되어있는리버싱을통해구해진 Windows 2000 의버전별 KiWaitInListHead, KiWaitOutListHead, KiDispatcherReadyListHead 의주소값을보여줍니다. 그림 34. OS 버전별주소값 먼저 main.cpp 를살펴보면 klister 라는디바이스를생성합니다. 그림 35. 디바이스생성 디바이스생성후아래그림처럼 DeviceIoContol 에서 IOCTL_KLISTER_INIT 호출과함께구해진 KiWaitInListHead, KiWaitOutListHead, KiDispatcherReadyListHead 의주소값을디바이스로전달 3

합니다. 그림 36. DeviceIoControl-1 아래는 IOCTL_KLISTER_INIT 의내용입니다. 4

그림 37. IOCTL_KLISTER_INIT IOCTL_KLISTER_INIT 에서는입력버퍼를통해전달된 KiWaitInListHead, KiWaitOutListHead, KiDispatcherReadyListHead의주소값을 PKLISTER_INIT형구조체에저장한후각값들을 PLIST_ENTRY 구조체를이용해 Double Linked List로연결합니다. 그리고 KLISTER_PROCINFO형구조체변수 procs의 pid와 ServiceTableInfo형구조체변수 SrvTables의 addr을 0으로초기화합니다. 사용된 KLISTER_PROCINFO, ServiceTableInfo 구조체는아래와같습니다. typedef struct _KLISTER_PROCINFO { int pid; int obaddr; char name [18]; } KLISTER_PROCINFO, *PKLISTER_PROCINFO; typedef struct _ServiceTableInfo { int addr; 5

int n; // size of the table int nthreads; // how many threads are using this table } ServiceTableInfo; 표 11. KLISTER_PROCINFO, ServiceTableInfo 구조체 IOCTL_KLISTER_INIT 이끝나면 main.cpp 에서 IOCTL_KLISTER_LISTPROC 를호출합니다. 그림 38. DeviceIoControl-2 아래는 IOCTL_KLISTER_LISTPROC 의내용입니다. 그림 39. IOCTL_KLISTER_LISTPROC IOCTL_KLISTER_LISTPROC 는 createproclist 함수를호출합니다. 6

그림 40. createproclist() 위의그림에서볼수있듯이 createproclist 함수는 3개의 for 문을가지고있는데 Double Linked List로연결된각 KiWaitInListHead, KiWaitOutListHead, KiDispatcherReadyListHead 들을한바퀴돌때까지순환하면서 insertservtable() 함수와 insertproc() 함수를호출합니다. insertproc() 함수에서는 PETHREAD형 pethread 변수를인자로하여 processobject() 함수를호출하는데이함수는 PETHREAD 구조체에포함되어있는 Process 정보를반환하여함수내용은아래와같습니다. PEPROCESS processobject (PETHREAD ethread) { return (PEPROCESS)(ethread->Tcb.ApcState.Process); } 표 12. processobject() insertservtable 함수는인자로넘어온값들, 즉 Thread 의 Cid.UniqueThread, Tcb.pServiceDescriptorTable->ntoskrnl.ServiceTable, Tcb.pServiceDescriptorTable- >ntoskrnl.servicelimit 값을저장합니다. 7

그림 41. insertservtable() 위에서사용된 ServiceTableInfo 구조체는아래와같습니다. typedef struct _ServiceTableInfo { int addr; int n; int nthreads; // size of the table // how many threads are using this table } ServiceTableInfo; 표 13. ServiceTableInfo 구조체 또, insertproc 함수는인자로전달된 PEPROCESS 구조체의주소와 UniqueProcessId, ImageFileName 값을저장합니다. 그림 42. insertproc() 위에서사용된 KLISTER_PROCINFO 구조체변수 procs 의내용은아래와같습니다. 8

typedef struct _KLISTER_PROCINFO { int pid; int obaddr; char name [18]; } KLISTER_PROCINFO, *PKLISTER_PROCINFO; 표 14. KLISTER_PROCINFO 구조체 자, 여기까지오면 CPU의자원을기다리고있는모든 Thread와해당 Thread에연결되어있는 Process의리스트를목록화하게됩니다. 이제 PsActiveProcessList 를통해목록화한 Process의리스트와비교하여숨겨진 Process를찾을수있습니다. Klister에는이외에도 IDT, SDT 관련기능들이더있는데이부분은 v0.2 이후업데이트된적이없으므로생략하도록하겠습니다. 9

3.3. BlackLight F-Secure에서제작한 Blacklight는숨겨진 Process를찾기위해 Anti-Rootkit으로서는드물게 User Mode에서작동합니다. User Mode에서 Process List를얻기위해서 ToolHelp API를이용하는법, ZwQuerySystemInformation API를이용하는법 (Driver를이용하므로 User Mode라고단언하기는힘듬 ), Open된 Handle list를이용하는법 (ZwQuerySystemInformation API를이용함 ), GetWindowThreadProcessId API를이용하는법, 연관된 Handle을분석하는방법등매우다양한방법을이용합니다 [11]. 여기서는 [5] 에서소개된숨겨진 Process를찾는방법을알아보도록하겠습니다. [5] 가발표될당시버전의 BlackLight는숨겨진 Process 를찾기위해 0x0에서 0x4E1C 까지 PID를 BruteForce 하여 OpenProcess API를호출하고, 이 list와 CreateToolhelp32Snapshot API 를호출하여얻어진 Process list를서로비교합니다. [6] 에서볼수있듯이 CreateToolhelp32Snapshot는 PsActiveProcesslist 로부터 Process 정보를가져옵니다. OpenProcess는 NtOpenProcess의 wrapper이며이 NtOpenProcess는 PID가주어졌을때 PsActiveProcesslist 와는다른자료구조를통해 Process 정보를가져옵니다. NtOpenProcess는 PsLookupProcessByProcessId를호출하여해당 PID를가진 Process가존재하는지검증합니다. PsLookupProcessByProcessId는아래와같습니다. 그림 43. PsLookupProcessByProcessId 빨간박스에서볼수있듯이 PsLookupProcessByProcessId는 PspCidTable이라는테이블을참조합니다. PspCidTable은 Process와 Thread client ID에대한정보를가지는 HANDLE_TABLE 구조체형테이블이며모든 Process에대한정보를가집니다. 지금까지알아본 Blacklight의숨겨진 Process를찾는단계는아래와같습니다. 1 0부터 0x41DC까지의값을 PID로하여 OpenProcess를호출 2 OpenProcess는 NtOpenProcess를호출 3 NtOpenProcess는 PsLookupProcessByProcessId 호출 4 PsLookupProcessByProcessId는 PspCidTable에서해당 PID를가지는 Process있는지를검사 5 NtOpenProcess는 ObOpenObjectByPointer를호출하여해당 Process의핸들을가져옴 0

6 loop 의끝에도달할때까지존재하는 Process 의정보를저장 7 CreateToolhelp32Snapshot 를호출하여얻은 Process 의목록과비교하여숨겨진 Process 를찾음 아래그림은 FU 를이용해 cmd.exe Process 를숨긴것을보여줍니다.. 그림 44. Hide cmd.exe with FU 아래그림은 Blacklight 를이용해숨겨진 cmd.exe 를발견하는것을보여줍니다. 그림 45. Balcklight 결과 1 1

그림 46. Blacklight 결과 2 2

3.4. Summary 3장에서는 Hidden Process를발견하는기술과해당기술을이용하는몇몇잘알려진 Anti Rootkit에대하여알아보았습니다. 3장에소개된 Hidden Process를발견하는기술과 Anti Rootkit을요약하면아래와같습니다. 1 VICE는메모리에서 ntoskrnl.exe 를찾아 SSDT의각함수들의 Base 주소가 ntoskrnl.exe의주소범위내에있는지를체크함으로써 SSDT Hook이발생했는지를탐지한다. 2 Klister는 3개의 Thread 리스트로부터 Process를추적하여 PsActiveProcessList 에서제거된 Process를탐지한다. 3 Blacklight는 User Mode에서동작하며 PspCidTable에기록된모든 Process들의목록을사용하여숨겨진 Process가있는지를검사한다. 3

4. Conclusion 지금까지우리에게잘알려진몇몇 Rootkit과 Anti-Rootkit에적용된기술에대해알아보았습니다. 나름대로쉽게쓸려고노력했지만지금에와서보니기존에있던, 참고한문서들과별반다를바없는것같아실망스럽습니다. 특히 Blacklight의 Reversing과 FUTo의소스분석을자세하게넣고싶었으나본인의실력부족및흥미감소로그냥대충마무리하게되어버렸습니다. 원래목록에포함되어있다가갑작스럽게마무리하게되면서빠진부분은 RAIDE, BluePill, CheatEngine, Shadow Walker입니다. 제대로다듬지않은문장을함부로내보이게되어부끄럽기그지없습니다. 이문서를작성하던와중에갑자기흥미가든것이 이제나도제대로된무언가를만들어보아야하겠다 라는것이었습니다. 앞으로는실제개발에중점을두고공부를해나갈것같습니다. 저보다도더모르시는몇몇 Newbie 분들을위해앞으로도계속정리를해나갈생각입니다. 뽀대나는 Windows System Programmer가될때까지열심히! 4

5. 참고자료 1. Microsoft Windows Internals, Fourth Edition 2. Subverting the Windows Kernel, Greg Hoglund, James Butler 3. Handles and Objects, MSDN, Microsoft http://msdn.microsoft.com/en-us/library/ms724457(vs.85).aspx 4. Windows Kernel-Mode Object Manager, MSDN, Microsoft http://msdn.microsoft.com/en-us/library/cc264621.aspx 5. FUTo, Peter Silberman, C.H.A.O.S, Uninformed volume 3, December 2005. http://www.uninformed.org/?v=3&a=7&t=sumry 6. Hide Process, Jerald Lee. http://lucid7.egloos.com/1256444 7. RAIDE:Rootkit Analysis Identification Elimination, Silberman. http://www.blackhat.com/html/bh-europe-06/bh-eu-06-speakers.htmlsilberman 8. Bypassing Klister 0.4 with No Hooks or Running a Controlled Thread Scheduler, 90210. http://www.hi-tech.nsys.by/33/ 9. Windows rootkits of 2005, part three, James Butler, Sherri Sparks http://www.securityfocus.com/infocus/1854 10. Win2K Kernel Hidden Process/Module Checker 0.1 (Proof-Of-Concept), Tan Chew Keong. http://www.security.org.sg/code/kproccheck.html 11. Detection of the hidden processes, wasm.ru. http://blog.csdn.net/linhanshi/archive/2006/01/04/569663.aspx 12. KiWaitListHead, KiDispatcherReadyListHead, somma http://somma.egloos.com/3455583 13. eeye BootRoot: A Basis for Bootstrap-Based Windows kernel Code, Derek Soeder, Ryan 5

Permeh, eeye digital Security, BlackHat Briefings 14. Getting Kernel Variables from KdVersionBlock, Part 2, Alex Ionescu. http://www.rootkit.com/newsread.php?newsid=153 6