/[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 299 - (hide annotations) (download)
Tue Jun 5 11:36:17 2012 UTC (8 years, 11 months ago) by william
File size: 15121 byte(s)
+ add internal logging override (so it can be turned on/off for performance reasons)

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

  ViewVC Help
Powered by ViewVC 1.1.22