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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 299 - (show 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 #define ENABLE_LOGGING
2 using System;
3 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 // 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 {
20 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 }
42
43 [StructLayout(LayoutKind.Sequential)]
44 public struct IMAGE_NT_HEADERS
45 {
46 public UInt32 Signature;
47 public IMAGE_FILE_HEADER FileHeader;
48 public IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
49 public IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
50 }
51
52 [StructLayout(LayoutKind.Sequential)]
53 public struct IMAGE_FILE_HEADER
54 {
55 public UInt16 Machine;
56 public UInt16 NumberOfSections;
57 public UInt32 TimeDateStamp;
58 public UInt32 PointerToSymbolTable;
59 public UInt32 NumberOfSymbols;
60 public UInt16 SizeOfOptionalHeader;
61 public UInt16 Characteristics;
62 }
63
64 [StructLayout(LayoutKind.Sequential)]
65 public struct IMAGE_OPTIONAL_HEADER32
66 {
67 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 }
100
101 [StructLayout(LayoutKind.Sequential)]
102 public struct IMAGE_OPTIONAL_HEADER64
103 {
104 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 }
136
137 [StructLayout(LayoutKind.Sequential)]
138 public struct IMAGE_DATA_DIRECTORY
139 {
140 public UInt32 VirtualAddress;
141 public UInt32 Size;
142 }
143
144 [StructLayout(LayoutKind.Sequential)]
145 public struct IMAGE_SECTION_HEADER
146 {
147 [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 }
159
160 [StructLayout(LayoutKind.Explicit)]
161 public struct Misc
162 {
163 [FieldOffset(0)]
164 public UInt32 PhysicalAddress;
165 [FieldOffset(0)]
166 public UInt32 VirtualSize;
167 }
168
169 #endregion
170
171 #region Fields
172
173 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
177 #endregion
178
179 #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 public PEReader(FileInfo fi) : this(fi.FullName) { }
220 public PEReader(string filename)
221 {
222 Exception ErrorInfo = null;
223 using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
224 {
225 try
226 {
227 log.verbose.debug.writeline("Reading PE Format from: {0}", filename);
228 BinaryReader reader = new BinaryReader(fs);
229 // Reset reader position, just in case
230 reader.BaseStream.Seek(0, SeekOrigin.Begin);
231
232 // 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
240 // Skip MS-DOS stub and seek reader to NT Headers
241 reader.BaseStream.Seek(_dosHeader.e_lfanew, SeekOrigin.Begin);
242
243 // Read NT Headers
244 _ntHeaders.Signature = MarshalBytesTo<UInt32>(reader);
245
246 // 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
252 _ntHeaders.FileHeader = MarshalBytesTo<IMAGE_FILE_HEADER>(reader);
253 // Read optional headers
254 if (Is32bitAssembly())
255 {
256 log.verbose.debug.writeline("\tDetected a 32Bit PE Executable");
257 Load32bitOptionalHeaders(reader);
258 }
259 else
260 {
261 log.verbose.debug.writeline("\tDetected a 64Bit PE Executable");
262 Load64bitOptionalHeaders(reader);
263 }
264
265 // Read section data
266 log.verbose.debug.writeline("\tTotal Section Headers: {0}", _sectionHeaders.Count);
267 foreach (IMAGE_SECTION_HEADER header in _sectionHeaders)
268 {
269 int section_index = _sectionHeaders.IndexOf(header) + 1;
270 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
278 // Skip to beginning of a section
279 reader.BaseStream.Seek(header.PointerToRawData, SeekOrigin.Begin);
280
281 // 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 log.verbose.error.writeline("Error Reading PE Format from: {0}", filename);
295 log.verbose.error.writeline(ErrorInfo.ToString());
296 }
297 }
298
299 public IMAGE_DOS_HEADER GetDOSHeader()
300 {
301 return _dosHeader;
302 }
303
304 public UInt32 GetPESignature()
305 {
306 return _ntHeaders.Signature;
307 }
308
309 public IMAGE_FILE_HEADER GetFileHeader()
310 {
311 return _ntHeaders.FileHeader;
312 }
313
314 public IMAGE_OPTIONAL_HEADER32 GetOptionalHeaders32()
315 {
316 return _ntHeaders.OptionalHeader32;
317 }
318
319 public IMAGE_OPTIONAL_HEADER64 GetOptionalHeaders64()
320 {
321 return _ntHeaders.OptionalHeader64;
322 }
323
324 public IList<IMAGE_SECTION_HEADER> GetSectionHeaders()
325 {
326 return _sectionHeaders;
327 }
328
329 public bool Is32bitAssembly()
330 {
331 return ((_ntHeaders.FileHeader.Characteristics & 0x0100) == 0x0100);
332 }
333
334 private void Load64bitOptionalHeaders(BinaryReader reader)
335 {
336 _ntHeaders.OptionalHeader64 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER64>(reader);
337
338 // 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
344 // 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
354 private void Load32bitOptionalHeaders(BinaryReader reader)
355 {
356 _ntHeaders.OptionalHeader32 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER32>(reader);
357
358 // 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
364 // 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
374 private static T MarshalBytesTo<T>(BinaryReader reader)
375 {
376 // Unmanaged data
377 byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
378
379 // 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
382 // 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
385 // Deallocate pointer
386 handle.Free();
387
388 return theStructure;
389 }
390 }
391 }

  ViewVC Help
Powered by ViewVC 1.1.22