Ejemplo n.º 1
0
        internal unsafe static MemoryMappedView CreateView(SafeMemoryMappedFileHandle memMappedFileHandle,
                                                           MemoryMappedFileAccess access, Int64 offset, Int64 size)
        {
            // MapViewOfFile can only create views that start at a multiple of the system memory allocation
            // granularity. We decided to hide this restriction form the user by creating larger views than the
            // user requested and hiding the parts that the user did not request.  extraMemNeeded is the amount of
            // extra memory we allocate before the start of the requested view. MapViewOfFile will also round the
            // capacity of the view to the nearest multiple of the system page size.  Once again, we hide this
            // from the user by preventing them from writing to any memory that they did not request.
            ulong extraMemNeeded = (ulong)offset % (ulong)MemoryMappedFile.GetSystemPageAllocationGranularity();

            // newOffset takes into account the fact that we have some extra memory allocated before the requested view
            ulong newOffset = (ulong)offset - extraMemNeeded;

            Debug.Assert(newOffset >= 0, "newOffset = (offset - extraMemNeeded) < 0");

            // determine size to pass to MapViewOfFile
            ulong nativeSize;

            if (size != MemoryMappedFile.DefaultSize)
            {
                nativeSize = (ulong)size + (ulong)extraMemNeeded;
            }
            else
            {
                nativeSize = 0;
            }

            if (IntPtr.Size == 4 && nativeSize > UInt32.MaxValue)
            {
                throw new ArgumentOutOfRangeException("size", SR.GetString(SR.ArgumentOutOfRange_CapacityLargerThanLogicalAddressSpaceNotAllowed));
            }

            // if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message
            // "the parameter is incorrect"; this provides better error message in advance
            UnsafeNativeMethods.MEMORYSTATUSEX memStatus = new UnsafeNativeMethods.MEMORYSTATUSEX();
            bool  result       = UnsafeNativeMethods.GlobalMemoryStatusEx(ref memStatus);
            ulong totalVirtual = memStatus.ullTotalVirtual;

            if (nativeSize >= totalVirtual)
            {
                throw new IOException(SR.GetString(SR.IO_NotEnoughMemory));
            }

            // split the Int64 into two ints
            uint offsetLow  = (uint)(newOffset & 0x00000000FFFFFFFFL);
            uint offsetHigh = (uint)(newOffset >> 32);

            // create the view
            SafeMemoryMappedViewHandle viewHandle = UnsafeNativeMethods.MapViewOfFile(memMappedFileHandle,
                                                                                      MemoryMappedFile.GetFileMapAccess(access), offsetHigh, offsetLow, new UIntPtr(nativeSize));

            if (viewHandle.IsInvalid)
            {
                __Error.WinIOError(Marshal.GetLastWin32Error(), String.Empty);
            }

            // Query the view for its size and allocation type
            UnsafeNativeMethods.MEMORY_BASIC_INFORMATION viewInfo = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
            UnsafeNativeMethods.VirtualQuery(viewHandle, ref viewInfo, (IntPtr)Marshal.SizeOf(viewInfo));
            ulong viewSize = (ulong)viewInfo.RegionSize;


            // Allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
            // OR check if the allocated view size is smaller than the expected native size
            // If multiple overlapping views are created over the file mapping object, the pages in a given region
            // could have different attributes(MEM_RESERVE OR MEM_COMMIT) as MapViewOfFile preserves coherence between
            // views created on a mapping object backed by same file.
            // In which case, the viewSize will be smaller than nativeSize required and viewState could be MEM_COMMIT
            // but more pages may need to be committed in the region.
            // This is because, VirtualQuery function(that internally invokes VirtualQueryEx function) returns the attributes
            // and size of the region of pages with matching attributes starting from base address.
            // VirtualQueryEx: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx
            if (((viewInfo.State & UnsafeNativeMethods.MEM_RESERVE) != 0) || (viewSize < nativeSize))
            {
                ulong  allocSize  = (nativeSize == 0) ? viewSize : nativeSize;
                IntPtr tempHandle = UnsafeNativeMethods.VirtualAlloc(viewHandle, (UIntPtr)allocSize, UnsafeNativeMethods.MEM_COMMIT,
                                                                     MemoryMappedFile.GetPageAccess(access));
                int lastError = Marshal.GetLastWin32Error();
                // The following is commented out for backward compatibility.
                // Previously releases failed to check for this error so introducing this check
                // could cause new/different exceptions in existing code paths.
                // if (tempHandle == IntPtr.Zero) {
                //     __Error.WinIOError(lastError, String.Empty);
                // }

                // again query the view for its new size
                viewInfo = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
                UnsafeNativeMethods.VirtualQuery(viewHandle, ref viewInfo, (IntPtr)Marshal.SizeOf(viewInfo));
                viewSize = (ulong)viewInfo.RegionSize;
            }

            // if the user specified DefaultSize as the size, we need to get the actual size
            if (size == MemoryMappedFile.DefaultSize)
            {
                size = (Int64)(viewSize - extraMemNeeded);
            }
            else
            {
                Debug.Assert(viewSize >= (ulong)size, "viewSize < size");
            }

            viewHandle.Initialize((ulong)size + extraMemNeeded);
            MemoryMappedView mmv = new MemoryMappedView(viewHandle, (long)extraMemNeeded, size, access);

            return(mmv);
        }
Ejemplo n.º 2
0
        internal unsafe static MemoryMappedView CreateView(SafeMemoryMappedFileHandle memMappedFileHandle,
                                                           MemoryMappedFileAccess access, Int64 offset, Int64 size)
        {
            // MapViewOfFile can only create views that start at a multiple of the system memory allocation
            // granularity. We decided to hide this restriction form the user by creating larger views than the
            // user requested and hiding the parts that the user did not request.  extraMemNeeded is the amount of
            // extra memory we allocate before the start of the requested view. MapViewOfFile will also round the
            // capacity of the view to the nearest multiple of the system page size.  Once again, we hide this
            // from the user by preventing them from writing to any memory that they did not request.
            ulong extraMemNeeded = (ulong)offset % (ulong)MemoryMappedFile.GetSystemPageAllocationGranularity();

            // newOffset takes into account the fact that we have some extra memory allocated before the requested view
            ulong newOffset = (ulong)offset - extraMemNeeded;

            Debug.Assert(newOffset >= 0, "newOffset = (offset - extraMemNeeded) < 0");

            // determine size to pass to MapViewOfFile
            ulong nativeSize;

            if (size != MemoryMappedFile.DefaultSize)
            {
                nativeSize = (ulong)size + (ulong)extraMemNeeded;
            }
            else
            {
                nativeSize = 0;
            }

            if (IntPtr.Size == 4 && nativeSize > UInt32.MaxValue)
            {
                throw new ArgumentOutOfRangeException("size", SR.GetString(SR.ArgumentOutOfRange_CapacityLargerThanLogicalAddressSpaceNotAllowed));
            }

            // if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message
            // "the parameter is incorrect"; this provides better error message in advance
            UnsafeNativeMethods.MEMORYSTATUSEX memStatus = new UnsafeNativeMethods.MEMORYSTATUSEX();
            bool  result       = UnsafeNativeMethods.GlobalMemoryStatusEx(memStatus);
            ulong totalVirtual = memStatus.ullTotalVirtual;

            if (nativeSize >= totalVirtual)
            {
                throw new IOException(SR.GetString(SR.IO_NotEnoughMemory));
            }

            // split the Int64 into two ints
            uint offsetLow  = (uint)(newOffset & 0x00000000FFFFFFFFL);
            uint offsetHigh = (uint)(newOffset >> 32);

            // create the view
            SafeMemoryMappedViewHandle viewHandle = UnsafeNativeMethods.MapViewOfFile(memMappedFileHandle,
                                                                                      MemoryMappedFile.GetFileMapAccess(access), offsetHigh, offsetLow, new UIntPtr(nativeSize));

            if (viewHandle.IsInvalid)
            {
                __Error.WinIOError(Marshal.GetLastWin32Error(), String.Empty);
            }

            // Query the view for its size and allocation type
            UnsafeNativeMethods.MEMORY_BASIC_INFORMATION viewInfo = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
            UnsafeNativeMethods.VirtualQuery(viewHandle, ref viewInfo, (IntPtr)Marshal.SizeOf(viewInfo));
            ulong viewSize = (ulong)viewInfo.RegionSize;


            // allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
            if ((viewInfo.State & UnsafeNativeMethods.MEM_RESERVE) != 0)
            {
                IntPtr tempHandle = UnsafeNativeMethods.VirtualAlloc(viewHandle, (UIntPtr)viewSize, UnsafeNativeMethods.MEM_COMMIT,
                                                                     MemoryMappedFile.GetPageAccess(access));
                int lastError = Marshal.GetLastWin32Error();
                if (viewHandle.IsInvalid)
                {
                    __Error.WinIOError(lastError, String.Empty);
                }
            }

            // if the user specified DefaultSize as the size, we need to get the actual size
            if (size == MemoryMappedFile.DefaultSize)
            {
                size = (Int64)(viewSize - extraMemNeeded);
            }
            else
            {
                Debug.Assert(viewSize >= (ulong)size, "viewSize < size");
            }

            viewHandle.Initialize((ulong)size + extraMemNeeded);
            MemoryMappedView mmv = new MemoryMappedView(viewHandle, (long)extraMemNeeded, size, access);

            return(mmv);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Installs an Import Address Table (IAT) hook.
        /// You choose a function (<paramref name="sFuncMod"/>, <paramref name="sFuncName"/>) whose entry will be replaced in the IAT of the specified module (<paramref name="sCallingMod"/>) to point to your own implementation (<see cref="pNewFunction"/>) instead.
        /// </summary>
        /// <param name="sFuncMod">Name of the module in which the function-to-be-hooked is defined. Example: <c>USER32.DLL</c>.</param>
        /// <param name="sFuncName">Name of the function to be hooked. Example: <c>SystemParametersInfoW</c>. Note that for the functions that have separate ANSI and Wide versions you must include a suffix in the function name. Must have the <c>stdcall</c> (<c>WINAPI</c>, <c>PASCAL</c>) calling convention.</param>
        /// <param name="sCallingMod">The module whose IAT is to be patched. Its calls to the Function will be intercepted. Must be loadable with <c>LoadLibrary</c> (or already loaded).</param>
        /// <param name="pNewFunction">The new implementation to replace the Function, in view of <paramref name"sCallingMod"/>. The hook will hold a reference on the delegate. Note that it's up to you to provide the appropriate signature of the delegate, which must match the one of the Function. Pay attention to the charset and bitness issues.</param>
        public static void Install([NotNull] string sFuncMod, [NotNull] string sFuncName, [NotNull] string sCallingMod, [NotNull] Delegate pNewFunction)
        {
            if (sFuncMod == null)
            {
                throw new ArgumentNullException("sFuncMod");
            }
            if (sFuncName == null)
            {
                throw new ArgumentNullException("sFuncName");
            }
            if (sCallingMod == null)
            {
                throw new ArgumentNullException("sCallingMod");
            }
            if (pNewFunction == null)
            {
                throw new ArgumentNullException("pNewFunction");
            }

            void *hmodCaller = UnsafeNativeMethods.LoadLibraryW(sCallingMod);

            if (Marshal.GetLastWin32Error() != 0)
            {
                throw new InvalidOperationException(string.Format("Could not load the module {0}.", sCallingMod.QuoteIfNeeded()), new Win32Exception());
            }
            if (hmodCaller == null)
            {
                throw new InvalidOperationException(string.Format("Could not load the module {0}.", sCallingMod.QuoteIfNeeded()));
            }

            void *hmodFunc = UnsafeNativeMethods.GetModuleHandleW(sFuncMod);

            if (Marshal.GetLastWin32Error() != 0)
            {
                throw new InvalidOperationException(string.Format("Could not load the module {0}.", sFuncMod.QuoteIfNeeded()), new Win32Exception());
            }
            if (hmodFunc == null)
            {
                throw new InvalidOperationException(string.Format("Could not load the module {0}.", sFuncMod.QuoteIfNeeded()));
            }

            void *pFunc = UnsafeNativeMethods.GetProcAddress(hmodFunc, sFuncName);

            if (Marshal.GetLastWin32Error() != 0)
            {
                throw new InvalidOperationException(string.Format("Could not locate the {0} function in the {1} module.", sFuncName.QuoteIfNeeded(), sFuncMod.QuoteIfNeeded()), new Win32Exception());
            }
            if (pFunc == null)
            {
                throw new InvalidOperationException(string.Format("Could not locate the {0} function in the {1} module.", sFuncName.QuoteIfNeeded(), sFuncMod.QuoteIfNeeded()));
            }

            uint ulSize;
            // Look for the imports section
            void *pImportDescVoid = UnsafeNativeMethods.ImageDirectoryEntryToData(hmodCaller, 1, UnsafeNativeMethods.IMAGE_DIRECTORY_ENTRY_IMPORT, out ulSize);

            if (Marshal.GetLastWin32Error() != 0)
            {
                throw new InvalidOperationException(string.Format("Could not locate the import address table for the {0} module.", sCallingMod.QuoteIfNeeded()), new Win32Exception());
            }
            if (pImportDescVoid == null)
            {
                throw new InvalidOperationException(string.Format("Could not locate the import address table for the {0} module.", sCallingMod.QuoteIfNeeded()));
            }

            // Find the entry for the function's module, look by its name
            var bytes       = new List <byte>();
            var pImportDesc = (UnsafeNativeMethods.IMAGE_IMPORT_DESCRIPTOR *)pImportDescVoid;
            int nCount;

            for (nCount = 0; (pImportDesc->Name != 0) && (nCount < IterationLimit); pImportDesc++, nCount++)
            {
                byte *szModName = (byte *)hmodCaller + pImportDesc->Name;                // RVA
                bytes.Clear();
                for (int a = 0; (a < 0x100) && (szModName[a] != 0); a++)
                {
                    bytes.Add(szModName[a]);
                }
                string sModName = Encoding.Default.GetString(bytes.ToArray());
                if (string.Compare(sModName, sFuncMod, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    break;
                }
            }
            if (!((pImportDesc->Name != 0) && (nCount < IterationLimit)))            // Gotten to the end
            {
                throw new InvalidOperationException(string.Format("Could not find an entry for the {0} module in the import address table of the {1} module.", sFuncMod, sCallingMod));
            }

            // Look for all the functions imported by the calling module from the function's module
            // Tell our Function apart by its address, as gotten from GetProcAddress
            var pThunk = (UnsafeNativeMethods.IMAGE_THUNK_DATA *)((byte *)hmodCaller + pImportDesc->FirstThunk);           // RVA

            for (nCount = 0; (pThunk->Function != null) && (nCount < IterationLimit); pThunk++, nCount++)
            {
                void **ppfn = &pThunk->Function;
                if (*ppfn == pFunc)
                {
                    var    mbi            = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
                    IntPtr nBytesReturned = UnsafeNativeMethods.VirtualQuery(ppfn, ref mbi, (IntPtr)Marshal.SizeOf(typeof(UnsafeNativeMethods.MEMORY_BASIC_INFORMATION)));
                    if ((nBytesReturned == IntPtr.Zero) && (Marshal.GetLastWin32Error() != 0))                    // Note: sometimes it would state "file not found" without any good reason
                    {
                        throw new InvalidOperationException("Could not query for the memory protection information.", new Win32Exception());
                    }

                    // Lift the memory protection
                    if (UnsafeNativeMethods.VirtualProtect(mbi.BaseAddress, mbi.RegionSize, UnsafeNativeMethods.PAGE_READWRITE, out mbi.Protect) == 0)
                    {
                        throw new InvalidOperationException(string.Format("Could not unlock import address table memory."));
                    }
                    // Hold a reference to the delegate (otherwise the pointer we create will be lost after the delegate gets collected)
                    DelegateAddRef(pNewFunction);

                    // This is it
                    *ppfn = (void *)Marshal.GetFunctionPointerForDelegate(pNewFunction);

                    // Restore the protection
                    uint dwOldProtect;
                    UnsafeNativeMethods.VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, out dwOldProtect);
                    break;                     // Done!
                }
            }
            if (!((pThunk->Function != null) && (nCount < IterationLimit)))            // No such func (btw may so happen we've already hooked it)
            {
                throw new InvalidOperationException(string.Format("Could not find the {0} function from the {1} module in the import address table of the {2} module.", sFuncName, sFuncMod, sCallingMod));
            }
        }