/* * Process Hacker - * memory region * * Copyright (C) 2008-2009 wj32 * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Process Hacker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . */ #define SIZE_CACHE_USE_RESOURCE_LOCK using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using ProcessHacker.Common.Objects; using ProcessHacker.Common.Threading; namespace ProcessHacker.Native { public class MemoryRegion : BaseObject { private static Dictionary _sizeCache = new Dictionary(); #if SIZE_CACHE_USE_RESOURCE_LOCK private static FastResourceLock _sizeCacheLock = new FastResourceLock(); #endif private static int GetStructSize(Type structType) { int size; #if SIZE_CACHE_USE_RESOURCE_LOCK _sizeCacheLock.AcquireShared(); if (_sizeCache.ContainsKey(structType)) { size = _sizeCache[structType]; _sizeCacheLock.ReleaseShared(); } else { _sizeCacheLock.ReleaseShared(); size = Marshal.SizeOf(structType); _sizeCacheLock.AcquireExclusive(); try { if (!_sizeCache.ContainsKey(structType)) _sizeCache.Add(structType, size); } finally { _sizeCacheLock.ReleaseExclusive(); } } return size; #else lock (_sizeCache) { if (_sizeCache.ContainsKey(structType)) size = _sizeCache[structType]; else _sizeCache.Add(structType, size = Marshal.SizeOf(structType)); return size; } #endif } public static T ReadStruct(IntPtr ptr) { return (T)Marshal.PtrToStructure(ptr, typeof(T)); } public static implicit operator IntPtr(MemoryRegion memory) { return memory.Memory; } public unsafe static implicit operator void*(MemoryRegion memory) { return memory.Memory.ToPointer(); } private MemoryRegion _parent; private IntPtr _memory; private int _size; /// /// Creates a new, invalid memory allocation. /// You must set the pointer using the Memory property. /// protected MemoryRegion() { } public MemoryRegion(IntPtr memory) : this(memory, 0) { } public MemoryRegion(IntPtr memory, int offset) : this(memory, offset, 0) { } public MemoryRegion(IntPtr memory, int offset, int size) : this(memory.Increment(offset), size, false) { } protected MemoryRegion(IntPtr memory, int size, bool owned) : this(null, memory, size, owned) { } protected MemoryRegion(MemoryRegion parent, IntPtr memory, int size, bool owned) : base(owned) { if (parent != null) parent.Reference(); _parent = parent; _memory = memory; _size = size; } protected sealed override void DisposeObject(bool disposing) { this.Free(); if (_parent != null) _parent.Dereference(disposing); _memory = IntPtr.Zero; _size = 0; } protected virtual void Free() { } /// /// Gets a pointer to the allocated memory. /// public IntPtr Memory { get { return _memory; } protected set { _memory = value; } } public MemoryRegion Parent { get { return _parent; } } /// /// Gets the size of the allocated memory. /// public virtual int Size { get { return _size; } protected set { _size = value; } } public void DestroyStruct() { this.DestroyStruct(0); } public void DestroyStruct(int index) { this.DestroyStruct(0, index); } public void DestroyStruct(int offset, int index) { if (index == 0) { Marshal.DestroyStructure(_memory.Increment(offset), typeof(T)); } else { Marshal.DestroyStructure( _memory.Increment(offset + GetStructSize(typeof(T)) * index), typeof(T) ); } } public void Fill(int offset, int length, byte value) { ProcessHacker.Native.Api.Win32.RtlFillMemory( _memory.Increment(offset), length.ToIntPtr(), value ); } public MemoryRegionStream GetStream() { return new MemoryRegionStream(this); } public MemoryRegion MakeChild(int offset, int size) { return new MemoryRegion(this, _memory.Increment(offset), size, true); } public string ReadAnsiString(int offset) { return Marshal.PtrToStringAnsi(_memory.Increment(offset)); } public string ReadAnsiString(int offset, int length) { return Marshal.PtrToStringAnsi(_memory.Increment(offset), length); } public byte[] ReadBytes(int length) { return this.ReadBytes(0, length); } public byte[] ReadBytes(int offset, int length) { byte[] buffer = new byte[length]; this.ReadBytes(offset, buffer, 0, length); return buffer; } public void ReadBytes(byte[] buffer, int startIndex, int length) { this.ReadBytes(0, buffer, startIndex, length); } public void ReadBytes(int offset, byte[] buffer, int startIndex, int length) { Marshal.Copy(_memory.Increment(offset), buffer, startIndex, length); } /// /// Reads a signed integer. /// /// The offset at which to begin reading. /// The integer. public int ReadInt32(int offset) { return this.ReadInt32(offset, 0); } /// /// Reads a signed integer. /// /// The offset at which to begin reading. /// The index at which to begin reading, after the offset is added. /// The integer. public int ReadInt32(int offset, int index) { unsafe { return ((int*)((byte*)_memory + offset))[index]; } } public int[] ReadInt32Array(int offset, int count) { int[] array = new int[count]; Marshal.Copy(_memory.Increment(offset), array, 0, count); return array; } public IntPtr ReadIntPtr(int offset) { return this.ReadIntPtr(offset, 0); } public IntPtr ReadIntPtr(int offset, int index) { unsafe { return ((IntPtr*)((byte*)_memory + offset))[index]; } } public void ReadMemory(IntPtr buffer, int destOffset, int srcOffset, int length) { ProcessHacker.Native.Api.Win32.RtlMoveMemory( buffer.Increment(destOffset), _memory.Increment(srcOffset), length.ToIntPtr() ); } /// /// Reads an unsigned integer. /// /// The offset at which to begin reading. /// The integer. public uint ReadUInt32(int offset) { return this.ReadUInt32(offset, 0); } /// /// Reads an unsigned integer. /// /// The offset at which to begin reading. /// The index at which to begin reading, after the offset is added. /// The integer. public uint ReadUInt32(int offset, int index) { unsafe { return ((uint*)((byte*)_memory + offset))[index]; } } /// /// Creates a struct from the memory allocation. /// /// The type of the struct. /// The new struct. public T ReadStruct() where T : struct { return this.ReadStruct(0); } /// /// Creates a struct from the memory allocation. /// /// The type of the struct. /// The index at which to begin reading to the struct. This is multiplied by /// the size of the struct. /// The new struct. public T ReadStruct(int index) where T : struct { return this.ReadStruct(0, index); } /// /// Creates a struct from the memory allocation. /// /// The type of the struct. /// The offset to add before reading. /// The index at which to begin reading to the struct. This is multiplied by /// the size of the struct. /// The new struct. public T ReadStruct(int offset, int index) where T : struct { if (index == 0) { return (T)Marshal.PtrToStructure(_memory.Increment(offset), typeof(T)); } else { return (T)Marshal.PtrToStructure( _memory.Increment(offset + GetStructSize(typeof(T)) * index), typeof(T) ); } } public string ReadUnicodeString(int offset) { return Marshal.PtrToStringUni(_memory.Increment(offset)); } public string ReadUnicodeString(int offset, int length) { return Marshal.PtrToStringUni(_memory.Increment(offset), length); } /// /// Writes a single byte to the memory allocation. /// /// The offset at which to write. /// The value of the byte. public void WriteByte(int offset, byte b) { unsafe { *((byte*)_memory + offset) = b; } } public void WriteBytes(int offset, byte[] b) { Marshal.Copy(b, 0, _memory.Increment(offset), b.Length); } public void WriteInt16(int offset, short i) { unsafe { *(short*)((byte*)_memory + offset) = i; } } public void WriteInt32(int offset, int i) { unsafe { *(int*)((byte*)_memory + offset) = i; } } public void WriteIntPtr(int offset, IntPtr i) { unsafe { *(IntPtr*)((byte*)_memory + offset) = i; } } public void WriteMemory(int offset, IntPtr buffer, int length) { ProcessHacker.Native.Api.Win32.RtlMoveMemory( _memory.Increment(offset), buffer, length.ToIntPtr() ); } public void WriteStruct(T s) where T : struct { this.WriteStruct(0, s); } public void WriteStruct(int index, T s) where T : struct { this.WriteStruct(0, index, s); } public void WriteStruct(int offset, int index, T s) where T : struct { if (index == 0) { Marshal.StructureToPtr(s, _memory.Increment(offset), false); } else { Marshal.StructureToPtr( s, _memory.Increment(offset + GetStructSize(typeof(T)) * index), false ); } } /// /// Writes a Unicode string (without a null terminator) to the allocated memory. /// /// The offset to add. /// The string to write. public void WriteUnicodeString(int offset, string s) { unsafe { fixed (char* ptr = s) { this.WriteMemory(offset, (IntPtr)ptr, s.Length * 2); } } } public void Zero(int offset, int length) { ProcessHacker.Native.Api.Win32.RtlZeroMemory( _memory.Increment(offset), length.ToIntPtr() ); } } }