2 Copyright (C) 2009 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using BYTE = System.Byte;
26 using WORD = System.UInt16;
27 using DWORD = System.UInt32;
28 using ULONGLONG = System.UInt64;
31 namespace IKVM.Reflection.Reader
33 sealed class MSDOS_HEADER
35 internal const WORD MAGIC_MZ = 0x5A4D;
37 internal WORD signature; // 'MZ'
39 internal DWORD peSignatureOffset;
42 sealed class IMAGE_NT_HEADERS
44 public const DWORD MAGIC_SIGNATURE = 0x00004550; // "PE\0\0"
46 public DWORD Signature;
47 public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
48 public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
50 internal void Read(BinaryReader br)
52 Signature = br.ReadUInt32();
53 if (Signature != IMAGE_NT_HEADERS.MAGIC_SIGNATURE)
55 throw new BadImageFormatException();
58 OptionalHeader.Read(br);
62 sealed class IMAGE_FILE_HEADER
64 public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c;
65 public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200;
66 public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664;
68 public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100;
69 public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
70 public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
71 public const WORD IMAGE_FILE_DLL = 0x2000;
74 public WORD NumberOfSections;
75 public DWORD TimeDateStamp;
76 public DWORD PointerToSymbolTable;
77 public DWORD NumberOfSymbols;
78 public WORD SizeOfOptionalHeader;
79 public WORD Characteristics;
81 internal void Read(BinaryReader br)
83 Machine = br.ReadUInt16();
84 NumberOfSections = br.ReadUInt16();
85 TimeDateStamp = br.ReadUInt32();
86 PointerToSymbolTable = br.ReadUInt32();
87 NumberOfSymbols = br.ReadUInt32();
88 SizeOfOptionalHeader = br.ReadUInt16();
89 Characteristics = br.ReadUInt16();
93 sealed class IMAGE_OPTIONAL_HEADER
95 public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
96 public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
98 public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2;
99 public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
102 public BYTE MajorLinkerVersion;
103 public BYTE MinorLinkerVersion;
104 public DWORD SizeOfCode;
105 public DWORD SizeOfInitializedData;
106 public DWORD SizeOfUninitializedData;
107 public DWORD AddressOfEntryPoint;
108 public DWORD BaseOfCode;
109 public DWORD BaseOfData;
110 public ULONGLONG ImageBase;
111 public DWORD SectionAlignment;
112 public DWORD FileAlignment;
113 public WORD MajorOperatingSystemVersion;
114 public WORD MinorOperatingSystemVersion;
115 public WORD MajorImageVersion;
116 public WORD MinorImageVersion;
117 public WORD MajorSubsystemVersion;
118 public WORD MinorSubsystemVersion;
119 public DWORD Win32VersionValue;
120 public DWORD SizeOfImage;
121 public DWORD SizeOfHeaders;
122 public DWORD CheckSum;
123 public WORD Subsystem;
124 public WORD DllCharacteristics;
125 public ULONGLONG SizeOfStackReserve;
126 public ULONGLONG SizeOfStackCommit;
127 public ULONGLONG SizeOfHeapReserve;
128 public ULONGLONG SizeOfHeapCommit;
129 public DWORD LoaderFlags;
130 public DWORD NumberOfRvaAndSizes;
131 public IMAGE_DATA_DIRECTORY[] DataDirectory;
133 internal void Read(BinaryReader br)
135 Magic = br.ReadUInt16();
136 if (Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
138 throw new BadImageFormatException();
140 MajorLinkerVersion = br.ReadByte();
141 MinorLinkerVersion = br.ReadByte();
142 SizeOfCode = br.ReadUInt32();
143 SizeOfInitializedData = br.ReadUInt32();
144 SizeOfUninitializedData = br.ReadUInt32();
145 AddressOfEntryPoint = br.ReadUInt32();
146 BaseOfCode = br.ReadUInt32();
147 if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
149 BaseOfData = br.ReadUInt32();
150 ImageBase = br.ReadUInt32();
154 ImageBase = br.ReadUInt64();
156 SectionAlignment = br.ReadUInt32();
157 FileAlignment = br.ReadUInt32();
158 MajorOperatingSystemVersion = br.ReadUInt16();
159 MinorOperatingSystemVersion = br.ReadUInt16();
160 MajorImageVersion = br.ReadUInt16();
161 MinorImageVersion = br.ReadUInt16();
162 MajorSubsystemVersion = br.ReadUInt16();
163 MinorSubsystemVersion = br.ReadUInt16();
164 Win32VersionValue = br.ReadUInt32();
165 SizeOfImage = br.ReadUInt32();
166 SizeOfHeaders = br.ReadUInt32();
167 CheckSum = br.ReadUInt32();
168 Subsystem = br.ReadUInt16();
169 DllCharacteristics = br.ReadUInt16();
170 if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
172 SizeOfStackReserve = br.ReadUInt32();
173 SizeOfStackCommit = br.ReadUInt32();
174 SizeOfHeapReserve = br.ReadUInt32();
175 SizeOfHeapCommit = br.ReadUInt32();
179 SizeOfStackReserve = br.ReadUInt64();
180 SizeOfStackCommit = br.ReadUInt64();
181 SizeOfHeapReserve = br.ReadUInt64();
182 SizeOfHeapCommit = br.ReadUInt64();
184 LoaderFlags = br.ReadUInt32();
185 NumberOfRvaAndSizes = br.ReadUInt32();
186 DataDirectory = new IMAGE_DATA_DIRECTORY[NumberOfRvaAndSizes];
187 for (uint i = 0; i < NumberOfRvaAndSizes; i++)
189 DataDirectory[i] = new IMAGE_DATA_DIRECTORY();
190 DataDirectory[i].Read(br);
195 struct IMAGE_DATA_DIRECTORY
197 public DWORD VirtualAddress;
200 internal void Read(BinaryReader br)
202 VirtualAddress = br.ReadUInt32();
203 Size = br.ReadUInt32();
206 internal void Write(IKVM.Reflection.Writer.MetadataWriter mw)
208 mw.Write(VirtualAddress);
215 public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020;
216 public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
217 public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
218 public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000;
219 public const DWORD IMAGE_SCN_MEM_READ = 0x40000000;
220 public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000;
222 public string Name; // 8 byte UTF8 encoded 0-padded
223 public DWORD VirtualSize;
224 public DWORD VirtualAddress;
225 public DWORD SizeOfRawData;
226 public DWORD PointerToRawData;
227 public DWORD PointerToRelocations;
228 public DWORD PointerToLinenumbers;
229 public WORD NumberOfRelocations;
230 public WORD NumberOfLinenumbers;
231 public DWORD Characteristics;
233 internal void Read(BinaryReader br)
235 char[] name = new char[8];
237 for (int i = 0; i < 8; i++)
239 byte b = br.ReadByte();
241 if (b == 0 && len == 8)
246 Name = new String(name, 0, len);
247 VirtualSize = br.ReadUInt32();
248 VirtualAddress = br.ReadUInt32();
249 SizeOfRawData = br.ReadUInt32();
250 PointerToRawData = br.ReadUInt32();
251 PointerToRelocations = br.ReadUInt32();
252 PointerToLinenumbers = br.ReadUInt32();
253 NumberOfRelocations = br.ReadUInt16();
254 NumberOfLinenumbers = br.ReadUInt16();
255 Characteristics = br.ReadUInt32();
259 sealed class PEReader
261 private MSDOS_HEADER msdos = new MSDOS_HEADER();
262 private IMAGE_NT_HEADERS headers = new IMAGE_NT_HEADERS();
263 private SectionHeader[] sections;
265 internal void Read(BinaryReader br)
267 msdos.signature = br.ReadUInt16();
268 br.BaseStream.Seek(58, SeekOrigin.Current);
269 msdos.peSignatureOffset = br.ReadUInt32();
271 if (msdos.signature != MSDOS_HEADER.MAGIC_MZ)
273 throw new BadImageFormatException();
276 br.BaseStream.Seek(msdos.peSignatureOffset, SeekOrigin.Begin);
278 sections = new SectionHeader[headers.FileHeader.NumberOfSections];
279 for (int i = 0; i < sections.Length; i++)
281 sections[i] = new SectionHeader();
282 sections[i].Read(br);
286 internal IMAGE_FILE_HEADER FileHeader
288 get { return headers.FileHeader; }
291 internal IMAGE_OPTIONAL_HEADER OptionalHeader
293 get { return headers.OptionalHeader; }
296 internal DWORD GetComDescriptorVirtualAddress()
298 return headers.OptionalHeader.DataDirectory[14].VirtualAddress;
301 internal void GetDataDirectoryEntry(int index, out int rva, out int length)
303 rva = (int)headers.OptionalHeader.DataDirectory[index].VirtualAddress;
304 length = (int)headers.OptionalHeader.DataDirectory[index].Size;
307 internal long RvaToFileOffset(DWORD rva)
309 for (int i = 0; i < sections.Length; i++)
311 if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].VirtualSize)
313 return sections[i].PointerToRawData + rva - sections[i].VirtualAddress;
316 throw new BadImageFormatException();
319 internal bool GetSectionInfo(int rva, out string name, out int characteristics)
321 for (int i = 0; i < sections.Length; i++)
323 if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].VirtualSize)
325 name = sections[i].Name;
326 characteristics = (int)sections[i].Characteristics;