diff --git a/Process.NET/Applied/AppliedManager.cs b/Process.NET/Applied/AppliedManager.cs
index 009ce8b..47932d7 100644
--- a/Process.NET/Applied/AppliedManager.cs
+++ b/Process.NET/Applied/AppliedManager.cs
@@ -2,8 +2,9 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-namespace Process.NET.Applied
+namespace ProcessNET.Applied
{
+ ///
[SuppressMessage("ReSharper", "LoopCanBePartlyConvertedToQuery")]
public class AppliedManager : IAppliedManager where T : IApplied
{
diff --git a/Process.NET/Applied/AppliedUtilities.cs b/Process.NET/Applied/AppliedUtilities.cs
new file mode 100644
index 0000000..87d02b3
--- /dev/null
+++ b/Process.NET/Applied/AppliedUtilities.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+#if X64
+using ADDR = System.UInt64;
+#else
+using ADDR = System.UInt32;
+#endif
+
+namespace ProcessNET.Applied
+{
+ public class AppliedUtilities
+ {
+ #region Delegate/Function Registration
+
+ ///
+ /// Registers a function into a delegate. Note: The delegate must provide a proper function signature!
+ ///
+ ///
+ ///
+ ///
+ public static T RegisterDelegate(ADDR address) where T : class
+ {
+ return RegisterDelegate((IntPtr)address);
+ }
+
+ ///
+ /// Registers a function into a delegate. Note: The delegate must provide a proper function signature!
+ ///
+ ///
+ ///
+ ///
+ public static T RegisterDelegate(IntPtr address) where T : class
+ {
+#if !NOEXCEPTIONS
+ // Make sure delegates are attributed properly!
+ if (!HasUFPAttribute(typeof(T)))
+ {
+ throw new ArgumentException("The delegate does not have proper attributes! It must be adorned with" +
+ " the System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute, with proper calling conventions" +
+ " to work properly!");
+ }
+#endif
+ return Marshal.GetDelegateForFunctionPointer(address);
+ }
+
+ #endregion
+
+ internal static bool HasAttrib(Type item)
+ {
+ return item.GetCustomAttributes(typeof(T), true).Length != 0;
+ }
+
+ internal static bool HasUFPAttribute(Delegate d)
+ {
+ return HasUFPAttribute(d.GetType());
+ }
+
+ internal static bool HasUFPAttribute(Type t)
+ {
+ return HasAttrib(t);
+ }
+ }
+}
diff --git a/Process.NET/Applied/ComplexAppliedManager.cs b/Process.NET/Applied/ComplexAppliedManager.cs
index d83c5de..ca15851 100644
--- a/Process.NET/Applied/ComplexAppliedManager.cs
+++ b/Process.NET/Applied/ComplexAppliedManager.cs
@@ -1,4 +1,4 @@
-namespace Process.NET.Applied
+namespace ProcessNET.Applied
{
public class ComplexAppliedManager : AppliedManager, IComplexAppliedManager where T : IComplexApplied
{
diff --git a/Process.NET/Applied/Detours/Detour.cs b/Process.NET/Applied/Detours/Detour.cs
index dea5b45..142fca6 100644
--- a/Process.NET/Applied/Detours/Detour.cs
+++ b/Process.NET/Applied/Detours/Detour.cs
@@ -2,12 +2,18 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;
-using Process.NET.Extensions;
-using Process.NET.Memory;
-using Process.NET.Utilities;
+using ProcessNET.Extensions;
+using ProcessNET.Memory;
-namespace Process.NET.Applied.Detours
+namespace ProcessNET.Applied.Detours
{
+ public enum DetourCreateFlags
+ {
+ None,
+ IgnoreRules,
+ FastCall,
+ _x64,
+ }
///
/// A manager class to handle function detours, and hooks.
/// All credits to the GreyMagic library written by Apoc @ www.ownedcore.com
@@ -19,112 +25,9 @@ public class Detour : IComplexApplied
/// to keep a reference, to avoid the GC from collecting the delegate instance!
///
// ReSharper disable once NotAccessedField.Local
- private readonly Delegate _hookDelegate;
-
- public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
- bool ignoreRules = false, bool fastCall = true, bool x64 = true)
- {
- ProcessMemory = memory;
- Identifier = identifier;
- IgnoreRules = ignoreRules;
-
- TargetDelegate = target;
- Target = target.ToFunctionPtr();
-
- _hookDelegate = hook;
- HookPointer = hook.ToFunctionPtr(); //target
-
- //Store the original bytes
- Original = new List();
-
- //Setup the detour bytes
- New = new List { 0x48, 0xb8 }; // movabs rax
- var bytes = BitConverter.GetBytes(HookPointer.ToInt64()); // hookptr
- New.AddRange(bytes);
- New.AddRange(new byte[] { 0xff, 0xe0 }); // jmp rax
-
- Original.AddRange(memory.Read(Target, New.Count));
- }
-
- public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
- bool ignoreRules = false, bool fastCall = true)
- {
- ProcessMemory = memory;
- Identifier = identifier;
- IgnoreRules = ignoreRules;
-
- TargetDelegate = target;
- Target = target.ToFunctionPtr();
-
- _hookDelegate = hook;
- HookPointer = hook.ToFunctionPtr(); //target
-
- //Store the orginal bytes
- Original = new List();
- Original.AddRange(memory.Read(Target, 6));
+ private Delegate _hookDelegate;
- //here the mess starts ...
- //-----------------------
- paramCount = target.Method.GetParameters().Length;
-
- //preparing the stack from fastcall to stdcall
- first = new List();
-
- first.Add(0x58); // pop eax - store the ret addr
-
- if (paramCount > 1)
- first.Add(0x52); // push edx
-
- if (paramCount > 0)
- first.Add(0x51); // push ecx
-
- first.Add(0x50); // push eax - retrieve ret addr
-
- //jump to the hook
- first.Add(0x68); // push HookPointer
-
- var bytes = BitConverter.GetBytes(HookPointer.ToInt32());
-
- first.AddRange(bytes);
- first.Add(0xC3); // ret - jump to the detour handler
-
- firstPtr = Marshal.AllocHGlobal(first.Count);
- //ProcessMemory.Write(firstPtr, first.ToArray());
-
- //Setup the detour bytes
- New = new List { 0x68 }; //push firstPtr
- var bytes2 = IntPtr.Size == 4 ? BitConverter.GetBytes(firstPtr.ToInt32()) :
- BitConverter.GetBytes(firstPtr.ToInt64());
- New.AddRange(bytes2);
- New.Add(0xC3); //ret - jump to the first
-
- //preparing ecx, edx and the stack from stdcall to fastcall
- last = new List();
- last.Add(0x58); // pop eax - store the ret addr
-
- if (paramCount > 0)
- last.Add(0x59); // pop ecx
-
- if (paramCount > 1)
- last.Add(0x5A); // pop edx
-
- last.Add(0x50); // push eax - retrieve ret addr
-
- //jump to the original function
- last.Add(0x68); // push Target
-
- var bytes3 = BitConverter.GetBytes(HookPointer.ToInt32());
-
- last.AddRange(bytes3);
- last.Add(0xC3); // ret
-
- lastPtr = Marshal.AllocHGlobal(last.Count);
-
- //ProcessMemory.Write(lastPtr, last.ToArray());
-
- //create the func called after the hook
- lastDelegate = Marshal.GetDelegateForFunctionPointer(lastPtr, TargetDelegate.GetType());
- }
+
///
/// Initializes a new instance of the class.
@@ -134,73 +37,52 @@ public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
///
/// The instance.
///
- public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
- bool ignoreRules = false)
+ public Detour(Delegate target, Delegate hook, string identifier, IMemory memory, DetourCreateFlags flags)
{
- ProcessMemory = memory;
- Identifier = identifier;
- IgnoreRules = ignoreRules;
-
- TargetDelegate = target;
- Target = target.ToFunctionPtr();
-
- _hookDelegate = hook;
- HookPointer = hook.ToFunctionPtr(); //target
-
- //Store the original bytes
- Original = new List();
- Original.AddRange(memory.Read(Target, 6));
-
- //Setup the detour bytes
- New = new List { 0x68 };
-
- var bytes = BitConverter.GetBytes(HookPointer.ToInt32());
-
- New.AddRange(bytes);
- New.Add(0xC3);
+ Construct(target, hook, identifier, memory, flags);
}
///
/// The reference of the object.
///
- private IMemory ProcessMemory { get; }
+ private IMemory ProcessMemory { get; set; }
///
/// Gets the pointer to be hooked/being hooked.
///
/// The pointer to be hooked/being hooked.
- public IntPtr HookPointer { get; }
+ public IntPtr HookPointer { get; protected set; }
///
/// Gets the new bytes.
///
/// The new bytes.
- public List New { get; }
+ public List New { get; protected set; }
///
/// Gets the original bytes.
///
/// The original bytes.
- public List Original { get; }
+ public List Original { get; protected set; }
///
/// Gets the pointer of the target function.
///
/// The pointer of the target function.
- public IntPtr Target { get; }
+ public IntPtr Target { get; protected set; }
///
/// Gets the targeted delegate instance.
///
/// The targeted delegate instance.
- public Delegate TargetDelegate { get; }
+ public Delegate TargetDelegate { get; protected set; }
- public int paramCount { get; }
- public List first { get; }
- public IntPtr firstPtr { get; }
- public List last { get; }
- public IntPtr lastPtr { get; }
- public Delegate lastDelegate { get; }
+ public int paramCount { get; protected set; }
+ public List first { get; protected set; }
+ public IntPtr firstPtr { get; protected set; }
+ public List last { get; protected set; }
+ public IntPtr lastPtr { get; protected set; }
+ public Delegate lastDelegate { get; protected set; }
///
/// Get a value indicating if the detour has been disabled due to a running AntiCheat scan
@@ -210,7 +92,7 @@ public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
///
/// Geta s value indicating if the detour should never be disabled by the AntiCheat scan logic
///
- public bool IgnoreRules { get; }
+ public bool IgnoreRules { get; protected set; }
///
/// States if the detour is currently enabled.
@@ -221,7 +103,7 @@ public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
/// The name of the detour.
///
/// The name of the detour.
- public string Identifier { get; }
+ public string Identifier { get; protected set; }
///
/// Gets a value indicating whether the is disposed.
@@ -234,6 +116,117 @@ public Detour(Delegate target, Delegate hook, string identifier, IMemory memory,
///
public bool MustBeDisposed { get; set; } = true;
+ protected void Construct(Delegate target, Delegate hook, string identifier, IMemory memory, DetourCreateFlags flags)
+ {
+ ProcessMemory = memory;
+ Identifier = identifier;
+ IgnoreRules = flags.HasFlag(DetourCreateFlags.IgnoreRules);
+
+ TargetDelegate = target;
+ Target = target.ToFunctionPtr();
+
+ _hookDelegate = hook;
+ HookPointer = hook.ToFunctionPtr(); //target
+
+ if (flags.HasFlag(DetourCreateFlags.FastCall))
+ {
+ if (flags.HasFlag(DetourCreateFlags._x64))
+ {
+ //Store the original bytes
+ Original = new List();
+
+ //Setup the detour bytes
+ New = new List { 0x48, 0xb8 }; // movabs rax
+ var bytes = BitConverter.GetBytes(HookPointer.ToInt64()); // hookptr
+ New.AddRange(bytes);
+ New.AddRange(new byte[] { 0xff, 0xe0 }); // jmp rax
+
+ Original.AddRange(memory.Read(Target, New.Count));
+ }
+ else
+ {
+ //Store the orginal bytes
+ Original = new List();
+ Original.AddRange(memory.Read(Target, 6));
+
+ //here the mess starts ...
+ //-----------------------
+ paramCount = target.Method.GetParameters().Length;
+
+ //preparing the stack from fastcall to stdcall
+ first = new List();
+
+ first.Add(0x58); // pop eax - store the ret addr
+
+ if (paramCount > 1)
+ first.Add(0x52); // push edx
+
+ if (paramCount > 0)
+ first.Add(0x51); // push ecx
+
+ first.Add(0x50); // push eax - retrieve ret addr
+
+ //jump to the hook
+ first.Add(0x68); // push HookPointer
+
+ var bytes = BitConverter.GetBytes(HookPointer.ToInt32());
+
+ first.AddRange(bytes);
+ first.Add(0xC3); // ret - jump to the detour handler
+
+ firstPtr = Marshal.AllocHGlobal(first.Count);
+ //ProcessMemory.Write(firstPtr, first.ToArray());
+
+ //Setup the detour bytes
+ New = new List { 0x68 }; //push firstPtr
+ var bytes2 = memory.Is32Bit ? BitConverter.GetBytes(firstPtr.ToInt32()) :
+ BitConverter.GetBytes(firstPtr.ToInt64());
+ New.AddRange(bytes2);
+ New.Add(0xC3); //ret - jump to the first
+
+ //preparing ecx, edx and the stack from stdcall to fastcall
+ last = new List();
+ last.Add(0x58); // pop eax - store the ret addr
+
+ if (paramCount > 0)
+ last.Add(0x59); // pop ecx
+
+ if (paramCount > 1)
+ last.Add(0x5A); // pop edx
+
+ last.Add(0x50); // push eax - retrieve ret addr
+
+ //jump to the original function
+ last.Add(0x68); // push Target
+
+ var bytes3 = BitConverter.GetBytes(HookPointer.ToInt32());
+
+ last.AddRange(bytes3);
+ last.Add(0xC3); // ret
+
+ lastPtr = Marshal.AllocHGlobal(last.Count);
+
+ //ProcessMemory.Write(lastPtr, last.ToArray());
+
+ //create the func called after the hook
+ lastDelegate = Marshal.GetDelegateForFunctionPointer(lastPtr, TargetDelegate.GetType());
+ }
+ }
+ else
+ {
+ //Store the original bytes
+ Original = new List();
+ Original.AddRange(memory.Read(Target, 6));
+
+ //Setup the detour bytes
+ New = new List { 0x68 };
+
+ var bytes = BitConverter.GetBytes(HookPointer.ToInt32());
+
+ New.AddRange(bytes);
+ New.Add(0xC3);
+ }
+ }
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. In this
/// case, it will disable the instance and suppress the finalizer.
diff --git a/Process.NET/Applied/Detours/DetourManager.cs b/Process.NET/Applied/Detours/DetourManager.cs
index d73fc05..771691d 100644
--- a/Process.NET/Applied/Detours/DetourManager.cs
+++ b/Process.NET/Applied/Detours/DetourManager.cs
@@ -1,9 +1,9 @@
using System;
-using Process.NET.Extensions;
-using Process.NET.Memory;
-using Process.NET.Utilities;
+using ProcessNET.Extensions;
+using ProcessNET.Memory;
+using ProcessNET.Utilities;
-namespace Process.NET.Applied.Detours
+namespace ProcessNET.Applied.Detours
{
///
/// A manager class to handle function detours, and hooks.
@@ -62,12 +62,16 @@ public Detour Create(Delegate target, Delegate newTarget, string name, bool igno
if (InternalItems.ContainsKey(name))
throw new ArgumentException($"The {name} detour already exists!", nameof(name));
- if (!fastCall)
- InternalItems[name] = new Detour(target, newTarget, name, ProcessPlus, ignoreAntiCheatRules);
- if (fastCall && !x64)
- InternalItems[name] = new Detour(target, newTarget, name, ProcessPlus, ignoreAntiCheatRules, fastCall);
- if (fastCall && x64)
- InternalItems[name] = new Detour(target, newTarget, name, ProcessPlus, ignoreAntiCheatRules, fastCall, x64);
+ DetourCreateFlags flags = DetourCreateFlags.None;
+ if (ignoreAntiCheatRules)
+ flags |= DetourCreateFlags.IgnoreRules;
+ if (fastCall)
+ flags |= DetourCreateFlags.FastCall;
+ if (x64)
+ flags |= DetourCreateFlags._x64;
+
+ InternalItems[name] = new Detour(target, newTarget, name, ProcessPlus, flags);
+
return InternalItems[name];
}
diff --git a/Process.NET/Applied/IApplied.cs b/Process.NET/Applied/IApplied.cs
index 2410890..6187872 100644
--- a/Process.NET/Applied/IApplied.cs
+++ b/Process.NET/Applied/IApplied.cs
@@ -1,6 +1,6 @@
-using Process.NET.Marshaling;
+using ProcessNET.Marshaling;
-namespace Process.NET.Applied
+namespace ProcessNET.Applied
{
public interface IApplied : IDisposableState
{
diff --git a/Process.NET/Applied/IAppliedManager.cs b/Process.NET/Applied/IAppliedManager.cs
index afc972e..5656994 100644
--- a/Process.NET/Applied/IAppliedManager.cs
+++ b/Process.NET/Applied/IAppliedManager.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace Process.NET.Applied
+namespace ProcessNET.Applied
{
public interface IAppliedManager where T : IApplied
{
diff --git a/Process.NET/Applied/IComplexApplied.cs b/Process.NET/Applied/IComplexApplied.cs
index 370b39e..bacbeab 100644
--- a/Process.NET/Applied/IComplexApplied.cs
+++ b/Process.NET/Applied/IComplexApplied.cs
@@ -1,4 +1,4 @@
-namespace Process.NET.Applied
+namespace ProcessNET.Applied
{
public interface IComplexApplied : IApplied
{
diff --git a/Process.NET/Applied/IComplexAppliedManager.cs b/Process.NET/Applied/IComplexAppliedManager.cs
index 77952ce..01e2fd7 100644
--- a/Process.NET/Applied/IComplexAppliedManager.cs
+++ b/Process.NET/Applied/IComplexAppliedManager.cs
@@ -1,4 +1,4 @@
-namespace Process.NET.Applied
+namespace ProcessNET.Applied
{
public interface IComplexAppliedManager : IAppliedManager where T : IApplied
{
diff --git a/Process.NET/Applied/Patches/Patch.cs b/Process.NET/Applied/Patches/Patch.cs
index b026863..83d47bc 100644
--- a/Process.NET/Applied/Patches/Patch.cs
+++ b/Process.NET/Applied/Patches/Patch.cs
@@ -1,8 +1,8 @@
using System;
using System.Linq;
-using Process.NET.Memory;
+using ProcessNET.Memory;
-namespace Process.NET.Applied.Patches
+namespace ProcessNET.Applied.Patches
{
///
/// Class representing a Memory Patch object.
diff --git a/Process.NET/Applied/Patches/PatchManager.cs b/Process.NET/Applied/Patches/PatchManager.cs
index d94b037..f0e2aba 100644
--- a/Process.NET/Applied/Patches/PatchManager.cs
+++ b/Process.NET/Applied/Patches/PatchManager.cs
@@ -1,7 +1,7 @@
using System;
-using Process.NET.Memory;
+using ProcessNET.Memory;
-namespace Process.NET.Applied.Patches
+namespace ProcessNET.Applied.Patches
{
///
/// A manager class to handle memory patches.
diff --git a/Process.NET/Assembly/Assemblers/Fasm32Assembler.cs b/Process.NET/Assembly/Assemblers/Fasm32Assembler.cs
new file mode 100644
index 0000000..af51072
--- /dev/null
+++ b/Process.NET/Assembly/Assemblers/Fasm32Assembler.cs
@@ -0,0 +1,37 @@
+using Binarysharp.Assemblers.Fasm;
+using System;
+
+namespace ProcessNET.Assembly.Assemblers
+{
+ ///
+ /// Implement Fasm.NET compiler for 32-bit development.
+ /// More info: https://github.com/ZenLulz/Fasm.NET
+ ///
+ public class Fasm32Assembler : IAssembler
+ {
+ ///
+ /// Assemble the specified assembly code.
+ ///
+ /// The assembly code.
+ /// An array of bytes containing the assembly code.
+ public byte[] Assemble(string asm)
+ {
+ // Assemble and return the code
+ return Assemble(asm, IntPtr.Zero);
+ }
+
+ ///
+ /// Assemble the specified assembly code at a base address.
+ ///
+ /// The assembly code.
+ /// The address where the code is rebased.
+ /// An array of bytes containing the assembly code.
+ public byte[] Assemble(string asm, IntPtr baseAddress)
+ {
+ // Rebase the code
+ asm = String.Format("use32\norg 0x{0:X8}\n", baseAddress.ToInt64()) + asm;
+ // Assemble and return the code
+ return FasmNet.Assemble(asm);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Process.NET/Assembly/Assemblers/IAssembler.cs b/Process.NET/Assembly/Assemblers/IAssembler.cs
index 0ee1758..c3ccb59 100644
--- a/Process.NET/Assembly/Assemblers/IAssembler.cs
+++ b/Process.NET/Assembly/Assemblers/IAssembler.cs
@@ -1,6 +1,6 @@
using System;
-namespace Process.NET.Assembly.Assemblers
+namespace ProcessNET.Assembly.Assemblers
{
///
/// Interface defining an assembler.
diff --git a/Process.NET/Assembly/AssemblyFactory.cs b/Process.NET/Assembly/AssemblyFactory.cs
index 02c0220..1189f5f 100644
--- a/Process.NET/Assembly/AssemblyFactory.cs
+++ b/Process.NET/Assembly/AssemblyFactory.cs
@@ -1,15 +1,15 @@
using System;
using System.Linq;
using System.Threading.Tasks;
-using Process.NET.Assembly.Assemblers;
-using Process.NET.Assembly.CallingConventions;
-using Process.NET.Marshaling;
-using Process.NET.Memory;
-using Process.NET.Native.Types;
-using Process.NET.Threads;
-using Process.NET.Utilities;
-
-namespace Process.NET.Assembly
+using ProcessNET.Assembly.Assemblers;
+using ProcessNET.Assembly.CallingConventions;
+using ProcessNET.Marshaling;
+using ProcessNET.Memory;
+using ProcessNET.Native.Types;
+using ProcessNET.Threads;
+using ProcessNET.Utilities;
+
+namespace ProcessNET.Assembly
{
public class AssemblyFactory : IAssemblyFactory
{
@@ -24,6 +24,17 @@ public AssemblyFactory(IProcess process, IAssembler assembler)
Assembler = assembler;
}
+ ///
+ /// Initializes a new instance of the class.
+ /// With the default assembler
+ ///
+ /// The process.
+ public AssemblyFactory(IProcess process)
+ : this(process, new Fasm32Assembler())
+ {
+
+ }
+
///
/// Gets or sets the assembler.
///
@@ -264,9 +275,19 @@ public Task ExecuteAsync(IntPtr address, Native.Types.CallingConventions
///
/// The mnemonics to inject.
/// The address where the assembly code is injected.
- public void Inject(string asm, IntPtr address)
+ public bool Inject(string asm, IntPtr address)
{
- Process.Memory.Write(address, Assembler.Assemble(asm, address));
+ byte[] bytes = Assembler.Assemble(asm, address);
+
+ try
+ {
+ int injectedCount = Process.Memory.Write(address, bytes);
+ return injectedCount == bytes.Length;
+ }
+ catch
+ {
+ return false;
+ }
}
///
@@ -274,9 +295,9 @@ public void Inject(string asm, IntPtr address)
///
/// An array containing the mnemonics to inject.
/// The address where the assembly code is injected.
- public void Inject(string[] asm, IntPtr address)
+ public bool Inject(string[] asm, IntPtr address)
{
- Inject(string.Join("\n", asm), address);
+ return Inject(string.Join("\n", asm), address);
}
///
@@ -315,7 +336,9 @@ public IAllocatedMemory Inject(string[] asm)
public T InjectAndExecute(string asm, IntPtr address)
{
// Inject the assembly code
- Inject(asm, address);
+ bool injected = Inject(asm, address);
+ if (!injected)
+ return default;
// Execute the code
return Execute(address);
}
diff --git a/Process.NET/Assembly/AssemblyTransaction.cs b/Process.NET/Assembly/AssemblyTransaction.cs
index 0adc34f..5302c14 100644
--- a/Process.NET/Assembly/AssemblyTransaction.cs
+++ b/Process.NET/Assembly/AssemblyTransaction.cs
@@ -1,8 +1,8 @@
using System;
using System.Text;
-using Process.NET.Marshaling;
+using ProcessNET.Marshaling;
-namespace Process.NET.Assembly
+namespace ProcessNET.Assembly
{
///
/// Class representing a transaction where the user can insert mnemonics.
@@ -110,12 +110,14 @@ public virtual void Dispose()
{
// If a pointer was specified
if (Address != IntPtr.Zero)
+ {
// If the assembly code must be executed
if (IsAutoExecuted)
ExitCode = _assemblyFactory.InjectAndExecute(Mnemonics.ToString(), Address);
// Else the assembly code is just injected
else
_assemblyFactory.Inject(Mnemonics.ToString(), Address);
+ }
// If no pointer was specified and the code assembly code must be executed
if (Address == IntPtr.Zero && IsAutoExecuted)
diff --git a/Process.NET/Assembly/CallingConventions/CallingConventionSelector.cs b/Process.NET/Assembly/CallingConventions/CallingConventionSelector.cs
index 9d252f8..04f1565 100644
--- a/Process.NET/Assembly/CallingConventions/CallingConventionSelector.cs
+++ b/Process.NET/Assembly/CallingConventions/CallingConventionSelector.cs
@@ -1,7 +1,7 @@
using System;
-using Process.NET.Utilities;
+using ProcessNET.Utilities;
-namespace Process.NET.Assembly.CallingConventions
+namespace ProcessNET.Assembly.CallingConventions
{
///
/// Static class providing calling convention instances.
diff --git a/Process.NET/Assembly/CallingConventions/CdeclCallingConvention.cs b/Process.NET/Assembly/CallingConventions/CdeclCallingConvention.cs
index 754d4a3..f1d189d 100644
--- a/Process.NET/Assembly/CallingConventions/CdeclCallingConvention.cs
+++ b/Process.NET/Assembly/CallingConventions/CdeclCallingConvention.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Text;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Assembly.CallingConventions
+namespace ProcessNET.Assembly.CallingConventions
{
///
/// Define the C Declaration Calling Convention.
diff --git a/Process.NET/Assembly/CallingConventions/FastcallCallingConvention.cs b/Process.NET/Assembly/CallingConventions/FastcallCallingConvention.cs
index a140150..248fa0c 100644
--- a/Process.NET/Assembly/CallingConventions/FastcallCallingConvention.cs
+++ b/Process.NET/Assembly/CallingConventions/FastcallCallingConvention.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Assembly.CallingConventions
+namespace ProcessNET.Assembly.CallingConventions
{
///
/// Define the Fast Calling Convention (aka __msfastcall).
diff --git a/Process.NET/Assembly/CallingConventions/ICallingConvention.cs b/Process.NET/Assembly/CallingConventions/ICallingConvention.cs
index 6d58ad8..a649aed 100644
--- a/Process.NET/Assembly/CallingConventions/ICallingConvention.cs
+++ b/Process.NET/Assembly/CallingConventions/ICallingConvention.cs
@@ -1,7 +1,7 @@
using System;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Assembly.CallingConventions
+namespace ProcessNET.Assembly.CallingConventions
{
///
/// Interface defining a calling convention.
diff --git a/Process.NET/Assembly/CallingConventions/StdcallCallingConvention.cs b/Process.NET/Assembly/CallingConventions/StdcallCallingConvention.cs
index 1f53098..234c8c3 100644
--- a/Process.NET/Assembly/CallingConventions/StdcallCallingConvention.cs
+++ b/Process.NET/Assembly/CallingConventions/StdcallCallingConvention.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Text;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Assembly.CallingConventions
+namespace ProcessNET.Assembly.CallingConventions
{
///
/// Define the Standard Calling Convention.
diff --git a/Process.NET/Assembly/CallingConventions/ThiscallCallingConvention.cs b/Process.NET/Assembly/CallingConventions/ThiscallCallingConvention.cs
index fb73b47..a230c8a 100644
--- a/Process.NET/Assembly/CallingConventions/ThiscallCallingConvention.cs
+++ b/Process.NET/Assembly/CallingConventions/ThiscallCallingConvention.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Assembly.CallingConventions
+namespace ProcessNET.Assembly.CallingConventions
{
///
/// Define the 'This' Calling Convention.
diff --git a/Process.NET/Assembly/IAssemblyFactory.cs b/Process.NET/Assembly/IAssemblyFactory.cs
index c123354..3d5ac1f 100644
--- a/Process.NET/Assembly/IAssemblyFactory.cs
+++ b/Process.NET/Assembly/IAssemblyFactory.cs
@@ -1,9 +1,9 @@
using System;
using System.Threading.Tasks;
-using Process.NET.Assembly.Assemblers;
-using Process.NET.Memory;
+using ProcessNET.Assembly.Assemblers;
+using ProcessNET.Memory;
-namespace Process.NET.Assembly
+namespace ProcessNET.Assembly
{
public interface IAssemblyFactory : IDisposable
{
@@ -32,8 +32,8 @@ Task ExecuteAsync(IntPtr address, Native.Types.CallingConventions callingC
IAllocatedMemory Inject(string[] asm);
IAllocatedMemory Inject(string asm);
- void Inject(string[] asm, IntPtr address);
- void Inject(string asm, IntPtr address);
+ bool Inject(string[] asm, IntPtr address);
+ bool Inject(string asm, IntPtr address);
IntPtr InjectAndExecute(string[] asm);
IntPtr InjectAndExecute(string asm);
IntPtr InjectAndExecute(string[] asm, IntPtr address);
diff --git a/Process.NET/Assembly/IAssemblyTransaction.cs b/Process.NET/Assembly/IAssemblyTransaction.cs
index 0f0367f..7fc3c2f 100644
--- a/Process.NET/Assembly/IAssemblyTransaction.cs
+++ b/Process.NET/Assembly/IAssemblyTransaction.cs
@@ -1,6 +1,6 @@
using System;
-namespace Process.NET.Assembly
+namespace ProcessNET.Assembly
{
public interface IAssemblyTransaction
{
diff --git a/Process.NET/Extensions/AttributeExtensions.cs b/Process.NET/Extensions/AttributeExtensions.cs
index abb5c54..00e8dc4 100644
--- a/Process.NET/Extensions/AttributeExtensions.cs
+++ b/Process.NET/Extensions/AttributeExtensions.cs
@@ -2,7 +2,7 @@
using System.Linq;
using System.Runtime.InteropServices;
-namespace Process.NET.Extensions
+namespace ProcessNET.Extensions
{
public static class AttributeExtensions
{
diff --git a/Process.NET/Extensions/IntPtrExtensions.cs b/Process.NET/Extensions/IntPtrExtensions.cs
new file mode 100644
index 0000000..aee6531
--- /dev/null
+++ b/Process.NET/Extensions/IntPtrExtensions.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace ProcessNET.Extensions
+{
+ public static class IntPtrExtensions
+ {
+
+ public static bool MayBeValid(this IntPtr ptr)
+ {
+ return ptr.IsInRange((IntPtr)0x10000, (IntPtr)int.MaxValue);
+ }
+
+ public static bool IsInRange(this IntPtr address, IntPtr start, IntPtr end)
+ {
+ var val = (uint)address.ToInt32();
+ return (uint)start.ToInt32() <= val && val <= (uint)end.ToInt32();
+ }
+ }
+}
diff --git a/Process.NET/Extensions/MemoryResourcesExtensions.cs b/Process.NET/Extensions/MemoryResourcesExtensions.cs
new file mode 100644
index 0000000..3b8846a
--- /dev/null
+++ b/Process.NET/Extensions/MemoryResourcesExtensions.cs
@@ -0,0 +1,33 @@
+using ProcessNET.Memory;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ProcessNET.Memory
+{
+ ///
+ /// Extension methods for safe handling of objects allocated in the remote/local memory.
+ ///
+ public static class MemoryResourcesExtensions
+ {
+ ///
+ /// Safely frees up the allocated memory region.
+ ///
+ /// The region to free up.
+ /// True if cleaned successfully, false otherwise.
+ public static bool SafeRelease(this IAllocatedMemory allocatedMemory)
+ {
+ try
+ {
+ allocatedMemory.Dispose();
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/Process.NET/Extensions/NativeExtensions.cs b/Process.NET/Extensions/NativeExtensions.cs
index ae5e473..738c8c2 100644
--- a/Process.NET/Extensions/NativeExtensions.cs
+++ b/Process.NET/Extensions/NativeExtensions.cs
@@ -1,4 +1,4 @@
-namespace Process.NET.Extensions
+namespace ProcessNET.Extensions
{
public static class NativeExtensions
{
diff --git a/Process.NET/Extensions/ProcessExtensions.cs b/Process.NET/Extensions/ProcessExtensions.cs
index 376a940..260d72b 100644
--- a/Process.NET/Extensions/ProcessExtensions.cs
+++ b/Process.NET/Extensions/ProcessExtensions.cs
@@ -3,10 +3,10 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Extensions
+namespace ProcessNET.Extensions
{
public static class ProcessExtensions
{
diff --git a/Process.NET/Extensions/ProcessModuleExtensions.cs b/Process.NET/Extensions/ProcessModuleExtensions.cs
index 70187a6..b2950b7 100644
--- a/Process.NET/Extensions/ProcessModuleExtensions.cs
+++ b/Process.NET/Extensions/ProcessModuleExtensions.cs
@@ -1,8 +1,8 @@
using System;
using System.Diagnostics;
-using Process.NET.Utilities;
+using ProcessNET.Utilities;
-namespace Process.NET.Extensions
+namespace ProcessNET.Extensions
{
public static class ProcessModuleExtensions
{
diff --git a/Process.NET/Extensions/UnsafeMemoryExtensions.cs b/Process.NET/Extensions/UnsafeMemoryExtensions.cs
index 5065390..a8fc796 100644
--- a/Process.NET/Extensions/UnsafeMemoryExtensions.cs
+++ b/Process.NET/Extensions/UnsafeMemoryExtensions.cs
@@ -1,10 +1,10 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
-using Process.NET.Marshaling;
-using Process.NET.Native;
+using ProcessNET.Marshaling;
+using ProcessNET.Native;
-namespace Process.NET.Extensions
+namespace ProcessNET.Extensions
{
public static class FastCall
{
@@ -51,11 +51,11 @@ public static IntPtr WrapStdCallInFastCall(IntPtr stdCallPtr)
public static class UnsafeMemoryExtensions
{
// Gets an address from a vtable index.Since it uses index * IntPtr, it should work for both x64 and x32.
- public static IntPtr GetVtableIntPtr(this IntPtr intPtr, int functionIndex)
- {
- var vftable = intPtr.Read();
- return (vftable + functionIndex * IntPtr.Size).Read();
- }
+ // public static IntPtr GetVtableIntPtr(this IntPtr intPtr, int functionIndex)
+ // {
+ // var vftable = intPtr.Read();
+ // return (vftable + functionIndex * IntPtr.Size).Read();
+ // }
//public static IntPtr GetVtableIntPtr2(this IntPtr intPtr, int functionIndex)
//{
diff --git a/Process.NET/ExternalProcessMemory.cs b/Process.NET/ExternalProcessMemory.cs
index 0666a64..f667157 100644
--- a/Process.NET/ExternalProcessMemory.cs
+++ b/Process.NET/ExternalProcessMemory.cs
@@ -1,9 +1,9 @@
using System;
-using Process.NET.Marshaling;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using ProcessNET.Marshaling;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class for memory editing a process.
@@ -31,7 +31,15 @@ public override byte[] Read(IntPtr intPtr, int length)
{
return MemoryHelper.ReadBytes(Handle, intPtr, length);
}
-
+ ///
+ /// Writes a set of bytes to memory.
+ ///
+ /// The address where the bytes start in memory.
+ /// The buffer to read data onto, it's size determines the count of bytes to read.
+ public override void Read(IntPtr intPtr, byte[] buffer)
+ {
+ MemoryHelper.ReadBytes(Handle, intPtr, buffer);
+ }
///
/// Reads the value of a specified type from memory.
///
@@ -40,7 +48,10 @@ public override byte[] Read(IntPtr intPtr, int length)
/// A value.
public override T Read(IntPtr intPtr)
{
- return MarshalType.ByteArrayToObject(Read(intPtr, MarshalType.Size));
+ int size = MarshalCache.Size;
+ if (typeof(T) == typeof(IntPtr))
+ size = Is32Bit ? 4 : 8;
+ return MarshalType.ByteArrayToObject(Read(intPtr, size));
}
///
@@ -61,8 +72,7 @@ public override void Write(IntPtr intPtr, T value)
/// The array of bytes to write.
public override int Write(IntPtr intPtr, byte[] bytesToWrite)
{
- using (new MemoryProtection(Handle, intPtr,
- MarshalType.Size*bytesToWrite.Length))
+ using (new MemoryProtection(Handle, intPtr, MarshalType.Size * bytesToWrite.Length))
MemoryHelper.WriteBytes(Handle, intPtr, bytesToWrite);
return bytesToWrite.Length;
}
diff --git a/Process.NET/IProcess.cs b/Process.NET/IProcess.cs
index 1e83934..4cdb87a 100644
--- a/Process.NET/IProcess.cs
+++ b/Process.NET/IProcess.cs
@@ -1,11 +1,11 @@
using System;
-using Process.NET.Memory;
-using Process.NET.Modules;
-using Process.NET.Native.Types;
-using Process.NET.Threads;
-using Process.NET.Windows;
+using ProcessNET.Memory;
+using ProcessNET.Modules;
+using ProcessNET.Native.Types;
+using ProcessNET.Threads;
+using ProcessNET.Windows;
-namespace Process.NET
+namespace ProcessNET
{
///
/// A class that offers several tools to interact with a process.
@@ -27,6 +27,10 @@ public interface IProcess : IDisposable
/// Class for reading and writing memory.
///
IMemory Memory { get; set; }
+ ///
+ /// Gets the name of the user this process belongs to.
+ ///
+ string OwnerUser { get; }
///
/// Factory for manipulating threads.
diff --git a/Process.NET/LocalProcessMemory.cs b/Process.NET/LocalProcessMemory.cs
index 4f2a9bb..d328541 100644
--- a/Process.NET/LocalProcessMemory.cs
+++ b/Process.NET/LocalProcessMemory.cs
@@ -1,10 +1,10 @@
using System;
using System.Runtime.InteropServices;
-using Process.NET.Extensions;
-using Process.NET.Native.Types;
+using ProcessNET.Extensions;
+using ProcessNET.Native.Types;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class for memory editing a process.
@@ -31,15 +31,24 @@ public LocalProcessMemory(SafeMemoryHandle handle) : base(handle)
public override byte[] Read(IntPtr intPtr, int length)
{
var readBytes = new byte[length];
+ Read(intPtr, readBytes);
+ return readBytes;
+ }
+ ///
+ /// Writes a set of bytes to memory.
+ ///
+ /// The address where the bytes start in memory.
+ /// The buffer to read data onto, it's size determines the count of bytes to read.
+ public override void Read(IntPtr intPtr, byte[] buffer)
+ {
+ int length = buffer.Length;
unsafe
{
- var bytes = (byte*) intPtr;
+ var bytes = (byte*)intPtr;
for (var i = 0; i < length; i++)
- readBytes[i] = bytes[i];
+ buffer[i] = bytes[i];
}
- return readBytes;
}
-
///
/// Reads the value of a specified type from memory.
///
diff --git a/Process.NET/Marshaling/IDisposableState.cs b/Process.NET/Marshaling/IDisposableState.cs
index 0016dbe..f713259 100644
--- a/Process.NET/Marshaling/IDisposableState.cs
+++ b/Process.NET/Marshaling/IDisposableState.cs
@@ -1,6 +1,6 @@
using System;
-namespace Process.NET.Marshaling
+namespace ProcessNET.Marshaling
{
///
/// Defines an IDisposable interface with a known state.
diff --git a/Process.NET/Marshaling/IMarshalledValue.cs b/Process.NET/Marshaling/IMarshalledValue.cs
index 44b991f..b6ace94 100644
--- a/Process.NET/Marshaling/IMarshalledValue.cs
+++ b/Process.NET/Marshaling/IMarshalledValue.cs
@@ -1,7 +1,7 @@
using System;
-using Process.NET.Memory;
+using ProcessNET.Memory;
-namespace Process.NET.Marshaling
+namespace ProcessNET.Marshaling
{
///
/// Interface representing a value within the memory of a remote process.
diff --git a/Process.NET/Marshaling/MarshalCache.cs b/Process.NET/Marshaling/MarshalCache.cs
index 008af0f..0e56196 100644
--- a/Process.NET/Marshaling/MarshalCache.cs
+++ b/Process.NET/Marshaling/MarshalCache.cs
@@ -7,7 +7,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-namespace Process.NET.Marshaling
+namespace ProcessNET.Marshaling
{
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
public static class MarshalCache
diff --git a/Process.NET/Marshaling/MarshalType.cs b/Process.NET/Marshaling/MarshalType.cs
index f2c019a..5b6d9a2 100644
--- a/Process.NET/Marshaling/MarshalType.cs
+++ b/Process.NET/Marshaling/MarshalType.cs
@@ -1,11 +1,11 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
-using Process.NET.Memory;
+using ProcessNET.Memory;
// ReSharper disable All
-namespace Process.NET.Marshaling
+namespace ProcessNET.Marshaling
{
///
/// Static class providing tools for extracting information related to types.
diff --git a/Process.NET/Marshaling/MarshalValue.cs b/Process.NET/Marshaling/MarshalValue.cs
index 1f376cd..fe0a6b8 100644
--- a/Process.NET/Marshaling/MarshalValue.cs
+++ b/Process.NET/Marshaling/MarshalValue.cs
@@ -7,7 +7,7 @@
* See the file LICENSE for more information.
*/
-namespace Process.NET.Marshaling
+namespace ProcessNET.Marshaling
{
///
/// The factory to create instance of the class.
diff --git a/Process.NET/Marshaling/MarshalledValue.cs b/Process.NET/Marshaling/MarshalledValue.cs
index 582ab37..02f5af1 100644
--- a/Process.NET/Marshaling/MarshalledValue.cs
+++ b/Process.NET/Marshaling/MarshalledValue.cs
@@ -1,9 +1,9 @@
using System;
using System.Text;
-using Process.NET.Memory;
-using Process.NET.Utilities;
+using ProcessNET.Memory;
+using ProcessNET.Utilities;
-namespace Process.NET.Marshaling
+namespace ProcessNET.Marshaling
{
///
/// Class marshalling a value into the remote process.
@@ -75,7 +75,7 @@ private void Marshal()
// Allocate memory in the remote process (string + '\0')
Allocated = Process.MemoryFactory.Allocate(Randomizer.GenerateString(), text.Length + 1);
// Write the value
- Allocated.Write(0, text, Encoding.UTF8);
+ Allocated.WriteString(0, text, Encoding.UTF8);
// Get the pointer
Reference = Allocated.BaseAddress;
}
diff --git a/Process.NET/Memory/AllocatedMemory.cs b/Process.NET/Memory/AllocatedMemory.cs
index 67d4627..731d184 100644
--- a/Process.NET/Memory/AllocatedMemory.cs
+++ b/Process.NET/Memory/AllocatedMemory.cs
@@ -1,14 +1,16 @@
using System;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using System.ComponentModel;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class representing an allocated memory in a remote process.
///
public class AllocatedMemory : MemoryRegion, IAllocatedMemory
{
+ private readonly System.Diagnostics.Process process = null;
///
/// Initializes a new instance of the class.
///
@@ -22,6 +24,7 @@ public AllocatedMemory(IProcess processPlus, string name, int size,
bool mustBeDisposed = true)
: base(processPlus, MemoryHelper.Allocate(processPlus.Handle, size, protection))
{
+ process = processPlus.Native;
// Set local vars
Identifier = name;
MustBeDisposed = mustBeDisposed;
@@ -39,30 +42,41 @@ public AllocatedMemory(IProcess processPlus, string name, int size,
///
public bool MustBeDisposed { get; set; }
+ public bool IsAllocated => !IsDisposed;
+ public int Size { get; }
+ public string Identifier { get; }
+
///
/// Releases all resources used by the object.
///
/// Don't use the IDisposable pattern because the class is sealed.
public virtual void Dispose()
{
- if (!IsDisposed)
+ if (IsDisposed)
+ return;
+ // Set the flag to true
+ IsDisposed = true;
+ if (!process.HasExited)
{
- // Set the flag to true
- IsDisposed = true;
- // Release the allocated memory
- Release();
- // Remove this object from the collection of allocated memory
- Process.MemoryFactory.Deallocate(this);
- // Remove the pointer
- BaseAddress = IntPtr.Zero;
- // Avoid the finalizer
- GC.SuppressFinalize(this);
+ try
+ {
+ // Release the allocated memory
+ Release();
+ }
+ catch (Win32Exception ex)
+ {
+ // Rethrow the exception but with the region's name.
+ throw new Win32Exception($"Allocated memory: {Identifier} in process id {process.Id}, {ex.Message}");
+ }
}
+ // Remove this object from the collection of allocated memory
+ Process.MemoryFactory.Deallocate(this);
+ // Remove the pointer
+ BaseAddress = IntPtr.Zero;
+ // Avoid the finalizer
+ GC.SuppressFinalize(this);
}
- public bool IsAllocated => IsDisposed;
- public int Size { get; }
- public string Identifier { get; }
///
/// Frees resources and perform other cleanup operations before it is reclaimed by garbage collection.
diff --git a/Process.NET/Memory/IAllocatedMemory.cs b/Process.NET/Memory/IAllocatedMemory.cs
index 4482abd..0184739 100644
--- a/Process.NET/Memory/IAllocatedMemory.cs
+++ b/Process.NET/Memory/IAllocatedMemory.cs
@@ -1,6 +1,6 @@
-using Process.NET.Marshaling;
+using ProcessNET.Marshaling;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
public interface IAllocatedMemory : IPointer, IDisposableState
{
diff --git a/Process.NET/Memory/IMemory.cs b/Process.NET/Memory/IMemory.cs
index 40c6827..d694b96 100644
--- a/Process.NET/Memory/IMemory.cs
+++ b/Process.NET/Memory/IMemory.cs
@@ -1,10 +1,11 @@
using System;
using System.Text;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
public interface IMemory
{
+ bool Is32Bit { get; }
///
/// Writes a set of bytes to memory.
///
@@ -15,6 +16,13 @@ public interface IMemory
///
byte[] Read(IntPtr intPtr, int length);
+ ///
+ /// Writes a set of bytes to memory.
+ ///
+ /// The address where the bytes start in memory.
+ /// The buffer to read data onto, it's size determines the count of bytes to read.
+ void Read(IntPtr intPtr, byte[] buffer);
+
///
/// Reads a string with a specified encoding from memory.
///
@@ -25,7 +33,7 @@ public interface IMemory
/// char).
///
/// The string.
- string Read(IntPtr intPtr, Encoding encoding, int maxLength);
+ string ReadString(IntPtr intPtr, Encoding encoding, int maxLength = 512);
///
/// Reads the value of a specified type from memory.
@@ -57,7 +65,7 @@ public interface IMemory
/// The address where the string is written.
/// The text to write.
/// The encoding used.
- void Write(IntPtr intPtr, string stringToWrite, Encoding encoding);
+ void WriteString(IntPtr intPtr, string stringToWrite, Encoding encoding);
///
/// Writes an array of a specified type to memory,
@@ -74,5 +82,12 @@ public interface IMemory
/// The address where the value is written.
/// The value to write.
void Write(IntPtr intPtr, T value);
+
+ ///
+ /// Reads the Runtime Type Information (RTTI) at certain address.
+ ///
+ /// Address to read the type from.
+ /// Runtime Type Information of the object at the passed address or null if it's not an object.
+ string ReadRemoteRuntimeTypeInformation(IntPtr address);
}
}
\ No newline at end of file
diff --git a/Process.NET/Memory/IMemoryFactory.cs b/Process.NET/Memory/IMemoryFactory.cs
index 2dcea56..6573600 100644
--- a/Process.NET/Memory/IMemoryFactory.cs
+++ b/Process.NET/Memory/IMemoryFactory.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
public interface IMemoryFactory : IDisposable
{
diff --git a/Process.NET/Memory/IPointer.cs b/Process.NET/Memory/IPointer.cs
index 52555cc..d43f8cc 100644
--- a/Process.NET/Memory/IPointer.cs
+++ b/Process.NET/Memory/IPointer.cs
@@ -1,18 +1,18 @@
using System;
using System.Text;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
public interface IPointer
{
IntPtr BaseAddress { get; }
bool IsValid { get; }
byte[] Read(int offset, int length);
- string Read(int offset, Encoding encoding, int maxLength);
+ string ReadString(int offset, Encoding encoding, int maxLength);
T Read(int offset);
T[] Read(int offset, int length);
int Write(int offset, byte[] toWrite);
- void Write(int offset, string stringToWrite, Encoding encoding);
+ void WriteString(int offset, string stringToWrite, Encoding encoding);
void Write(int offset, T[] values);
void Write(int offset, T value);
}
diff --git a/Process.NET/Memory/LocalUnmanagedMemory.cs b/Process.NET/Memory/LocalUnmanagedMemory.cs
index 2bd6e89..b11dee5 100644
--- a/Process.NET/Memory/LocalUnmanagedMemory.cs
+++ b/Process.NET/Memory/LocalUnmanagedMemory.cs
@@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class representing a block of memory allocated in the local process.
diff --git a/Process.NET/Memory/MemoryFactory.cs b/Process.NET/Memory/MemoryFactory.cs
index 1bde4a4..0b6691e 100644
--- a/Process.NET/Memory/MemoryFactory.cs
+++ b/Process.NET/Memory/MemoryFactory.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class providing tools for manipulating memory space.
@@ -21,6 +21,7 @@ public class MemoryFactory : IMemoryFactory
///
protected readonly IProcess Process;
+ protected bool isDisposed = false;
///
/// Initializes a new instance of the class.
///
@@ -58,7 +59,7 @@ public IEnumerable Regions
{
get
{
- var size = IntPtr.Size;
+ var size = Process.Memory.Is32Bit ? 4 : 8;
var adresseTo = size == 8 ? new IntPtr(0x7fffffffffffffff) : new IntPtr(0x7fffffff);
return
MemoryHelper.Query(Process.Handle, IntPtr.Zero, adresseTo)
@@ -102,6 +103,9 @@ public void Deallocate(IAllocatedMemory allocation)
///
public virtual void Dispose()
{
+ if (isDisposed)
+ return;
+ isDisposed = true;
// Release all allocated memories which must be disposed
foreach (var allocatedMemory in InternalRemoteAllocations.Where(m => m.MustBeDisposed).ToArray())
allocatedMemory.Dispose();
diff --git a/Process.NET/Memory/MemoryPointer.cs b/Process.NET/Memory/MemoryPointer.cs
index 929d6b9..7aefc16 100644
--- a/Process.NET/Memory/MemoryPointer.cs
+++ b/Process.NET/Memory/MemoryPointer.cs
@@ -1,8 +1,8 @@
using System;
using System.Text;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class representing a pointer in the memory of the remote process.
@@ -39,7 +39,7 @@ public bool Equals(MemoryPointer other)
///
/// The address of the pointer in the remote process.
///
- public IntPtr BaseAddress { get; protected set; }
+ public virtual IntPtr BaseAddress { get; protected set; }
///
/// Gets if the is valid.
@@ -89,9 +89,9 @@ public int Write(int offset, byte[] toWrite)
/// ('\0' char).
///
/// The string.
- public string Read(int offset, Encoding encoding, int maxLength = 512)
+ public string ReadString(int offset, Encoding encoding, int maxLength = 512)
{
- return Process.Memory.Read(BaseAddress + offset, encoding, maxLength);
+ return Process.Memory.ReadString(BaseAddress + offset, encoding, maxLength);
}
///
@@ -122,9 +122,9 @@ public void Write(int offset, T[] array)
/// The offset where the string is written from the pointer.
/// The text to write.
/// The encoding used.
- public void Write(int offset, string text, Encoding encoding)
+ public void WriteString(int offset, string text, Encoding encoding)
{
- Process.Memory.Write(BaseAddress + offset, text, encoding);
+ Process.Memory.WriteString(BaseAddress + offset, text, encoding);
}
///
@@ -183,9 +183,9 @@ public T[] Read(Enum offset, int count)
/// ('\0' char).
///
/// The string.
- public string Read(Enum offset, Encoding encoding, int maxLength = 512)
+ public string ReadString(Enum offset, Encoding encoding, int maxLength = 512)
{
- return Read(Convert.ToInt32(offset), encoding, maxLength);
+ return ReadString(Convert.ToInt32(offset), encoding, maxLength);
}
///
@@ -197,9 +197,9 @@ public string Read(Enum offset, Encoding encoding, int maxLength = 512)
/// ('\0' char).
///
/// The string.
- public string Read(Encoding encoding, int maxLength = 512)
+ public string ReadString(Encoding encoding, int maxLength = 512)
{
- return Read(0, encoding, maxLength);
+ return ReadString(0, encoding, maxLength);
}
///
@@ -212,9 +212,9 @@ public string Read(Encoding encoding, int maxLength = 512)
///
///
/// The string.
- public string Read(int offset, int maxLength, Encoding encoding)
+ public string ReadString(int offset, int maxLength, Encoding encoding)
{
- return Process.Memory.Read(BaseAddress + offset, encoding, maxLength);
+ return Process.Memory.ReadString(BaseAddress + offset, encoding, maxLength);
}
///
@@ -226,9 +226,9 @@ public string Read(int offset, int maxLength, Encoding encoding)
/// ('\0' char).
///
/// The string.
- public string Read(Enum offset, int maxLength = 512)
+ public string ReadStringUTF8(Enum offset, int maxLength = 512)
{
- return Read(Convert.ToInt32(offset), maxLength, Encoding.UTF8);
+ return ReadString(Convert.ToInt32(offset), maxLength, Encoding.UTF8);
}
///
@@ -287,9 +287,9 @@ public void Write(T[] array)
/// The offset where the string is written from the pointer.
/// The text to write.
/// The encoding used.
- public void Write(Enum offset, string text, Encoding encoding)
+ public void WriteString(Enum offset, string text, Encoding encoding)
{
- Write(Convert.ToInt32(offset), text, encoding);
+ WriteString(Convert.ToInt32(offset), text, encoding);
}
///
@@ -297,9 +297,9 @@ public void Write(Enum offset, string text, Encoding encoding)
///
/// The text to write.
/// The encoding used.
- public void Write(string text, Encoding encoding)
+ public void WriteString(string text, Encoding encoding)
{
- Write(0, text, encoding);
+ WriteString(0, text, encoding);
}
///
@@ -307,7 +307,7 @@ public void Write(string text, Encoding encoding)
///
/// The offset where the string is written from the pointer.
/// The text to write.
- public void Write(int offset, string text)
+ public void WriteString(int offset, string text)
{
Process.Memory.Write(BaseAddress + offset, text);
}
@@ -317,18 +317,18 @@ public void Write(int offset, string text)
///
/// The offset where the string is written from the pointer.
/// The text to write.
- public void Write(Enum offset, string text)
+ public void WriteString(Enum offset, string text)
{
- Write(Convert.ToInt32(offset), text);
+ WriteString(Convert.ToInt32(offset), text);
}
///
/// Writes a string using the encoding UTF8 in the remote process.
///
/// The text to write.
- public void Write(string text)
+ public void WriteString(string text)
{
- Write(0, text);
+ WriteString(0, text);
}
///
diff --git a/Process.NET/Memory/MemoryProtection.cs b/Process.NET/Memory/MemoryProtection.cs
index 602e8df..4a79778 100644
--- a/Process.NET/Memory/MemoryProtection.cs
+++ b/Process.NET/Memory/MemoryProtection.cs
@@ -1,8 +1,8 @@
using System;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Class providing tools for manipulating memory protection.
@@ -10,6 +10,7 @@ namespace Process.NET.Memory
public class MemoryProtection : IDisposable
{
protected readonly SafeMemoryHandle Handle;
+ private bool isDisposed = false;
///
/// Initializes a new instance of the class.
@@ -33,7 +34,6 @@ public MemoryProtection(SafeMemoryHandle handle, IntPtr baseAddress, int size,
// Change the memory protection
OldProtection = MemoryHelper.ChangeProtection(Handle, baseAddress, size, protection);
}
-
///
/// The base address of the altered memory.
///
@@ -59,13 +59,18 @@ public MemoryProtection(SafeMemoryHandle handle, IntPtr baseAddress, int size,
///
public int Size { get; }
+
///
/// Restores the initial protection of the memory.
///
public virtual void Dispose()
{
+ if (isDisposed)
+ return;
+ isDisposed = true;
// Restore the memory protection
MemoryHelper.ChangeProtection(Handle, BaseAddress, Size, OldProtection);
+
// Avoid the finalizer
GC.SuppressFinalize(this);
}
diff --git a/Process.NET/Memory/MemoryProtectionOperation.cs b/Process.NET/Memory/MemoryProtectionOperation.cs
index 547107b..21f1b99 100644
--- a/Process.NET/Memory/MemoryProtectionOperation.cs
+++ b/Process.NET/Memory/MemoryProtectionOperation.cs
@@ -3,7 +3,7 @@
// ReSharper disable All
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
public enum MemoryProtectionType
{
diff --git a/Process.NET/Memory/MemoryRegion.cs b/Process.NET/Memory/MemoryRegion.cs
index 65cfe3e..bf93bcb 100644
--- a/Process.NET/Memory/MemoryRegion.cs
+++ b/Process.NET/Memory/MemoryRegion.cs
@@ -1,8 +1,10 @@
using System;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using System.ComponentModel;
+using System.Security.Cryptography;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
///
/// Represents a contiguous block of memory in the remote process.
diff --git a/Process.NET/Memory/MemoryType.cs b/Process.NET/Memory/MemoryType.cs
index 88291aa..70a6740 100644
--- a/Process.NET/Memory/MemoryType.cs
+++ b/Process.NET/Memory/MemoryType.cs
@@ -4,7 +4,7 @@
using System.Text;
using System.Threading.Tasks;
-namespace Process.NET.Memory
+namespace ProcessNET.Memory
{
public enum MemoryType
{
diff --git a/Process.NET/Modules/IModuleFactory.cs b/Process.NET/Modules/IModuleFactory.cs
index 5304a8a..23b334b 100644
--- a/Process.NET/Modules/IModuleFactory.cs
+++ b/Process.NET/Modules/IModuleFactory.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
public interface IModuleFactory : IDisposable
{
diff --git a/Process.NET/Modules/IProcessFunction.cs b/Process.NET/Modules/IProcessFunction.cs
index b322f09..462cb99 100644
--- a/Process.NET/Modules/IProcessFunction.cs
+++ b/Process.NET/Modules/IProcessFunction.cs
@@ -1,6 +1,6 @@
using System;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
public interface IProcessFunction
{
diff --git a/Process.NET/Modules/IProcessModule.cs b/Process.NET/Modules/IProcessModule.cs
index 45cfde3..13b3209 100644
--- a/Process.NET/Modules/IProcessModule.cs
+++ b/Process.NET/Modules/IProcessModule.cs
@@ -1,7 +1,7 @@
using System.Diagnostics;
-using Process.NET.Memory;
+using ProcessNET.Memory;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
public interface IProcessModule : IPointer
{
diff --git a/Process.NET/Modules/InjectedModule.cs b/Process.NET/Modules/InjectedModule.cs
index 6ffaa8e..9385f2e 100644
--- a/Process.NET/Modules/InjectedModule.cs
+++ b/Process.NET/Modules/InjectedModule.cs
@@ -1,9 +1,9 @@
using System;
using System.Diagnostics;
using System.Linq;
-using Process.NET.Marshaling;
+using ProcessNET.Marshaling;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
///
/// Class representing an injected module in a remote process.
diff --git a/Process.NET/Modules/ModuleFactory.cs b/Process.NET/Modules/ModuleFactory.cs
index 5d7ae71..aaa3e99 100644
--- a/Process.NET/Modules/ModuleFactory.cs
+++ b/Process.NET/Modules/ModuleFactory.cs
@@ -3,9 +3,9 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
-using Process.NET.Memory;
+using ProcessNET.Memory;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
///
/// Class providing tools for manipulating modules and libraries.
@@ -157,8 +157,9 @@ public IProcessModule FetchModule(string moduleName)
if (!Path.HasExtension(moduleName))
moduleName += ".dll";
+ var module = NativeModules.First(m => m.ModuleName.ToLower() == moduleName);
// Fetch and return the module
- return new RemoteModule(ProcessPlus, NativeModules.First(m => m.ModuleName.ToLower() == moduleName));
+ return FetchModule(module);
}
///
@@ -168,7 +169,11 @@ public IProcessModule FetchModule(string moduleName)
/// A new instance of a class.
public IProcessModule FetchModule(ProcessModule module)
{
- return FetchModule(module.ModuleName);
+ if (module is null)
+ {
+ throw new ArgumentNullException(nameof(module));
+ }
+ return new RemoteModule(ProcessPlus, module);
}
}
}
\ No newline at end of file
diff --git a/Process.NET/Modules/RemoteFunction.cs b/Process.NET/Modules/RemoteFunction.cs
index d186566..8be51bb 100644
--- a/Process.NET/Modules/RemoteFunction.cs
+++ b/Process.NET/Modules/RemoteFunction.cs
@@ -1,8 +1,8 @@
using System;
using System.Runtime.InteropServices;
-using Process.NET.Memory;
+using ProcessNET.Memory;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
///
/// Class representing a function in the remote process.
diff --git a/Process.NET/Modules/RemoteModule.cs b/Process.NET/Modules/RemoteModule.cs
index bc8d7c8..1eaade8 100644
--- a/Process.NET/Modules/RemoteModule.cs
+++ b/Process.NET/Modules/RemoteModule.cs
@@ -2,12 +2,12 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
-using Process.NET.Extensions;
-using Process.NET.Memory;
-using Process.NET.Native.Types;
-using Process.NET.Utilities;
+using ProcessNET.Extensions;
+using ProcessNET.Memory;
+using ProcessNET.Native.Types;
+using ProcessNET.Utilities;
-namespace Process.NET.Modules
+namespace ProcessNET.Modules
{
///
/// Class repesenting a module in the remote process.
diff --git a/Process.NET/Native/Advapi32.cs b/Process.NET/Native/Advapi32.cs
index 9bef8c0..f10fdb2 100644
--- a/Process.NET/Native/Advapi32.cs
+++ b/Process.NET/Native/Advapi32.cs
@@ -1,8 +1,8 @@
using System;
using System.Runtime.InteropServices;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Native
+namespace ProcessNET.Native
{
public static class Advapi32
{
@@ -24,5 +24,9 @@ public static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
int zero,
IntPtr null1,
IntPtr null2);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ public static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
+
}
}
\ No newline at end of file
diff --git a/Process.NET/Native/Callbacks.cs b/Process.NET/Native/Callbacks.cs
index 07bf8ba..c9a642b 100644
--- a/Process.NET/Native/Callbacks.cs
+++ b/Process.NET/Native/Callbacks.cs
@@ -1,6 +1,6 @@
using System;
-namespace Process.NET.Native
+namespace ProcessNET.Native
{
///
/// This delegate matches the type of parameter "lpfn" for the NativeMethods method "SetWindowsHookEx".
diff --git a/Process.NET/Native/DbgHelp.cs b/Process.NET/Native/DbgHelp.cs
new file mode 100644
index 0000000..7fef2f7
--- /dev/null
+++ b/Process.NET/Native/DbgHelp.cs
@@ -0,0 +1,25 @@
+using System.Runtime.InteropServices;
+using System.Text;
+using ProcessNET.Native.Types;
+
+namespace ProcessNET.Native
+{
+ public static class DbgHelp
+ {
+ private const string DLLName = "dbghelp.dll";
+ [DllImport(DLLName, SetLastError = true, PreserveSig = true)]
+ private static extern int UnDecorateSymbolName(
+ [In] [MarshalAs(UnmanagedType.LPStr)] string DecoratedName,
+ [Out] StringBuilder UnDecoratedName,
+ [In] [MarshalAs(UnmanagedType.U4)] int UndecoratedLength,
+ [In] [MarshalAs(UnmanagedType.U4)] UnDecorateFlags Flags);
+
+
+ public static string UnDecorateSymbolName(string name, UnDecorateFlags flags)
+ {
+ StringBuilder undecorated = new StringBuilder(255);
+ UnDecorateSymbolName(name, undecorated, undecorated.Capacity, flags);
+ return undecorated.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Process.NET/Native/Kernel32.cs b/Process.NET/Native/Kernel32.cs
index 2278f63..9a7edc0 100644
--- a/Process.NET/Native/Kernel32.cs
+++ b/Process.NET/Native/Kernel32.cs
@@ -2,10 +2,10 @@
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
-using Process.NET.Native.Types;
-using Process.NET.Windows;
+using ProcessNET.Native.Types;
+using ProcessNET.Windows;
-namespace Process.NET.Native
+namespace ProcessNET.Native
{
public static class Kernel32
{
diff --git a/Process.NET/Native/Nt.cs b/Process.NET/Native/Nt.cs
index 07f77c6..52570e1 100644
--- a/Process.NET/Native/Nt.cs
+++ b/Process.NET/Native/Nt.cs
@@ -1,11 +1,39 @@
using System;
using System.Runtime.InteropServices;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Native
+namespace ProcessNET.Native
{
public static class Nt
{
+ [DllImport("ntdll.dll")]
+ public static extern int NtAllocateVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, uint zeroBits, ref uint regionSize, uint allocationType, uint protect);
+
+ [DllImport("ntdll.dll")]
+ public static extern int NtWriteVirtualMemory(IntPtr processHandle, IntPtr baseAddress, byte[] buffer, uint bufferSize, out uint written);
+
+ [DllImport("ntdll.dll")]
+ public static extern int RtlCreateUserThread(SafeMemoryHandle processHandle, IntPtr securityDescriptor, bool createSuspended, uint zeroBits, IntPtr zeroReserve, IntPtr zeroCommit, IntPtr startAddress, IntPtr startParameter, ref IntPtr threadHandle, ref NtClientId clientid);
+
+ [DllImport("ntdll.dll")]
+ public static extern int NtWaitForSingleObject(IntPtr threadHandle, bool alertable, LARGE_INTEGER largeInt);
+
+ [DllImport("ntdll.dll")]
+ public static extern int NtClose(IntPtr handle);
+
+ [DllImport("ntdll.dll")]
+ public static extern int NtProtectVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, ref uint numberOfBytes, uint newProtect, ref uint oldProtect);
+
+
+ [DllImport("ntdll.dll")]
+ public static extern int NtFreeVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, uint regionSize, uint freeType);
+
+ [DllImport("ntdll.dll", SetLastError = true)]
+ public static extern SafeMemoryHandle RtlCreateUserThread(SafeMemoryHandle processHandle, IntPtr threadSecurity, bool createSuspended, Int32 stackZeroBits, IntPtr stackReserved,
+ IntPtr stackCommit, IntPtr startAddress, IntPtr parameter, ref IntPtr threadHandle, ref IntPtr clientId);
+
+ public const uint INFINITE = 0xFFFFFFFF;
+
///
/// Retrieves information about the specified process.
///
@@ -63,5 +91,16 @@ public static extern int NtQueryInformationProcess(SafeMemoryHandle processHandl
[DllImport("ntdll.dll")]
public static extern int NtQueryInformationThread(SafeMemoryHandle hwnd, int infoclass,
ref ThreadBasicInformation threadinfo, int length, IntPtr bytesread);
+
+
+ ///
+ /// Check if the returned flag from an Nt function call represents an operation success.
+ ///
+ /// The flag value to check.
+ /// True if the flag represents success.
+ public static bool IsNT_StatusSuccess(int value)
+ {
+ return (value >= 0 && value <= 0x3FFFFFFF) || (value >= 0x40000000 && value <= 0x7FFFFFFF);
+ }
}
}
\ No newline at end of file
diff --git a/Process.NET/Native/PSAPI.cs b/Process.NET/Native/PSAPI.cs
new file mode 100644
index 0000000..d4f6214
--- /dev/null
+++ b/Process.NET/Native/PSAPI.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+using ProcessNET.Native.Types;
+
+namespace ProcessNET.Native
+{
+ public static class PSAPI
+ {
+ [DllImport("psapi.dll", SetLastError = true)]
+ public static extern bool EnumProcessModulesEx(
+ IntPtr hProcess,
+ [Out] IntPtr lphModule,
+ UInt32 cb,
+ [MarshalAs(UnmanagedType.U4)] out UInt32 lpcbNeeded,
+ DwModuleFilterFlag dwff);
+
+ [DllImport("psapi.dll")]
+ public static extern uint GetModuleFileNameEx(
+ IntPtr hProcess,
+ IntPtr hModule,
+ [Out] StringBuilder lpBaseName,
+ [In][MarshalAs(UnmanagedType.U4)] int nSize);
+ }
+}
\ No newline at end of file
diff --git a/Process.NET/Native/Types/NativeEnums.cs b/Process.NET/Native/Types/NativeEnums.cs
index 2346425..486b93e 100644
--- a/Process.NET/Native/Types/NativeEnums.cs
+++ b/Process.NET/Native/Types/NativeEnums.cs
@@ -2,8 +2,83 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-namespace Process.NET.Native.Types
+namespace ProcessNET.Native.Types
{
+ [Flags]
+ public enum UnDecorateFlags
+ {
+ ///
+ /// Enable full undecoration
+ ///
+ UNDNAME_COMPLETE = (0x0000),
+ ///
+ /// Remove leading underscores from MS extended keywords
+ ///
+ UNDNAME_NO_LEADING_UNDERSCORES = (0x0001),
+ ///
+ /// Disable expansion of MS extended keywords
+ ///
+ UNDNAME_NO_MS_KEYWORDS = (0x0002),
+ ///
+ /// Disable expansion of return type for primary declaration
+ ///
+ UNDNAME_NO_FUNCTION_RETURNS = (0x0004),
+ ///
+ /// Disable expansion of the declaration model
+ ///
+ UNDNAME_NO_ALLOCATION_MODEL = (0x0008),
+ ///
+ /// Disable expansion of the declaration language specifier
+ ///
+ UNDNAME_NO_ALLOCATION_LANGUAGE = (0x0010),
+ ///
+ /// NYI Disable expansion of MS keywords on the 'this' type for primary declaration
+ ///
+ UNDNAME_NO_MS_THISTYPE = (0x0020),
+ ///
+ /// NYI Disable expansion of CV modifiers on the 'this' type for primary declaration
+ ///
+ UNDNAME_NO_CV_THISTYPE = (0x0040),
+ ///
+ /// Disable all modifiers on the 'this' type
+ ///
+ UNDNAME_NO_THISTYPE = (0x0060),
+ ///
+ /// Disable expansion of access specifiers for members
+ ///
+ UNDNAME_NO_ACCESS_SPECIFIERS = (0x0080),
+ ///
+ /// Disable expansion of 'throw-signatures' for functions and pointers to functions
+ ///
+ UNDNAME_NO_THROW_SIGNATURES = (0x0100),
+ ///
+ /// Disable expansion of 'static' or 'virtual'ness of members
+ ///
+ UNDNAME_NO_MEMBER_TYPE = (0x0200),
+ ///
+ /// Disable expansion of MS model for UDT returns
+ ///
+ UNDNAME_NO_RETURN_UDT_MODEL = (0x0400),
+ ///
+ /// Undecorate 32-bit decorated names
+ ///
+ UNDNAME_32_BIT_DECODE = (0x0800),
+ ///
+ /// Crack only the name for primary declaration;
+ ///
+ UNDNAME_NAME_ONLY = (0x1000),
+
+ ///
+ /// return just [scope::]name. Does expand template params
+ /// Don't undecorate arguments to function
+ ///
+ UNDNAME_NO_ARGUMENTS = (0x2000),
+ ///
+ /// Don't undecorate special names (v-table, vcall, vector xxx, metatype, etc)
+ ///
+ UNDNAME_NO_SPECIAL_SYMS = (0x4000),
+ }
+
///
/// A list of calling conventions.
///
@@ -906,6 +981,17 @@ public enum PebStructure
MinimumStackCommit = 0x208
}
+ [Flags]
+ public enum NtProcessAccessFlags
+ {
+ DELETE = 0x00010000,
+ READ_CONTROL = 0x00020000,
+ WRITE_DAC = 0x00040000,
+ WRITE_OWNER = 0x00080000,
+ SYNCHRONIZE = 0x00100000,
+ END = 0xFFF, //if you have Windows XP or Windows Server 2003 you must change this to 0xFFFF
+ PROCESS_ALL_ACCESS = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | END,
+ }
///
/// Process access rights list.
///
@@ -3056,4 +3142,14 @@ public enum SegmentRegisters
///
Ss
}
+ ///
+ /// Module filtering flag.
+ ///
+ public enum DwModuleFilterFlag : uint
+ {
+ LIST_MODULES_DEFAULT = 0x0, // This is the default one app would get without any flag.
+ LIST_MODULES_32BIT = 0x01, // list 32bit modules in the target process.
+ LIST_MODULES_64BIT = 0x02, // list all 64bit modules. 32bit exe will be stripped off.
+ LIST_MODULES_ALL = (LIST_MODULES_32BIT | LIST_MODULES_64BIT) // list all the modules
+ }
}
\ No newline at end of file
diff --git a/Process.NET/Native/Types/NativeStructs.cs b/Process.NET/Native/Types/NativeStructs.cs
index 31abd69..45f90e0 100644
--- a/Process.NET/Native/Types/NativeStructs.cs
+++ b/Process.NET/Native/Types/NativeStructs.cs
@@ -1,9 +1,9 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-using Process.NET.Marshaling;
+using ProcessNET.Marshaling;
-namespace Process.NET.Native.Types
+namespace ProcessNET.Native.Types
{
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
@@ -707,4 +707,40 @@ public struct WindowPlacement
///
public Rectangle NormalPosition;
}
+
+
+ [StructLayout(LayoutKind.Explicit, Size = 8)]
+ public struct LARGE_INTEGER
+ {
+ [FieldOffset(0)] public long QuadPart;
+
+ [FieldOffset(0)] public uint LowPart;
+ [FieldOffset(4)] public int HighPart;
+
+ [FieldOffset(0)] public int LowPartAsInt;
+ [FieldOffset(0)] public uint LowPartAsUInt;
+
+ [FieldOffset(4)] public int HighPartAsInt;
+ [FieldOffset(4)] public uint HighPartAsUInt;
+
+ public long ToInt64()
+ {
+ return ((long)this.HighPart << 32) | (uint)this.LowPartAsInt;
+ }
+
+ public static LARGE_INTEGER FromInt64(long value)
+ {
+ return new LARGE_INTEGER
+ {
+ LowPartAsInt = (int)(value),
+ HighPartAsInt = (int)((value >> 32))
+ };
+ }
+ }
+
+ public struct NtClientId
+ {
+ public IntPtr processHandle;
+ public IntPtr threadHandle;
+ }
}
\ No newline at end of file
diff --git a/Process.NET/Native/Types/SafeLoadLibrary.cs b/Process.NET/Native/Types/SafeLoadLibrary.cs
index 69752e5..ba6fd2a 100644
--- a/Process.NET/Native/Types/SafeLoadLibrary.cs
+++ b/Process.NET/Native/Types/SafeLoadLibrary.cs
@@ -1,6 +1,6 @@
using Microsoft.Win32.SafeHandles;
-namespace Process.NET.Native.Types
+namespace ProcessNET.Native.Types
{
///
/// Provides a safe handle for a library loaded via LoadLibraryEx.
diff --git a/Process.NET/Native/Types/SafeMemoryHandle.cs b/Process.NET/Native/Types/SafeMemoryHandle.cs
index 7738101..2a28395 100644
--- a/Process.NET/Native/Types/SafeMemoryHandle.cs
+++ b/Process.NET/Native/Types/SafeMemoryHandle.cs
@@ -3,7 +3,7 @@
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
-namespace Process.NET.Native.Types
+namespace ProcessNET.Native.Types
{
///
/// Represents a Win32 handle safely managed.
diff --git a/Process.NET/Native/User32.cs b/Process.NET/Native/User32.cs
index b9381df..361e748 100644
--- a/Process.NET/Native/User32.cs
+++ b/Process.NET/Native/User32.cs
@@ -2,9 +2,9 @@
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
-using Process.NET.Native.Types;
+using ProcessNET.Native.Types;
-namespace Process.NET.Native
+namespace ProcessNET.Native
{
public static class User32
{
@@ -108,8 +108,8 @@ public static class User32
/// to the variable; otherwise, it does not.
///
/// The return value is the identifier of the thread that created the window.
- [DllImport("user32.dll")]
- public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
+ [DllImport("user32.dll", SetLastError =true)]
+ public static extern int GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
///
/// Enumerates the child windows that belong to the specified parent window by passing the handle to each child window,
@@ -134,6 +134,42 @@ public static class User32
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
+ ///
+ /// Get the handle of the parent window of the passed child.
+ ///
+ ///
+ /// The handle of the window whose parent to get.
+ ///
+ ///
+ /// The handle of the parent window.
+ ///
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetParent(IntPtr hWnd);
+
+ ///
+ /// Retrieves a handle to a window whose class name and window name match the specified strings. The function searches child windows, beginning with the one following the specified child window.
+ /// This function does not perform a case-sensitive search.
+ ///
+ ///
+ /// A handle to the parent window whose child windows are to be searched.
+ /// If hwndParent is NULL, the function uses the desktop window as the parent window.
+ /// The function searches among windows that are child windows of the desktop.
+ /// If hwndParent is HWND_MESSAGE, the function searches all message-only windows.
+ ///
+ ///
+ /// A handle to a child window. The search begins with the next child window in the Z order.
+ /// The child window must be a direct child window of hwndParent, not just a descendant window.
+ /// If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.
+ /// Note that if both hwndParent and hwndChildAfter are NULL, the function searches all top-level and message-only windows.
+ ///
+ /// The class name or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
+ /// The atom must be placed in the low-order word of lpszClass; the high-order word must be zero.
+ ///
+ /// The window name (the window's title). If this parameter is NULL, all window names match.
+ ///
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
+
///
/// Flashes the specified window one time. It does not change the active state of the window.
/// To flash the window a specified number of times, use the function.
@@ -406,5 +442,10 @@ internal static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd,
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UnhookWindowsHookEx(IntPtr hhk);
+
+
+ [DllImport("user32.dll")]
+ public static extern bool EnumThreadWindows(int dwThreadId, EnumWindowsProc lpfn, IntPtr lParam);
+
}
}
\ No newline at end of file
diff --git a/Process.NET/Patterns/DwordPattern.cs b/Process.NET/Patterns/DwordPattern.cs
index 77f9434..83bc789 100644
--- a/Process.NET/Patterns/DwordPattern.cs
+++ b/Process.NET/Patterns/DwordPattern.cs
@@ -2,7 +2,7 @@
using System.Globalization;
using System.Linq;
-namespace Process.NET.Patterns
+namespace ProcessNET.Patterns
{
public class DwordPattern : IMemoryPattern
{
@@ -10,25 +10,30 @@ public class DwordPattern : IMemoryPattern
private readonly string _mask;
public readonly string PatternText;
+ public int SearchStartOffset { get; set; }
+ public MemoryPatternType PatternType { get; }
+ public PatternScannerAlgorithm Algorithm { get; }
- public DwordPattern(string dwordPattern)
+ public DwordPattern(string dwordPattern, int startOffset = 0, PatternScannerAlgorithm algorithm = PatternScannerAlgorithm.Naive)
{
+ this.PatternType = MemoryPatternType.Function;
+ this.Algorithm = algorithm;
+ this.SearchStartOffset = startOffset;
PatternText = dwordPattern;
- PatternType = MemoryPatternType.Function;
- Offset = 0;
_bytes = GetBytesFromDwordPattern(dwordPattern);
_mask = GetMaskFromDwordPattern(dwordPattern);
}
-
- public DwordPattern(string pattern, int offset)
+ public DwordPattern(byte[] pattern, int startOffset = 0, PatternScannerAlgorithm algorithm = PatternScannerAlgorithm.Naive)
{
- PatternText = pattern;
- PatternType = MemoryPatternType.Data;
- Offset = offset;
- _bytes = GetBytesFromDwordPattern(pattern);
- _mask = GetMaskFromDwordPattern(pattern);
+ this.PatternType = MemoryPatternType.Function;
+ this.Algorithm = algorithm;
+ this.SearchStartOffset = startOffset;
+ PatternText = string.Join(" ", pattern.Select(o => o.ToString("X2")));
+ _bytes = new byte[pattern.Length];
+ for (int i = 0; i < _bytes.Length; i++)
+ _bytes[i] = pattern[i];
+ _mask = new string(Enumerable.Repeat('x', _bytes.Length).ToArray());
}
-
public IList GetBytes()
{
return _bytes;
@@ -39,8 +44,6 @@ public string GetMask()
return _mask;
}
- public int Offset { get; }
- public MemoryPatternType PatternType { get; }
private static string GetMaskFromDwordPattern(string pattern)
{
diff --git a/Process.NET/Patterns/IMemoryPattern.cs b/Process.NET/Patterns/IMemoryPattern.cs
index e2cb229..631b716 100644
--- a/Process.NET/Patterns/IMemoryPattern.cs
+++ b/Process.NET/Patterns/IMemoryPattern.cs
@@ -1,11 +1,12 @@
using System.Collections.Generic;
-namespace Process.NET.Patterns
+namespace ProcessNET.Patterns
{
public interface IMemoryPattern
{
- int Offset { get; }
+ int SearchStartOffset { get; }
MemoryPatternType PatternType { get; }
+ PatternScannerAlgorithm Algorithm { get; }
IList GetBytes();
string GetMask();
}
diff --git a/Process.NET/Patterns/IPatternScanner.cs b/Process.NET/Patterns/IPatternScanner.cs
index 6218795..5481bf8 100644
--- a/Process.NET/Patterns/IPatternScanner.cs
+++ b/Process.NET/Patterns/IPatternScanner.cs
@@ -1,7 +1,7 @@
-namespace Process.NET.Patterns
+namespace ProcessNET.Patterns
{
public interface IPatternScanner
{
- PatternScanResult Find(IMemoryPattern pattern);
+ PatternScanResult Find(IMemoryPattern pattern, bool useCache = true);
}
}
\ No newline at end of file
diff --git a/Process.NET/Patterns/MemoryPatternType.cs b/Process.NET/Patterns/MemoryPatternType.cs
index b112937..1fc8e7d 100644
--- a/Process.NET/Patterns/MemoryPatternType.cs
+++ b/Process.NET/Patterns/MemoryPatternType.cs
@@ -1,4 +1,4 @@
-namespace Process.NET.Patterns
+namespace ProcessNET.Patterns
{
public enum MemoryPatternType
{
diff --git a/Process.NET/Patterns/PatternScanResult.cs b/Process.NET/Patterns/PatternScanResult.cs
index 16e5a1a..f76c948 100644
--- a/Process.NET/Patterns/PatternScanResult.cs
+++ b/Process.NET/Patterns/PatternScanResult.cs
@@ -1,6 +1,6 @@
using System;
-namespace Process.NET.Patterns
+namespace ProcessNET.Patterns
{
public struct PatternScanResult
{
@@ -8,5 +8,8 @@ public struct PatternScanResult
public IntPtr BaseAddress { get; set; }
public int Offset { get; set; }
public bool Found { get; set; }
+
+
+ public static PatternScanResult NotFound => new PatternScanResult();
}
}
\ No newline at end of file
diff --git a/Process.NET/Patterns/PatternScanner.cs b/Process.NET/Patterns/PatternScanner.cs
index 777ea15..00df858 100644
--- a/Process.NET/Patterns/PatternScanner.cs
+++ b/Process.NET/Patterns/PatternScanner.cs
@@ -1,83 +1,122 @@
using System;
+using System.Collections.Concurrent;
using System.Linq;
-using Process.NET.Modules;
+using ProcessNET.Memory;
+using ProcessNET.Modules;
+using ProcessNET.Utilities;
-namespace Process.NET.Patterns
+namespace ProcessNET.Patterns
{
public class PatternScanner : IPatternScanner
{
+ private class CachedPatternScanResult
+ {
+ public int Offset { get; set; }
+ public string ModuleName { get; set; }
+ }
+
+ static ConcurrentDictionary cache = null;
+
private readonly IProcessModule _module;
+ private readonly IProcess _process;
+ public byte[] Data { get; }
- public PatternScanner(IProcessModule module)
+ public PatternScanner(IProcess process, IProcessModule module)
{
+ this._process = process;
_module = module;
Data = module.Read(0, _module.Size);
}
+ static PatternScanner()
+ {
+ cache = new ConcurrentDictionary();
+ }
- public byte[] Data { get; }
- public PatternScanResult Find(IMemoryPattern pattern)
+ public PatternScanResult Find(IMemoryPattern pattern, bool useCache = true)
{
+ if(useCache && cache.TryGetValue(GetPatternCacheKey(pattern), out CachedPatternScanResult cachedResult))
+ {
+ return new PatternScanResult()
+ {
+ BaseAddress = _module.BaseAddress + cachedResult.Offset,
+ ReadAddress = _module.BaseAddress + cachedResult.Offset,
+ Offset = cachedResult.Offset,
+ Found = true,
+ };
+ }
+
return pattern.PatternType == MemoryPatternType.Function
? FindFunctionPattern(pattern)
: FindDataPattern(pattern);
}
-
- private PatternScanResult FindFunctionPattern(IMemoryPattern pattern)
+
+
+ private int GetOffset(IMemoryPattern pattern)
{
- var patternData = Data;
- var patternDataLength = patternData.Length;
-
- for (var offset = 0; offset < patternDataLength; offset++)
+ switch (pattern.Algorithm)
{
- if (
- pattern.GetMask()
- .Where((m, b) => m == 'x' && pattern.GetBytes()[b] != patternData[b + offset])
- .Any())
- continue;
-
- return new PatternScanResult
- {
- BaseAddress = _module.BaseAddress + offset,
- ReadAddress = _module.BaseAddress + offset,
- Offset = offset,
- Found = true
- };
+ case PatternScannerAlgorithm.Naive:
+ return StringSearching.Naive.GetIndexOf(pattern, Data, _module, pattern.SearchStartOffset);
+ case PatternScannerAlgorithm.BoyerMooreHorspool:
+ return StringSearching.BoyerMooreHorspool.IndexOf(Data, pattern.GetBytes().ToArray(), pattern.SearchStartOffset);
+ default:
+ throw new NotImplementedException($"Unknown search algorithm, please implement it, {pattern.Algorithm}.");
}
- return new PatternScanResult
+ }
+ private PatternScanResult FindFunctionPattern(IMemoryPattern pattern)
+ {
+ int offset = GetOffset(pattern);
+ if (offset < 0)
+ return PatternScanResult.NotFound;
+ PatternScanResult result = new PatternScanResult
{
- BaseAddress = IntPtr.Zero,
- ReadAddress = IntPtr.Zero,
- Offset = 0,
- Found = false
+ BaseAddress = _module.BaseAddress + offset,
+ ReadAddress = _module.BaseAddress + offset,
+ Offset = offset,
+ Found = true
};
+ CachePatternScanResult(pattern, result);
+ return result;
}
-
private PatternScanResult FindDataPattern(IMemoryPattern pattern)
{
- var patternData = Data;
- var patternBytes = pattern.GetBytes();
- var patternMask = pattern.GetMask();
+ int offset = GetOffset(pattern);
+ if (offset < 0)
+ return PatternScanResult.NotFound;
var result = new PatternScanResult();
+ // If this area is reached, the pattern has been found.
+ result.Found = true;
+ result.ReadAddress = _module.Read(offset);
+ result.BaseAddress = new IntPtr(result.ReadAddress.ToInt64() - _module.BaseAddress.ToInt64());
+ result.Offset = offset;
+ CachePatternScanResult(pattern, result);
+ return result;
+ }
- for (var offset = 0; offset < patternData.Length; offset++)
+ private string GetPatternCacheKey(IMemoryPattern pattern)
+ {
+ return $"{pattern.ToString()}_{_module.Name}_{_module.Path}_{pattern.SearchStartOffset}";
+ }
+ private void CachePatternScanResult(IMemoryPattern pattern, PatternScanResult result)
+ {
+ if (!result.Found)
+ return;
+ string key = GetPatternCacheKey(pattern);
+ CachedPatternScanResult cachedPatternScanResult = new CachedPatternScanResult()
{
- if (patternMask.Where((m, b) => m == 'x' && patternBytes[b] != patternData[b + offset]).Any())
- continue;
- // If this area is reached, the pattern has been found.
- result.Found = true;
- result.ReadAddress = _module.Read(offset + pattern.Offset);
- result.BaseAddress = new IntPtr(result.ReadAddress.ToInt64() - _module.BaseAddress.ToInt64());
- result.Offset = offset;
- return result;
- }
- // If this is reached, the pattern was not found.
- result.Found = false;
- result.Offset = 0;
- result.ReadAddress = IntPtr.Zero;
- result.BaseAddress = IntPtr.Zero;
- return result;
+ ModuleName = _module.Name,
+ Offset = result.Offset,
+ };
+
+ cache.AddOrUpdate(key, oldKey =>
+ {
+ return cachedPatternScanResult;
+ }, (oldKey, oldValue) =>
+ {
+ return cachedPatternScanResult;
+ });
}
}
}
\ No newline at end of file
diff --git a/Process.NET/Patterns/PatternScannerAlgorithm.cs b/Process.NET/Patterns/PatternScannerAlgorithm.cs
new file mode 100644
index 0000000..c7180d3
--- /dev/null
+++ b/Process.NET/Patterns/PatternScannerAlgorithm.cs
@@ -0,0 +1,8 @@
+namespace ProcessNET.Patterns
+{
+ public enum PatternScannerAlgorithm
+ {
+ Naive,
+ BoyerMooreHorspool,
+ }
+}
\ No newline at end of file
diff --git a/Process.NET/Process.NET.csproj b/Process.NET/Process.NET.csproj
index ba44703..8525d77 100644
--- a/Process.NET/Process.NET.csproj
+++ b/Process.NET/Process.NET.csproj
@@ -9,7 +9,7 @@
Properties
Process.NET
Process.NET
- v4.7.2
+ v4.5.2
512
@@ -80,25 +80,36 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\Fasm.NET.1.70.03.2\lib\Fasm.NET.dll
+
+
+
+
+
+
+
+
+
@@ -188,6 +199,9 @@
+
+
+