'aspack'에 해당되는 글 1건

  1. 2010.12.13 [Unpacking] ESP trick을 이용한 ASPack Manual Unpacking
0x03 Reversing/Reversing2010.12.13 20:14

1. 개 요
일을 하다 보면 unpacking이 필요한 순간이 많이 있어서 하나하나 정리하는 차원에서 정리해 보려고 합니다. 먼저 ESP trick을 이용한 ASPack 언팩부터 차근차근 정리해 나가야 겠습니다.

2. ASPack Manual Unpacking

먼저 언패킹 대상이 되는 샘플을 PEiD를 이용하여 살펴보겠습니다. [그림 1]과 같이 해당 파일은 ASPack 2.12 버젼으로 패킹되어 있는 것을 확인할 수 있으며, 섹션 테이블 정보를 봐도 패킹되어 있음을 추측할 수 있습니다.

[그림 1]

OllyDbg를 이용하여 해당 파일을 로딩해 보면 PUSHAD 구문에서 시작됨을 알 수 있습니다. PUSHAD는 범용 레지스터들에 저장된 값들을 스택에 저장하는 명령어입니다. 자세한 내용은 아래 표를 참고하시기 바랍니다.

 
PUSHAD Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI

Pushes the contents of the general-purpose registers onto the stack. The registers are stored on the stack in the following order: EAX, ECX, EDX, EBX, EBP, ESP (original value), EBP, ESI, and EDI (if the current operand-size attribute is 32) and AX, CX, DX, BX, SP (original value), BP, SI, and DI (if the operand-size attribute is 16). (These instructions perform the reverse operation of the POPA/POPAD instructions.) The value pushed for the ESP or SP register is its value before prior to pushing the first register (see the "Operation" section below).

ASPack 언패킹은 이 PUSHAD 명령어의 특성을 이용해서 충분히 가능합니다. [그림 2]와 같은 과정으로 ASPacker는 원본 코드를 메모리 상에 복구할 것입니다.

[그림 2]
위와 같은 특성을 이용하여 PUSHAD로 레지스터 값을 스택에 저장하고 나서는 차후에 다시 스택에 저장된 레지스터 값에 접근할 것입니다. 따라서 PUSHAD 이후 ESP가 가르키는 스택의 메모리 주소 접근시 BP(Break Point)를 설정해 두면 메모리 상에 복구를 마친 뒤 OEP 분기전의 상태가 될 것입니다.

OllyDbg로 로딩한 파일을 F8(Step-Over)을 눌러 PUSHAD를 진행해 보겠습니다. 아래 [그림 3]과 같이 스택에 레지스터의 값이 저장된 것을 볼 수 있으며 현재 ESP가 가르키는 곳의 주소에 해당 값들이 저장되어 있는 것을 볼 수 있습니다.
[그림 3]

위의 시나리오 대라면 원본 코드 메모리 상에 복구 후 레지스터 복구를 위해 현재 ESP가 가르키는 메모리 주소에 접근할 것입니다. 따라서 ESP가 가르키는 곳에 BP를 설정합니다. 설정 방법은 [그림 4]를 참고하시기 바랍니다. BP설정 후 Debug -> Hardware Breakpoints를 확인하시면 BP가 설정된 것을 확인할 수 있습니다.
[그림 4]

BP 설정 후 F9를 눌러 프로그램을 진행시켜 봅니다. 아래와 같이 [그림 5]에서 BP에 의해 진행이 멈추는 것을 볼 수 있습니다. JNZ 구문에 의해 분기가 일어나며 PUSH 구문을 이용하여 특정 주소(00401836)를 스택에 저장합니다. 이후 RETN 구문을 실행하게 됩니다. PUSH로 특정 주소 저장 후 RETN 구문을 만나게 되면 JMP 구문과 동일하게 스택에 저장된 주소로 점프하게 됩니다.
[그림 5]

실제로 F8을 눌러 진행하면 [그림 6]과 같이 00401836 주소로 점프하는 것을 볼 수 있습니다. 해당 주소에서 레지스터의 값들을 확인해 보면 처음에 PUSHAD를 실행하기 전의 레지스터 값들로 복구된 것을 확인할 수 있습니다. 따라서 00401836 주소가 OEP인 것을 확인할 수 있습니다.
[그림 6]

OEP를 찾았으니 [그림 7]과 같이 Ollydump를 이용하여 dump를 생성합니다.
[그림 7]

이제 IAT(Import Address Table)을 복구할 차례입니다. OllyDbg를 이용하여 좀 더 진행하다 보면 [그림 8]과 같이 실제 API를 호출하는 부분에서 함수들의 주소가 저장된 메모리 영역을 참조하는 것을 확인할 수 있습니다. 해당 메모리영역(403000) 부분을 확인하면 참조하는 API의 메모리 상의 포인터가 저장되어 있음을 확인할 수 있습니다.
[그림 8]

이제 ImportREC을 이용하여 IAT를 복구하도록 하겠습니다. [그림 9]와 같이 OEP, RVA, Size를 입력해 준 뒤 "Get Imports"를 클릭합니다. (물론 OEP 입력 후 ImportREC의 AutoSearch 기능을 이용해되 됩니다 :) )
[그림 9]
불필요한 값들이 많이 생성된 것을 확인할 수 있습니다. 불필요한 값들 제거를 위해 Show Invalid 클릭 후 Delete thunk(s)를 선택합니다. [그림 10]과 같이 유용한 IAT 값들만 남은 것을 확인할 수 있으며 이제 Fix Dump를 이용하여 OllyDbg를 이용하여 덤프해 놓은 파일에 해당 IAT 값을 저장합니다.
[그림 10]

IAT 복구까지 마친 파일을 PEiD를 이용하여 확인해 보면 [그림 11]과 같이 언팩된 것을 확인할 수 있습니다.
[그림 11]

Import funtions 확인시에도 [그림 12]와 같이 정상적으로 복구된 것을 확인할 수 있습니다.
[그림 12]

                                                                                                    +---------------------------------+
                                                                                                    | Infinite Flow..                              |
                                                                                                    | mail : geekspark@gmail.com         |
                                                                                                    | Blog : http://sinun.tistory.com       |
                                                                                                    | twitter : @unpacker                      |
                                                                                                    | CISSP                                        |
                                                                                                    +----------------------------------+
저작자 표시 비영리 변경 금지
신고
Posted by By. PHR34K

티스토리 툴바