void MemoryLoadLibrary(byte[] data) { if (data.Length < Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))) { throw new DllException("Not a valid executable file"); } IMAGE_DOS_HEADER DosHeader = BytesReadStructAt <IMAGE_DOS_HEADER>(data, 0); if (DosHeader.e_magic != Win.IMAGE_DOS_SIGNATURE) { throw new BadImageFormatException("Not a valid executable file"); } if (data.Length < DosHeader.e_lfanew + Marshal.SizeOf(typeof(IMAGE_NT_HEADERS))) { throw new DllException("Not a valid executable file"); } IMAGE_NT_HEADERS OrgNTHeaders = BytesReadStructAt <IMAGE_NT_HEADERS>(data, DosHeader.e_lfanew); if (OrgNTHeaders.Signature != Win.IMAGE_NT_SIGNATURE) { throw new BadImageFormatException("Not a valid PE file"); } if (OrgNTHeaders.FileHeader.Machine != GetMachineType()) { throw new BadImageFormatException("Machine type doesn't fit (i386 vs. AMD64)"); } if ((OrgNTHeaders.OptionalHeader.SectionAlignment & 1) > 0) { throw new BadImageFormatException("Wrong section alignment"); //Only support multiple of 2 } if (OrgNTHeaders.OptionalHeader.AddressOfEntryPoint == 0) { throw new DllException("Module has no entry point"); } SYSTEM_INFO systemInfo; Win.GetNativeSystemInfo(out systemInfo); uint lastSectionEnd = 0; int ofSection = Win.IMAGE_FIRST_SECTION(DosHeader.e_lfanew, OrgNTHeaders.FileHeader.SizeOfOptionalHeader); for (int i = 0; i != OrgNTHeaders.FileHeader.NumberOfSections; i++, ofSection += Sz.IMAGE_SECTION_HEADER) { IMAGE_SECTION_HEADER Section = BytesReadStructAt <IMAGE_SECTION_HEADER>(data, ofSection); uint endOfSection = Section.VirtualAddress + (Section.SizeOfRawData > 0 ? Section.SizeOfRawData : OrgNTHeaders.OptionalHeader.SectionAlignment); if (endOfSection > lastSectionEnd) { lastSectionEnd = endOfSection; } } uint alignedImageSize = AlignValueUp(OrgNTHeaders.OptionalHeader.SizeOfImage, systemInfo.dwPageSize); uint alignedLastSection = AlignValueUp(lastSectionEnd, systemInfo.dwPageSize); if (alignedImageSize != alignedLastSection) { throw new BadImageFormatException("Wrong section alignment"); } IntPtr oldHeader_OptionalHeader_ImageBase; if (Is64BitProcess) { oldHeader_OptionalHeader_ImageBase = (IntPtr) unchecked ((long)(OrgNTHeaders.OptionalHeader.ImageBaseLong)); } else { oldHeader_OptionalHeader_ImageBase = (IntPtr) unchecked ((int)(OrgNTHeaders.OptionalHeader.ImageBaseLong >> 32)); } // reserve memory for image of library pCode = Win.VirtualAlloc(oldHeader_OptionalHeader_ImageBase, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); //pCode = IntPtr.Zero; //test relocation with this // try to allocate memory at arbitrary position if (pCode == IntPtr.Zero) { pCode = Win.VirtualAlloc(IntPtr.Zero, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); } if (pCode == IntPtr.Zero) { throw new DllException("Out of Memory"); } if (Is64BitProcess && PtrSpanBoundary(pCode, alignedImageSize, 32)) { // Memory block may not span 4 GB (32 bit) boundaries. System.Collections.Generic.List <IntPtr> BlockedMemory = new System.Collections.Generic.List <IntPtr>(); while (PtrSpanBoundary(pCode, alignedImageSize, 32)) { BlockedMemory.Add(pCode); pCode = Win.VirtualAlloc(IntPtr.Zero, (UIntPtr)alignedImageSize, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); if (pCode == IntPtr.Zero) { break; } } foreach (IntPtr ptr in BlockedMemory) { Win.VirtualFree(ptr, IntPtr.Zero, AllocationType.RELEASE); } if (pCode == IntPtr.Zero) { throw new DllException("Out of Memory"); } } // commit memory for headers IntPtr headers = Win.VirtualAlloc(pCode, (UIntPtr)OrgNTHeaders.OptionalHeader.SizeOfHeaders, AllocationType.COMMIT, MemoryProtection.READWRITE); if (headers == IntPtr.Zero) { throw new DllException("Out of Memory"); } // copy PE header to code Marshal.Copy(data, 0, headers, (int)(OrgNTHeaders.OptionalHeader.SizeOfHeaders)); pNTHeaders = PtrAdd(headers, DosHeader.e_lfanew); IntPtr locationDelta = PtrSub(pCode, oldHeader_OptionalHeader_ImageBase); if (locationDelta != IntPtr.Zero) { // update relocated position Marshal.OffsetOf(typeof(IMAGE_NT_HEADERS), "OptionalHeader"); Marshal.OffsetOf(typeof(IMAGE_OPTIONAL_HEADER), "ImageBaseLong"); IntPtr pImageBase = PtrAdd(pNTHeaders, Of.IMAGE_NT_HEADERS_OptionalHeader + (Is64BitProcess ? Of64.IMAGE_OPTIONAL_HEADER_ImageBase : Of32.IMAGE_OPTIONAL_HEADER_ImageBase)); PtrWrite(pImageBase, pCode); } // copy sections from DLL file block to new memory location CopySections(ref OrgNTHeaders, pCode, pNTHeaders, data); // adjust base address of imported data _isRelocated = (locationDelta != IntPtr.Zero ? PerformBaseRelocation(ref OrgNTHeaders, pCode, locationDelta) : true); // load required dlls and adjust function table of imports ImportModules = BuildImportTable(ref OrgNTHeaders, pCode); // mark memory pages depending on section headers and release // sections that are marked as "discardable" FinalizeSections(ref OrgNTHeaders, pCode, pNTHeaders, systemInfo.dwPageSize); // TLS callbacks are executed BEFORE the main loading ExecuteTLS(ref OrgNTHeaders, pCode, pNTHeaders); // get entry point of loaded library IsDll = ((OrgNTHeaders.FileHeader.Characteristics & Win.IMAGE_FILE_DLL) != 0); if (OrgNTHeaders.OptionalHeader.AddressOfEntryPoint != 0) { if (IsDll) { // notify library about attaching to process IntPtr dllEntryPtr = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.AddressOfEntryPoint); _dllEntry = (DllEntryDelegate)Marshal.GetDelegateForFunctionPointer(dllEntryPtr, typeof(DllEntryDelegate)); _initialized = (_dllEntry != null && _dllEntry(pCode, DllReason.DLL_PROCESS_ATTACH, IntPtr.Zero)); if (!_initialized) { throw new DllException("Can't attach DLL to process"); } } else { IntPtr exeEntryPtr = PtrAdd(pCode, OrgNTHeaders.OptionalHeader.AddressOfEntryPoint); _exeEntry = (ExeEntryDelegate)Marshal.GetDelegateForFunctionPointer(exeEntryPtr, typeof(ExeEntryDelegate)); } } }