Пример #1
0
        private static void *GetRealSectionSize(MEMORYMODULE module, IMAGE_SECTION_HEADER *section)
        {
            uint size = section->SizeOfRawData;

            if (size == 0)
            {
                if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) != 0)
                {
                    size = (WIN64 ? ((IMAGE_NT_HEADERS64 *)module.headers)->OptionalHeader.SizeOfInitializedData : ((IMAGE_NT_HEADERS32 *)module.headers)->OptionalHeader.SizeOfInitializedData);
                }
                else if ((section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0)
                {
                    size = (WIN64 ? ((IMAGE_NT_HEADERS64 *)module.headers)->OptionalHeader.SizeOfUninitializedData : ((IMAGE_NT_HEADERS32 *)module.headers)->OptionalHeader.SizeOfUninitializedData);
                }
            }
            return((void *)size);
        }
Пример #2
0
        public static void MemoryFreeLibrary(MEMORYMODULE mod)
        {
            MEMORYMODULE module = mod;

            if (module == null)
            {
                return;
            }
            if (module.initialized)
            {
                // notify library about detaching from process
                DllEntryProc DllEntry = (DllEntryProc)Marshal.GetDelegateForFunctionPointer((IntPtr)(module.codeBase + (WIN64 ? ((IMAGE_NT_HEADERS64 *)module.headers)->OptionalHeader.AddressOfEntryPoint : ((IMAGE_NT_HEADERS32 *)module.headers)->OptionalHeader.AddressOfEntryPoint)), typeof(DllEntryProc));
                DllEntry(module.codeBase, DLL_PROCESS_DETACH, null);
            }

            if (module.modules != null)
            {
                // free previously opened libraries
                int i;
                for (i = 0; i < module.numModules; i++)
                {
                    if ((void *)((IntPtr *)module.modules)[i] != null)
                    {
                        module.freeLibrary((void *)((IntPtr *)module.modules)[i], module.userdata);
                    }
                }

                free(module.modules);
            }

            if (module.codeBase != null)
            {
                // release memory of library
                module.free(module.codeBase, null, MEM_RELEASE, module.userdata);
            }

            if (WIN64)
            {
                FreePointerList(module.blockedMemory, module.free, module.userdata);
            }
        }
Пример #3
0
        private static bool FinalizeSection(MEMORYMODULE module, SECTIONFINALIZEDATA sectionData)
        {
            uint protect, oldProtect;
            bool executable;
            bool readable;
            bool writeable;

            if (sectionData.size == null)
            {
                return(true);
            }

            if ((sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
            {
                // section is not needed any more and can safely be freed
                if (sectionData.address == sectionData.alignedAddress && (sectionData.last || (WIN64 ? ((IMAGE_NT_HEADERS64 *)module.headers)->OptionalHeader.SectionAlignment : ((IMAGE_NT_HEADERS32 *)module.headers)->OptionalHeader.SectionAlignment) == module.pageSize || ((ulong)sectionData.size % module.pageSize) == 0))
                {
                    // Only allowed to decommit whole pages
                    module.free(sectionData.address, sectionData.size, MEM_DECOMMIT, module.userdata);
                }
                return(true);
            }

            // determine protection flags based on characteristics
            executable = (sectionData.characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
            readable   = (sectionData.characteristics & IMAGE_SCN_MEM_READ) != 0;
            writeable  = (sectionData.characteristics & IMAGE_SCN_MEM_WRITE) != 0;
            protect    = ProtectionFlags[executable ? 1 : 0, readable ? 1 : 0, writeable ? 1 : 0];
            if ((sectionData.characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0)
            {
                protect |= PAGE_NOCACHE;
            }

            // change memory access flags
            if (!VirtualProtect(sectionData.address, sectionData.size, protect, &oldProtect))
            {
                return(false);
            }

            return(true);
        }
Пример #4
0
        public static void *MemoryFindResourceEx(MEMORYMODULE module, string s_name, string s_type, ushort language, bool unicode)
        {
            byte *name;
            byte *type;

            if (unicode)
            {
                fixed(char *p = s_name.ToCharArray())
                name = (byte *)p;

                fixed(char *p = s_type.ToCharArray())
                type = (byte *)p;
            }
            else
            {
                fixed(byte *p = Encoding.Convert(Encoding.Unicode, Encoding.ASCII, Encoding.Unicode.GetBytes(s_name)))
                name = p;

                fixed(byte *p = Encoding.Convert(Encoding.Unicode, Encoding.ASCII, Encoding.Unicode.GetBytes(s_type)))
                type = p;
            }
            return(MemoryFindResourceEx(module, name, type, language, unicode));
        }
Пример #5
0
        private static bool ExecuteTLS(MEMORYMODULE module)
        {
            byte* codeBase = module.codeBase;
            IMAGE_TLS_DIRECTORY tls;
            void** callback;

            IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS);
            if (directory->VirtualAddress == 0)
            {
                return true;
            }

            tls = *(IMAGE_TLS_DIRECTORY*)((ulong)codeBase + directory->VirtualAddress);
            callback = (void**)tls.AddressOfCallBacks;
            if (callback != null)
            {
                while (*callback != null)
                {
                    ((IMAGE_TLS_CALLBACK)Marshal.GetDelegateForFunctionPointer((IntPtr)(*callback), typeof(IMAGE_TLS_CALLBACK)))((void*)codeBase, DLL_PROCESS_ATTACH, null);
                    callback++;
                }
            }
            return true;
        }
Пример #6
0
        internal static void* MemoryGetProcAddress(MEMORYMODULE mod, byte* name)
        {
            MEMORYMODULE module = mod;
            byte* codeBase = module.codeBase;
            uint idx = 0;
            IMAGE_EXPORT_DIRECTORY* exports;
            IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT);
            if (directory->Size == 0)
                // no export table found
                return null;

            exports = (IMAGE_EXPORT_DIRECTORY*)(codeBase + directory->VirtualAddress);
            if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0)
                // DLL doesn't export anything
                return null;

            if (HIWORD(name) == 0)
            {
                // load function by ordinal value
                if (LOWORD(name) < exports->Base)
                    return null;

                idx = LOWORD(name) - exports->Base;
            }
            else if (exports->NumberOfNames == 0)
                return null;
            else
            {
                ExportNameEntry found;

                // Lazily build name table and sort it by names
                if (module.nameExportsTable == null)
                {
                    uint i;
                    uint* nameRef = (uint*)(codeBase + exports->AddressOfNames);
                    ushort* ordinal = (ushort*)(codeBase + exports->AddressOfNameOrdinals);
                    ExportNameEntry[] entry = new ExportNameEntry[exports->NumberOfNames];
                    module.nameExportsTable = entry;
                    for (i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++)
                        entry[i] = new ExportNameEntry
                        {
                            name = codeBase + (*nameRef),
                            idx = *ordinal
                        };
                    Array.Sort(module.nameExportsTable, _compare);
                }

                // search function name in list of exported names with binary search
                ExportNameEntry tmp = new ExportNameEntry { name = name };
                int foundIndex = Array.BinarySearch(module.nameExportsTable, tmp, tmp);
                found = foundIndex < 0 ? null : module.nameExportsTable[foundIndex];
                if (found == null)
                    // exported symbol not found
                    return null;

                idx = found.idx;
            }

            if (idx > exports->NumberOfFunctions)
                // name <. ordinal number don't match
                return null;

            // AddressOfFunctions contains the RVAs to the "real" functions
            return (void*)(codeBase + (*(uint*)(codeBase + exports->AddressOfFunctions + (idx * 4))));
        }
Пример #7
0
 internal static void* MemoryGetProcAddress(MEMORYMODULE mod, string s_name)
 {
     fixed (byte* p = Encoding.Convert(Encoding.Unicode, Encoding.ASCII, Encoding.Unicode.GetBytes(s_name)))
         return MemoryGetProcAddress(mod, p);
 }
Пример #8
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;
        }
Пример #9
0
        private static bool BuildImportTable(MEMORYMODULE module)
        {
            byte* codeBase = module.codeBase;
            IMAGE_IMPORT_DESCRIPTOR* importDesc;
            bool result = true;

            IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
            if (directory->Size == 0)
            {
                return true;
            }

            importDesc = (IMAGE_IMPORT_DESCRIPTOR*)(codeBase + directory->VirtualAddress);
            for (; !IsBadReadPtr(importDesc, (void*)IMAGE_IMPORT_DESCRIPTOR.UnmanagedSize) && importDesc->Name != 0; importDesc++)
            {
                void** thunkRef;
                void** funcRef;
                void** tmp;
                void* handle = module.loadLibrary(codeBase + importDesc->Name, module.userdata);
                if (handle == null)
                {
                    result = false;
                    break;
                }

                tmp = (void**)realloc(module.modules, (void*)((module.numModules + 1) * sizeof(void*)));
                if (tmp == null)
                {
                    module.freeLibrary(handle, module.userdata);
                    result = false;
                    break;
                }
                module.modules = tmp;

                module.modules[module.numModules++] = handle;
                if (importDesc->OriginalFirstThunk != 0)
                {
                    thunkRef = (void**)(codeBase + importDesc->OriginalFirstThunk);
                    funcRef = (void**)(codeBase + importDesc->FirstThunk);
                }
                else
                {
                    // no hint table
                    thunkRef = (void**)(codeBase + importDesc->FirstThunk);
                    funcRef = (void**)(codeBase + importDesc->FirstThunk);
                }
                for (; *thunkRef != null; thunkRef++, funcRef++)
                {
                    if (IMAGE_SNAP_BY_ORDINAL(*thunkRef))
                    {
                        *funcRef = module.getProcAddress(handle, (byte*)IMAGE_ORDINAL(*thunkRef), module.userdata);
                    }
                    else
                    {
                        IMAGE_IMPORT_BY_NAME* thunkData = (IMAGE_IMPORT_BY_NAME*)(codeBase + (ulong)(*thunkRef));
                        *funcRef = module.getProcAddress(handle, thunkData->Name, module.userdata);
                    }
                    if (*funcRef == null)
                    {
                        result = false;
                        break;
                    }
                }

                if (!result)
                {
                    module.freeLibrary(handle, module.userdata);
                    break;
                }
            }

            return result;
        }
Пример #10
0
 private static IMAGE_DATA_DIRECTORY* GET_HEADER_DICTIONARY(MEMORYMODULE module, uint idx)
 {
     return WIN64 ? (IMAGE_DATA_DIRECTORY*)&((IMAGE_NT_HEADERS64*)module.headers)->OptionalHeader.DataDirectory[idx] : (IMAGE_DATA_DIRECTORY*)&((IMAGE_NT_HEADERS32*)module.headers)->OptionalHeader.DataDirectory[idx];
 }
Пример #11
0
 private MemoryModule(MEMORYMODULE internalModule) => _internalModule = internalModule;
Пример #12
0
 public static int MemoryLoadString(MEMORYMODULE module, uint id, out string buffer, int maxsize, bool unicode)
 {
     return(MemoryLoadStringEx(module, id, out buffer, maxsize, DEFAULT_LANGUAGE, unicode));
 }
Пример #13
0
 public static void *MemoryFindResource(MEMORYMODULE module, string name, string type, bool unicode)
 {
     return(MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE, unicode));
 }