/// <summary> /// Loads a unmanged (native) DLL in the memory. /// </summary> /// <param name="data">Dll as a byte array</param> public MemoryModule(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } _headers = null; _codeBase = null; _pageSize = 0; _modules = new List <HCoustomMudule>(); _initialized = false; _exeEntry = null; _dllEntry = null; Disposed = false; _isRelocated = false; MemoryLoadLibrary(data); }
private void MemoryLoadLibrary(byte[] data) { IMAGE_DOS_HEADER32* dosHeader; IMAGE_NT_HEADERS32* ntHeader; IntPtr dllEntryPtr; byte* code, headers, dataPtr; uint locationDelta; this.dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); dataPtr = (byte*)this.dataHandle.AddrOfPinnedObject().ToPointer(); dosHeader = (IMAGE_DOS_HEADER32*)dataPtr; if (dosHeader->e_magic != NativeDeclarations.IMAGE_DOS_SIGNATURE) throw new BadImageFormatException("Not a valid executable file."); ntHeader = (IMAGE_NT_HEADERS32*)(dataPtr + dosHeader->e_lfanew); if (ntHeader->Signature != NativeDeclarations.IMAGE_NT_SIGNATURE) throw new BadImageFormatException("Not a valid PE file."); code = (byte*)NativeDeclarations.VirtualAlloc( new IntPtr(ntHeader->OptionalHeader.ImageBase), ntHeader->OptionalHeader.SizeOfImage, AllocationType.RESERVE, MemoryProtection.READWRITE).ToPointer(); if (code == null) { code = (byte*)NativeDeclarations.VirtualAlloc( IntPtr.Zero, ntHeader->OptionalHeader.SizeOfImage, AllocationType.RESERVE, MemoryProtection.READWRITE).ToPointer(); } if (code == null) throw new Win32Exception(); NativeDeclarations.VirtualAlloc( new IntPtr(code), ntHeader->OptionalHeader.SizeOfImage, AllocationType.COMMIT, MemoryProtection.READWRITE); this.codeBase = code; headers = (byte*)NativeDeclarations.VirtualAlloc( new IntPtr(code), ntHeader->OptionalHeader.SizeOfHeaders, AllocationType.COMMIT, MemoryProtection.READWRITE).ToPointer(); if (headers == null) throw new Win32Exception(); Marshal.Copy(data, 0, new IntPtr(headers), (int)(dosHeader->e_lfanew + ntHeader->OptionalHeader.SizeOfHeaders)); this.headers = (IMAGE_NT_HEADERS32*)&((byte*)(headers))[dosHeader->e_lfanew]; this.headers->OptionalHeader.ImageBase = (uint)code; this.CopySections(data, ntHeader); locationDelta = (uint)(code - ntHeader->OptionalHeader.ImageBase); if (locationDelta != 0) PerformBaseRelocation(locationDelta); this.BuildImportTable(); this.FinalizeSections(); if (this.headers->OptionalHeader.AddressOfEntryPoint == 0) throw new NativeDllLoadException("DLL has no entry point"); dllEntryPtr = new IntPtr(code + this.headers->OptionalHeader.AddressOfEntryPoint); this.dllEntry = (DllEntryDelegate)Marshal.GetDelegateForFunctionPointer(dllEntryPtr, typeof(DllEntryDelegate)); if (dllEntry(new IntPtr(code), DllReason.DLL_PROCESS_ATTACH, IntPtr.Zero)) this.initialized = true; else { this.initialized = false; throw new NativeDllLoadException("Can't attach DLL to process."); } }
private void MemoryLoadLibrary(byte[] data) { IMAGE_DOS_HEADER32 *dosHeader; IMAGE_NT_HEADERS32 *ntHeader; IntPtr dllEntryPtr; byte * code, headers, dataPtr; uint locationDelta; this.dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); dataPtr = (byte *)this.dataHandle.AddrOfPinnedObject().ToPointer(); dosHeader = (IMAGE_DOS_HEADER32 *)dataPtr; if (dosHeader->e_magic != NativeDeclarations.IMAGE_DOS_SIGNATURE) { throw new BadImageFormatException("Not a valid executable file."); } ntHeader = (IMAGE_NT_HEADERS32 *)(dataPtr + dosHeader->e_lfanew); if (ntHeader->Signature != NativeDeclarations.IMAGE_NT_SIGNATURE) { throw new BadImageFormatException("Not a valid PE file."); } code = (byte *)NativeDeclarations.VirtualAlloc( new IntPtr(ntHeader->OptionalHeader.ImageBase), ntHeader->OptionalHeader.SizeOfImage, AllocationType.RESERVE, MemoryProtection.READWRITE).ToPointer(); if (code == null) { code = (byte *)NativeDeclarations.VirtualAlloc( IntPtr.Zero, ntHeader->OptionalHeader.SizeOfImage, AllocationType.RESERVE, MemoryProtection.READWRITE).ToPointer(); } if (code == null) { throw new Win32Exception(); } NativeDeclarations.VirtualAlloc( new IntPtr(code), ntHeader->OptionalHeader.SizeOfImage, AllocationType.COMMIT, MemoryProtection.READWRITE); this.codeBase = code; headers = (byte *)NativeDeclarations.VirtualAlloc( new IntPtr(code), ntHeader->OptionalHeader.SizeOfHeaders, AllocationType.COMMIT, MemoryProtection.READWRITE).ToPointer(); if (headers == null) { throw new Win32Exception(); } Marshal.Copy(data, 0, new IntPtr(headers), (int)(dosHeader->e_lfanew + ntHeader->OptionalHeader.SizeOfHeaders)); this.headers = (IMAGE_NT_HEADERS32 *)&((byte *)(headers))[dosHeader->e_lfanew]; this.headers->OptionalHeader.ImageBase = (uint)code; this.CopySections(data, ntHeader); locationDelta = (uint)(code - ntHeader->OptionalHeader.ImageBase); if (locationDelta != 0) { PerformBaseRelocation(locationDelta); } this.BuildImportTable(); this.FinalizeSections(); if (this.headers->OptionalHeader.AddressOfEntryPoint == 0) { throw new NativeDllLoadException("DLL has no entry point"); } dllEntryPtr = new IntPtr(code + this.headers->OptionalHeader.AddressOfEntryPoint); this.dllEntry = (DllEntryDelegate)Marshal.GetDelegateForFunctionPointer(dllEntryPtr, typeof(DllEntryDelegate)); if (dllEntry(new IntPtr(code), DllReason.DLL_PROCESS_ATTACH, IntPtr.Zero)) { this.initialized = true; } else { this.initialized = false; throw new NativeDllLoadException("Can't attach DLL to process."); } }
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)); } } }
private void MemoryLoadLibrary(byte[] data) { IMAGE_DOS_HEADER * dosHeader; IMAGE_NT_HEADERS * oldHeader; IMAGE_SECTION_HEADER *section; SYSTEM_INFO systemInfo; void * dllEntryPtr; void * exeEntryPtr; byte * headers, dataPtr, code; SizeT optionalSectionSize; SizeT lastSectionEnd = 0; SizeT alignedImageSize; PtrDiffT locationDelta; _dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); if (!_dataHandle.IsAllocated) { throw new NativeDllLoadException("Can't allocate memory."); } dataPtr = (byte *)_dataHandle.AddrOfPinnedObject(); dosHeader = (IMAGE_DOS_HEADER *)dataPtr; if (dosHeader->e_magic != Win.IMAGE_DOS_SIGNATURE) { throw new BadImageFormatException("Not a valid executable file."); } oldHeader = (IMAGE_NT_HEADERS *)(dataPtr + dosHeader->e_lfanew); if (oldHeader->Signature != Win.IMAGE_NT_SIGNATURE) { throw new BadImageFormatException("Not a valid PE file."); } if (oldHeader->FileHeader.Machine != GetMachineType()) { throw new BadImageFormatException("Machine type doesn't fit. (i386 vs. AMD64)"); } if ((oldHeader->OptionalHeader.SectionAlignment & 1) > 0) { throw new BadImageFormatException("Wrong section alignment"); } section = Win.IMAGE_FIRST_SECTION(oldHeader); optionalSectionSize = oldHeader->OptionalHeader.SectionAlignment; for (int i = 0; i < oldHeader->FileHeader.NumberOfSections; i++, section++) { SizeT endOfSection; if (section->SizeOfRawData == 0) // Section without data in the DLL { endOfSection = section->VirtualAddress + optionalSectionSize; } else { endOfSection = section->VirtualAddress + section->SizeOfRawData; } if (endOfSection > lastSectionEnd) { lastSectionEnd = endOfSection; } } Win.GetNativeSystemInfo(&systemInfo); alignedImageSize = AlignValueUp(oldHeader->OptionalHeader.SizeOfImage, systemInfo.dwPageSize); if (alignedImageSize != AlignValueUp(lastSectionEnd, systemInfo.dwPageSize)) { throw new BadImageFormatException("Wrong section alignment."); } code = (byte *)Win.VirtualAlloc( (void *)(oldHeader->OptionalHeader.ImageBase), oldHeader->OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); if (code == null) { code = (byte *)Win.VirtualAlloc( null, oldHeader->OptionalHeader.SizeOfImage, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); } if (code == null) { throw new NativeDllLoadException("Out of Memory"); } #if WIN64 while ((((ulong)code) >> 32) < (((ulong)(code + alignedImageSize)) >> 32)) { _blockedMemory.Add((IntPtr)code); code = (byte *)Win.VirtualAlloc( null, alignedImageSize, AllocationType.RESERVE | AllocationType.COMMIT, MemoryProtection.READWRITE); if (code == null) { throw new NativeDllLoadException("Out of Memory"); } } #endif _pageSize = systemInfo.dwPageSize; _codeBase = code; IsDll = (oldHeader->FileHeader.Characteristics & Win.IMAGE_FILE_DLL) != 0; headers = (byte *)Win.VirtualAlloc( code, oldHeader->OptionalHeader.SizeOfHeaders, AllocationType.COMMIT, MemoryProtection.READWRITE); if (headers == null) { throw new NativeDllLoadException("Out of Memory"); } Marshal.Copy(data, 0, (IntPtr)headers, (int)(dosHeader->e_lfanew + oldHeader->OptionalHeader.SizeOfHeaders)); _headers = (IMAGE_NT_HEADERS *)&(headers)[dosHeader->e_lfanew]; _headers->OptionalHeader.ImageBase = (UIntPtrT)code; CopySections(data, oldHeader); locationDelta = (PtrDiffT)(_headers->OptionalHeader.ImageBase - oldHeader->OptionalHeader.ImageBase); if (locationDelta != 0) { _isRelocated = PerformBaseRelocation(locationDelta); } else { _isRelocated = true; } BuildImportTable(); FinalizeSections(); ExecuteTLS(); if (_headers->OptionalHeader.AddressOfEntryPoint == 0) { throw new NativeDllLoadException("DLL has no entry point"); } if (IsDll) { dllEntryPtr = code + _headers->OptionalHeader.AddressOfEntryPoint; _dllEntry = (DllEntryDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)dllEntryPtr, typeof(DllEntryDelegate)); if (_dllEntry != null && _dllEntry(code, DllReason.DLL_PROCESS_ATTACH, null)) { _initialized = true; } else { _initialized = false; throw new NativeDllLoadException("Can't attach DLL to process."); } } else { exeEntryPtr = code + _headers->OptionalHeader.AddressOfEntryPoint; _exeEntry = Marshal.GetDelegateForFunctionPointer <ExeEntryDelegate>((IntPtr)exeEntryPtr); } }