public Dumper(IRemoteMemoryReader process) { Contract.Requires(process != null); Contract.Ensures(this.process != null); this.process = process; }
public static string ReadRemoteString(this IRemoteMemoryReader reader, IntPtr address, Encoding encoding, int length) { Contract.Requires(encoding != null); Contract.Requires(length >= 0); Contract.Ensures(Contract.Result <string>() != null); var data = reader.ReadRemoteMemory(address, length * encoding.GuessByteCountPerChar()); try { var sb = new StringBuilder(encoding.GetString(data)); for (var i = 0; i < sb.Length; ++i) { if (sb[i] == '\0') { sb.Length = i; break; } if (!sb[i].IsPrintable()) { sb[i] = '.'; } } return(sb.ToString()); } catch { return(string.Empty); } }
public static string ReadRemoteStringUntilFirstNullCharacter(this IRemoteMemoryReader reader, IntPtr address, Encoding encoding, int length) { Contract.Requires(encoding != null); Contract.Requires(length >= 0); Contract.Ensures(Contract.Result <string>() != null); var data = reader.ReadRemoteMemory(address, length * encoding.GuessByteCountPerChar()); // TODO We should cache the pattern per encoding. var index = PatternScanner.FindPattern(BytePattern.From(new byte[encoding.GuessByteCountPerChar()]), data); if (index == -1) { index = data.Length; } try { return(encoding.GetString(data, 0, Math.Min(index, data.Length))); } catch { return(string.Empty); } }
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>) in the remote process.</summary> /// <param name="process">The process to read from.</param> /// <param name="address">The address of the code.</param> /// <param name="length">The length of the code in bytes.</param> /// <returns>A list of <see cref="DisassembledInstruction"/>.</returns> public IReadOnlyList <DisassembledInstruction> RemoteDisassembleCode(IRemoteMemoryReader process, IntPtr address, int length) { Contract.Requires(process != null); Contract.Ensures(Contract.Result <IList <DisassembledInstruction> >() != null); return(RemoteDisassembleCode(process, address, length, -1)); }
private static string ReadPtrInfo(IntPtr value, IRemoteMemoryReader process) { var getTypeFnPtr = process.ReadRemoteIntPtr(value); if (getTypeFnPtr.MayBeValid()) { #if RECLASSNET64 var offset = process.ReadRemoteInt32(getTypeFnPtr + 3); var typeInfoPtr = getTypeFnPtr + offset + 7; #else var typeInfoPtr = process.ReadRemoteIntPtr(getTypeFnPtr + 1); #endif if (typeInfoPtr.MayBeValid()) { var typeInfoDataPtr = process.ReadRemoteIntPtr(typeInfoPtr); if (typeInfoDataPtr.MayBeValid()) { var namePtr = process.ReadRemoteIntPtr(typeInfoDataPtr); if (namePtr.MayBeValid()) { var info = process.ReadRemoteStringUntilFirstNullCharacter(namePtr, Encoding.UTF8, 64); if (info.Length > 0 && info[0].IsPrintable()) { return(info); } } } } } return(null); }
/// <summary>Dumps a section to the given stream.</summary> /// <param name="reader">The memory reader to use.</param> /// <param name="section">The section to dump.</param> /// <param name="stream">The stream to dump to.</param> public static void DumpSection(IRemoteMemoryReader reader, Section section, Stream stream) { Contract.Requires(section != null); Contract.Requires(stream != null); DumpRaw(reader, section.Start, section.Size.ToInt32(), stream); }
public static IntPtr ReadRemoteIntPtr(this IRemoteMemoryReader reader, IntPtr address) { #if RECLASSNET64 return((IntPtr)reader.ReadRemoteInt64(address)); #else return((IntPtr)reader.ReadRemoteInt32(address)); #endif }
public string ReadNodeInfo(BaseHexCommentNode node, IRemoteMemoryReader reader, MemoryBuffer memory, IntPtr nodeAddress, IntPtr nodeValue) { Contract.Requires(node != null); Contract.Requires(reader != null); Contract.Requires(memory != null); throw new NotImplementedException(); }
/// <summary>Tries to find and disassembles the instruction prior to the given address.</summary> /// <param name="process">The process to read from.</param> /// <param name="address">The address of the code.</param> /// <returns>The prior instruction.</returns> public DisassembledInstruction RemoteGetPreviousInstruction(IRemoteMemoryReader process, IntPtr address) { const int TotalBufferSize = 7 * MaximumInstructionLength; const int BufferShiftSize = 6 * MaximumInstructionLength; var buffer = process.ReadRemoteMemory(address - BufferShiftSize, TotalBufferSize); var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { var bufferAddress = handle.AddrOfPinnedObject(); var targetBufferAddress = bufferAddress + BufferShiftSize; var instruction = default(InstructionData); foreach (var offset in new[] { 6 * MaximumInstructionLength, 4 * MaximumInstructionLength, 2 * MaximumInstructionLength, 1 * MaximumInstructionLength, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }) { var currentAddress = targetBufferAddress - offset; coreFunctions.DisassembleCode(currentAddress, offset + 1, address - offset, false, (ref InstructionData data) => { var nextAddress = currentAddress + data.Length; if (nextAddress.CompareTo(targetBufferAddress) > 0) { return(false); } instruction = data; currentAddress = nextAddress; return(true); }); if (currentAddress == targetBufferAddress) { return(new DisassembledInstruction(ref instruction)); } } return(null); } finally { if (handle.IsAllocated) { handle.Free(); } } }
/// <summary>Dumps a chunk of memory to the given stream.</summary> /// <param name="reader">The memory reader to use.</param> /// <param name="address">The begin of the chunk.</param> /// <param name="size">The size of the chunk.</param> /// <param name="stream">The stream to dump to.</param> public static void DumpRaw(IRemoteMemoryReader reader, IntPtr address, int size, Stream stream) { Contract.Requires(size >= 0); Contract.Requires(stream != null); var data = reader.ReadRemoteMemory(address, size); stream.Write(data, 0, data.Length); }
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="maxLength"/>) in the remote process until the first 0xCC instruction.</summary> /// <param name="process">The process to read from.</param> /// <param name="address">The address of the code.</param> /// <param name="maxLength">The maximum maxLength of the code.</param> /// <returns>A list of <see cref="DisassembledInstruction"/> which belong to the function.</returns> public IReadOnlyList <DisassembledInstruction> RemoteDisassembleFunction(IRemoteMemoryReader process, IntPtr address, int maxLength) { Contract.Requires(process != null); Contract.Ensures(Contract.Result <IEnumerable <DisassembledInstruction> >() != null); var buffer = process.ReadRemoteMemory(address, maxLength); return(DisassembleFunction(buffer, address)); }
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>) in the remote process.</summary> /// <param name="process">The process to read from.</param> /// <param name="address">The address of the code.</param> /// <param name="length">The length of the code in bytes.</param> /// <param name="maxInstructions">The maximum number of instructions to disassemble. If <paramref name="maxInstructions"/> is -1, all available instructions get returned.</param> /// <returns>A list of <see cref="DisassembledInstruction"/>.</returns> public IReadOnlyList <DisassembledInstruction> RemoteDisassembleCode(IRemoteMemoryReader process, IntPtr address, int length, int maxInstructions) { Contract.Requires(process != null); Contract.Ensures(Contract.Result <IList <DisassembledInstruction> >() != null); var buffer = process.ReadRemoteMemory(address, length); return(DisassembleCode(buffer, address, maxInstructions)); }
/// <summary>Dumps a module to the given stream. The section headers of the pe header get fixed to build a valid pe file.</summary> /// <param name="reader">The memory reader to use.</param> /// <param name="module">The module to dump.</param> /// <param name="stream">The stream to dump to.</param> public static void DumpModule(IRemoteMemoryReader reader, Module module, Stream stream) { Contract.Requires(module != null); Contract.Requires(stream != null); var data = reader.ReadRemoteMemory(module.Start, module.Size.ToInt32()); SimplePeHeader.FixSectionHeaders(data); stream.Write(data, 0, data.Length); }
/// <summary>Tries to find the start address of the function <paramref name="address"/> points into.</summary> /// <param name="process">The process to read from.</param> /// <param name="address">The address inside the function.</param> /// <returns>The start address of the function (maybe) or <see cref="IntPtr.Zero"/> if no start address could be found.</returns> public IntPtr RemoteGetFunctionStartAddress(IRemoteMemoryReader process, IntPtr address) { const int BufferLength = 512; var buffer = new byte[2 + BufferLength + 2 + 1]; for (var i = 1; i <= 10; ++i) { if (!process.ReadRemoteMemoryIntoBuffer(address - i * BufferLength - 2, ref buffer)) { return(IntPtr.Zero); } for (var o = BufferLength + 4; o > 0; --o) { // Search for two CC in a row. if (buffer[o] == 0xCC && buffer[o - 1] == 0xCC) { var start = address - i * BufferLength + o - 1; // Check if the two previous instructions are really a CC. var prevInstruction = RemoteGetPreviousInstruction(process, start); if (prevInstruction.Length == 1 && prevInstruction.Data[0] == 0xCC) { prevInstruction = RemoteGetPreviousInstruction(process, start - 1); if (prevInstruction.Length == 1 && prevInstruction.Data[0] == 0xCC) { // Disassemble the code from the start and check if the instructions sum up to address. var totalInstructionLength = RemoteDisassembleCode(process, start, address.Sub(start).ToInt32()) .Sum(ins => ins.Length); if (start + totalInstructionLength == address) { return(start); } } else { o -= prevInstruction.Length; } } else { o -= prevInstruction.Length; } } } } return(IntPtr.Zero); }
public string ReadNodeInfo(BaseHexCommentNode node, IRemoteMemoryReader reader, MemoryBuffer memory, IntPtr nodeAddress, IntPtr nodeValue) { // 1. try the direct value var info = ReadPtrInfo(nodeValue, reader); if (!string.IsNullOrEmpty(info)) { return(info); } // 2. try indirect pointer var indirectPtr = reader.ReadRemoteIntPtr(nodeValue); if (indirectPtr.MayBeValid()) { info = ReadPtrInfo(indirectPtr, reader); if (!string.IsNullOrEmpty(info)) { return($"Ptr -> {info}"); } // 3. try weak pointer var weakTempPtr = indirectPtr - IntPtr.Size; if (weakTempPtr.MayBeValid()) { var weakPtr = reader.ReadRemoteIntPtr(weakTempPtr); if (weakPtr.MayBeValid()) { info = ReadPtrInfo(weakPtr, reader); if (!string.IsNullOrEmpty(info)) { return($"WeakPtr -> {info}"); } } } } return(null); }
/// <summary> /// Used to print custom informations about a node. /// </summary> /// <param name="node">The node.</param> /// <param name="reader">The current <see cref="T:ReClassNET.Memory.IRemoteMemoryReader" />.</param> /// <param name="memory">The current <see cref="T:ReClassNET.Memory.MemoryBuffer" />.</param> /// <param name="nodeAddress">The absolute address of the node.</param> /// <param name="nodeValue">The memory value of the node as <see cref="T:System.IntPtr" />.</param> public string ReadNodeInfo(BaseHexCommentNode node, IRemoteMemoryReader reader, MemoryBuffer memory, IntPtr nodeAddress, IntPtr nodeValue) { if (nodeValue.IsNull() || _base.NameDump.Count is 0) { return(null); } dynamic uobject = null; switch (_base.Game) { case UE3PluginExt.GameType.KillingFloor2: { uobject = reader.ReadRemoteObject <KillingFloor2.UObject>(nodeValue); break; } case UE3PluginExt.GameType.RocketLeague: { uobject = reader.ReadRemoteObject <RocketLeague.UObject>(nodeValue); break; } } if (uobject.Name.Index < 0 || uobject.Name.Index >= _base.NameDump.Count) { return(null); } if (_base.NameDump.TryGetValue(uobject.Name.Index, out string name)) { return(name); } return(null); }
/// <summary>This method lets ReClass.NET print the name and the value of the node.</summary> public string ReadNodeInfo(BaseHexCommentNode node, IRemoteMemoryReader reader, MemoryBuffer memory, IntPtr nodeAddress, IntPtr nodeValue) { return($"{node.Name}@{nodeAddress.ToString("X")} => {nodeValue.ToString("X")}"); }
public static byte ReadRemoteUInt8(this IRemoteMemoryReader reader, IntPtr address) { var data = reader.ReadRemoteMemory(address, sizeof(byte)); return(data[0]); }
public static ushort ReadRemoteUInt16(this IRemoteMemoryReader reader, IntPtr address) { var data = reader.ReadRemoteMemory(address, sizeof(ushort)); return(reader.BitConverter.ToUInt16(data, 0)); }
public static int ReadRemoteInt32(this IRemoteMemoryReader reader, IntPtr address) { var data = reader.ReadRemoteMemory(address, sizeof(int)); return(reader.BitConverter.ToInt32(data, 0)); }
public static double ReadRemoteDouble(this IRemoteMemoryReader reader, IntPtr address) { var data = reader.ReadRemoteMemory(address, sizeof(double)); return(reader.BitConverter.ToDouble(data, 0)); }
public static float ReadRemoteFloat(this IRemoteMemoryReader reader, IntPtr address) { var data = reader.ReadRemoteMemory(address, sizeof(float)); return(reader.BitConverter.ToSingle(data, 0)); }
public static ulong ReadRemoteUInt64(this IRemoteMemoryReader reader, IntPtr address) { var data = reader.ReadRemoteMemory(address, sizeof(ulong)); return(reader.BitConverter.ToUInt64(data, 0)); }