본문 바로가기
리버싱(Reversing)/리버싱 개념

리버싱 핵심원리 18장(UPack PE 헤더 상세 분석)

by LIZ0904 2020. 11. 14.
반응형

1. UPack 이란?

UPack(Ultimate PE 패커)은 실행 압축기(PE Run-Time 패커)이다. UPack의 특징은 PE 헤더를 독특한 방식으로 변형 하는 것으로, 중국의 dwing이라는 사람이 만든 PE 패커이다. 

 

 

 

 

2 UPack으로 notepad.exe 실행 압축하기

우선 첫번째로 UPack.exe를 이용해 notepad.exe를 실행압축 해줄 것이다. 

upack notepad.exe 명령

upack.exe와 notepad.exe를 복사한 뒤, cmd 창에서 'upack notepad.exe' 명령을 내린다. 참고로 UPack은 원본 파일 자체를 실행 압축하기 때문에 따로 백업해놓지 않으니, 중요 파일을 실행 압축할 때는 꼭 미리 백업을 해둬야 한다!

 

 

 

 

 

헤더 겹쳐쓰기

IMAGE_DOS_HEADER와 IMAGE_NT_HEADERS를 겹쳐쓰는 기법이다. 헤더를 겹처씀으로서 헤더 공간을 절약할 수 있으며 복잡성을 증가시켜 분석을 어렵게 만든다. Stub_PE로 IMAGE_DOS_HEADER(MZ 헤더)를 살펴본다.

 

MZ 헤더에서 중요한 멤버는 e_magic과 e_Ifanew이다. 그 외 나머지는 프로그램 실행에 영향이 없는 멤버들이다. e_Ifanew의 값에 따라서 IMAGE_NT_HEADERS의 시작 위치가 결정된다.

정상적인 notepad에서는 000000F8이었던 e_Ifanew 값이 00000010이 되었다. 이를 통해 IMAGE_DOS_HEADER와 IMAGE_NT_HEADERS가 겹쳐있다는 것을 알 수 있다. PE 스펙 자체는 갖추고 있다.

 

 

 

 

IMAGE_FILE_HEADER.SizeOfOptionalHeader

IMAGE_FILE_HEADER.SizeOfOptionalHeader의 값을 변경하면서 헤더 안에 디코딩 코드를 삽입한다. 값의 의미는 PE 헤더에서 바로 뒤따르는 IMAGE_OPTIONAL_HEADER 구조체의 크기(E0)이다. UPack은 이 값을 148로 변경했다.

 

 

IMAGE_OPTIONAL_HEADER는 구조체이기 때문에 이미 PE File format에서 그 크기가 E0로 정해져 있다. 원래 의도는 PE 파일의 형태에 따라서 각각 IMAGE_OPTIONAL_HEADER 형태의 구조체를 바꿔 끼울 수 있도록 설계했다.

또한, SizeOfOptionalHeader의 또 다른 존재의의는 IMAGE_SECTION_HEADER의 시작 offset을 결정하는 역할이다. PE 헤더를 보면 IMAGE_OPTIONAL_HEADER에 이어서 IMAGE_SECTION_HEADER가 나타나는 것처럼 보인다. 하지만 실제로는 IMAGE_OPTIONAL_HEADER의 시작 offset에 SizeOfOptionalHeader 값을 더한 위치에서부터 IMAGE_SECTION_HEADER가 시작되는 방식이다.

UPack에서는 IMAGE_OPTIONAL_HEADER 시작 offset 28 + SizeOfOptionalHeader(148)=170에서IMAGE_SECTION_HEADER가 시작한다.

UPack이 이렇게 값을 변경하는 이유가 무엇일까? UPack의 특징은 Pㄸ 헤더를 뒤섞어놓고 헤더 안에 디코딩에 필요한 코드를 적절히 끼워 넣는 것이다. SizeOfOptionalHeader 값을 늘리면 IMAGE_OPTIONAL_HEADER와 IMAGE_SECTION_HEADER 사이에 공간을 확보할 수 있고, 이 영역에 디코딩 코드를 충가한다.

 

이 영역은 PE헤더 정보가 아니라 UPack에서 사용하는 디코딩 코드이다. 만약 PE 관련 유틸리티가 이 부분을 PE헤더 정보라고 판단하면 오동작을 일으킨다.

 

 

 

 

IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes

이 값의 변경 역시 Upack이 자신의 코드를 사용하기 위한 이유이다. NumberOfRvaAndSizes는 바로 뒤에 이어지는 IMAGE_DATA_DIRECTORY 구조체 배열의 원소 개수를 나타낸다. 정상적인 파일에서 IMAGE_DATA_DIRECTORY 배열의 원소 개수는 10(16개)이지만, UPack에서는 A(10개)로 변경된다.

IMAGE_DATA_DIRECTORY 구조체 배열의 원소 개수는 이미 10으로 정해져 있지만, PE 스펙에 따르면 NumberOfRvaAndSizes 값을 배열의 원소 개수로 이정하도록 되어 있다. 앞선 SizeOfOptionalHeader와 같은 개념이다. 따라서 UPack의 경우 IMAGE_DATA_DIRECTORY 구조체 배열의 마지막 6개 원소는 무시한다.

그리고 그 무시된 영역에 자신의 코드를 덮어씌운다. 여기서 마지막 6개 배열 중 가장 앞의 주소가 바로 D8이다.

 

 

 

 

 

 

IMAGE_SECTION_HEADER

 

IMAGE_SECTION_HEADER 내에서 프로그램 실행에 사용되지 않는 멤버들에 UPack의 데이터를 기록한다. 이 기법 역시 앞선 방법과 같은 맥락이다.

위에서 확인한 바로 NumberOfSections의 값은 3이었고, IMAGE_SECTION_HEADER는 170에서 시작한다.

PE File format에서 IMAGE_SECTION_HEADER 구조체의 크기는 28hex 였으므로, 이 구조체 3개는 78hex.

170(hex)+78(hex)=1E8. 즉, 170~1E7 범위가 IMAGE_SECTION_HEADER의 영역이다.

 

 

 

 

 

섹션 겹쳐쓰기

 

 

첫 번째 섹션과 세 번째 섹션의 파일 시작 offset(RawOffset) 값이 10으로 같다. offset 10은 헤더 영역인데 Upack에서는 이곳에서 섹션이 시작된다.

첫 번째 섹션과 세 번째 섹션의 크기도 같다. 단, 섹션의 메모리 시작 offset(RVA)와 메모리 크기(VirtualSize)값은 다르다.

결론. UPack은 PE헤더, 첫번째 섹션, 세번째 섹션이 겹쳐 있는 상태이다. PE로더는 파일 offset 0~1FF 영역을 3곳의 서로 다른 메모리 위치에 매핑한다. 같은 파일 이미지를 가지고 각기 다른 위치와 다른 크기의 메모리 이미지를 만들 수 있다.

'파일'의 첫 번째 섹션의 크기는 200으로 다소 작은 편이지만 두 번째 섹션의 크기는 파일의 대부분을 차지할 정도로 크다.

'메모리'의 첫 번째 섹션 크기는 14000이다. 이 값은 원본 파일의 SizeOfImage 값과 같다. UPack의 두 번째 섹션 안에, 원본 파일의 압축된 이미지를 저장해두었다가, UPack의 첫 번째 섹션에 풀어주는 것이다.

 

 

 

반응형

댓글