[조립하면서 배우는 PE] 다섯번째 이야기 : PE Header(3) - Data Directory Reverse Engineering

리버싱 2017. 1. 10. 16:33

다섯번째 이야기입니다. 이번 이야기는 좀 짧을 것 같네요. ^^; Data Directory 자체보다는 Data Directory가 가르키는 자료 구조들이 중요하죠. 어쨌든, 자~ 빠.아져 볼.까요?  

Data Directory 
데이터 디렉토리는 PE 헤더의 마지막에 위치한 128bytes 사이즈의 배열입니다.(여기에 대해서는 사실 확인 작업이 좀 필요할 것 같습니다. 누차 밝혀온 것 처럼 데이터 디렉토리는 옵션이어서 존재하지 않을 수도 있고 존재하는 경우 16개의 엔트리를 가져야 한다고 했습니다. 이호동님께서 저술하신 "Windows 시스템 실행 파일의 구조와 원리"의 76page 표2-4와 80page의 설명을보면 데이터 디렉토리의 엘리먼트 개수는 무조건 16이라고 못박아 놨더군요. 하지만 최근의 인터넷 상의 논의들을 살펴보면 반드시 16개일 필요는 없는 것 같습니다. 제가 직접 확인해보지 못한 관계로 사실로 규정하기는 어렵지만, 사실 실험 자체가 어려운 것은 아니라 곧 확인하고 연재 마치기 전에 결과를 말씀드리도록 하겠습니다. ) 각 배열 구성 요소(이하 엘리먼트)들은 IMAGE_DATA_DIRECTORY 타입을 가지는데 아래와 같이 정의 되어 있습니다. 

  typedef struct _IMAGE_DATA_DIRECTORY {
      DWORD   VirtualAddress;
      DWORD   Size;
  } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 

Optional Header의 뒷부분에 있던 NumberOfRvaAndSize 라는 이름의 필드가 데이터 디렉토리의 엘리먼트 수를 저장하고 있다고 했던 것 기억나시죠? 위 구조체를 보면 필드의 이름에 이유가 있음을 알 수 있을 것입니다. 
 데이터 디렉토리의 각 엘리먼트는 익스포트 테이블, 임포트 테이블 등 PE 파일에서 중요한 역할을 담당하는 개체들의 위치(VirtualAddress)와 크기(Size)에 대한 정보를 가지고 있습니다. 아래 데이터 디렉토리의 전체적인 모양을 그려두었습니다.
 

사용자 삽입 이미지



위 그림에 나타나있는 데이터 디렉토리내의 엘리먼트의 데이터 타입은 이름만 다르고 실제 모양은 모두 같습니다. 예를 들어 IMAGE_DIRECTORY_ENTRY_EXPORT도 IMAGE_DATA_DIRECTORY  로 정의되어 있으며 IMAGE_DIRETORY_ENTRY_IMPORT도 IMAGE_DATA_DIRECTORY로 정의되어 있습니다.  또한 0-15번까지의 엔트리만 유효한 값을 가지고 있으며 맨 마지막 엘리먼트는 데이터 디렉토리의 끝을 나타내기 위해 8byte 전체가 0x00으로 채워져 있습니다. (이것만 봐도 데이터 디렉토리의 엘리먼트가 꼭 16개가 아니라도 될 것 같다는 생각이 듭니다. 16개로 고정되어 있는 것이라면 끝을 나타내는 엘리먼트가 필요없겠죠) 

15개의 엘리먼트 모두를 알아두어야 하는 것은 아닙니다. 일단 색칠되어 있는 부분들은 알아야 하는데 처음 공부하는 분들은 첫번째 엘리먼트(EXPORT), 두번째 엘리먼트(IMPORT), 열번째 엘리먼트(TLS) 정도만 공부하면 되겠습니다. 좀 더 익숙해지면 지연로딩에 관련된 항목들도 공부해야 하는데 처음부터 완벽할 필요는 없죠. ^^;  

IMAGE_DIRECTORY_ENTRY_EXPORT : 익스포트 테이블의 메모리 상에서의 시작점과 크기에 대한 정보를 가지고 있습니다. 익스포트 테이블은 대부분 DLL에 존재합니다. 익스포트 테이블에 대한 자세한 이야기는 뒤에서 다루도록 하겠습니다. 

IMAGE_DIRECTORY_ENTRY_IMPORT : 임포트 테이블의 메모리 상에서의 시작점과 크기에 대한 정보를 가지고 있습니다. 아마 가장 먼저 공부해야 하고 가장 잘 알아야 하는 부분일 것 같습니다. 리버싱을 하다보면 메뉴얼 언패킹을 하는 경우가 있는데, 이 때 이 엘리먼트가 가르키는 임포트 테이블에 대한 지식이 매우 유용하게 사용되기 때문이죠. 여섯번째 이야기가 바로 임포트 테이블에 관한 것입니다. ^^;

IMAGE_DIRECTORY_ENTRY_BASERELOC : 재배치와 관련된 데이터 구조에 대한 시작점과 크기 정보를 가지고 있습니다. 재배치는 일반 EXE 파일과는 무관하며 DLL과 연관되어 있습니다. 역시 자세한 이야기는 뒤에서 살펴보도록 하죠 ^^;

IMAGE_DIRECTORY_ENTRY_TLS : 리버서의 입장에서 TLS는 TLS callback 함수를 이용한  안티 리버싱 테크닉 때문에 알아두어야 합니다. 자세한 이야기는 여기를 참고하세요. 


PE 제작하기  4 : 데이터 디렉토리 채우기 

Step 1: 데이터 디렉토리를 위한 공간 128bytes를 추가합니다. MyFirstPE를 열어 Ctrl+0(숫자)을 누른후 128bytes를 추가하면 되겠습니다. 완성된 모습은 아래와 같습니다. 

사용자 삽입 이미지



끝났습니다. ㅠ.ㅠ; 어이없죠?  사실 우리는 MessageBox를 임포트해서 사용할 것이기 때문에 두번째 데이터 디렉토리와 열세번째 데이터 디렉토리를 채워줘야 하는데요... 이 작업은 여섯번째 이야기에서 하려고 합니다. 아무래도 임포트를 이해해야 하기 때문에... 

맺음말 
^^; 지금은 오후 9시입니다. 허무해 하신 분들을 위해 빨리 작업해서 이 밤이 다가기 전에 여섯번째 글을 올리도록 하겠습니다. 즐핵하세요~


출처 - http://zesrever.tistory.com/59

: