'Reversing'에 해당되는 글 4건

  1. 2010.08.19 [Reversing With Lena] lena's tutorial 14 풀이

1. 개 요
예제 문제 및 강의 내용 출처 : http://www.tuts4you.com/download.php?view.135

이번 Lena의 14장 강의에서는 디버깅 대상에 대한 좀 더 자세한 Patch 기법과 inline patching에 대하여 설명한다.


2. 사용도구
Ollydbg :
http://www.ollydbg.de


3. 분 석
리버싱 대상 프로그램을 PEiD로 확인해 보면 Microsoft Visual C++ 6.0로 생성된 프로그램임을 알 수 있다.
일단 OllyDbg를 이용하여 프로그램을 로딩해 보자.

위와 같이 남아 있는 사용기간과 Reg. Code를 입력하는 부분이 있는 것을 알 수 있다.(실제 lena131의 강의와 틀린 부분이 있을 수 있음)
일단 "Enter Reg. Code" 를 클릭한 뒤 임의의 값을 입력하자. "확인" 버튼을 클릭하기 전에 다시 OllyDbg로 이동한다.

Ctrl+N을 눌러 KillerTimer 함수를 선택한 뒤 위와 같이 KillTimer가 호출되는 모든 부분에 BP를 설정한다. KillerTimer 함수에 대한 정의는 다음과 같다.


시리얼을 입력한 창에서 이제 "확인" 버튼을 눌러보자.
위와 같이 4DC1A7 부분에서 멈추는 것을 볼 수 있으며, 등록 성공과 실패시 출력되는 메시지를 볼 수 있다. 또한 CMP 구문 뒤의 JNZ 문에 의해서 많은 조건 분기가 이루어 지는 것을 볼 수 있으며, 마지막으로 EAX의 값을 0B와 비교하는 것을 알 수 있다. 단순 Good Boy와 Bad Boy 진입만을 비교했을 때 EAX의 값은 3이 아니고 4이어야 된다는 것을 알 수 있다.

CMP EAX, 3 구문을 클릭하면 어디에서 인가 분기하여 온 것을 알 수 있다.
위 그림과 같이 CMP EAX, 3 구문 클릭 후에 jump from 004DC04C에서 마우스 우클릭 후 "Go to JNZ from 004DC04C"를 클릭한다.
해당하는 곳으로 이동하며 JNZ 구문 위에 또 CMP 구문이 있으며 어디에서 인가 분기된 구문임을 알 수 있다. 위와 동일한 방법을 이용하여 계속 추적해서 소스를 거슬러 올라가 보자.

마지막까지 이동하면 아래와 같은 부분을 만날 수 있으며, 구문의 구조를 보아 시리얼 값의 정상 여부를 체크하는 함수의 시작 부분임을 알 수 있다.

최초의 비교 구문은 CMP EAX, 1 부분 임을 알 수 있으며 EAX의 값은 "MOV EAX, DWORD PTR SS:[EBP+8]"에서 설정됨을 알 수 있다.
따라서 시리얼 검사 루틴의 시작 부분(0x004DBD80)과 최초 EAX 값 설정 부분(0x004DbD9E)에 BP를 설정한다. 이후 F9를 눌러 다시 프로그램을 실행한 뒤 다시 시리얼 값을 입력한 뒤 확인 버튼을 눌러보자.

위와 같이 4DBD80에서 정지되는 것을 볼 수 있으며 EAX의 값은 3으로 설정되는 것을 알 수 있다. 하지만 시리얼 값 등록이 성공하기 위해서 EAX의 값은 4이어야 한다. EAX 값이 설정되는 부분에서 간단하게 "MOV EAX, 4"로 변경하면 쉽게 해결이 가능하겠지만 여의치가 않다. 그 이유는 4DBD9E 주소는 3 Bytes를 이용하여 EAX 값을 설정하지만 "MOV EAX, 4"는 총 5Bytes가 필요하게 된다. 따라서 다른 방법을 사용해야 한다. 따라서 "inline patching" 기법을 사용하기로 한다.

lena151은 code cave(메모리 상의 사용되지 않는 공간으로 프로그램 행위 변경을 위해 특정 프로그램 코드를 삽입할 공간)라 칭하는 공간을 이용하여 inline patching 하는 방법을 설명한다. 하지만 여전히 OP Code가 사용하는 Bytes가 골치거리이다. 현재 3Bytes의 공간 사용만(4DBD9E 주소의) 가용하지만 long jump를 위해서는 5 Bytes가 필요하게 되므로 바로 뒤에 나오는 2 Bytes의 명령인 "PUSH EBX", "PUSH ESI"가 덮어 씌워지게 되어 원치 않는 결과가 발생할 수 있다.

이를 해결하기 위해 lena151은 다음과 같은 방법을 제시한다. 일단 아래와 같이 복사를 해두며, 나중을 위해 4DBD9E 주소에 북마크를 설정해 둔다,(우클릭 -> Bookmark -> Insert bookmark 1)

다음 code cave를 찾아 우리가 원하는 명령어들을 입력해 준다. 예제에서는 5E47D4 주소를 사용하고 있다. 아래와 같이 시리얼값 등록을 위해 EAX 값을 4로 설정하는 부분과, 위에서 복사한 코드 부분을 복사해 준다. 마지막으로 정상적인 프로그램 흐름으로 다시 돌아오기 위핸 Jump 코드를 입력해 준다.

이제 프로그램에 code cave로 흐름이 옮겨 갈 수 있도록 jump 구문을 입력해 주자.

KillTimer에 걸린 BP는 더이상 필요없으므로 모두 해제하도록 한다.

이후 F9를 눌러 프로그램을 실행해도 시리얼 값을 검증하는 루틴(4DBD80)을 계속적으로 반복하는 것을 볼 수 있다. lena151의 경우 여기서 JMP EAX, 4 구문을 JMP EAX, 0B로 수정하여 해결하고 있다. 정확히 이해가 가지 않아 좀 더 생각해 봐야 할 듯 하다. 시리얼 값 최후의 검증 부분의 값이 0B 였던 것과 관련이 있는 듯 하다.

위와 같이 code cave 부분의 값을 MOV EAX, 0B로 변경 후 아래와 같이 정상적으로 시리얼 값이 등록되는 것을 볼 수 있다.

저작자 표시 비영리 변경 금지
신고
Posted by By. PHR34K