├── README.md
├── detection.sln
└── detection
├── App.config
├── PeHeaderReader .cs
├── Program.cs
├── Properties
└── AssemblyInfo.cs
└── detection.csproj
/README.md:
--------------------------------------------------------------------------------
1 | Author: Aden Chung Wee Jing (weejing789@gmail.com)
2 |
3 | Company: Countercept (@countercept)
4 |
5 | Website: https://countercept.com
6 |
7 |
8 | How to Compile/execute
9 |
10 | Program must be compiled in x64 and run with adminstrative privliges.
11 |
--------------------------------------------------------------------------------
/detection.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.421
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "detection", "detection\detection.csproj", "{4C736F07-FB70-453A-9D8E-ACB036B4038D}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|x64 = Debug|x64
12 | Release|Any CPU = Release|Any CPU
13 | Release|x64 = Release|x64
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Debug|x64.ActiveCfg = Debug|x64
19 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Debug|x64.Build.0 = Debug|x64
20 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Release|x64.ActiveCfg = Release|x64
23 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}.Release|x64.Build.0 = Release|x64
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {EC09AE34-7D3D-4094-B817-907249FF8A31}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/detection/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/detection/PeHeaderReader .cs:
--------------------------------------------------------------------------------
1 | // Credits: John Stewien
2 | // From: http://code.cheesydesign.com/?p=572
3 |
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Runtime.InteropServices;
8 | using System.IO;
9 |
10 | namespace detection
11 | {
12 | public class PeHeaderReader
13 | {
14 | #region File Header Structures
15 |
16 | public struct IMAGE_DOS_HEADER
17 | { // DOS .EXE header
18 | public UInt16 e_magic; // Magic number
19 | public UInt16 e_cblp; // Bytes on last page of file
20 | public UInt16 e_cp; // Pages in file
21 | public UInt16 e_crlc; // Relocations
22 | public UInt16 e_cparhdr; // Size of header in paragraphs
23 | public UInt16 e_minalloc; // Minimum extra paragraphs needed
24 | public UInt16 e_maxalloc; // Maximum extra paragraphs needed
25 | public UInt16 e_ss; // Initial (relative) SS value
26 | public UInt16 e_sp; // Initial SP value
27 | public UInt16 e_csum; // Checksum
28 | public UInt16 e_ip; // Initial IP value
29 | public UInt16 e_cs; // Initial (relative) CS value
30 | public UInt16 e_lfarlc; // File address of relocation table
31 | public UInt16 e_ovno; // Overlay number
32 | public UInt16 e_res_0; // Reserved words
33 | public UInt16 e_res_1; // Reserved words
34 | public UInt16 e_res_2; // Reserved words
35 | public UInt16 e_res_3; // Reserved words
36 | public UInt16 e_oemid; // OEM identifier (for e_oeminfo)
37 | public UInt16 e_oeminfo; // OEM information; e_oemid specific
38 | public UInt16 e_res2_0; // Reserved words
39 | public UInt16 e_res2_1; // Reserved words
40 | public UInt16 e_res2_2; // Reserved words
41 | public UInt16 e_res2_3; // Reserved words
42 | public UInt16 e_res2_4; // Reserved words
43 | public UInt16 e_res2_5; // Reserved words
44 | public UInt16 e_res2_6; // Reserved words
45 | public UInt16 e_res2_7; // Reserved words
46 | public UInt16 e_res2_8; // Reserved words
47 | public UInt16 e_res2_9; // Reserved words
48 | public UInt32 e_lfanew; // File address of new exe header
49 | }
50 |
51 | [StructLayout(LayoutKind.Sequential)]
52 | public struct IMAGE_DATA_DIRECTORY
53 | {
54 | public UInt32 VirtualAddress;
55 | public UInt32 Size;
56 | }
57 |
58 | [StructLayout(LayoutKind.Sequential, Pack = 1)]
59 | public struct IMAGE_OPTIONAL_HEADER32
60 | {
61 | public UInt16 Magic;
62 | public Byte MajorLinkerVersion;
63 | public Byte MinorLinkerVersion;
64 | public UInt32 SizeOfCode;
65 | public UInt32 SizeOfInitializedData;
66 | public UInt32 SizeOfUninitializedData;
67 | public UInt32 AddressOfEntryPoint;
68 | public UInt32 BaseOfCode;
69 | public UInt32 BaseOfData;
70 | public UInt32 ImageBase;
71 | public UInt32 SectionAlignment;
72 | public UInt32 FileAlignment;
73 | public UInt16 MajorOperatingSystemVersion;
74 | public UInt16 MinorOperatingSystemVersion;
75 | public UInt16 MajorImageVersion;
76 | public UInt16 MinorImageVersion;
77 | public UInt16 MajorSubsystemVersion;
78 | public UInt16 MinorSubsystemVersion;
79 | public UInt32 Win32VersionValue;
80 | public UInt32 SizeOfImage;
81 | public UInt32 SizeOfHeaders;
82 | public UInt32 CheckSum;
83 | public UInt16 Subsystem;
84 | public UInt16 DllCharacteristics;
85 | public UInt32 SizeOfStackReserve;
86 | public UInt32 SizeOfStackCommit;
87 | public UInt32 SizeOfHeapReserve;
88 | public UInt32 SizeOfHeapCommit;
89 | public UInt32 LoaderFlags;
90 | public UInt32 NumberOfRvaAndSizes;
91 |
92 | public IMAGE_DATA_DIRECTORY ExportTable;
93 | public IMAGE_DATA_DIRECTORY ImportTable;
94 | public IMAGE_DATA_DIRECTORY ResourceTable;
95 | public IMAGE_DATA_DIRECTORY ExceptionTable;
96 | public IMAGE_DATA_DIRECTORY CertificateTable;
97 | public IMAGE_DATA_DIRECTORY BaseRelocationTable;
98 | public IMAGE_DATA_DIRECTORY Debug;
99 | public IMAGE_DATA_DIRECTORY Architecture;
100 | public IMAGE_DATA_DIRECTORY GlobalPtr;
101 | public IMAGE_DATA_DIRECTORY TLSTable;
102 | public IMAGE_DATA_DIRECTORY LoadConfigTable;
103 | public IMAGE_DATA_DIRECTORY BoundImport;
104 | public IMAGE_DATA_DIRECTORY IAT;
105 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
106 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
107 | public IMAGE_DATA_DIRECTORY Reserved;
108 | }
109 |
110 | [StructLayout(LayoutKind.Sequential, Pack = 1)]
111 | public struct IMAGE_OPTIONAL_HEADER64
112 | {
113 | public UInt16 Magic;
114 | public Byte MajorLinkerVersion;
115 | public Byte MinorLinkerVersion;
116 | public UInt32 SizeOfCode;
117 | public UInt32 SizeOfInitializedData;
118 | public UInt32 SizeOfUninitializedData;
119 | public UInt32 AddressOfEntryPoint;
120 | public UInt32 BaseOfCode;
121 | public UInt64 ImageBase;
122 | public UInt32 SectionAlignment;
123 | public UInt32 FileAlignment;
124 | public UInt16 MajorOperatingSystemVersion;
125 | public UInt16 MinorOperatingSystemVersion;
126 | public UInt16 MajorImageVersion;
127 | public UInt16 MinorImageVersion;
128 | public UInt16 MajorSubsystemVersion;
129 | public UInt16 MinorSubsystemVersion;
130 | public UInt32 Win32VersionValue;
131 | public UInt32 SizeOfImage;
132 | public UInt32 SizeOfHeaders;
133 | public UInt32 CheckSum;
134 | public UInt16 Subsystem;
135 | public UInt16 DllCharacteristics;
136 | public UInt64 SizeOfStackReserve;
137 | public UInt64 SizeOfStackCommit;
138 | public UInt64 SizeOfHeapReserve;
139 | public UInt64 SizeOfHeapCommit;
140 | public UInt32 LoaderFlags;
141 | public UInt32 NumberOfRvaAndSizes;
142 |
143 | public IMAGE_DATA_DIRECTORY ExportTable;
144 | public IMAGE_DATA_DIRECTORY ImportTable;
145 | public IMAGE_DATA_DIRECTORY ResourceTable;
146 | public IMAGE_DATA_DIRECTORY ExceptionTable;
147 | public IMAGE_DATA_DIRECTORY CertificateTable;
148 | public IMAGE_DATA_DIRECTORY BaseRelocationTable;
149 | public IMAGE_DATA_DIRECTORY Debug;
150 | public IMAGE_DATA_DIRECTORY Architecture;
151 | public IMAGE_DATA_DIRECTORY GlobalPtr;
152 | public IMAGE_DATA_DIRECTORY TLSTable;
153 | public IMAGE_DATA_DIRECTORY LoadConfigTable;
154 | public IMAGE_DATA_DIRECTORY BoundImport;
155 | public IMAGE_DATA_DIRECTORY IAT;
156 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
157 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
158 | public IMAGE_DATA_DIRECTORY Reserved;
159 | }
160 |
161 | [StructLayout(LayoutKind.Sequential, Pack = 1)]
162 | public struct IMAGE_FILE_HEADER
163 | {
164 | public UInt16 Machine;
165 | public UInt16 NumberOfSections;
166 | public UInt32 TimeDateStamp;
167 | public UInt32 PointerToSymbolTable;
168 | public UInt32 NumberOfSymbols;
169 | public UInt16 SizeOfOptionalHeader;
170 | public UInt16 Characteristics;
171 | }
172 |
173 | // Grabbed the following 2 definitions from http://www.pinvoke.net/default.aspx/Structures/IMAGE_SECTION_HEADER.html
174 |
175 | [StructLayout(LayoutKind.Explicit)]
176 | public struct IMAGE_SECTION_HEADER
177 | {
178 | [FieldOffset(0)]
179 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
180 | public char[] Name;
181 | [FieldOffset(8)]
182 | public UInt32 VirtualSize;
183 | [FieldOffset(12)]
184 | public UInt32 VirtualAddress;
185 | [FieldOffset(16)]
186 | public UInt32 SizeOfRawData;
187 | [FieldOffset(20)]
188 | public UInt32 PointerToRawData;
189 | [FieldOffset(24)]
190 | public UInt32 PointerToRelocations;
191 | [FieldOffset(28)]
192 | public UInt32 PointerToLinenumbers;
193 | [FieldOffset(32)]
194 | public UInt16 NumberOfRelocations;
195 | [FieldOffset(34)]
196 | public UInt16 NumberOfLinenumbers;
197 | [FieldOffset(36)]
198 | public DataSectionFlags Characteristics;
199 |
200 | public string Section
201 | {
202 | get { return new string(Name); }
203 | }
204 | }
205 |
206 | [Flags]
207 | public enum DataSectionFlags : uint
208 | {
209 | ///
210 | /// Reserved for future use.
211 | ///
212 | TypeReg = 0x00000000,
213 | ///
214 | /// Reserved for future use.
215 | ///
216 | TypeDsect = 0x00000001,
217 | ///
218 | /// Reserved for future use.
219 | ///
220 | TypeNoLoad = 0x00000002,
221 | ///
222 | /// Reserved for future use.
223 | ///
224 | TypeGroup = 0x00000004,
225 | ///
226 | /// The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files.
227 | ///
228 | TypeNoPadded = 0x00000008,
229 | ///
230 | /// Reserved for future use.
231 | ///
232 | TypeCopy = 0x00000010,
233 | ///
234 | /// The section contains executable code.
235 | ///
236 | ContentCode = 0x00000020,
237 | ///
238 | /// The section contains initialized data.
239 | ///
240 | ContentInitializedData = 0x00000040,
241 | ///
242 | /// The section contains uninitialized data.
243 | ///
244 | ContentUninitializedData = 0x00000080,
245 | ///
246 | /// Reserved for future use.
247 | ///
248 | LinkOther = 0x00000100,
249 | ///
250 | /// The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
251 | ///
252 | LinkInfo = 0x00000200,
253 | ///
254 | /// Reserved for future use.
255 | ///
256 | TypeOver = 0x00000400,
257 | ///
258 | /// The section will not become part of the image. This is valid only for object files.
259 | ///
260 | LinkRemove = 0x00000800,
261 | ///
262 | /// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files.
263 | ///
264 | LinkComDat = 0x00001000,
265 | ///
266 | /// Reset speculative exceptions handling bits in the TLB entries for this section.
267 | ///
268 | NoDeferSpecExceptions = 0x00004000,
269 | ///
270 | /// The section contains data referenced through the global pointer (GP).
271 | ///
272 | RelativeGP = 0x00008000,
273 | ///
274 | /// Reserved for future use.
275 | ///
276 | MemPurgeable = 0x00020000,
277 | ///
278 | /// Reserved for future use.
279 | ///
280 | Memory16Bit = 0x00020000,
281 | ///
282 | /// Reserved for future use.
283 | ///
284 | MemoryLocked = 0x00040000,
285 | ///
286 | /// Reserved for future use.
287 | ///
288 | MemoryPreload = 0x00080000,
289 | ///
290 | /// Align data on a 1-byte boundary. Valid only for object files.
291 | ///
292 | Align1Bytes = 0x00100000,
293 | ///
294 | /// Align data on a 2-byte boundary. Valid only for object files.
295 | ///
296 | Align2Bytes = 0x00200000,
297 | ///
298 | /// Align data on a 4-byte boundary. Valid only for object files.
299 | ///
300 | Align4Bytes = 0x00300000,
301 | ///
302 | /// Align data on an 8-byte boundary. Valid only for object files.
303 | ///
304 | Align8Bytes = 0x00400000,
305 | ///
306 | /// Align data on a 16-byte boundary. Valid only for object files.
307 | ///
308 | Align16Bytes = 0x00500000,
309 | ///
310 | /// Align data on a 32-byte boundary. Valid only for object files.
311 | ///
312 | Align32Bytes = 0x00600000,
313 | ///
314 | /// Align data on a 64-byte boundary. Valid only for object files.
315 | ///
316 | Align64Bytes = 0x00700000,
317 | ///
318 | /// Align data on a 128-byte boundary. Valid only for object files.
319 | ///
320 | Align128Bytes = 0x00800000,
321 | ///
322 | /// Align data on a 256-byte boundary. Valid only for object files.
323 | ///
324 | Align256Bytes = 0x00900000,
325 | ///
326 | /// Align data on a 512-byte boundary. Valid only for object files.
327 | ///
328 | Align512Bytes = 0x00A00000,
329 | ///
330 | /// Align data on a 1024-byte boundary. Valid only for object files.
331 | ///
332 | Align1024Bytes = 0x00B00000,
333 | ///
334 | /// Align data on a 2048-byte boundary. Valid only for object files.
335 | ///
336 | Align2048Bytes = 0x00C00000,
337 | ///
338 | /// Align data on a 4096-byte boundary. Valid only for object files.
339 | ///
340 | Align4096Bytes = 0x00D00000,
341 | ///
342 | /// Align data on an 8192-byte boundary. Valid only for object files.
343 | ///
344 | Align8192Bytes = 0x00E00000,
345 | ///
346 | /// The section contains extended relocations.
347 | ///
348 | LinkExtendedRelocationOverflow = 0x01000000,
349 | ///
350 | /// The section can be discarded as needed.
351 | ///
352 | MemoryDiscardable = 0x02000000,
353 | ///
354 | /// The section cannot be cached.
355 | ///
356 | MemoryNotCached = 0x04000000,
357 | ///
358 | /// The section is not pageable.
359 | ///
360 | MemoryNotPaged = 0x08000000,
361 | ///
362 | /// The section can be shared in memory.
363 | ///
364 | MemoryShared = 0x10000000,
365 | ///
366 | /// The section can be executed as code.
367 | ///
368 | MemoryExecute = 0x20000000,
369 | ///
370 | /// The section can be read.
371 | ///
372 | MemoryRead = 0x40000000,
373 | ///
374 | /// The section can be written to.
375 | ///
376 | MemoryWrite = 0x80000000
377 | }
378 |
379 | #endregion File Header Structures
380 |
381 | #region Private Fields
382 |
383 | ///
384 | /// The DOS header
385 | ///
386 | private IMAGE_DOS_HEADER dosHeader;
387 | ///
388 | /// The file header
389 | ///
390 | private IMAGE_FILE_HEADER fileHeader;
391 | ///
392 | /// Optional 32 bit file header
393 | ///
394 | private IMAGE_OPTIONAL_HEADER32 optionalHeader32;
395 | ///
396 | /// Optional 64 bit file header
397 | ///
398 | private IMAGE_OPTIONAL_HEADER64 optionalHeader64;
399 | ///
400 | /// Image Section headers. Number of sections is in the file header.
401 | ///
402 | private IMAGE_SECTION_HEADER[] imageSectionHeaders;
403 | public byte[] allBytes;
404 |
405 | #endregion Private Fields
406 |
407 | #region Public Methods
408 |
409 | public PeHeaderReader(string filePath)
410 | {
411 | // Read in the DLL or EXE and get the timestamp
412 | using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
413 | {
414 | BinaryReader reader = new BinaryReader(stream);
415 | dosHeader = FromBinaryReader(reader);
416 |
417 | // Add 4 bytes to the offset
418 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
419 |
420 | UInt32 ntHeadersSignature = reader.ReadUInt32();
421 | fileHeader = FromBinaryReader(reader);
422 | if (this.Is32BitHeader)
423 | {
424 | optionalHeader32 = FromBinaryReader(reader);
425 | }
426 | else
427 | {
428 | optionalHeader64 = FromBinaryReader(reader);
429 | }
430 |
431 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections];
432 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo)
433 | {
434 | imageSectionHeaders[headerNo] = FromBinaryReader(reader);
435 | }
436 | }
437 | allBytes = File.ReadAllBytes(filePath);
438 | }
439 |
440 |
441 | public PeHeaderReader(byte[] fileBytes)
442 | {
443 | // Read in the DLL or EXE and get the timestamp
444 | using (MemoryStream stream = new MemoryStream(fileBytes, 0, fileBytes.Length))
445 | {
446 | BinaryReader reader = new BinaryReader(stream);
447 | dosHeader = FromBinaryReader(reader);
448 |
449 | // Add 4 bytes to the offset
450 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
451 |
452 | UInt32 ntHeadersSignature = reader.ReadUInt32();
453 | fileHeader = FromBinaryReader(reader);
454 | if (this.Is32BitHeader)
455 | {
456 | optionalHeader32 = FromBinaryReader(reader);
457 | }
458 | else
459 | {
460 | optionalHeader64 = FromBinaryReader(reader);
461 | }
462 |
463 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections];
464 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo)
465 | {
466 | imageSectionHeaders[headerNo] = FromBinaryReader(reader);
467 | }
468 | }
469 |
470 | }
471 |
472 | ///
473 | /// Gets the header of the .NET assembly that called this function
474 | ///
475 | ///
476 | public static PeHeaderReader GetCallingAssemblyHeader()
477 | {
478 | // Get the path to the calling assembly, which is the path to the
479 | // DLL or EXE that we want the time of
480 | string filePath = System.Reflection.Assembly.GetCallingAssembly().Location;
481 |
482 | // Get and return the timestamp
483 | return new PeHeaderReader(filePath);
484 | }
485 |
486 | ///
487 | /// Gets the header of the .NET assembly that called this function
488 | ///
489 | ///
490 | public static PeHeaderReader GetAssemblyHeader()
491 | {
492 | // Get the path to the calling assembly, which is the path to the
493 | // DLL or EXE that we want the time of
494 | string filePath = System.Reflection.Assembly.GetAssembly(typeof(PeHeaderReader)).Location;
495 |
496 | // Get and return the timestamp
497 | return new PeHeaderReader(filePath);
498 | }
499 |
500 | ///
501 | /// Reads in a block from a file and converts it to the struct
502 | /// type specified by the template parameter
503 | ///
504 | ///
505 | ///
506 | ///
507 | public static T FromBinaryReader(BinaryReader reader)
508 | {
509 | // Read in a byte array
510 | byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
511 |
512 | // Pin the managed memory while, copy it out the data, then unpin it
513 | GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
514 | T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
515 | handle.Free();
516 |
517 | return theStructure;
518 | }
519 |
520 | #endregion Public Methods
521 |
522 | #region Properties
523 |
524 | ///
525 | /// Gets if the file header is 32 bit or not
526 | ///
527 | public bool Is32BitHeader
528 | {
529 | get
530 | {
531 | UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100;
532 | return (IMAGE_FILE_32BIT_MACHINE & FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE;
533 | }
534 | }
535 |
536 | ///
537 | /// Gets the file header
538 | ///
539 | public IMAGE_FILE_HEADER FileHeader
540 | {
541 | get
542 | {
543 | return fileHeader;
544 | }
545 | }
546 |
547 | ///
548 | /// Gets the optional header
549 | ///
550 | public IMAGE_OPTIONAL_HEADER32 OptionalHeader32
551 | {
552 | get
553 | {
554 | return optionalHeader32;
555 | }
556 | }
557 |
558 | ///
559 | /// Gets the optional header
560 | ///
561 | public IMAGE_OPTIONAL_HEADER64 OptionalHeader64
562 | {
563 | get
564 | {
565 | return optionalHeader64;
566 | }
567 | }
568 |
569 | public IMAGE_SECTION_HEADER[] ImageSectionHeaders
570 | {
571 | get
572 | {
573 | return imageSectionHeaders;
574 | }
575 | }
576 |
577 | ///
578 | /// Gets the timestamp from the file header
579 | ///
580 | public DateTime TimeStamp
581 | {
582 | get
583 | {
584 | // Timestamp is a date offset from 1970
585 | DateTime returnValue = new DateTime(1970, 1, 1, 0, 0, 0);
586 |
587 | // Add in the number of seconds since 1970/1/1
588 | returnValue = returnValue.AddSeconds(fileHeader.TimeDateStamp);
589 | // Adjust to local timezone
590 | returnValue += TimeZone.CurrentTimeZone.GetUtcOffset(returnValue);
591 |
592 | return returnValue;
593 | }
594 | }
595 |
596 | #endregion Properties
597 | }
598 | }
599 |
--------------------------------------------------------------------------------
/detection/Program.cs:
--------------------------------------------------------------------------------
1 | //Author : Aden Chung Wee jing
2 | //Email : weejing789@gmail.com
3 |
4 | using System;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Management;
8 | using System.Collections;
9 | using System.Threading;
10 | using System.Collections.Generic;
11 | using System.Security.Cryptography;
12 | using System.IO;
13 |
14 | namespace detection
15 | {
16 |
17 | class catchAmsiBypass
18 | {
19 | static LinkedList listOfProcessId;
20 | static Semaphore semaphore;
21 |
22 | [StructLayout(LayoutKind.Sequential)]
23 | public struct MODULEINFO
24 | {
25 | public IntPtr lpBaseOfDll;
26 | public uint SizeOfImage;
27 | public IntPtr EntryPoint;
28 | }
29 |
30 |
31 | [DllImport("psapi.dll", SetLastError = true)]
32 | public static extern bool EnumProcessModules(
33 | IntPtr hProcess,
34 | [Out] IntPtr lphModule,
35 | UInt32 cb,
36 | [MarshalAs(UnmanagedType.U4)] out UInt32 lpcbNeeded);
37 |
38 | [DllImport("kernel32.dll")]
39 | public static extern IntPtr OpenProcess(
40 | int dwDesiredAccess,
41 | bool bInheritHandle,
42 | int dwProcessId);
43 |
44 | [DllImport("psapi.dll")]
45 | static extern uint GetModuleFileNameEx(
46 | IntPtr hProcess,
47 | IntPtr hModule,
48 | [Out] StringBuilder lpBaseName,
49 | [In] [MarshalAs(UnmanagedType.U4)] int nSize);
50 |
51 |
52 | [DllImport("kernel32.dll")]
53 | public static extern bool ReadProcessMemory(
54 | IntPtr hProcess,
55 | IntPtr lpBaseAddress,
56 | byte[] lpBuffer,
57 | int dwSize,
58 | ref int lpNumberOfBytesRead);
59 |
60 | [DllImport("psapi.dll", SetLastError = true)]
61 | public static extern bool GetModuleInformation(
62 | IntPtr hProcess,
63 | IntPtr hModule,
64 | out MODULEINFO lpmodinfo,
65 | uint cb);
66 |
67 |
68 | static void Main(string[] args)
69 | {
70 |
71 | PeHeaderReader amsiReader = new PeHeaderReader("C:/Windows/System32/amsi.dll");
72 | byte[] amsiModule = amsiReader.allBytes;
73 | String onDiskAmsiCodehash = getSectionHeaderofAmsi(amsiReader, false, amsiModule);
74 |
75 |
76 | ManagementEventWatcher eventWatcher = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
77 | eventWatcher.EventArrived += new EventArrivedEventHandler(newEvent);
78 |
79 | listOfProcessId = new LinkedList();
80 | semaphore = new Semaphore(1, 1);
81 | eventWatcher.Start();
82 |
83 | while (true)
84 | {
85 | Thread.Sleep(5000);
86 | semaphore.WaitOne();
87 | LinkedListNode headPointer = listOfProcessId.First;
88 |
89 | if (headPointer == null)
90 | Console.WriteLine("Empty");
91 |
92 | while(headPointer != null)
93 | {
94 | LinkedListNode nextPointer = headPointer.Next;
95 | checkForBypassEvidence(headPointer, onDiskAmsiCodehash);
96 | headPointer = nextPointer;
97 | }
98 | semaphore.Release();
99 | }
100 |
101 | }
102 |
103 | // this method returns the hash of Amsi.dll code section.
104 | static String getSectionHeaderofAmsi(PeHeaderReader amsiReader, Boolean inMemory, byte[] amsiModule)
105 | {
106 | PeHeaderReader.IMAGE_SECTION_HEADER[] amsiSection = amsiReader.ImageSectionHeaders;
107 | int codeSectionPointer;
108 | for (int count = 0; count < amsiSection.Length; count++ )
109 | {
110 | char[] sectionName = amsiSection[count].Name;
111 | if (sectionName[0] =='.' && sectionName[1] =='t' && sectionName[2] =='e' && sectionName[3] == 'x' && sectionName[4] =='t')
112 | {
113 | if (inMemory)
114 | codeSectionPointer = (int)amsiSection[count].VirtualAddress;
115 | else
116 | codeSectionPointer = (int)amsiSection[count].PointerToRawData;
117 |
118 | int SizeOfRawData = (int)amsiSection[count].SizeOfRawData;
119 | byte[] amsiCodeSection = new byte[SizeOfRawData];
120 | Array.Copy(amsiModule, codeSectionPointer, amsiCodeSection, 0, SizeOfRawData);
121 | return calculateHash(amsiCodeSection);
122 | }
123 | }
124 | return "error";
125 | }
126 |
127 | //this method returns the md5 hash of a file
128 | static String calculateHash(byte [] bytesToHash)
129 | {
130 | MD5 md5CheckSum = MD5.Create();
131 | var hash = md5CheckSum.ComputeHash(bytesToHash);
132 | return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
133 | }
134 |
135 |
136 |
137 | // this method checks for the creation of new PowerShell events
138 | static void newEvent(object sender, EventArrivedEventArgs e)
139 | {
140 | String processName = e.NewEvent.Properties["ProcessName"].Value.ToString();
141 | bool match = string.Equals(processName, "powershell.exe");
142 | if (match == true)
143 | {
144 | int processId = Int32.Parse(e.NewEvent.Properties["ProcessID"].Value.ToString());
145 | semaphore.WaitOne();
146 | listOfProcessId.AddFirst(processId);
147 | semaphore.Release();
148 | }
149 |
150 | }
151 |
152 | // this method sets a handle on an identified process
153 | static void checkForBypassEvidence(LinkedListNode processId, string onDiskAmsiCodehash)
154 | {
155 | int PROCESS_VM_READ = (0x0010);
156 | int PROCESS_QUERY_INFORMATION = (0x0400);
157 | Console.WriteLine("Analysing process id: " + processId.Value);
158 |
159 | IntPtr processHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
160 | true, processId.Value);
161 |
162 | if (processHandle != null)
163 | {
164 | Boolean bypassFound = analyseAmsiDLL(processHandle, onDiskAmsiCodehash);
165 | if(bypassFound == true)
166 | {
167 | Console.WriteLine("Amsi tampering found in " + processId.Value);
168 | listOfProcessId.Remove(processId);
169 | }
170 | }
171 | else
172 | {
173 | listOfProcessId.Remove(processId);
174 | }
175 | }
176 |
177 | // this method sets a handle on the amsi DLL
178 | static Boolean analyseAmsiDLL(IntPtr processHandle, String onDiskAmsiCodehash)
179 | {
180 | IntPtr[] listOfModules = new IntPtr[1024];
181 | GCHandle gch = GCHandle.Alloc(listOfModules, GCHandleType.Pinned);
182 | IntPtr modulePointer = gch.AddrOfPinnedObject();
183 |
184 | uint uiSize = (uint)(Marshal.SizeOf(typeof(IntPtr)) * (listOfModules.Length));
185 | uint cbNeeded = 0;
186 |
187 | if (EnumProcessModules(processHandle, modulePointer, uiSize, out cbNeeded))
188 | {
189 | int numOfModules = (Int32)(cbNeeded / (Marshal.SizeOf(typeof(IntPtr))));
190 | for (int count = 0; count <= numOfModules; count++)
191 | {
192 | StringBuilder moduleName = new StringBuilder(1024);
193 | GetModuleFileNameEx(processHandle, listOfModules[count], moduleName, (int)(moduleName.Capacity));
194 | if (moduleName.ToString().Contains("amsi.dll"))
195 | {
196 | Boolean amsiIntegrityCheck = AmsiIntegrityCheck(processHandle, listOfModules[count], onDiskAmsiCodehash);
197 | //Boolean bypassFound = checkAmsiScanBufferBypass(processHandle, listOfModules[count]);
198 | gch.Free();
199 | return amsiIntegrityCheck;
200 | }
201 | }
202 | }
203 | gch.Free();
204 | return false;
205 | }
206 |
207 | // this method checks if any section of AmsiDll is tampered with by comparing the hash
208 | static Boolean AmsiIntegrityCheck(IntPtr processHandle, IntPtr amsiModuleHandle, String onDiskAmsiCodehash)
209 | {
210 | MODULEINFO amsiDLLInfo = new MODULEINFO();
211 | GetModuleInformation(processHandle, amsiModuleHandle, out amsiDLLInfo, (uint)(Marshal.SizeOf(typeof(MODULEINFO))));
212 | byte[] inMemoryAmsiDLL = new byte[amsiDLLInfo.SizeOfImage];
213 | int bytesRead = 0;
214 |
215 | ReadProcessMemory(processHandle, amsiModuleHandle, inMemoryAmsiDLL, inMemoryAmsiDLL.Length, ref bytesRead);
216 | PeHeaderReader amsiReader = new PeHeaderReader(inMemoryAmsiDLL);
217 |
218 | String inMemoryAmsiCodehash = getSectionHeaderofAmsi(amsiReader, true, inMemoryAmsiDLL);
219 |
220 | if (inMemoryAmsiCodehash.Equals(onDiskAmsiCodehash))
221 | {
222 | Console.WriteLine("hash matches");
223 | return false;
224 | }
225 | else
226 | {
227 | Console.WriteLine("Hash does not match");
228 | return true;
229 | }
230 | }
231 |
232 | // this method check if the AmsiScanBuffer is tampered with
233 | static Boolean checkAmsiScanBufferBypass(IntPtr processHandle, IntPtr amsiModuleHandle)
234 | {
235 | byte[] amsiBuffer = new byte[3];
236 | int bytesRead = 0;
237 | ReadProcessMemory(processHandle, (amsiModuleHandle + 9248 + 27), amsiBuffer, amsiBuffer.Length, ref bytesRead);
238 | if (amsiBuffer[0] == 49 && amsiBuffer[1] == 255 && amsiBuffer[2] == 144 )
239 | {
240 | return true;
241 | }
242 | if (amsiBuffer[0] !=65 && amsiBuffer[1] !=139 && amsiBuffer[2] !=248)
243 | {
244 | return true;
245 | }
246 | return false;
247 | }
248 | }
249 | }
250 |
251 |
252 |
--------------------------------------------------------------------------------
/detection/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("detection")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("detection")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4c736f07-fb70-453a-9d8e-acb036b4038d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/detection/detection.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4C736F07-FB70-453A-9D8E-ACB036B4038D}
8 | Exe
9 | detection
10 | detection
11 | v4.6.1
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\x64\Debug\
39 | DEBUG;TRACE
40 | full
41 | x64
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 | true
45 |
46 |
47 | bin\x64\Release\
48 | TRACE
49 | true
50 | pdbonly
51 | x64
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------