protected virtual void Dispose() { if (dataHandle.IsAllocated) { dataHandle.Free(); } if (this.initialized) { this.dllEntry(new IntPtr(this.codeBase), DllReason.DLL_PROCESS_DETACH, IntPtr.Zero); this.initialized = false; } if (this.modules.Count > 0) { foreach (IntPtr module in this.modules) { if (module != new IntPtr(-1) || module != IntPtr.Zero) // INVALID_HANDLE { NativeDeclarations.FreeLibrary(module); } } } if (this.codeBase != null) { NativeDeclarations.VirtualFree(new IntPtr(this.codeBase), 0, AllocationType.RELEASE); } this.Disposed = true; }
private void BuildImportTable() { IMAGE_DATA_DIRECTORY *directory = &this.headers->OptionalHeader.ImportTable; if (directory->Size > 0) { IMAGE_IMPORT_DESCRIPTOR *importDesc = (IMAGE_IMPORT_DESCRIPTOR *)(this.codeBase + directory->VirtualAddress); for (; !NativeDeclarations.IsBadReadPtr(new IntPtr(importDesc), (uint)Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR))) && importDesc->Name > 0; importDesc++) { uint *thunkRef; int * funcRef; string funcName = Marshal.PtrToStringAnsi(new IntPtr(this.codeBase + importDesc->Name)); IntPtr handle = NativeDeclarations.LoadLibrary(funcName); if (handle == IntPtr.Zero) { throw new NativeDllLoadException("Can't load libary " + funcName); } this.modules.Add(handle); if (importDesc->OriginalFirstThunk > 0) { thunkRef = (uint *)(codeBase + importDesc->OriginalFirstThunk); funcRef = (int *)(codeBase + importDesc->FirstThunk); } else { // no hint table thunkRef = (uint *)(codeBase + importDesc->FirstThunk); funcRef = (int *)(codeBase + importDesc->FirstThunk); } for (; *thunkRef > 0; thunkRef++, funcRef++) { string procName; if (NativeDeclarations.IMAGE_SNAP_BY_ORDINAL32(*thunkRef)) { procName = Marshal.PtrToStringAnsi(new IntPtr(NativeDeclarations.IMAGE_ORDINAL32(*thunkRef))); *funcRef = (int)NativeDeclarations.GetProcAddress(handle, procName); } else { IMAGE_IMPORT_BY_NAME *thunkData = (IMAGE_IMPORT_BY_NAME *)(codeBase + (*thunkRef)); procName = Marshal.PtrToStringAnsi(new IntPtr(thunkData->Name)); *funcRef = (int)NativeDeclarations.GetProcAddress(handle, procName); } // if (*funcRef == 0) // throw new NativeDllLoadException("Can't get adress for " + procName); } } } }
void CopySections(byte[] data, IMAGE_NT_HEADERS32 *ntHeader) { if (data == null) { throw new ArgumentNullException("data"); } if (ntHeader->Signature != NativeDeclarations.IMAGE_NT_SIGNATURE) { throw new BadImageFormatException("Inavlid PE-Header"); } uint size; int *dest; IMAGE_SECTION_HEADER *section = NativeDeclarations.IMAGE_FIRST_SECTION(this.headers); for (int i = 0; i < this.headers->FileHeader.NumberOfSections; i++, section++) { if (section->SizeOfRawData == 0) { // section doesn't contain data in the dll itself, but may define // uninitialized data size = ntHeader->OptionalHeader.SectionAlignment; if (size > 0) { dest = (int *)NativeDeclarations.VirtualAlloc( new IntPtr(this.codeBase + section->VirtualAddress), size, AllocationType.COMMIT, MemoryProtection.READWRITE).ToPointer(); section->PhysicalAddress = (uint)dest; NativeDeclarations.MemSet(new IntPtr(dest), 0, new IntPtr(size)); } continue; } dest = (int *)NativeDeclarations.VirtualAlloc( new IntPtr((int)this.codeBase + section->VirtualAddress), section->SizeOfRawData, AllocationType.COMMIT, MemoryProtection.READWRITE).ToPointer(); Marshal.Copy(data, (int)section->PointerToRawData, new IntPtr(dest), (int)section->SizeOfRawData); section->PhysicalAddress = (uint)dest; } }
private void FinalizeSections() { int imageOffset = 0; IMAGE_SECTION_HEADER *section = (IMAGE_SECTION_HEADER *)NativeDeclarations.IMAGE_FIRST_SECTION(this.headers); for (int i = 0; i < this.headers->FileHeader.NumberOfSections; i++, section++) { uint protect, oldProtect, size; int executable = (section->Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0 ? 1 : 0; int readable = (section->Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_READ) != 0 ? 1 : 0; int writeable = (section->Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_WRITE) != 0 ? 1 : 0; if ((section->Characteristics & (int)ImageSectionFlags.IMAGE_SCN_MEM_DISCARDABLE) > 0) { NativeDeclarations.VirtualFree(new IntPtr(section->PhysicalAddress | (uint)imageOffset), section->SizeOfRawData, AllocationType.DECOMMIT); continue; } protect = (uint)ProtectionFlags[executable, readable, writeable]; if ((section->Characteristics & (uint)ImageSectionFlags.IMAGE_SCN_MEM_NOT_CACHED) > 0) { protect |= NativeDeclarations.PAGE_NOCACHE; } size = section->SizeOfRawData; if (size == 0) { if ((section->Characteristics & (uint)ImageSectionContains.INITIALIZED_DATA) > 0) { size = this.headers->OptionalHeader.SizeOfInitializedData; } else if ((section->Characteristics & (uint)ImageSectionContains.UNINITIALIZED_DATA) > 0) { size = this.headers->OptionalHeader.SizeOfUninitializedData; } } if (size > 0) { if (!NativeDeclarations.VirtualProtect(new IntPtr(section->PhysicalAddress | (uint)imageOffset), size, protect, out oldProtect)) { throw new Win32Exception("Can't change section access rights"); } } } }
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."); } }