Exemple #1
0
        /// <summary>
        /// Finds an available already present buffer and writes writes your own memory bytes into
        /// the specified buffer, giving you back the address of said buffer. If there is no available
        /// buffer, a new buffer will be automatically created.
        /// </summary>
        /// <param name="bytesToWrite">Individual bytes to be written onto a buffer.</param>
        /// <returns>Pointer to the passed in bytes written to memory.</returns>
        public static IntPtr Add(byte[] bytesToWrite)
        {
            // Get available buffers.
            List <MemoryBuffer> buffers = GetCachedBuffers(bytesToWrite.Length);

            // If there are no available buffers, create one.
            if (buffers.Count < 1)
            {
                // Get System Allocation Granularity.
                GetSystemInfo(out var systemInfo);

                // Get the desired page size, that being 1 allocation granularity greater than the bytes to be written.
                // 40 is an (over) estimate on the buffer header size, which cannot be properly read due string.
                // Retrieves the total size of the object to be added to a buffer, and the buffer header.
                int  totalObjectSize    = bytesToWrite.Length + Marshal.SizeOf(typeof(MemoryBufferHeader));
                int  desiredGranularity = (totalObjectSize / (int)systemInfo.allocationGranularity) + 1;
                uint desiredBufferSize  = (uint)(desiredGranularity * systemInfo.allocationGranularity);

                // Create new buffer.
                var memoryPageSet = Bindings.TargetProcess.GetPages();
                foreach (var memoryPages in memoryPageSet)
                {
                    // For clarity, will be optimized out by the JIT compiler.
                    // We have to align the starting address with the allocation granularity, it must be a multiple of it.
                    long pageEnd = (long)memoryPages.BaseAddress + (long)memoryPages.RegionSize;

                    // Place on next 64K boundary (or allocation granularity)
                    long firstPageBase = (((long)memoryPages.BaseAddress / systemInfo.allocationGranularity) + 1) * systemInfo.allocationGranularity;
                    long firstPageEnd  = firstPageBase + desiredBufferSize;

                    long lastPageBase = ((pageEnd - desiredBufferSize) / systemInfo.allocationGranularity) * systemInfo.allocationGranularity;
                    long lastPageEnd  = lastPageBase + desiredBufferSize;

                    // Check if desired buffer would fit in the free page region.
                    if ((uint)memoryPages.RegionSize > desiredBufferSize && memoryPages.State == PageState.Free)
                    {
                        // 1. Check if inbounds. 2. Check if new page start aligned to 64K/Granularity still fits.
                        if (lastPageBase > (long)memoryPages.BaseAddress)
                        {
                            MemoryBuffer buffer = new MemoryBuffer((IntPtr)lastPageBase, desiredBufferSize);
                            _knownBuffers.Add(buffer);
                            return(buffer.Add(bytesToWrite));
                        }
                        // 1. Check if inbounds. 2. Check if new page start aligned to 64K/Granularity still fits.
                        else if (firstPageEnd < (long)memoryPages.BaseAddress + (long)memoryPages.RegionSize)
                        {
                            MemoryBuffer buffer = new MemoryBuffer((IntPtr)firstPageBase, desiredBufferSize);
                            _knownBuffers.Add(buffer);
                            return(buffer.Add(bytesToWrite));
                        }
                    }
                }

                // Probably out of memory.
                return(IntPtr.Zero);
            }
            else
            {
                return(buffers[0].Add(bytesToWrite));
            }
        }
Exemple #2
0
        /// <summary>
        /// See <see cref="Add(byte[])"/> for details. Intended to use for X64 assembly purely.
        /// Adds the specified byte contents into a buffer in 32bit signed (2GB) proximity to a specified target address.
        /// Intended to be used in conjunction with 64bit Assembly, where 64bit immediates are not available.
        /// </summary>
        /// <param name="bytesToWrite">Individual bytes to be written onto a buffer.</param>
        /// <param name="targetAddress">
        ///     The target address within which the buffer to be written to must lie in 2GB memory proximity of.
        ///     Specify 0 for 32bit address, else near whatever assembly code you are targeting.
        /// </param>
        /// <returns>Pointer to the passed in bytes written to memory.</returns>
        public static unsafe IntPtr Add(byte[] bytesToWrite, IntPtr targetAddress)
        {
            // Get available buffers.
            List <MemoryBuffer> buffers = GetCachedBuffers(bytesToWrite.Length);

            // Iterate over all buffers to see if any fits the desired target.
            ulong minimumAddress = (ulong)(targetAddress + -2000000000);  // 2GB
            ulong maximumAddress = (ulong)targetAddress + 2000000000;     // 2GB

            // Check in case minimum address < 0
            if (minimumAddress > (ulong)targetAddress)
            {
                minimumAddress = 0;
            }

            // Find appropriate buffer, add and return.
            // If buffer not found, fallback is provided below to create a new buffer.
            foreach (var buffer in buffers)
            {
                ulong startAddress = (ulong)buffer.BaseBufferAddress;
                ulong endAddress   = (ulong)buffer.BaseBufferAddress + buffer.BufferHeader.BufferSize;

                if (startAddress >= minimumAddress && endAddress < maximumAddress)
                {
                    // Ensure our bytes fit to the buffer.
                    if (buffer.CheckItemSize(bytesToWrite.Length))
                    {
                        return(buffer.Add(bytesToWrite));
                    }
                }
            }

            // If we have not returned, no buffer was found in the specified range.
            // Get a list of all pages.
            var memoryBasicInformation = Bindings.TargetProcess.GetPages();

            // Get System Allocation Granularity.
            GetSystemInfo(out var systemInfo);

            // Get the desired page size, that being 1 allocation granularity greater than the bytes to be written.
            int  totalBytesToWrite  = bytesToWrite.Length + sizeof(MemoryBufferHeader);
            int  desiredGranularity = (totalBytesToWrite / (int)systemInfo.allocationGranularity) + 1;
            uint desiredBufferSize  = (uint)(desiredGranularity * systemInfo.allocationGranularity);

            // Iterate each page.
            foreach (var memoryPages in memoryBasicInformation)
            {
                // For clarity, will be optimized out by the JIT compiler.
                // We have to align the starting address with the allocation granularity, it must be a multiple of it.
                ulong pageEnd = (ulong)memoryPages.BaseAddress + (ulong)memoryPages.RegionSize;

                // Place on next 64K boundary (or allocation granularity)
                ulong firstPageBase = (((ulong)memoryPages.BaseAddress / systemInfo.allocationGranularity) + 1) * systemInfo.allocationGranularity;
                ulong firstPageEnd  = firstPageBase + desiredBufferSize;

                ulong lastPageBase = ((pageEnd - desiredBufferSize) / systemInfo.allocationGranularity) * systemInfo.allocationGranularity;
                ulong lastPageEnd  = lastPageBase + desiredBufferSize;

                // Check if desired buffer would fit in the free page region.
                if ((ulong)memoryPages.RegionSize > desiredBufferSize && memoryPages.State == PageState.Free)
                {
                    // 1. Check if inbounds. 2. Check if new page start aligned to 64K/Granularity still fits.
                    if (lastPageBase >= minimumAddress && lastPageEnd < maximumAddress &&
                        lastPageBase > (ulong)memoryPages.BaseAddress)
                    {
                        MemoryBuffer buffer = new MemoryBuffer((IntPtr)lastPageBase, desiredBufferSize);
                        _knownBuffers.Add(buffer);
                        return(buffer.Add(bytesToWrite));
                    }
                    // 1. Check if inbounds. 2. Check if new page start aligned to 64K/Granularity still fits.
                    else if (firstPageBase >= minimumAddress && firstPageEnd < maximumAddress &&
                             firstPageEnd < (ulong)memoryPages.BaseAddress + (ulong)memoryPages.RegionSize)
                    {
                        MemoryBuffer buffer = new MemoryBuffer((IntPtr)firstPageBase, desiredBufferSize);
                        _knownBuffers.Add(buffer);
                        return(buffer.Add(bytesToWrite));
                    }
                }
            }

            return(IntPtr.Zero);
        }