diff --git a/App.xaml.cs b/App.xaml.cs index 47352cb..a9f73cd 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace DeathloopTrainer { diff --git a/DeepPointer.cs b/DeepPointer.cs index 337b1ea..40c662c 100644 --- a/DeepPointer.cs +++ b/DeepPointer.cs @@ -10,223 +10,223 @@ namespace DeathloopTrainer { - using OffsetT = Int32; - - public class DeepPointer - { - private IntPtr _absoluteBase; - private bool _usingAbsoluteBase; - - private OffsetT _base; - private List _offsets; - private string _module; - - public DeepPointer(IntPtr absoluteBase, params OffsetT[] offsets) - { - _absoluteBase = absoluteBase; - _usingAbsoluteBase = true; - - InitializeOffsets(offsets); - } - - public DeepPointer(string module, OffsetT base_, params OffsetT[] offsets) - : this(base_, offsets) - { - _module = module.ToLower(); - } - - public DeepPointer(OffsetT base_, params OffsetT[] offsets) - { - _base = base_; - InitializeOffsets(offsets); - } - - public T Deref(Process process, T default_ = default(T)) where T : struct // all value types including structs - { - T val; - if (!Deref(process, out val)) - val = default_; - return val; - } - - public bool Deref(Process process, out T value) where T : struct - { - IntPtr ptr; - if (!DerefOffsets(process, out ptr) - || !process.ReadValue(ptr, out value)) - { - value = default(T); - return false; - } - - return true; - } - - public byte[] DerefBytes(Process process, int count) - { - byte[] bytes; - if (!DerefBytes(process, count, out bytes)) - bytes = null; - return bytes; - } - - public bool DerefBytes(Process process, int count, out byte[] value) - { - IntPtr ptr; - if (!DerefOffsets(process, out ptr) - || !process.ReadBytes(ptr, count, out value)) - { - value = null; - return false; - } - - return true; - } - - public string DerefString(Process process, int numBytes, string default_ = null) - { - string str; - if (!DerefString(process, ReadStringType.AutoDetect, numBytes, out str)) - str = default_; - return str; - } - - public string DerefString(Process process, ReadStringType type, int numBytes, string default_ = null) - { - string str; - if (!DerefString(process, type, numBytes, out str)) - str = default_; - return str; - } - - public bool DerefString(Process process, int numBytes, out string str) - { - return DerefString(process, ReadStringType.AutoDetect, numBytes, out str); - } - - public bool DerefString(Process process, ReadStringType type, int numBytes, out string str) - { - var sb = new StringBuilder(numBytes); - if (!DerefString(process, type, sb)) - { - str = null; - return false; - } - str = sb.ToString(); - return true; - } - - public bool DerefString(Process process, StringBuilder sb) - { - return DerefString(process, ReadStringType.AutoDetect, sb); - } - - public bool DerefString(Process process, ReadStringType type, StringBuilder sb) - { - IntPtr ptr; - if (!DerefOffsets(process, out ptr) - || !process.ReadString(ptr, type, sb)) - { - return false; - } - return true; - } - - public bool DerefOffsets(Process process, out IntPtr ptr) - { - bool is64Bit = process.Is64Bit(); - - if (!string.IsNullOrEmpty(_module)) - { - ProcessModuleWow64Safe module = process.ModulesWow64Safe() - .FirstOrDefault(m => m.ModuleName.ToLower() == _module); - if (module == null) - { - ptr = IntPtr.Zero; - return false; - } - - ptr = module.BaseAddress + _base; - } - else if (_usingAbsoluteBase) - { - ptr = _absoluteBase; - } - else - { - ptr = process.MainModuleWow64Safe().BaseAddress + _base; - } - - for (int i = 0; i < _offsets.Count - 1; i++) - { - if (!process.ReadPointer(ptr + _offsets[i], is64Bit, out ptr) - || ptr == IntPtr.Zero) - { - return false; - } - } - - ptr = ptr + _offsets[_offsets.Count - 1]; - return true; - } - - private void InitializeOffsets(params OffsetT[] offsets) - { - _offsets = new List(); - _offsets.Add(0); // deref base first - _offsets.AddRange(offsets); - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct Vector3f - { - public float X { get; set; } - public float Y { get; set; } - public float Z { get; set; } - - public int IX { get { return (int)X; } } - public int IY { get { return (int)Y; } } - public int IZ { get { return (int)Z; } } - - public Vector3f(float x, float y, float z) : this() - { - X = x; - Y = y; - Z = z; - } - - public float Distance(Vector3f other) - { - float result = (X - other.X) * (X - other.X) + - (Y - other.Y) * (Y - other.Y) + - (Z - other.Z) * (Z - other.Z); - return (float)Math.Sqrt(result); - } - - public float DistanceXY(Vector3f other) - { - float result = (X - other.X) * (X - other.X) + - (Y - other.Y) * (Y - other.Y); - return (float)Math.Sqrt(result); - } - - public bool BitEquals(Vector3f other) - { - return X.BitEquals(other.X) - && Y.BitEquals(other.Y) - && Z.BitEquals(other.Z); - } - - public bool BitEqualsXY(Vector3f other) - { - return X.BitEquals(other.X) - && Y.BitEquals(other.Y); - } - - public override string ToString() - { - return X + " " + Y + " " + Z; - } - } + using OffsetT = Int32; + + public class DeepPointer + { + private IntPtr _absoluteBase; + private bool _usingAbsoluteBase; + + private OffsetT _base; + private List _offsets; + private string _module; + + public DeepPointer(IntPtr absoluteBase, params OffsetT[] offsets) + { + _absoluteBase = absoluteBase; + _usingAbsoluteBase = true; + + InitializeOffsets(offsets); + } + + public DeepPointer(string module, OffsetT base_, params OffsetT[] offsets) + : this(base_, offsets) + { + _module = module.ToLower(); + } + + public DeepPointer(OffsetT base_, params OffsetT[] offsets) + { + _base = base_; + InitializeOffsets(offsets); + } + + public T Deref(Process process, T default_ = default(T)) where T : struct // all value types including structs + { + T val; + if (!Deref(process, out val)) + val = default_; + return val; + } + + public bool Deref(Process process, out T value) where T : struct + { + IntPtr ptr; + if (!DerefOffsets(process, out ptr) + || !process.ReadValue(ptr, out value)) + { + value = default(T); + return false; + } + + return true; + } + + public byte[] DerefBytes(Process process, int count) + { + byte[] bytes; + if (!DerefBytes(process, count, out bytes)) + bytes = null; + return bytes; + } + + public bool DerefBytes(Process process, int count, out byte[] value) + { + IntPtr ptr; + if (!DerefOffsets(process, out ptr) + || !process.ReadBytes(ptr, count, out value)) + { + value = null; + return false; + } + + return true; + } + + public string DerefString(Process process, int numBytes, string default_ = null) + { + string str; + if (!DerefString(process, ReadStringType.AutoDetect, numBytes, out str)) + str = default_; + return str; + } + + public string DerefString(Process process, ReadStringType type, int numBytes, string default_ = null) + { + string str; + if (!DerefString(process, type, numBytes, out str)) + str = default_; + return str; + } + + public bool DerefString(Process process, int numBytes, out string str) + { + return DerefString(process, ReadStringType.AutoDetect, numBytes, out str); + } + + public bool DerefString(Process process, ReadStringType type, int numBytes, out string str) + { + var sb = new StringBuilder(numBytes); + if (!DerefString(process, type, sb)) + { + str = null; + return false; + } + str = sb.ToString(); + return true; + } + + public bool DerefString(Process process, StringBuilder sb) + { + return DerefString(process, ReadStringType.AutoDetect, sb); + } + + public bool DerefString(Process process, ReadStringType type, StringBuilder sb) + { + IntPtr ptr; + if (!DerefOffsets(process, out ptr) + || !process.ReadString(ptr, type, sb)) + { + return false; + } + return true; + } + + public bool DerefOffsets(Process process, out IntPtr ptr) + { + bool is64Bit = process.Is64Bit(); + + if (!string.IsNullOrEmpty(_module)) + { + ProcessModuleWow64Safe module = process.ModulesWow64Safe() + .FirstOrDefault(m => m.ModuleName.ToLower() == _module); + if (module == null) + { + ptr = IntPtr.Zero; + return false; + } + + ptr = module.BaseAddress + _base; + } + else if (_usingAbsoluteBase) + { + ptr = _absoluteBase; + } + else + { + ptr = process.MainModuleWow64Safe().BaseAddress + _base; + } + + for (int i = 0; i < _offsets.Count - 1; i++) + { + if (!process.ReadPointer(ptr + _offsets[i], is64Bit, out ptr) + || ptr == IntPtr.Zero) + { + return false; + } + } + + ptr = ptr + _offsets[_offsets.Count - 1]; + return true; + } + + private void InitializeOffsets(params OffsetT[] offsets) + { + _offsets = new List(); + _offsets.Add(0); // deref base first + _offsets.AddRange(offsets); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct Vector3f + { + public float X { get; set; } + public float Y { get; set; } + public float Z { get; set; } + + public int IX { get { return (int)X; } } + public int IY { get { return (int)Y; } } + public int IZ { get { return (int)Z; } } + + public Vector3f(float x, float y, float z) : this() + { + X = x; + Y = y; + Z = z; + } + + public float Distance(Vector3f other) + { + float result = (X - other.X) * (X - other.X) + + (Y - other.Y) * (Y - other.Y) + + (Z - other.Z) * (Z - other.Z); + return (float)Math.Sqrt(result); + } + + public float DistanceXY(Vector3f other) + { + float result = (X - other.X) * (X - other.X) + + (Y - other.Y) * (Y - other.Y); + return (float)Math.Sqrt(result); + } + + public bool BitEquals(Vector3f other) + { + return X.BitEquals(other.X) + && Y.BitEquals(other.Y) + && Z.BitEquals(other.Z); + } + + public bool BitEqualsXY(Vector3f other) + { + return X.BitEquals(other.X) + && Y.BitEquals(other.Y); + } + + public override string ToString() + { + return X + " " + Y + " " + Z; + } + } } \ No newline at end of file diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 4c43f2e..d8e174e 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -8,426 +8,426 @@ namespace DeathloopTrainer { - public partial class MainWindow : Window - { + public partial class MainWindow : Window + { - globalKeyboardHook kbHook = new globalKeyboardHook(); - Timer updateTimer; - Process game; - public bool hooked = false; + globalKeyboardHook kbHook = new globalKeyboardHook(); + Timer updateTimer; + Process game; + public bool hooked = false; - DeepPointer characterDP = new DeepPointer(0x02D5F688, 0x8, 0x8, 0x98, 0xA0, 0x1F0, 0x0); - DeepPointer statusDP = new DeepPointer(0x900); + DeepPointer characterDP = new DeepPointer(0x02D5F688, 0x8, 0x8, 0x98, 0xA0, 0x1F0, 0x0); + DeepPointer statusDP = new DeepPointer(0x900); - IntPtr xVelPtr, yVelPtr, zVelPtr, xPosPtr, yPosPtr, zPosPtr, godPtr, ammoPtr; + IntPtr xVelPtr, yVelPtr, zVelPtr, xPosPtr, yPosPtr, zPosPtr, godPtr, ammoPtr; - bool god, ammo, teleFw = false; - float[] storedPos = new float[5] { 0f, 0f, 0f, 0f, 0f }; + bool god, ammo, teleFw = false; + float[] storedPos = new float[5] { 0f, 0f, 0f, 0f, 0f }; - float xVel, yVel, zVel, xPos, yPos, zPos; + float xVel, yVel, zVel, xPos, yPos, zPos; private void teleportFwBtn_Click(object sender, RoutedEventArgs e) { - e.Handled = true; - TeleportForward(); + e.Handled = true; + TeleportForward(); } private void godModeBtn_Click(object sender, RoutedEventArgs e) { - e.Handled = true; - ToggleGod(); + e.Handled = true; + ToggleGod(); } private void ammoBtn_Click(object sender, RoutedEventArgs e) { - e.Handled = true; - ToggleAmmo(); + e.Handled = true; + ToggleAmmo(); } private void saveBtn_Click(object sender, RoutedEventArgs e) { - e.Handled = true; - StorePosition(); + e.Handled = true; + StorePosition(); } private void teleBtn_Click(object sender, RoutedEventArgs e) { - e.Handled = true; - Teleport(); + e.Handled = true; + Teleport(); } - public MainWindow() - { - InitializeComponent(); - kbHook.KeyDown += InputKeyDown; - kbHook.KeyUp += InputKeyUp; - kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F1); - kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F2); - kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F3); - kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F5); - kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F6); - - updateTimer = new Timer - { - Interval = 16 // ~60 Hz - }; - updateTimer.Tick += new EventHandler(Update); - updateTimer.Start(); - } - - private void Update(object sender, EventArgs e) - { - if (game == null || game.HasExited) - { - game = null; - hooked = false; - } - if (!hooked) - hooked = Hook(); - if (!hooked) - return; - try - { - DerefPointers(); - } - catch (Exception) - { - return; - } - - Debug.WriteLine(game.Modules.Count); - - game.ReadValue(xPosPtr, out xPos); - game.ReadValue(yPosPtr, out yPos); - game.ReadValue(zPosPtr, out zPos); - - game.ReadValue(xVelPtr, out xVel); - game.ReadValue(yVelPtr, out yVel); - game.ReadValue(zVelPtr, out zVel); - double hVel = (Math.Sqrt(xVel * xVel + yVel * yVel)); - - game.ReadValue(godPtr, out god); - game.ReadValue(ammoPtr, out ammo); - - - SetLabel(god, godModeLabel); - SetLabel(ammo, ammoLabel); - - - positionBlock.Text = (xPos).ToString("0.00") + "\n" + (yPos).ToString("0.00") + "\n" + (zPos).ToString("0.00"); - speedBlock.Text = hVel.ToString("0.00") + " m/s"; - if(teleFw) - { - TeleportForward(); + public MainWindow() + { + InitializeComponent(); + kbHook.KeyDown += InputKeyDown; + kbHook.KeyUp += InputKeyUp; + kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F1); + kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F2); + kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F3); + kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F5); + kbHook.HookedKeys.Add(System.Windows.Forms.Keys.F6); + + updateTimer = new Timer + { + Interval = 16 // ~60 Hz + }; + updateTimer.Tick += new EventHandler(Update); + updateTimer.Start(); + } + + private void Update(object sender, EventArgs e) + { + if (game == null || game.HasExited) + { + game = null; + hooked = false; + } + if (!hooked) + hooked = Hook(); + if (!hooked) + return; + try + { + DerefPointers(); + } + catch (Exception) + { + return; + } + + Debug.WriteLine(game.Modules.Count); + + game.ReadValue(xPosPtr, out xPos); + game.ReadValue(yPosPtr, out yPos); + game.ReadValue(zPosPtr, out zPos); + + game.ReadValue(xVelPtr, out xVel); + game.ReadValue(yVelPtr, out yVel); + game.ReadValue(zVelPtr, out zVel); + double hVel = (Math.Sqrt(xVel * xVel + yVel * yVel)); + + game.ReadValue(godPtr, out god); + game.ReadValue(ammoPtr, out ammo); + + + SetLabel(god, godModeLabel); + SetLabel(ammo, ammoLabel); + + + positionBlock.Text = (xPos).ToString("0.00") + "\n" + (yPos).ToString("0.00") + "\n" + (zPos).ToString("0.00"); + speedBlock.Text = hVel.ToString("0.00") + " m/s"; + if (teleFw) + { + TeleportForward(); + } + } + + private bool Hook() + { + List processList = Process.GetProcesses().ToList().FindAll(x => x.ProcessName == "Deathloop"); + if (processList.Count == 0) + { + game = null; + return false; + } + game = processList[0]; + + if (game.HasExited) + return false; + + try + { + if (game.Modules.Count < 110) + return false; } - } - - private bool Hook() - { - List processList = Process.GetProcesses().ToList().FindAll(x => x.ProcessName == "Deathloop"); - if (processList.Count == 0) - { - game = null; - return false; - } - game = processList[0]; - - if (game.HasExited) - return false; - - try - { - if (game.Modules.Count < 110) - return false; - } - catch - { - return false; + catch + { + return false; } - if(new DeepPointer(0x900).Deref(game, out byte statusByte)) - { - Debug.WriteLine(statusByte); - if(statusByte != (byte)0x1) - { - bool success = false; - while(!success) - { - Debug.WriteLine("attempting to write function hooks"); - success = WriteFunctionHooks(); + if (new DeepPointer(0x900).Deref(game, out byte statusByte)) + { + Debug.WriteLine(statusByte); + if (statusByte != (byte)0x1) + { + bool success = false; + while (!success) + { + Debug.WriteLine("attempting to write function hooks"); + success = WriteFunctionHooks(); } } - return true; + return true; } - return false; - } - - - - private void DerefPointers() - { - characterDP.DerefOffsets(game, out IntPtr basePtr); - xPosPtr = basePtr + 0x80; - yPosPtr = basePtr + 0x84; - zPosPtr = basePtr + 0x88; - xVelPtr = basePtr + 0xB0; - yVelPtr = basePtr + 0xB4; - zVelPtr = basePtr + 0xB8; - - statusDP.DerefOffsets(game, out IntPtr statusBasePtr); - godPtr = statusBasePtr + 0x10; - ammoPtr = statusBasePtr + 0x20; - - } - - private void InputKeyDown(object sender, KeyEventArgs e) - { - switch (e.KeyCode) - { - case Keys.F1: - teleFw = true; - break; - case Keys.F2: - ToggleGod(); - break; - case Keys.F3: - ToggleAmmo(); - break; - case Keys.F5: - StorePosition(); - break; - case Keys.F6: - Teleport(); - break; - default: - break; - } - e.Handled = true; - } + return false; + } + + + + private void DerefPointers() + { + characterDP.DerefOffsets(game, out IntPtr basePtr); + xPosPtr = basePtr + 0x80; + yPosPtr = basePtr + 0x84; + zPosPtr = basePtr + 0x88; + xVelPtr = basePtr + 0xB0; + yVelPtr = basePtr + 0xB4; + zVelPtr = basePtr + 0xB8; + + statusDP.DerefOffsets(game, out IntPtr statusBasePtr); + godPtr = statusBasePtr + 0x10; + ammoPtr = statusBasePtr + 0x20; + + } + + private void InputKeyDown(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.F1: + teleFw = true; + break; + case Keys.F2: + ToggleGod(); + break; + case Keys.F3: + ToggleAmmo(); + break; + case Keys.F5: + StorePosition(); + break; + case Keys.F6: + Teleport(); + break; + default: + break; + } + e.Handled = true; + } private void ToggleAmmo() { - if (!hooked) - return; + if (!hooked) + return; - game.WriteValue(ammoPtr, !ammo); - } + game.WriteValue(ammoPtr, !ammo); + } private void ToggleGod() { - if (!hooked) - return; + if (!hooked) + return; - game.WriteValue(godPtr, !god); - } + game.WriteValue(godPtr, !god); + } private void TeleportForward() { - if (!hooked) - return; + if (!hooked) + return; + + float a = new DeepPointer(0x3283134).Deref(game); + float b = new DeepPointer(0x3283138).Deref(game); + System.Windows.Media.Media3D.Quaternion q = new System.Windows.Media.Media3D.Quaternion(0, b, 0, a); + float angle = ((float)((q.Angle / 2) * -q.Axis.Y)); + angle = (float)(angle / 180 * Math.PI); + + double x = 0, y = 0; + x += Math.Sin(angle + Math.PI / 2) * 1; + y += Math.Cos(angle + Math.PI / 2) * 1; + Debug.WriteLine(x + ", " + y); + float scale = 1f; + + game.WriteBytes(xPosPtr, BitConverter.GetBytes((float)(xPos + (float)(x * scale * 1)))); + game.WriteBytes(yPosPtr, BitConverter.GetBytes((float)(yPos + (float)(y * scale * 1)))); + } - float a = new DeepPointer(0x3283134).Deref(game); - float b = new DeepPointer(0x3283138).Deref(game); - System.Windows.Media.Media3D.Quaternion q = new System.Windows.Media.Media3D.Quaternion(0, b, 0, a); - float angle = ((float)((q.Angle / 2) * -q.Axis.Y)); - angle = (float)(angle / 180 * Math.PI); + private void Teleport() + { + if (!hooked) + return; + game.WriteBytes(xPosPtr, BitConverter.GetBytes(storedPos[0])); + game.WriteBytes(yPosPtr, BitConverter.GetBytes(storedPos[1])); + game.WriteBytes(zPosPtr, BitConverter.GetBytes(storedPos[2])); + + game.WriteBytes(xVelPtr, BitConverter.GetBytes(0f)); + game.WriteBytes(yVelPtr, BitConverter.GetBytes(0f)); + game.WriteBytes(zVelPtr, BitConverter.GetBytes(0f)); + } - double x = 0, y = 0; - x += Math.Sin(angle + Math.PI / 2) * 1; - y += Math.Cos(angle + Math.PI / 2) * 1; - Debug.WriteLine(x + ", " + y); - float scale = 1f; + private void SetLabel(bool state, System.Windows.Controls.Label label) + { + if (state) + { + label.Content = "ON"; + label.Foreground = Brushes.Green; + } + else + { + label.Content = "OFF"; + label.Foreground = Brushes.Red; + } + } - game.WriteBytes(xPosPtr, BitConverter.GetBytes((float)(xPos + (float)(x * scale * 1)))); - game.WriteBytes(yPosPtr, BitConverter.GetBytes((float)(yPos + (float)(y * scale * 1)))); - } + private void StorePosition() + { + if (!hooked) + return; + storedPos = new float[3] { xPos, yPos, zPos }; + return; + } - private void Teleport() - { - if (!hooked) - return; - game.WriteBytes(xPosPtr, BitConverter.GetBytes(storedPos[0])); - game.WriteBytes(yPosPtr, BitConverter.GetBytes(storedPos[1])); - game.WriteBytes(zPosPtr, BitConverter.GetBytes(storedPos[2])); - - game.WriteBytes(xVelPtr, BitConverter.GetBytes(0f)); - game.WriteBytes(yVelPtr, BitConverter.GetBytes(0f)); - game.WriteBytes(zVelPtr, BitConverter.GetBytes(0f)); - } - - private void SetLabel(bool state, System.Windows.Controls.Label label) - { - if (state) - { - label.Content = "ON"; - label.Foreground = Brushes.Green; - } - else - { - label.Content = "OFF"; - label.Foreground = Brushes.Red; - } - } - - private void StorePosition() - { - if (!hooked) - return; - storedPos = new float[3] { xPos, yPos, zPos }; - return; - } - - private void InputKeyUp(object sender, KeyEventArgs e) - { - switch (e.KeyCode) - { - case Keys.F1: - teleFw = false; - break; - } - e.Handled = true; - } - - private bool WriteFunctionHooks() - { - SignatureScanner scanner = new SignatureScanner(game, game.MainModule.BaseAddress, (int)game.MainModule.ModuleMemorySize); - - SigScanTarget antiDebugSig = new SigScanTarget("FF 50 38 88 44 24 70 E8 ?? ?? ?? ?? 0F B6 C0 83 F8 01 0F 85 ?? ?? ?? ?? C7 84 24 F8 01 00 00 3C 00 00 00"); - IntPtr antiDbgPtr = scanner.Scan(antiDebugSig); - if(antiDbgPtr != IntPtr.Zero) - { - game.WriteBytes(antiDbgPtr, StringToByteArray("B0 01 90")); + private void InputKeyUp(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.F1: + teleFw = false; + break; + } + e.Handled = true; + } + + private bool WriteFunctionHooks() + { + SignatureScanner scanner = new SignatureScanner(game, game.MainModule.BaseAddress, (int)game.MainModule.ModuleMemorySize); + + SigScanTarget antiDebugSig = new SigScanTarget("FF 50 38 88 44 24 70 E8 ?? ?? ?? ?? 0F B6 C0 83 F8 01 0F 85 ?? ?? ?? ?? C7 84 24 F8 01 00 00 3C 00 00 00"); + IntPtr antiDbgPtr = scanner.Scan(antiDebugSig); + if (antiDbgPtr != IntPtr.Zero) + { + game.WriteBytes(antiDbgPtr, StringToByteArray("B0 01 90")); + } + + + SigScanTarget getPlayerSig = new SigScanTarget("?? ?? ?? ?? ?? 48 83 C4 20 5F C3 83 FB 03"); + + IntPtr getPlayerPtr = IntPtr.Zero; + getPlayerPtr = scanner.Scan(getPlayerSig); + if (getPlayerPtr == IntPtr.Zero) + { + throw new Exception("Can't Find GetPlayer Signature"); } + _ = new DeepPointer(0x900).DerefOffsets(game, out IntPtr statusPtr); + IntPtr godModePtr = statusPtr + 0x10; + IntPtr ammoInfPtr = statusPtr + 0x20; + _ = new DeepPointer(0x500).DerefOffsets(game, out IntPtr newGetPlayerPtr); + _ = new DeepPointer(0x800).DerefOffsets(game, out IntPtr playerPtr); + byte[] newGetPlayerCode = StringToByteArray("48 A3 " + IntPtrToASMString(playerPtr) + + " 48 8B 74 24 40"); + + game.WriteBytes(newGetPlayerPtr, newGetPlayerCode); + + long jumpOffset = getPlayerPtr.ToInt64() - newGetPlayerPtr.ToInt64() - newGetPlayerCode.Length; + byte[] jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); + game.WriteBytes(newGetPlayerPtr + newGetPlayerCode.Length, jumpCode); + + jumpOffset = newGetPlayerPtr.ToInt64() - getPlayerPtr.ToInt64() - 0x5; + jumpCode = jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4)); + + game.WriteBytes(getPlayerPtr, jumpCode); + + + SigScanTarget applyDamageSig = new SigScanTarget("?? ?? ?? ?? ?? ?? ?? 0F 28 C1 75 ?? 80 B9"); + IntPtr applyDamagePtr = scanner.Scan(applyDamageSig); + if (applyDamagePtr == IntPtr.Zero) + { + throw new Exception("Can't Find ApplyDamage Signature"); + } + + _ = new DeepPointer(0x550).DerefOffsets(game, out IntPtr newApplyDamagePtr); + jumpOffset = godModePtr.ToInt64() - newApplyDamagePtr.ToInt64() - 0x9; + byte[] newApplyDamageCode = StringToByteArray("53 52 48 8B 1D " + IntPtrToASMString(new IntPtr(jumpOffset), 4) + + " 48 83 FB 01 75 11 48 8B 59 70 48 BA " + IntPtrToASMString(playerPtr) + + " 48 3B 1A 5A 5B 75 01 C3 80 B9 18 04 00 00 00"); + game.WriteBytes(newApplyDamagePtr, newApplyDamageCode); + + jumpOffset = applyDamagePtr.ToInt64() - newApplyDamagePtr.ToInt64() - newApplyDamageCode.Length + 2; + jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); + game.WriteBytes(newApplyDamagePtr + newApplyDamageCode.Length, jumpCode); + + jumpOffset = newApplyDamagePtr.ToInt64() - applyDamagePtr.ToInt64() - 0x5; + jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4) + " 66 90"); + game.WriteBytes(applyDamagePtr, jumpCode); - SigScanTarget getPlayerSig = new SigScanTarget("?? ?? ?? ?? ?? 48 83 C4 20 5F C3 83 FB 03"); - IntPtr getPlayerPtr = IntPtr.Zero; - getPlayerPtr = scanner.Scan(getPlayerSig); - if(getPlayerPtr == IntPtr.Zero) - { - throw new Exception("Can't Find GetPlayer Signature"); + SigScanTarget applyWaterDamageSig = new SigScanTarget("?? ?? ?? ?? ?? 57 48 83 EC ?? 80 B9 ?? ?? ?? ?? 00 41 0F B6 F8 0F 29"); + IntPtr applyWaterDamagePtr = scanner.Scan(applyWaterDamageSig); + if (applyWaterDamagePtr == IntPtr.Zero) + { + throw new Exception("Can't Find GetPlayer Signature"); } - _ = new DeepPointer(0x900).DerefOffsets(game, out IntPtr statusPtr); - IntPtr godModePtr = statusPtr + 0x10; - IntPtr ammoInfPtr = statusPtr + 0x20; - _ = new DeepPointer(0x500).DerefOffsets(game, out IntPtr newGetPlayerPtr); - _ = new DeepPointer(0x800).DerefOffsets(game, out IntPtr playerPtr); - byte[] newGetPlayerCode = StringToByteArray("48 A3 " + IntPtrToASMString(playerPtr) - + " 48 8B 74 24 40"); - - game.WriteBytes(newGetPlayerPtr, newGetPlayerCode); - - long jumpOffset = getPlayerPtr.ToInt64() - newGetPlayerPtr.ToInt64() - newGetPlayerCode.Length; - byte[] jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); - game.WriteBytes(newGetPlayerPtr + newGetPlayerCode.Length, jumpCode); - - jumpOffset = newGetPlayerPtr.ToInt64() - getPlayerPtr.ToInt64() - 0x5; - jumpCode = jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4)); - - game.WriteBytes(getPlayerPtr, jumpCode); - - - SigScanTarget applyDamageSig = new SigScanTarget("?? ?? ?? ?? ?? ?? ?? 0F 28 C1 75 ?? 80 B9"); - IntPtr applyDamagePtr = scanner.Scan(applyDamageSig); - if (applyDamagePtr == IntPtr.Zero) - { - throw new Exception("Can't Find ApplyDamage Signature"); - } - - _ = new DeepPointer(0x550).DerefOffsets(game, out IntPtr newApplyDamagePtr); - jumpOffset = godModePtr.ToInt64() - newApplyDamagePtr.ToInt64() - 0x9; - byte[] newApplyDamageCode = StringToByteArray("53 52 48 8B 1D " + IntPtrToASMString(new IntPtr(jumpOffset), 4) + - " 48 83 FB 01 75 11 48 8B 59 70 48 BA " + IntPtrToASMString(playerPtr) + - " 48 3B 1A 5A 5B 75 01 C3 80 B9 18 04 00 00 00"); - game.WriteBytes(newApplyDamagePtr, newApplyDamageCode); - - jumpOffset = applyDamagePtr.ToInt64() - newApplyDamagePtr.ToInt64() - newApplyDamageCode.Length + 2; - jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); - game.WriteBytes(newApplyDamagePtr + newApplyDamageCode.Length, jumpCode); - - jumpOffset = newApplyDamagePtr.ToInt64() - applyDamagePtr.ToInt64() - 0x5; - jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4) + " 66 90"); - game.WriteBytes(applyDamagePtr, jumpCode); - - - SigScanTarget applyWaterDamageSig = new SigScanTarget("?? ?? ?? ?? ?? 57 48 83 EC ?? 80 B9 ?? ?? ?? ?? 00 41 0F B6 F8 0F 29"); - IntPtr applyWaterDamagePtr = scanner.Scan(applyWaterDamageSig); - if (applyWaterDamagePtr == IntPtr.Zero) - { - throw new Exception("Can't Find GetPlayer Signature"); - } - - _ = new DeepPointer(0x600).DerefOffsets(game, out IntPtr newApplyWaterDamagePtr); - jumpOffset = godModePtr.ToInt64() - newApplyWaterDamagePtr.ToInt64() - 0x9; - byte[] newApplyWaterDamageCode = StringToByteArray("53 52 48 8B 1D " + IntPtrToASMString(new IntPtr(jumpOffset), 4) + - " 48 83 FB 01 75 11 48 8B 59 70 48 BA " + IntPtrToASMString(playerPtr) + - " 48 3B 1A 5A 5B 75 01 C3 48 89 5C 24 08"); - game.WriteBytes(newApplyWaterDamagePtr, newApplyWaterDamageCode); - - jumpOffset = applyWaterDamagePtr.ToInt64() - newApplyWaterDamagePtr.ToInt64() - newApplyWaterDamageCode.Length; - jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); - game.WriteBytes(newApplyWaterDamagePtr + newApplyWaterDamageCode.Length, jumpCode); - - jumpOffset = newApplyWaterDamagePtr.ToInt64() - applyWaterDamagePtr.ToInt64() - 0x5; - jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4)); - game.WriteBytes(applyWaterDamagePtr, jumpCode); - - - SigScanTarget consumeAmmoSig = new SigScanTarget("?? ?? ?? ?? ?? 48 C7 44 24 ?? FE FF FF FF 48 89 5C 24 ?? 48 89 74 24 ?? 48 8B D9 44 8B 81"); - IntPtr consumeAmmoPtr = scanner.Scan(consumeAmmoSig); - if (consumeAmmoPtr == IntPtr.Zero) - { - throw new Exception("Can't Find ConsumeAmmo Signature"); - } - - _ = new DeepPointer(0x650).DerefOffsets(game, out IntPtr newConsumeAmmoPtr); - jumpOffset = ammoInfPtr.ToInt64() - newConsumeAmmoPtr.ToInt64() - 0x9; - - byte[] newConsumeAmmoCode = StringToByteArray("53 52 48 8B 1D " + IntPtrToASMString(new IntPtr(jumpOffset), 4) + - " 48 83 FB 01 75 18 48 8B 99 08 01 00 00 48 8B 5B 70 48 BA " + IntPtrToASMString(playerPtr) + - " 48 3B 1A 5A 5B 75 01 C3 40 57 48 83 EC 40"); - game.WriteBytes(newConsumeAmmoPtr, newConsumeAmmoCode); - - jumpOffset = consumeAmmoPtr.ToInt64() - newConsumeAmmoPtr.ToInt64() - newConsumeAmmoCode.Length; - jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); - game.WriteBytes(newConsumeAmmoPtr + newConsumeAmmoCode.Length, jumpCode); - - jumpOffset = newConsumeAmmoPtr.ToInt64() - consumeAmmoPtr.ToInt64() - 0x5; - jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4) + " 90"); - game.WriteBytes(consumeAmmoPtr, jumpCode); - - game.WriteValue(statusPtr, 0x1); - return true; - } - - - byte[] StringToByteArray(string input) - { - string[] byteStringArray = input.Split(' '); - byte[] output = new byte[byteStringArray.Length]; - for (int i = 0; i < byteStringArray.Length; i++) - { - output[i] = Byte.Parse(byteStringArray[i], System.Globalization.NumberStyles.HexNumber); - } - return output; - } - - string IntPtrToASMString(IntPtr input, int length = 8) - { - string ptrString = input.ToString("X16"); - string output = ""; - for (int i = 0; i < length; i++) - { - output += ptrString[14 - i * 2]; - output += ptrString[15 - i * 2]; - if (i != length - 1) - output += " "; - } - return output; - } - - } + _ = new DeepPointer(0x600).DerefOffsets(game, out IntPtr newApplyWaterDamagePtr); + jumpOffset = godModePtr.ToInt64() - newApplyWaterDamagePtr.ToInt64() - 0x9; + byte[] newApplyWaterDamageCode = StringToByteArray("53 52 48 8B 1D " + IntPtrToASMString(new IntPtr(jumpOffset), 4) + + " 48 83 FB 01 75 11 48 8B 59 70 48 BA " + IntPtrToASMString(playerPtr) + + " 48 3B 1A 5A 5B 75 01 C3 48 89 5C 24 08"); + game.WriteBytes(newApplyWaterDamagePtr, newApplyWaterDamageCode); + + jumpOffset = applyWaterDamagePtr.ToInt64() - newApplyWaterDamagePtr.ToInt64() - newApplyWaterDamageCode.Length; + jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); + game.WriteBytes(newApplyWaterDamagePtr + newApplyWaterDamageCode.Length, jumpCode); + + jumpOffset = newApplyWaterDamagePtr.ToInt64() - applyWaterDamagePtr.ToInt64() - 0x5; + jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4)); + game.WriteBytes(applyWaterDamagePtr, jumpCode); + + + SigScanTarget consumeAmmoSig = new SigScanTarget("?? ?? ?? ?? ?? 48 C7 44 24 ?? FE FF FF FF 48 89 5C 24 ?? 48 89 74 24 ?? 48 8B D9 44 8B 81"); + IntPtr consumeAmmoPtr = scanner.Scan(consumeAmmoSig); + if (consumeAmmoPtr == IntPtr.Zero) + { + throw new Exception("Can't Find ConsumeAmmo Signature"); + } + + _ = new DeepPointer(0x650).DerefOffsets(game, out IntPtr newConsumeAmmoPtr); + jumpOffset = ammoInfPtr.ToInt64() - newConsumeAmmoPtr.ToInt64() - 0x9; + + byte[] newConsumeAmmoCode = StringToByteArray("53 52 48 8B 1D " + IntPtrToASMString(new IntPtr(jumpOffset), 4) + + " 48 83 FB 01 75 18 48 8B 99 08 01 00 00 48 8B 5B 70 48 BA " + IntPtrToASMString(playerPtr) + + " 48 3B 1A 5A 5B 75 01 C3 40 57 48 83 EC 40"); + game.WriteBytes(newConsumeAmmoPtr, newConsumeAmmoCode); + + jumpOffset = consumeAmmoPtr.ToInt64() - newConsumeAmmoPtr.ToInt64() - newConsumeAmmoCode.Length; + jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr(jumpOffset), 4)); + game.WriteBytes(newConsumeAmmoPtr + newConsumeAmmoCode.Length, jumpCode); + + jumpOffset = newConsumeAmmoPtr.ToInt64() - consumeAmmoPtr.ToInt64() - 0x5; + jumpCode = StringToByteArray("E9 " + IntPtrToASMString(new IntPtr((uint)jumpOffset), 4) + " 90"); + game.WriteBytes(consumeAmmoPtr, jumpCode); + + game.WriteValue(statusPtr, 0x1); + return true; + } + + + byte[] StringToByteArray(string input) + { + string[] byteStringArray = input.Split(' '); + byte[] output = new byte[byteStringArray.Length]; + for (int i = 0; i < byteStringArray.Length; i++) + { + output[i] = Byte.Parse(byteStringArray[i], System.Globalization.NumberStyles.HexNumber); + } + return output; + } + + string IntPtrToASMString(IntPtr input, int length = 8) + { + string ptrString = input.ToString("X16"); + string output = ""; + for (int i = 0; i < length; i++) + { + output += ptrString[14 - i * 2]; + output += ptrString[15 - i * 2]; + if (i != length - 1) + output += " "; + } + return output; + } + + } } diff --git a/MemoryWatcher.cs b/MemoryWatcher.cs index 9feeb33..bf39013 100644 --- a/MemoryWatcher.cs +++ b/MemoryWatcher.cs @@ -8,284 +8,284 @@ namespace DeathloopTrainer { - public class MemoryWatcherList : List - { - public delegate void MemoryWatcherDataChangedEventHandler(MemoryWatcher watcher); - public event MemoryWatcherDataChangedEventHandler OnWatcherDataChanged; - - public MemoryWatcher this[string name] - { - get { return this.First(w => w.Name == name); } - } - - public void UpdateAll(Process process) - { - if (OnWatcherDataChanged != null) - { - var changedList = new List(); - - foreach (var watcher in this) - { - bool changed = watcher.Update(process); - if (changed) - changedList.Add(watcher); - } - - // only report changes when all of the other watches are updated too - foreach (var watcher in changedList) - { - OnWatcherDataChanged(watcher); - } - } - else - { - foreach (var watcher in this) - { - watcher.Update(process); - } - } - } - - public void ResetAll() - { - foreach (var watcher in this) - { - watcher.Reset(); - } - } - } - - public abstract class MemoryWatcher - { - public enum ReadFailAction - { - DontUpdate, - SetZeroOrNull, - } - - public string Name { get; set; } - public bool Enabled { get; set; } - public object Current { get; set; } - public object Old { get; set; } - public bool Changed { get; protected set; } - public TimeSpan? UpdateInterval { get; set; } - public ReadFailAction FailAction { get; set; } - - protected bool InitialUpdate { get; set; } - protected DateTime? LastUpdateTime { get; set; } - protected DeepPointer DeepPtr { get; set; } - protected IntPtr Address { get; set; } - - protected AddressType AddrType { get; } - protected enum AddressType { DeepPointer, Absolute } - - protected MemoryWatcher(DeepPointer pointer) - { - DeepPtr = pointer; - AddrType = AddressType.DeepPointer; - Enabled = true; - FailAction = ReadFailAction.DontUpdate; - } - - protected MemoryWatcher(IntPtr address) - { - Address = address; - AddrType = AddressType.Absolute; - Enabled = true; - FailAction = ReadFailAction.DontUpdate; - } - - /// - /// Updates the watcher and returns true if the value has changed. - /// - public abstract bool Update(Process process); - - public abstract void Reset(); - - protected bool CheckInterval() - { - if (UpdateInterval.HasValue) - { - if (LastUpdateTime.HasValue) - { - if (DateTime.Now - LastUpdateTime.Value < UpdateInterval.Value) - return false; - } - LastUpdateTime = DateTime.Now; - } - return true; - } - } - - public class StringWatcher : MemoryWatcher - { - public new string Current - { - get { return (string)base.Current; } - set { base.Current = value; } - } - public new string Old - { - get { return (string)base.Old; } - set { base.Old = value; } - } - - public delegate void StringChangedEventHandler(string old, string current); - public event StringChangedEventHandler OnChanged; - - private ReadStringType _stringType; - private int _numBytes; - - public StringWatcher(DeepPointer pointer, ReadStringType type, int numBytes) - : base(pointer) - { - _stringType = type; - _numBytes = numBytes; - } - - public StringWatcher(DeepPointer pointer, int numBytes) - : this(pointer, ReadStringType.AutoDetect, numBytes) { } - - public StringWatcher(IntPtr address, ReadStringType type, int numBytes) - : base(address) - { - _stringType = type; - _numBytes = numBytes; - } - - public StringWatcher(IntPtr address, int numBytes) - : this(address, ReadStringType.AutoDetect, numBytes) { } - - public override bool Update(Process process) - { - Changed = false; - - if (!Enabled) - return false; - - if (!CheckInterval()) - return false; - - string str; - bool success; - if (AddrType == AddressType.DeepPointer) - success = DeepPtr.DerefString(process, _stringType, _numBytes, out str); - else - success = process.ReadString(Address, _stringType, _numBytes, out str); - - if (success) - { - base.Old = base.Current; - base.Current = str; - } - else - { - if (FailAction == ReadFailAction.DontUpdate) - return false; - - base.Old = base.Current; - base.Current = str; - } - - if (!InitialUpdate) - { - InitialUpdate = true; - return false; - } - - if (!Current.Equals(Old)) - { - OnChanged?.Invoke(Old, Current); - Changed = true; - return true; - } - - return false; - } - - public override void Reset() - { - base.Current = null; - base.Old = null; - InitialUpdate = false; - } - } - - public class MemoryWatcher : MemoryWatcher where T : struct - { - public new T Current - { - get { return (T)(base.Current ?? default(T)); } - set { base.Current = value; } - } - public new T Old - { - get { return (T)(base.Old ?? default(T)); } - set { base.Old = value; } - } - - public delegate void DataChangedEventHandler(T old, T current); - public event DataChangedEventHandler OnChanged; - - public MemoryWatcher(DeepPointer pointer) - : base(pointer) { } - public MemoryWatcher(IntPtr address) - : base(address) { } - - public override bool Update(Process process) - { - Changed = false; - - if (!Enabled) - return false; - - if (!CheckInterval()) - return false; - - base.Old = Current; - - T val; - bool success; - if (AddrType == AddressType.DeepPointer) - success = DeepPtr.Deref(process, out val); - else - success = process.ReadValue(Address, out val); - - if (success) - { - base.Old = base.Current; - base.Current = val; - } - else - { - if (FailAction == ReadFailAction.DontUpdate) - return false; - - base.Old = base.Current; - base.Current = val; - } - - if (!InitialUpdate) - { - InitialUpdate = true; - return false; - } - - if (!Current.Equals(Old)) - { - OnChanged?.Invoke(Old, Current); - Changed = true; - return true; - } - - return false; - } - - public override void Reset() - { - base.Current = default(T); - base.Old = default(T); - InitialUpdate = false; - } - } + public class MemoryWatcherList : List + { + public delegate void MemoryWatcherDataChangedEventHandler(MemoryWatcher watcher); + public event MemoryWatcherDataChangedEventHandler OnWatcherDataChanged; + + public MemoryWatcher this[string name] + { + get { return this.First(w => w.Name == name); } + } + + public void UpdateAll(Process process) + { + if (OnWatcherDataChanged != null) + { + var changedList = new List(); + + foreach (var watcher in this) + { + bool changed = watcher.Update(process); + if (changed) + changedList.Add(watcher); + } + + // only report changes when all of the other watches are updated too + foreach (var watcher in changedList) + { + OnWatcherDataChanged(watcher); + } + } + else + { + foreach (var watcher in this) + { + watcher.Update(process); + } + } + } + + public void ResetAll() + { + foreach (var watcher in this) + { + watcher.Reset(); + } + } + } + + public abstract class MemoryWatcher + { + public enum ReadFailAction + { + DontUpdate, + SetZeroOrNull, + } + + public string Name { get; set; } + public bool Enabled { get; set; } + public object Current { get; set; } + public object Old { get; set; } + public bool Changed { get; protected set; } + public TimeSpan? UpdateInterval { get; set; } + public ReadFailAction FailAction { get; set; } + + protected bool InitialUpdate { get; set; } + protected DateTime? LastUpdateTime { get; set; } + protected DeepPointer DeepPtr { get; set; } + protected IntPtr Address { get; set; } + + protected AddressType AddrType { get; } + protected enum AddressType { DeepPointer, Absolute } + + protected MemoryWatcher(DeepPointer pointer) + { + DeepPtr = pointer; + AddrType = AddressType.DeepPointer; + Enabled = true; + FailAction = ReadFailAction.DontUpdate; + } + + protected MemoryWatcher(IntPtr address) + { + Address = address; + AddrType = AddressType.Absolute; + Enabled = true; + FailAction = ReadFailAction.DontUpdate; + } + + /// + /// Updates the watcher and returns true if the value has changed. + /// + public abstract bool Update(Process process); + + public abstract void Reset(); + + protected bool CheckInterval() + { + if (UpdateInterval.HasValue) + { + if (LastUpdateTime.HasValue) + { + if (DateTime.Now - LastUpdateTime.Value < UpdateInterval.Value) + return false; + } + LastUpdateTime = DateTime.Now; + } + return true; + } + } + + public class StringWatcher : MemoryWatcher + { + public new string Current + { + get { return (string)base.Current; } + set { base.Current = value; } + } + public new string Old + { + get { return (string)base.Old; } + set { base.Old = value; } + } + + public delegate void StringChangedEventHandler(string old, string current); + public event StringChangedEventHandler OnChanged; + + private ReadStringType _stringType; + private int _numBytes; + + public StringWatcher(DeepPointer pointer, ReadStringType type, int numBytes) + : base(pointer) + { + _stringType = type; + _numBytes = numBytes; + } + + public StringWatcher(DeepPointer pointer, int numBytes) + : this(pointer, ReadStringType.AutoDetect, numBytes) { } + + public StringWatcher(IntPtr address, ReadStringType type, int numBytes) + : base(address) + { + _stringType = type; + _numBytes = numBytes; + } + + public StringWatcher(IntPtr address, int numBytes) + : this(address, ReadStringType.AutoDetect, numBytes) { } + + public override bool Update(Process process) + { + Changed = false; + + if (!Enabled) + return false; + + if (!CheckInterval()) + return false; + + string str; + bool success; + if (AddrType == AddressType.DeepPointer) + success = DeepPtr.DerefString(process, _stringType, _numBytes, out str); + else + success = process.ReadString(Address, _stringType, _numBytes, out str); + + if (success) + { + base.Old = base.Current; + base.Current = str; + } + else + { + if (FailAction == ReadFailAction.DontUpdate) + return false; + + base.Old = base.Current; + base.Current = str; + } + + if (!InitialUpdate) + { + InitialUpdate = true; + return false; + } + + if (!Current.Equals(Old)) + { + OnChanged?.Invoke(Old, Current); + Changed = true; + return true; + } + + return false; + } + + public override void Reset() + { + base.Current = null; + base.Old = null; + InitialUpdate = false; + } + } + + public class MemoryWatcher : MemoryWatcher where T : struct + { + public new T Current + { + get { return (T)(base.Current ?? default(T)); } + set { base.Current = value; } + } + public new T Old + { + get { return (T)(base.Old ?? default(T)); } + set { base.Old = value; } + } + + public delegate void DataChangedEventHandler(T old, T current); + public event DataChangedEventHandler OnChanged; + + public MemoryWatcher(DeepPointer pointer) + : base(pointer) { } + public MemoryWatcher(IntPtr address) + : base(address) { } + + public override bool Update(Process process) + { + Changed = false; + + if (!Enabled) + return false; + + if (!CheckInterval()) + return false; + + base.Old = Current; + + T val; + bool success; + if (AddrType == AddressType.DeepPointer) + success = DeepPtr.Deref(process, out val); + else + success = process.ReadValue(Address, out val); + + if (success) + { + base.Old = base.Current; + base.Current = val; + } + else + { + if (FailAction == ReadFailAction.DontUpdate) + return false; + + base.Old = base.Current; + base.Current = val; + } + + if (!InitialUpdate) + { + InitialUpdate = true; + return false; + } + + if (!Current.Equals(Old)) + { + OnChanged?.Invoke(Old, Current); + Changed = true; + return true; + } + + return false; + } + + public override void Reset() + { + base.Current = default(T); + base.Old = default(T); + InitialUpdate = false; + } + } } \ No newline at end of file diff --git a/ProcessExtensions.cs b/ProcessExtensions.cs index 6fae65c..e18f4dd 100644 --- a/ProcessExtensions.cs +++ b/ProcessExtensions.cs @@ -12,529 +12,529 @@ namespace DeathloopTrainer { - using SizeT = UIntPtr; - - public class ProcessModuleWow64Safe - { - public IntPtr BaseAddress { get; set; } - public IntPtr EntryPointAddress { get; set; } - public string FileName { get; set; } - public int ModuleMemorySize { get; set; } - public string ModuleName { get; set; } - public FileVersionInfo FileVersionInfo - { - get { return FileVersionInfo.GetVersionInfo(FileName); } - } - public override string ToString() - { - return ModuleName ?? base.ToString(); - } - } - - public enum ReadStringType - { - AutoDetect, - ASCII, - UTF8, - UTF16 - } - - public static class ExtensionMethods - { - private static Dictionary ModuleCache = new Dictionary(); - - public static ProcessModuleWow64Safe MainModuleWow64Safe(this Process p) - { - return p.ModulesWow64Safe().First(); - } - - public static ProcessModuleWow64Safe[] ModulesWow64Safe(this Process p) - { - if (ModuleCache.Count > 100) - ModuleCache.Clear(); - - const int LIST_MODULES_ALL = 3; - const int MAX_PATH = 260; - - var hModules = new IntPtr[1024]; - - uint cb = (uint)IntPtr.Size * (uint)hModules.Length; - uint cbNeeded; - - if (!WinAPI.EnumProcessModulesEx(p.Handle, hModules, cb, out cbNeeded, LIST_MODULES_ALL)) - throw new Win32Exception(); - uint numMods = cbNeeded / (uint)IntPtr.Size; - - int hash = p.StartTime.GetHashCode() + p.Id + (int)numMods; - if (ModuleCache.ContainsKey(hash)) - return ModuleCache[hash]; - - var ret = new List(); - - // everything below is fairly expensive, which is why we cache! - var sb = new StringBuilder(MAX_PATH); - for (int i = 0; i < numMods; i++) - { - sb.Clear(); - if (WinAPI.GetModuleFileNameEx(p.Handle, hModules[i], sb, (uint)sb.Capacity) == 0) - throw new Win32Exception(); - string fileName = sb.ToString(); - - sb.Clear(); - if (WinAPI.GetModuleBaseName(p.Handle, hModules[i], sb, (uint)sb.Capacity) == 0) - throw new Win32Exception(); - string baseName = sb.ToString(); - - var moduleInfo = new WinAPI.MODULEINFO(); - if (!WinAPI.GetModuleInformation(p.Handle, hModules[i], out moduleInfo, (uint)Marshal.SizeOf(moduleInfo))) - throw new Win32Exception(); - - - ret.Add(new ProcessModuleWow64Safe() - { - FileName = fileName, - BaseAddress = moduleInfo.lpBaseOfDll, - ModuleMemorySize = (int)moduleInfo.SizeOfImage, - EntryPointAddress = moduleInfo.EntryPoint, - ModuleName = baseName - }); - } - - ModuleCache.Add(hash, ret.ToArray()); - - return ret.ToArray(); - } - - public static IEnumerable MemoryPages(this Process process, bool all = false) - { - // hardcoded values because GetSystemInfo / GetNativeSystemInfo can't return info for remote process - var min = 0x10000L; - var max = process.Is64Bit() ? 0x00007FFFFFFEFFFFL : 0x7FFEFFFFL; - - var mbiSize = (SizeT)Marshal.SizeOf(typeof(MemoryBasicInformation)); - - var addr = min; - do - { - MemoryBasicInformation mbi; - if (WinAPI.VirtualQueryEx(process.Handle, (IntPtr)addr, out mbi, mbiSize) == (SizeT)0) - break; - addr += (long)mbi.RegionSize; - - // don't care about reserved/free pages - if (mbi.State != MemPageState.MEM_COMMIT) - continue; - - // probably don't care about guarded pages - if (!all && (mbi.Protect & MemPageProtect.PAGE_GUARD) != 0) - continue; - - // probably don't care about image/file maps - if (!all && mbi.Type != MemPageType.MEM_PRIVATE) - continue; - - yield return mbi; - - } while (addr < max); - } - - public static bool Is64Bit(this Process process) - { - bool procWow64; - WinAPI.IsWow64Process(process.Handle, out procWow64); - if (Environment.Is64BitOperatingSystem && !procWow64) - return true; - return false; - } - - public static bool ReadValue(this Process process, IntPtr addr, out T val) where T : struct - { - var type = typeof(T); - type = type.IsEnum ? Enum.GetUnderlyingType(type) : type; - - val = default(T); - object val2; - if (!ReadValue(process, addr, type, out val2)) - return false; - - val = (T)val2; - - return true; - } - - public static bool ReadValue(Process process, IntPtr addr, Type type, out object val) - { - byte[] bytes; - - val = null; - int size = type == typeof(bool) ? 1 : Marshal.SizeOf(type); - if (!ReadBytes(process, addr, size, out bytes)) - return false; - - val = ResolveToType(bytes, type); - - return true; - } - - public static bool ReadBytes(this Process process, IntPtr addr, int count, out byte[] val) - { - var bytes = new byte[count]; - - SizeT read; - val = null; - if (!WinAPI.ReadProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out read) - || read != (SizeT)bytes.Length) - return false; - - val = bytes; - - return true; - } - - public static bool ReadPointer(this Process process, IntPtr addr, out IntPtr val) - { - return ReadPointer(process, addr, process.Is64Bit(), out val); - } - - public static bool ReadPointer(this Process process, IntPtr addr, bool is64Bit, out IntPtr val) - { - var bytes = new byte[is64Bit ? 8 : 4]; - - SizeT read; - val = IntPtr.Zero; - if (!WinAPI.ReadProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out read) - || read != (SizeT)bytes.Length) - return false; - - val = is64Bit ? (IntPtr)BitConverter.ToInt64(bytes, 0) : (IntPtr)BitConverter.ToUInt32(bytes, 0); - - return true; - } - - public static bool ReadString(this Process process, IntPtr addr, int numBytes, out string str) - { - return ReadString(process, addr, ReadStringType.AutoDetect, numBytes, out str); - } - - public static bool ReadString(this Process process, IntPtr addr, ReadStringType type, int numBytes, out string str) - { - var sb = new StringBuilder(numBytes); - if (!ReadString(process, addr, type, sb)) - { - str = string.Empty; - return false; - } - - str = sb.ToString(); - - return true; - } - - public static bool ReadString(this Process process, IntPtr addr, StringBuilder sb) - { - return ReadString(process, addr, ReadStringType.AutoDetect, sb); - } - - public static bool ReadString(this Process process, IntPtr addr, ReadStringType type, StringBuilder sb) - { - var bytes = new byte[sb.Capacity]; - SizeT read; - if (!WinAPI.ReadProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out read) - || read != (SizeT)bytes.Length) - return false; - - if (type == ReadStringType.AutoDetect) - { - if (read.ToUInt64() >= 2 && bytes[1] == '\x0') - sb.Append(Encoding.Unicode.GetString(bytes)); - else - sb.Append(Encoding.UTF8.GetString(bytes)); - } - else if (type == ReadStringType.UTF8) - sb.Append(Encoding.UTF8.GetString(bytes)); - else if (type == ReadStringType.UTF16) - sb.Append(Encoding.Unicode.GetString(bytes)); - else - sb.Append(Encoding.ASCII.GetString(bytes)); - - for (int i = 0; i < sb.Length; i++) - { - if (sb[i] == '\0') - { - sb.Remove(i, sb.Length - i); - break; - } - } - - return true; - } - - public static T ReadValue(this Process process, IntPtr addr, T default_ = default(T)) where T : struct - { - T val; - if (!process.ReadValue(addr, out val)) - val = default_; - return val; - } - - public static byte[] ReadBytes(this Process process, IntPtr addr, int count) - { - byte[] bytes; - if (!process.ReadBytes(addr, count, out bytes)) - return null; - return bytes; - } - - public static IntPtr ReadPointer(this Process process, IntPtr addr, IntPtr default_ = default(IntPtr)) - { - IntPtr ptr; - if (!process.ReadPointer(addr, out ptr)) - return default_; - return ptr; - } - - public static string ReadString(this Process process, IntPtr addr, int numBytes, string default_ = null) - { - string str; - if (!process.ReadString(addr, numBytes, out str)) - return default_; - return str; - } - - public static string ReadString(this Process process, IntPtr addr, ReadStringType type, int numBytes, string default_ = null) - { - string str; - if (!process.ReadString(addr, type, numBytes, out str)) - return default_; - return str; - } - - public static bool WriteValue(this Process process, IntPtr addr, T obj) where T : struct - { - int size = Marshal.SizeOf(obj); - byte[] arr = new byte[size]; - - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - Marshal.Copy(ptr, arr, 0, size); - Marshal.FreeHGlobal(ptr); - - return process.WriteBytes(addr, arr); - } - - public static bool WriteBytes(this Process process, IntPtr addr, byte[] bytes) - { - SizeT written; - if (!WinAPI.WriteProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out written) - || written != (SizeT)bytes.Length) - return false; - - return true; - } - - private static bool WriteJumpOrCall(Process process, IntPtr addr, IntPtr dest, bool call) - { - var x64 = process.Is64Bit(); - - int jmpLen = x64 ? 12 : 5; - - var instruction = new List(jmpLen); - if (x64) - { - instruction.AddRange(new byte[] { 0x48, 0xB8 }); // mov rax immediate - instruction.AddRange(BitConverter.GetBytes((long)dest)); - instruction.AddRange(new byte[] { 0xFF, call ? (byte)0xD0 : (byte)0xE0 }); // jmp/call rax - } - else - { - int offset = unchecked((int)dest - (int)(addr + jmpLen)); - instruction.AddRange(new byte[] { call ? (byte)0xE8 : (byte)0xE9 }); // jmp/call immediate - instruction.AddRange(BitConverter.GetBytes(offset)); - } - - MemPageProtect oldProtect; - process.VirtualProtect(addr, jmpLen, MemPageProtect.PAGE_EXECUTE_READWRITE, out oldProtect); - bool success = process.WriteBytes(addr, instruction.ToArray()); - process.VirtualProtect(addr, jmpLen, oldProtect); - - return success; - } - - public static bool WriteJumpInstruction(this Process process, IntPtr addr, IntPtr dest) - { - return WriteJumpOrCall(process, addr, dest, false); - } - - public static bool WriteCallInstruction(this Process process, IntPtr addr, IntPtr dest) - { - return WriteJumpOrCall(process, addr, dest, true); - } - - public static IntPtr WriteDetour(this Process process, IntPtr src, int overwrittenBytes, IntPtr dest) - { - int jmpLen = process.Is64Bit() ? 12 : 5; - if (overwrittenBytes < jmpLen) - throw new ArgumentOutOfRangeException(nameof(overwrittenBytes), - $"must be >= length of jmp instruction ({jmpLen})"); - - // allocate memory to store the original src prologue bytes we overwrite with jump to dest - // along with the jump back to src - IntPtr gate; - if ((gate = process.AllocateMemory(jmpLen + overwrittenBytes)) == IntPtr.Zero) - throw new Win32Exception(); - - try - { - // read the original bytes from the prologue of src - var origSrcBytes = process.ReadBytes(src, overwrittenBytes); - if (origSrcBytes == null) - throw new Win32Exception(); - - // write the original prologue of src into the start of gate - if (!process.WriteBytes(gate, origSrcBytes)) - throw new Win32Exception(); - - // write the jump from the end of the gate back to src - if (!process.WriteJumpInstruction(gate + overwrittenBytes, src + overwrittenBytes)) - throw new Win32Exception(); - - // finally write the jump from src to dest - if (!process.WriteJumpInstruction(src, dest)) - throw new Win32Exception(); - - // nop the leftover bytes in the src prologue - int extraBytes = overwrittenBytes - jmpLen; - if (extraBytes > 0) - { - var nops = Enumerable.Repeat((byte)0x90, extraBytes).ToArray(); - MemPageProtect oldProtect; - if (!process.VirtualProtect(src + jmpLen, nops.Length, MemPageProtect.PAGE_EXECUTE_READWRITE, - out oldProtect)) - throw new Win32Exception(); - if (!process.WriteBytes(src + jmpLen, nops)) - throw new Win32Exception(); - process.VirtualProtect(src + jmpLen, nops.Length, oldProtect); - } - } - catch - { - process.FreeMemory(gate); - throw; - } - - return gate; - } - - static object ResolveToType(byte[] bytes, Type type) - { - object val; - - if (type == typeof(int)) - { - val = BitConverter.ToInt32(bytes, 0); - } - else if (type == typeof(uint)) - { - val = BitConverter.ToUInt32(bytes, 0); - } - else if (type == typeof(float)) - { - val = BitConverter.ToSingle(bytes, 0); - } - else if (type == typeof(double)) - { - val = BitConverter.ToDouble(bytes, 0); - } - else if (type == typeof(byte)) - { - val = bytes[0]; - } - else if (type == typeof(bool)) - { - if (bytes == null) - val = false; - else - val = (bytes[0] != 0); - } - else if (type == typeof(short)) - { - val = BitConverter.ToInt16(bytes, 0); - } - else // probably a struct - { - var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - try - { - val = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), type); - } - finally - { - handle.Free(); - } - } - - return val; - } - - public static IntPtr AllocateMemory(this Process process, int size) - { - return WinAPI.VirtualAllocEx(process.Handle, IntPtr.Zero, (SizeT)size, (uint)MemPageState.MEM_COMMIT, - MemPageProtect.PAGE_EXECUTE_READWRITE); - } - - public static bool FreeMemory(this Process process, IntPtr addr) - { - const uint MEM_RELEASE = 0x8000; - return WinAPI.VirtualFreeEx(process.Handle, addr, SizeT.Zero, MEM_RELEASE); - } - - public static bool VirtualProtect(this Process process, IntPtr addr, int size, MemPageProtect protect, - out MemPageProtect oldProtect) - { - return WinAPI.VirtualProtectEx(process.Handle, addr, (SizeT)size, protect, out oldProtect); - } - - public static bool VirtualProtect(this Process process, IntPtr addr, int size, MemPageProtect protect) - { - MemPageProtect oldProtect; - return WinAPI.VirtualProtectEx(process.Handle, addr, (SizeT)size, protect, out oldProtect); - } - - public static IntPtr CreateThread(this Process process, IntPtr startAddress, IntPtr parameter) - { - IntPtr threadId; - return WinAPI.CreateRemoteThread(process.Handle, IntPtr.Zero, (SizeT)0, startAddress, parameter, 0, - out threadId); - } - - public static IntPtr CreateThread(this Process process, IntPtr startAddress) - { - return CreateThread(process, startAddress, IntPtr.Zero); - } - - public static void Suspend(this Process process) - { - WinAPI.NtSuspendProcess(process.Handle); - } - - public static void Resume(this Process process) - { - WinAPI.NtResumeProcess(process.Handle); - } - - public static float ToFloatBits(this uint i) - { - return BitConverter.ToSingle(BitConverter.GetBytes(i), 0); - } - - public static uint ToUInt32Bits(this float f) - { - return BitConverter.ToUInt32(BitConverter.GetBytes(f), 0); - } - - public static bool BitEquals(this float f, float o) - { - return ToUInt32Bits(f) == ToUInt32Bits(o); - } - } + using SizeT = UIntPtr; + + public class ProcessModuleWow64Safe + { + public IntPtr BaseAddress { get; set; } + public IntPtr EntryPointAddress { get; set; } + public string FileName { get; set; } + public int ModuleMemorySize { get; set; } + public string ModuleName { get; set; } + public FileVersionInfo FileVersionInfo + { + get { return FileVersionInfo.GetVersionInfo(FileName); } + } + public override string ToString() + { + return ModuleName ?? base.ToString(); + } + } + + public enum ReadStringType + { + AutoDetect, + ASCII, + UTF8, + UTF16 + } + + public static class ExtensionMethods + { + private static Dictionary ModuleCache = new Dictionary(); + + public static ProcessModuleWow64Safe MainModuleWow64Safe(this Process p) + { + return p.ModulesWow64Safe().First(); + } + + public static ProcessModuleWow64Safe[] ModulesWow64Safe(this Process p) + { + if (ModuleCache.Count > 100) + ModuleCache.Clear(); + + const int LIST_MODULES_ALL = 3; + const int MAX_PATH = 260; + + var hModules = new IntPtr[1024]; + + uint cb = (uint)IntPtr.Size * (uint)hModules.Length; + uint cbNeeded; + + if (!WinAPI.EnumProcessModulesEx(p.Handle, hModules, cb, out cbNeeded, LIST_MODULES_ALL)) + throw new Win32Exception(); + uint numMods = cbNeeded / (uint)IntPtr.Size; + + int hash = p.StartTime.GetHashCode() + p.Id + (int)numMods; + if (ModuleCache.ContainsKey(hash)) + return ModuleCache[hash]; + + var ret = new List(); + + // everything below is fairly expensive, which is why we cache! + var sb = new StringBuilder(MAX_PATH); + for (int i = 0; i < numMods; i++) + { + sb.Clear(); + if (WinAPI.GetModuleFileNameEx(p.Handle, hModules[i], sb, (uint)sb.Capacity) == 0) + throw new Win32Exception(); + string fileName = sb.ToString(); + + sb.Clear(); + if (WinAPI.GetModuleBaseName(p.Handle, hModules[i], sb, (uint)sb.Capacity) == 0) + throw new Win32Exception(); + string baseName = sb.ToString(); + + var moduleInfo = new WinAPI.MODULEINFO(); + if (!WinAPI.GetModuleInformation(p.Handle, hModules[i], out moduleInfo, (uint)Marshal.SizeOf(moduleInfo))) + throw new Win32Exception(); + + + ret.Add(new ProcessModuleWow64Safe() + { + FileName = fileName, + BaseAddress = moduleInfo.lpBaseOfDll, + ModuleMemorySize = (int)moduleInfo.SizeOfImage, + EntryPointAddress = moduleInfo.EntryPoint, + ModuleName = baseName + }); + } + + ModuleCache.Add(hash, ret.ToArray()); + + return ret.ToArray(); + } + + public static IEnumerable MemoryPages(this Process process, bool all = false) + { + // hardcoded values because GetSystemInfo / GetNativeSystemInfo can't return info for remote process + var min = 0x10000L; + var max = process.Is64Bit() ? 0x00007FFFFFFEFFFFL : 0x7FFEFFFFL; + + var mbiSize = (SizeT)Marshal.SizeOf(typeof(MemoryBasicInformation)); + + var addr = min; + do + { + MemoryBasicInformation mbi; + if (WinAPI.VirtualQueryEx(process.Handle, (IntPtr)addr, out mbi, mbiSize) == (SizeT)0) + break; + addr += (long)mbi.RegionSize; + + // don't care about reserved/free pages + if (mbi.State != MemPageState.MEM_COMMIT) + continue; + + // probably don't care about guarded pages + if (!all && (mbi.Protect & MemPageProtect.PAGE_GUARD) != 0) + continue; + + // probably don't care about image/file maps + if (!all && mbi.Type != MemPageType.MEM_PRIVATE) + continue; + + yield return mbi; + + } while (addr < max); + } + + public static bool Is64Bit(this Process process) + { + bool procWow64; + WinAPI.IsWow64Process(process.Handle, out procWow64); + if (Environment.Is64BitOperatingSystem && !procWow64) + return true; + return false; + } + + public static bool ReadValue(this Process process, IntPtr addr, out T val) where T : struct + { + var type = typeof(T); + type = type.IsEnum ? Enum.GetUnderlyingType(type) : type; + + val = default(T); + object val2; + if (!ReadValue(process, addr, type, out val2)) + return false; + + val = (T)val2; + + return true; + } + + public static bool ReadValue(Process process, IntPtr addr, Type type, out object val) + { + byte[] bytes; + + val = null; + int size = type == typeof(bool) ? 1 : Marshal.SizeOf(type); + if (!ReadBytes(process, addr, size, out bytes)) + return false; + + val = ResolveToType(bytes, type); + + return true; + } + + public static bool ReadBytes(this Process process, IntPtr addr, int count, out byte[] val) + { + var bytes = new byte[count]; + + SizeT read; + val = null; + if (!WinAPI.ReadProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out read) + || read != (SizeT)bytes.Length) + return false; + + val = bytes; + + return true; + } + + public static bool ReadPointer(this Process process, IntPtr addr, out IntPtr val) + { + return ReadPointer(process, addr, process.Is64Bit(), out val); + } + + public static bool ReadPointer(this Process process, IntPtr addr, bool is64Bit, out IntPtr val) + { + var bytes = new byte[is64Bit ? 8 : 4]; + + SizeT read; + val = IntPtr.Zero; + if (!WinAPI.ReadProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out read) + || read != (SizeT)bytes.Length) + return false; + + val = is64Bit ? (IntPtr)BitConverter.ToInt64(bytes, 0) : (IntPtr)BitConverter.ToUInt32(bytes, 0); + + return true; + } + + public static bool ReadString(this Process process, IntPtr addr, int numBytes, out string str) + { + return ReadString(process, addr, ReadStringType.AutoDetect, numBytes, out str); + } + + public static bool ReadString(this Process process, IntPtr addr, ReadStringType type, int numBytes, out string str) + { + var sb = new StringBuilder(numBytes); + if (!ReadString(process, addr, type, sb)) + { + str = string.Empty; + return false; + } + + str = sb.ToString(); + + return true; + } + + public static bool ReadString(this Process process, IntPtr addr, StringBuilder sb) + { + return ReadString(process, addr, ReadStringType.AutoDetect, sb); + } + + public static bool ReadString(this Process process, IntPtr addr, ReadStringType type, StringBuilder sb) + { + var bytes = new byte[sb.Capacity]; + SizeT read; + if (!WinAPI.ReadProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out read) + || read != (SizeT)bytes.Length) + return false; + + if (type == ReadStringType.AutoDetect) + { + if (read.ToUInt64() >= 2 && bytes[1] == '\x0') + sb.Append(Encoding.Unicode.GetString(bytes)); + else + sb.Append(Encoding.UTF8.GetString(bytes)); + } + else if (type == ReadStringType.UTF8) + sb.Append(Encoding.UTF8.GetString(bytes)); + else if (type == ReadStringType.UTF16) + sb.Append(Encoding.Unicode.GetString(bytes)); + else + sb.Append(Encoding.ASCII.GetString(bytes)); + + for (int i = 0; i < sb.Length; i++) + { + if (sb[i] == '\0') + { + sb.Remove(i, sb.Length - i); + break; + } + } + + return true; + } + + public static T ReadValue(this Process process, IntPtr addr, T default_ = default(T)) where T : struct + { + T val; + if (!process.ReadValue(addr, out val)) + val = default_; + return val; + } + + public static byte[] ReadBytes(this Process process, IntPtr addr, int count) + { + byte[] bytes; + if (!process.ReadBytes(addr, count, out bytes)) + return null; + return bytes; + } + + public static IntPtr ReadPointer(this Process process, IntPtr addr, IntPtr default_ = default(IntPtr)) + { + IntPtr ptr; + if (!process.ReadPointer(addr, out ptr)) + return default_; + return ptr; + } + + public static string ReadString(this Process process, IntPtr addr, int numBytes, string default_ = null) + { + string str; + if (!process.ReadString(addr, numBytes, out str)) + return default_; + return str; + } + + public static string ReadString(this Process process, IntPtr addr, ReadStringType type, int numBytes, string default_ = null) + { + string str; + if (!process.ReadString(addr, type, numBytes, out str)) + return default_; + return str; + } + + public static bool WriteValue(this Process process, IntPtr addr, T obj) where T : struct + { + int size = Marshal.SizeOf(obj); + byte[] arr = new byte[size]; + + IntPtr ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + Marshal.Copy(ptr, arr, 0, size); + Marshal.FreeHGlobal(ptr); + + return process.WriteBytes(addr, arr); + } + + public static bool WriteBytes(this Process process, IntPtr addr, byte[] bytes) + { + SizeT written; + if (!WinAPI.WriteProcessMemory(process.Handle, addr, bytes, (SizeT)bytes.Length, out written) + || written != (SizeT)bytes.Length) + return false; + + return true; + } + + private static bool WriteJumpOrCall(Process process, IntPtr addr, IntPtr dest, bool call) + { + var x64 = process.Is64Bit(); + + int jmpLen = x64 ? 12 : 5; + + var instruction = new List(jmpLen); + if (x64) + { + instruction.AddRange(new byte[] { 0x48, 0xB8 }); // mov rax immediate + instruction.AddRange(BitConverter.GetBytes((long)dest)); + instruction.AddRange(new byte[] { 0xFF, call ? (byte)0xD0 : (byte)0xE0 }); // jmp/call rax + } + else + { + int offset = unchecked((int)dest - (int)(addr + jmpLen)); + instruction.AddRange(new byte[] { call ? (byte)0xE8 : (byte)0xE9 }); // jmp/call immediate + instruction.AddRange(BitConverter.GetBytes(offset)); + } + + MemPageProtect oldProtect; + process.VirtualProtect(addr, jmpLen, MemPageProtect.PAGE_EXECUTE_READWRITE, out oldProtect); + bool success = process.WriteBytes(addr, instruction.ToArray()); + process.VirtualProtect(addr, jmpLen, oldProtect); + + return success; + } + + public static bool WriteJumpInstruction(this Process process, IntPtr addr, IntPtr dest) + { + return WriteJumpOrCall(process, addr, dest, false); + } + + public static bool WriteCallInstruction(this Process process, IntPtr addr, IntPtr dest) + { + return WriteJumpOrCall(process, addr, dest, true); + } + + public static IntPtr WriteDetour(this Process process, IntPtr src, int overwrittenBytes, IntPtr dest) + { + int jmpLen = process.Is64Bit() ? 12 : 5; + if (overwrittenBytes < jmpLen) + throw new ArgumentOutOfRangeException(nameof(overwrittenBytes), + $"must be >= length of jmp instruction ({jmpLen})"); + + // allocate memory to store the original src prologue bytes we overwrite with jump to dest + // along with the jump back to src + IntPtr gate; + if ((gate = process.AllocateMemory(jmpLen + overwrittenBytes)) == IntPtr.Zero) + throw new Win32Exception(); + + try + { + // read the original bytes from the prologue of src + var origSrcBytes = process.ReadBytes(src, overwrittenBytes); + if (origSrcBytes == null) + throw new Win32Exception(); + + // write the original prologue of src into the start of gate + if (!process.WriteBytes(gate, origSrcBytes)) + throw new Win32Exception(); + + // write the jump from the end of the gate back to src + if (!process.WriteJumpInstruction(gate + overwrittenBytes, src + overwrittenBytes)) + throw new Win32Exception(); + + // finally write the jump from src to dest + if (!process.WriteJumpInstruction(src, dest)) + throw new Win32Exception(); + + // nop the leftover bytes in the src prologue + int extraBytes = overwrittenBytes - jmpLen; + if (extraBytes > 0) + { + var nops = Enumerable.Repeat((byte)0x90, extraBytes).ToArray(); + MemPageProtect oldProtect; + if (!process.VirtualProtect(src + jmpLen, nops.Length, MemPageProtect.PAGE_EXECUTE_READWRITE, + out oldProtect)) + throw new Win32Exception(); + if (!process.WriteBytes(src + jmpLen, nops)) + throw new Win32Exception(); + process.VirtualProtect(src + jmpLen, nops.Length, oldProtect); + } + } + catch + { + process.FreeMemory(gate); + throw; + } + + return gate; + } + + static object ResolveToType(byte[] bytes, Type type) + { + object val; + + if (type == typeof(int)) + { + val = BitConverter.ToInt32(bytes, 0); + } + else if (type == typeof(uint)) + { + val = BitConverter.ToUInt32(bytes, 0); + } + else if (type == typeof(float)) + { + val = BitConverter.ToSingle(bytes, 0); + } + else if (type == typeof(double)) + { + val = BitConverter.ToDouble(bytes, 0); + } + else if (type == typeof(byte)) + { + val = bytes[0]; + } + else if (type == typeof(bool)) + { + if (bytes == null) + val = false; + else + val = (bytes[0] != 0); + } + else if (type == typeof(short)) + { + val = BitConverter.ToInt16(bytes, 0); + } + else // probably a struct + { + var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + try + { + val = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), type); + } + finally + { + handle.Free(); + } + } + + return val; + } + + public static IntPtr AllocateMemory(this Process process, int size) + { + return WinAPI.VirtualAllocEx(process.Handle, IntPtr.Zero, (SizeT)size, (uint)MemPageState.MEM_COMMIT, + MemPageProtect.PAGE_EXECUTE_READWRITE); + } + + public static bool FreeMemory(this Process process, IntPtr addr) + { + const uint MEM_RELEASE = 0x8000; + return WinAPI.VirtualFreeEx(process.Handle, addr, SizeT.Zero, MEM_RELEASE); + } + + public static bool VirtualProtect(this Process process, IntPtr addr, int size, MemPageProtect protect, + out MemPageProtect oldProtect) + { + return WinAPI.VirtualProtectEx(process.Handle, addr, (SizeT)size, protect, out oldProtect); + } + + public static bool VirtualProtect(this Process process, IntPtr addr, int size, MemPageProtect protect) + { + MemPageProtect oldProtect; + return WinAPI.VirtualProtectEx(process.Handle, addr, (SizeT)size, protect, out oldProtect); + } + + public static IntPtr CreateThread(this Process process, IntPtr startAddress, IntPtr parameter) + { + IntPtr threadId; + return WinAPI.CreateRemoteThread(process.Handle, IntPtr.Zero, (SizeT)0, startAddress, parameter, 0, + out threadId); + } + + public static IntPtr CreateThread(this Process process, IntPtr startAddress) + { + return CreateThread(process, startAddress, IntPtr.Zero); + } + + public static void Suspend(this Process process) + { + WinAPI.NtSuspendProcess(process.Handle); + } + + public static void Resume(this Process process) + { + WinAPI.NtResumeProcess(process.Handle); + } + + public static float ToFloatBits(this uint i) + { + return BitConverter.ToSingle(BitConverter.GetBytes(i), 0); + } + + public static uint ToUInt32Bits(this float f) + { + return BitConverter.ToUInt32(BitConverter.GetBytes(f), 0); + } + + public static bool BitEquals(this float f, float o) + { + return ToUInt32Bits(f) == ToUInt32Bits(o); + } + } } \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 3d4904e..d59e71f 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -1,6 +1,4 @@ using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows; diff --git a/SignatureScanner.cs b/SignatureScanner.cs index 92f7575..a42af59 100644 --- a/SignatureScanner.cs +++ b/SignatureScanner.cs @@ -12,336 +12,336 @@ namespace DeathloopTrainer { - public class SignatureScanner - { - private byte[] _memory; - private Process _process; - private IntPtr _address; - private int _size; - - public IntPtr Address - { - get { return _address; } - set - { - _memory = null; - _address = value; - } - } - - public int Size - { - get { return _size; } - set - { - _memory = null; - _size = value; - } - } - - public Process Process - { - get { return _process; } - set - { - _memory = null; - _process = value; - } - } - - public byte[] Memory - { - get { return _memory; } - set - { - _memory = value; - _size = value.Length; - } - } - - public SignatureScanner(Process proc, IntPtr addr, int size) - { - if (proc == null) - throw new ArgumentNullException(nameof(proc)); - if (addr == IntPtr.Zero) - throw new ArgumentException("addr cannot be IntPtr.Zero.", nameof(addr)); - if (size <= 0) - throw new ArgumentException("size cannot be less than zero.", nameof(size)); - - _process = proc; - _address = addr; - _size = size; - _memory = new byte[1]; - } - - public SignatureScanner(byte[] mem) - { - if (mem == null) - throw new ArgumentNullException(nameof(mem)); - - _memory = mem; - _size = mem.Length; - } - - // backwards compat method signature - public IntPtr Scan(SigScanTarget target) - { - return Scan(target, 1); - } - - public IntPtr Scan(SigScanTarget target, int align) - { - if ((long)_address % align != 0) - throw new ArgumentOutOfRangeException(nameof(align), "start address must be aligned"); - - return ScanAll(target, align).FirstOrDefault(); - } - - public IEnumerable ScanAll(SigScanTarget target, int align = 1) - { - if ((long)_address % align != 0) - throw new ArgumentOutOfRangeException(nameof(align), "start address must be aligned"); - - return ScanInternal(target, align); - } - - IEnumerable ScanInternal(SigScanTarget target, int align) - { - if (_memory == null || _memory.Length != _size) - { - byte[] bytes; - - if (!_process.ReadBytes(_address, _size, out bytes)) - { - _memory = null; - yield break; - } - - _memory = bytes; - } - - foreach (SigScanTarget.Signature sig in target.Signatures) - { - // have to implement IEnumerator manually because you can't yield in an unsafe block... - foreach (int off in new ScanEnumerator(_memory, align, sig)) - { - var ptr = _address + off + sig.Offset; - if (target.OnFound != null) - ptr = target.OnFound(_process, this, ptr); - yield return ptr; - } - } - } - - class ScanEnumerator : IEnumerator, IEnumerable - { - // IEnumerator - public int Current { get; private set; } - object IEnumerator.Current { get { return Current; } } - - private readonly byte[] _memory; - private readonly int _align; - private readonly SigScanTarget.Signature _sig; - - private readonly int _sigLen; - private readonly int _end; - - private int _nextIndex; - - public ScanEnumerator(byte[] mem, int align, SigScanTarget.Signature sig) - { - if (mem.Length < sig.Pattern.Length) - throw new ArgumentOutOfRangeException(nameof(mem), "memory buffer length must be >= pattern length"); - - _memory = mem; - _align = align; - _sig = sig; - - _sigLen = _sig.Pattern.Length; - _end = _memory.Length - _sigLen; - } - - // IEnumerator - public bool MoveNext() - { - return _sig.Mask != null ? NextPattern() : NextBytes(); - } - public void Reset() - { - _nextIndex = 0; - } - public void Dispose() - { - } - - // IEnumerable - public IEnumerator GetEnumerator() - { - return this; - } - IEnumerator IEnumerable.GetEnumerator() - { - return this; - } - - unsafe bool NextPattern() - { - fixed (bool* mask = _sig.Mask) - fixed (byte* mem = _memory, sig = _sig.Pattern) - { - // perf: locals are MUCH faster than properties and fields, especially on writes - int end = _end; - int sigLen = _sigLen; - int align = _align; - int index = _nextIndex; // biggest speed increase - - for (; index < end; index += align) // index++ would be ~7% faster - { - for (int sigIndex = 0; sigIndex < sigLen; sigIndex++) - { - if (mask[sigIndex]) - continue; - if (sig[sigIndex] != mem[index + sigIndex]) - goto next; - } - - // fully matched - Current = index; - _nextIndex = index + align; - return true; - - next: - ; - } - - return false; - } - } - - unsafe bool NextBytes() - { - // just a straight memory compare - fixed (byte* mem = _memory, sig = _sig.Pattern) - { - int end = _end; - int index = _nextIndex; - int align = _align; - int sigLen = _sigLen; - - for (; index < end; index += align) - { - for (int sigIndex = 0; sigIndex < sigLen; sigIndex++) - { - if (sig[sigIndex] != mem[index + sigIndex]) - goto next; - } - - // fully matched - Current = index; - _nextIndex = index + align; - return true; - - next: - ; - } - - return false; - } - } - } - } - - public class SigScanTarget - { - public struct Signature - { - public byte[] Pattern; - public bool[] Mask; - public int Offset; - } - - public delegate IntPtr OnFoundCallback(Process proc, SignatureScanner scanner, IntPtr ptr); - public OnFoundCallback OnFound { get; set; } - - private List _sigs; - public ReadOnlyCollection Signatures - { - get { return _sigs.AsReadOnly(); } - } - - public SigScanTarget() - { - _sigs = new List(); - } - - public SigScanTarget(int offset, params string[] signature) - : this() - { - AddSignature(offset, signature); - } - - public SigScanTarget(int offset, params byte[] signature) - : this() - { - AddSignature(offset, signature); - } - - public SigScanTarget(params string[] signature) : this(0, signature) { } - // make sure to cast the first arg to byte if using params, so you don't accidentally use offset ctor - public SigScanTarget(params byte[] binary) : this(0, binary) { } - - public void AddSignature(int offset, params string[] signature) - { - string sigStr = string.Join(string.Empty, signature).Replace(" ", string.Empty); - if (sigStr.Length % 2 != 0) - throw new ArgumentException(nameof(signature)); - - var sigBytes = new List(); - var sigMask = new List(); - var hasMask = false; - - for (int i = 0; i < sigStr.Length; i += 2) - { - byte b; - if (byte.TryParse(sigStr.Substring(i, 2), NumberStyles.HexNumber, null, out b)) - { - sigBytes.Add(b); - sigMask.Add(false); - } - else - { - sigBytes.Add(0); - sigMask.Add(true); - hasMask = true; - } - } - - _sigs.Add(new Signature - { - Pattern = sigBytes.ToArray(), - Mask = hasMask ? sigMask.ToArray() : null, - Offset = offset, - }); - } - - public void AddSignature(int offset, params byte[] binary) - { - _sigs.Add(new Signature - { - Pattern = binary, - Mask = null, - Offset = offset, - }); - } - - public void AddSignature(params string[] signature) - { - AddSignature(0, signature); - } - - public void AddSignature(params byte[] binary) - { - AddSignature(0, binary); - } - } + public class SignatureScanner + { + private byte[] _memory; + private Process _process; + private IntPtr _address; + private int _size; + + public IntPtr Address + { + get { return _address; } + set + { + _memory = null; + _address = value; + } + } + + public int Size + { + get { return _size; } + set + { + _memory = null; + _size = value; + } + } + + public Process Process + { + get { return _process; } + set + { + _memory = null; + _process = value; + } + } + + public byte[] Memory + { + get { return _memory; } + set + { + _memory = value; + _size = value.Length; + } + } + + public SignatureScanner(Process proc, IntPtr addr, int size) + { + if (proc == null) + throw new ArgumentNullException(nameof(proc)); + if (addr == IntPtr.Zero) + throw new ArgumentException("addr cannot be IntPtr.Zero.", nameof(addr)); + if (size <= 0) + throw new ArgumentException("size cannot be less than zero.", nameof(size)); + + _process = proc; + _address = addr; + _size = size; + _memory = new byte[1]; + } + + public SignatureScanner(byte[] mem) + { + if (mem == null) + throw new ArgumentNullException(nameof(mem)); + + _memory = mem; + _size = mem.Length; + } + + // backwards compat method signature + public IntPtr Scan(SigScanTarget target) + { + return Scan(target, 1); + } + + public IntPtr Scan(SigScanTarget target, int align) + { + if ((long)_address % align != 0) + throw new ArgumentOutOfRangeException(nameof(align), "start address must be aligned"); + + return ScanAll(target, align).FirstOrDefault(); + } + + public IEnumerable ScanAll(SigScanTarget target, int align = 1) + { + if ((long)_address % align != 0) + throw new ArgumentOutOfRangeException(nameof(align), "start address must be aligned"); + + return ScanInternal(target, align); + } + + IEnumerable ScanInternal(SigScanTarget target, int align) + { + if (_memory == null || _memory.Length != _size) + { + byte[] bytes; + + if (!_process.ReadBytes(_address, _size, out bytes)) + { + _memory = null; + yield break; + } + + _memory = bytes; + } + + foreach (SigScanTarget.Signature sig in target.Signatures) + { + // have to implement IEnumerator manually because you can't yield in an unsafe block... + foreach (int off in new ScanEnumerator(_memory, align, sig)) + { + var ptr = _address + off + sig.Offset; + if (target.OnFound != null) + ptr = target.OnFound(_process, this, ptr); + yield return ptr; + } + } + } + + class ScanEnumerator : IEnumerator, IEnumerable + { + // IEnumerator + public int Current { get; private set; } + object IEnumerator.Current { get { return Current; } } + + private readonly byte[] _memory; + private readonly int _align; + private readonly SigScanTarget.Signature _sig; + + private readonly int _sigLen; + private readonly int _end; + + private int _nextIndex; + + public ScanEnumerator(byte[] mem, int align, SigScanTarget.Signature sig) + { + if (mem.Length < sig.Pattern.Length) + throw new ArgumentOutOfRangeException(nameof(mem), "memory buffer length must be >= pattern length"); + + _memory = mem; + _align = align; + _sig = sig; + + _sigLen = _sig.Pattern.Length; + _end = _memory.Length - _sigLen; + } + + // IEnumerator + public bool MoveNext() + { + return _sig.Mask != null ? NextPattern() : NextBytes(); + } + public void Reset() + { + _nextIndex = 0; + } + public void Dispose() + { + } + + // IEnumerable + public IEnumerator GetEnumerator() + { + return this; + } + IEnumerator IEnumerable.GetEnumerator() + { + return this; + } + + unsafe bool NextPattern() + { + fixed (bool* mask = _sig.Mask) + fixed (byte* mem = _memory, sig = _sig.Pattern) + { + // perf: locals are MUCH faster than properties and fields, especially on writes + int end = _end; + int sigLen = _sigLen; + int align = _align; + int index = _nextIndex; // biggest speed increase + + for (; index < end; index += align) // index++ would be ~7% faster + { + for (int sigIndex = 0; sigIndex < sigLen; sigIndex++) + { + if (mask[sigIndex]) + continue; + if (sig[sigIndex] != mem[index + sigIndex]) + goto next; + } + + // fully matched + Current = index; + _nextIndex = index + align; + return true; + +next: + ; + } + + return false; + } + } + + unsafe bool NextBytes() + { + // just a straight memory compare + fixed (byte* mem = _memory, sig = _sig.Pattern) + { + int end = _end; + int index = _nextIndex; + int align = _align; + int sigLen = _sigLen; + + for (; index < end; index += align) + { + for (int sigIndex = 0; sigIndex < sigLen; sigIndex++) + { + if (sig[sigIndex] != mem[index + sigIndex]) + goto next; + } + + // fully matched + Current = index; + _nextIndex = index + align; + return true; + +next: + ; + } + + return false; + } + } + } + } + + public class SigScanTarget + { + public struct Signature + { + public byte[] Pattern; + public bool[] Mask; + public int Offset; + } + + public delegate IntPtr OnFoundCallback(Process proc, SignatureScanner scanner, IntPtr ptr); + public OnFoundCallback OnFound { get; set; } + + private List _sigs; + public ReadOnlyCollection Signatures + { + get { return _sigs.AsReadOnly(); } + } + + public SigScanTarget() + { + _sigs = new List(); + } + + public SigScanTarget(int offset, params string[] signature) + : this() + { + AddSignature(offset, signature); + } + + public SigScanTarget(int offset, params byte[] signature) + : this() + { + AddSignature(offset, signature); + } + + public SigScanTarget(params string[] signature) : this(0, signature) { } + // make sure to cast the first arg to byte if using params, so you don't accidentally use offset ctor + public SigScanTarget(params byte[] binary) : this(0, binary) { } + + public void AddSignature(int offset, params string[] signature) + { + string sigStr = string.Join(string.Empty, signature).Replace(" ", string.Empty); + if (sigStr.Length % 2 != 0) + throw new ArgumentException(nameof(signature)); + + var sigBytes = new List(); + var sigMask = new List(); + var hasMask = false; + + for (int i = 0; i < sigStr.Length; i += 2) + { + byte b; + if (byte.TryParse(sigStr.Substring(i, 2), NumberStyles.HexNumber, null, out b)) + { + sigBytes.Add(b); + sigMask.Add(false); + } + else + { + sigBytes.Add(0); + sigMask.Add(true); + hasMask = true; + } + } + + _sigs.Add(new Signature + { + Pattern = sigBytes.ToArray(), + Mask = hasMask ? sigMask.ToArray() : null, + Offset = offset, + }); + } + + public void AddSignature(int offset, params byte[] binary) + { + _sigs.Add(new Signature + { + Pattern = binary, + Mask = null, + Offset = offset, + }); + } + + public void AddSignature(params string[] signature) + { + AddSignature(0, signature); + } + + public void AddSignature(params byte[] binary) + { + AddSignature(0, binary); + } + } } \ No newline at end of file diff --git a/WinAPI.cs b/WinAPI.cs index f628232..f6b0d80 100644 --- a/WinAPI.cs +++ b/WinAPI.cs @@ -6,118 +6,118 @@ namespace DeathloopTrainer { - using SizeT = UIntPtr; - - public enum MemPageState : uint - { - MEM_COMMIT = 0x1000, - MEM_RESERVE = 0x2000, - MEM_FREE = 0x10000, - } - - public enum MemPageType : uint - { - MEM_PRIVATE = 0x20000, - MEM_MAPPED = 0x40000, - MEM_IMAGE = 0x1000000 - } - - [Flags] - public enum MemPageProtect : uint - { - PAGE_NOACCESS = 0x01, - PAGE_READONLY = 0x02, - PAGE_READWRITE = 0x04, - PAGE_WRITECOPY = 0x08, - PAGE_EXECUTE = 0x10, - PAGE_EXECUTE_READ = 0x20, - PAGE_EXECUTE_READWRITE = 0x40, - PAGE_EXECUTE_WRITECOPY = 0x80, - PAGE_GUARD = 0x100, - PAGE_NOCACHE = 0x200, - PAGE_WRITECOMBINE = 0x400, - } - - [StructLayout(LayoutKind.Sequential)] - public struct MemoryBasicInformation // MEMORY_BASIC_INFORMATION - { - public IntPtr BaseAddress; - public IntPtr AllocationBase; - public MemPageProtect AllocationProtect; - public SizeT RegionSize; - public MemPageState State; - public MemPageProtect Protect; - public MemPageType Type; - } - - public static class WinAPI - { - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, - SizeT nSize, out SizeT lpNumberOfBytesRead); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, - SizeT nSize, out SizeT lpNumberOfBytesWritten); - - [DllImport("psapi.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool EnumProcessModulesEx(IntPtr hProcess, [Out] IntPtr[] lphModule, uint cb, - out uint lpcbNeeded, uint dwFilterFlag); - - [DllImport("psapi.dll", SetLastError = true)] - public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, - uint nSize); - - [DllImport("psapi.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, [Out] out MODULEINFO lpmodinfo, - uint cb); - - [DllImport("psapi.dll")] - public static extern uint GetModuleBaseName(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, - uint nSize); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWow64Process(IntPtr hProcess, - [Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern SizeT VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, - [Out] out MemoryBasicInformation lpBuffer, SizeT dwLength); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, SizeT dwSize, uint flAllocationType, - MemPageProtect flProtect); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, SizeT dwSize, uint dwFreeType); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, SizeT dwSize, - MemPageProtect flNewProtect, [Out] out MemPageProtect lpflOldProtect); - - [DllImport("ntdll.dll", SetLastError = true)] - public static extern IntPtr NtSuspendProcess(IntPtr hProcess); - - [DllImport("ntdll.dll", SetLastError = true)] - public static extern IntPtr NtResumeProcess(IntPtr hProcess); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, SizeT dwStackSize, - IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId); - - [StructLayout(LayoutKind.Sequential)] - public struct MODULEINFO - { - public IntPtr lpBaseOfDll; - public uint SizeOfImage; - public IntPtr EntryPoint; - } - } + using SizeT = UIntPtr; + + public enum MemPageState : uint + { + MEM_COMMIT = 0x1000, + MEM_RESERVE = 0x2000, + MEM_FREE = 0x10000, + } + + public enum MemPageType : uint + { + MEM_PRIVATE = 0x20000, + MEM_MAPPED = 0x40000, + MEM_IMAGE = 0x1000000 + } + + [Flags] + public enum MemPageProtect : uint + { + PAGE_NOACCESS = 0x01, + PAGE_READONLY = 0x02, + PAGE_READWRITE = 0x04, + PAGE_WRITECOPY = 0x08, + PAGE_EXECUTE = 0x10, + PAGE_EXECUTE_READ = 0x20, + PAGE_EXECUTE_READWRITE = 0x40, + PAGE_EXECUTE_WRITECOPY = 0x80, + PAGE_GUARD = 0x100, + PAGE_NOCACHE = 0x200, + PAGE_WRITECOMBINE = 0x400, + } + + [StructLayout(LayoutKind.Sequential)] + public struct MemoryBasicInformation // MEMORY_BASIC_INFORMATION + { + public IntPtr BaseAddress; + public IntPtr AllocationBase; + public MemPageProtect AllocationProtect; + public SizeT RegionSize; + public MemPageState State; + public MemPageProtect Protect; + public MemPageType Type; + } + + public static class WinAPI + { + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, + SizeT nSize, out SizeT lpNumberOfBytesRead); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, + SizeT nSize, out SizeT lpNumberOfBytesWritten); + + [DllImport("psapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EnumProcessModulesEx(IntPtr hProcess, [Out] IntPtr[] lphModule, uint cb, + out uint lpcbNeeded, uint dwFilterFlag); + + [DllImport("psapi.dll", SetLastError = true)] + public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, + uint nSize); + + [DllImport("psapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, [Out] out MODULEINFO lpmodinfo, + uint cb); + + [DllImport("psapi.dll")] + public static extern uint GetModuleBaseName(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, + uint nSize); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWow64Process(IntPtr hProcess, + [Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern SizeT VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, + [Out] out MemoryBasicInformation lpBuffer, SizeT dwLength); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, SizeT dwSize, uint flAllocationType, + MemPageProtect flProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, SizeT dwSize, uint dwFreeType); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, SizeT dwSize, + MemPageProtect flNewProtect, [Out] out MemPageProtect lpflOldProtect); + + [DllImport("ntdll.dll", SetLastError = true)] + public static extern IntPtr NtSuspendProcess(IntPtr hProcess); + + [DllImport("ntdll.dll", SetLastError = true)] + public static extern IntPtr NtResumeProcess(IntPtr hProcess); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, SizeT dwStackSize, + IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId); + + [StructLayout(LayoutKind.Sequential)] + public struct MODULEINFO + { + public IntPtr lpBaseOfDll; + public uint SizeOfImage; + public IntPtr EntryPoint; + } + } } \ No newline at end of file diff --git a/globalKeyboardHook.cs b/globalKeyboardHook.cs index 952f22f..207a3e2 100644 --- a/globalKeyboardHook.cs +++ b/globalKeyboardHook.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using System.Runtime.InteropServices; using System.Windows.Forms;