示例#1
0
        public void SealImportsAndTakeXorSnapshot()
        {
            if (_everythingSealed)
            {
                throw new InvalidOperationException($"{nameof(ElfLoader)} already sealed!");
            }

            // save import values, then zero them all (for hash purposes), then take our snapshot, then load them again,
            // then set the .wbxsyscall area to read only
            byte[] impData = null;
            impData = new byte[_imports.Size];
            Marshal.Copy(Z.US(_imports.LoadAddress), impData, 0, (int)_imports.Size);
            WaterboxUtils.ZeroMemory(Z.US(_imports.LoadAddress), (long)_imports.Size);

            byte[] invData = null;
            if (_invisible != null)
            {
                invData = new byte[_invisible.Size];
                Marshal.Copy(Z.US(_invisible.LoadAddress), invData, 0, (int)_invisible.Size);
                WaterboxUtils.ZeroMemory(Z.US(_invisible.LoadAddress), (long)_invisible.Size);
            }

            Memory.Seal();

            Marshal.Copy(impData, 0, Z.US(_imports.LoadAddress), (int)_imports.Size);

            if (_invisible != null)
            {
                Marshal.Copy(invData, 0, Z.US(_invisible.LoadAddress), (int)_invisible.Size);
            }

            _everythingSealed = true;
            Protect();
        }
示例#2
0
        public void SealImportsAndTakeXorSnapshot()
        {
            if (_everythingSealed)
            {
                throw new InvalidOperationException("PeWrapper already sealed!");
            }

            // save import values, then zero them all (for hash purposes), then take our snapshot, then load them again,
            // then set the .idata area to read only
            byte[] impData = null;
            if (_imports != null)
            {
                impData = new byte[_imports.Size];
                Marshal.Copy(Z.US(_imports.Start), impData, 0, (int)_imports.Size);
                WaterboxUtils.ZeroMemory(Z.US(_imports.Start), (long)_imports.Size);
            }
            Memory.SaveXorSnapshot();
            if (_imports != null)
            {
                Marshal.Copy(impData, 0, Z.US(_imports.Start), (int)_imports.Size);
                _imports.W = false;
                Memory.Protect(_imports.Start, _imports.Size, _imports.Prot);
            }
            if (_sealed != null)
            {
                _sealed.W = false;
                Memory.Protect(_sealed.Start, _sealed.Size, _sealed.Prot);
            }

            _everythingSealed = true;
        }
示例#3
0
        private void ProtectInternal(int startPage, int numPages, MemoryBlock.Protection prot, bool wasUsed)
        {
            for (var i = startPage; i < startPage + numPages; i++)
            {
                _pages[i] = prot;
            }

            ulong start  = GetStartAddr(startPage);
            ulong length = ((ulong)numPages) << WaterboxUtils.PageShift;

            if (prot == FREE)
            {
                Memory.Protect(start, length, MemoryBlock.Protection.RW);
                WaterboxUtils.ZeroMemory(Z.US(start), (long)length);
                Memory.Protect(start, length, MemoryBlock.Protection.None);
                Used -= length;
                Console.WriteLine($"Freed {length} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
            }
            else
            {
                Memory.Protect(start, length, prot);
                if (wasUsed)
                {
                    Console.WriteLine($"Set protection for {length} bytes on {Name} to {prot}");
                }
                else
                {
                    Used += length;
                    Console.WriteLine($"Allocated {length} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
                }
            }
        }
示例#4
0
        public void LoadStateBinary(BinaryReader br)
        {
            var name = br.ReadString();

            if (name != Name)
            {
                // probable cause: internal error
                throw new InvalidOperationException($"Name did not match for heap {Name}");
            }
            var used = br.ReadUInt64();

            if (used > Memory.Size)
            {
                throw new InvalidOperationException($"Heap {Name} used {used} larger than available {Memory.Size}");
            }
            if (!Sealed)
            {
                var hash = br.ReadBytes(Memory.XorHash.Length);
                if (!hash.SequenceEqual(Memory.XorHash))
                {
                    throw new InvalidOperationException($"Hash did not match for heap {Name}.  Is this the same rom with the same SyncSettings?");
                }
                var oldUsedAligned = WaterboxUtils.AlignUp(Used);
                var usedAligned    = WaterboxUtils.AlignUp(used);
                if (usedAligned > oldUsedAligned)
                {
                    // grow
                    var s = Memory.Start + oldUsedAligned;
                    var l = usedAligned - oldUsedAligned;
                    Memory.Protect(s, l, MemoryBlock.Protection.RW);
                }
                else if (usedAligned < oldUsedAligned)
                {
                    // shrink
                    var s = Memory.Start + usedAligned;
                    var l = oldUsedAligned - usedAligned;
                    // like elsewhere, we zero on free to avoid nondeterminism if later reallocated
                    WaterboxUtils.ZeroMemory(Z.US(s), (long)l);
                    Memory.Protect(s, l, MemoryBlock.Protection.None);
                }

                var ms = Memory.GetXorStream(Memory.Start, usedAligned, true);
                WaterboxUtils.CopySome(br.BaseStream, ms, (long)usedAligned);
                Used = used;
            }
            else
            {
                var hash = br.ReadBytes(_hash.Length);
                if (!hash.SequenceEqual(_hash))
                {
                    throw new InvalidOperationException($"Hash did not match for heap {Name}.  Is this the same rom with the same SyncSettings?");
                }
            }
        }
示例#5
0
        public PeWrapper(string moduleName, byte[] fileData, ulong destAddress)
        {
            ModuleName = moduleName;
            _fileData  = fileData;
            _pe        = new PeFile(fileData);
            Size       = _pe.ImageNtHeaders.OptionalHeader.SizeOfImage;
            Start      = destAddress;

            if (Size < _pe.ImageSectionHeaders.Max(s => (ulong)s.VirtualSize + s.VirtualAddress))
            {
                throw new InvalidOperationException("Image not Big Enough");
            }

            _fileHash = WaterboxUtils.Hash(fileData);

            foreach (var s in _pe.ImageSectionHeaders)
            {
                ulong start  = Start + s.VirtualAddress;
                ulong length = s.VirtualSize;

                MemoryBlock.Protection prot;
                var r = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_READ) != 0;
                var w = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_WRITE) != 0;
                var x = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0;
                if (w && x)
                {
                    throw new InvalidOperationException("Write and Execute not allowed");
                }

                prot = x ? MemoryBlock.Protection.RX : w ? MemoryBlock.Protection.RW : MemoryBlock.Protection.R;

                var section = new Section
                {
                    // chop off possible null padding from name
                    Name = Encoding.ASCII.GetString(s.Name, 0,
                                                    (s.Name.Select((v, i) => new { v, i }).FirstOrDefault(a => a.v == 0) ?? new { v = (byte)0, i = s.Name.Length }).i),
                    Start     = start,
                    Size      = length,
                    SavedSize = WaterboxUtils.AlignUp(length),
                    R         = r,
                    W         = w,
                    X         = x,
                    Prot      = prot,
                    DiskStart = s.PointerToRawData,
                    DiskSize  = s.SizeOfRawData
                };

                _sections.Add(section);
                _sectionsByName.Add(section.Name, section);
            }
            _sectionsByName.TryGetValue(".idata", out _imports);

            Mount();
        }
示例#6
0
        private void SettingsQuery(string name, IntPtr dest)
        {
            var val   = SettingsQuery(name);
            var bytes = Encoding.UTF8.GetBytes(val);

            if (bytes.Length > 255)
            {
                throw new InvalidOperationException($"Value {val} for setting {name} was too long");
            }
            WaterboxUtils.ZeroMemory(dest, 256);
            Marshal.Copy(bytes, 0, dest, bytes.Length);
        }
示例#7
0
 public MapHeap(ulong start, ulong size, string name)
 {
     size          = WaterboxUtils.AlignUp(size);
     Memory        = new MemoryBlock(start, size);
     Name          = name;
     _pagesAsBytes = new byte[size >> WaterboxUtils.PageShift];
     _pages        = (MemoryBlock.Protection[])(object) _pagesAsBytes;
     for (var i = 0; i < _pages.Length; i++)
     {
         _pages[i] = FREE;
     }
     Console.WriteLine("Created mapheap `{1}` at {0:x16}:{2:x16}", start, name, start + size);
 }
示例#8
0
 public void Seal()
 {
     if (!Sealed)
     {
         Memory.Protect(Memory.Start, Used, MemoryBlock.Protection.R);
         _hash  = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false));
         Sealed = true;
     }
     else
     {
         throw new InvalidOperationException(string.Format("Attempt to reseal heap {0}", Name));
     }
 }
示例#9
0
 public MapHeap(ulong start, ulong size, string name)
 {
     size          = WaterboxUtils.AlignUp(size);
     Memory        = MemoryBlock.Create(start, size);
     Name          = name;
     _pagesAsBytes = new byte[size >> WaterboxUtils.PageShift];
     _pages        = (MemoryBlock.Protection[])(object) _pagesAsBytes;
     for (var i = 0; i < _pages.Length; i++)
     {
         _pages[i] = FREE;
     }
     Console.WriteLine($"Created {nameof(MapHeap)} `{name}` at {start:x16}:{start + size:x16}");
 }
示例#10
0
		public void Seal()
		{
			if (!Sealed)
			{
				Memory.Protect(Memory.Start, Used, MemoryBlock.Protection.R);
				_hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, WaterboxUtils.AlignUp(Used), false));
				Sealed = true;
			}
			else
			{
				throw new InvalidOperationException($"Attempt to reseal heap {Name}");
			}
		}
示例#11
0
        public void LoadStateBinary(BinaryReader br)
        {
            if (!_everythingSealed)
            {
                // operations happening in the wrong order.  probable cause: internal logic error.  make sure frontend calls Seal
                throw new InvalidOperationException(".wbxsyscall section must be closed before loading state");
            }

            if (br.ReadUInt64() != MAGIC)
            {
                // file id is missing.  probable cause:  garbage savestate
                throw new InvalidOperationException("Savestate corrupted!");
            }

            var elfHash = br.ReadBytes(_elfHash.Length);

            if (_skipCoreConsistencyCheck)
            {
                throw new InvalidOperationException("We decided that the core consistency check should always run");
            }
            else
            {
                if (!elfHash.SequenceEqual(_elfHash))
                {
                    // the .dll file that is loaded now has a different hash than the .dll that created the savestate
                    throw new InvalidOperationException("Core consistency check failed.  Is this a savestate from a different version?");
                }
            }

            var xorHash = br.ReadBytes(Memory.XorHash.Length);

            if (!_skipMemoryConsistencyCheck)
            {
                if (!xorHash.SequenceEqual(Memory.XorHash))
                {
                    // the post-Seal memory state is different. probable cause:  different rom or different version of rom,
                    // different syncsettings
                    throw new InvalidOperationException("Memory consistency check failed.  Is this savestate from different SyncSettings?");
                }
            }

            var len = Memory.EndExclusive - _saveStart;

            if (br.ReadUInt64() != len)
            {
                throw new InvalidOperationException("Unexpected saved length");
            }
            var ms = Memory.GetXorStream(_saveStart, len, true);

            WaterboxUtils.CopySome(br.BaseStream, ms, (long)len);
        }
示例#12
0
        public void LoadStateBinary(BinaryReader br)
        {
            Enter();
            try
            {
                if (br.ReadUInt64() != MAGIC)
                {
                    throw new InvalidOperationException("Magic not magic enough!");
                }
                if (!br.ReadBytes(_elfhash.Length).SequenceEqual(_elfhash))
                {
                    throw new InvalidOperationException("Elf changed disguise!");
                }
                if (br.ReadInt64() != _loadoffset)
                {
                    throw new InvalidOperationException("Trickys elves moved on you!");
                }

                foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Writable) != 0))
                {
                    var len = br.ReadInt64();
                    if (sec.Size != len)
                    {
                        throw new InvalidOperationException("Unexpected section size for " + sec.Name);
                    }
                    var ms = _base.GetStream((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, true);
                    WaterboxUtils.CopySome(br.BaseStream, ms, len);
                }

                if (_heap != null)
                {
                    _heap.LoadStateBinary(br);
                }
                if (_sealedheap != null)
                {
                    _sealedheap.LoadStateBinary(br);
                }
                if (br.ReadUInt64() != MAGIC)
                {
                    throw new InvalidOperationException("Magic not magic enough!");
                }

                // the syscall trampolines were overwritten in loadstate (they're in .bss), and if we're cross-session,
                // are no longer valid.  cores must similiarly resend any external pointers they gave the core.
                ConnectAllClibPatches();
            }
            finally
            {
                Exit();
            }
        }
示例#13
0
        public void LoadStateBinary(BinaryReader br)
        {
            if (!_everythingSealed)
            {
                // operations happening in the wrong order.  probable cause: internal logic error.  make sure frontend calls Seal
                throw new InvalidOperationException(".idata sections must be closed before loading state");
            }

            if (br.ReadUInt64() != MAGIC)
            {
                // file id is missing.  probable cause:  garbage savestate
                throw new InvalidOperationException("Savestate corrupted!");
            }
            if (!br.ReadBytes(_fileHash.Length).SequenceEqual(_fileHash))
            {
                // the .dll file that is loaded now has a different hash than the .dll that created the savestate
                throw new InvalidOperationException("Core consistency check failed.  Is this a savestate from a different version?");
            }
            if (!br.ReadBytes(Memory.XorHash.Length).SequenceEqual(Memory.XorHash))
            {
                // the post-Seal memory state is different. probable cause:  different rom or different version of rom,
                // different syncsettings
                throw new InvalidOperationException("Memory consistency check failed.  Is this savestate from different SyncSettings?");
            }
            if (br.ReadUInt64() != Start)
            {
                // dll loaded somewhere else.  probable cause: internal logic error.
                // unlikely to get this far if the previous checks pssed
                throw new InvalidOperationException("Trickys elves moved on you!");
            }

            Memory.Protect(Memory.AddressRange.Start, Memory.Size, MemoryBlockBase.Protection.RW);

            foreach (var s in _sections)
            {
                if (!s.W || s == _invisible)
                {
                    continue;
                }

                if (br.ReadUInt64() != s.SavedSize)
                {
                    throw new InvalidOperationException("Unexpected section size for " + s.Name);
                }

                var ms = Memory.GetXorStream(s.Start, s.SavedSize, true);
                WaterboxUtils.CopySome(br.BaseStream, ms, (long)s.SavedSize);
            }

            ProtectMemory();
        }
示例#14
0
        public void LoadStateBinary(BinaryReader br)
        {
            var name = br.ReadString();

            if (name != Name)
            {
                throw new InvalidOperationException($"Name did not match for {nameof(MapHeap)} {Name}");
            }
            var size = br.ReadUInt64();

            if (size != Memory.Size)
            {
                throw new InvalidOperationException($"Size did not match for {nameof(MapHeap)} {Name}");
            }
            var used = br.ReadUInt64();
            var hash = br.ReadBytes(Memory.XorHash.Length);

            if (!hash.SequenceEqual(Memory.XorHash))
            {
                throw new InvalidOperationException($"Hash did not match for {nameof(MapHeap)} {Name}.  Is this the same rom?");
            }

            if (br.BaseStream.Read(_pagesAsBytes, 0, _pagesAsBytes.Length) != _pagesAsBytes.Length)
            {
                throw new InvalidOperationException("Unexpected error reading!");
            }

            Used = 0;
            Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
            var dsts = Memory.GetXorStream(Memory.Start, Memory.Size, true);

            for (int i = 0, addr = 0; i < _pages.Length; i++, addr += WaterboxUtils.PageSize)
            {
                if (_pages[i] != FREE)
                {
                    dsts.Seek(addr, SeekOrigin.Begin);
                    WaterboxUtils.CopySome(br.BaseStream, dsts, WaterboxUtils.PageSize);
                    Used += (uint)WaterboxUtils.PageSize;
                }
            }
            if (Used != used)
            {
                throw new InvalidOperationException("Internal savestate error");
            }
            if (br.ReadUInt64() != MAGIC)
            {
                throw new InvalidOperationException("Savestate internal error");
            }
            RefreshAllProtections();
        }
示例#15
0
文件: Heap.cs 项目: WolfpawGroup/RTC3
 public void SaveStateBinary(BinaryWriter bw)
 {
     bw.Write(Name);
     bw.Write(Used);
     if (!Sealed)
     {
         bw.Write(Memory.XorHash);
         var ms = Memory.GetXorStream(Memory.Start, WaterboxUtils.AlignUp(Used), false);
         ms.CopyTo(bw.BaseStream);
     }
     else
     {
         bw.Write(_hash);
     }
 }
示例#16
0
文件: Heap.cs 项目: WolfpawGroup/RTC3
        public void Seal()
        {
            if (!Sealed)
            {
                //RTC_Hijack : Change the protect level to RW instead of R
                Memory.Protect(Memory.Start, Used, MemoryBlock.Protection.RW);


                _hash  = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false));
                Sealed = true;
            }
            else
            {
                throw new InvalidOperationException(string.Format("Attempt to reseal heap {0}", Name));
            }
        }
示例#17
0
        public bool Protect(ulong start, ulong size, MemoryBlockBase.Protection prot)
        {
            if (start < Memory.Start || start + size > Memory.End || size == 0)
            {
                return(false);
            }

            var startPage = GetPage(start);
            var numPages  = WaterboxUtils.PagesNeeded(size);

            if (!EnsureMapped(startPage, numPages))
            {
                return(false);
            }

            ProtectInternal(startPage, numPages, prot, true);
            return(true);
        }
示例#18
0
        public ulong Map(ulong size, MemoryBlock.Protection prot)
        {
            if (size == 0)
            {
                return(0);
            }
            int numPages  = WaterboxUtils.PagesNeeded(size);
            int startPage = FindConsecutiveFreePages(numPages);

            if (startPage == -1)
            {
                return(0);
            }
            var ret = GetStartAddr(startPage);

            ProtectInternal(startPage, numPages, prot, false);
            return(ret);
        }
示例#19
0
 public void StoreSaveRam(byte[] data)
 {
     using (_exe.EnterExit())
     {
         if (data.Length != _saveramSize)
         {
             throw new InvalidOperationException("Saveram size mismatch");
         }
         using (_exe.EnterExit())
         {
             var source = new MemoryStream(data, false);
             foreach (var area in _saveramAreas)
             {
                 WaterboxUtils.CopySome(source, new MemoryDomainStream(area), area.Size);
             }
         }
     }
 }
示例#20
0
        public bool Protect(ulong start, ulong size, MemoryBlock.Protection prot)
        {
            // TODO: eliminate copy+pasta between unmap and protect
            if (start < Memory.Start || start + size > Memory.EndExclusive || size == 0)
            {
                return(false);
            }

            var startPage = GetPage(start);
            var numPages  = WaterboxUtils.PagesNeeded(size);

            if (!EnsureMappedNonStack(startPage, numPages))
            {
                return(false);
            }

            ProtectInternal(startPage, numPages, prot, true);
            return(true);
        }
示例#21
0
        private void SettingsQuery(string name, IntPtr dest)
        {
            if (!_syncSettingsActual.MednafenValues.TryGetValue(name, out var val))
            {
                if (SettingsInfo.SettingsByKey.TryGetValue(name, out var info))
                {
                    val = info.DefaultValue;
                }
                else
                {
                    throw new InvalidOperationException($"Core asked for setting {name} which was not found in the defaults");
                }
            }
            var bytes = Encoding.UTF8.GetBytes(val);

            if (bytes.Length > 255)
            {
                throw new InvalidOperationException($"Value {val} for setting {name} was too long");
            }
            WaterboxUtils.ZeroMemory(dest, 256);
            Marshal.Copy(bytes, 0, dest, bytes.Length);
        }
示例#22
0
文件: Heap.cs 项目: WolfpawGroup/RTC3
        public void LoadStateBinary(BinaryReader br)
        {
            var name = br.ReadString();

            if (name != Name)
            {
                // probable cause: internal error
                throw new InvalidOperationException(string.Format("Name did not match for heap {0}", Name));
            }
            var used = br.ReadUInt64();

            if (used > Memory.Size)
            {
                throw new InvalidOperationException(string.Format("Heap {0} used {1} larger than available {2}", Name, used, Memory.Size));
            }
            if (!Sealed)
            {
                var hash = br.ReadBytes(Memory.XorHash.Length);
                if (!hash.SequenceEqual(Memory.XorHash))
                {
                    throw new InvalidOperationException(string.Format("Hash did not match for heap {0}.  Is this the same rom with the same SyncSettings?", Name));
                }
                var usedAligned = WaterboxUtils.AlignUp(used);

                Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None);
                Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW);
                var ms = Memory.GetXorStream(Memory.Start, usedAligned, true);
                WaterboxUtils.CopySome(br.BaseStream, ms, (long)usedAligned);
                Used = used;
            }
            else
            {
                var hash = br.ReadBytes(_hash.Length);
                if (!hash.SequenceEqual(_hash))
                {
                    throw new InvalidOperationException(string.Format("Hash did not match for heap {0}.  Is this the same rom with the same SyncSettings?", Name));
                }
            }
        }
示例#23
0
        public void SaveStateBinary(BinaryWriter bw)
        {
            bw.Write(Name);
            bw.Write(Memory.Size);
            bw.Write(Used);
            bw.Write(Memory.XorHash);
            bw.Write(_pagesAsBytes);

            Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R);
            var srcs = Memory.GetXorStream(Memory.Start, Memory.Size, false);

            for (int i = 0, addr = 0; i < _pages.Length; i++, addr += WaterboxUtils.PageSize)
            {
                if (_pages[i] != FREE)
                {
                    srcs.Seek(addr, SeekOrigin.Begin);
                    WaterboxUtils.CopySome(srcs, bw.BaseStream, WaterboxUtils.PageSize);
                }
            }
            bw.Write(MAGIC);
            RefreshAllProtections();
        }
示例#24
0
        /// <summary>
        /// Set memory protections, pre or post seal
        /// </summary>
        private void Protect()
        {
            var writeStart = _everythingSealed ? _postSealWriteStart : _writeStart;

            Memory.Protect(Memory.Start, _execEnd - Memory.Start, MemoryBlock.Protection.RX);
            Memory.Protect(_execEnd, writeStart - _execEnd, MemoryBlock.Protection.R);
            Memory.Protect(writeStart, Memory.EndExclusive - writeStart, MemoryBlock.Protection.RW);
            if (_invisible != null)
            {
                if (!WaterboxUtils.Aligned(_invisible.LoadAddress))
                {
                    throw new InvalidOperationException("Invisible section start not aligned!  Check linker script");
                }
                var end = WaterboxUtils.AlignUp(_invisible.LoadAddress + _invisible.Size);
                if (_sectionsByName.Values.Any(s => s != _invisible && s.LoadAddress < end && s.LoadAddress >= _invisible.LoadAddress))
                {
                    throw new InvalidOperationException("Invisible section end not aligned, or not padded!  Check linker script");
                }
                Memory.Protect(
                    _invisible.LoadAddress,
                    _invisible.Size,
                    MemoryBlock.Protection.RW_Invisible);
            }
        }
示例#25
0
        public ElfLoader(string moduleName, byte[] fileData, ulong assumedStart, bool skipCoreConsistencyCheck, bool skipMemoryConsistencyCheck)
        {
            ModuleName = moduleName;
            _skipCoreConsistencyCheck   = skipCoreConsistencyCheck;
            _skipMemoryConsistencyCheck = skipMemoryConsistencyCheck;

            _elfHash = WaterboxUtils.Hash(fileData);
            _elf     = ELFReader.Load <ulong>(new MemoryStream(fileData, false), true);

            var loadsegs = _elf.Segments.Where(s => s.Type == SegmentType.Load);
            var start    = loadsegs.Min(s => s.Address);

            start = WaterboxUtils.AlignDown(start);
            var end = loadsegs.Max(s => s.Address + s.Size);

            end = WaterboxUtils.AlignUp(end);
            var size = end - start;

            if (start != assumedStart)
            {
                throw new InvalidOperationException($"{nameof(assumedStart)} did not match actual origin in elf file");
            }

            if (_elf.Sections.Any(s => s.Name.StartsWith(".rel")))
            {
                throw new InvalidOperationException("Elf has relocations!");
            }

            _allSymbols = ((ISymbolTable)_elf.GetSection(".symtab"))
                          .Entries
                          .Cast <SymbolEntry <ulong> >()
                          .ToList();

            _sectionsByName = _elf.Sections
                              .ToDictionary(s => s.Name);

            _sectionsByName.TryGetValue(".wbxsyscall", out _imports);
            if (_imports == null)
            {
                // Likely cause:  This is a valid elf file, but it was not compiled by our toolchain at all
                throw new InvalidOperationException("Missing .wbxsyscall section!");
            }
            _sectionsByName.TryGetValue(".sealed", out _sealed);
            _sectionsByName.TryGetValue(".invis", out _invisible);

            _visibleSymbols = _allSymbols
                              .Where(s => s.Binding == SymbolBinding.Global && s.Visibility == SymbolVisibility.Default)
                              .ToDictionary(s => s.Name);

            _importSymbols = _allSymbols
                             // TODO: No matter what attributes I provide, I seem to end up with Local and/or Hidden symbols in
                             // .wbxsyscall a lot of the time on heavily optimized release builds.
                             // Fortunately, there's nothing else in .wbxsyscall so we can just not filter at all.
                             .Where(s => s.PointedSection == _imports)
                             .ToList();

            Memory = MemoryBlock.Create(start, size);
            Memory.Activate();
            Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW);

            foreach (var seg in loadsegs)
            {
                var data = seg.GetFileContents();
                Marshal.Copy(data, 0, Z.US(seg.Address), Math.Min((int)seg.Size, (int)seg.FileSize));
            }

            {
                // Compute RW boundaries

                var allocated = _elf.Sections
                                .Where(s => (s.Flags & SectionFlags.Allocatable) != 0);
                var writable = allocated
                               .Where(s => (s.Flags & SectionFlags.Writable) != 0);
                var postSealWritable = writable
                                       .Where(s => !IsSpecialReadonlySection(s));
                var saveable = postSealWritable
                               .Where(s => s != _invisible);
                var executable = allocated
                                 .Where(s => (s.Flags & SectionFlags.Executable) != 0);

                _writeStart         = WaterboxUtils.AlignDown(writable.Min(s => s.LoadAddress));
                _postSealWriteStart = WaterboxUtils.AlignDown(postSealWritable.Min(s => s.LoadAddress));
                _execEnd            = WaterboxUtils.AlignUp(executable.Max(s => s.LoadAddress + s.Size));

                // validate; this may require linkscript cooperation
                // due to the segment limitations, the only thing we'd expect to catch is a custom eventually readonly section
                // in the wrong place (because the linkscript doesn't know "eventually readonly")
                if (_execEnd > _writeStart)
                {
                    throw new InvalidOperationException($"ElfLoader: Executable data to {_execEnd:X16} overlaps writable data from {_writeStart}");
                }
            }

            PrintSections();
            PrintGdbData();
            PrintTopSavableSymbols();
            Protect();
        }
示例#26
0
        public ulong Remap(ulong start, ulong oldSize, ulong newSize, bool canMove)
        {
            // TODO: what is the expected behavior when everything requested for remap is allocated,
            // but with different protections?
            if (start < Memory.Start || start + oldSize > Memory.EndExclusive || oldSize == 0 || newSize == 0)
            {
                return(0);
            }

            var oldStartPage = GetPage(start);
            var oldNumPages  = WaterboxUtils.PagesNeeded(oldSize);

            if (!EnsureMappedNonStack(oldStartPage, oldNumPages))
            {
                return(0);
            }
            var oldProt = _pages[oldStartPage];

            int newNumPages = WaterboxUtils.PagesNeeded(newSize);

            if (!canMove)
            {
                if (newNumPages <= oldNumPages)
                {
                    if (newNumPages < oldNumPages)
                    {
                        ProtectInternal(oldStartPage + newNumPages, oldNumPages - newNumPages, FREE, true);
                    }
                    return(start);
                }
                else if (newNumPages > oldNumPages)
                {
                    for (var i = oldStartPage + oldNumPages; i < oldStartPage + newNumPages; i++)
                    {
                        if (_pages[i] != FREE)
                        {
                            return(0);
                        }
                    }
                    ProtectInternal(oldStartPage + oldNumPages, newNumPages - oldNumPages, oldProt, false);
                    return(start);
                }
            }

            // if moving is allowed, we always move to simplify and defragment when possible
            int newStartPage = FindConsecutiveFreePagesAssumingFreed(newNumPages, oldStartPage, oldNumPages);

            if (newStartPage == -1)
            {
                return(0);
            }

            var copyDataLen = Math.Min(oldSize, newSize);
            var copyPageLen = Math.Min(oldNumPages, newNumPages);

            var data = new byte[copyDataLen];

            Memory.Protect(start, copyDataLen, MemoryBlock.Protection.RW);
            Marshal.Copy(Z.US(start), data, 0, (int)copyDataLen);

            var pages = new MemoryBlock.Protection[copyPageLen];

            Array.Copy(_pages, oldStartPage, pages, 0, copyPageLen);

            ProtectInternal(oldStartPage, oldNumPages, FREE, true);
            ProtectInternal(newStartPage, newNumPages, MemoryBlock.Protection.RW, false);

            var ret = GetStartAddr(newStartPage);

            Marshal.Copy(data, 0, Z.US(ret), (int)copyDataLen);

            Array.Copy(pages, 0, _pages, newStartPage, copyPageLen);
            RefreshProtections(newStartPage, copyPageLen);
            if (newNumPages > oldNumPages)
            {
                ProtectInternal(newStartPage + oldNumPages, newNumPages - oldNumPages, oldProt, true);
            }

            return(ret);
        }
示例#27
0
        /// <summary>
        /// load the PE into memory
        /// </summary>
        /// <param name="org">start address</param>
        private void Mount()
        {
            LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase;
            Memory     = new MemoryBlock(Start, Size);
            Memory.Activate();
            Memory.Protect(Start, Size, MemoryBlock.Protection.RW);

            // copy headers
            Marshal.Copy(_fileData, 0, Z.US(Start), (int)_pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders);

            // copy sections
            foreach (var s in _sections)
            {
                ulong datalength = Math.Min(s.Size, s.DiskSize);
                Marshal.Copy(_fileData, (int)s.DiskStart, Z.US(s.Start), (int)datalength);
                WaterboxUtils.ZeroMemory(Z.US(s.Start + datalength), (long)(s.SavedSize - datalength));
            }

            // apply relocations
            var n32 = 0;
            var n64 = 0;

            foreach (var rel in _pe.ImageRelocationDirectory)
            {
                foreach (var to in rel.TypeOffsets)
                {
                    ulong address = Start + rel.VirtualAddress + to.Offset;

                    switch (to.Type)
                    {
                    // there are many other types of relocation specified,
                    // but the only that are used is 0 (does nothing), 3 (32 bit standard), 10 (64 bit standard)

                    case 3:                             // IMAGE_REL_BASED_HIGHLOW
                    {
                        byte[] tmp = new byte[4];
                        Marshal.Copy(Z.US(address), tmp, 0, 4);
                        uint val = BitConverter.ToUInt32(tmp, 0);
                        tmp = BitConverter.GetBytes((uint)(val + LoadOffset));
                        Marshal.Copy(tmp, 0, Z.US(address), 4);
                        n32++;
                        break;
                    }

                    case 10:                             // IMAGE_REL_BASED_DIR64
                    {
                        byte[] tmp = new byte[8];
                        Marshal.Copy(Z.US(address), tmp, 0, 8);
                        long val = BitConverter.ToInt64(tmp, 0);
                        tmp = BitConverter.GetBytes(val + LoadOffset);
                        Marshal.Copy(tmp, 0, Z.US(address), 8);
                        n64++;
                        break;
                    }
                    }
                }
            }
            if (IntPtr.Size == 8 && n32 > 0)
            {
                // check mcmodel, etc
                throw new InvalidOperationException("32 bit relocations found in 64 bit dll!  This will fail.");
            }
            Console.WriteLine($"Processed {n32} 32 bit and {n64} 64 bit relocations");

            ProtectMemory();

            // publish exports
            EntryPoint = Z.US(Start + _pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint);
            foreach (var export in _pe.ExportedFunctions)
            {
                if (export.Name != null)
                {
                    ExportsByName.Add(export.Name, Z.US(Start + export.Address));
                }
                ExportsByOrdinal.Add(export.Ordinal, Z.US(Start + export.Address));
            }

            // collect information about imports
            // NB: Hints are not the same as Ordinals
            foreach (var import in _pe.ImportedFunctions)
            {
                Dictionary <string, IntPtr> module;
                if (!ImportsByModule.TryGetValue(import.DLL, out module))
                {
                    module = new Dictionary <string, IntPtr>();
                    ImportsByModule.Add(import.DLL, module);
                }
                var dest = Start + import.Thunk;
                if (_imports == null || dest >= _imports.Start + _imports.Size || dest < _imports.Start)
                {
                    throw new InvalidOperationException("Import record outside of .idata!");
                }

                module.Add(import.Name, Z.US(dest));
            }

            Section midipix;

            if (_sectionsByName.TryGetValue(".midipix", out midipix))
            {
                var dataOffset = midipix.DiskStart;
                CtorList = Z.SS(BitConverter.ToInt64(_fileData, (int)(dataOffset + 0x30)) + LoadOffset);
                DtorList = Z.SS(BitConverter.ToInt64(_fileData, (int)(dataOffset + 0x38)) + LoadOffset);
            }

            Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}");
            foreach (var s in _sections.OrderBy(s => s.Start))
            {
                Console.WriteLine("  @{0:x16} {1}{2}{3} `{4}` {5} bytes",
                                  s.Start,
                                  s.R ? "R" : " ",
                                  s.W ? "W" : " ",
                                  s.X ? "X" : " ",
                                  s.Name,
                                  s.Size);
            }
            Console.WriteLine("GDB Symbol Load:");
            var symload = $"add-sym {ModuleName} {_sectionsByName[".text"].Start}";

            if (_sectionsByName.ContainsKey(".data"))
            {
                symload += $" -s .data {_sectionsByName[".data"].Start}";
            }
            if (_sectionsByName.ContainsKey(".bss"))
            {
                symload += $" -s .bss {_sectionsByName[".bss"].Start}";
            }
            Console.WriteLine(symload);
        }
示例#28
0
        public PeWrapper(string moduleName, byte[] fileData, ulong destAddress)
        {
            ModuleName = moduleName;
            _pe        = new PeFile(fileData);
            Size       = _pe.ImageNtHeaders.OptionalHeader.SizeOfImage;
            Start      = destAddress;

            if (Size < _pe.ImageSectionHeaders.Max(s => (ulong)s.VirtualSize + s.VirtualAddress))
            {
                throw new InvalidOperationException("Image not Big Enough");
            }

            _fileHash = WaterboxUtils.Hash(fileData);

            foreach (var s in _pe.ImageSectionHeaders)
            {
                ulong start  = Start + s.VirtualAddress;
                ulong length = s.VirtualSize;

                MemoryBlockBase.Protection prot;
                var r = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_READ) != 0;
                var w = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_WRITE) != 0;
                var x = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0;
                if (w && x)
                {
                    throw new InvalidOperationException("Write and Execute not allowed");
                }

                prot = x ? MemoryBlockBase.Protection.RX : w ? MemoryBlockBase.Protection.RW : MemoryBlockBase.Protection.R;

                var section = new Section
                {
                    // chop off possible null padding from name
                    Name = Encoding.ASCII.GetString(s.Name, 0,
                                                    (s.Name.Select((v, i) => new { v, i }).FirstOrDefault(a => a.v == 0) ?? new { v = (byte)0, i = s.Name.Length }).i),
                    Start     = start,
                    Size      = length,
                    SavedSize = WaterboxUtils.AlignUp(length),
                    R         = r,
                    W         = w,
                    X         = x,
                    Prot      = prot,
                    DiskStart = s.PointerToRawData,
                    DiskSize  = s.SizeOfRawData
                };

                _sections.Add(section);
                _sectionsByName.Add(section.Name, section);
            }
            _sectionsByName.TryGetValue(".idata", out _imports);
            _sectionsByName.TryGetValue(".sealed", out _sealed);
            _sectionsByName.TryGetValue(".invis", out _invisible);

            // OK, NOW MOUNT

            LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase;
            Memory     = MemoryBlockBase.CallPlatformCtor(Start, Size);
            Memory.Activate();
            Memory.Protect(Start, Size, MemoryBlockBase.Protection.RW);

            // copy headers
            Marshal.Copy(fileData, 0, Z.US(Start), (int)_pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders);

            // copy sections
            foreach (var s in _sections)
            {
                ulong datalength = Math.Min(s.Size, s.DiskSize);
                Marshal.Copy(fileData, (int)s.DiskStart, Z.US(s.Start), (int)datalength);
                WaterboxUtils.ZeroMemory(Z.US(s.Start + datalength), (long)(s.SavedSize - datalength));
            }

            // apply relocations
            var n32 = 0;
            var n64 = 0;

            foreach (var rel in _pe.ImageRelocationDirectory)
            {
                foreach (var to in rel.TypeOffsets)
                {
                    ulong address = Start + rel.VirtualAddress + to.Offset;

                    switch (to.Type)
                    {
                    // there are many other types of relocation specified,
                    // but the only that are used is 0 (does nothing), 3 (32 bit standard), 10 (64 bit standard)

                    case 3:                             // IMAGE_REL_BASED_HIGHLOW
                    {
                        byte[] tmp = new byte[4];
                        Marshal.Copy(Z.US(address), tmp, 0, 4);
                        uint val = BitConverter.ToUInt32(tmp, 0);
                        tmp = BitConverter.GetBytes((uint)(val + LoadOffset));
                        Marshal.Copy(tmp, 0, Z.US(address), 4);
                        n32++;
                        break;
                    }

                    case 10:                             // IMAGE_REL_BASED_DIR64
                    {
                        byte[] tmp = new byte[8];
                        Marshal.Copy(Z.US(address), tmp, 0, 8);
                        long val = BitConverter.ToInt64(tmp, 0);
                        tmp = BitConverter.GetBytes(val + LoadOffset);
                        Marshal.Copy(tmp, 0, Z.US(address), 8);
                        n64++;
                        break;
                    }
                    }
                }
            }
            if (IntPtr.Size == 8 && n32 > 0)
            {
                // check mcmodel, etc
                throw new InvalidOperationException("32 bit relocations found in 64 bit dll!  This will fail.");
            }
            Console.WriteLine($"Processed {n32} 32 bit and {n64} 64 bit relocations");

            ProtectMemory();

            // publish exports
            EntryPoint = Z.US(Start + _pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint);
            foreach (var export in _pe.ExportedFunctions)
            {
                if (export.Name != null)
                {
                    ExportsByName.Add(export.Name, Z.US(Start + export.Address));
                }
                ExportsByOrdinal.Add(export.Ordinal, Z.US(Start + export.Address));
            }

            // collect information about imports
            // NB: Hints are not the same as Ordinals
            foreach (var import in _pe.ImportedFunctions)
            {
                Dictionary <string, IntPtr> module;
                if (!ImportsByModule.TryGetValue(import.DLL, out module))
                {
                    module = new Dictionary <string, IntPtr>();
                    ImportsByModule.Add(import.DLL, module);
                }
                var dest = Start + import.Thunk;
                if (_imports == null || dest >= _imports.Start + _imports.Size || dest < _imports.Start)
                {
                    throw new InvalidOperationException("Import record outside of .idata!");
                }

                module.Add(import.Name, Z.US(dest));
            }

            Section midipix;

            if (_sectionsByName.TryGetValue(".midipix", out midipix))
            {
                var dataOffset = midipix.DiskStart;
                CtorList = Z.SS(BitConverter.ToInt64(fileData, (int)(dataOffset + 0x30)) + LoadOffset);
                DtorList = Z.SS(BitConverter.ToInt64(fileData, (int)(dataOffset + 0x38)) + LoadOffset);
            }

            Console.WriteLine($"Mounted `{ModuleName}` @{Start:x16}");
            foreach (var s in _sections.OrderBy(s => s.Start))
            {
                Console.WriteLine("  @{0:x16} {1}{2}{3} `{4}` {5} bytes",
                                  s.Start,
                                  s.R ? "R" : " ",
                                  s.W ? "W" : " ",
                                  s.X ? "X" : " ",
                                  s.Name,
                                  s.Size);
            }
            Console.WriteLine("GDB Symbol Load:");
            var symload = $"add-sym {ModuleName} {_sectionsByName[".text"].Start}";

            if (_sectionsByName.ContainsKey(".data"))
            {
                symload += $" -s .data {_sectionsByName[".data"].Start}";
            }
            if (_sectionsByName.ContainsKey(".bss"))
            {
                symload += $" -s .bss {_sectionsByName[".bss"].Start}";
            }
            Console.WriteLine(symload);
        }
示例#29
0
 public ReadonlyFirmware(byte[] data, string name)
 {
     _data = data;
     _hash = WaterboxUtils.Hash(data);
     Name  = name;
 }
示例#30
0
        public ElfRunner(string filename, long heapsize, long sealedheapsize, long invisibleheapsize)
        {
            using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                _elfhash = WaterboxUtils.Hash(fs);
            }

            // todo: hack up this baby to take Streams
            _elf = ELFReader.Load <long>(filename);

            var loadsegs = _elf.Segments.Where(s => s.Type == SegmentType.Load);

            long orig_start = loadsegs.Min(s => s.Address);

            orig_start &= ~(Environment.SystemPageSize - 1);
            long orig_end = loadsegs.Max(s => s.Address + s.Size);

            if (HasRelocations())
            {
                _base       = new MemoryBlock((ulong)(orig_end - orig_start));
                _loadoffset = (long)_base.Start - orig_start;
                Initialize(0);
            }
            else
            {
                Initialize((ulong)orig_start);
                _base       = new MemoryBlock((ulong)orig_start, (ulong)(orig_end - orig_start));
                _loadoffset = 0;
                Enter();
            }

            try
            {
                _disposeList.Add(_base);
                AddMemoryBlock(_base, "elf");
                _base.Activate();
                _base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.RW);

                foreach (var seg in loadsegs)
                {
                    var data = seg.GetContents();
                    Marshal.Copy(data, 0, Z.SS(seg.Address + _loadoffset), data.Length);
                }
                RegisterSymbols();
                ProcessRelocations();

                _base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.R);

                foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Allocatable) != 0))
                {
                    if ((sec.Flags & SectionFlags.Executable) != 0)
                    {
                        _base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RX);
                    }
                    else if ((sec.Flags & SectionFlags.Writable) != 0)
                    {
                        _base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RW);
                    }
                }

                ulong end = _base.End;

                if (heapsize > 0)
                {
                    _heap = new Heap(GetHeapStart(end), (ulong)heapsize, "sbrk-heap");
                    _heap.Memory.Activate();
                    end = _heap.Memory.End;
                    _disposeList.Add(_heap);
                    AddMemoryBlock(_heap.Memory, "sbrk - heap");
                }

                if (sealedheapsize > 0)
                {
                    _sealedheap = new Heap(GetHeapStart(end), (ulong)sealedheapsize, "sealed-heap");
                    _sealedheap.Memory.Activate();
                    end = _sealedheap.Memory.End;
                    _disposeList.Add(_sealedheap);
                    AddMemoryBlock(_sealedheap.Memory, "sealed-heap");
                }

                if (invisibleheapsize > 0)
                {
                    _invisibleheap = new Heap(GetHeapStart(end), (ulong)invisibleheapsize, "invisible-heap");
                    _invisibleheap.Memory.Activate();
                    end = _invisibleheap.Memory.End;
                    _disposeList.Add(_invisibleheap);
                    AddMemoryBlock(_invisibleheap.Memory, "invisible-heap");
                }

                ConnectAllClibPatches();
                Console.WriteLine("Loaded {0}@{1:X16}", filename, _base.Start);
                foreach (var sec in _elf.Sections.Where(s => s.LoadAddress != 0))
                {
                    Console.WriteLine("  {0}@{1:X16}, size {2}", sec.Name.PadLeft(20), sec.LoadAddress + _loadoffset, sec.Size.ToString().PadLeft(12));
                }

                PrintTopSavableSymbols();
            }
            catch
            {
                Dispose();
                throw;
            }
            finally
            {
                Exit();
            }
        }