예제 #1
0
        /// <summary>
        /// Takes an unmanaged memory address and reads the unmanaged memory given by its pointer,
        /// with memory address validation for added protection
        /// </summary>
        /// <typeparam name="T">the type of structure to return</typeparam>
        /// <param name="memAddress">the unamanaged memory address to read</param>
        /// <returns>the requested structure T</returns>
        public static T ReadStructureSafe <T>(IntPtr memAddress)
        {
            if (UnmanagedMemoryHelper.IsValidMemoryRange(memAddress, RdMarshal.SizeOf(typeof(T))))
            {
                return((T)RdMarshal.PtrToStructure(memAddress, typeof(T)));
            }

            throw new ArgumentException("Bad data pointer - unable to read structure data.");
        }
예제 #2
0
 /// <summary>
 /// frees all unmanaged memory assoicated with a DISPPARAMS structure
 /// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms221416(v=vs.85).aspx
 /// </summary>
 /// <param name="pDispParams"></param>
 private static void UnprepareDispatchArgs(ComTypes.DISPPARAMS pDispParams)
 {
     if (pDispParams.rgvarg != IntPtr.Zero)
     {
         // free the array of COM VARIANTs
         var variantStructSize      = RdMarshal.SizeOf(typeof(VARIANT));
         var variantArgsArrayOffset = pDispParams.rgvarg;
         var argIndex = 0;
         while (argIndex < pDispParams.cArgs)
         {
             VariantClear(variantArgsArrayOffset);
             variantArgsArrayOffset += variantStructSize;
             argIndex++;
         }
         RdMarshal.FreeHGlobal(pDispParams.rgvarg);
     }
 }
예제 #3
0
        /// <summary>
        /// Validate a memory address range
        /// </summary>
        /// <param name="memOffset">the input memory address to check</param>
        /// <param name="size">the minimum size of data we are expecting to be available next to memOffset</param>
        /// <param name="checkIsExecutable">optionally check if the memory address points to EXECUTABLE memory</param>
        public static bool IsValidMemoryRange(IntPtr memOffset, int size, bool checkIsExecutable = false)
        {
            if (memOffset == IntPtr.Zero)
            {
                return(false);
            }

            var memInfo       = new MEMORY_BASIC_INFORMATION();
            var sizeOfMemInfo = new IntPtr(RdMarshal.SizeOf(memInfo));

            // most of the time, a bad pointer will fail here
            if (VirtualQuery(memOffset, out memInfo, sizeOfMemInfo) != sizeOfMemInfo)
            {
                return(false);
            }

            // check the memory area is not a guard page, or otherwise inaccessible
            if ((memInfo.Protect.HasFlag(ALLOCATION_PROTECTION.PAGE_NOACCESS)) ||
                (memInfo.Protect.HasFlag(ALLOCATION_PROTECTION.PAGE_GUARD)))
            {
                return(false);
            }

            // We've confirmed the base memory address is valid, and is accessible.
            // Finally just check the full address RANGE is also valid (i.e. the end point of the structure we're reading)
            var validMemAddressEnd = memInfo.BaseAddress.ToInt64() + memInfo.RegionSize.ToInt64();
            var endOfStructPtr     = memOffset.ToInt64() + size;

            if (endOfStructPtr > validMemAddressEnd)
            {
                return(false);
            }

            if (checkIsExecutable)
            {
                // We've been asked to check if the memory address is marked as containing executable code
                return(memInfo.Protect.HasFlag(ALLOCATION_PROTECTION.PAGE_EXECUTE) ||
                       memInfo.Protect.HasFlag(ALLOCATION_PROTECTION.PAGE_EXECUTE_READ) ||
                       memInfo.Protect.HasFlag(ALLOCATION_PROTECTION.PAGE_EXECUTE_READWRITE) ||
                       memInfo.Protect.HasFlag(ALLOCATION_PROTECTION.PAGE_EXECUTE_WRITECOPY));
            }
            return(true);
        }
예제 #4
0
        /// <summary>
        /// Convert input args into a contiguous array of real COM VARIANTs for the DISPPARAMS struct used by IDispatch::Invoke
        /// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms221416(v=vs.85).aspx
        /// </summary>
        /// <param name="args">An array of arguments to wrap</param>
        /// <returns><see cref="ComTypes.DISPPARAMS"/> structure ready to pass to IDispatch::Invoke</returns>
        private static ComTypes.DISPPARAMS PrepareDispatchArgs(object[] args)
        {
            var pDispParams = new ComTypes.DISPPARAMS();

            if ((args != null) && (args.Length != 0))
            {
                var variantStructSize = RdMarshal.SizeOf(typeof(VARIANT));
                pDispParams.cArgs = args.Length;

                var argsVariantLength = variantStructSize * pDispParams.cArgs;
                var variantArgsArray  = RdMarshal.AllocHGlobal(argsVariantLength);

                // In IDispatch::Invoke, arguments are passed in reverse order
                var variantArgsArrayOffset = variantArgsArray + argsVariantLength;
                foreach (var arg in args)
                {
                    variantArgsArrayOffset -= variantStructSize;
                    RdMarshal.GetNativeVariantForObject(arg, variantArgsArrayOffset);
                }
                pDispParams.rgvarg = variantArgsArray;
            }
            return(pDispParams);
        }