Exemplo n.º 1
0
        /// <summary>
        /// allocate size bytes starting at a particular address
        /// </summary>
        public MemoryBlock(ulong start, ulong size)
        {
            if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
            {
                throw new InvalidOperationException("MemoryBlock ctor called on Unix");
            }

            if (!WaterboxUtils.Aligned(start))
            {
                throw new ArgumentOutOfRangeException();
            }
            if (size == 0)
            {
                throw new ArgumentOutOfRangeException();
            }
            size = WaterboxUtils.AlignUp(size);

            _handle = Kernel32.CreateFileMapping(Kernel32.INVALID_HANDLE_VALUE, IntPtr.Zero,
                                                 Kernel32.FileMapProtection.PageExecuteReadWrite | Kernel32.FileMapProtection.SectionCommit, (uint)(size >> 32), (uint)size, null);

            if (_handle == IntPtr.Zero)
            {
                throw new InvalidOperationException($"{nameof(Kernel32.CreateFileMapping)}() returned NULL");
            }
            Start     = start;
            End       = start + size;
            Size      = size;
            _pageData = new Protection[GetPage(End - 1) + 1];
        }
Exemplo n.º 2
0
        /// <summary>
        /// take a snapshot of the entire memory block's contents, for use in GetXorStream
        /// </summary>
        public override void SaveXorSnapshot()
        {
            if (_snapshot != null)
            {
                throw new InvalidOperationException("Snapshot already taken");
            }
            if (!Active)
            {
                throw new InvalidOperationException("Not active");
            }

            // temporarily switch the entire block to `R`: in case some areas are unreadable, we don't want
            // that to complicate things
            if (mprotect(Z.US(Start), Z.UU(Size), MemoryProtection.Read) != 0)
            {
                throw new InvalidOperationException("mprotect() returned -1!");
            }

            _snapshot = new byte[Size];
            var ds = new MemoryStream(_snapshot, true);
            var ss = GetStream(Start, Size, false);

            ss.CopyTo(ds);
            XorHash = WaterboxUtils.Hash(_snapshot);

            ProtectAll();
        }
Exemplo n.º 3
0
        /// <summary>
        /// set r/w/x protection on a portion of memory.  rounded to encompassing pages
        /// </summary>
        public void Protect(ulong start, ulong length, Protection prot)
        {
            if (length == 0)
            {
                return;
            }
            int pstart = GetPage(start);
            int pend   = GetPage(start + length - 1);

            var p = GetKernelMemoryProtectionValue(prot);

            for (int i = pstart; i <= pend; i++)
            {
                _pageData[i] = prot; // also store the value for later use
            }
            if (Active)              // it's legal to Protect() if we're not active; the information is just saved for the next activation
            {
                var computedStart  = WaterboxUtils.AlignDown(start);
                var computedEnd    = WaterboxUtils.AlignUp(start + length);
                var computedLength = computedEnd - computedStart;

                Kernel32.MemoryProtection old;
                if (!Kernel32.VirtualProtect(Z.UU(computedStart),
                                             Z.UU(computedLength), p, out old))
                {
                    throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!");
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// take a snapshot of the entire memory block's contents, for use in GetXorStream
        /// </summary>
        public void SaveXorSnapshot()
        {
            if (_snapshot != null)
            {
                throw new InvalidOperationException("Snapshot already taken");
            }
            if (!Active)
            {
                throw new InvalidOperationException("Not active");
            }

            // temporarily switch the entire block to `R`: in case some areas are unreadable, we don't want
            // that to complicate things
            Kernel32.MemoryProtection old;
            if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old))
            {
                throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!");
            }

            _snapshot = new byte[Size];
            var ds = new MemoryStream(_snapshot, true);
            var ss = GetStream(Start, Size, false);

            ss.CopyTo(ds);
            XorHash = WaterboxUtils.Hash(_snapshot);

            ProtectAll();
        }
Exemplo n.º 5
0
        /// <summary>
        /// set r/w/x protection on a portion of memory.  rounded to encompassing pages
        /// </summary>
        public override void Protect(ulong start, ulong length, Protection prot)
        {
            if (length == 0)
            {
                return;
            }
            int pstart = GetPage(start);
            int pend   = GetPage(start + length - 1);

            var p = GetMemoryProtectionValue(prot);

            for (int i = pstart; i <= pend; i++)
            {
                _pageData[i] = prot; // also store the value for later use
            }
            if (Active)              // it's legal to Protect() if we're not active; the information is just saved for the next activation
            {
                var computedStart  = WaterboxUtils.AlignDown(start);
                var computedEnd    = WaterboxUtils.AlignUp(start + length);
                var computedLength = computedEnd - computedStart;

                if (mprotect(Z.US(computedStart), Z.UU(computedLength), p) != 0)
                {
                    throw new InvalidOperationException("mprotect() returned -1!");
                }
            }
        }
Exemplo n.º 6
0
        /// <exception cref="InvalidOperationException">failed to protect memory</exception>
        public override void Protect(ulong start, ulong length, Protection prot)
        {
            if (length == 0)
            {
                return;
            }

            var pstart = GetPage(start);
            var pend   = GetPage(start + length - 1);

            for (var i = pstart; i <= pend; i++)
            {
                _pageData[i] = prot;                                              // also store the value for later use
            }
            if (!Active)
            {
                return;                      // it's legal to call this method if we're not active; the information is just saved for the next activation
            }
            var computedStart = WaterboxUtils.AlignDown(start);
            var protEnum      = prot.ToMemoryProtection();
            var exitCode      = mprotect(
                Z.US(computedStart),
                Z.UU(WaterboxUtils.AlignUp(start + length) - computedStart),
                protEnum
                );

            if (exitCode != 0)
            {
                throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
            }
        }
Exemplo n.º 7
0
 /// <summary>allocate <paramref name="size"/> bytes starting at a particular address <paramref name="start"/></summary>
 /// <exception cref="ArgumentOutOfRangeException"><paramref name="start"/> is not aligned or <paramref name="size"/> is <c>0</c></exception>
 protected MemoryBlockBase(ulong start, ulong size)
 {
     if (!WaterboxUtils.Aligned(start))
     {
         throw new ArgumentOutOfRangeException(nameof(start), start, "start address must be aligned");
     }
     if (size == 0)
     {
         throw new ArgumentOutOfRangeException(nameof(size), size, "cannot create 0-length block");
     }
     Size         = WaterboxUtils.AlignUp(size);
     AddressRange = start.RangeToExclusive(start + Size);
     _pageData    = new Protection[1 + GetPage(AddressRange.EndInclusive)];
 }
Exemplo n.º 8
0
 protected MemoryBlockBase(ulong start, ulong size)
 {
     if (!WaterboxUtils.Aligned(start))
     {
         throw new ArgumentOutOfRangeException();
     }
     if (size == 0)
     {
         throw new ArgumentOutOfRangeException();
     }
     Start     = start;
     Size      = WaterboxUtils.AlignUp(size);
     End       = Start + Size;
     _pageData = new Protection[GetPage(End - 1) + 1];
 }
Exemplo n.º 9
0
        /// <summary>
        /// take a hash of the current full contents of the block, including unreadable areas
        /// </summary>
        /// <returns></returns>
        public override byte[] FullHash()
        {
            if (!Active)
            {
                throw new InvalidOperationException("Not active");
            }
            // temporarily switch the entire block to `R`
            if (mprotect(Z.US(Start), Z.UU(Size), MemoryProtection.Read) != 0)
            {
                throw new InvalidOperationException("mprotect() returned -1!");
            }
            var ret = WaterboxUtils.Hash(GetStream(Start, Size, false));

            ProtectAll();
            return(ret);
        }
Exemplo n.º 10
0
        /// <summary>
        /// take a hash of the current full contents of the block, including unreadable areas
        /// </summary>
        public byte[] FullHash()
        {
            if (!Active)
            {
                throw new InvalidOperationException("Not active");
            }
            // temporarily switch the entire block to `R`
            Kernel32.MemoryProtection old;
            if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old))
            {
                throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!");
            }
            var ret = WaterboxUtils.Hash(GetStream(Start, Size, false));

            ProtectAll();
            return(ret);
        }
Exemplo n.º 11
0
        /// <exception cref="InvalidOperationException"><see cref="MemoryBlockBase.Active"/> is <see langword="false"/> or failed to make memory read-only</exception>
        public override byte[] FullHash()
        {
            if (!Active)
            {
                throw new InvalidOperationException("Not active");
            }

            // temporarily switch the entire block to `R`
            var exitCode = mprotect(Z.US(AddressRange.Start), Z.UU(Size), MemoryProtection.Read);

            if (exitCode != 0)
            {
                throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
            }

            var ret = WaterboxUtils.Hash(GetStream(AddressRange.Start, Size, false));

            ProtectAll();
            return(ret);
        }
Exemplo n.º 12
0
 /// <summary>
 /// allocate size bytes starting at a particular address
 /// </summary>
 /// <param name="start"></param>
 /// <param name="size"></param>
 public MemoryBlockUnix(ulong start, ulong size)
 {
     if (!WaterboxUtils.Aligned(start))
     {
         throw new ArgumentOutOfRangeException();
     }
     if (size == 0)
     {
         throw new ArgumentOutOfRangeException();
     }
     size = WaterboxUtils.AlignUp(size);
     _fd  = memfd_create("MemoryBlockUnix", 0);
     if (_fd == -1)
     {
         throw new InvalidOperationException("memfd_create() returned -1");
     }
     Start     = start;
     End       = start + size;
     Size      = size;
     _pageData = new Protection[GetPage(End - 1) + 1];
 }
Exemplo n.º 13
0
        /// <summary>
        /// allocate size bytes starting at a particular address
        /// </summary>
        /// <param name="start"></param>
        /// <param name="size"></param>
        public MemoryBlockWin32(ulong start, ulong size)
        {
            if (!WaterboxUtils.Aligned(start))
            {
                throw new ArgumentOutOfRangeException();
            }
            if (size == 0)
            {
                throw new ArgumentOutOfRangeException();
            }
            size = WaterboxUtils.AlignUp(size);

            _handle = Kernel32.CreateFileMapping(Kernel32.INVALID_HANDLE_VALUE, IntPtr.Zero, Kernel32.FileMapProtection.PageExecuteReadWrite | Kernel32.FileMapProtection.SectionCommit, (uint)(size >> 32), (uint)size, null);
            if (_handle == IntPtr.Zero)
            {
                throw new InvalidOperationException("CreateFileMapping() returned NULL");
            }
            Start     = start;
            End       = start + size;
            Size      = size;
            _pageData = new Protection[GetPage(End - 1) + 1];
        }
Exemplo n.º 14
0
        /// <exception cref="InvalidOperationException">snapshot already taken, <see cref="MemoryBlockBase.Active"/> is <see langword="false"/>, or failed to make memory read-only</exception>
        public override void SaveXorSnapshot()
        {
            if (_snapshot != null)
            {
                throw new InvalidOperationException("Snapshot already taken");
            }
            if (!Active)
            {
                throw new InvalidOperationException("Not active");
            }

            // temporarily switch the entire block to `R`: in case some areas are unreadable, we don't want that to complicate things
            var exitCode = mprotect(Z.US(AddressRange.Start), Z.UU(Size), MemoryProtection.Read);

            if (exitCode != 0)
            {
                throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
            }

            _snapshot = new byte[Size];
            GetStream(AddressRange.Start, Size, false).CopyTo(new MemoryStream(_snapshot, true));
            XorHash = WaterboxUtils.Hash(_snapshot);
            ProtectAll();
        }