Пример #1
0
        /// <summary>
        /// Reserves a region of memory within the virtual address space of a specified process.
        /// </summary>
        /// <param name="processHandle">The handle to a process.</param>
        /// <param name="allocAddress">The rough address of where the allocation should take place.</param>
        /// <param name="size">The size of the region of memory to allocate, in bytes.</param>
        /// <param name="protectionFlags">The memory protection for the region of pages to be allocated.</param>
        /// <param name="allocationFlags">The type of memory allocation.</param>
        /// <returns>The base address of the allocated region</returns>
        public static UInt64 Allocate(
            IntPtr processHandle,
            UInt64 allocAddress,
            Int32 size,
            MemoryProtectionFlags protectionFlags = MemoryProtectionFlags.ExecuteReadWrite,
            MemoryAllocationFlags allocationFlags = MemoryAllocationFlags.Commit | MemoryAllocationFlags.Reserve)
        {
            if (allocAddress != 0)
            {
                /* A specific address has been given. We will modify it to support the following constraints:
                 *  - Aligned by 0x10000 / 65536
                 *  - Pointing to an unallocated region of memory
                 *  - Within +/- 2GB (using 1GB for safety) of address space of the originally specified address, such as to always be in range of a far jump instruction
                 * Note: A retry count has been put in place because VirtualAllocEx with an allocAddress specified may be invalid by the time we request the allocation.
                 */

                UInt64 result     = 0;
                Int32  retryCount = 0;

                // Request all chunks of unallocated memory. These will be very large in a 64-bit process.
                IEnumerable <MemoryBasicInformation64> freeMemory = Memory.QueryUnallocatedMemory(
                    processHandle,
                    allocAddress.Subtract(Int32.MaxValue >> 1, wrapAround: false),
                    allocAddress.Add(Int32.MaxValue >> 1, wrapAround: false));

                // Convert to normalized regions
                IEnumerable <NormalizedRegion> regions = freeMemory.Select(x => new NormalizedRegion(x.BaseAddress.ToUInt64(), x.RegionSize.ToInt32()));

                // Chunk the large regions into smaller regions based on the allocation size (minimum size is the alloc alignment to prevent creating too many chunks)
                List <NormalizedRegion> subRegions = new List <NormalizedRegion>();
                foreach (NormalizedRegion region in regions)
                {
                    region.BaseAddress = region.BaseAddress.Subtract(region.BaseAddress.Mod(Memory.AllocAlignment), wrapAround: false);
                    IEnumerable <NormalizedRegion> chunkedRegions = region.ChunkNormalizedRegion(Math.Max(size, Memory.AllocAlignment)).Take(128).Where(x => x.RegionSize >= size);
                    subRegions.AddRange(chunkedRegions);
                }

                do
                {
                    // Sample a random chunk and attempt to allocate the memory
                    result = subRegions.ElementAt(StaticRandom.Next(0, subRegions.Count())).BaseAddress;
                    result = NativeMethods.VirtualAllocEx(processHandle, result.ToIntPtr(), size, allocationFlags, protectionFlags).ToUInt64();

                    if (result != 0 || retryCount >= Memory.AllocateRetryCount)
                    {
                        break;
                    }

                    retryCount++;
                }while (result == 0);

                return(result);
            }
            else
            {
                // Allocate a memory page
                return(NativeMethods.VirtualAllocEx(processHandle, allocAddress.ToIntPtr(), size, allocationFlags, protectionFlags).ToUInt64());
            }
        }