UPack(Ultimate PE 패커)는 실행 압축기(PE Run-Time 패커)이다. UPack의 특징은 PE 헤더를 굉장히 독특한 방식으로 변형한다는 것이다. UPack 때문에 기존의 많은 PE분석 프로그램들이 오작동을 일으켜서 패치를 해야만 할정도로 획기적인 기법을 사용했다는 얘기다. UPack 상세분석을 통해 PE 헤더에 대한 지식을 완전히 엎어버리는 내용이며 리버싱에 대한 흥미와 열정을 더욱 끌어낼 수 있을 것이다.
1.UPack 설명
UPack은 중국의 dwing이라는 사람이 만든 PE패커이다.
http://www.geocities.jp/dwingj/mycomp.htm
UPack으로 실행 압축된 파일들의 PE 헤더를 보면 실행이 될 지 의문이 들 정도로 특이하게 변형되어 있다. 이러한 특이한 PE 헤더때문에 각종 PE유틸리티들이 정상적으로 동작하지 않았다. 이 특징 때문에 많은 삭성코드 제작자들이 자신들의 악성코드를 UPack으로 실행합축하여 배포하였다. 그런 악성코드가 너무 많아져서 Anti-Virus 제품들은 아예 Upack으로 실행 압축된 파일에 대해서는 그자체만으로도 악성파일로 진단/삭제 해버린다.(이렇게 악성코드에 자주 사용되는 패커들이 몇개 더 있다.)
아래 내용을 다 이해한 후 PE Viewer 또는 PE패커/Crypter를 직접 만들어보거나 향후 PE 헤더를 변형해도 어렵지 않게 분석할 수 있다.
2. Upack으로 notepad.exe를 실행압축하기.
Upack 0.39Final버전을 이용해서 notepad.exe를 실행압축해보자. Upack을 사용해서 notepad.exe를 실행압축을 하고 PEView로 살펴보자
PE View로 보았지만 PE헤더를 제대로 읽어들이지 못하고 있다.(IMAGE_OPTIONAL_HEADER,IMAGE_SECTION_HEADER 등 정보들이 없다). 참고로 예전 버전의 PE View에서는 프로그램이 비정상 종료가 되버렸다.
3. Sutd_PE 이용
PEView가 정상작동하지 않으니 다른 유틸리티인 Stud_PE를 사용하자.
http://www.cgsoftlabs.ro/studpe.html
.
실행하면 다음과 같은 화면이다.
PE View보다 좀 더 복잡한 화면 구성이지만 장점이 많은 유틸리티이다. Stud_PE에 대해서는 UPack 파일의 PE헤더를 분석할 때 자세히 설명하도록 하겠다
4.PE 헤더 비교
Hex Editor로 두 파일(notepad.exe, notepad_upack.exe)의 헤더부분을 비교해보자.
4-1 notepad.exe(원본)의 PE 헤더
평범한 PE 헤더의 모습이다. IMAGE_HEADER. DOS Stub, IMAGE_NT_HEADERS, IMAGE_SECTION_HEADER 순으로 전형적인 PE 헤더를 보여주고 있다.
4-2 notepad_upack.exe(실행압축)의 PE헤더
화면을 보면 MZ,PE시그니처가 매우 가깝게 붙어있고, DOS Stub은 아예 없어졌고, 여러 문자열이 보이고, 중간에 특수 코드가 존재하는것 처럼 보이기도 하다.
그러면 이제부터 UPack에서 사용되는 독특한 PE 헤더 구조에 대해 상세하게 살펴보자
5. UPack의 PE 헤더 분석
5-1 헤더 겹쳐쓰기
다른 패커에서도 많이 쓰이는 기법이다. MZ 헤더(IMAGE_DOS_HEADER)와 PE헤더(IMAGE_NT_HEADERS)를 교묘하게 겹쳐쓰는 것이다. 헤더를 겹쳐씀으로써 헤더 공간을 절약할 수 있다. 부가적으로 복잡성을 증가시켜 분석을 어렵게 만드는 효과가 있다.
StudPE를 이용해서 MZ헤더를 살펴보자. 'Headers' 탭의[Basic HEADERS tree view in hexditor] 버튼을 눌러보자
MZ 헤더(IMAGE_DOS_HEADER)에서 아래 2가지 맴버가 중요하다.
(offset 0) e_magic : Magic Number =4D5A('MZ')
(offset 3C) e_lfanew : File address of new exe header
그 외 나머지는 크게 중요하지 않다.(프로그램 실행에 아무 의미가 없다.) 문제는 PE File Format의 스펙에 따라서 IMAGE_NT_HEADERS의 시작 위치가 '가변적'이라는 것이다. 즉 e_lfanew의 값에 따라서 IMGAE_NT_HEADERS의 시작 위치가 결정된다. 보통 정상적인 프로그램에서는 e_lfnew 값은 아래와 같다
e_lfnew =MZ 헤더크기(40) + DOS Stub 크기(가변 : VC++의 경우 보통 A0) =E0 |
UPack에서는 e_lfanew 값이 10이다. PE 스펙에 어긋나진 않았다. 그냥 스펙자체의 허술함을 이용한것이다. 이런식으로 MZ 헤더와 PE 헤더의 겹쳐쓰기가 가능해진다.
5.2 IMAGE_FILE_HEADER.SizeOfOptionalHeader
IMAGE_FILE_HEADER.SizeOfOptionalHeader의 값을 변경한다. 이 값을 조작하여 해더 안에 디코딩 코드를 삽입하기 위한 목적이다.
값의 의미는 PE 헤더에서 바로 뒤따르는 IMAGE_OPTIONAL_HEADER 구조체의 크기(E0)이다. UPack은 이 값을 아래 그림과 같이 148로 변경한다.
여기서 한가지 의문이 생긴다. IMAGE_OPTIONAL_HEADER는 말그대로 '구조체'이기 때문에 PE32 파일 포멧에서는 이미 크기는 E0으로 결정되어 있다.
그런데 왜 PE File Fomat 설계자들은 IMAGE_OOPTIONAL_HEADER 구조체의 크기를 따로 입력했을까? 원래 의도는 PE 파일의 형태에 따라서 각각 다른 IMAGE_OPTIONAL_HEADER 형태의 구조체를 바꿔 낄 수 있도록 설계 한 것이다. 한마디로 IMAGE_OPTIONAL_HEADER의 종류가 여러개이므로 구조체의 크기를 따로 입력할 필요가 있는 것이다.
SizeOfOptionalHeader의 또 다른 의미는 섹션 헤더(IMAGE_SECTION_HEADER)의 시작 옵셋을 결정하는 것이다.
PE 헤더를 그냥 보면 IMAGE_OPTIONAL_HEADER에 이어서 IMAGE_SECTION_HEADER가 나타나는 듯이 보입니다. 하지만 실제로는 IMAGE_OPTIONAL_HEADER 시작 옵셋에 SizeOfOptionalHeader 값을 더한 위치(옵셋)부터 IMAGE_SECTION_HEADER가 나타난다.
UPack에서는 SizeOfOptionalHeader 값이 148로 정상적인 값(E0,F0)보다 더 크게 설정된다. 따라서 IMAGE_SECTION_HEADER는 옵셋 170부터 시작하게 된다.(IMAGE_OPTIONAL_HEADER 시작 옵셋(28) + SizeOfOptionalHeader(148)=170)
Upack의 의도는 무엇일까? 왜 이값(SizeOfOPtionalHeader)을 바꿨을까? UPack의 특징은 기본적으로 PE 헤더를 꽙배기처럼 꼬아놓고 헤더안에 디코딩에 필요한 코드를 적절히 끼워넣는 것이다. SizeOfOptionalHeader 값을 늘리면 IMAGE_OPTIONAL_HEADER와 IMAGE_SECTION_HEADER 사이에 추가적인 공간을 확보할 수 있다. UPack은 바로 이 영역에 디코딩 코드를 추가한다. 실제로 PE 헤더에 대한 일반 상식으 뛰어넘는 수법이다.
실제로 문제의 영역을 살펴보자. IMAGE_OPTIONAL_HEADER의 끝은 D7이고, IMAGE_SECTION_HEADER 시작은 170이다. 이 사이 영역을 Hex Editor로 보면 아래 그림과 같다.
디버거를 이용해서 디스어셈 코드를 보면 아래와 같다
위 그림은 PE헤더 정보가 아니라 UPack에서 사용하는 코드이다. 만약 PE 관련 유틸리티들이 여기를 PE 헤더 정보라고 판단하면 오작동을 하게 된다.
5-3 IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes
IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes 값을 변경한다. 이 역시 헤더에 자신의 코드를 삽입하기 위한 목적이다.
이 값의 의미는 바로 뒤에 이어지는 IMAGE_DATA_DIRECTORY 구조체 배열의 우너소 개수를 나타낸다. 정상적인 파일에서는 IMAGE_DATA_DIRECTORY 배열의 원소 개수는 10이지만, UPack에서는 A개로 변경된다.
IMAGE_DATA_DIRECTORY 구조체 배열의 원소 개수는 이미10으로 정해져있지만, PE스펙에 따르면 NumberOfRvaAndSizes 값을 배열의 우너소 개수로 인정하도록 되어있다(앞서 설명한 SizeOfOptionalHeader와 비슷한 개념이다.)따라서 UPack의 경우 IMAGE_DATA_DIRECTORY 구조체 배열의 뒤쪽 6개의 원소들은 무시하게 된다.
UPACK은 IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes 값을 Afh qusrudgkdu LOAD_CONFIG 항목(파일 옵셋 D8이후)부터는 사용하지 않는다. 그리고 바로 그 무시된 IMAGE_DATA_DIRECTORY 영역에 자신의 코드를 덮어써버렸다.
Hex Editor로 IMAGE_DATA_DIRECTORY 구조체 배열 영역을 보도록 하자
.
위의 그림에서 파란색 영역은 정상 파일의 IMAGE_DATA_DIRECTORY 구조체 배열이고, 빨간 부분은 UPack에서 무시되는 부분이다.(D8~107영역 =LOAD_CONFIG Directory 이후). 무시되는 영역을 디버거로 확인하면 위의 디버거로 확인한 그림과 같다. UPack 자체의 디코딩 코드이다.
5-4 IMAGE_SECTION_HEADER
IMAGE_SECTION_HEADER 구조체에서 프로그램 실행에 사용되지 않는 항목들에게 UPack 자신의 데이터를 기록한다. 이 역시 PE 헤더에서 쓰이지 않는 영역에 자신의 코드와 데이터로 덮어쓰는 기법이다.
이미 앞에서 섹션의 개수는 3이고 IMAGE_SECTION_HEADER 구조체 배열의 시작 위치는 170이라는 것을 알았다. Hex Editor로 IMAGE_SECTION_HEADER 구조체를 보자.(옵셋 170~1E7 영역)
그림 12
위의 영역의 IMAGE_SECTION_HEADER 구조체에 맞게 보기 좋게 정리하면 다음과 같다
위의 박스로 표시된 구고체 맴버들은 프로그램 실행에 아무런 의미없는 맴버들이다. 일례로 파일 옵셋 1B0 위치에 있는 offset to relocation의 값 0100739D는 원본 notepad.exe의 EP(Entry Point)값이다. 이 외에도 섹션 헤더에는 몇가지 비밀이 더 있다.
5-5 섹션 겹쳐쓰기
UPack의 주요 특징 중 하나가 바로 섹션과 헤더를 마구 겹쳐쓰는 것이다.
간략한 보기를 제공하는 Stud_PE를 이용해서 Upack의 IMAGE_SECTION_HEADER를 살펴보자. Stud_PE의 'Sections'탭을 보자
위를 보면 이상한 부분이 있다. 먼저 눈에 띄는 것은 첫번째 섹션과 세번째 섹션의 파일 시작 옵셋(RawOffset) 값이 10으로 되어있다. 옵셋 10은 헤더 영역인데 UPack에서 이곳에서부터 섹션이 시작된다.
그 다음에 눈에 띄는 내용은 첫 번째 섹션과 세 번째 섹셔의 파일 시작 옵셋(Raw_Offset)과 파일에서의 크기(RawSize)가 완전히 동일하다는 것이다. 단, 섹션의 메모리 시작 RVA(VirtualOffset) 항목과 메모리 크기(Virtual Size) 값이 서로 다르다. PE 스펙에 따르면 이렇게 해도 문제가 없다.
위 두가지 사실을 종합해보면 UPack은 PE 헤더, 첫번째 섹션, 세번째 섹션이 겹쳐있다. 숫자만 봐서는 의미가 잘 안와닿기에 밑에 그림을 참고하자.
위 그림은 왼쪽은 파일에서의 섹션 정보를, 오른쪽은 메모리에서의 섹션 정보를 보여주고 있다.
섹션 헤더(IMAGE_SECTION_HEADER)에 정의된 값에 의해서 PE 로더는 파일 옵셋 0~1FF 영역을 3군데 다른 메모리 위치(헤더, 첫 번째 섹션, 세 번째 섹션)에 각각 매핑한다. 같은 파일 이미지를 가지고 각각 다른 위치와 다른 키기의 메모리 이미지를 만들 수 있다는 사실에 주목하다.
파일 헤더(첫째/셋째 섹션) 영역의 크기는 200이다. 사실 매우 작은 크기이다. 반면 두번째 섹션영역의 크기는(AE28) 파일의 대부분을 차지할 정도로 크다. 바로 이곳에 원본 파일(notepad.exe)가 압축되어 있다.
또 하나 주목해야 하는 부분은 메모리에서 첫 번째 섹션 영역이다. 섹션의 메모리 크기는 14000이다. 이는 원본 파일(notepad.exe)의 Size of Image와 같은 값이다. 즉 두 번째 섹션에서 압축된 파일 이미지를 첫 번째 섹션에(notepad의 메모리 이미지) 그대로 압축헤제하는 것이다. 참고로 notepad.exe 원본은 3개의 섹션이 있다. 이를 하나의 섹션에 풀어낸것이다.
압축이 해제된 첫번째 섹션은 다음과 같다.
다시 한 번 정리하면 메모리 두 번째 섹션 영역에 압축된 notepad가 들어있고 압축이 풀리면서 첫 번째 섹션 영역에 기록된다. 중요한건 notepad.exe(원본파일)의 메모리 이미지가 통째로 풀리기 때문에 프로그램이 정상적으로 실행될 수 있다.
'리버스 엔지니어링' 카테고리의 다른 글
DLL 인젝션- Window 메시지 후킹 (0) | 2018.05.26 |
---|---|
UPack PE헤더 상세 분석 -2 (0) | 2018.05.15 |
실행파일에서 .reloc 섹션 제거하기 (0) | 2018.05.15 |
PE재배치 동작 원리 (0) | 2018.05.14 |
PE 재배치 -1 (0) | 2018.05.14 |