protected virtual void Dispose() { if (_dataHandle.IsAllocated) { _dataHandle.Free(); } if (_initialized) { _dllEntry?.Invoke(_codeBase, DllReason.DLL_PROCESS_DETACH, null); _initialized = false; } if (_modules.Count > 0) { foreach (HCoustomMudule module in _modules) { if (!InvalidHandle(module)) // INVALID_HANDLE { Win.FreeLibrary(module); } } } if (_codeBase != null) { Win.VirtualFree(_codeBase, 0, AllocationType.RELEASE); } Disposed = true; }
private void FinalizeSections() { IMAGE_SECTION_HEADER *section = Win.IMAGE_FIRST_SECTION(_headers); #if WIN64 UIntPtrT imageOffset = ((UIntPtrT)_headers->OptionalHeader.ImageBase & 0xffffffff00000000); #elif WIN32 UIntPtrT imageOffset = 0; #endif SectionFinalizeData sectionData = new SectionFinalizeData(); sectionData.Address = (void *)(section->PhysicalAddress | imageOffset); sectionData.AlignedAddress = AlignAddressDown(sectionData.Address, _pageSize); sectionData.Size = GetRealSectionSize(section); sectionData.Characteristics = section->Characteristics; sectionData.Last = false; section++; // loop through all sections and change access flags for (int i = 1; i < _headers->FileHeader.NumberOfSections; i++, section++) { void *sectionAddress = (void *)(section->PhysicalAddress | imageOffset); void *alignedAddress = AlignAddressDown(sectionAddress, _pageSize); SizeT sectionSize = GetRealSectionSize(section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section // with the page of a first small section. This should be optimized. if (sectionData.AlignedAddress == alignedAddress || (UIntPtrT)sectionData.Address + sectionData.Size > (UIntPtrT)alignedAddress) { // Section shares page with previous if ((section->Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) == 0) { sectionData.Characteristics = (sectionData.Characteristics | section->Characteristics) & ~Win.IMAGE_SCN_MEM_DISCARDABLE; } else { sectionData.Characteristics |= section->Characteristics; } sectionData.Size = (((UIntPtrT)sectionAddress) + (sectionSize)) - (UIntPtrT)sectionData.Address; continue; } FinalizeSection(sectionData); sectionData.Address = sectionAddress; sectionData.AlignedAddress = alignedAddress; sectionData.Size = sectionSize; sectionData.Characteristics = section->Characteristics; } sectionData.Last = true; FinalizeSection(sectionData); }
private void FinalizeSection(SectionFinalizeData sectionData) { uint protect, oldProtect; int executable; int readable; int writeable; if (sectionData.Size == 0) { return; } if ((sectionData.Characteristics & Win.IMAGE_SCN_MEM_DISCARDABLE) > 0) { // section is not needed any more and can safely be freed if (sectionData.Address == sectionData.AlignedAddress && (sectionData.Last || _headers->OptionalHeader.SectionAlignment == _pageSize || (sectionData.Size % _pageSize) == 0) ) { // Only allowed to decommit whole pages Win.VirtualFree(sectionData.Address, sectionData.Size, AllocationType.DECOMMIT); } return; } // determine protection flags based on characteristics executable = (sectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0 ? 1 : 0; readable = (sectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_READ) != 0 ? 1 : 0; writeable = (sectionData.Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_WRITE) != 0 ? 1 : 0; protect = (uint)ProtectionFlags[executable, readable, writeable]; if ((sectionData.Characteristics & Win.IMAGE_SCN_MEM_NOT_CACHED) > 0) { protect |= Win.PAGE_NOCACHE; } // change memory access flags if (!Win.VirtualProtect(sectionData.Address, sectionData.Size, protect, out oldProtect)) { throw new NativeDllLoadException("Error protecting memory page"); } }
void CopySections(byte[] data, IMAGE_NT_HEADERS *oldHeader) { if (data == null) { throw new ArgumentNullException("data"); } if (oldHeader->Signature != Win.IMAGE_NT_SIGNATURE) { throw new BadImageFormatException("Invalid PE-Header"); } uint size; byte *dest; IMAGE_SECTION_HEADER *section = Win.IMAGE_FIRST_SECTION(_headers); for (int i = 0; i < _headers->FileHeader.NumberOfSections; i++, section++) { if (section->SizeOfRawData == 0) { // section doesn't contain data in the dll itself, but may define // uninitialized data size = oldHeader->OptionalHeader.SectionAlignment; if (size > 0) { dest = (byte *)Win.VirtualAlloc( _codeBase + section->VirtualAddress, size, AllocationType.COMMIT, MemoryProtection.READWRITE); if (dest == null) { throw new NativeDllLoadException("Unable to allocate memory."); } dest = _codeBase + section->VirtualAddress; section->PhysicalAddress = (uint)dest & 0xffffffff; Win.MemSet(dest, 0, (void *)size); } continue; } dest = (byte *)Win.VirtualAlloc( _codeBase + section->VirtualAddress, section->SizeOfRawData, AllocationType.COMMIT, MemoryProtection.READWRITE); if (dest == null) { throw new NativeDllLoadException("Out of memory."); } dest = _codeBase + section->VirtualAddress; Marshal.Copy(data, (int)section->PointerToRawData, (IntPtr)dest, (int)section->SizeOfRawData); section->PhysicalAddress = (uint)dest & 0xffffffff; } }
private void BuildImportTable() { IMAGE_DATA_DIRECTORY *directory = &_headers->OptionalHeader.ImportTable; if (directory->Size == 0) { throw new NativeDllLoadException("Invalid import table."); } IMAGE_IMPORT_DESCRIPTOR *importDesc = (IMAGE_IMPORT_DESCRIPTOR *)(_codeBase + directory->VirtualAddress); for (; !Win.IsBadReadPtr((importDesc), (UIntPtrT)Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR))) && importDesc->Name > 0; importDesc++) { UIntPtrT *thunkRef; Farproc * funcRef; HCoustomMudule handle = Win.LoadLibrary(_codeBase + importDesc->Name); if (InvalidHandle(handle)) { if (_modules.Any()) { _modules.ForEach(m => Win.FreeLibrary(m)); } throw new NativeDllLoadException("Can't load libary " + Marshal.PtrToStringAnsi(new IntPtr(_codeBase + importDesc->Name))); } _modules.Add(handle); if (importDesc->OriginalFirstThunk > 0) { thunkRef = (UIntPtrT *)(_codeBase + importDesc->OriginalFirstThunk); funcRef = (Farproc *)(_codeBase + importDesc->FirstThunk); } else { // no hint table thunkRef = (UIntPtrT *)(_codeBase + importDesc->FirstThunk); funcRef = (Farproc *)(_codeBase + importDesc->FirstThunk); } for (; *thunkRef > 0; thunkRef++, funcRef++) { string procName; if (Win.IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { procName = Marshal.PtrToStringAnsi(new IntPtr()); *funcRef = (Farproc)Win.GetProcAddress(handle, (byte *)Win.IMAGE_ORDINAL(*thunkRef)); } else { IMAGE_IMPORT_BY_NAME *thunkData = (IMAGE_IMPORT_BY_NAME *)(_codeBase + (*thunkRef)); *funcRef = (Farproc)Win.GetProcAddress(handle, thunkData->Name); } if (*funcRef == 0) { throw new NativeDllLoadException("Can't get adress for imported function."); } } } }
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); } }