1 /* 2 Copyright (C) 2009 Jeroen Frijters 3 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. 7 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: 11 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. 19 20 Jeroen Frijters 21 jeroen@frijters.net 22 23 */ 24 using System; 25 using BYTE = System.Byte; 26 using WORD = System.UInt16; 27 using DWORD = System.UInt32; 28 using ULONGLONG = System.UInt64; 29 using System.IO; 30 31 namespace IKVM.Reflection.Reader 32 { 33 sealed class MSDOS_HEADER 34 { 35 internal const WORD MAGIC_MZ = 0x5A4D; 36 37 internal WORD signature; // 'MZ' 38 // skip 58 bytes 39 internal DWORD peSignatureOffset; 40 } 41 42 sealed class IMAGE_NT_HEADERS 43 { 44 public const DWORD MAGIC_SIGNATURE = 0x00004550; // "PE\0\0" 45 46 public DWORD Signature; 47 public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER(); 48 public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER(); 49 Read(BinaryReader br)50 internal void Read(BinaryReader br) 51 { 52 Signature = br.ReadUInt32(); 53 if (Signature != IMAGE_NT_HEADERS.MAGIC_SIGNATURE) 54 { 55 throw new BadImageFormatException(); 56 } 57 FileHeader.Read(br); 58 long optionalHeaderPosition = br.BaseStream.Position; 59 OptionalHeader.Read(br); 60 if (br.BaseStream.Position > optionalHeaderPosition + FileHeader.SizeOfOptionalHeader) 61 { 62 throw new BadImageFormatException(); 63 } 64 br.BaseStream.Seek(optionalHeaderPosition + FileHeader.SizeOfOptionalHeader, SeekOrigin.Begin); 65 } 66 } 67 68 sealed class IMAGE_FILE_HEADER 69 { 70 public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c; 71 public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200; 72 public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664; 73 74 public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100; 75 public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002; 76 public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020; 77 public const WORD IMAGE_FILE_DLL = 0x2000; 78 79 public WORD Machine; 80 public WORD NumberOfSections; 81 public DWORD TimeDateStamp; 82 public DWORD PointerToSymbolTable; 83 public DWORD NumberOfSymbols; 84 public WORD SizeOfOptionalHeader; 85 public WORD Characteristics; 86 Read(BinaryReader br)87 internal void Read(BinaryReader br) 88 { 89 Machine = br.ReadUInt16(); 90 NumberOfSections = br.ReadUInt16(); 91 TimeDateStamp = br.ReadUInt32(); 92 PointerToSymbolTable = br.ReadUInt32(); 93 NumberOfSymbols = br.ReadUInt32(); 94 SizeOfOptionalHeader = br.ReadUInt16(); 95 Characteristics = br.ReadUInt16(); 96 } 97 } 98 99 sealed class IMAGE_OPTIONAL_HEADER 100 { 101 public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; 102 public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; 103 104 public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; 105 public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3; 106 107 public WORD Magic; 108 public BYTE MajorLinkerVersion; 109 public BYTE MinorLinkerVersion; 110 public DWORD SizeOfCode; 111 public DWORD SizeOfInitializedData; 112 public DWORD SizeOfUninitializedData; 113 public DWORD AddressOfEntryPoint; 114 public DWORD BaseOfCode; 115 public DWORD BaseOfData; 116 public ULONGLONG ImageBase; 117 public DWORD SectionAlignment; 118 public DWORD FileAlignment; 119 public WORD MajorOperatingSystemVersion; 120 public WORD MinorOperatingSystemVersion; 121 public WORD MajorImageVersion; 122 public WORD MinorImageVersion; 123 public WORD MajorSubsystemVersion; 124 public WORD MinorSubsystemVersion; 125 public DWORD Win32VersionValue; 126 public DWORD SizeOfImage; 127 public DWORD SizeOfHeaders; 128 public DWORD CheckSum; 129 public WORD Subsystem; 130 public WORD DllCharacteristics; 131 public ULONGLONG SizeOfStackReserve; 132 public ULONGLONG SizeOfStackCommit; 133 public ULONGLONG SizeOfHeapReserve; 134 public ULONGLONG SizeOfHeapCommit; 135 public DWORD LoaderFlags; 136 public DWORD NumberOfRvaAndSizes; 137 public IMAGE_DATA_DIRECTORY[] DataDirectory; 138 Read(BinaryReader br)139 internal void Read(BinaryReader br) 140 { 141 Magic = br.ReadUInt16(); 142 if (Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) 143 { 144 throw new BadImageFormatException(); 145 } 146 MajorLinkerVersion = br.ReadByte(); 147 MinorLinkerVersion = br.ReadByte(); 148 SizeOfCode = br.ReadUInt32(); 149 SizeOfInitializedData = br.ReadUInt32(); 150 SizeOfUninitializedData = br.ReadUInt32(); 151 AddressOfEntryPoint = br.ReadUInt32(); 152 BaseOfCode = br.ReadUInt32(); 153 if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) 154 { 155 BaseOfData = br.ReadUInt32(); 156 ImageBase = br.ReadUInt32(); 157 } 158 else 159 { 160 ImageBase = br.ReadUInt64(); 161 } 162 SectionAlignment = br.ReadUInt32(); 163 FileAlignment = br.ReadUInt32(); 164 MajorOperatingSystemVersion = br.ReadUInt16(); 165 MinorOperatingSystemVersion = br.ReadUInt16(); 166 MajorImageVersion = br.ReadUInt16(); 167 MinorImageVersion = br.ReadUInt16(); 168 MajorSubsystemVersion = br.ReadUInt16(); 169 MinorSubsystemVersion = br.ReadUInt16(); 170 Win32VersionValue = br.ReadUInt32(); 171 SizeOfImage = br.ReadUInt32(); 172 SizeOfHeaders = br.ReadUInt32(); 173 CheckSum = br.ReadUInt32(); 174 Subsystem = br.ReadUInt16(); 175 DllCharacteristics = br.ReadUInt16(); 176 if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) 177 { 178 SizeOfStackReserve = br.ReadUInt32(); 179 SizeOfStackCommit = br.ReadUInt32(); 180 SizeOfHeapReserve = br.ReadUInt32(); 181 SizeOfHeapCommit = br.ReadUInt32(); 182 } 183 else 184 { 185 SizeOfStackReserve = br.ReadUInt64(); 186 SizeOfStackCommit = br.ReadUInt64(); 187 SizeOfHeapReserve = br.ReadUInt64(); 188 SizeOfHeapCommit = br.ReadUInt64(); 189 } 190 LoaderFlags = br.ReadUInt32(); 191 NumberOfRvaAndSizes = br.ReadUInt32(); 192 DataDirectory = new IMAGE_DATA_DIRECTORY[NumberOfRvaAndSizes]; 193 for (uint i = 0; i < NumberOfRvaAndSizes; i++) 194 { 195 DataDirectory[i] = new IMAGE_DATA_DIRECTORY(); 196 DataDirectory[i].Read(br); 197 } 198 } 199 } 200 201 struct IMAGE_DATA_DIRECTORY 202 { 203 public DWORD VirtualAddress; 204 public DWORD Size; 205 ReadIKVM.Reflection.Reader.IMAGE_DATA_DIRECTORY206 internal void Read(BinaryReader br) 207 { 208 VirtualAddress = br.ReadUInt32(); 209 Size = br.ReadUInt32(); 210 } 211 } 212 213 class SectionHeader 214 { 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; 221 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; 232 Read(BinaryReader br)233 internal void Read(BinaryReader br) 234 { 235 char[] name = new char[8]; 236 int len = 8; 237 for (int i = 0; i < 8; i++) 238 { 239 byte b = br.ReadByte(); 240 name[i] = (char)b; 241 if (b == 0 && len == 8) 242 { 243 len = i; 244 } 245 } 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(); 256 } 257 } 258 259 sealed class PEReader 260 { 261 private MSDOS_HEADER msdos = new MSDOS_HEADER(); 262 private IMAGE_NT_HEADERS headers = new IMAGE_NT_HEADERS(); 263 private SectionHeader[] sections; 264 private bool mapped; 265 Read(BinaryReader br, bool mapped)266 internal void Read(BinaryReader br, bool mapped) 267 { 268 this.mapped = mapped; 269 msdos.signature = br.ReadUInt16(); 270 br.BaseStream.Seek(58, SeekOrigin.Current); 271 msdos.peSignatureOffset = br.ReadUInt32(); 272 273 if (msdos.signature != MSDOS_HEADER.MAGIC_MZ) 274 { 275 throw new BadImageFormatException(); 276 } 277 278 br.BaseStream.Seek(msdos.peSignatureOffset, SeekOrigin.Begin); 279 headers.Read(br); 280 sections = new SectionHeader[headers.FileHeader.NumberOfSections]; 281 for (int i = 0; i < sections.Length; i++) 282 { 283 sections[i] = new SectionHeader(); 284 sections[i].Read(br); 285 } 286 } 287 288 internal IMAGE_FILE_HEADER FileHeader 289 { 290 get { return headers.FileHeader; } 291 } 292 293 internal IMAGE_OPTIONAL_HEADER OptionalHeader 294 { 295 get { return headers.OptionalHeader; } 296 } 297 GetComDescriptorVirtualAddress()298 internal DWORD GetComDescriptorVirtualAddress() 299 { 300 return headers.OptionalHeader.DataDirectory[14].VirtualAddress; 301 } 302 GetDataDirectoryEntry(int index, out int rva, out int length)303 internal void GetDataDirectoryEntry(int index, out int rva, out int length) 304 { 305 rva = (int)headers.OptionalHeader.DataDirectory[index].VirtualAddress; 306 length = (int)headers.OptionalHeader.DataDirectory[index].Size; 307 } 308 RvaToFileOffset(DWORD rva)309 internal long RvaToFileOffset(DWORD rva) 310 { 311 if (mapped) 312 { 313 return rva; 314 } 315 for (int i = 0; i < sections.Length; i++) 316 { 317 if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].VirtualSize) 318 { 319 return sections[i].PointerToRawData + rva - sections[i].VirtualAddress; 320 } 321 } 322 throw new BadImageFormatException(); 323 } 324 GetSectionInfo(int rva, out string name, out int characteristics, out int virtualAddress, out int virtualSize, out int pointerToRawData, out int sizeOfRawData)325 internal bool GetSectionInfo(int rva, out string name, out int characteristics, out int virtualAddress, out int virtualSize, out int pointerToRawData, out int sizeOfRawData) 326 { 327 for (int i = 0; i < sections.Length; i++) 328 { 329 if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + sections[i].VirtualSize) 330 { 331 name = sections[i].Name; 332 characteristics = (int)sections[i].Characteristics; 333 virtualAddress = (int)sections[i].VirtualAddress; 334 virtualSize = (int)sections[i].VirtualSize; 335 pointerToRawData = (int)sections[i].PointerToRawData; 336 sizeOfRawData = (int)sections[i].SizeOfRawData; 337 return true; 338 } 339 } 340 name = null; 341 characteristics = 0; 342 virtualAddress = 0; 343 virtualSize = 0; 344 pointerToRawData = 0; 345 sizeOfRawData = 0; 346 return false; 347 } 348 } 349 } 350