본문 바로가기

CAT-Security/미분류

[안티디버깅] UPX packer 이해

실행압축

실행압축이란 실행가능 한 파일(PE파일)을 대상으로 파일 압축을 하지만, 파일 내에 압축해제 코드를 포함 하고 있어서 

실행되는 순간 메모리에서 압축을 해제시킨 후 실행을 시키는 기술

 

압축해제 루틴이 존재 하기 때문에, 메모리에서 압축을 해제 시킨 후 실행되는 것이 특징

 

사용목적으로는, 압축이기에 파일 자체의 크기를 줄이는 효과로 전송 및 보관에 용의 함을 얻기 위함이고 가장 큰 목적으로는 내부 코드와 리소스를 임의의 사용자가 보지 못하게 방해 하는 것 입니다.

즉 압축이 되어있기에 임의의 사용자가 보기에는 압축된 데이터는 알아보기 힘든 형태의 바이너리로 저장이 되어 있습니다.

 

이중 UPX 실행압축에 대해 알아 보도록 하겠습니다.


.

첫째 섹션인 UPX0 RawDataSize 0이기에 파일 내에 존재 하지 않습니다.

(RawDataSize는 파일에서 섹션이 차지 하는 크기 이다.)

이것에 대한 실마리로는 Virtual Size에서 찾을 수 있습니다. 실제 파일에서의 사이즈는 0인데 왜 저렇게 메모리에서의 사이즈는 큰 것일까?

이유는 압축해제 코드와 압축된 원본 코드는 두째 섹션에 존재 합니다.

파일이 실행되면서 먼저 압축해제 코드가 실행되고, 원본코드를 첫째 섹션에 해제 시키는 것 입니다.

그렇기에 실제 파일의 크기는 0인것이고, 메모리에서의 크기가 저런 것 입니다.



두째 섹션의 실제 크기와, 메모리 크기를 보면 알 수 있습니다.

 

 

프로그램은 http://bbolmin.tistory.com/47 에서 가져 왔으며 CodeEngn Basic 6번 문제 입니다.

 

PUSHAD 의미 - CPU 레지스터값들을 모두 스택에 넣는 명령어

POPAD 의미 - 반대로 스택에 넣은 값들을 CPU 레지스터로 복귀시키는 명령어

의문점 왜 PUSHAD POPAD를 하는것일까?


 

PUSHAD가 일어나기 전



PUSHAD가 일어난 이후 스택의 상황



EAX~EDI의 값까지가 순서대로 들어가 있음을 확인 할 수 있습니다 둘째 섹션의 주소 ESI(00424000)와 첫째 섹션의 주소 EDI(00401000)을 셋팅 합니다.

ESI가 가르키는 버퍼에서 EDI가 가르키는 버퍼로 메모리 복사가 일어남을 예상 할 수 있습니다.EDX가 가르키는 곳은 NULL으로 초기화가 되어 있습니다.EDX로부터 데이터를 읽어서 압축을 해제한 후 EDI에 저장을 시킬 것 입니다.

또한 ESI+FFFDD000의 값은 23000으로 VA와 사이즈가 같음을 확인 할 수 있습니다.



값들이 복사 됨을 확인 할 수 있습니다.

 



전체적으로 큰 루프 안에서 ESI가 가르키는 곳에 있는 값을 가져와서  EDI가 가르키는 값들을 복사함을 알 수 있습니다.



이렇게 여러 곳에서 EDX의값을 가져와서 EDI의 값으로 넣음을 확인 할 수 있습니다.

이것이 압축 해제 루프 입니다.



 



JMP 0042990E로 계속 가게 되며, 0값으로 세팅 되어있는 첫째 섹션에 값을 계속 복사 함을 알 수 있습니다. 004299C2 POP ESI에 브레이크 포인터를 걸고 F9실행을 시키면은 첫째 섹션에 모두 압축 해제된 코드가 쓰여지었던 것을 확인 할 수 있습니다.


 

IAT 셋팅 부분 입니다.



 



프로그램에서 사용 하는 API의 이름 문자열들이 저장 되어 있습니다.

004299F4 명령어의 GetProcAddress를 이용해서 API 시작 주소를 얻은 후에 EBX 레지스터가 가르키는 원본 프로그램 IAT 영역에 API 주소를 입력 합니다. 이 과정은 API 이름 문자열이 끝날 때 까지 반복 됩니다.



EBX에 저장되는 스크린샷 입니다.

 



그 뒤 스택에 EAX~ EBP까지 넣은 후 POPAD를 하는 모습입니다.

POPAD를 한 이후 CPU는 이렇게 변경이 됩니다.



 

모든 압축해제 과정이 끝나면은 OEP로 점프를 하게 됩니다.



이 부분이 OEP로 점프 하는 부분입니다.

 

 

 

 

이렇게 실습을 하면서 몇 가지 의문점을 가지게 되었습니다.

첫째. PUSHAD POPAD를 하는 이유

패킹된 파일은 루프를 돌면서 연산을 하게 됩니다. (두째 섹션의 압축해제 루틴 때문에) 이러면서 레지스터가 수정이 되는데 기존 레지스터가 수정 될 수 있기 때문에 PUSHAD로 레지스터를 밀어 넣어서 저장해두고, 루틴이 모두 끝나고 정상 코드를 실행시킬 때 이 레지스터들을 돌려 받기 위함 입니다.

 

둘째. 왜 섹션이 두 개 인가

이것은 개인적으로 생각한 것은, 어차피 PE View에 보인 PE구조들은 패킹된 프로그램의 구조 이기 때문에 정상 PE섹션이 아니고, 단순 만들어진 섹션으로 두째 섹션에서 첫째 섹션으로 원래 코드를 풀어놓는 작업은 다시 말해 처음서부터 다시 섹션을 만들어내는 과정이라고 생각 했습니다.

 

셋째. 스택에 하드웨어 브레이크 포인트를 걸어 바로 OEP를 가는 방법은 어떻게 가능한가?

이것은 첫째 의문점을 쓰다 보니까 알게 되었습니다.

저장된 레지스터로 바로 이동하기 때문에, 저장한 레지스터는 건드려지지 않은 원래 파일의 레지스터이고 이것이 브레이크포인트가 걸려있다가 돌려받은 시점에서 실행 되기 때문에 그 부분은 POPAD 부분이기 때문에 바로 OEP를찾을 수 있는 것 이었습니다.

 

요약.

1. UPX는 실행압축이다. 그래서 메모리 용량 절약과 코드들을 감춘다.

2. 맨 처음 ESI+FFFDD000의 값은 둘째 섹션 VA와 같다.

3. PUSHAD POPAD를 하는 이유는 레지스터 백업에 있다.

4. UPX는 둘째 섹션부터 시작하며, 둘째 섹션에는 해제루틴과 원래의 코드를 가지고 있다. 그리고 순서대로 실행되면서 해제루틴으로 ESI가 가르키는 버퍼에서 EDI가 가르키는 버퍼로 메모리 복사가 일어 난다. 그리고 나서 OEP로 점프 한다.

5. 루프마다 복사되는 영역과 값들이 모두 다르다.

6. 바로 POPAD BP를 걸거나 PUSHAD를 한 이후 그 레지스터에 BP를 걸은 뒤에 실행 시키면은 바로 OEP를 찾을 수 있다.

'CAT-Security > 미분류' 카테고리의 다른 글

gdb 잘나와있음  (2) 2012.11.09
[시스템 기초] 스터디(1주차)  (0) 2012.11.08
[안티디버깅] Anti-Debuging(안티디버깅) 기초  (2) 2012.11.08
리버싱 워게임 사이트  (0) 2012.10.27
system 링크  (0) 2012.07.21