앞서 소개해 드린 각 기법들 중에서 Debug 기법에 대한 설명입니다.

실습으로 메모장의 kernel32!WriteFile() API 를 후킹하여 기존과는 다른 동작을 하도록 만들어 보겠습니다.


<실습 예제 – WriteFile() API hooking>

API Hooking 의 기본 설명은 아래 글을 참고하세요.

API Hooking - 리버싱의 '꽃'
API Hooking - Tech Map



Debug Technique




<Fig. 1>

Debug 방식의 API 후킹을 설명 드리겠습니다. (위의 Tech Map 에서 빨간색 표시 부분을 참고하세요)

이 방식의 장점은 후킹을 위해서 '디버깅'을 사용하므로 좀 더 interactive 한 후킹을 수행할 수 있습니다. 즉, 간단한 GUI 를 제공하여 후킹 대상 프로그램의 실행을 제어하고, 메모리를 자유롭게 사용할 수 있습니다.

하지만 먼저 Debugger 구조에 대한 이해가 필요합니다.



Debugger 설명


# 용어

간단한 용어 정리부터 하겠습니다.

Debugger – debugging tool
Debuggee – application to debug

# 디버거 기능

Debugger 의 기능은 Debuggee 가 올바르게 실행되는지 확인하고 (예상치 못한) 프로그램의 오류를 발견하는 것입니다.

Debugger 는 Debuggee 의 명령어 instruction 을 하나씩 실행 가능하며, 레지스터와 메모리에 대한 모든 접근 권한을 가집니다.

# 디버거 동작 원리

일단 Debugger 프로세스로 등록되면 OS 는 Debuggee 에게 debug event가 발생할 때 Debuggee 의 실행을 멈추고 해당 event 를 Debugger 에게 통보합니다. Debugger 는 해당 event 에 대해 적절한 처리를 한 후 Debuggee 의 실행을 재개합니다.

* 일반적인 예외(Exception)도 Debug event 에 해당합니다.
* 만약 해당 프로세스가 디버깅 중이 아니었다면 debug event 는 자체 예외처리 아니면 OS 의 예외처리 루틴에서 처리됩니다.
* Debugger 는 debug event 중에서 처리할 수 없거나 관심 없는 event 들은 OS 가 처리하도록 만들어 줍니다.

아래 그림은 위 설명을 도식화 한 것입니다.


<Fig. 2>

# Debug event

Debug event 입니다.

EXCEPTION_DEBUG_EVENT     
CREATE_THREAD_DEBUG_EVENT  
CREATE_PROCESS_DEBUG_EVENT 
EXIT_THREAD_DEBUG_EVENT     
EXIT_PROCESS_DEBUG_EVENT   
LOAD_DLL_DEBUG_EVENT       
UNLOAD_DLL_DEBUG_EVENT     
OUTPUT_DEBUG_STRING_EVENT  
RIP_EVENT

* 출처 : http://msdn.microsoft.com/en-us/library/ms679302(VS.85).aspx

<List 1>

위 Debug event 중에서 Debugging 관련된 event 는 아래에 표시된 EXCEPTION_DEBUG_EVENT 입니다.

EXCEPTION_ACCESS_VIOLATION
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
EXCEPTION_BREAKPOINT
EXCEPTION_DATATYPE_MISALIGNMENT
EXCEPTION_FLT_DENORMAL_OPERAND
EXCEPTION_FLT_DIVIDE_BY_ZERO
EXCEPTION_FLT_INEXACT_RESULT
EXCEPTION_FLT_INVALID_OPERATION
EXCEPTION_FLT_OVERFLOW
EXCEPTION_FLT_STACK_CHECK
EXCEPTION_FLT_UNDERFLOW
EXCEPTION_ILLEGAL_INSTRUCTION
EXCEPTION_IN_PAGE_ERROR
EXCEPTION_INT_DIVIDE_BY_ZERO
EXCEPTION_INT_OVERFLOW
EXCEPTION_INVALID_DISPOSITION
EXCEPTION_NONCONTINUABLE_EXCEPTION
EXCEPTION_PRIV_INSTRUCTION
EXCEPTION_SINGLE_STEP
EXCEPTION_STACK_OVERFLOW

* 출처 : http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx

<List 2>

각종 예외(Exception) 중에서 Debugger 가 반드시 처리해야 하는 예외는 바로 EXCEPTION_BREAKPOINT 예외입니다.

BreakPoint 는 어셈블리 명령어 "INT3" 이며, IA-32 Op code 는 0xCC 입니다. 코드 디버깅 중에 INT3 명령어를 만나면 Debugger 에게 EXCEPTION_BREAKPOINT 예외 이벤트가 날아갑니다.

Debugger 에서 BreakPoint 를 구현하는 방법은 간단합니다.

BreakPoint 를 설치하기 원하는 코드의 메모리 시작 주소에서 1 byte 를 0xCC 로 바꿔 치는 것입니다. 디버깅을 계속 진행하고 싶을 때는 다시 원래 값으로 복원시키고 실행해줍니다.

Debug 방식의 API Hooking 은 이와 같은 BreakPoint 의 특성을 이용하는 것입니다.



API Hooking - Debug Method


Debug 기법을 통한 API Hooking 에 대해 좀 더 자세히 설명 드리겠습니다.

기본적인 아이디어는 Debugger-Debuggee 관계를 가진 상태에서 Debuggee 의 API 시작 부분을 0xCC 로 바꿔 제어를 Debugger 로 가져온 상태에서 원하는 작업을 수행한 후 Debuggee 를 다시 실행상태로 바꾸는 것입니다.

작업 흐름은 아래와 같습니다.

- 후킹을 원하는 프로세스에 ‘attach’ 하여 Debuggee 로 만듦
- Hook : API 시작 주소의 첫 바이트를 0xCC 로 변경
- 해당 API 가 호출되면 제어는 Debugger 에게 넘어옴
- 원하는 작업을 수행(파라미터, 리턴 값 조작 등)
- Unhook : Debuggee 의 0xCC 를 원래대로 복원시킴 (<– API 의 정상 실행을 위해)
- 해당 API 실행 (0xCC 가 빠진 정상적인 상태)
- Hook : 다시 0xCC 로 바꿈 (<– 지속적인 후킹을 위해)
- Debuggee 에게 제어를 되돌려줌


위 방식은 가장 간단한 경우를 소개한 것입니다.

이걸 기준으로 다양하게 변형할 수 있습니다. 가령 original API 를 호출 하지 않을 수 도 있고, 사용자가 제공한 custom API 를 호출 할 수 도 있고, 한번만 후킹 할 수도 있고, 여러 번 후킹 할 수도 있습니다.

작업 목적에 따라서 알맞게 변형해서 사용하시면 됩니다.



Notepad.exe 의 WriteFile() API Hooking


지금 까지 공부한 내용을 바탕으로 실제 코드를 보면서 실습을 해보도록 하겠습니다.

작업할 내용은 Notepad.exe 의 WriteFile() API 후킹입니다.
입력된 파라미터를 조작하여 소문자로 입력된 내용을 전부 대문자로 바꿔 보겠습니다.

즉, Notepad 에서 입력된 모든 소문자는 파일로 저장되는 순간에 대문자로 변경되어 저장됩니다.

Notepad.exe 를 실행시킨 후 PID 를 알아냅니다.


<Fig. 3>

첨부된 후킹 프로그램(hookdbg.exe)을 실행합니다.

hookdbg.exe 는 콘솔 기반 프로그램이며 실행 파라미터로 후킹 할 프로세스의 PID 를 넘겨 받습니다.



<Fig. 4>

위 그림과 같이 hookdbg.exe 를 실행하면 PID 1688 에 해당하는 notepad 프로세스의 WriteFile() API 후킹이 시작됩니다.

그리고 notepad 에 아무 글자나 입력해 보세요.


<Fig. 5>

입력을 마치셨으면 저장을 해주세요.


<Fig. 6>

저장을 마치면 notepad 화면에는 아무런 변화가 일어나지 않습니다. (WriteFile() API 만 후킹 했다는 사실을 기억해 주세요.)

notepad 를 종료해 주시고, hookdbg 프로그램을 봐주세요.


<Fig. 7>

위 그림을 보시면 “original string” 에는 제가 입력한 문자열이 나타나고, “converted string” 에는 변경된(소문자 -> 대문자) 문자열이 나타납니다.

이것은 hookdbg.exe 프로그램 내부에서 후킹의 진행과정을 표시하기 위해서 출력하는 문자열입니다.

실제로 대문자로 저장되었는지 파일을 열어서 확인합니다.


<Fig. 8>

정확히 모든 소문자가 대문자로 변경되어서 저장되었습니다.

이 예제는 아주 간단한 기능을 가지고 있지만 Debug Method 에 대한 기본적인 개념을 잘 설명해줄 수 있습니다.

다음 포스트에서 hookdbg.exe 의 실제 코드를 상세히 살펴보도록 하겠습니다.

API Hooking - 메모장 WriteFile() 후킹 (2)


+---+

ReverseCore

 

Trackback Address :: http://www.reversecore.com/trackback/56 관련글 쓰기

  1. 늅늅 2009/10/28 13:58 댓글주소 | 수정 | 삭제 | 댓글

    언제나 친절하게 설명 되어있는 강좌 잘 보고 있습니다 ^^

  2. 냥냥 2009/10/28 23:59 댓글주소 | 수정 | 삭제 | 댓글

    와... 정말 많은걸 보고 배워가요 ^^*
    좋은글 앞으로도.. 많이 많이 very 많이 많이 부탁드릴께요..ㅎㅎ
    댓글중에 회사원이라고 들었는데요... 하는 일이 무엇인가요..?
    전 학생이라... IT업계의 일에는 무엇이 있는지 궁금해서요... 프라이버시라면... 말 안해주셔도되요~
    히힛~..~ 양질의 좋은 자료 부탁드리겠습니다~ ㅎㅎ.. 근데 퍼가도 되는건가요..?!

    • ReverseCore 2009/10/29 06:14 댓글주소 | 수정 | 삭제

      냥냥님, 안녕하세요.

      도움이 되셨다니 기쁘네요~ ^^

      그냥 평범한 IT 관련 회사원이구요, 개발과 리버싱에 많은 관심을 가지고 있지요.

      퍼가지는 마시구요, 링크만 해주세요~
      (미리 물어봐 주셔서 감사합니다.)

  3. 이승철 2009/10/29 11:07 댓글주소 | 수정 | 삭제 | 댓글

    언제나 잘 보고 있습니다. 감사합니다.

  4. 김형근 2009/10/29 18:05 댓글주소 | 수정 | 삭제 | 댓글

    좋은글 감사합니다.
    궁금한것이 더 많아지네여 ^^
    좋은글 앞으로도 부탁드립니다.

  5. 몽상가 2009/10/30 03:19 댓글주소 | 수정 | 삭제 | 댓글

    저도 요즘 공부 차원에서 다시 보고 있습니다. ^^
    목표는 모 프로그램의 크랙입니다. 물론 나쁜 용도는 아니고, 최소한 내가 의도한 정도까지? 지만, 욕심이 크다보니 할 수 있는데 까지 해보는게 목표입니다.

    근데 일단 가장 기본적인 디버거를 붙이면 강제 종료되는데, 아마 이게 다른 쓰레드에서 디버그가 붙으면 강제종료를 하는 스레드가 있나 봅니다. 이럴땐 어떤 방식으로 해야되는가 궁금합니다.
    아예 실행하고 붙이는게 아니라 실행전에 수정을 해야되는건가요?

    강좌가 계속 나와서 이런 방식까지 나왔으면 좋겠습니다.
    제 블로그 링크도 해주시고 감사합니다. RSS 로 꾸준히 보고있어요 :D

    • reversecore 2009/10/30 07:19 댓글주소 | 수정 | 삭제

      몽상가님, 안녕하세요.

      디버깅 당했다고 판단되면 스스로 종료 <- 안티 디버깅 기법을 사용한 듯 하군요.

      계획에는 일반적인 안티디버깅에 대한 강좌를 하고, 특별한 안티기법은 파일을 분석하는 도중에 따로 정리해보려고 합니다.

      말씀하신 내용도 참고할께요~ (attach 할 수 없는 프로세스)

      감사합니다.

  6. 졸작땜시날새는코더 2009/10/30 13:51 댓글주소 | 수정 | 삭제 | 댓글

    글잘보았습니다 참고많이되었구요
    혹시
    특정 이벤트처리가아니라
    그 해당 프로그램이 사용하는 API함수들을 모두 체크할수있는 방법이없을까요
    변조하는게 아닌 그저 무슨 API함수를 사용했다 정도로만요
    대충 이미지는 나오는데 어떻게해야할지 막막합니다 ㅠㅠ

    • ReverseCore 2009/10/31 12:30 댓글주소 | 수정 | 삭제

      안녕하세요.

      프로그램이 사용하는 모든 API 함수를 확인하고 싶으시다는 말씀이시죠?

      IDAPro, OllyDbg 에서 그런 기능을 지원하는데요, 그 원리는 코드의 CALL, JMP 명령어을 전부 파싱하는 것입니다.

      혹시 이런류의 프로그램이나 OllyDbg 플러그인등이 존재할 수도 있겠네요.

      참고로 예전에 제가 했던 비슷한(?) 방법으로는 관심있는 API 를 전부(약 120여개) 후킹해서 각 파라미터/리턴값을 확인하고 호출 순서등을 확인한 적이 있었습니다.

  7. 냥냥 2009/10/31 03:16 댓글주소 | 수정 | 삭제 | 댓글

    NotePad에 관한 질문드리겠습니다 ㅠ
    제가 더미dll ( Attatch 시 빈 메세지 박스만띄우는 ) 을 만든후 Notepad.exe에 dll injection을 통해서 구현해보려고 했습니다.
    방식은 Notepad를 디버거로서 연다음 Notepad.exe의 메모리공간을 할당받은후 LoadLabrary()를 실행해서 더미dll을 Attatch시키게하는 명령어 코드를 복사한뒤 EIP수정후 실행하게한후, 실행후 다시 EIP를 원래의 EIP주소로 변경하도록 만들었습니다,
    근데... 제대로 동작을안하고 Notepad.exe가 그냥 죽어버리는군요...
    코드가 잘못됐는지 확인하려고... 아무런 보안기능이 없는 전에 만든 툴로 대상을 변경후 실행하니 아무런 이상없이 실행이 잘됐습니다 ( 빈 메세지박스를 확인 )
    Notepad.exe에서는 제대로 실행되지 않는 이유가 무엇을까요..?
    운영체제에서 특별한 알고리즘을 가지고 보호하는건가요..? ( 부팅시 원도우 기본파일들인 calc,notepad 같은 프로그램은 수정되었을시 복원하는 기능은 있다고 들었지만... )

    • ReverseCore 2009/10/31 12:35 댓글주소 | 수정 | 삭제

      안녕하세요

      어떤 OS 를 쓰시나요?

      전 주로 XP 를 쓰는데, DLL Injection 은 아무런 문제가 없습니다.

      다른 프로그램에서는 잘 동작하는데 notepad 만 동작하지 않는다고 하셨는데요, 저도 잘 이해가지 않는군요.

      참고로 DLL Injection 을 위해서 반드시 notepad 를 디버깅 할 필요는 없습니다. 그리고 DLL Injection 의 코드를 확인 해보시는 것이 좋을것 같습니다.

      가능하시면 저에게 보내주시기 바랍니다. 이곳에 올리셔도 되구요.

    • 나그네 2009/11/03 05:34 댓글주소 | 수정 | 삭제

      WFP(Windows File Protection) 때문에 그런거 아닐까요? system 폴더에 있는 notepad.exe 를 다른 폴더로 옮겨서하면 괜찮을 것 같은데요.ㅋ

    • reversecore 2009/11/03 22:25 댓글주소 | 수정 | 삭제

      나그네님, 소중한 답변 감사드립니다. ^^

  8. 냥냥 2009/10/31 16:09 댓글주소 | 수정 | 삭제 | 댓글

    메일 주소가 어떻게 되시나요..? ;;
    마땅히 보낼만한...ㅠㅠ

  9. vice 2009/12/16 11:15 댓글주소 | 수정 | 삭제 | 댓글

    잘 보구 갑니다. 간단하구 쉽게 설명 잘 해주시네요 ^^

  10. thav 2009/12/21 13:23 댓글주소 | 수정 | 삭제 | 댓글

    잘봤습니다. 근데. 님께서 첨부해주신 샘플 소스 구동하다가 notepad 저장할때 정지됩니다.
    혹시 이런 현상 보신적 있나요?
    OS 는 윈도우 XP 입니다.

    • ReverseCore 2009/12/22 11:30 댓글주소 | 수정 | 삭제

      thav님, 안녕하세요.
      notepad 저장시에 프로그램이 멈춘다는 말씀이시죠?

      제 환경(XP SP3)에서는 그런 일이 없었지만, 충분히 그럴 가능성은 있습니다.

      * 참고로 제 테스트 PC 는 OS 만 설치된 클린 PC 환경입니다.

      제가 여러가지 상황에서 충분히 테스트하지 않아서 그럴 수 있고요. thav님 PC 에 실행중인 프로세스들에 의해서 그렇게 될 수 도 있습니다. (충돌!)
      (또한 실습 예제 파일들은 코드의 간결성을 위해서 에러처리가 거의 되어있지 않습니다.)

      (가능하시다면) 다른 PC 에서도 테스트 해보시기 바랍니다.

      감사합니다.


◀ PREV : [1] : ... [28] : [29] : [30] : [31] : [32] : [33] : [34] : [35] : [36] : ... [84] : NEXT ▶