Ejemplo n.º 1
0
 private static void FreePointerList(POINTER_LIST head, CustomFreeFunc freeMemory, void* userdata)
 {
     POINTER_LIST node = head;
     while (node != null)
     {
         POINTER_LIST next;
         freeMemory(node.address, null, MEM_RELEASE, userdata);
         next = node.next;
         node = next;
     }
 }
Ejemplo n.º 2
0
        internal static MEMORYMODULE MemoryLoadLibraryEx(void* data, void* size, CustomAllocFunc allocMemory, CustomFreeFunc freeMemory, CustomLoadLibraryFunc loadLibrary, CustomGetProcAddressFunc getProcAddress, CustomFreeLibraryFunc freeLibrary, void* userdata)
        {
            MEMORYMODULE result = null;
            IMAGE_DOS_HEADER* dos_header;
            void* old_header;
            byte* code, headers;
            void* locationDelta;
            SYSTEM_INFO sysInfo;
            IMAGE_SECTION_HEADER* section;
            uint i;
            void* optionalSectionSize;
            void* lastSectionEnd = null;
            void* alignedImageSize;
            POINTER_LIST blockedMemory = null;

            if (!CheckSize(size, (void*)IMAGE_DOS_HEADER.UnmanagedSize))
                return null;
            dos_header = (IMAGE_DOS_HEADER*)data;
            if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
                return null;

            if (!CheckSize(size, (void*)(dos_header->e_lfanew + (WIN64 ? IMAGE_NT_HEADERS64.UnmanagedSize : IMAGE_NT_HEADERS32.UnmanagedSize))))
                return null;
            old_header = &((byte*)data)[dos_header->e_lfanew];
            if ((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->Signature : ((IMAGE_NT_HEADERS32*)old_header)->Signature) != IMAGE_NT_SIGNATURE)
                return null;

            if ((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->FileHeader.Machine : ((IMAGE_NT_HEADERS32*)old_header)->FileHeader.Machine) != HOST_MACHINE)
                return null;

            if (((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SectionAlignment : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SectionAlignment) & 1) != 0)
                // Only support section alignments that are a multiple of 2
                return null;

            section = IMAGE_FIRST_SECTION(old_header);
            optionalSectionSize = (void*)((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SectionAlignment : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SectionAlignment));
            for (i = 0; i < (WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->FileHeader.NumberOfSections : ((IMAGE_NT_HEADERS32*)old_header)->FileHeader.NumberOfSections); i++, section++)
            {
                void* endOfSection;
                if (section->SizeOfRawData == 0)
                {
                    // Section without data in the DLL
                    endOfSection = (void*)(section->VirtualAddress + (ulong)optionalSectionSize);
                }
                else
                {
                    endOfSection = (void*)(section->VirtualAddress + (ulong)section->SizeOfRawData);
                }

                if ((ulong)endOfSection > (ulong)lastSectionEnd)
                    lastSectionEnd = endOfSection;
            }

            GetNativeSystemInfo(&sysInfo);
            alignedImageSize = AlignValueUp((void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfImage : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfImage), (void*)sysInfo.dwPageSize);
            if (alignedImageSize != AlignValueUp(lastSectionEnd, (void*)sysInfo.dwPageSize))
                return null;

            // reserve memory for image of library
            // XXX: is it correct to commit the complete memory region at once?
            //      calling DllEntry raises an exception if we don't...
            code = (byte*)allocMemory((void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.ImageBase : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, userdata);

            if (code == null)
            {
                // try to allocate memory at arbitrary position
                code = (byte*)allocMemory(null, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, userdata);
                if (code == null)
                    return null;
            }

            if (WIN64)
            {
                // Memory block may not span 4 GB boundaries.
                while ((ulong)code >> 32 < ((ulong)code + (ulong)alignedImageSize) >> 32)
                {
                    POINTER_LIST node = new POINTER_LIST
                    {
                        next = blockedMemory,
                        address = code
                    };
                    blockedMemory = node;

                    code = (byte*)allocMemory(null, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE, userdata);
                    if (code == null)
                    {
                        FreePointerList(blockedMemory, freeMemory, userdata);
                        return null;
                    }
                }
            }

            result = new MEMORYMODULE
            {
                codeBase = code,
                isDLL = ((WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->FileHeader.Characteristics : ((IMAGE_NT_HEADERS32*)old_header)->FileHeader.Characteristics) & IMAGE_FILE_DLL) != 0,
                alloc = allocMemory,
                free = freeMemory,
                loadLibrary = loadLibrary,
                getProcAddress = getProcAddress,
                freeLibrary = freeLibrary,
                userdata = userdata,
                pageSize = sysInfo.dwPageSize
            };
            if (WIN64)
                result.blockedMemory = blockedMemory;

            if (!CheckSize(size, (void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfHeaders : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfHeaders)))
                goto error;

            // commit memory for headers
            headers = (byte*)allocMemory(code, (void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfHeaders : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfHeaders), MEM_COMMIT, PAGE_READWRITE, userdata);

            // copy PE header to code
            memcpy(headers, dos_header, (void*)(WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.SizeOfHeaders : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.SizeOfHeaders));
            result.headers = &headers[dos_header->e_lfanew];

            // update position
            if (WIN64)
                ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.ImageBase = (ulong)code;
            else
                ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.ImageBase = (uint)code;

            // copy sections from DLL file block to new memory location
            if (!CopySections((byte*)data, size, old_header, result))
                goto error;

            // adjust base address of imported data
            locationDelta = (void*)((WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.ImageBase : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.ImageBase) - (WIN64 ? ((IMAGE_NT_HEADERS64*)old_header)->OptionalHeader.ImageBase : ((IMAGE_NT_HEADERS32*)old_header)->OptionalHeader.ImageBase));
            if ((ulong)locationDelta != 0)
                result.isRelocated = PerformBaseRelocation(result, locationDelta);
            else
                result.isRelocated = true;

            // load required dlls and adjust function table of imports
            if (!BuildImportTable(result))
                goto error;

            // mark memory pages depending on section headers and release
            // sections that are marked as "discardable"
            if (!FinalizeSections(result))
                goto error;

            // TLS callbacks are executed BEFORE the main loading
            if (!ExecuteTLS(result))
                goto error;

            // get entry point of loaded library
            if ((WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.AddressOfEntryPoint) != 0)
            {
                if (result.isDLL)
                {
                    DllEntryProc DllEntry = (DllEntryProc)Marshal.GetDelegateForFunctionPointer((IntPtr)(code + (WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.AddressOfEntryPoint)), typeof(DllEntryProc));
                    // notify library about attaching to process
                    bool successfull = DllEntry(code, DLL_PROCESS_ATTACH, null);
                    if (!successfull)
                        goto error;
                    result.initialized = true;
                }
                else
                    result.exeEntry = (ExeEntryProc)Marshal.GetDelegateForFunctionPointer((IntPtr)(code + (WIN64 ? ((IMAGE_NT_HEADERS64*)result.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32*)result.headers)->OptionalHeader.AddressOfEntryPoint)), typeof(ExeEntryProc));
            }
            else
                result.exeEntry = null;

            return result;

            error:
            // cleanup
            MemoryFreeLibrary(result);
            return null;
        }