PE둥PE둥 놀면서 훑어보는 PE(2)

By conchi | December 7, 2016

PE둥PE둥 놀면서 훑어보는 PE(2)


쓰면서 노잼바이러스에 감염된 콘치와 PE 포맷에 대해 야매로(?) 알아보자.




들어가며


안녕하세여 지난시간 충격적인 예고로 여러분의 곁을 떠났던 콘치가 돌아왔습니다.

이번편은 지난번에 말씀 드린대로 딱히 재미가 없을거 같아여.

사실 이번 편을 쓰려고 예전에 정리해뒀던 자료들을 보려는데 콘치 마저도 흥미를 잃어버렸어요.


와.. 이럴수가있나..


나는 무슨정신으로 이를 기념하기 위해 이런걸 준비했단 말인가…


여러분들에게 재밌게 야매로 알려줄랬는데 제가 흥미를 잃어버리는 초유의 사태가 발생했어요.

아 게임에 대해서 흥미를 잃었다면 내가  짱해커가 될 수 있었을지도 모르겠는데..

별로 좋지 못한곳에서 흥미를 잃을 위기인 처한 콘치입니다.


ㅠㅠ.. 아 진짜 미치겠다

아 진짜 재미없다

극혐… ㅠㅠ… 넘나 우울한것..

모두들 나에게 용기를!!!!!!!!!! 람쥐썬더!!!





준비물 : HxD

작업환경 : windows7 32bit


들어가기전에 ‘ㅅ’! 알아야 할 개념!!


  • 메모리 읽기

    • 우리가 지금부터 보게될 그림에 나오는 메모리 주소값은 모두 `리틀엔디언(Little-endian`으로 적혀있습니다.

    • 01 23 45 67 이라고 적혀있지만 실제로는 0x67452301이 되는셈이지요.

    • 끵? 무슨말인지 잘 모르겠다구여? 요 링크를 참고해주세요 :)




노잼끝판왕 PE, 야매로 알아보자


없는 내용을 말하자는건 아니에요.

단지… PE공부를 시작할 때, 저처럼 빨리 포기하지 않기 위해 일종의 상술(?)을 사용해보자는 거져.

자주 보게되는 부분들만 딱딱 찝어서 보고 슉 넘어가자구요.

어차피 지금 이렇게 슉슉 넘어간다고 해서 PE공부가 끝난건 아니니께…!!!!(음흉)



이번 편에서 물어뜯기게 될 실행파일(.exe)입니다.

예전에 어디에선가 본적이 있는거 같기도 하고 아닌거 같기도 합니다.

낯이 익은 느낌적인 느낌이 드는 파일이네요. 실행하면 역시나 낯이익습니다.


이 실행파일을 예로들어가며 PE를 한번 설명해볼게요. 잘 따라오세여!!

저도 지금 넘나 노잼상태라 정신 못차리면 우리 같이 망하는거에여ㅜㅜ…

지금부터는 정신적 편의를 위해 실행파일을 PE라고부르겠습니당 참고해주세여




우선 이 PE의 속내는 어떻게 생겼는지부터 봅시다.



음…

음……….

녜..ㅋ

(동공이 심하게 흔들림)

네 여러분 이렇게 생겼다고 합니다!


지난번 리버싱 튜토리얼에서 봤을땐 그래도 육안으로 식별이 가능한 정도였는데

이젠 숫자…ㅋ… 모다.. ㅋㅋ.. 한번 차근차근 알아봐여.




여러분들에게 머리가 있듯이 PE에도 머리가 있슴당. 우리는 얘들을 PE헤더라고 불러여.

요 PE헤더에는 해당 PE에서 사용하는 정보들이 모두 정의(?)되어 있어요.

이 PE는 크기가얼마나 되고, 헤더의 크기는 얼마나 되고 이 프로그램은 어디서부터 시작되고,

어떤 함수들을 쓸꺼고 등등 PE에 대한 수상한 정보들이 모두 담겨있는 부분입니다.


끵? 우리눈엔 저 숫자들밖에 없는데 그럼 저 숫자들이 정보인가여??


네 ‘ㅅ’.. ㅋㅋ..


…라고하면 멘탈에 파삭파삭 금이 가기 시작한 여러분들 자신을 만나게 될 거에여.

근데 참트루에여.


뭔가 대충 아무 숫자나 갈겨놓은 것 같이 생겼지만, 쟤들은 멋대로 적혀있는게 아닙니다.

그렇기 때문에 ‘에라이 이건 뭐냐’ 싶어서 마음대로 이것저것 수정하다가는

자칫 프로그램이 돌아가지 않는(!) 끔찍한 상황을 만나게 될 수도 있답니다.


그럼 지금부터 이 정신없는 숫자들을 한번 분해해봅시다.

누워서 자기전에 볼 수 있을정도로 야매로 적어볼게여(히죽).




Dos Header


헤더는 크게 Dos Header와 NT Header, Section Header로 나눌 수 있어요.


Dos Header는 말그대로 Dos환경을 위해 존재하는 부분입니다.


우린 windows쓰는데 왠 Dos??

그림과 함께 보도록 합시당.



어디보자.. 우리가 알아먹을 수 있는 글자라곤 MZ와 This program cannot be run in DOS mode 가 전부네요.

This program cannot be run in DOS mode라는 문자열로 보아 DOS mode와 상관이 있나보군여.


그럼 MZ?? 얜모징???


얘는 모든 PE파일의 앞부분에 고정적으로 박혀있는 놈이에요. 걍 알아두시면 됩니다.

(MZ의 정확한 의미가 궁금하신분들은 요기 링크를 참고하세여. )


그럼 Dos랑 관련있는거니까 이부분은 안보고 그냥 넘겨도 되는부분!!! 이라고 생각하겠지만

그렇게 생각없이 이런 부분을 만들어 둔게 아니에여. 필요한 부분은 챙기고 넘어갑시다.


우선 챙기기 전에 Dos Header는 다음과 같은 구조체로 이루어져 있어여.


typedef struct _IMAGE_DOS_HEADER {
     WORD  e_magic;      /* 00: MZ Header signature */
     WORD  e_cblp;       /* 02: Bytes on last page of file */
     WORD  e_cp;         /* 04: Pages in file */
     WORD  e_crlc;       /* 06: Relocations */
     WORD  e_cparhdr;    /* 08: Size of header in paragraphs */
     WORD  e_minalloc;   /* 0a: Minimum extra paragraphs needed */
     WORD  e_maxalloc;   /* 0c: Maximum extra paragraphs needed */
     WORD  e_ss;         /* 0e: Initial (relative) SS value */
     WORD  e_sp;         /* 10: Initial SP value */
     WORD  e_csum;       /* 12: Checksum */
     WORD  e_ip;         /* 14: Initial IP value */
     WORD  e_cs;         /* 16: Initial (relative) CS value */
     WORD  e_lfarlc;     /* 18: File address of relocation table */
     WORD  e_ovno;       /* 1a: Overlay number */
     WORD  e_res[4];     /* 1c: Reserved words */
     WORD  e_oemid;      /* 24: OEM identifier (for e_oeminfo) */
     WORD  e_oeminfo;    /* 26: OEM information; e_oemid specific */
     WORD  e_res2[10];   /* 28: Reserved words */
     DWORD e_lfanew;     /* 3c: Offset to extended header */
 } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


이렇게 구조체로 이루어져 있고, 각각 선언된 자료형의 크기만큼 각각의 자리를 차지하고 있어요.

(WORD = 2byte, LONG = 4byte)


그중에서도 다른거 보는게 넘나 귀찮은 콘치는 딱 두개의 부분만 확인할거에요.


WORD e_magic;
LONG e_lfanew;


볼까요?


  • e_magic

    • PE인증마크인 MZ 라는 문자열을 표시하는 부분입니다. 아까 PE파일 맨앞에는 MZ가 나온다고 했잖아여.

    • 이 구조체에 `4D5A`라는 값이 들어있기 때문에 `MZ`라는 문자가 보이는거에여.

    • 왜 `4D5A`가 나오냐고 묻고 싶으면 구글가셔서 `ASCII`라고 검색해서 나오는 표에 M이랑 Z의 16진수 값을 확인해주세여.

  • e_lfanew

    • 얘가 포인트에요. Dos Header가 지나고 나서, 다음으로 나올 `NT Header`가 어디에 있는지, 그러니까 `NT Header`에 대한 내용이 시작하는 위치(Offset)를 알려주는 부분입니다.

    • 못믿을거 같아서 보여드림 ㅎ_ㅎ..(자비 + 300)



보시면 맨처음에 MZ를 출력하는 `e_magic` 구조체가 나오고, 그 다음으로 나오는 네모상자가 `e_lfanew`입니다.

요녀석.. `F0 00 00 00` 라고 적혀있네요. 리틀엔디언으로 적혀있기 때문에 실제로는 `0x000000F0` 위치를 확인해주시면 됩니다.

`0x000000F0` 위치에 있는 녀석이 뭔지 봅시다. PE라고 적혀있네여. ㅎㅎㅋ  위치 들킴잼!


이런식으로 그냥 막 적어 둔거 같지만 막 적혀있지 않은..

쉬운거 같지만 쉽지만은 않은 PE포맷 입니다.


Dos Header 한줄요약 : 시작과 끝을 주목하셈.




그럼 말나온김에 다음 헤더로 가볼까여 ‘ㅅ’?(ㅋㅋ 님들, PE는 지금부터임ㅋㅋ)


는 다음헤더로 넘어가기전에 당부의 말씀!


+) PE의 구조(포맷)에 대해 이야기를 하다보면 제가 Offset이라는 말과 RVA 이라는 말을 자주 사용할거예요.

이는 제가 다음편에 가서 조금 자세히 알려드릴테니 지금은 그냥 구랭구랭 하고 넘어가시면 됩니다.

지금은 그냥


Offset은 우리가 눈으로 보고 있는 HxD 상에서의 주소

RVA는 요 실행파일이 메모리에 올라가면 시작되는 주소로 부터의 거리


라고 생각해주세요. 왜 주소가 아닌 거리를 표현하는지 또한 다음편에 다 나옵니다.




NT Header


다음으로 보게 될 헤더는 NT Header라고 합니다. ‘ㅅ’


typedef struct _IMAGE_NT_HEADERS {
   DWORD Signature;
   IMAGE_FILE_HEADER FileHeader;     /* 0x04 */
   IMAGE_OPTIONAL_HEADER32 OptionalHeader;   /* 0x18 */
 } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;


헤헤 몇개 없네요 ㄱㅇㄷ?


은뻥


typedef struct _IMAGE_FILE_HEADER {
   WORD  Machine;
   WORD  NumberOfSections;
   DWORD TimeDateStamp;
   DWORD PointerToSymbolTable;
   DWORD NumberOfSymbols;
   WORD  SizeOfOptionalHeader;
   WORD  Characteristics;
 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


typedef struct _IMAGE_OPTIONAL_HEADER {  

   /* Standard fields */
   WORD  Magic; /* 0x10b or 0x107 */ /* 0x00 */
   BYTE  MajorLinkerVersion;
   BYTE  MinorLinkerVersion;
   DWORD SizeOfCode;
   DWORD SizeOfInitializedData;
   DWORD SizeOfUninitializedData;
   DWORD AddressOfEntryPoint;        /* 0x10 */
   DWORD BaseOfCode;
   DWORD BaseOfData;

   /* NT additional fields */
   DWORD ImageBase;
   DWORD SectionAlignment;       /* 0x20 */
   DWORD FileAlignment;
   WORD  MajorOperatingSystemVersion;
   WORD  MinorOperatingSystemVersion;
   WORD  MajorImageVersion;
   WORD  MinorImageVersion;
   WORD  MajorSubsystemVersion;      /* 0x30 */
   WORD  MinorSubsystemVersion;
   DWORD Win32VersionValue;
   DWORD SizeOfImage;
   DWORD SizeOfHeaders;
   DWORD CheckSum;           /* 0x40 */
   WORD  Subsystem;
   WORD  DllCharacteristics;
   DWORD SizeOfStackReserve;
   DWORD SizeOfStackCommit;
   DWORD SizeOfHeapReserve;      /* 0x50 */
   DWORD SizeOfHeapCommit;
   DWORD LoaderFlags;
   DWORD NumberOfRvaAndSizes;
   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */

 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;


히히!


진정하시고! 모두 다 필요하기때문에 다~~~ 봐야 하지만 ‘ㅅ’.. 그중에서도

★자★주★봐야 하는 부분만 몇개 뽑아서 소개를 해줄게요.

(그래도 넘나 많기 때문에 어느정도는 각오해야함 ㅎㅎ 이정도는 다들 할 수 있져? :D)


NT Header 구조체부터 구경합시다. ‘ㅅ’..


typedef struct _IMAGE_NT_HEADERS {
   DWORD Signature;
   IMAGE_FILE_HEADER FileHeader;     /* 0x04 */
   IMAGE_OPTIONAL_HEADER32 OptionalHeader;   /* 0x18 */
 } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;


NT Header는 PE(50 45)라는 문자로 시작합니다.

아까 Dos Header가 MZ로 시작했던거랑 비슷하게 말이에요.

이 PE는 구조체의 가장 첫번째에도 나와있다시피 Signature안에 들어있는 내용입니다.


한줄정리 : PE라는 문자열이 보이면 NT Header의 시작인셈이네요!




그다음으로 나오는 녀석들은 자료형이 조금 특이하네요.

이름만 보고선 느낌이 쓰윽 오시는 분들도 계시겠지만…

얘들은 각각의 구조체입니다. ㅋㅋ


IMAGE_FILE_HEADER부터 한번 보도록 합시다.


typedef struct _IMAGE_FILE_HEADER {
   WORD  Machine;
   WORD  NumberOfSections;
   DWORD TimeDateStamp;
   DWORD PointerToSymbolTable;
   DWORD NumberOfSymbols;
   WORD  SizeOfOptionalHeader;
   WORD  Characteristics;
 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


뭐가 많네여 -ㅅ-

그러니까 필요한거만 몇개 보고 가도록 해여 나 넘나 힘듬.


 typedef struct _IMAGE_FILE_HEADER {
   WORD  Machine;
   WORD  NumberOfSections;
   WORD  SizeOfOptionalHeader;
   WORD  Characteristics;
 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


  • Machine

    • 얘는 그거에요, 이 파일이 어떤 환경에서 돌아가는지 알려주는 부분.

    • 아래의 그림에서는 014C라고 되어있네여.

    • 이를 아래의 필드에서 찾아보면 Intel 386 환경에서 돌아감을 의미하고 있어여. 그렇다고 해서 반드시 014C라고 되어있는건 아닙니다. PE가 존재하는 환경이 반드시 Intel 386이란 법은 없으니까요.
      자세한 내용은 아래의 그림을 참고하세여.
      뭐 이정도 값은 다들 외울수 있죠?ㅎㅎ?
      는 몰라 안해 안할꺼야ㅑㅑㅑㅑㅑㅑ끼에에에엥


 /* These are the settings of the Machine field. */
 #define IMAGE_FILE_MACHINE_UNKNOWN  0
 #define IMAGE_FILE_MACHINE_I860     0x014d
 #define IMAGE_FILE_MACHINE_I386     0x014c
 #define IMAGE_FILE_MACHINE_R3000    0x0162
 #define IMAGE_FILE_MACHINE_R4000    0x0166
 #define IMAGE_FILE_MACHINE_R10000   0x0168
 #define IMAGE_FILE_MACHINE_WCEMIPSV2    0x0169
 #define IMAGE_FILE_MACHINE_ALPHA    0x0184
 #define IMAGE_FILE_MACHINE_SH3      0x01a2
 #define IMAGE_FILE_MACHINE_SH3DSP   0x01a3
 #define IMAGE_FILE_MACHINE_SH3E     0x01a4
 #define IMAGE_FILE_MACHINE_SH4      0x01a6
 #define IMAGE_FILE_MACHINE_SH5      0x01a8
 #define IMAGE_FILE_MACHINE_ARM      0x01c0
 #define IMAGE_FILE_MACHINE_THUMB    0x01c2
 #define IMAGE_FILE_MACHINE_ARMNT    0x01c4
 #define IMAGE_FILE_MACHINE_ARM64    0xaa64
 #define IMAGE_FILE_MACHINE_AM33     0x01d3
 #define IMAGE_FILE_MACHINE_POWERPC  0x01f0
 #define IMAGE_FILE_MACHINE_POWERPCFP    0x01f1
 #define IMAGE_FILE_MACHINE_IA64     0x0200
 #define IMAGE_FILE_MACHINE_MIPS16   0x0266
 #define IMAGE_FILE_MACHINE_ALPHA64  0x0284
 #define IMAGE_FILE_MACHINE_MIPSFPU  0x0366
 #define IMAGE_FILE_MACHINE_MIPSFPU16    0x0466
 #define IMAGE_FILE_MACHINE_AXP64    IMAGE_FILE_MACHINE_ALPHA64
 #define IMAGE_FILE_MACHINE_TRICORE  0x0520
 #define IMAGE_FILE_MACHINE_CEF      0x0cef
 #define IMAGE_FILE_MACHINE_EBC      0x0ebc
 #define IMAGE_FILE_MACHINE_AMD64    0x8664
 #define IMAGE_FILE_MACHINE_M32R     0x9041
 #define IMAGE_FILE_MACHINE_CEE      0xc0ee


  • NumberOfSections

    • 얘는 이름 그대로 현재의 PE에 몇개의 섹션이 들어있는지를 알려주는 녀석이에요. 얘들 이름 잘보면 얼추 뭐하는 부분인지 알 수 있어요.
      되게 이름 잘지어둔듯;;

    • PE에 저장되는 데이터들은 `섹션`이라는 부분들에 나누어져서 저장이 되는데 이 섹션이 몇개가 있는지 알려줘요.

    • 아참 섹션에 대한 내용은 나중에 언급되니 그때가서 자세히 보도록 해염!!

    • 위의 그림을 보면`0007`이라고 적혀있으니 얘는 총 7개의 섹션을 가지고 있다고 볼 수 있겠군요.
      아래 그림을 보면 참트루네여 ‘ ㅅ’!!


  • SizeOfOptionalHeader

    • 얘는 자기 다음으로 오는 `IMAGE_OPTIONAL_HEADE`의 크기를 알려주는 녀석입니다.

    • 오잉 이걸 왜알아야하져? 라고 생각하시는 분들이 있겠네요.
      얘를 알아야 다음에 오는 구조체의 범위(크기)를 잡고 얘가 그만큼의 데이터를 파일의 정보로 이해 하겠죠?


  • Characteristics

    • 얘는 PE파일이 어떤 특성을 가지고있는지 낭낭하게 알려주는 녀석이에여.
      여러가지 특성이 있어서 요 값들이 합쳐져서 나타나요.
      값을 찾는 재미가 있달까…(수줍) `0102` 면 0002와 0100이 합쳐져 있네요.
      처음에 아니 이걸 내가 어떻게 알아 !!!!!!!!!!!!! 미칭거아냐!!! 했는데
      플래그 값들을 보면 이해할 수 밖에 없습니다 -.- .. ㅎㅎ.. 제자신에게 분노가 많은걸로..


+) 아참 제가 지금 설명해드리는 구조체와 플래그 값들은 모두 여기에서 이름 고대로 검색하시면 잘들 나옵니다. 

참고하세영 :3(얘들이 winnt.h를 참조하기 때문이져 요 사이트 개꿀인듯)




훔냥 NT Header의 두번째 구조체 IMAGE_OPTIONAL_HEADER32입니다.


typedef struct _IMAGE_OPTIONAL_HEADER {  

   /* Standard fields */
   WORD  Magic; /* 0x10b or 0x107 */ /* 0x00 */
   BYTE  MajorLinkerVersion;
   BYTE  MinorLinkerVersion;
   DWORD SizeOfCode;
   DWORD SizeOfInitializedData;
   DWORD SizeOfUninitializedData;
   DWORD AddressOfEntryPoint;        /* 0x10 */
   DWORD BaseOfCode;
   DWORD BaseOfData;

   /* NT additional fields */
   DWORD ImageBase;
   DWORD SectionAlignment;       /* 0x20 */
   DWORD FileAlignment;
   WORD  MajorOperatingSystemVersion;
   WORD  MinorOperatingSystemVersion;
   WORD  MajorImageVersion;
   WORD  MinorImageVersion;
   WORD  MajorSubsystemVersion;      /* 0x30 */
   WORD  MinorSubsystemVersion;
   DWORD Win32VersionValue;
   DWORD SizeOfImage;
   DWORD SizeOfHeaders;
   DWORD CheckSum;           /* 0x40 */
   WORD  Subsystem;
   WORD  DllCharacteristics;
   DWORD SizeOfStackReserve;
   DWORD SizeOfStackCommit;
   DWORD SizeOfHeapReserve;      /* 0x50 */
   DWORD SizeOfHeapCommit;
   DWORD LoaderFlags;
   DWORD NumberOfRvaAndSizes;
   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */

 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;


뭔가 내용이 겁나 많아보이네여…ㄷㄷ..


현기증이 나는듯하니 당장 필요한 몇개만 추려보도록 하겠습니다.

(그렇다고해서 다른것들은 필요없다는 이야기는 아닙니다. 오해 ㄴㄴ)


typedef struct _IMAGE_OPTIONAL_HEADER {

   /* Standard fields */
   WORD  Magic; /* 0x10b or 0x107 */ /* 0x00 */
   DWORD SizeOfCode;
   DWORD AddressOfEntryPoint;        /* 0x10 */
   DWORD BaseOfCode;
   DWORD BaseOfData;

   /* NT additional fields */
   DWORD ImageBase;
   DWORD SizeOfImage;
   DWORD SizeOfHeaders;
   WORD  Subsystem;
   DWORD NumberOfRvaAndSizes;
   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */

 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;


(지극히 개인적인 콘치의 중요도입니다. 아니 이중요한게 왜빠졌어??? 라고 물으신다면… 그건 콘치가 물고기라 그런걸로…)

어맛! 확줄어들었네영 ‘0’!! 넘나!! 신나는것!!


  • Magic

    • 매직매직매직 매직매직매직~

    • 얘는 32bit PE, 64bit PE에서 각각 다른값을 가져요.
      때문에 얘를 보고서 아 얘는 32bit PE, 64bit PE구나 알 수 있게되는거져.
      두 값이 어떻게 다른지는 한번 직접 테스트해서 알아보시는걸로 ~~!(절대 귀찮아서 그러는게 아님!


  • AddressOfEntryPoint
    • 오 ~ 이름만 슥 봐도 “오 이건 좀 알아야겠다” 싶지 않나여
      제목 그대로 엔트리포인트의 RVA에 대한 정보가 들어있는 녀석입니다.
    • 지난 리버싱 튜토리얼때도 잠깐 말씀드렷던것 같은데 엔트리포인트라 하면 무려 프로그램이 시작되는 ★프로그램의 시작점★을 의미합니다.
        이런 상당히 중요한 주소값을 담고 있다니.. 넘나 중요해보이는것!!
    • 음.. 그런데 어째 주소의 상태가 이상한것 같네요. ‘ㅅ’..?
      0x0002FCAD 라는데 저런 위치에 프로그램이 로드될 수 있나요…?? 라고 생각이 드시나여!
      이는 왕콘치의 빅픽쳐 입니다.
      다음편을 보시면 한방에 해소 될 문제이니 우선은 음.. 그러큐냐… 뭐지이건 하고 넘어가도록 합시다.


  • BaseOfCode / BaseOfData
    • 얘들도 말 그대로 코드와 데이터가 어디서 시작되는지 시작주소의 RVA를 의미해여.
      PE 구조를 볼때마다 느끼지만 얘들 보면 참 설계 예쁘게 잘해놓은 것 같아요..
      크기, 시작주소 딱딱 정해놔서 얼만큼은 코드다 데이터다 쌱! 끝!
      아니라구여? ㅈㅅ


  • ImageBase
    • 또 한번 `AddressOfEntryPoint`만큼 중요한 녀석이 나왔네여
      이건 정말 넘나 중요한 부분이니 별을 세개정도만 쳐주도록 해여.
      이미지 베이스 입니다 두둠칫!!
      얘는 메모리에서 PE파일이 어디에 로딩이 되는지 메모리에 로딩되는 시작 주소를 알려주는 부분이에요.
      넘나 중요합니다 완전 중요합니다. 별다섯개
    • 이건 다음시간에 만나게될 `RAW`, `RVA`에 대해 이야기할때 얘가 주인공이 될테니 지금은 넘어가는걸로!!
      잊지말고 있으세여 다음시간에 또 물어볼꺼니까


  • SizeOfImage
    • 얘는 파일이 실행되기 위해서 메모리에 탑승(로딩)했을때의 PE Image가 가지는 크기를 의미합니다.
    • 오잉 뭐 실행되기 전이랑 후랑 뭐가 다르겠…네 다릅니다 ‘ㅅ’…ㅎ..
      요건 나중에 가면 왜그런지 나올꺼에여 !! :3


  • SizeOfHeaders
    • 얘는 파일에서의 PE Header 전체적인 크기를 나타내는 부분이에요(으앙 헤깔려 !!)
      앞에 나왔던 DosHeader, 지금 이부분인 NT Header, 그리고 다음에 나올 Section Header 까지 모든 헤더의 사이즈를 나타냅니다.


  • IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
    • 얘는 이름 고대로 데이터들의 사전같은 존재임당.
    • 얘를 이해하기 위해선 IMAGE_DATA_DIRECTORY 구조체 배열을 한번 확인해보는게 좋을것 같군여.
    • 사실 얘한테 PE구조의 핵심 액기스들이 다 들어있다고 해도 과언이 아닙니다.


#define IMAGE_DIRECTORY_ENTRY_EXPORT        0
#define IMAGE_DIRECTORY_ENTRY_IMPORT        1
#define IMAGE_DIRECTORY_ENTRY_RESOURCE      2
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION     3
#define IMAGE_DIRECTORY_ENTRY_SECURITY      4
#define IMAGE_DIRECTORY_ENTRY_BASERELOC     5
#define IMAGE_DIRECTORY_ENTRY_DEBUG         6
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT     7
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR     8   /* (MIPS GP) */
#define IMAGE_DIRECTORY_ENTRY_TLS           9
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG   10
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  11
#define IMAGE_DIRECTORY_ENTRY_IAT           12  /* Import Address Table */
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT  13
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR    14


짜잔 요렇습니다.


뭐 다들 중요하지만 그중에서도 주목해야할게 IMAGE_DIRECTORY_ENTRY_EXPORT 와 IMAGE_DIRECTORY_ENTRY_IMPORT 입니당.


그리고 나중에 언젠가 보게될 #define IMAGE_DIRECTORY_ENTRY_TLS 와 #define IMAGE_DIRECTORY_ENTRY_IAT 까지두여.

TLS 어쩌구 저쩌구를 제외한 나머지는 모두 IAT와 EAT에 관여하는 부분들인데여 이또한 다음편에서 모두 상세하게 다룰 예정입니다.


얘들이 뭔지 간단하게 말씀드리자면


  1. 내가 이 프로그램에서 어떤 함수를 사용하는지 모아둔 것과(IAT)

  2. 내가 라이브러리가 되어서 다른 프로그램들에게 제공하는 함수들을 모아둔것에 대한 내용이 담겨있는 부분입니다(EAT)


우리는 이러한 부분들을 이용하여 후킹을하거나, 이 프로그램에서는 요런 함수가 쓰이니까 얘는 뭐하는 프로그램이다!

하고 추측할 수 있게 되죠.

키득키득




Section Header


헷헷! 마지막으로 소개할 Section Header입니다.


우선 섹션에 대해서 간단하게 소개할게요!


PE는 각각의 데이터들을 각각의 용도에 맞게 각각의 Section에 저장합니다.



제가 씹고 뜯고 맛보고 즐기고 있는 프로그램의 섹션들입니다.


ㅁ_ㅁ이런 섹션들을 사용하기 위해서 얘들도 다들 각각의 정보가 들은 Header를 가집니다.


typedef struct _IMAGE_SECTION_HEADER {
   BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
   union {
     DWORD PhysicalAddress;
     DWORD VirtualSize;
   } Misc;
   DWORD VirtualAddress;
   DWORD SizeOfRawData;
   DWORD PointerToRawData;
   DWORD PointerToRelocations;
   DWORD PointerToLinenumbers;
   WORD  NumberOfRelocations;
   WORD  NumberOfLinenumbers;
   DWORD Characteristics;
 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;


뭔가 위에서 봤던 다른 헤더들에서 나오던 내용과 비슷해보이져?

맞아염 비슷한데 얘는 섹션에 대한 내용일 뿐이에여.


그중에서 몇개만 살펴볼까여?


  • VirtualSize

    • 요프로그램이 메모리에 올라갔을때, 해당하는 섹션이 얼만큼 공간을 차지하고 있는지 알려주는 부분이에요.


  • VirtualAddress

    • 섹션의 시작주소를 의미하는 곳인데 프로그램이 메모리에 올라갔을때의 RVA를 의미합니다.

    • 그러고보니 PE헤더 에서는 거의 대부분의 값이 RVA로 되어있네요. 왜그럴까요 ~~~????

    • 다음편에서 뵙도록 하겠습니다ㅋㅋ


  • SizeOfRawData

    • 얘는 파일 그 자체(실행전)에서 섹션이 차지하는 크기를 의미합니다.
      자꾸 파일/메모리 이런 말들이 나와서 혼란혼란 열매를 드신분들은 다음편에서 정리해드릴테니 조금만 참아주세영!
      지금은 아 그런게 있구나~!! 하고 넘어가시면 됩니다.


  • PointerToRawData

    • 얘도 RawData라는 단어가 붙어있는걸 보니 파일에서의 뭐쩌구저쩌구겠네요.
      맞아여 얘는 파일에서의 섹션 시작위치(Offset)를 의미합니다.


  • Characteristics

    • 그리고 얘는 다른 헤더에서 나왔던것과 마찬가지로 속성을 의미하구요.




정리


  • 이름에 base가 나오면 시작주소를 의미하는경우가 많다.

  • EntryPoint가 들어간건 넘나 중요한것 같다.

  • Raw 라는 말이 들어가면 Offset을 의미하는 듯 하다.

  • 파일에서의 구조와 실행된 후의 구조는 다른듯하다(이름들을 귀찮게 구분해둔데는 이유가 있을듯)

  • Address가 들어간 부분도 주의깊게 살펴보도록 하자.

  • 거의 대부분의 주소는 RVA로 되어있다. 왜그런지는 자꾸 다음편에서 설명해준다고 하는데 못믿겠다.

  • 존ㄴr 뭔말인지 모르겠다.

  • 개노잼




마치며


이렇게 뭔가 배운듯 안배운듯한 PE헤더에 대한 설명들이 끝났습니다.

별로 안어렵져?^^?ㅋㅋ;;;


그런데 제가 설명한것 보다는 중간에 혼자 강제 점프해서 넘어간 내용들이 더 많아

이건 맛보기로만 보시고 제대로 마음잡고 공부할때는 참고만 하시면 될듯 합니다.

헤헤 이거만 보고 PE별거 아니네 하면 큰일남…ㅎ..ㅋ..


왜냐하면 우리에겐 64bit PE라는 존재가아직 남아 있기 때문이라는


그리고 더 환장하겠는 사실은

우리가 본 PE를 통째로 외우는 분이 계십니다. ㄷㄷ;; ㅎ…

와타시는 책봐도 잘 모르겠는데!!!!!!!!!!!!….

사람아닌줄..

;;; ..


결론 : 갈길이 개 멀다. 응 끝아니야 ~~ 




다음편 예고


중간중간에 이해가 안되는 부분들이 많이 있었어여


뭐 메모리상의 뭐쩌구 저쩌구, 파일상의 뭐쩌구 저쩌구… !!!

RVA, Offset, Raw????

뭐가다른데 자꾸 구별을 하는건지 요걸 이해 못했어요.

왜 PE는 메모리상의 공간과 파일상의 공간을 따로 나눌까여 ‘ㅅ’…?

결국 컴퓨터 안에 있는건 매한가지면서 -ㅅ-!!!!!


다음편에서는 이런것들에 대한내용들을 조금 다룰까 합니다.

PE를 좀더 이해하기 위한 이야기들을 들고 찾아올테니 그때 다시 뵙도록 해염


난2만 !


comments powered by Disqus