Black- out Frenzy [ B] (F) Security Researcher Center B0Frenzy.freehostia.com PE Infection How to Inject a dll www.mihanit.net Thank you to my friends who help me in this research (K053,Heli, L U C I F E R(Bl4ck_Ic3)) Author: Nightmare(BioHazard) Date: 03.05.2009(88.02.13) Hint : Only the reader is responsible for any abuse of context of this document. OVERTIME OVERTIME force <forceteam01@gmail.com < forceteam01@gmail.com>2007.06.25
Introduction 우리의목적은 PE File 에특정 DLL 을삽입하는것이다. 이와같은작업을위해서우리는 PE 구조에대해서알아봐야한다 먼저우리는 PE 구조가포함하고있는 PE Section 들과부가 Section ((PE Sections & Add a Section(Manually &Automaticly)) 에대해서알아보도록하자 그리고우리는 Import Table 에대해서간략히다루며최종적으로어떻게 dll 을삽입하는지에대해서알아볼것이다. PE section(s): 위에보이는것과같이.text,.rdata,.data,.rsrc,.reloc, BSS 을포함하는 Potable Executable 은 windows loader 에의해서생성되는 PE section 들이다
.text.rdata.data BSS.rsrc &.reloc PE의 Main code를저장한다 String literals, Debug Directory와같은읽기전용데이터를포함한다모든 static data와초기화된글로벌데이터를저장한다초기화되지않은글로벌데이타를저장한다로딩되는동안이미지의재위치정보를저장한다 자그럼우리는어떻게 PE 에 section 을추가할수있는지알아봐야한다. 먼저약간의인내심이필요한어려운방법을알아보자이방법을위해서는너의비상한머리와 Hex- Editor 가필요하다 첫번째우리는마지막 section 의정보를수집해야한다. 대상이되는 firefox 를 hex editor 로열고.reloc 를찾아본다 바이트순서에따른정보는다음과같다 Section name(8byte) Virtual Size(4byte) Virtual Address(4byte) 2E 72 65 6C 6F 63 00 00 06 05 00 00 00 C0 04 00 Raw Size(4byte) Raw offset(4byte) null(12byte) flags(4byte) 00 06 00 00 00 96 04 00 00 00 00 ~ 40 00 00 42
여기서한가지중요한점은우리의 section alignment 는 1000h 라는점이다 이제우리는 1000h Virtual size and Raw size( 이것은 section alignment 와는연관이없다 ) 의 section 을추가할것이다. 따라서우리의새로운 section 의정보를계산을필요가있다. New Virtual Address = Virtual Address + Virtual Size + Section Alignment / / = 0004C000 + 00000506 + 1000 = 0004D506 - > 06 D5 04 00 (We use nearer 0004D000 > 00 D0 04 00) New Raw Offset = Raw Offset + Raw Size / / = 00049600 + 600 = 00049C00 - > 00 9C 04 00 Virtual Size and Raw size for the new section = 1000h - > 00 10 00 00 Flags = E00000E0 - > E0 00 00 E0 이제새로운 section 정보에대한계산이끝났으면 PE 에 Hex Editor 를이용해서추가한다.
대상파일에 1000h bytes 추가한다 Section 의수를 6 으로변경하기위해서 IMAGE_FILE_HEADER 의 Number of sections 값을 6 으로수정한다. (Number of sections 값은 PE Signature(50450000) 2byte(4C01) 뒤 2byte(0600) 이다 )
LoadPE 를이용하여추가한 section 이정상적으로추가되었는지를확인한다. 이와같은결과를얻게되면수동으로대상파일에 section 을추가하는것이성공한것이다. 이제좀더쉬운방법으로.BFNIGHT section 을추가해보도록하자여기서는단지 LordPE 와같은훌륭한 PE Editor 만을이용해서추가해보도록하겠다. 공격대상을 lordpe 로오픈하고 Section 버튼을클릭한다. Section Table 윈도우가나타나면우측마우스클릭메뉴중 add section header 를클릭한다. 이옵션은새로운 section 을추가한다. 그래서새로운 section 을추가하면 Edit Section Header 메뉴를이용하여추가된새로운 section 의정보를수정해야만한다.
OK 및 SAVE 버튼을클릭해서수정된내용을저장한다. 하지만아직우리는대상프로그램에 hex Editor 를이용해서 1000h bytes 를추가해야한다. IAT(Import Address Table): 모든 PE 는기본적으로포함되지않는함수의리스트를가지고있다. 이와같은함수들은 OS DLL 안에위치해서 import 된다고말한다. 반면에 PE 는그들이어디에위치하는지알지못한다그래서모든 win32 executable 은 PE 안에 Import Table Address 또는 IAT 를갖는다. IAT 는모든 import 정보를포함하고있다, 이것의의미는 PE 가 windows32 API 를호출할때해당되는 API 를찾는테이블로사용된다는것을의미한다. 간단하게 windows loader 는시작전에 PE 에의해서호출되는 API 각각의주소를찾아야한다
자그럼 firefox 내부를들여다보자 그림에서보여지는 Call function 은 API 의좋은예제이다. 이것은 SetUnhandledExceptionFilter API 를호출한다. 해당라인을더블클릭하면다음과 같이 CALL DWORD PTR DS.[ XXXXXX].[ XXXXXX] 나타난다. 여기서주소값에주목하여 hex dump 화면에서 [ 402024] 주소로이동한다 ( 마우스우측클릭 - >go to- >expression or CTRL+G) 그림에서보다시피 API 의주소는 7C81495D 이다. 사용하는시스템에따라서필자와는다를수도있으며 API 의주소는 7XXXXXXX 형태로시작한다. 이제부터 windows loader 가어떻게모든 API 의주소를찾는지알아보도록하자. 첫째 windows loader 는 PE 의헤더를읽는다. RVA 3C 바이트를읽는다. VA 의바이트는 40003C 가될것이다 (imagebase 400000) 그러나 Import Table 은무엇인가? Import Table 은 windows 가 API 를링크하기위해서필요로하는모든정보가담겨져있다. Import Table 의구조는간단하다. 각각의 import 되는 DLL 을위한헤더와 Import Table 의끝을나타내는부가적인 null 헤더가있다. 예를들어만일 kernel32.dll 과 User32.dll 에서 API 를 import 한다면 3 개의헤더로구성이된다. 2 개는 kernel32.dll 과 User32.dll 로구성되고끝을나타내는하나의제로헤더로구성된다.
각 dll 의헤더는 IMPORT_IMAGE_DIRECTORY 라불린다. IMAGE 문자의의미는모든자료들이메모리에있다는의미이다. 하지만 IMAGE_IMPORT_DESCRIPTOR 라불리는 import symbol 들에대한정보를저장하는데이터구조는 5 가지요소를갖는다. Identifying Malicious Reverse Engineering Code Through 책에잘나와있다. OriginalFirstThunk: IMAGE_TUNK_DATA array 의 RVA (pointer) 를포함하는멤버 IMAGE_TUNK_DATA 는 dword 크기의 Union 구조체이다. 이것은 IMAGE_IMPORT_BY_NAME 구조체에대한포인터로생각할수있다. 구조체는다음과같다 IMAGE_IMPORT_BY_NAME STRUCT Hint Name1 Time/Date Stamp: 이필드는 DLL 의 time/data stamp 를나타낸다필수적인필드는아니며 zero 값으로지정될수있다 Forwarder Chain: 첫번째 forwarder reference 의 index 필수적인필드는아니며 zero 값으로지정될수있다 Name: DLL 의이름을포함하는 ASCII string 의 RVA(pointer) 를포함한다 FirstThunk: 이름에서나타나듯 OriginalFirstThunk 와매우비슷하다. IMAGE THUNK DATA 구조체 array 의 pointer(rva) 를포함한다비록두 array 가같은값을포함하더라도 executable 안에는다른위치에있게된다 참조 참조 : http://www.openrce.org/reference_library/files/ reference_library/ files/ reference/pe%20format.pdf
이와같은말보다는직접해당내용을확인해보도록하자. 먼저 Import Table 을찾아보도록하자. Ollydbg 로 firefox 를열고 M(Memory Map Button) 을클릭하고 PE Header 를더블클릭한다. 이제 firefox 의헤더를확인할수있다. RVA 의 3C(ImageBase + 3C = 40003c) 를찾는다. D8 값을확인하고 80h 값을더한다 D8h + 80h + 400000h = 400158h 이 RVA 는 Import Table 의 VA 값을저장하고있다. Import Table 주소의 RVA 는 402374 주소일것이다. CPU 창에서 402374 주소로이동한다.( 마우스우클릭 Go To- >Expression 또는 CTRL+G 후 402374 입력 ) 필요하다면 Analyze Code(CTRL+A) 를시행한다. 우리는 8 개의 IMAGE_IMPORT_DESCRIPTOR 들을발견할수있으며마지막하나는각 dll 의정보를담고있는 Import Lookup Table 의끝을가리키는 zero- header 이다. 그리고우리는 import 함수각각의이름을가지고있다 IMAGE_IMPORT_DESCRIPTOR 에의해서가리키는지점에 import 정보들이있다. 역자주 : 원문서에서는주석을달아놓은화면을첨부하였다그러나여기서는원시적인방법을사용한다 간단하게 7 개의 DLL 을확인하는방법은 ollydbg 에서 E(Executable module) 창을클릭하고현재분석대상인 firefox( 필자의경우는 firefox2) 모듈을마우스우클릭하여 View Names 또는 CTRL+N 을선택한다.
Names 윈도우가나타나면 Type 항목으로정렬하여 Import Type 의 DLL 항목수를확인한다 (firefox2 7 개 KERNEL32, MOZCRT19, USER32, nspr4, plc4, xpcom, xul) Names 창에서는어떤 DLL 에서어떤 API 를호출하는지확인할수있다. 자그러면 PE 구조를자세히알아보기위해서 import DLL 이름을 PE 구조를이용하여확인하는방법에대해서알아본다참조 : http://www.openrce.org/reference_library/files/ reference_library/ files/ reference/pe%20format.pdf 참조문서를보면 IMAGE_IMPORT_DESCRIPTOR 구조체는 0x14h bytes size 이다그중 Name 값은 0x0Ch byte에위치하고있다. 위에서알아봤듯이 Import Table 주소의 RVA 는 402374 이다. Ollydbg CPU 창에서해당위치로이동한다
우리가원하는값은 name 값 0x0C byte 를더해야한다. 그러면 RVA 는 402380 이다. 402380 주소로이동하여마우스우클릭 Follow in Dump- > Selection 항목을클릭하여하단덤프창의 hex dump 값을확인한다.
덤프값을확인하면 00002574 이다. 이값에 ImageBase 400000 을더하면 402574 값이나온다덤프창에서 GTRL+G 402574 주소로이동하여 ASCII 값을확인하면 xul.dll 을확인할수있다. 이와같은방식으로 DLL 내역을확인할수있다. API 함수를확인하기위해서는 IMAGE_IMPORT_DESCRIPTOR 구조체의 OriginalFirstThunk 값을확인하여같은방식으로확인하면된다. 00402374 의값은 00002500 RVA 는 00402500 이며해당값은해당 DLL 에서사용하는 API 함수의포인터를값으로가지고있는배열로되어있다. 좀더간단히설명한다면 OriginalFirstThunk 의값 00002500 RVA 00402500 은 xul.dll 에서사용되는 API 함수의이름을가리키는배열을가리키는포인터이다. ollydbg 에서 E(Executable module) 창을열어서 xul.dll 에서사용하는함수들을살펴보면 5 개의함수를사용하는것을알수있다. 그럼 00402500 부분의 Hex dump 를살펴보도록하자 그림에서알수있듯이총 5 개의포인터로구성된배열을확인할수있다. 각포인터는이전에언급한참조문서 (PE Format.pdf) 에서확인하면 IMAGE_IMPORT_BY_NAME 구조체를가리키는포인터로 2byte Hint 와함수이름으로구성되어있다. 예제로 00402568 RVA ASCII 값을확인하면 XRE_main API 임을확인할수있다.
Inject A DLL: 이제까지우리는대상프로그램에 dll 을 inject 하기위한충분한정보를확보했다. 하지만위에서알아본내용외에도 framework, 종이와연필또한필요할것이다. Framework: 1. 첫째우리는 Origin EP(Entry Point) 로점프하는 section 을추가해야하며또한원래 EP 를추가한 section 의 EP 로변경해야한다. 2. 그리고 firefox2 의 IMAGE_IMPORT_DESCRIPTOR 모두를새로운 section 으로이동해야하며 Import Table Address 의값은새로운 section 의 Import Table Address 로변경되어야한다. 3. Inject 대상 dll 을위한 Import Lookup 및 IMAGE_IMPORT_DESCRIPTOR 을추가해야한다. 4. 호출하라 5. 즐겨볼까나 ~ ~ 첫째단계초기에알아봤듯이 loadpe 를이용하여 3000h 크기의 section 을추가한다. 또 EP RVA 를찾아야한다. 좀쉬운방법으로.BFNIGHT 의 Voffset 값을확인하면된다. 그래서새로운 EP 는 4D000 + 15F1 = 4E5F1 ( EP 가많은 code cave 를갖는것을고려해야한다 ) EP 를수정하기전에 Origin EP 로점프해야하기때문에 Origin EP 를기억해야한다. 그래서 Origin EP 는 4015A0 이고새로운 EP 는 4E5F1 이다. 자그럼변경해보자
변경후 firefox2 를 Hex Editor 로열고마지막에 12288 byte 추가한다. Firefox2 를 ollydbg 로열고 jmp 4015A0 어셈블러명령을추가하고컴파일한다. firefox2-2.exe 파일로저장한다. 만일 firefox2-2.exe 를실행하면잘동작할것이다.
둘째단계전에말한것처럼 IMAGE_IMPORT_DESCRIPTOR 를찾는다. 선택후마우스우클릭메뉴 Binary- >Binary copy 를선택한다 (20bytes 8개의구조체이다 ) 추가한새로운 section 의 Null space 에붙여넣고 firefox2-3.exe 로저장한다.
이제 Import Table Address 를수정해야한다. IMAGE_IMPORT_DESCRIPTOR 의첫번째 Byte 는 Import Table Address 이며 lordpe 를이용하여수정해야한다. Import Table Address(new) = 44E61B(in my system) RVA = 44E61B 400000 = 4E61B LordPE 로 firefox2-3.exe 를열고 Directories 버튼을클릭하여 Import Table 을수정한다 셋째와넷째단계여기에서는 Ashraf Cracker 의 DLL (Password.dll) 을사용한다. http:/ / www.4shared.com/ file/ 112647070/ 69e44e47/ Password.html firefox 디렉토리에 dll 을복사한다. Password.dll 은 PasswordMain 을호출하는함수를가지고있다.
이제 dll 을위한 Import Lookup Table 을만들어야한다. 44E6CD 와같은 Null Data 장소를고르고 Dump view 에서값을확인한다. 먼저 dll name(password.dll) 을입력해야한다. 44E6CD 값부터 12bytes 를선택하고마우스우클릭후 Binary - > Edit 항목을선택하여 Password.dll 항목을입력한다. 다음은함수이름 (PasswordMain) 을입력한다. 다음으로함수이름을가리키는 RVA와 20 10 00 10 을입력해야한다역자주 : 20 10 00 10 궁금한사람은 FirstThunk 에대해서알아봐라 RVA = 44E6DB 40000 = 4E6DB - > DB E6 04 00
마지막단계로 IMAGE_IMPORT_DESCRIPTOR 구조를완성한다 OriginalFirstThunk = 44E6ED 400000 = 4E6ED - > ED E6 04 00 Time/ Date Stamp and ForwaderChain = Zero Name: 4E6CD - > CD E6 04 00 FirstThunk:4E6F5 - > F5 E6 04 00 IMAGE_IMPORT_DESCRIPTOR 구조를완성하기위해서해당부분을수정한다. 0044E5F1 을 CALL DWORD PTR[ 44E6F5] 로수정한다 0044E5F7 을 JMP 004015A0 로수정한다. 수정한내용을 firefox2-4.exe 로저장한다. 모든것이정상적으로이루어졌다면 dll 이 Inject 되어정상적으로작동하는화면을볼수있을것이다. Password : 0128793089
참고문헌참고자료 참고문헌 : Windows 시스템실행파일의구조와원리 한빛미디어이호동저참고자료 : http:// www.openrce.org/ reference_library/ _library/files/reference/pe%20format.pdf reference/