/[RomCheater]/trunk/Win32/Sojaner.MemoryScanner/PEReader.cs
ViewVC logotype

Annotation of /trunk/Win32/Sojaner.MemoryScanner/PEReader.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 318 - (hide annotations) (download)
Tue Jun 5 17:57:37 2012 UTC (8 years, 11 months ago) by william
File size: 18273 byte(s)
+ add support for displaying PE Struct data into property grid (read-only)

1 william 299 #define ENABLE_LOGGING
2     using System;
3 william 159 using System.Collections.Generic;
4     using System.Linq;
5     using System.Text;
6     using System.IO;
7     using RomCheater.Logging;
8     using System.Runtime.InteropServices;
9     using System.Diagnostics;
10 william 318 using System.ComponentModel;
11 william 159
12     namespace Sojaner.MemoryScanner
13     {
14     public class PEReader
15     {
16 william 294 // Code (C) Sergey utilized from: http://www.sergeyakopov.com/2010/11/03/reading-pe-format-using-data-marshalling-in-net/
17     #region Structs
18 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
19 william 294 [StructLayout(LayoutKind.Sequential)]
20     public struct IMAGE_DOS_HEADER
21 william 290 {
22 william 318 public UInt16 _e_magic;
23     public UInt16 _e_cblp;
24     public UInt16 _e_cp;
25     public UInt16 _e_crlc;
26     public UInt16 _e_cparhdr;
27     public UInt16 _e_minalloc;
28     public UInt16 _e_maxalloc;
29     public UInt16 _e_ss;
30     public UInt16 _e_sp;
31     public UInt16 _e_csum;
32     public UInt16 _e_ip;
33     public UInt16 _e_cs;
34     public UInt16 _e_lfarlc;
35     public UInt16 _e_ovno;
36 william 294 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
37 william 318 public UInt16[] _e_res1;
38     public UInt16 _e_oemid;
39     public UInt16 _e_oeminfo;
40 william 294 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
41 william 318 public UInt16[] _e_res2;
42     public UInt32 _e_lfanew;
43    
44     public string e_magic { get { return string.Format("0x{0:x4}", _e_magic); } }
45     public string e_cblp { get { return string.Format("0x{0:x4}", _e_cblp); } }
46     public string e_cp { get { return string.Format("0x{0:x4}", _e_cp); } }
47     public string e_crlc { get { return string.Format("0x{0:x4}", _e_crlc); } }
48     public string e_cparhdr { get { return string.Format("0x{0:x4}", _e_cparhdr); } }
49     public string e_minalloc { get { return string.Format("0x{0:x4}", _e_minalloc); } }
50     public string e_maxalloc { get { return string.Format("0x{0:x4}", _e_maxalloc); } }
51     public string e_ss { get { return string.Format("0x{0:x4}", _e_ss); } }
52     public string e_sp { get { return string.Format("0x{0:x4}", _e_sp); } }
53     public string e_csum { get { return string.Format("0x{0:x4}", _e_csum); } }
54     public string e_ip { get { return string.Format("0x{0:x4}", _e_ip); } }
55     public string e_cs { get { return string.Format("0x{0:x4}", _e_cs); } }
56     public string e_lfarlc { get { return string.Format("0x{0:x4}", _e_lfarlc); } }
57     public string e_ovno { get { return string.Format("0x{0:x4}", _e_ovno); } }
58     public ushort[] e_res1 { get { return _e_res1; } }
59     public string e_oemid { get { return string.Format("0x{0:x4}", _e_oemid); } }
60     public string e_oeminfo { get { return string.Format("0x{0:x4}", _e_oeminfo); } }
61     public ushort[] e_res2 { get { return _e_res2; } }
62     public string e_lfanew { get { return string.Format("0x{0:x8}", _e_lfanew); } }
63    
64 william 290 }
65 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
66 william 294 [StructLayout(LayoutKind.Sequential)]
67     public struct IMAGE_NT_HEADERS
68 william 159 {
69 william 294 public UInt32 Signature;
70     public IMAGE_FILE_HEADER FileHeader;
71     public IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
72     public IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
73 william 159 }
74 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
75 william 159 [StructLayout(LayoutKind.Sequential)]
76     public struct IMAGE_FILE_HEADER
77     {
78 william 294 public UInt16 Machine;
79 william 159 public UInt16 NumberOfSections;
80     public UInt32 TimeDateStamp;
81     public UInt32 PointerToSymbolTable;
82     public UInt32 NumberOfSymbols;
83     public UInt16 SizeOfOptionalHeader;
84 william 294 public UInt16 Characteristics;
85 william 159 }
86 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
87 william 159 [StructLayout(LayoutKind.Sequential)]
88 william 294 public struct IMAGE_OPTIONAL_HEADER32
89 william 159 {
90 william 294 public UInt16 Magic;
91     public Byte MajorLinkerVersion;
92     public Byte MinorLinkerVersion;
93     public UInt32 SizeOfCode;
94     public UInt32 SizeOfInitializedData;
95     public UInt32 SizeOfUninitializedData;
96     public UInt32 AddressOfEntryPoint;
97     public UInt32 BaseOfCode;
98     public UInt32 BaseOfData;
99     public UInt32 ImageBase;
100     public UInt32 SectionAlignment;
101     public UInt32 FileAlignment;
102     public UInt16 MajorOperatingSystemVersion;
103     public UInt16 MinorOperatingSystemVersion;
104     public UInt16 MajorImageVersion;
105     public UInt16 MinorImageVersion;
106     public UInt16 MajorSubsystemVersion;
107     public UInt16 MinorSubsystemVersion;
108     public UInt32 Win32VersionValue;
109     public UInt32 SizeOfImage;
110     public UInt32 SizeOfHeaders;
111     public UInt32 CheckSum;
112     public UInt16 Subsystem;
113     public UInt16 DllCharacteristics;
114     public UInt32 SizeOfStackReserve;
115     public UInt32 SizeOfStackCommit;
116     public UInt32 SizeOfHeapReserve;
117     public UInt32 SizeOfHeapCommit;
118     public UInt32 LoaderFlags;
119     public UInt32 NumberOfRvaAndSizes;
120     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
121     public IMAGE_DATA_DIRECTORY[] DataDirectory;
122 william 159 }
123 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
124 william 294 [StructLayout(LayoutKind.Sequential)]
125     public struct IMAGE_OPTIONAL_HEADER64
126 william 159 {
127 william 294 public UInt16 Magic;
128     public Byte MajorLinkerVersion;
129     public Byte MinorLinkerVersion;
130     public UInt32 SizeOfCode;
131     public UInt32 SizeOfInitializedData;
132     public UInt32 SizeOfUninitializedData;
133     public UInt32 AddressOfEntryPoint;
134     public UInt32 BaseOfCode;
135     public UInt64 ImageBase;
136     public UInt32 SectionAlignment;
137     public UInt32 FileAlignment;
138     public UInt16 MajorOperatingSystemVersion;
139     public UInt16 MinorOperatingSystemVersion;
140     public UInt16 MajorImageVersion;
141     public UInt16 MinorImageVersion;
142     public UInt16 MajorSubsystemVersion;
143     public UInt16 MinorSubsystemVersion;
144     public UInt32 Win32VersionValue;
145     public UInt32 SizeOfImage;
146     public UInt32 SizeOfHeaders;
147     public UInt32 CheckSum;
148     public UInt16 Subsystem;
149     public UInt16 DllCharacteristics;
150     public UInt64 SizeOfStackReserve;
151     public UInt64 SizeOfStackCommit;
152     public UInt64 SizeOfHeapReserve;
153     public UInt64 SizeOfHeapCommit;
154     public UInt32 LoaderFlags;
155     public UInt32 NumberOfRvaAndSizes;
156     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
157     public IMAGE_DATA_DIRECTORY[] DataDirectory;
158 william 159 }
159 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
160 william 294 [StructLayout(LayoutKind.Sequential)]
161     public struct IMAGE_DATA_DIRECTORY
162 william 159 {
163 william 294 public UInt32 VirtualAddress;
164     public UInt32 Size;
165 william 159 }
166 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
167 william 294 [StructLayout(LayoutKind.Sequential)]
168     public struct IMAGE_SECTION_HEADER
169 william 159 {
170 william 294 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
171     public string Name;
172     public Misc Misc;
173     public UInt32 VirtualAddress;
174     public UInt32 SizeOfRawData;
175     public UInt32 PointerToRawData;
176     public UInt32 PointerToRelocations;
177     public UInt32 PointerToLinenumbers;
178     public UInt16 NumberOfRelocations;
179     public UInt16 NumberOfLinenumbers;
180     public UInt32 Characteristics;
181 william 159 }
182 william 318 [TypeConverter(typeof(ExpandableObjectConverter))]
183 william 159 [StructLayout(LayoutKind.Explicit)]
184 william 294 public struct Misc
185 william 159 {
186     [FieldOffset(0)]
187 william 294 public UInt32 PhysicalAddress;
188     [FieldOffset(0)]
189     public UInt32 VirtualSize;
190     }
191 william 159
192 william 294 #endregion
193 william 159
194 william 294 #region Fields
195 william 159
196 william 294 private readonly IMAGE_DOS_HEADER _dosHeader;
197     private IMAGE_NT_HEADERS _ntHeaders;
198     private readonly IList<IMAGE_SECTION_HEADER> _sectionHeaders = new List<IMAGE_SECTION_HEADER>();
199     #endregion
200 william 159
201 william 299 #region logging implementation
202     private static class log
203     {
204     public static class verbose
205     {
206     public static class debug
207     {
208     public static void writeline(string format, params object[] args)
209     {
210     #if ENABLE_LOGGING
211     logger.VerboseDebug.WriteLine(format, args);
212     #endif
213     }
214     public static void write(string format, params object[] args)
215     {
216     #if ENABLE_LOGGING
217     logger.VerboseDebug.Write(format, args);
218     #endif
219     }
220     }
221     public static class error
222     {
223     public static void writeline(string format, params object[] args)
224     {
225     #if ENABLE_LOGGING
226     logger.VerboseError.WriteLine(format, args);
227     #endif
228     }
229     public static void write(string format, params object[] args)
230     {
231     #if ENABLE_LOGGING
232     logger.VerboseError.Write(format, args);
233     #endif
234     }
235     }
236     }
237     }
238     #endregion
239    
240    
241 william 318 public PEData GetData
242     {
243     get
244     {
245     PEData _data = new PEData(_dosHeader, _ntHeaders, _sectionHeaders);
246     return _data;
247     }
248     }
249     #region t
250     public class PEData
251     {
252     public PEData():this(new IMAGE_DOS_HEADER(),new IMAGE_NT_HEADERS(),new List<IMAGE_SECTION_HEADER>()) { }
253     public PEData(IMAGE_DOS_HEADER DosHeader, IMAGE_NT_HEADERS NTHeader, IList<IMAGE_SECTION_HEADER> SectionHeaders)
254     {
255     this.DosHeader = DosHeader;
256     this.NTHeader = NTHeader;
257     this.SectionHeaders = SectionHeaders;
258     }
259     public IMAGE_DOS_HEADER DosHeader { get; private set; }
260     public IMAGE_NT_HEADERS NTHeader { get; private set; }
261     public IList<IMAGE_SECTION_HEADER> SectionHeaders { get; private set; }
262     }
263    
264     #endregion
265    
266 william 294 public PEReader(FileInfo fi) : this(fi.FullName) { }
267     public PEReader(string filename)
268 william 299 {
269 william 294 Exception ErrorInfo = null;
270     using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
271     {
272     try
273     {
274 william 299 log.verbose.debug.writeline("Reading PE Format from: {0}", filename);
275 william 294 BinaryReader reader = new BinaryReader(fs);
276     // Reset reader position, just in case
277     reader.BaseStream.Seek(0, SeekOrigin.Begin);
278 william 159
279 william 294 // Read MS-DOS header section
280     _dosHeader = MarshalBytesTo<IMAGE_DOS_HEADER>(reader);
281     // MS-DOS magic number should read 'MZ'
282 william 318 if (_dosHeader._e_magic != 0x5a4d)
283 william 294 {
284     throw new InvalidOperationException("File is not a portable executable.");
285     }
286 william 159
287 william 294 // Skip MS-DOS stub and seek reader to NT Headers
288 william 318 reader.BaseStream.Seek(_dosHeader._e_lfanew, SeekOrigin.Begin);
289 william 159
290 william 294 // Read NT Headers
291     _ntHeaders.Signature = MarshalBytesTo<UInt32>(reader);
292 william 159
293 william 294 // Make sure we have 'PE' in the pe signature
294     if (_ntHeaders.Signature != 0x4550)
295     {
296     throw new InvalidOperationException("Invalid portable executable signature in NT header.");
297     }
298 william 159
299 william 294 _ntHeaders.FileHeader = MarshalBytesTo<IMAGE_FILE_HEADER>(reader);
300     // Read optional headers
301     if (Is32bitAssembly())
302     {
303 william 299 log.verbose.debug.writeline("\tDetected a 32Bit PE Executable");
304 william 294 Load32bitOptionalHeaders(reader);
305     }
306     else
307     {
308 william 299 log.verbose.debug.writeline("\tDetected a 64Bit PE Executable");
309 william 294 Load64bitOptionalHeaders(reader);
310     }
311 william 159
312 william 294 // Read section data
313 william 299 log.verbose.debug.writeline("\tTotal Section Headers: {0}", _sectionHeaders.Count);
314 william 294 foreach (IMAGE_SECTION_HEADER header in _sectionHeaders)
315     {
316     int section_index = _sectionHeaders.IndexOf(header) + 1;
317 william 299 log.verbose.debug.writeline("\tSection Header: {0} of {1}", section_index, _sectionHeaders.Count);
318     log.verbose.debug.writeline("\t\tName: {0}", header.Name);
319     log.verbose.debug.writeline("\t\tVirtual Address: 0x{0:x8}", header.VirtualAddress);
320     log.verbose.debug.writeline("\t\tPhysical Address: 0x{0:x8}", header.Misc.PhysicalAddress);
321     log.verbose.debug.writeline("\t\tVirtual Size: 0x{0:x8}", header.Misc.VirtualSize);
322     log.verbose.debug.writeline("\t\tRaw Data Size: 0x{0:x8}", header.SizeOfRawData);
323     log.verbose.debug.writeline("\t\tPointer To Raw Data: 0x{0:x8}", header.PointerToRawData);
324 william 159
325 william 294 // Skip to beginning of a section
326     reader.BaseStream.Seek(header.PointerToRawData, SeekOrigin.Begin);
327 william 159
328 william 294 // Read section data... and do something with it
329     byte[] sectiondata = reader.ReadBytes((int)header.SizeOfRawData);
330     }
331     reader.Close();
332     }
333     catch (Exception ex)
334     {
335     ErrorInfo = ex;
336     throw ErrorInfo;
337     }
338     }
339     if (ErrorInfo != null)
340     {
341 william 299 log.verbose.error.writeline("Error Reading PE Format from: {0}", filename);
342     log.verbose.error.writeline(ErrorInfo.ToString());
343 william 294 }
344     }
345 william 159
346 william 294 public IMAGE_DOS_HEADER GetDOSHeader()
347     {
348     return _dosHeader;
349     }
350 william 159
351 william 294 public UInt32 GetPESignature()
352     {
353     return _ntHeaders.Signature;
354     }
355 william 159
356 william 294 public IMAGE_FILE_HEADER GetFileHeader()
357     {
358     return _ntHeaders.FileHeader;
359     }
360 william 159
361 william 294 public IMAGE_OPTIONAL_HEADER32 GetOptionalHeaders32()
362     {
363     return _ntHeaders.OptionalHeader32;
364     }
365 william 159
366 william 294 public IMAGE_OPTIONAL_HEADER64 GetOptionalHeaders64()
367     {
368     return _ntHeaders.OptionalHeader64;
369     }
370 william 159
371 william 294 public IList<IMAGE_SECTION_HEADER> GetSectionHeaders()
372     {
373     return _sectionHeaders;
374     }
375 william 159
376 william 294 public bool Is32bitAssembly()
377 william 159 {
378 william 294 return ((_ntHeaders.FileHeader.Characteristics & 0x0100) == 0x0100);
379 william 159 }
380 william 294
381     private void Load64bitOptionalHeaders(BinaryReader reader)
382 william 293 {
383 william 294 _ntHeaders.OptionalHeader64 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER64>(reader);
384 william 293
385 william 294 // Should have 10 data directories
386     if (_ntHeaders.OptionalHeader64.NumberOfRvaAndSizes != 0x10)
387     {
388     throw new InvalidOperationException("Invalid number of data directories in NT header");
389     }
390 william 293
391 william 294 // Scan data directories and load section headers
392     for (int i = 0; i < _ntHeaders.OptionalHeader64.NumberOfRvaAndSizes; i++)
393     {
394     if (_ntHeaders.OptionalHeader64.DataDirectory[i].Size > 0)
395     {
396     _sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(reader));
397     }
398     }
399     }
400 william 293
401 william 294 private void Load32bitOptionalHeaders(BinaryReader reader)
402     {
403     _ntHeaders.OptionalHeader32 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER32>(reader);
404 william 293
405 william 294 // Should have 10 data directories
406     if (_ntHeaders.OptionalHeader32.NumberOfRvaAndSizes != 0x10)
407     {
408     throw new InvalidOperationException("Invalid number of data directories in NT header");
409     }
410 william 293
411 william 294 // Scan data directories and load section headers
412     for (int i = 0; i < _ntHeaders.OptionalHeader32.NumberOfRvaAndSizes; i++)
413     {
414     if (_ntHeaders.OptionalHeader32.DataDirectory[i].Size > 0)
415     {
416     _sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(reader));
417     }
418     }
419     }
420 william 293
421 william 294 private static T MarshalBytesTo<T>(BinaryReader reader)
422     {
423     // Unmanaged data
424     byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
425 william 293
426 william 294 // Create a pointer to the unmanaged data pinned in memory to be accessed by unmanaged code
427     GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
428 william 293
429 william 294 // Use our previously created pointer to unmanaged data and marshal to the specified type
430     T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
431 william 293
432 william 294 // Deallocate pointer
433     handle.Free();
434 william 293
435 william 294 return theStructure;
436 william 293 }
437 william 159 }
438     }

  ViewVC Help
Powered by ViewVC 1.1.22