이전 강좌에서 이어지는 내용입니다. 

어셈블리 언어를 이용한 Code Injection (4)



# MessageBoxA() 파라미터 입력 1 – MB_OK

002D002C    6A 00         PUSH 0

PUSH 0 은 스택에 0 을 입력하는 명령입니다. 이 0 의 의미는 아래에서 호출될 MessageBoxA() API 의 네 번째 파라미터(uType)로 사용됩니다.

참고로 MessageBoxA() API 는 아래와 같이 4 개의 파라미터를 받습니다.

int WINAPI MessageBox(
  __in_opt  HWND hWnd,
  __in_opt  LPCTSTR lpText,
  __in_opt  LPCTSTR lpCaption,
  __in      UINT uType
);


* 참고
uType 값이 0 이면 MB_OK 를 의미하며, 단순히 OK(“확인”) 버튼 한 개만 보여주게 됩니다.


# MessageBoxA() 파라미터 입력 2 – "ReverseCore"

002D002E    E8 0C000000   CALL 002D003F
002D0033    52            PUSH EDX
002D0034    65:76 65      JBE SHORT 002D009C
002D0037    72 73         JB SHORT 002D00AC
002D0039    65:43         INC EBX
002D003B    6F            OUTS DX,DWORD PTR ES:[EDI]
002D003C    72 65         JB SHORT 002D00A3
002D003E    00E8          ADD AL,CH

이번에는 CALL 명령으로 코드 사이에 포함된 문자열 데이터 주소를 스택에 입력하는 기법을 소개하겠습니다. 이 역시 Assembly 프로그래밍 언어에서만 가능한 기법입니다.

위 2D0033 ~ 2D003E 주소 영역은 분명히 프로그램 코드 영역이지만 그 내용은 사실 "ReverseCore" 문자열 데이터 입니다. (붉은색 표시 부분) 즉, "ReverseCore" 문자열의 시작주소는 2D0033 입니다. 그리고 이 문자열은 MessageBoxA() API 의 세 번째 파라미터 (lpCaption)로 사용됩니다. 

함수 파라미터로 사용되려면 문자열 주소를 스택에 넣어줘야 하는데 과연 어떤 방식으로 입력할까요? 

2D002E 주소의 CALL 002D003F 명령을 디버깅으로 쫓아 들어가 보겠습니다. (StepIn [F7]) 그리고 아래 그림과 같이 스택 주소를 봐주시기 바랍니다.


<Fig. 13>

스택에 "ReverseCore" 문자열 시작 주소인 2D0033 이 입력되었습니다!!! MessageBoxA() 의 세 번째 파라미터가 입력된 셈이죠.

이 트릭은 CALL 명령어의 "동작원리"를 응용한 것입니다.

CALL 002D003F 명령을 수행하면 함수(2D003F) 가 종료된 후 돌아올 리턴 주소(2D0033)를 스택에 입력(PUSH)한 후 해당 함수 주소(2D003F)로 이동(JMP)합니다. 즉, CALL 명령어는 PUSH, JMP 명령어를 합쳐 놓은 것입니다. 

사실 2D003F 는 함수 형태가 아닙니다. RETN 명령어로 되돌아가는 형태가 아니란 얘기지요. 여기서의 CALL 002D003F 명령어는 바로 뒤에 이어지는 "ReverseCore" 문자열 주소를 스택에 입력하고 그 다음 코드 명령어로 가기 위해서 사용되고 있는 것입니다.

이해 되시나요? ^^ 재미있는 CALL 명령어 사용법입니다.


# MessageBoxA() 파라미터 입력 3 – "www.reversecore.com"

002D003F    E8 14000000   CALL 002D0058
002D0044    77 77         JA SHORT 002D00BD
002D0046    77 2E         JA SHORT 002D0076
002D0048    72 65         JB SHORT 002D00AF
002D004A    76 65         JBE SHORT 002D00B1
002D004C    72 73         JB SHORT 002D00C1
002D004E    65:636F 72    ARPL WORD PTR GS:[EDI+72],BP
002D0052    65:           PREFIX GS:
002D0053    2E:636F 6D    ARPL WORD PTR CS:[EDI+6D],BP
002D0057    006A 00       ADD BYTE PTR DS:[EDX],CH

역시 위 "ReverseCore" 문자열과 마찬가지로 MessageBoxA() API 의 두 번째 파라미터 lpText 문자열("www.reversecore.com")을 입력하는 명령입니다.

위 코드에서 빨간색으로 표시된 부분은 코드 명령어가 아니라 문자열 데이터("www.reversecore.com") 입니다. 

2D003F 주소의 CALL 002D0058 명령어는 (앞에서 설명 드린 바와 같이) 바로 뒤에 이어지는 문자열("www.reversecore.com") 데이터의 주소(2D0044)를 스택에 입력하고 그 다음 명령어 주소(2D0058)로 갑니다. (아래 그림 참고)


<Fig. 14>


# MessageBoxA() 파라미터 입력 4 – NULL

002D0058    6A 00         PUSH 0

MessageBoxA() API 의 첫 번째 파라미터인 hWnd 값을 입력합니다. 일반적으로는 메시지 박스가 소속된 윈도우 핸들을 입력하지만, 여기서는 NULL 을 입력하여 무소속(?) 메시지 박스가 출력되도록 만들겠습니다.


# MessageBoxA(NULL, "www.reversecore.com", "ReverseCore", MB_OK) 호출

002D005A    FFD0          CALL EAX

드디어 MessageBoxA() API 를 호출하는 CALL 명령어 입니다. 현재 EAX 레지스터에는 위에서 호출한 GetProcAddress() 에 의해서 리턴된 MessageBoxA() API 의 시작 주소(7793EA71)가 저장되어 있습니다. (<Fig. 12> 참고)

2D005A 주소의 CALL EAX 명령어까지 디버깅한 후 레지스터와 스택을 살펴보면 아래 그림과 같습니다.


<Fig. 15>

이 CALL EAX 명령어를 실행하면 메시지 박스가 나타날 것입니다.


<Fig. 16>


# ThreadProc() 리턴값 세팅

002D005C    33C0          XOR EAX,EAX

notepad.exe 프로세스에 인젝션된 코드(ThreadProc() 스레드 함수) 가 종료될 준비를 합니다. 스레드 함수의 리턴값을 0 으로 세팅하기 위해서 XOR EAX, EAX 명령어가 사용됩니다. 함수의 리턴값은 EAX 레지스터를 사용한다는 것을 기억 하시죠?

* 참고
XOR EAX, EAX 명령어는 EAX 레지스터를 0 으로 초기화하는 가장 쉽고 빠른 명령어 입니다. 디버깅하면서 많이 접하게 될 것입니다.


# Stack Frame 해제 및 함수 리턴

002D005E    8BE5          MOV ESP,EBP
002D0060    5D            POP EBP
002D0061    C3            RETN

ThreadProc() 함수 시작할 때 생성한 Stack Frame 을 해제 합니다. 그리고 RETN 명령으로 함수가 종료됩니다.

이 ThreadProc() 함수에서 Stack Frame 은 매우 중요합니다. 앞에서 설명 드린 "PUSH 를 이용한 스택에 문자열 넣는 기법" 에서 스택에 입력된 문자열을 일일이 POP 명령으로 힘들게 없앨 필요 없이 Stack Frame 해제 명령어 한방으로 가볍게 초기화 시킬 수 있습니다.

* 참고
Stack Frame 관련 내용은 아래 링크를 참고하세요~


+--+

Assembly 언어를 이용한 Code Injection 에 관한 설명을 마치도록 하겠습니다. C 언어 보다 더 자유로운 Assembly 언어를 사용하여 다양하고 창의적인 코드를 생성해 보시기 바랍니다. Assembly 초보자도 OllyDbg 의 "Assemble" 명령어를 이용하면 좀 더 쉽게 이용하실 수 있습니다.

위 실습을 다 끝내신 분께서는 한번 제 블로그 이미지에 있는 바이트 코드를 입력해서 실행해 보시기 바랍니다. ^^ 어떤 코드가 나타날까요? (OllyDbg 의 편집 기능과 New Origin Here 기능을 사용하면 되겠지요~)


ReverseCore

위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~

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

  1. 철이 2010/07/06 15:44 댓글주소 | 수정 | 삭제 | 댓글

    정말로 잘보았습니다 ㅎ

  2. sonickaka 2010/07/10 14:23 댓글주소 | 수정 | 삭제 | 댓글

    정말 좋은 포스팅 감사합니다 ^^
    코드 인젝션을 체계적으로 정리해볼수 있어서 너무 갚지네요.. ^^
    감사합니다~!

  3. 땅콩 2010/07/24 11:35 댓글주소 | 수정 | 삭제 | 댓글

    한번 꼭 다 봐야지 봐야지..하면서...계속 미루다가..방학이라서..
    매일보고 있습니다..ㅎㅎ (analysis..부분만..거의 다 본듯..)

    이렇게 좋은 자료를..날로 먹는거 같아서....

    암튼..너무 감사합니다...

  4. 2010/07/31 00:11 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글 입니다


◀ PREV : [1] : [2] : [3] : [4] : [5] : ... [84] : NEXT ▶