반응형

어플리케이션 후킹(Application Hooking) 설계(디자인)에 대한 설명입니다. 후킹 방법을 결정하고, 검증하는 과정을 보여드립니다. 



후킹 방법 결정 - 무엇을? 어떻게? 후킹 할 것인가?


우리의 목표는 [HxD.exe 프로그램에서 PE 파일을 열었을 때 상태바의 "Offset: XXXX" 문자열에 "RVA: YYYY" 문자열을 추가하기]  입니다.


기존 어플리케이션에 어떤 기능을 추가(혹은 수정) 하려고 마음을 먹었다면 그 다음에는 구체적인 방법에 대해 고민을 해야 합니다. 즉, 후킹 설계 과정으로 들어가야 합니다.


윈도우즈 OS의 대표적인 후킹 기법은 "메시지 후킹(Message Hooking)""API 후킹(API Hooking)" 입니다. 둘 중에서 목표 달성에 더 적합하고 구현이 편리한 방법을 사용하는 것이 좋을 것입니다.


일반적으로는 메시지 후킹 기법이 더 간단하고 더 안전하다고 볼 수 있습니다. 대신 경우에 따라(특히 GUI 관련) 더 많은 고려사항이 필요한 경우가 있습니다. 따라서 실전에서는 후킹 설계 단계에서 메시지 후킹 방법이 더 편리할지 확인해 보는 것이 좋습니다.



메시지 후킹 기법 검증


우리 목표에 메시지 후킹 기법이 잘 어울릴지 검증해 보도록 하겠습니다. 


Windows OS 는 어플리케이션 윈도우의 GUI 처리 작업을 위해 윈도우 메시지를 이용합니다. HxD.exe 의 상태바도 일종의 윈도우입니다. 프로그램 내부에서 상태바에 특정 문자열을 쓰기 위해 관련된 윈도우 메시지를 전달할 것입니다. 


* 참고 


GUI 관련 API 를 호출하면 GUI 작업 처리를 할 수 있기 때문에 마치 윈도우 메시지를 사용하지 않고도 작업이 가능한 것처럼 생각될 수도 있습니다. 그러나 실제로는 API 내부에서 윈도우 메시지를 보내는 것입니다. 일반적인 GUI 작업은 메시지 기반으로 동작한다는 것을 기억하시기 바랍니다.


HxD.exe 의 상태바에 있는 "Offset: XXXX" 문자열이 변경될 때 상태바 윈도우 프로시저(Window Procedure)에서 처리하는 윈도우 메시지들을 확인해 보겠습니다. 먼저 HxD.exe 프로그램을 실행 하신 후 적당한 PE 파일을 열어 주세요.


그리고 윈도우 메시지를 모니터링 하기 위해 Spy++ 유틸리티를 실행합니다.



<그림 3 - Spy++ 실행화면>


* 참고


윈도우 메시지 확인에 있어서 Spy++ 은 최고의 유틸리티입니다. 기본 동작 원리는 윈도우 메시지 후킹입니다. 모니터링 대상 프로세스에 DLL 을 인젝션 시켜서 사용자가 원하는 메시지를 모니터링 합니다. Spy++ 은 Microsoft Visual Studio 패키지에 포함된 유틸리티 입니다. 


Spy++의 툴바에서 "Log Messages... (Ctrl+M)" 버튼을 선택합니다. (또는 "Spy - Log Messages..." 메뉴를 선택하셔도 됩니다.)



<그림 4 - Log Messages... (Ctrl+M) 툴바 버튼>


Message Options 다이알로그가 나타납니다.



<그림 5 - Message Options 다이알로그>


Windows 탭의 Finder Tool 을 이용할 것입니다. Finder Tool 아이콘을 마우스 버튼을 누른 채로 드래그 하면 마우스 포인터가 과녁 모양으로 바뀝니다. 이 과녁 모양의 마우스 포인터를 HxD 의 상태바 윈도우에 위치시킨 후 마우스 버튼에서 손을 떼면 Spy++ 의 타겟(Target) 윈도우로 설정됩니다. (과녁 모양의 마우스 포인터 밑에 있는 윈도우는 두꺼운 검은색 테두리가 생겨서 잘 알아 볼 수 있습니다.)



<그림 6 - Finder Tool 로 상태바 설정>


이제 Spy++ 의 Message Options 다이알로그의 "Selected Object" 섹션에 지금 선택된 HxD 의 상태바 윈도우에 대한 정보들이 표시됩니다.



<그림 7 - HxD 의 상태바 윈도우 정보>


각 정보들이 나타내는 의미는 <표 1>과 같습니다.


 항목

 의미

 

 Window

 윈도우 핸들

 001B0362

 Text

 윈도우 텍스트

 Offset: 0

 Class

 윈도우 클래스 이름

 TXmStatusBar

 Style

 윈도우 스타일

 54000100

 Rect

 윈도우 위치와 크기

 (15, 663)-(589, 684) 574x21

 Thread ID

 윈도우를 생성한 스레드 ID

 00000150

 Process ID

 윈도우가 속한 프로세스 ID

 00000F30


<표 1 - Selected Object 항목들의 의미>


* 참고


Spy++ 에서 보여주는 상태바 윈도우의 정보는 나중에 메시지 후킹을 구현할 때 좋은 참고자료가 됩니다.


윈도우 클래스 이름이 "TXmStatusBar" 인 걸로 봐서 윈도우 기본 상태바(StatusBar)를 서브클래싱(SubClassing) 한 것으로 추정됩니다. 그렇다면 기본 동작은 윈도우 기본 상태바와 비슷할 것이라고 예상해 봅니다.


Message Options 다이알로그의 [확인] 버튼을 선택하면 이제부터 Spy++ 은 HxD 의 상태바 메시지를 모니터링하기 시작 합니다. 시험 삼아서 마우스 포인터를 상태바 위에서 이리저리 이동해 보시기 바랍니다. Spy++ 화면에 마우스 관련 메시지가 많이 나타날 것입니다.



<그림 8 - 마우스 이동 메시지>


Spy++ 의 메시지 캡쳐 옵션을 디폴트인 'ALL' 로 설정하였기 때문에 상태바로 전달되는 모든 메시지가 표시되는 것입니다. 우리가 진짜 궁금한 내용은 상태바에 문자열이 써지는 순간에 어떤 메시지를 받느냐 하는 것입니다. 


Spy++ 툴바의 'Clear Log (Del)' 버튼을 선택하여 지금까지 쌓인 로그를 지워버립니다. 그리고 HxD.exe 의 메인 화면 내의 아무 부분을 마우스로 클릭하시기 바랍니다. 마우스가 선택한 파일의 옵셋을 상태바에 출력하기 위해 메시지가 전달될 것입니다.



<그림 9 - 문자열 출력 메시지>


HxD 메인 윈도우에서 마우스 클릭을 한번 하면 정확히 9개의 메시지 로그가 출력됩니다. (제가 보기 편하게 들여쓰기를 하였습니다.)


<00001> 001B0362 S message:0x040A [User-defined:WM_USER+10] wParam:00000000 lParam:0012FA84

<00002> 001B0362 R message:0x040A [User-defined:WM_USER+10] lResult:00000001


<00003> 001B0362 P WM_PAINT hdc:00000000


<00004> 001B0362 S message:0x0401 [User-defined:WM_USER+1] wParam:00000000 lParam:01A06768

<00005> 001B0362 S   WM_PAINT hdc:00000000

<00006> 001B0362 S     WM_ERASEBKGND hdc:33010BC2

<00007> 001B0362 R     WM_ERASEBKGND fErased:True

<00008> 001B0362 R   WM_PAINT

<00009> 001B0362 R message:0x0401 [User-defined:WM_USER+1] lResult:00000001


1번 로그의 메시지는 WM_USER(0x400)+A 이고 그 때의 lParam 값은 0012FA84 입니다. lParam 값이 마치 스택의 주소를 가리키는 것으로 추정됩니다. 그리고 4번 로그의 메시지는 WM_USER(0x400)+1 이고 lParam 값은 01A06768 입니다. 이 값 또한 메모리 주소를 표시한다고 추정해 볼 수 있겠습니다. 


마우스(또는 키보드)를 이용하여 HxD 메인 윈도우의 커서를 다른 옵셋으로 이동시키면 기본적으로 이와 동일한 9 개의 메시지 로그가 기록됩니다. 그리고 4 번째 로그의 lParam 값은 계속 바뀌는 것을 알 수 있습니다. (아마 동적 할당 메모리로 추정됩니다.)


따라서 상태바 윈도우는 사용자 정의 메시지인 WM_USER+1 또는 WM_USER+A 메시지를 받아서 lParam 이 가리키는 주소의 문자열을 상태바 윈도우에 쓴다고 추정해 볼 수 있겠습니다. 그 중에서도 4번 로그 메시지 WM_USER+1 을 받은 직후 WM_PAINT 와 WM_ERASEBKGND 메시지가 연속해서 나타나는 걸로 봐서는 WM_USER+1 메시지가 상태바 윈도우에 실제 값을 쓰라는 명령으로 보입니다.


디버거를 이용하여 lParam 이 가리키는 주소를 확인해보면 앞에서 추론한 내용이 맞는지 알 수 있겠지요.


* 참고


WM_PAINT 는 윈도우를 다시 그릴 때 발생되고, WM_ERASEBKGND 는 윈도우 배경을 지울 때 발생됩니다. WM_USER (0x400) 이후부터는 사용자 정의 메시지로서 프로그래머가 마음대로 지정해서 사용할 수 있습니다. 물론 메시지를 받는 윈도우 프로시저에서 사용자 정의 메시지를 잘 처리할 수 있도록 구현해야 합니다. 해당 메시지에 대한 더 자세한 설명은 MSDN 을 참고하시기 바랍니다.



디버깅


OllyDbg 를 실행하여 HxD.exe 프로세스에 Attach 시킵니다. 디버거는 ntdll.dll 메모리 영역의 System Break Point 위치에서 멈춥니다. 디버거를 실행[F9] 시켜 줍니다. 


윈도우 메시지를 디버깅 할 때는 주의사항이 있습니다. 그건 바로 디버기 프로세스(HxD.exe)의 윈도우를 가리면 안된다는 것입니다. 즉 OllyDbg 나 Spy++ 윈도우에 의해 HxD 윈도우가 가려졌다가 나타났다가 하게 되면 불필요한 로그가 Spy++ 에 쌓이게 됩니다. (물론 Spy++ 옵션을 고쳐서 모니터링 메시지를 필요한 것 만으로 제한해도 됩니다.) 


작업 편의상 각 윈도우들을 독립적으로 배치 시켜 주시기 바랍니다.



<그림 10 - 윈도우 배치>


다시 Spy++ 의 로그를 깨끗이 지우신 다음 마우스로 HxD 메인 윈도우 아무 곳이나 선택해 주세요. 제 경우에 Spy++ 의 WM_USER+1 로그의 lParam 주소는 01A0BA28 입니다. 



<그림 11 - 새로운 lParam 값>


이 주소를 OllyDbg 의 메모리 윈도우에서 검색해 보겠습니다.



<그림 12 - OllyDbg 에서 확인한 lParam 내용>


HxD 의 상태바에 나타난 것과 동일한 문자열이 ASCII 형태로 표시되어 있습니다. (이 경우에는 운좋게 예상과 잘 맞아서 쉽게 발견할 수 있었습니다.) 이 WM_USER+1 메시지를 후킹해서 lParam 이 가리키는 문자열("Offset: XXXX")을 읽은 후 RAW -> RVA 변환하여 표시해 주면 목표를 완수 할 수 있을 것 같습니다.


결론적으로 메시지 후킹 방법은 우리 목표에 잘 들어맞는 방법입니다. 다음 포스트에서 실제 메시지 후킹을 구현해 보도록 하겠습니다.


* 참고


사실 제가 처음 떠올렸던 아이디어는 단순한 마우스 메시지 후킹이었습니다. HxD.exe 상태바의 문자열이 바뀌려면 먼저 마우스로 커서 위치를 바꿔줘야 했으니 마우스 훅 프로시저에서 상태바의 문자열을 읽고 쓸 수 있지 않을까 하고 말이죠. 그러나 조금 더 생각해보니 좋은 아이디어가 아니라서 접었습니다. 이유는 키보드로도 커서 위치를 바꿀 수 있으니 키보드 메시지도 후킹 해야 할 테고, 상태바 윈도우가 다시 그려져야 하는 모든 상황(윈도우 이동, 윈도우가 가려졌다가 다시 나타나기, HxD 에서 다른 파일 열기, 기타)을 고려했을 때 후킹해야 할 메시지가 많아 질 것 같았기 때문입니다. 

따라서 덮어놓고 후킹을 시도하기보다는 먼저 차분히 생각을 정리해보고, 아이디어를 검증하는 단계가 매우 중요하다고 볼 수 있겠습니다.




ReverseCore

반응형
반응형

리버싱 기술을 조금 응용하면 다른 응용프로그램의 기능을 추가/변경시킬 수 있습니다. 


제가 애용하는 헥스 에디터 HxD.exe 에 필요한 기능을 살짝 추가하였습니다.



HxD.exe



DLL InjectionAPI Hooking 기술을 이용하여 HxD.exe 프로그램에 새로운 기능을 추가하였습니다.



제가 추가시킨 기능은 PE 파일 Offset 의 RVA 값을 계산해서 출력해 주는 것입니다. (위 그림 참고)


키보드나 마우스를 이용하여 커서 위치를 이동하면 Offset 값이 변함에 따라서 자동으로 그에 맞는 RVA 값이 계산되어 표시됩니다.



사용방법



HxD.exe  - Hex Editor

hxdhook.dll  - hooking dll

InjDll32.exe  - Injector

PEInfo.dll  - File Offset <->RVA converter



1. HxD.exe 실행


2. HxD 에서 아무 PE 파일을 오픈


3. InjDll32.exe 를 이용하여 HxD.exe 프로세스에 hxdhook.dll 을 인젝션





HxD.exe 프로세스에 hxdhook.dll 이 정상적으로 인젝션 되었다면 이제부터 프로그램 하단의 Status Bar 에 Offset 과 RVA 가 동시에 표시될 것입니다. 


크게 유용하다고 볼 수 는 없지만 리버싱 기술을 응용하여 기존 프로그램에 새로운 기능을 추가하는 방법을 잘 보여주는 예제라고 생각합니다. 필요하신 분께서는 자유롭게 가져다 쓰실 수 있습니다.



* 블로그에 리버싱 기술 응용편을 올리기 위해 준비한 간단한 시연입니다. 자세한 동작 원리, 후킹 과정, 모듈 개발 과정 등은 따로 포스팅 하도록 하겠습니다.



ReverseCore



반응형

'tool' 카테고리의 다른 글

PEView.exe  (21) 2013.01.27
리버싱 현업에서 사용되는 디버거(Debugger)들  (33) 2010.09.29
InjDll.exe – DLL Injection/Ejection 전용 도구  (43) 2010.03.15
Process Explorer - 최고의 작업 관리자  (1) 2009.05.03
www.virustotal.com  (3) 2009.03.20
www.google.com  (2) 2009.03.06
반응형


Introduction


Windows 운영체제의 PE(Portable Executable) File Format 에 대해서 아주 상세히 공부해 보도록 하겠습니다.

PE format 을 공부하면서 Windows 운영체제의 가장 핵심적인 부분인
Process, Memory, DLL 등에 대한 내용을 같이 정리할 수 있습니다.



PE(Portable Executable) File Format


PE 파일의 종류는 아래와 같습니다.

  • 실행 파일 계열 : EXE, SCR
  • 라이브러리 계열 : DLL, OCX
  • 드라이버 계열 : SYS
  • 오브젝트 파일 계열 : OBJ

엄밀히 얘기하면 OBJ(오브젝트) 파일을 제외한 모든 파일들은 실행 가능한 파일 입니다.

DLL, SYS 파일등은 쉘(Explorer.exe) 에서 직접 실행 할 수는 없지만,
다른 형태의 방법(디버거, 서비스, 기타)을 이용하여 실행이 가능한 파일들입니다.

* PE 공식 스펙 에는 컴파일 결과물인 OBJ(오브젝트) 파일도 PE 파일로 간주합니다.
  하지만 OBJ 파일 자체로는 어떠한 형태의 실행도 불가능하므로 리버싱에서 관심을 가질 필요는 없습니다.


간단한 설명을 위해서 노트패드(notepad.exe) 파일을 hex editor 를 이용해서 열어보겠습니다.


<Fig. 1>

<Fig. 1> 은 notepad.exe 파일의 시작 부분이며, PE 파일의 헤더 (PE header) 부분입니다.

바로 이 PE header 에 notepad.exe 파일이 실행되기 위해 필요한 모든 정보가 적혀있습니다.

어떻게 메모리에 적재되고, 어디서부터 실행되어야 하며, 실행에 필요한 DLL 들은 어떤것들이 있고,
필요한 stack/heap 메모리의 크기를 얼마로 할지 등등...


수 많은 정보들이 PE header 에 구조체 형식으로 저장되어 있습니다.

즉, PE File Format 을 공부한다는 것은 PE header 구조체를 공부한다는 것과 같은 말입니다.



Basic Structure


일반적인 PE 파일의 기본 구조입니다. (notepad.exe)


<Fig. 2>

<Fig. 2> 는 notepad.exe 파일이 메모리에 적재(loading 또는 mapping)될 때의 모습을 나타낸 그림입니다.
많은 내용을 함축하고 있는데요, 하나씩 살펴보겠습니다.


  • DOS header 부터 Section header 까지를 PE Header, 그 밑의 Section 들을 합쳐서 PE Body 라고 합니다.

  • 파일에서는 offset 으로, 메모리에서는 VA(Virtual Address) 로 위치를 표현합니다.

  • 파일이 메모리에 로딩되면 모양이 달라집니다. (Section 의 크기, 위치 등)

  • 파일의 내용은 보통 코드(".text" 섹션), 데이타(".data" 섹션), 리소스(".rsrc") 섹션에 나뉘어서 저장됩니다.
    반드시 그런것은 아니며 개발도구(VB/VC++/Delphi/etc)와 빌드 옵션에 따라서
    섹션의 이름, 크기, 개수, 저장내용 등은 틀려집니다. 중요한 것은 섹션이 나뉘어서 저장 된다는 것입니다.

  • Section Header 에 각 Section 에 대한 파일/메모리에서의 크기, 위치, 속성 등이 정의 되어 있습니다.

  • PE Header 의 끝부분과 각 Section 들의 끝에는 NULL padding 이라고 불리우는 영역이 존재합니다.
    컴퓨터에서 파일, 메모리, 네트워크 패킷 등을 처리할 때 효율을 높이기 위해 최소 기본 단위 개념을 사용하는데,
    PE 파일에도 같은 개념이 적용된 것입니다.

  • 파일/메모리에서 섹션의 시작위치는 각 파일/메모리의 최소 기본 단위의 배수에 해당하는 위치여야 하고,
    빈 공간은 NULL 로 채워버립니다. (<Fig. 2> 를 보면 각 섹션의 시작이 이쁘게 딱딱 끊어지는 걸 볼 수 있습니다.)



VA & RVA



VA (Virtual Address) 는 프로세스 가상 메모리의 절대 주소를 말하며,
RVA (Relative Virtual Address) 는 어느 기준위치(ImageBase) 에서부터의 상대 주소를 말합니다.

VA 와 RVA 의 관계는 아래 식과 같습니다.

RVA + ImageBase = VA

PE header 내의 많은 정보는 RVA 형태로 된 것들이 많습니다.
그 이유는 PE 파일(주로 DLL)이 프로세스 가상 메모리의 특정 위치에 로딩되는 순간
이미 그 위치에 다른 PE 파일(DLL) 이 로딩 되어 있을 수 있습니다.

그럴때는 재배치(Relocation) 과정을 통해서 비어 있는 다른 위치에 로딩되어야 하는데,
만약 PE header 정보들이 VA (Virtual Address - 절대주소) 로 되어 있다면 정상적인 엑세스가 이루어지지 않을것입니다.

정보들이 RVA (Relative Virtual Address - 상대주소) 로 되어 있으면 Relocation 이 발생해도
기준위치에 대한 상대주소는 변하지 않기 때문에 아무런 문제없이 원하는 정보에 엑세스 할 수 있을 것입니다.




이어지는 강좌에서 PE Header 구조체를 하나씩 상세히 살펴보도록 하겠습니다.



(continue)



반응형

+ Recent posts