'엔트리 포인트'에 해당되는 글 1건

  1. 2009.03.29 PE(Portable Executable) File Format (3) - PE Header (18)



NT header



NT header 구조체 IMAGE_NT_HEADERS 입니다.

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                          // PE Signature : 50450000 ("PE"00)
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

* 출처 : Microsoft 의 Visual C++ 에서 제공하는 winnt.h


위 구조체는 32 bit 용이며, 64 bit 용은 세번째 멤버가 IMAGE_OPTIONAL_HEADER64 입니다.

IMAGE_NT_HEADER 구조체는 3개의 멤버로 되어 있는데요,
제일 첫 멤버는 Signature 로서 50450000h ("PE"00) 값을 가집니다. (변경불가!)
그리고 FileHeader OptionalHeader 구조체 멤버가 있습니다.

notepad.exe 의 IMAGE_NT_HEADERS 의 내용을 hex editor 로 살펴보겠습니다.


IMAGE_NT_HEADERS 구조체의 크기는 F8h 입니다. 상당히 큰 구조체 입니다.
FileHeader 와 OptionalHeader 구조체를 하나하나 살펴보겠습니다.



IMAGE_NT_HEADERS - IMAGE_FILE_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;

* 출처 : Microsoft 의 Visual C++ 에서 제공하는 winnt.h

IMAGE_FILE_HEADER 구조체에서 아래 4 가지 멤버들이 중요합니다.
(이 값들이 정확히 세팅되어 있지 않으면 파일은 정상적으로 실행되지 않습니다.)


#1. Machine
Machine
넘버는 CPU 별로 고유한 값이며 32 bit Intel 호환 칩은 14Ch 의 값을 가집니다.
아래는 winnt.h 파일에 정의된 Machine 넘버의 값들입니다. (일반적인 14Ch 의 값을 기억하면 됩니다.)

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64



#2. NumberOfSections
PE 파일은 코드, 데이타, 리소스 등이 각각의 섹션에 나뉘어서 저장된다고 설명드렸습니다.
NumberOfSections 는 바로 그 섹션의 갯수를 나타냅니다.

이 값은 반드시 0 보다 커야 합니다.

정의된 섹션 갯수보다 실제 섹션이 적다면 실행 에러가 발생하며,
정의된 섹션 갯수보다 실제 섹션이 많다면 정의된 갯수만큼만 인식됩니다.


#3. SizeOfOptionalHeader
IMAGE_NT_HEADERS 구조체의 마지막 멤버는 IMAGE_OPTIONAL_HEADER32 구조체입니다.
SizeOfOptionalHeader 멤버는 바로 이 IMAGE_OPTIONAL_HEADER32 구조체의 크기를 나타냅니다.

IMAGE_OPTIONAL_HEADER32 는 C 언어의 구조체이기 때문에 이미 그 크기가 결정되어 있습니다.
그런데 Windows 의 PE Loader 는 IMAGE_FILE_HEADER 의 SizeOfOptionalHeader 값을 보고
IMAGE_OPTIONAL_HEADER32 구조체의 크기를 인식합니다.


IMAGE_DOS_HEADER 의 e_lfanew 멤버와 IMAGE_FILE_HEADER 의 SizeOfOptionalHeader 멤버 때문에
일반적인(상식적인) PE 파일 형식을 벗어나는 일명 '꽈배기' PE 파일(PE Patch) 이 만들 수 있습니다.
(나중에 PE Patch 에 대해서 상세히 설명하도록 하겠습니다.)


#4. Characteristics
파일의 속성을 나타내는 값으로써, 실행이 가능한 형태인지(executable or not)
혹은 DLL 파일인지 등의 정보들이 bit OR 형식으로 조합됩니다.

아래는 winnt.h 파일에 정의된 Characteristics 값들입니다. (0002h 와 2000h 의 값을 기억해 두세요.)

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable 
                                                     // (i.e. no unresolved externel references).

#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from
                                                     // file in .DBG file

#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, 
                                                     // copy and run from the swap file.

#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net,
                                                     // copy and run from the swap file.

#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.


참고로 PE 파일중에 Characteristics 값에 0002h 가 없는 경우(not executable)가 있을까요?
네, 있습니다. 예를 들어 *.obj 와 같은 object 파일이 그런 경우이고, resource DLL 같은 파일이 그런 경우 입니다.

이 정도면 IMAGE_FILE_HEADER 의 구조를 이해하는데 부족함이 없을 것입니다.

마지막으로 IMAGE_FILE_HAEDER 의 TimeDateStamp 멤버에 대해서 설명드리겠습니다.
이 값은 파일의 실행에 영향을 미치지 않는 값으로써 해당 파일의 빌드 시간을 나타낸 값입니다.
단, 개발 도구에 따라서 이 값을 세팅해주는 도구(VB, VC++)가 있고, 그렇지 않은 도구(Delphi)가 있습니다.
(또한 개발 도구의 옵션에 따라서 달라질 수 있습니다.)


이제 실제로 notepad.exe 의 IMAGE_FILE_HEADER 를 확인해 보겠습니다.


위 그림은 hex editor 로 봤을때의 그림이고, 이를 알아보기 쉽게 구조체 멤버로 표현하면 아래와 같습니다.

[ IMAGE_FILE_HEADER ] - notepad.exe

 offset   value   description

-------------------------------------------------------------------------------
000000E4     014C machine
000000E6     0003 number of sections
000000E8 48025287 time date stamp (Mon Apr 14 03:35:51 2008)
000000EC 00000000 offset to symbol table
000000F0 00000000 number of symbols
000000F4     00E0 size of optional header
000000F6     010F characteristics
                      IMAGE_FILE_RELOCS_STRIPPED
                      IMAGE_FILE_EXECUTABLE_IMAGE
                      IMAGE_FILE_LINE_NUMS_STRIPPED
                      IMAGE_FILE_LOCAL_SYMS_STRIPPED
                      IMAGE_FILE_32BIT_MACHINE


다음에는 NT header 의 세번째 멤버인 IMAGE_OPTIONAL_HEADER32 에 대해서 알아보겠습니다.

(continue)


 

  1. hoon038 2009.11.28 18:52 신고 댓글주소 | 수정 | 삭제 | 댓글

    감사합니다 잘 봤어요^^

  2. Ezbeat 2009.12.22 15:42 신고 댓글주소 | 수정 | 삭제 | 댓글

    시간날 때마다 조금씩 잘 읽어보고 있습니다 ^^
    음.. 잘못 표기한 부분이 있으신거 같네요;;
    IMAGE_FILE_HEADER부분을 설명 하신 후
    실제로 notepad.exe의 IMAGE_FILE_HEADER를 확인해 주신다고 하셨을 때
    IMAGE_FILE_HEADER부분이 아닌 IMAGE_NT_HEADERS멤버인 Signature변수가
    그림에 포함이 되어 있네요 ^^;;(4Byte)

  3. Lum4n 2010.07.17 08:41 신고 댓글주소 | 수정 | 삭제 | 댓글

    유익하게 보고있습니다ㅎㅎ 정말 이해하기 쉽게 설명해놓으셨군요 : )

  4. Acaicat 2010.08.12 00:03 신고 댓글주소 | 수정 | 삭제 | 댓글

    Charateristics에 관해 궁금한게 있는데요.
    그 0x0002와 0x2000을 기억해 두라고 하셨는데,
    아래 hex를 보면 0x010F인데 이것은 어떻게 봐야하나요?
    제 컴에서 켰을 때는 0x0102가 나와서
    winnt.h를 열어서 봤는데 이런 것 정의 에 없더라구요.
    혹시나 해서 win32 콘솔로 컴파일된 실행 파일을 넣어 봤는데 0x0102가 나오더라구요.
    이건 또 어떻게 봐야하는지 궁금합니다.

  5. db_click 2011.01.17 16:49 신고 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요!
    눈팅만 하다가,
    궁금한게 생겼는데,

    검색 능력이 턱없이 부족한지라..
    질문 해도 되나요..ㅎㅎ

    * TimeDateStamp 값 해석
    노트패드를 PEView로 확인해 보니
    TimeDateStamp에 저장되는 값이
    0x47918EA2 가 나오던데요,
    이 값이 2008/01/19, 05:46:10 UTC 로
    풀어져있더라구요.
    어떻게 하면, 이렇게 해석이 될까요..

  6. TeamKhan 2011.04.01 17:59 신고 댓글주소 | 수정 | 삭제 | 댓글

    IMAGE_NT_HEADERS 구조체의 크기는 F8h 이란걸 어떻게 파악하신건가요 ?
    그리고 어떻게 실제로
    hex editor 부분에서
    이부분까지가 IMAGE_FILE_HEADER 인걸
    파악하셧나요 ?

    • reversecore 2011.04.06 01:07 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      C 언어의 구조체는 크기가 정해져 있으니 자연히 그 크기를 알 수 있구요. sizeof(IMAGE_NT_HEADERS) 연산자를 써도 알 수 있지요.

      그리고 구조체의 내부 구조를 훤히 알고 있으니 IMAGE_NT_HEADERS 구조체 시작부터 4 byte 이후가 IMAGE_FILE_HEADER 인걸 아는 거지요. ^^

      감사합니다.

  7. 강한이 2011.05.26 23:39 신고 댓글주소 | 수정 | 삭제 | 댓글

    위에 마지막 케릭터리스틱스에 010F로 되어있는데 원래 핵스는 뒤에서 읽어와서 그런건지 알겠고
    그밑에 부가적인 값들은 어떻게 계산하는건가요? 보니까 뒤에 읽어보니 OR명령어도 되있다고하는데 추가설명이 없네요.
    그리고 타임스템프는 어떻게 변환해야하는거죠?
    48025287-> Mon Apr 14 03:35:51 2008
    답변 부탁드려요

    • Zero 2011.05.31 14:35 신고 댓글주소 | 수정 | 삭제

      010F는 위에 써있는 옵션들을 모두 OR연산 할경우 나오는 값입니다.

      옵션으로인해

      0001
      0002
      0004
      0008
      값들이 합쳐서 F가 되는거구요.
      0100도 OR연산이 되어
      010F가 되는것입니다.

      타임스템프는 위에 C언어 함수를 사용하면 된다고 댓글에 있군요..

    • reversecore 2011.06.03 22:18 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      Zero 님께서 답변을 잘 해주셨네요~ 감사합니다. ^^

      참고로 VC++, SDK 를 설치하신 후 winnt.h 파일에 보시면 저 값의 정의가 나와 있습니다.

      #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
      #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
      #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
      #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
      #define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.

      감사합니다.

  8. bp 2012.11.30 16:42 신고 댓글주소 | 수정 | 삭제 | 댓글

    안녕하세요.
    characteristics에서 add 연산을 사용할 수는 없을까요?
    or 연산을 사용하는 특별한 이유가 있나요?

    • reversecore 2012.12.02 19:00 신고 댓글주소 | 수정 | 삭제

      안녕하세요.

      좋은 질문이네요~

      Characteristics 는 각 bit 별로 의미를 가지는 형태입니다. 이러한 형태는 C언어의 강력한 bit 단위 처리 능력을 활용할 수 있기 때문에 관례적으로 OR 명령으로 처리되고 있습니다.

      말씀하신대로 ADD 로도 됩니다만, 의미를 부여하기 위해 (그 bit 를 ON 시킨다.) OR 를 쓰게되면 프로그래머들끼리 의사 전달이 명확하게 되지요. "아~ bit 처리를 이용한 FLAG 사용법이군~" 하고 말이죠. ^^

      감사합니다.





티스토리 툴바