HelloReversing.exex




문자열 패치

목표 달성이 눈앞에 다가왔습니다.

MessageBoxW 호출하는 부분을 찾았으니 이제 "Hello World!" 문자열을 "Hello Reversing!" 으로 패치시킬 차례입니다.

디버깅을 재실행[Ctrl+F2] 시키고, main 함수 시작 부분까지 실행합니다.
(401000 에 BP 를 설정[F2]하고 실행[F9] 하세요. - 이 주소를 2 번째 베이스 캠프라고 하겠습니다.)




문자열을 패치하는 2 가지 방법

가장 쉬운 2 가지 방법을 소개합니다.

  • 문자열 버퍼를 직접 수정
  • 다른 메모리 영역에 새로운 문자열을 생성하여 전달



1) 문자열 버퍼를 직접 수정

MessageBoxW 함수의 전달인자 4092A4 의 메모리 주소 내용("Hello World!\)을 직접 수정해 버리는 것입니다.

메모리 윈도우에서 4092A4 로 갑니다 [Ctrl+G].
그리고 주소를 마우스로 선택한 후 [Ctrl+E] 단축키로 에디트 윈도우를 띄웁니다.


<Fig. 16>


'UNICODE' 항목에 "Hello Reversing!" 을 입력합니다.

변경된 코드는 아래와 같습니다.


<Fig. 17>


명령어는 그대로
이지만 MessageBoxW 함수에 전달되는 파라미터의 내용 자체가 변경되었습니다.
(파라미터의 주소도 그대로 입니다. 주소의 내용이 변경된 것입니다.)

이처럼 문자열 버퍼 내용을 직접 수정하는 방법은 사용하기에 가장 간단한 방법입니다.

* 하지만 기존 문자열 버퍼 크기를 잘 고려해서 수정해야만 프로그램이 에러 없이 잘 동작할 수 있습니다.
  즉, 기존 문자열 버퍼 크기 이상의 문자를 입력할 수 없다는 제약 조건이 있습니다.

변경된 내용을 영구히 보존하려면 파일로 만들어야 합니다.
<Fig. 16> 의 dump 윈도우에서 변경된 내용 ("Hello Reversing!" 문자열)을 선택하여
마우스 우측 버튼의 Copy to executable file 메뉴를 선택하면 아래와 같이 hexa 윈도우가 나타납니다.


<Fig. 18>


다시 마우스 우측 버튼의 Save file 메뉴를 선택하고 파일 이름을 HelloReversing.exe 로 해줍니다.

실행해보면 문자열이 성공적으로 변경되었습니다!


<Fig. 19>




2) 다른 메모리 영역에 새로운 문자열을 생성하여 전달

1) 방법은 MessageBoxW 함수의 파라미터인 문자열 버퍼의 내용을 직접 수정하는 방법이었습니다.

간단하지만 그만큼 단점도 존재합니다.
가령 훨씬 긴 문자열로 수정하고 싶을때 해당 버퍼 크기가 작다면
인접한 다른 메모리 영역을 침범하는 buffer overflow 가 발생할 것입니다.

이럴때 사용할 수 있는 방법이 바로 다른 버퍼 주소를 전달하는 것입니다.
적당한 메모리 주소에 변경하고자 하는 긴 문자열을 적어 놓고
MessageBoxW 함수에게 그 주소를 파라미터로 넘겨주는 것입니다.

즉, 버퍼 자체를 변경하는 것이죠.

아이디어가 좋긴 한데 한가지 고려해야 할 사항은 "메모리 어느 영역에 문자열을 써도 되는가?" 입니다.

자세한 설명은 PE header가상 메모리 구조를 알고 계셔야 하므로 나중에 자세히 다루도록 하고,
여기서는 임의로 적절한 영역을 선택하도록 하겠습니다.

우리가 방법 1) 에서 수정한 버퍼는 408000 ~ 40A000 영역 (.rdata section) 입니다.
이 부분을 다시 dump 윈도우로 살펴보죠. dump 윈도우에서 408000 주소로 갑니다. [Ctrl+G]

스크롤을 밑으로 내리다보면 .rdata section 은 아래와 같이 끝이 납니다.


<Fig. 20>


끝부분에 NULL 로 채워진 영역이 보입니다.

* 이곳은 보통 프로그램에서 사용되지 않는 NULL padding 영역입니다.
  프로그램이 메모리에 로딩될 때 최소 기본 단위(보통 1000)가 있습니다.
  비록 프로그램내에서 메모리를 100 크기만큼만 사용한다고 해도 실제로는 최소 기본 단위인 1000 크기가 잡히는 것입니다.
  (나머지 F00 크기의 사용되지 않는 영역은 그냥 NULL 로 채워집니다.)

이곳을 문자열 버퍼로 사용해서 MessageBoxW 함수에 넘겨주면 좋을 것 같습니다.
끝부분의 적당한 위치 409F50 에 출력하고 싶은 문자열을 써주면 됩니다. [Ctrl+E]


<Fig. 21>


버퍼를 새로 구성하였으니 그 다음에 할 일은 MessageBoxW 함수에게 새로운 버퍼 주소를 전달하는 것입니다.

그러기 위해서는 코드를 수정해야 하는데,
이번에는 Code 윈도우에서 Assemble 명령을 사용해서 코드를 수정해 보겠습니다.

아래 그림처럼 cursor 를 401007 주소위치에 놓고 Assemble 명령(단축키 [Space])을 내리면
아래와 같은 Assemble 윈도우가 나타납니다.


<Fig. 22>


새로운 버퍼주소인 409F50 을 입력합니다.

* 디버깅의 강력한 기능중의 하나가 바로 위와 같이 실행중인 프로세스의 코드를 동적으로 패치 시킬 수 있다는 것입니다.

* 향후 실습해 볼 crackme 샘플에서 serial key 검사 코드를 건너뛰는 방법도 코드를 동적으로 패치하는 것입니다.

OllyDbg 에서 MessageBoxW 함수를 실행하면 결과는 <Fig. 19> 와 같습니다.

그런데 위 수정된 코드를 파일로 만들면 제대로 동작하지 않을 것입니다.
이유는 409F50 메모리 주소 때문입니다.

실행 파일이 메모리에 로딩되어 프로세스로써 실행될 때 그대로 1:1 로 로딩되는 것이 아니라,
어떤 규칙에 의해서 올라가게 되며, 보통은 파일과 메모리가 1:1 로 매칭 되지도 않습니다.

즉, 메모리 409F50 에 대응되는 파일 offset 이 존재하지 않는 것이죠.

방법 2)를 파일로 저장하기 위해서는 아래 2가지 방법중에 하나를 사용하시면 됩니다.

  • PE header 를 분석하여 파일에 존재하지만 프로그램에서 사용되지 않는 공간을 버퍼영역으로 선정
  • 파일 끝을 버퍼 영역 만큼 확장하고, PE header 를 수정하여 그 부분을 메모리에 로딩시킴


역시 PE header 를 알아야 하기에 여기서는 설명을 생략하였습니다.

* 앞으로 작성하게 될 PE header 강좌도 기대해 주세요~



배운내용

- OllyDbg 기초 사용법

Step Into [F7] : 하나의 OP code 실행 (CALL 명령을 만나면, 그 함수 코드 내부로 따라 들어감.)
Step Over [F8] : 하나의 OP code 실행 (CALL 명령을 만나면, 따라 들어가지 않고 그냥 함수자체를 실행함.)
Execute till Return [Ctrl+F9] : 함수 코드 내에서 RETN 명령어 까지 실행 (함수 탈출 목적)
Restart [Ctrl+F2] : 다시 처음부터 디버깅 시작. (디버깅 당하는 프로세스를 종료하고 재실행 시킴.)
Go to [Ctrl+G] : 원하는 주소를 찾아감. (코드를 확인할 때 사용. 실행되는 것은 아님.)
Execute till Cursor [F4] : cursor 위치까지 실행함 (디버깅 하고 싶은 주소까지 바로 갈 수 있음.)
Comment [;] : Comment 추가
User Defined Comments [마우스 우측 메뉴 -> Search for -> User defined Comment] : 사용자가 입력한 comment 목록 보기
Set/Reset BreakPoint [F2] : BP 설정/해제
Run [F9] : 실행 (BP 가 걸려있으면 그곳에서 실행이 정지됨.)
All referenced text strings [마우스 우측 메뉴 -> Search for -> All referenced text strings] : 코드에서 참조되는 문자열 보기
All intermodular calls [마우스 우측 메뉴 -> Search for -> All intermodular calls] : 코드에서 호출되는 모든 API 함수 보기
Name in all modules [마우스 우측 메뉴 -> Search for -> Name in all modules] : 모든 API 함수 보기
Edit data [Ctrl+E] : 메모리 수정
Assemble [Space] : Assembly 코드 작성
Copy to executable file [마우스 우측 메뉴 -> Copy to executable file] : 파일의 복사본 생성 (변경사항 반영됨)

- Assembly 기초 명령어

CALL XXXX : XXXX 주소의 함수를 호출
JMP XXXX : XXXX 주소로 점프
PUSH XXXX : 스택에 XXXX 저장
RETN : 스택에 저장된 복귀주소로 점프

- 프로세스 data/code 패치 방법

OllyDbg 의 ‘Edit data’와’Assemble’기능 이용

- 용어

VA (Virtual Address) : 프로세스내의 가상 메모리
OP code (OPeration code) : CPU 명령어 (byte code)
PE (Portable Executable) : Windows 실행 파일(EXE, DLL, SYS)




배워야할 내용

Virtual memory
PE header
Stack frame
OP code (advanced)
OllyDbg (advanced)



Epilogue

여기까지 따라 오시느라고 수고 하셨습니다.

위에 나온 모든 내용을 한번에 이해하기는 어렵습니다.
2 ~ 3번 반복해서 읽고, 직접 실습해 보시기 바랍니다.

C 프로그래밍에서 Hello World! 는 가장 간단한 프로그램이었습니다.
마찬가지로 Hello World! 디버깅 또한 가장 간단한 디버깅입니다.

Hello World! 를 시작으로 C 프로그래밍을 정복하셨듯이 디버깅 역시 정복하시기 바랍니다.

리버싱에서 디버깅이 차지하는 비중은 매우 큽니다. 또한 가장 재미있습니다.

부디 제 글이 디버깅의 재미를 조금이나마 전달해 드렸으면 좋겠습니다.

감사합니다.

    이전 댓글 더보기
  1. 이누 2010.07.28 12:51 신고 댓글주소 | 수정 | 삭제 | 댓글

    최고입니다!
    정말 쉽게 잘 설명해주시는군요!

    책은 준비중이시라니, 책도 너무 기대됩니다!

  2. 라이벌 2010.07.31 11:44 신고 댓글주소 | 수정 | 삭제 | 댓글

    와.. 멋진 강의! 감사합니다.
    여기서 정말 많은 것을 배워갑니다. ^^
    책... 저도 너무 기대됩니다. 흘흘

  3. 2010.08.02 22:40 댓글주소 | 수정 | 삭제 | 댓글

    비밀댓글입니다

    • reversecore 2010.08.04 21:56 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      이렇게 한번 해보시기 바랍니다.

      변경하신 부분을 마우스로 죽 선택하신 후 그 위치에서 마우스 우측메뉴를 선택해 보세요~

      감사합니다. ^^

  4. 공부중 2010.08.16 15:28 신고 댓글주소 | 수정 | 삭제 | 댓글

    와..정말 자세한 설명 감사합니다..
    이해가 쏙쏙되네요...
    왠지 모르게 모든 리버싱을 할수있을것같은 자신감이 드는이유는 뭘까요 ㅎㅎ ^^

    • reversecore 2010.08.20 15:24 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      리버싱에 자신감은 매우 중요합니다.

      알고보면 별거 아니거든요. 처음에 겁 먹지 않는 것이 중요하지요. ^^

      분명히 앞으로 리버싱을 잘 하실 것입니다.

  5. 감사합니다 2010.09.27 21:22 신고 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요,
    정말 훌륭한 글이기에 감사를 표현하지 않으수 없네요.
    어려운 리버싱을 이해하는데 너무 많은 도움이 됩니다.
    감사합니다.

  6. reversingK 2010.11.09 20:51 신고 댓글주소 | 수정 | 삭제 | 댓글

    ㅎㅎ Hello World1강 부터 3강 까지 너무 잘봤습니다.
    리버싱 처음 하지만 강의가 너무 좋아~ 쉽고 재미있게
    따라 한거 같습니다.. 뒤에 있는 강의도 기대됩니다^^
    열심히보고 열심히 배우겠습니다. 이런 좋은 강의
    올려주셔서 너무 감사합니다 ^^

  7. 리버싱입문자 2010.12.14 23:45 신고 댓글주소 | 수정 | 삭제 | 댓글

    이제 막 리버싱에 입문했는데
    다른 강좌들은 너무 어려워서 고생하고있었는데
    이 블로그는 입문자에게 좋은 내용인거 같습니다.
    책도 곧 출판되신다는 소식 들었는데
    기대 많이 하고있습니다.
    감사해요~ ㅎ

  8. Reverser_H 2011.01.19 21:33 신고 댓글주소 | 수정 | 삭제 | 댓글

    강의가 너무 좋네요~

    책이 나오면 바로 절판되지 않을까 하는

    걱정이 들기도 하는군요 ^^

    • reversecore 2011.01.20 00:08 신고 댓글주소 | 수정 | 삭제

      ㅎㅎ

      그것도 나름대로 제겐 의미 있는 일입니다.

      리버싱을 널리 보급하는게 목표니까요~

      책이 나와도 블로그 내용은 계속 유지합니다.

      그리고 더 흥미로운 분석 위주의 내용으로 채울 예정입니다.

      감사합니다.

  9. 아르가페 2011.03.02 18:12 신고 댓글주소 | 수정 | 삭제 | 댓글

    너무 쉽게 설명해주시니 초보인 저로서는 배우기가 그만이네요^^

  10. TeamKhan 2011.03.04 17:20 신고 댓글주소 | 수정 | 삭제 | 댓글

    OllyDbg 에서 MessageBoxW 함수를 실행하면 결과는 <Fig. 19> 와 같습니다.

    그런데 위 수정된 코드를 파일로 만들면 제대로 동작하지 않을 것입니다.
    이유는 409F50 메모리 주소 때문입니다.

    실행 파일이 메모리에 로딩되어 프로세스로써 실행될 때 그대로 1:1 로 로딩되는 것이 아니라,
    어떤 규칙에 의해서 올라가게 되며, 보통은 파일과 메모리가 1:1 로 매칭 되지도 않습니다.

    즉, 메모리 409F50 에 대응되는 파일 offset 이 존재하지 않는 것이죠.
    ==========================================
    라는 본문이 잘 이해가안가는데요... 실행파일이 메모리에 로딩되어서
    실행될때 그대로 1:1로 로딩되는것이 아니라고하셧는데 1:1로 로딩안된다는게
    무슨소린지모르겟구요...파일과 메모리가 1:1로 매칭된다는 말씀도 전혀 이해가안가내요...
    무엇보다 409f50에 대응되는 파일 offset이 존재하지않는다는말도 이해가안갑니다...
    파일 offset이 뭐길래...ㅠ 정말 답답합니다 답변부탁드려요 ..ㅠ

    • reversecore 2011.03.10 11:05 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      PE 파일 구조를 모르시면 저 말을 이해하기 힘드실 겁니다.

      그래서 제가 본문에 PE header 를 공부하셔야 한다고 코멘트를 달아두었죠. ^^

      제 원래 의도는 그러한 개념은 약간 어렵고 재미 없으니 차차 공부하기로 하고, 일단 디버깅에 재미를 가져보자는 것이었습니다.

      리버싱 입문 과정에서부터 PE Header 를 설명하면 너무 지루하기 때문에 일단 기반 기술 설명 없이 디버깅 자체만을 보여드렸습니다.

      질문하신 내용에 대해서 간단히 설명드리자면...
      실행 파일(EXE)이 메모리에 올라가서 실행되면, 파일로 존재할때의 모습과 메모리에 로딩된 모습이 서로 다릅니다.

      어떻게 달라지는지를 알려면 PE 파일 구조를 공부하셔야 되는 것이구요. 리버싱에서 필수 과목이라고 생각하시면 됩니다.

      그리고 파일 Offset 이란 말은 파일을 Hex Editor 로 봤을 때 파일 시작 부터의 거리를 의미합니다. (시작이 0, 끝은 파일크기-1 과 같지요.)

      제 블로그의 PE 설명을 처음부터 읽어보시구요. 또 질문 올려주세요~

      감사합니다.

  11. 대단하세요 2011.03.11 13:24 신고 댓글주소 | 수정 | 삭제 | 댓글

    구글로 몇일쨰 강좌를쳐봐도 제대로된것도없고 어제여기를 발견하게되어서 막꼼꼼히살펴보고해서 지

    금 여기까지오게되었는데.. 제가 해보고싶은것은 게임실행파일이나 다른소프트웨어 등 리버싱을 하고싶은데

    그정도실력까지가려면 오래걸릴까요.. 이번년도는 하려고하는데.. 작성자분께선 정말대단하시네요

    • reversecore 2011.03.16 22:47 신고 댓글주소 | 수정 | 삭제

      안녕하세요. 반갑습니다.

      음... 뭐든지 주변에 좋은 스승이 계시다면 금방 배울 수 있습니다. 1년정도 제대로 교육받으시면 충분히 원하시는 정도의 리버싱이 가능하십니다.

      하지만 저렇게 체계적으로 배울 수 있는 곳은 국내에 몇몇 회사 정도 뿐입니다. (사실 회사에서 배우는것도 거의 독학 수준입니다만... 그래도 아무때나 질문할 수 있다는 것은 엄청난 장점입니다.)

      인터넷으로 독학하신다면... 많은 시간을 투자하시고 시행착오도 겪으셔야 할 것이라고 생각됩니다.

      감사합니다.

  12. 아무개 2011.03.22 00:02 신고 댓글주소 | 수정 | 삭제 | 댓글

    넘 좋은 글을 읽고 가네요...
    근데요.. 한가지 질문,,, 맨위에 있는 첨부파일의 정체는 몬가요?
    앞선 강의에서 사용하던 걸 패치한것 같진 않고요... ????

  13. 갓태어난.. 2011.04.26 17:05 신고 댓글주소 | 수정 | 삭제 | 댓글

    본인에 것을 남에게 나누어 주는것이 결코 쉬운일이 아닌데

    정말 대단하신 분 같습니다.

    첫강부터 정말 설명을 너무 잘해주셔서..쉽게 따라 해보았습니다.

    천천히 꾸준이 열심히 따라가겠습니다.

    앞으로 많은 가르침을 주십시요..

    정말 감사합니다.

  14. 리버싱생초보 2011.06.26 20:13 신고 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세여 강의 잘보고 있습니다.

    이 글을 따라 하던도중, 방법2)에서 문자열 출력할때 PUSH 409F50 으로 바꾼 후 실행을 하니

    헥스?에서 409F50주소에 있는 문자열만 출력되고 그 밑에 있는 409F60까지는 출력이 되질 않네

    요 ';;

    요약하면은 409F50과 409F60에 Hello, Reversing 을 입력하면 Hello, 까지밖에 안나옵니다 ㅜㅜ 어

    떻게 된걸까여.. 중간에 띄어쓰기하려고 4칸을 비워둔

    게 문제일까여;;?

    • reversecore 2011.06.29 12:09 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      네, 문자열 중간에 NULL(0) 이 삽입되어서 그렇습니다.

      띄어쓰기를 하시려면 공백(Space) 에 해당하는 ASCII 코드 0x20 을 입력해 주시면 됩니다.

      감사합니다.

  15. bomberman 2011.07.15 01:45 신고 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요, 리버싱 공부를 시작하는 학생입니다 ^^
    아는분 추천으로 들렀는데 정말 도움많이되었습니다.
    자주 들르겠습니다 ~

  16. bomberman 2011.07.15 01:45 신고 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요, 리버싱 공부를 시작하는 학생입니다 ^^
    아는분 추천으로 들렀는데 정말 도움많이되었습니다.
    자주 들르겠습니다 ~

  17. 잘읽었습니다. 2011.08.01 23:08 신고 댓글주소 | 수정 | 삭제 | 댓글

    잘읽었습니다.^^:
    감사합니다.

  18. hongyang 2012.05.15 22:26 신고 댓글주소 | 수정 | 삭제 | 댓글

    으어엉 눈물이 핑돈다. 책나오면 바로사야지 ㅡㅡㅋ

  19. STIH 2012.06.17 19:55 신고 댓글주소 | 수정 | 삭제 | 댓글

    좋은 글 잘보았습니다. : )

  20. TepeRin 2012.06.27 17:28 신고 댓글주소 | 수정 | 삭제 | 댓글

    정말 설명이 자세해서 너무 좋았습니다. 사용을 해도 뭐가 뭔줄 몰랐는데, 이 글이 저의 이해를 도와주네요. 감사합니다.





티스토리 툴바