고수닷넷 - 데미소다오렌지님
이 문서는 msdn의 매트 피에트릭의 문서 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndebug/html/msdn_peeringpe.asp 를 번역한 것 입니다.
섹션 테이블
PE 헤더와 바이너리 데이터 데이터 사이에는 이미지의 섹션을 위한 섹션 테이블이 위치해 있다. 섹션 테이블은 본질적으로 이미지에 포함된 각각의 섹션과 관련된 정보를 가지고 있는 전화번호부와 같은 역할을 한다. 이미지에 포함된 섹션은 알파벳순이 아닌, 시작 주소(RVA)에 의해서 정렬된다.
이제 섹션이 무엇인지 좀 더 명확하게 할 수 있다. NE 파일에서, 프로그램의 코드와 데이터는 파일의 구분된 "세그먼트"내에서 정렬되어진다. NE 헤더중의 일부는 프로그램이 사용하는 각각의 세그먼트의 구조체 배열이다. 배열속의 각각의 구조체는 하나의 세그먼트에 대한 정보를 가지고 있다. 저장되어져있는 정보는 세그먼트의 타입(코드냐 데이터냐), 크기, 그리고 파일에서 저장된 위치에 대한 것들을 포함한다. PE 파일에서, 섹션 테이블은 NE 파일의 세그먼트 테이블과 유사하다. 반면에 NE 파일의 세그먼트 테이블과는 대조적으로 각각의 섹션 테이블 항목은 파일의 바이너리 데이터가 메모리로 맵핑되는 위치에 대한 주소를 저장하고 있다. 섹션이 32비트 세그먼트와 유사하지만, 섹션이 실제로 각각의 세그먼트가 되는 것은 아니다. 그것들은 단지 프로세스의 가상 주소 공간에서 메모리 범위일 뿐이다.
또 다른 PE 파일이 NE 파일의 차이점은 프로그램이 사용하지 않고 운영체제에서 사용하는 지원(서포팅) 데이터들을 다루는 방법이다. 예를들면, 실행 파일이 사용하는 DLL의 목록이나 픽스업 테이블의 위치와 같은 것이다. NE 파일에서는, 리소스는 세그먼트로 고려되지 않는다. 비록 리소스에 할당된 셀렉터들이 있다고 하더라도, 리소스와 관련된 정보는 NE 헤더의 세그먼트 테이블에 저장되지 않는다. 대신에, 리소스는 NE 헤더의 마지막에 위차한 분리된 테이블내에 저장된다. 임포트되거나 익스포트된 함수와 관련된 정보 또한 독립된 세그먼트를 가질 권리가 없다. 해당 정보들은 NE 헤더에 포함된다.
PE파일에서는 이 모든 이야기가 틀리게 된다. 필수적인 코드와 데이터로 고려되는 모든것은 완전한 섹션속에 저장된다. 그래서 임포트된 함수와 관련된 정보는 독립된 섹션에 저장되며, 익스포트된 함수 테으블또한 그렇게 된다. 재배치 데이터와 관련된 것들도 동일한 방식으로 처리된다. 프로그램 또는 운영체제에서 필요한 어떠한 코드나 데이터도 그들의 독립적인 섹션을 가지게 된다.
특정 섹션과 관련된 논의를 하기 전에, 운영체제가 다루는 섹션과 관련된 데이터를 먼저 설명할 필요가 있다. 메모리에서 PE 헤더 바로 뒤에는 IMAGE_SECTION_HEADER의 배열이 오게 된다. 배열 항목의 갯수는 PE 헤더에서 알 수 있다. (IMAGE_NT_HEADER.FileHeader.NumberOfSections 필드) 섹션 테이블과 모든 섹션 필드와 속성을 출력하기 위해서 PEDUMP를 사용했다. 그림 5는 PEDUMP의 보편적인 EXE 파일의 섹션 테이블 출력 결과를 보여주고, 그림 6은 OBJ 파일의 섹션 테이블을 보여준다.
Table 4. A Typical Section Table from an EXE File
01 .text VirtSize: 00005AFA VirtAddr: 00001000 raw data offs: 00000400 raw data size: 00005C00 relocation offs: 00000000 relocations: 00000000 line # offs: 00009220 line #'s: 0000020C characteristics: 60000020 CODE MEM_EXECUTE MEM_READ 02 .bss VirtSize: 00001438 VirtAddr: 00007000 raw data offs: 00000000 raw data size: 00001600 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: C0000080 UNINITIALIZED_DATA MEM_READ MEM_WRITE 03 .rdata VirtSize: 0000015C VirtAddr: 00009000 raw data offs: 00006000 raw data size: 00000200 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: 40000040 INITIALIZED_DATA MEM_READ 04 .data VirtSize: 0000239C VirtAddr: 0000A000 raw data offs: 00006200 raw data size: 00002400 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: C0000040 INITIALIZED_DATA MEM_READ MEM_WRITE 05 .idata VirtSize: 0000033E VirtAddr: 0000D000 raw data offs: 00008600 raw data size: 00000400 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: C0000040 INITIALIZED_DATA MEM_READ MEM_WRITE 06 .reloc VirtSize: 000006CE VirtAddr: 0000E000 raw data offs: 00008A00 raw data size: 00000800 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: 42000040 INITIALIZED_DATA MEM_DISCARDABLE MEM_READ[/code] [color=red][b]Table 5. A Typical Section Table from an OBJ File [/b][/color]01 .drectve PhysAddr: 00000000 VirtAddr: 00000000 raw data offs: 000000DC raw data size: 00000026 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: 00100A00 LNK_INFO LNK_REMOVE 02 .debug$S PhysAddr: 00000026 VirtAddr: 00000000 raw data offs: 00000102 raw data size: 000016D0 relocation offs: 000017D2 relocations: 00000032 line # offs: 00000000 line #'s: 00000000 characteristics: 42100048 INITIALIZED_DATA MEM_DISCARDABLE MEM_READ 03 .data PhysAddr: 000016F6 VirtAddr: 00000000 raw data offs: 000019C6 raw data size: 00000D87 relocation offs: 0000274D relocations: 00000045 line # offs: 00000000 line #'s: 00000000 characteristics: C0400040 INITIALIZED_DATA MEM_READ MEM_WRITE 04 .text PhysAddr: 0000247D VirtAddr: 00000000 raw data offs: 000029FF raw data size: 000010DA relocation offs: 00003AD9 relocations: 000000E9 line # offs: 000043F3 line #'s: 000000D9 characteristics: 60500020 CODE MEM_EXECUTE MEM_READ 05 .debug$T PhysAddr: 00003557 VirtAddr: 00000000 raw data offs: 00004909 raw data size: 00000030 relocation offs: 00000000 relocations: 00000000 line # offs: 00000000 line #'s: 00000000 characteristics: 42100048 INITIALIZED_DATA MEM_DISCARDABLE MEM_READ각각의 IMAGE_SECTION_HEADER는 그림 7에서 묘사된 것과 같은 포맷을 가지고 있다. 각각의 섹션을 위해서 저장된 정보중에 무엇이 빠졌는지 알아내는 것은 흥미로운 작업이다. 첫째로, PRELOAD 속성을 위한 어떤 표시도 없다는 점이다. NE 파일 포맷은 PRELOAD 속성을 통해서 어떠한 세그먼트가 모듈이 로드되는 시점에 같이 로드되어야 하는지 결정한다.Os/2 2.0 LX 포맷은 8페이지까지 먼저 로드되어야 하는 것으로 지정할 수 있다는 점에서 유사하다. PE 포맷은 이런 유사한 것이 아무것도 없다. 마이크로소프트는 Win32 의존적인 페이지 로딩의 성능을 확신했음에 틀림없다.
Table 6. IMAGE_SECTION_HEADER 포맷BYTE Name[IMAGE_SIZEOF_SHORT_NAME] 이것은 8바이트 안시로된 섹션 이름이다(유니코드가 아니다). 대부분의 섹션명은 .로 시작된다. (예를들면 ".text"), 그러나 몇몇 믿을만한 PE 문서에서 보면 이것은 요구사항은 아니다. 어셈블리 언어에서는 segment 지시자를 사용해서 섹션명을 지을 수 있고, 마이크로소프트의 C/C++ 컴파일러에서는 "#pragma data_seg"와 "#pragama code_seg"를 사용해서 지을 수 있다. 섹션명이 8바이트를 넘을 경우에는 NULL 종료 문자가 없게 된다는 것을 알아야 한다. 만약 devotee라는 섹션명을 출력코자 할 경우에는, %.8s를 사용해서 추가로 다른 버퍼에 복사하지 않고 출력할 수 있다.
union { DWORD PhysicalAddress DWORD VirtualSize } Misc;이 필드는 EXE와 OBJ 파일에서 다른 의미를 지니게 된다. EXE파일에서는, 이 필드는 코드와 데이터의 실제 사이즈를 가지고 있다. 이것은 파일 정렬 경계의 배수근처에서 반올림 되기전의 크기가 된다. 추후에 설명될 구조체의 SizeOfRawData 필드는 (약간 잘못된 명칭으로 보인다) 반올림된 값을 가지고 있다. 볼랜드 링커는 이 두 필드의 의미를 역으로 만들었으나 지금은 고쳐진 것으로 보인다. OBJ 파일에서는, 이 필드는 섹션의 물리적인 주소와 관련되어 있다. 첫번째 섹션은 0번지에서 시작한다. 따라서 OBJ 파일에서 다음 섹션의 물리적인 주소를 찾으려면, SizeOfRawData 값에 현재 섹션의 물리 주소를 더하면 된다.
DWORD VirtualAddress
EXE 파일에서는 로더가 섹션을 맵핑해야 하는 곳의 RVA를 저장하고 있다. 메모리에서 주어진 섹션의 실제 시작 주소를 계산하기 위해서는, 이미지의 베이스 주소에 이 필드에 저장된 섹션의 가상 주소를 더해주면 된다. 마이크로소프트 툴에서는 첫번째 섹션의 기본값은 0x1000 RVA로 되어 있다. OBJ 파일에서는 이 필드는 의미가 없으며 0으로 설정되어 있다.
DWORD SizeOfRawData
EXE 파일에서는, 이 필드는 파일 정렬 크기에서 반올림 된 후 섹션의 크기를 담고 있다. 예를 들면, 파일 정렬 크기가 0x200이라고 가정해 보자. 위에서 언급한 그 섹션에 대한 VirtualSize가 0x35A 바이트였다고 한다면, 이 필드는 0x400 바이트가 되는 것이다. OBJ 파일에서는, 이 필드는 컴파일러와 어셈블러에서 종결한 그 섹션의 정확한 크기를 담고 있다. 다시말하면, OBJ에서는 EXE 파일에서의 VirtualSize와 동일한 의미를 가진다는 것이다.
DWORD PointerToRawData
이 것은 컴파일러나 어셈블러가 종결한 바이너리 데이터를 찾을 수 있는 곳에 대한 파일 기반의 오프셋이다. 프로그램이 PE나 COFF 파일을 스스로 메모리 맵하려고 한다면(운영체제가 그것을 로드하는 대신에), 이 필드는 VIrtualAddress 필드보다 더 중요하다. 이 상황에서는 완전히 선형적인 파일 맵핑이 이루어지게 된다. 따라서 섹션 데이터를 VritaulAddress 필드가 가리키는 RVA에서 보다는 이 필드가 가리키는 오프셋에서 찾을 수 있다.
DWORD PointerToRelocations
OBJ 파일에서, 이것은 이 섹션에 대한 재배치 정보를 가리키는 파일 기반의 오프셋이다. 각각의 OBJ 섹션에 대한 재배치 정보는 해당 섹션에 대한 바이너리 데이터 바로 뒤에 따라온다. EXE 파일에서, 이 필드는 (아래에 나오는 필드또한) 의미가 없으며, 0으로 설정된다. 링커가 EXE파일을 만들때, 베이스 주소 재배치와 로드 타임에 해결되어야 할 임포트된 함수를 남겨둔 나머지 대부분의 수정 사항을 모두 수정한다. 베이스 주소 재배치와 임포트된 함수와 관련된 정보는 각각의 섹션에 저장되게 된다. 따라서 EXE 파일이 바이너리 섹션 데이터에 따라 나오는 섹션별 재배치 데이터를 가질 필요가 없는 것이다.
DWORD PointerToLinenumbers
이것은 라인 번호 테이블의 파일 기반 오프셋이다. 라인 번호 테이블은 소스 파일의 라인 번호와 주어진 라인에 대해서 생성된 코드의 주소를 서로 연관시킨다. CodeView 포맷과 같은 현대의 디버그 포맷에서는, 라인 번호 정보는 디버그 정보의 일부로 저장된다. 그러나 COFF 디버그 포맷에서는 라인 번호 정보는 심볼 이름/타입 정보와 분리되어서 저장된다. 일반적으로 단지 코드 섹션(.text같은)만이 라인 번호를 가진다. EXE 파일에서는, 라인 번호는 섹션 바이너리 데이터 다음부터 파일 끝까지 수집되게 된다. OBJ 파일에서는, 섹션의 라인 번호 테이블은 바이너리 섹션 데이터와 섹션 재배치 테이블 다음에 오게 된다.
WORD NumberOfRelocations
섹션에 포함된 재배치 테이블(위의 PointerToRelocations 필드) 안의 재배치 갯수. 이 필드는 단지 OBJ 파일에서만 유효한 것으로 보인다.
WORD NumberOfLinenumbers
섹션 라인 번호 테이블(위에서 말한 PointerToLinenumbers)에서 라인 번호 갯수
DWORD Characteristics
대부분의 프로그래머가 플래그라 부르는 것을 COFF/PE 포맷에서는 속성(characteristics)라 부른다. 이 필드는 섹션 속성과 관련된 플래그 집합(코드/데이터냐?, 읽기가능? 쓰기가능?)이다. 모든 가능한 섹션 속성은 WNNT.H에서 IMAGE_SCN_XXX_XXX형태로 #define 된 것으로 찾을 수 있다. 몇가지 중요한 속성으로 다음과 같은 것들이 있다.
-
0x00000020 이 섹션은 코드를 포함하고 있다. 일반적으로 실행 가능 플래그(0x80000000)와 결합해서 사용된다.
-
0x00000040 이 섹션은 초기화된 데이터를 포함하고 있다. 실행 가능하지않은 거의 대부분의 섹션과 .bss 섹션은 이 플래그가 설정되어져 있다.
-
0x00000080 이 섹션은 초기화되지 않은 데이터를 포함하고 있다(예를들면 .bss 섹션).
-
0x00000200 이 섹션은 코멘트나 다른 타입의 정보를 포함하고 있다. 이 플래그를 사용하는 일반적인 섹션은 컴파일러에 의해서 선언된 .drective 섹션이다. .directive 섹션은 링커를 위한 커맨드를 포함하고 있다.
-
0x00000800 이 섹션의 내용은 EXE 파일에는 담겨서는 안된다. 이 섹션들은 컴파일러와/어셈블러가 링커에게 정보를 전달하기 위해서 사용한다.
-
0x02000000 이 섹션은 프로세스가 한번 로드되고 나면 더 이상 필요하지 않기 때문에 무시될 수 있다. 대부분의 무시될 수 있는 것은 베이스 재배치(.reloc) 섹션이다.
-
0x10000000 이 섹션은 공유가능하다. DLL과 함께 사용될때, 이 섹션에 포함된 데이터는 DLL을 사용하는 프로세스 간에 공유될 수 있다. 데이터 섹션의 기본값은 공유하지 않는(nonshared) 이다. DLL을 사용하는 각각의 프로세스는 섹션에 포함된 데이터의 자신만의 복사본을 가진다는 의미이다. 좀더 기술적인 용어로 설명하면, 공유 섹션은 메모리 매니저에게 이 섹션의 페이지 맵핑을 DLL을 사용하는 모든 프로세스가 메모리내의 동일한 물리적 페이지를 참조하도록 설정하는 것이다. 섹션을 공유가능하도록 만들기 위해서, SHARED 속성을 링크 타임에 사용할 수 있다. 예를들면,
LINK /SECTION:MYDATA,RWS ...
링커에게 MYDATA라는 섹션은 읽기, 쓰기, 공유가 가능하다고 알려주는 것이다.
-
0x20000000 이 섹션은 실행가능하다. 이 플래그는 보통 "코드 포함" 플래그 (0x00000020)가 설정될때마다 설정된다.
-
0x40000000 이 섹션은 읽기 가능하다. 이 플래는 EXE 파일내에 포함된 거의 모든 섹션에 대해서 설정된다.
-
0x80000000 이 섹션은 쓰기 가능하다. 만약 EXE 파일의 섹션에 이 플래그가 설정되어 있지 않다면, 로더는 메모리 맵 페이지를 읽기 전용 내지는 실행 전용으로 마크한다. 일반적으로 이 속성을 가진 섹션은 .data와 .bss다. 흥미롭게도, .idata 섹션은 또한 이 속성을 설정하고 있다.
또한 PE 포맷에서 제외된것으로 페이지 테이블이 있다. LX 포맷의 IMAGE_SECTION_HEADER에 대한 OS/2의 동치는 파일에서 발견될 수 있는 코드나 데이터 섹션이 있는 곳을 직접적으로 가리키진 않는다. 대신에 그것은 섹션내에 있는 페이지의 구체적인 범위의 위치와 속성을 가지고 있는 페이지 룩업 테이블을 참조한다. PE 포맷은 그러한 모든 것들을 하지않아도 되게 한다. 그리고 섹션 데이터가 파일내에서 연속적으로 저장되도록 보장한다. 두가지 포맷에서, LX가 취하는 방법은 유연성을 허용한다. 그러나 PE 스타일은 작업하기가 더욱 간단하고 쉽다. 두가지 포맷을 위한 파일 덤퍼를 작성해야 할때, 나는 이것을 보장할 수 있다.
PE 포맷에서 좋아진 또다른 점으로 저장된 아이템의 위치가 간단하게 DWORD 오프셋이라는 것을 들 수 있다. NE 포맷에서는, 거의 대부분의 위치는 섹터 값으로 저장되어 진다. 실제 오프셋을 찾기 위해서 첫째로 NE 헤더의 정렬 유닛 크기를 보고 그것을 섹터 크기로 변환해야 한다. (일반적으로 16내지는 512 바이트) 그리고 나서는 실제 파일 오프셋을 구하기 위해서 섹터 크기에 지정된 섹터 오프셋을 곱할 필요가 있다. NE 파일에서 섹터 오프셋으로 저장되어져 있지 않은 어떤것이 있다면, 그것은 아마도 NE 헤더부터의 상대 오프셋으로 저장된 것이다. NE 헤더가 파일의 시작 부분에 있지 않기 때문에, 코드에서 NE 헤더의 파일 오프셋을 사용해야 할 필요가 있다. 대체로, PE 포맷은 NE, LX내지는 LE 포맷보다 다루기가 쉽다(메모리 맵 파일을 사용할 수 있다는 가정하에서)
- 트레이로 내려가는 애니메이션 출력 (0)2007/01/02
- XP 프로그램 호환성 정보 얻기 (0)2007/01/02
- PE 포맷 분석3 (0)2007/01/02
- PE 포맷 분석2 (0)2007/01/02
- PE 포맷 분석1
[color=red][b]Table 5. A Typical Section Table from an OBJ File [/b][/color]
[code]01 .drectve PhysAddr: 00000000 VirtAddr: 00000000
raw data offs: 000000DC raw data size: 00000026
relocation offs: 00000000 relocations: 00000000
line # offs: 00000000 line #'s: 00000000
characteristics: 00100A00
LNK_INFO LNK_REMOVE
02 .debug$S PhysAddr: 00000026 VirtAddr: 00000000
raw data offs: 00000102 raw data size: 000016D0
relocation offs: 000017D2 relocations: 00000032
line # offs: 00000000 line #'s: 00000000
characteristics: 42100048
INITIALIZED_DATA MEM_DISCARDABLE MEM_READ
03 .data PhysAddr: 000016F6 VirtAddr: 00000000
raw data offs: 000019C6 raw data size: 00000D87
relocation offs: 0000274D relocations: 00000045
line # offs: 00000000 line #'s: 00000000
characteristics: C0400040
INITIALIZED_DATA MEM_READ MEM_WRITE
04 .text PhysAddr: 0000247D VirtAddr: 00000000
raw data offs: 000029FF raw data size: 000010DA
relocation offs: 00003AD9 relocations: 000000E9
line # offs: 000043F3 line #'s: 000000D9
characteristics: 60500020
CODE MEM_EXECUTE MEM_READ
05 .debug$T PhysAddr: 00003557 VirtAddr: 00000000
raw data offs: 00004909 raw data size: 00000030
relocation offs: 00000000 relocations: 00000000
line # offs: 00000000 line #'s: 00000000
characteristics: 42100048
INITIALIZED_DATA MEM_DISCARDABLE MEM_READ
각각의 IMAGE_SECTION_HEADER는 그림 7에서 묘사된 것과 같은 포맷을 가지고 있다. 각각의 섹션을 위해서 저장된 정보중에 무엇이 빠졌는지 알아내는 것은 흥미로운 작업이다. 첫째로, PRELOAD 속성을 위한 어떤 표시도 없다는 점이다. NE 파일 포맷은 PRELOAD 속성을 통해서 어떠한 세그먼트가 모듈이 로드되는 시점에 같이 로드되어야 하는지 결정한다.Os/2 2.0 LX 포맷은 8페이지까지 먼저 로드되어야 하는 것으로 지정할 수 있다는 점에서 유사하다. PE 포맷은 이런 유사한 것이 아무것도 없다. 마이크로소프트는 Win32 의존적인 페이지 로딩의 성능을 확신했음에 틀림없다.
Table 6. IMAGE_SECTION_HEADER 포맷BYTE Name[IMAGE_SIZEOF_SHORT_NAME] 이것은 8바이트 안시로된 섹션 이름이다(유니코드가 아니다). 대부분의 섹션명은 .로 시작된다. (예를들면 ".text"), 그러나 몇몇 믿을만한 PE 문서에서 보면 이것은 요구사항은 아니다. 어셈블리 언어에서는 segment 지시자를 사용해서 섹션명을 지을 수 있고, 마이크로소프트의 C/C++ 컴파일러에서는 "#pragma data_seg"와 "#pragama code_seg"를 사용해서 지을 수 있다. 섹션명이 8바이트를 넘을 경우에는 NULL 종료 문자가 없게 된다는 것을 알아야 한다. 만약 devotee라는 섹션명을 출력코자 할 경우에는, %.8s를 사용해서 추가로 다른 버퍼에 복사하지 않고 출력할 수 있다.
union { DWORD PhysicalAddress DWORD VirtualSize } Misc;이 필드는 EXE와 OBJ 파일에서 다른 의미를 지니게 된다. EXE파일에서는, 이 필드는 코드와 데이터의 실제 사이즈를 가지고 있다. 이것은 파일 정렬 경계의 배수근처에서 반올림 되기전의 크기가 된다. 추후에 설명될 구조체의 SizeOfRawData 필드는 (약간 잘못된 명칭으로 보인다) 반올림된 값을 가지고 있다. 볼랜드 링커는 이 두 필드의 의미를 역으로 만들었으나 지금은 고쳐진 것으로 보인다. OBJ 파일에서는, 이 필드는 섹션의 물리적인 주소와 관련되어 있다. 첫번째 섹션은 0번지에서 시작한다. 따라서 OBJ 파일에서 다음 섹션의 물리적인 주소를 찾으려면, SizeOfRawData 값에 현재 섹션의 물리 주소를 더하면 된다.
DWORD VirtualAddress
EXE 파일에서는 로더가 섹션을 맵핑해야 하는 곳의 RVA를 저장하고 있다. 메모리에서 주어진 섹션의 실제 시작 주소를 계산하기 위해서는, 이미지의 베이스 주소에 이 필드에 저장된 섹션의 가상 주소를 더해주면 된다. 마이크로소프트 툴에서는 첫번째 섹션의 기본값은 0x1000 RVA로 되어 있다. OBJ 파일에서는 이 필드는 의미가 없으며 0으로 설정되어 있다.
DWORD SizeOfRawData
EXE 파일에서는, 이 필드는 파일 정렬 크기에서 반올림 된 후 섹션의 크기를 담고 있다. 예를 들면, 파일 정렬 크기가 0x200이라고 가정해 보자. 위에서 언급한 그 섹션에 대한 VirtualSize가 0x35A 바이트였다고 한다면, 이 필드는 0x400 바이트가 되는 것이다. OBJ 파일에서는, 이 필드는 컴파일러와 어셈블러에서 종결한 그 섹션의 정확한 크기를 담고 있다. 다시말하면, OBJ에서는 EXE 파일에서의 VirtualSize와 동일한 의미를 가진다는 것이다.
DWORD PointerToRawData
이 것은 컴파일러나 어셈블러가 종결한 바이너리 데이터를 찾을 수 있는 곳에 대한 파일 기반의 오프셋이다. 프로그램이 PE나 COFF 파일을 스스로 메모리 맵하려고 한다면(운영체제가 그것을 로드하는 대신에), 이 필드는 VIrtualAddress 필드보다 더 중요하다. 이 상황에서는 완전히 선형적인 파일 맵핑이 이루어지게 된다. 따라서 섹션 데이터를 VritaulAddress 필드가 가리키는 RVA에서 보다는 이 필드가 가리키는 오프셋에서 찾을 수 있다.
DWORD PointerToRelocations
OBJ 파일에서, 이것은 이 섹션에 대한 재배치 정보를 가리키는 파일 기반의 오프셋이다. 각각의 OBJ 섹션에 대한 재배치 정보는 해당 섹션에 대한 바이너리 데이터 바로 뒤에 따라온다. EXE 파일에서, 이 필드는 (아래에 나오는 필드또한) 의미가 없으며, 0으로 설정된다. 링커가 EXE파일을 만들때, 베이스 주소 재배치와 로드 타임에 해결되어야 할 임포트된 함수를 남겨둔 나머지 대부분의 수정 사항을 모두 수정한다. 베이스 주소 재배치와 임포트된 함수와 관련된 정보는 각각의 섹션에 저장되게 된다. 따라서 EXE 파일이 바이너리 섹션 데이터에 따라 나오는 섹션별 재배치 데이터를 가질 필요가 없는 것이다.
DWORD PointerToLinenumbers
이것은 라인 번호 테이블의 파일 기반 오프셋이다. 라인 번호 테이블은 소스 파일의 라인 번호와 주어진 라인에 대해서 생성된 코드의 주소를 서로 연관시킨다. CodeView 포맷과 같은 현대의 디버그 포맷에서는, 라인 번호 정보는 디버그 정보의 일부로 저장된다. 그러나 COFF 디버그 포맷에서는 라인 번호 정보는 심볼 이름/타입 정보와 분리되어서 저장된다. 일반적으로 단지 코드 섹션(.text같은)만이 라인 번호를 가진다. EXE 파일에서는, 라인 번호는 섹션 바이너리 데이터 다음부터 파일 끝까지 수집되게 된다. OBJ 파일에서는, 섹션의 라인 번호 테이블은 바이너리 섹션 데이터와 섹션 재배치 테이블 다음에 오게 된다.
WORD NumberOfRelocations
섹션에 포함된 재배치 테이블(위의 PointerToRelocations 필드) 안의 재배치 갯수. 이 필드는 단지 OBJ 파일에서만 유효한 것으로 보인다.
WORD NumberOfLinenumbers
섹션 라인 번호 테이블(위에서 말한 PointerToLinenumbers)에서 라인 번호 갯수
DWORD Characteristics
대부분의 프로그래머가 플래그라 부르는 것을 COFF/PE 포맷에서는 속성(characteristics)라 부른다. 이 필드는 섹션 속성과 관련된 플래그 집합(코드/데이터냐?, 읽기가능? 쓰기가능?)이다. 모든 가능한 섹션 속성은 WNNT.H에서 IMAGE_SCN_XXX_XXX형태로 #define 된 것으로 찾을 수 있다. 몇가지 중요한 속성으로 다음과 같은 것들이 있다.
-
0x00000020 이 섹션은 코드를 포함하고 있다. 일반적으로 실행 가능 플래그(0x80000000)와 결합해서 사용된다.
-
0x00000040 이 섹션은 초기화된 데이터를 포함하고 있다. 실행 가능하지않은 거의 대부분의 섹션과 .bss 섹션은 이 플래그가 설정되어져 있다.
-
0x00000080 이 섹션은 초기화되지 않은 데이터를 포함하고 있다(예를들면 .bss 섹션).
-
0x00000200 이 섹션은 코멘트나 다른 타입의 정보를 포함하고 있다. 이 플래그를 사용하는 일반적인 섹션은 컴파일러에 의해서 선언된 .drective 섹션이다. .directive 섹션은 링커를 위한 커맨드를 포함하고 있다.
-
0x00000800 이 섹션의 내용은 EXE 파일에는 담겨서는 안된다. 이 섹션들은 컴파일러와/어셈블러가 링커에게 정보를 전달하기 위해서 사용한다.
-
0x02000000 이 섹션은 프로세스가 한번 로드되고 나면 더 이상 필요하지 않기 때문에 무시될 수 있다. 대부분의 무시될 수 있는 것은 베이스 재배치(.reloc) 섹션이다.
-
0x10000000 이 섹션은 공유가능하다. DLL과 함께 사용될때, 이 섹션에 포함된 데이터는 DLL을 사용하는 프로세스 간에 공유될 수 있다. 데이터 섹션의 기본값은 공유하지 않는(nonshared) 이다. DLL을 사용하는 각각의 프로세스는 섹션에 포함된 데이터의 자신만의 복사본을 가진다는 의미이다. 좀더 기술적인 용어로 설명하면, 공유 섹션은 메모리 매니저에게 이 섹션의 페이지 맵핑을 DLL을 사용하는 모든 프로세스가 메모리내의 동일한 물리적 페이지를 참조하도록 설정하는 것이다. 섹션을 공유가능하도록 만들기 위해서, SHARED 속성을 링크 타임에 사용할 수 있다. 예를들면,
LINK /SECTION:MYDATA,RWS ...
링커에게 MYDATA라는 섹션은 읽기, 쓰기, 공유가 가능하다고 알려주는 것이다.
-
0x20000000 이 섹션은 실행가능하다. 이 플래그는 보통 "코드 포함" 플래그 (0x00000020)가 설정될때마다 설정된다.
-
0x40000000 이 섹션은 읽기 가능하다. 이 플래는 EXE 파일내에 포함된 거의 모든 섹션에 대해서 설정된다.
-
0x80000000 이 섹션은 쓰기 가능하다. 만약 EXE 파일의 섹션에 이 플래그가 설정되어 있지 않다면, 로더는 메모리 맵 페이지를 읽기 전용 내지는 실행 전용으로 마크한다. 일반적으로 이 속성을 가진 섹션은 .data와 .bss다. 흥미롭게도, .idata 섹션은 또한 이 속성을 설정하고 있다.
또한 PE 포맷에서 제외된것으로 페이지 테이블이 있다. LX 포맷의 IMAGE_SECTION_HEADER에 대한 OS/2의 동치는 파일에서 발견될 수 있는 코드나 데이터 섹션이 있는 곳을 직접적으로 가리키진 않는다. 대신에 그것은 섹션내에 있는 페이지의 구체적인 범위의 위치와 속성을 가지고 있는 페이지 룩업 테이블을 참조한다. PE 포맷은 그러한 모든 것들을 하지않아도 되게 한다. 그리고 섹션 데이터가 파일내에서 연속적으로 저장되도록 보장한다. 두가지 포맷에서, LX가 취하는 방법은 유연성을 허용한다. 그러나 PE 스타일은 작업하기가 더욱 간단하고 쉽다. 두가지 포맷을 위한 파일 덤퍼를 작성해야 할때, 나는 이것을 보장할 수 있다.
PE 포맷에서 좋아진 또다른 점으로 저장된 아이템의 위치가 간단하게 DWORD 오프셋이라는 것을 들 수 있다. NE 포맷에서는, 거의 대부분의 위치는 섹터 값으로 저장되어 진다. 실제 오프셋을 찾기 위해서 첫째로 NE 헤더의 정렬 유닛 크기를 보고 그것을 섹터 크기로 변환해야 한다. (일반적으로 16내지는 512 바이트) 그리고 나서는 실제 파일 오프셋을 구하기 위해서 섹터 크기에 지정된 섹터 오프셋을 곱할 필요가 있다. NE 파일에서 섹터 오프셋으로 저장되어져 있지 않은 어떤것이 있다면, 그것은 아마도 NE 헤더부터의 상대 오프셋으로 저장된 것이다. NE 헤더가 파일의 시작 부분에 있지 않기 때문에, 코드에서 NE 헤더의 파일 오프셋을 사용해야 할 필요가 있다. 대체로, PE 포맷은 NE, LX내지는 LE 포맷보다 다루기가 쉽다(메모리 맵 파일을 사용할 수 있다는 가정하에서)
"Win32 API" 카테고리의 다른 글- 트레이로 내려가는 애니메이션 출력 (0)2007/01/02
- XP 프로그램 호환성 정보 얻기 (0)2007/01/02
- PE 포맷 분석3 (0)2007/01/02
- PE 포맷 분석2 (0)2007/01/02
- PE 포맷 분석1 (0)2007/01/02
-

수안이의 컴퓨터 연구실



Leave your greetings.