예제 #1
0
        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;
        }
예제 #2
0
        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);
        }
예제 #3
0
        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");
            }
        }
예제 #4
0
        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;
            }
        }
예제 #5
0
        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.");
                    }
                }
            }
        }
예제 #6
0
        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);
            }
        }