[리버싱 핵심원리]1부 2장_Hello Reversing!

2016. 10. 25. 06:052018년 이전글/역공학

기본기를 다지려고 리버싱 공부를 책보고 차근차근 해보기로 하였다 ㅎㅎ

그래서 선택한 책이 리버싱 핵심원리라는 책인데, 너무......길다!!!!!!!!!!!!

근데 해보고 싶으니까 해야쥐 ㅎㅎㅎ 코럼 잡담은 그만하고 시작하도록하겠다.

                                                                                                                                                                                   


1부 1장의 경우 마음가짐과 같은 당부를 하는 부분이라 생략하도록 하겠다. 1부 2장의 경우 "Hello World!"의 문자열을 포함한 메세지박스를 출력하는 코드를 작성한 후 그 동작원리를 알아보기 위해 리버싱실습을 하는 것을 목표로하는 듯하다. 그러면 우선 해당 코드를 작성해보자.


[그림 1]Hello World_cpp_code

그런데 책을 읽어보면 Release mode로 빌드를 하는 것이 코드가 더 간결해 져서 디버깅하기가 더 편하다고 말한다. 왜 그럴까??

엄~청 궁금해서 알아보았다 ㅎㅎ


Release Mode? Debug Mode?                                                                                                         

Release Mode     

  • 초기화하지않는다.

  • 같은 문자열 상수라도 서로 다른 공간에 할당된다.

  • 디버깅정보를 삽입하지 않고 코드를 최적화하여 실행 파일 크기를 최대한 줄여준다.

  • 속도나 크기면에서 월등히 유리하다.(메모리 점유율로 낮아지고 실행도 빨라진다.)

  • 더 이상 현재버전에서 내결함성이나 문제점들을 발견할 수 없었을때 빌드하여 주는 모드이다.

Debug Mode      

  • 실행파일에 디버깅 정보를 삽입하여 언제든지 디버깅할 수 있도록 하며 Debug서브 폴더에 실행파일을 만들어 준다.

  • 디버깅정보가 들어가 있기 때문에 실행파일 상태를 확인할 수 있다.

  • 디버그에 필요한 정보들을 실행시 계속 체크함으로써 속도가 느리다.


**즉, Debug mode와 Release mode에서 빌드할때의 차이점은 디버깅정보를 실행코드내에 넣느냐 넣지 않느냐이다.

좀 더 풀어서 쓰자면 Debug mode로 컴파일하게 된다면 실행상태에서 추적할 수 있는 정보가 실행파일 안에 들어가게 되므로 용량이 커지고 Release mode로 컴파일을 할경우 디버깅 정보없이 순수 코드자체의 기능만 컴파일되어 실행파일로 만들어진다.


**누가 내결함성이 뭐냐고 물어봄;;;그래서 찾아봄 ㅎㅎㅎ


출처:https://www.symantec.com/ko/kr/security_response/glossary/define.jsp?letter=f&word=fault-tolerance


*참고 및 퍼옴* https://social.msdn.microsoft.com/Forums/ko-KR/b1db19b8-106f-461e-ae99-a0fd01cb9a5f/tip-?forum=visualcsharpko

                                                                                                                                               


자! 그러면 해당 코드를 빌드하여 실행파일을 OllyDbg로 디버깅해보자.

우선, 책을 따라서 Release mode로 디버깅 해보고 나중에 Debug mode로 디버깅 해보겠다.

(비교하고픈 욕구가 생겼답 ㅎㅎㅎㅎㅎ)


[그림 2]Hello World_cpp_folder


 

[그림 3]Hello World_cpp_release(1)

자. 이제 release mode로 빌드된 프로그램을 디버깅해보자. 단, 책의 방향대로 실습을 해보자.


Main()함수 찾아 떠나봅세다~~-release mode편                                             


[그림 4]Hello World_cpp_release(2)

자, 처음 OllyDbg를 켜면 보이는 첫 명령어다. 여기서 주소값 01391255는 EP 즉, Entry Point 해당 실행파일의 시작주소이다. 위의 명령어를 그대로 읽어준다면 

"013915EA(2_2_hell .__security_init_cookie의 주소)의 함수를 호출한 후 013910E6(2_2_hell .__scrt_common_main_seh)로 점프하여라."

 라는 뜻을 가진다. 자, 그러면 013915EA의 주소에 있는 함수에 들어가보자.


[그림 5]Hello World_cpp_release(3)

[그림 6]Hello World_cpp_release(4)

[그림 5]와 [그림 6]이 주소값 013915EA에 있는 함수이다. 다음의 함수를 보면 정말 복잡해 보인다. 하지만 comment창에 보이는 함수들 같은 경우 보통 코드에서 호출되어지는 API들이므로 넘어가도록 하자. 자, 그럼 다시 main()을 찾으로 떠나보자. 함수에서 return을 하면 전에 있던 곳으로 돌아가게 되므로 위의 함수가 돌아가게 될 주소는 0139125A이다.

 자, 그럼 0139125A주소의 명령인 

"013910E6(2_2_hell .__scrt_common_main_seh)로 점프하여라."

를 따라가보면 다음 [그림 7]과 같다.

[그림 7]Hello World_cpp_release(5)

다음은 JMP문을 따라 013910E6주소로 갔을 때의 일부코드이다. 다음을 쭉 따라가면서 보다보면 

[그림 8]Hello World_cpp_release(6)

이런 함수가 보이는데, 아! 저런 식으로 말고 

[그림 9]Hello World_cpp_release(7)

[그림 9]에 CALL 01391000이런식으로 보일 수 도있을 듯하다.(책에는 주소값으로 나와있다.)

여튼, 위의 함수에 들어가보면

[그림 10]Hello World_cpp_release(8)

다음과 같이 messageBox를 호출하는 부분이 보인다. 보면 [그림 1]에서 짠 c++코드와 동일하다.

그렇다!! 여기가 main()함수이다.!! 처음 목표였던 'main()함수 찾기'를 달성하였다.

.

.

.

.

.

그런데, 진짜 진짜 무식한 방법으로 찾아간다는 느낌이든다!!

진짜!

싫다!

책에서 알려주는 꿀팁!

마치 내가 알려 주는 것처럼 써먹자!

꿀팁!!!

Basecamp설치

**여기서 내가 원하는 Basecamp주소를 main()함수의 주소인 01391000라고 하자.(크런데 어쩌다보니 01391002를 목표로 찾고있...........)

1.Goto명령을 이용하여 basecamp를 만들어서 디버깅을 하자!!!

ctrl+G를 하면 Goto명령을 할 수 있다.

[그림 11]Goto 명령

2.BP(Break Point)를 설치(F2)하고 실행(F9)을 하자!!!

[그림 12]Break Point

[그림 12]에서 빨간 글씨의 주소값이 BP가 걸린 것이고 F9를 눌러 실행을 시키면 BP에서 걸리게 된다.

3.주석(;)을 달고 주석을 찾아가자!!

;을 눌러서 주석을 다는 단축키를 사용해서 [그림 13]처럼 주석을 달고

[그림 13]comment(1)

Search for -> User defined-comment에 들어가보면 다음과 같이 해당 부분이 등록 되어 있다.

[그림 14]comment(2)


4.Label을 사용(:)하자!!!

[그림 14]Label(1)

:를 눌러서 label을 붙여주자. 그러면 

[그림 15]Label(2)

[그림 15]처럼 해당 주소 혹은 함수의 호출부분에서 다음과 같이 변화 된다. 또한 

Search for -> User defined-label에 들어가보면 다음과 같이 label이 등록되어 있다.

[그림 15]Label(3)



원하는 코드를 빨리 찾아내자

1.코드를 실행하자!!

계속, 반복적으로 실행하다보면 보이게 된다라고 하는데 그러면 뭐.........위에 방식이랑 뭐가 다름

2.문자열을 검색하자!!

Search for -> All referenced text strings에 들어가보면 프로그램코드에서 참조되는 문자열들이 보이는데 여기서 원하는 문자열들을 찾아서 BP를 걸고 시작하는 방법이다.

[그림 16]referenced text strings

3.API를 검색하자_호출코드에 BP

현재 연습용을 사용되고 있는 Hello World프로그램처럼 윈도우 내에서 창이 띄어진다면 Win32 API호출을 예상할 수 있다. 그러면 원하는 API의 위치를 찾아서 코드를 검색하는 방법도 있다.

     Search for -> intermodular calls에 들어가보면 프로그램에서 사용되는 API함수 호출 목록이 나타난다. 

[그림 17] Intermodular calls

여기서 원하는 API를 찾아 검색해나가는 방법도 존재한다.

4.API를 검색하자_API코드에 직접 BP

Search for -> name in all modules에 들어가보면 [그림 18]과 해당 프로그램을 실행시키기위해 로딩된 시스템 DLL파일이 제공하는 모든 API목록을 볼 수 있다.

 

[그림 18]name in all modules


프로그램을 패치시켜보아영~~                                             

 자, 이제는 main함수를 찾았으니 해당 함수를 한 번 변형시켜보자!!!! 책을 따라하려고 보니까 

Hello World! --> Hello Reversing!

 이라고 고칠려고 한다. 코러면 따라해야쥐이~~

1. 문자열 버퍼를 직접 수정하자.

[그림 19]patch_string buffer(1)

우선 문자열 "Hello World!"가 저장되어 있는 주소 1392120에 들어가자.

[그림 20]patch_string buffer(2)

해당 문자열을 드래그해서 선택해준 후 ctrl+E(edit)을 해주면 해당 영역만큼 문자열을 변경해줄 수 있다.

[그림 21]patch_string buffer(3)

다음과 같이 코드를 고치고 실행시켜보자.

[그림 22]patch_string buffer(4)

짜라라란~~~다음과 같이 고쳐졌다. 

그.런.데.!!!!!

요 방법은 사용하기엔 정말정말 간단하지만 기존 문자열 버퍼크기 이상의 문자를 입력하기가 어렵다는 제약조건이 존재한다ㅠㅠ

자!!!!그러면 다른방법을 알아보러 떠나보잡~~~

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

자, 이제 메모리가 비어있는 부분을 찾아서 모험을 떠나보자~~~~

오호~~!

[그림 23]patch_memory(1)

여기에 비어있네에에에!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

그러면 여기에 "Hello Reversing!"을 입력해주자 ㅎㅎㅎㅎㅎ

[그림 24]patch_memory(2)

이제 입력을 했으면 messagebox를 호출할때 "Hello World!"가 들어있는 주소말고 "Hello Reversing!"이 들어있는 주소로 바꾸어 주자 ㅎ

[그림 25]patch_memory(3)

[그림 26]patch_memory(4)

주소를 바꾸어주면 다음과 같이 변경되고 이것을 실행시켜보면

[그림 27]patch_memory(5)

쫜!!!!!!!!!!!!다음과 같이 문자열이 변경되어 실행된다 ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎ




Main()함수 찾아 떠나봅세다~~-debug mode편                                             


 자! 여러분 이제 제 개인의 사리사욕을 채울 시간이 왔습니다!!! 
얼마나!
Debug mode가!
Release mode보다!
개떡같나!
구경하고!
더러우면!
때려칩시다!

[그림 28]Hello World_cpp_debug(1)

호에?????EP부터 이렇게 더럽다니여 ㄷㄷㄷㄷㄷㄷㄷㄷ 크러면 정신건강을 위해 코냥 넘어가려고 했는데에......넘나 찝찝한것;;;;;;;;;걍 노동해야져 ㅎㅎㅎ

-------------호기심이 고양이를 죽인다------------꽥!!!!!

간단히 분석하기 위해서 위에 release에서 했던 디버깅을 참고하며 하도록하져 ㅎㅎ

[그림 4]를 보면 main함수가 있는 곳에 가려면 2_2_hell .__scrt_common_main_seh으로 점프하여야 했습니다 즉! JMP문에서 보이는 Label들에서 얘가 main으로 갈꺼 같다!라고 냄새를 풍기는 아이한테 가보도록 하자는 겁니다! 아까처럼 무식하게 다 찾아보지말고요.ㅎㅎㅎ그러면 여기 나!Main이야!잡아가죠!라고 홍보다니는 녀석이 보이네여

[그림 29]Hello World_cpp_debug(2)

wmain으로 말이져 ㅎㅎㅎㅎ 코러면 여기 들어가보도록 해볼까여 ㅎㅎㅎ

[그림 30]Hello World_cpp_debug(3)

오!!!!흐~미?? main()이네양 ㅎㅎㅎ 코러니까 저기저기 저런 이상한 JMP문들은 디버깅하는데 불피요한 요소들이네요 크러니까 아까 알아본바와 같이 Release mode에서는 실행에 필요한 최소한의 요소를 넣어서 빌드를 하고 debug mode에서는 디버깅정보까지 집어넣는다를 눈으로 확인해보았네양 ㅎㅎㅎ