리버싱 핵심원리 15장
15장 UPX 실행 압축된 notepad 디버깅
실행 압축 파일들의 디버깅은 많은 루프의 연속이며 어떠한 루프를 하는지 UPX로 패킹된 notepad로 알아볼 예정
(*ESI와 EDI가 동시에 세팅되면 ESI가 가르키는 버퍼에서 EDI가 가르키는 버퍼로 메모리 복사가 일어날 것이라고 예측할 수 있다. 압축 해제의 경우에는 ESI로부터 데이터를 읽어서 압축을 해제한 후 EDI에 저장하는 것.)
루프1
EDX에서 한 바이트를 읽어 EDI에 쓰는 것. EDX 레지스터가 가리키는 01001000 주소는 첫 번째 섹션(UPX0)의 시작 주소이며, 메모리에서만 존재하는 섹션이다.
루프2
본격적인 디코딩 루프(압축해제 루프)이다. ESI가 가리키는 두 번째 섹션(UPX1)의 주소에서 차례대로 값을 읽어서 적절한 연산을 거쳐 압축을 해제하여 EDI가 가리키는 첫 번째 섹션(UPX0)의 주소에 값을 써준다.
이 루프가 끝나면 UPX0 영역(01007000)에 압축 해제된 코드가 쓰여져있는 것을 확인할 수 있다.(dump창)
루프3
이 루프는 원본 코드의 CALL/JMP 명령어(op code : E8/E9)의 목적지 주소를 복원시켜주는 코드이다. 이후 IAT세팅만 하면 UPX압축 해제 코드는 끝*일반적인 실행 압축 파일은 원본 파일의 코드, 데이터, 리소스의 압축 해제 과정이 끝나면 IAT를 세팅하고 OEP로 감
루프4
리버싱을 진행하다보면 EDI가 UPX1영역에 세팅된다. 이곳에는 원본 notepad에서 사용되는 API 이름 문자열이 저장되어 있다. 이 문자열들은 UPX가 원본 notepad를 실행 압축시킬 때 원본 파일의 IAT를 분석하여 프로그램에 사용되는 API 이름 목록을 뽑아 놓은 것이다. 이 API 이름 문자열들을 가지고 GetProcAddress()를 호출하여 API 시작 주소를 얻은 후 EBX 레지스터가 가리키는 원본 notepad의 IAT 영역에 API주소를 입력한다. 이 과정을 API이름 문자열이 끝날 때까지 반복하면 원본 notepad의 IAT복원 과정이 끝나고 OEP로 제어를 돌려준다.*POPAD 명령은 PUSHAD에 대응되는 명령으로 레지스터를 원래대로 복원시키는 명령이다.
UPX의 OEP를 빨리 찾는 방법 (UPX로 실행 압축된 파일 기준)
1. POPAD명령어 이후의 JMP 명령어에 BP설치 UPX 패커의 특징 중 하나는 EP코드가 PUSHAD/POPAD 명령어로 둘러싸여 있다는 것이다. 그리고 OEP로 가는 JMP명령어가 POPAD 명령어 바로 이후에 나타남. (PUSHAD는 EAX~EDI까지 8개의 범용 레지스터의 값을 스택에 저장하는 명령이고 POPAD는 PUSHAD 명령에 의해 스택에 저장된 값을 다시 레지스터들에게 입력하는 명령이다.)2. 스택에 하드웨어 브레이크 포인트 설치 이 방법도 UPX의 특징인 PUSHAD/POPAD 명령어의 특징을 이용하는 것이다. PUSHAD 명령이 실행된 후 스택창에서 주소를 우클릭한 후 hardware on access - byte를 누르면 된다. 하드웨어 BP란 CPU에서 지원하는 브레이크 포인트이며 4개까지 설치가 가능하다. 일반적인 BP와 다른점은 하드웨어 BP가 설치된 명령어가 실행된 이후에 제어가 멈추게 된다는 점이다. 이 상태에서 실행하면 압축이 해제되면서 코드가 실행되고 POPAD가 호출되는 순간에 하드웨어 BP가 설치된 주소를 엑세스하고 그때 제어가 멈춘다.