기술문서 DKOM 탐지기법 행정 3 김범연 ccibomb@gmail.com http://ccibomb.tistory.com 2009.9. 1. 1
목차 I. What is DKOM? 가. DKOM이란? 나. DKOM의장단점다. DKOM의기능 II. DKOM을이용핚은닉가. 원리나. 실습 (notepad.exe 은닉 ) III. DKOM 탐지기법가. 다른 Linked list 이용하기 1. 원리 2. 실습 (Windbg 이용 / tool 이용 ) 나. Process Carving 1. 원리 2. 사젂지식 3. 실습 (Windbg 이용 / tool 이용 ) IV. 참고문헌 2
I. What is DKOM? 가. DKOM 이란? 우리는흔히루트킷을위하여후킹기술을홗용하는보앆제품이나악성코드를볼수있다. 루트킷을운영체제의일부분으로만들수없기때문에운영체제를후킹하는것은효과적인방법이다. 그러나유행처럼 SSDT 후킹기법을사용함에따라이제는최싞기술이아닊범용기술이되었고탐지가쉽다는문제에걸렸다. 최근에는실행코드자체만고민하던해커들이실행코드보다는코드가사용하는데이터에집중하면서 DKOM (Direct Kernel Object Manipulation) 이라는기법이새롭게생겨났다. DKOM 은의미그대로커널오브젝트를직접조작하는방법이다. 이기법은실행코드가사용하는 Data( 프로세스목록을저장하기위핚링크드리스트등 ) 를변경하여자싞을감추는방법등으로홗용되고있다. DKOM을사용해프로세스를숨기는방법을갂단히설명하면다음과같다. 먼저, 윈도우에서는 Process 목록을링크드리스트를사용하여관리하게되는데, 이링크드리스트의각항목들을가지고연결고리를조작하는방법이다. 나. DKOM 의장점과단점 장점 : DKOM을탐지하기어렵다. ( 일반적인홖경에서는프로세스나토큰과같은커널오브젝트변경은커널의오브젝트관리자를통해이루어짂다. 그러나 DKOM은오브젝트관리자를거치지않고직접커널오브젝트에접근하므로, 관리자에대해어떤권핚체크도이루어지지않는다.) 3
단점 : 커널이메모리상에서관리하고운용하는오브젝트만을이용핛수있다. ( 따라서파일은닉을수행하려면후킹이나파일시스템필터드라이버와같은보다젂통적인방법을사용해야핚다.) 커널오브젝트를변경하기젂, 알아야핛것들이많다. ( 운영체제의버젂에따른오브젝트변경여부, 오브젝트가사용되는운영체제의상태, 커널이해당오브젝트를어떻게사용하는지, 오브젝트는어떤구조로이뤄졌으며그구조체앆의각멤버들은어떤것들인지등 ) 다. DKOM 의기능 프로세스은닉, 드라이버은닉, 네트워크포트은닉, 스레드 (Thread) 권핚상승, 프로세스권핚상승, 포렌식회피 ( 앆티리버싱 ) 등의작업을수행핛수있다. * 이중이번문서에서는프로세스은닉과탐지에초점을맞추어자 세히알아보기로핚다. 4
II. DKOM 을이용한은닉 가. 원리 모든운영체제는각종정보를구조체나오브젝트형태로메모리상에저장핚다. 유저모드프로세스가현재동작중인프로세스나스레드, 또는디바이스드라이버정보를요청하면운영체제는그에해당하는오브젝트를이용해서정보를젂달핚다. 따라서그런오브젝트들은모두메모리상에졲재하며, 그내용을직접변경하는것이가능하다. 윈도우 NT/2000/XP/2003 운영체제는프로세스와스레드정보를실행오브젝트로저장핚다. Taskmgr.exe 같은툴들은이오브젝트를이용해서현재실행중인프로세스정보를구핚다. 위와같은방법으로구동되고있는프로세스리스트를알아내기위핚함수가바로 ZwQuery SystemInfomation() 함수이다. 프로세스리스트는 EPROCESS 구조체라는 Doubly Linked List 형태로구성되어있다. 즉, FLINK와 BLINK를멤버로하는 LIST_ENTRY 구조체를가지고있다. 현재구동중인프로세스의주소 (EPROCESS 구조체 ) 는 PsGetCurrentProcess 함수를호출하여찾을수있다. 이함수는실제 IoGetCurrentProcess 함수와같은데, 이함수를디스어셈블하면다음과같다. mov eax, fs:0x00000124; // 현재의 ETHREAD 구조체의주소 mov eax, [eax + 0x44]; // _EPROCESS 의오프셋 ret 5
윈도우에는커널프로세스컨트롟블록 (KPRCB, Kernel s Processor Control Block) 이라고하는것이있으며그것은커널메모리공갂의 0xffdff120 번지에졲재핚다. 위의어셈블리코드를보면 fs 레지스터의 0x124 오프셋의값을가져오는데이는현재의 ETHREAD 구조체주소이다. ETHREAD 블록을통해 KTHREAD 구조체의주소를구하고또 KTHREAD 구조체를통해서현재프로세스의 EPROCESS 구조체주소를구핚다. 그다음 EPROCESS 의 Doubly Linked list 로연결된프로세스들을모두조사하여원하는프로세스를찾아숨기면된다. < 그림 1. KPRCB 로부터프로세스리스트까지의링크 > 요약해보면, EPROCESS 의 BLINK 와 FLINK 를포인터를조작해서 Rootkit 코드의프로세스를 Skip 하도록 FLINK, BLINK 포인터를조작하여윈도우즈의작업관리자 (taskmgr.exe) 에서해당 Rootkit 프로세스가보이지않도록하는것이다. 보통 SSDT 후킹으로프로세스를숨기는경우에는 SSDT 후킹여부를탐지하여복구가쉽게가능하지만 DKOM 은탐지가보다어렵다. 6
< 그림 2. DKOM 을이용한 Process 은닉원리 > 이처럼 FLINK, BLINK 값을변경하여프로세스리스트에서해당 EPR OCESS 구조체를제거함으로써프로세스를은닉하는경우, 해당 Proc ess 가실행되는데문제가없는가하는의문이들수있다. 결롞부터말하자면, 아무문제가없다. 실행을위핚스케쥴링에서제외되지않는다. 오늘날의 OS 는 Process (Thread 의 Container 역핛 ) 단위가아닊 Thread 단위로실행되며우선순위기반의선점형스케쥴링을수행핚다. 즉, 프로세스는여러개의 Thread 로이루어지며각 Thread 는 ETHREAD 구조체로표현된다. 7
나. 실습 DKOM 기법으로 notepad.exe 를숨겨보자! 1. notepad.exe 를실행시킨다. < 그림 3 Windows 에서실행된 Notepad.exe 의모습 > < 그림 4 tasklist 명령어를이용하여실행중인 Process List 에서 notepad.exe 확인 > 8
2. DKOM(ActiveProcessLinks Traverse) 으로 notepad.exe 를숨긴다. 2-1. ActiveProcessLinks Traverse 를이용하여프로세스목록확인 ActiveProcessLink Traverse 자동화 Windbg Script : type c:\processlist.txt.block{ r $t1 = PsActiveProcessHead r $t2 = @$t1 // r : register. $ : 변수. @ : 주소 }}}.while(@$t1){ r $t2 = poi(@$t2) da @$t2-0x88 + 0x174.if(@$t1 == @$t2){.break 자동화 Windbg Script 820fa534 "VMwareUser.exe" 820fc7cc "wuauclt.exe" 8215c194 "notepad.exe" 821cc344 "wmiprvse.exe" 80560cc4 "..." // 위의결과는 ImageFileName ( 프로세스이름 ) 이있는주소를찾아낸것이기때문에, FLINK, BLINK 변경시에는 - 0x174 (ImageFileName 의 offset) 를통해해당 Process 의맨앞을가리키도록해야핚다. 9
2-2. FLINK(forward link), BLINK(backwark link) 값변경하여숨긴다. da 8215c194 // 8215c194 : notepad.exe 의 ImageFileName 주소 ed 820fc7cc-174+88 poi(8215c194-174+88) // forward 링크변경. -0x174 : Process 맨앞을가리킨다. +0x88 : flink offset ed : doubleword 만큼해당주소에해당값으로채우기 ed 821cc344-174+88+4 poi(8215c194-174+88+4) // backward 링크변경. -0x174 : Process 맨앞을가리킨다. +0x88+4 : blink offset 3. 실제로 notepad.exe 가프로세스목록에서숨겨졌는지확인해보자. < 그림 5 DOS 의 tasklist 명령어로 notepad.exe 가보이지않는다.> 10
< 그림 6 Windows 의 Task Manager 상에도 notepad.exe 가보이지않는다.> 11
III. DKOM 탐지기법 가. 다른 Linked list 이용하기 1. 원리 DKOM( 루트킷 ) 이조작하지못핚 Linked list 를찾아 walking 하는방법이다. 감추려했던오브젝트를탐지하기위해서는몇개의 Linked list 를탐지핚결과를비교분석하는작업이필요하다. 본문의상기기술 ( II. DKOM 을이용핚은닉 ) 에서는 ActiveProcess Links 의 List 를변경핚것이므로, 이와는다른 Linked list 구조인 HandleTableList 를이용하여 DKOM 으로숨겨짂프로세스를찾아낼수있다. EPROCESS 의 0x0c4 위치에 Object Table 이 HANDLE TABLE 구조체의포인터로프로세스의핸들정보를담고있다. HANDLE TABLE 의 QuotaProcess 를확인하여해당프로세스를확인핛수있다. 따라서이렇게 QuotaProcess 를따라확인해보면지금실행중인프로세스를확인하여감춰짂프로세스를찾아낼수있다. HandleTableList 를사용핛경우 ActiveProcessLinks 가손상된 프로세스도탐지핛수있다. 12
< 그림 7 HandleTableList 의구조 > // HandleTableList 를이용핚프로세스목록조사 System Idle Process 와 System 프로세스는 EPROCESS 구조체의주소가없음 13
2. 실습 2-1. 직접 Windbg Script 를작성하여은닉된프로세스찾기 Process Handle Linked List 이용해 Process List 얻는 Windbg Script :.block { r $t1 = poi(poi(poi(ffdff12c)+0x44)+0xc4).while(true){ r $t1=poi(@$t1 + 0x1c) - 0x1c.if(poi(@$t1+0x4) == 0){.break} da poi(@$t1+0x4) + 0x174 } } // 위의 script 를 c:\processlist.txt 에저장핚다면, Windbg 에서실행시 kd> $$>a<c:\processlist.txt 라고입력하면된다. 이렇게다른 linked list 를이용하여숨겨짂프로세스를찾아내는 것이고아래의툴들도 linked list 를이용핚다. 툴이사용하는링크를 우회핚다면툴도찾아내지못핛수도있다. 14
2-2. 툴을사용하여은닉된프로세스찾기 2-2-1. Volatility 의 pslist ActiveProcessLinks 를따라 Linked list 를이어가면서실행중인프로세스목록을조사하므로위와같이 ActiveProcessLinks 를조작핚경우찾아내지못핚다. 그러나 Hooking 에의해감춰짂프로세스는출력가능하다. 실행방법 : python volatility pslist -f c:\dkom.dd // c:\dkom.dd : Memory dump 핚파일 -f : 현재실행중인 Process 목록을출력핚다. < 그림 8 Volatility pslist 로는 notepad.exe 가보이지않는다.> 15
2-2-2. IceSword ActiveProcessLinks 이외에도 HandleTableList 등다른 Linked list 를조사하므로 notepad.exe 가발견된다. IceSword 에서탐지가능핚모든 Linked list 를조작핚다면이툴에서도 DKOM 탐지는불가능하다. < 그림 9 IceSword 로 Process 를탐지한결과은닉된 notepad.exe 가빨간색으로나타났다.> 16
나. Process Carving 1. 원리 Memory Dump 를핚후 Signature 를찾아내어 EPROCESS 를모두추출하는방법이다. Linked List 를이용하지않고, 메모리덤프에서데이터를읽어들여 EPROCESS 구조체인지검증핚다. EPROCESS 구조체에특별핚 Signature 가없으므로 Pool Tag, Object Header 값등을확인핚다. 실행중인프로세스, 감춰짂프로세스, 이미종료된프로세스에대핚정보를모두수집가능하다. 2. 실습을위해필요핚사젂지식 2-1. Memory Pool Hardware Level 에서메모리핛당의최소단위는 : Page(4k) 커널이사용하는메모리영역의일부를예약을해두고, 해당영역에서메모리를조금씩핛당받아서사용하는방식이다. 하나의커널오브젝트를위해젂체페이지를핛당하는것은메모리낭비이다. 윈도우의경우메모리풀 (memory pool) 에서 8 바이트단위로메모리핛당이가능하며, ETHREAD, EPROCESS 와같은커널오브젝트는메모리풀에졲재핚다. 2-2. Pool_Header < 그림 10 Memory Pool 에할당된 Memory Block> 17
메모리풀에핛당된메모리블록은관리를위핚자료구조 (POOL_HEADER) 를포함핚다. < 그림 11 Pool_Header 의구조확인 > 2-3. Paged Pool 과 Non Paged Pool Paged pool - 메모리부족시 Page in, Page out 을통해 swap 하여메모리를확보핚다. Non paged Pool - 젃대로 Page out 이앆된다. 커널은중요핚데이터는대부분 Non paged pool 에서핛당받는다. 18
3. 실습 3-0. 먼저 mdd 를통해서메모리를덤프핚다. Notepad 는 DKOM 으로감춘상태이고 calc.exe 는실행시키고종료핚상태이다. c.f) mdd : Mantech Memory DD (www.mantech.com/msma/mdd.asp) < 그림 12 현재 Physical Memory 를 c:\dkom.dd 파일로 dump 함 > // 원래는 mdd.exe 와만들어질 dkom.dd 모두 usb 에넣고 run 해야해당 시스템을완젂히보졲하여이미지를뜰수있다. 19
3-1. 직접 Windbg 를이용하기 3-1-1. PoolTag 값검증 ExAllocatePoolWithTag 와같은함수를이용하여메모리를핛당받는경우 PoolTag 를파라미터로젂달핚다. PoolTag : Memory Pool 을사용하는주체를식별하려는목적 Object 의성격에대핚정보를메모리를요청핛때 4byte 의 ASCII 문자열을붙여서보낸다. i. kd>!process 0 0 ( 생략 ) < 그림 13 현재모든프로세스정보를보여준다. > c.f)!process The!process extension displays information about the specified process, or about all processes, including the EPROCESS block. This extension can be used only during kernel-mode debugging. 20
ii. kd> dt_eprocess 820f5020 (EPROCESS 의시작점 ) < 그림 14 EPROCESS 의시작점 smss.exe 를 EPROCESS 의구조체로정보확인 > iii. EPROCESS 앞에 Object Header(size : 0x18) 가있다. 확인해보자. < 그림 15 첫번째 EPROCESS 인 smss.exe 의 Object Header 정보확인 > 21
iv. Object Header 앞에는 PoolHeader(size : 0x8) 가있다. 확인해보자. < 그림 16 첫번째 EPROCESS 인 smss.exe 의 Pool Header 정보확인 > // PoolTag 값 0xe36f7250 은실제로는 0x636f7250 이다. 최상위비트를항상 1 로설정하기때문이다. v. POOL_HEADER 의 PoolTag 값이 e36f7250 인것을찾는다. 실행방법 :!poolfind 0xe36f7250 0 // 0xe36f7250 PoolTag 값을갖는 Pool 중 0(Non paged pool) 을찾으라는뜻이다. < 그림 17 0xe36f7250 PoolTag 를갖는해당 Non paged pool 정보확인 > 22
vi. 위의결과여러주소가나왔다. 이주소는 PoolTag 가 proc 값을가지는 Pool Header 의주소이므로여기에적젃하게 offset 값을더하여 EPROCESS 를확인하면다음과같다. < 그림 18 81f69000 에 +20 하여 EPROCESS 확인 > // +20 (0x18 : Object Header Size + 0x8 : Pool Header Size) 23
3-1-2. OBJECT_HEADER 검증 윈도우커널은 Process, Thread, File, Event 등커널내부에서사용하는자료구조들의접근방법을단일화하고보앆성을높이기위해오브젝트모델을사용핚다. OBJECT_HEADER 내의 Type 필드는대상오브젝트 (eg. _EPROCESS) 의일반적인속성에대핚정보를담고있는 OBJECT_TYPE 구조체를가리키는포인터이다. 프로세스의경우이값이 PsProcessType 과같거나 0xbad0404 값을가짂다. < 그림 19 Object Header 를포함한 Memory 구조 > 24
i. kd> dt _OBJECT_HEADER 820F5000+8 (!object 820f5000 도같은결과를보여준다.) < 그림 20 EPROCESS 중하나를선택하여 Object Header 검증 > //!process 0 0 의결과값중하나를선택하여 OBJECT_HEADER 를검증해본다. PoolHeader Size 인 0x8 을더하여오브젝트헤더의정보중 Type 을확인핚다. Type 정보의값은 0x823c8e70 이다. 이것이 PsProcessType 값과같을까? 확인해보자. ii. kd> dd PsProcessType L1 < 그림 21 PsProcessType 확인 > // L1 : Doubleword 하나를의미핚다. 실제로 PsProcessType 값을확인해보면 823c8e70 이라는 Object_Type 과같은값을갖는다. 25
3-1-3. _EPROCESS 검증 i. ThreadListHead 의값을검증 < 그림 22 Process 와 Thread> 프로세스는반드시하나이상의 Thread 를가짂다. 그렇기때문에 ThreadList 의시작값을가지는 ThreadList Head 가 0 이아니어야핚다. Thread Control Block 은커널메모리영역에졲재핚다. 커널의가상주소공갂은일반적으로 0x00000000~0x7fffffff 앆에위치하며, /3GB 옵션은 0x00000000~0xbfffffff 의주소를갖는다. < 그림 23 ThreadListHead 의값이 0 이아님을확인 > 26
ii. DISPATCHER_HEADER 검증 EPROCESS 는 Dispatcher Object 이다. 구조체의맨앞부분에 DISPATCHER_HEADER 가졲재핚다. < 그림 24 DISPATCHER_HEADER 의구조 > 관찰을통해확인해보면 process 의경우 DISPATCHER HEADER 의 Type 필드와 Size 필드의값이각각 0x3 과 0x1b 로 고정되어있다. < 그림 25 Type=3, Size=1b 고정 > 27
iii. DirectoryTableBase 값검증가상주소를물리주소로변홖하는데필요핚 Page Directory 의시작주소를저장핚다. 정상적인 EPROCESS 객체의경우이값이 0 이아니어야핚다. Page Directory 는페이지하나를통째로사용하여시작주소는페이지단위로 alignement 되므로 4k 의배수가되어야핚다. < 그림 26 DirectoryTableBase 확인 > // 우리가 DirectoryTableBase 로부르지만 windbg 에서는 VadRoot 로 불리우며, 0x8227a0f0 을십짂수 4k 로나누면 532725 로딱떨어짂다. 28
3-2. 툴을사용하기 3-2-1. Volatility 의 psscan Process Carving 의방법을사용하므로 DKOM 탐지가가능하다. 루트킷으로감춘프로세스뿐만아니라종료핚프로세스까지도탐지핚다. 실행방법 : python volatility psscan -f c:\dkom.dd // c:\dkom.dd : Memory dump 핚파일 -f : 현재실행중인 Process 목록을출력핚다. // 실행중인프로세스가나오기시작핚다. // 감추어짂 notepad 가나온다. // 종료했던계산기 (calc.exe) 가나타났으며, 종료된시갂까지나왔다. < 그림 27 Volatility psscan 은숨겨진프로세스및종료된프로세스도출력 > 3-2-2. 그밖의유명핚툴 : PTFinder(Process&Thread Finder) 29
IV. 참고문헌 Greg Hoglund ㆍ Jamie Butler, " 루트킷 : 윈도우커널조작의미학 ", 에이콘, July 2008 30