├── HoLLy.MemoryLib ├── Input │ ├── Structs.cs │ ├── Input.cs │ └── VirtualKeyCode.cs ├── HoLLy.MemoryLib.csproj ├── Patterns │ ├── PatternByte.cs │ └── PatternScanner.cs ├── NativeHelper.cs ├── OOP │ └── StructureBase.cs ├── MemoryAbstraction.cs └── Native.cs ├── LICENSE ├── HoLLy.MemoryLib.sln ├── README.md ├── .gitattributes └── .gitignore /HoLLy.MemoryLib/Input/Structs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | #pragma warning disable 649 4 | 5 | namespace HoLLy.Memory.Input 6 | { 7 | internal struct InputStruct 8 | { 9 | public uint Type; 10 | public MixedInput Data; 11 | } 12 | 13 | [StructLayout(LayoutKind.Explicit)] 14 | internal struct MixedInput 15 | { 16 | [FieldOffset(0)] 17 | public MouseInput Mouse; 18 | 19 | [FieldOffset(0)] 20 | public KeyboardInput Keyboard; 21 | } 22 | 23 | internal struct MouseInput 24 | { 25 | public int X; 26 | public int Y; 27 | public uint MouseData; 28 | public uint Flags; 29 | public uint Time; 30 | public IntPtr ExtraInfo; 31 | } 32 | 33 | internal struct KeyboardInput 34 | { 35 | public ushort KeyCode; 36 | public ushort Scan; 37 | public uint Flags; 38 | public uint Time; 39 | public IntPtr ExtraInfo; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 HoLLy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/HoLLy.MemoryLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | HoLLy.Memory 5 | 0.1.0 6 | HoLLy 7 | HoLLy 8 | A memory library 9 | true 10 | net461 11 | https://github.com/HoLLy-HaCKeR/HoLLy.MemoryLib 12 | https://github.com/HoLLy-HaCKeR/HoLLy.MemoryLib/blob/master/LICENSE 13 | https://github.com/HoLLy-HaCKeR/HoLLy.MemoryLib 14 | git 15 | 16 | 17 | 18 | true 19 | 7.3 20 | 21 | 22 | 23 | true 24 | 7.3 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2002 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HoLLy.MemoryLib", "HoLLy.MemoryLib\HoLLy.MemoryLib.csproj", "{18136CFB-23FB-4668-BB7E-715D024B064E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {18136CFB-23FB-4668-BB7E-715D024B064E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {18136CFB-23FB-4668-BB7E-715D024B064E}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {18136CFB-23FB-4668-BB7E-715D024B064E}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {18136CFB-23FB-4668-BB7E-715D024B064E}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C86F8AEB-E977-4579-A130-73BC8E6F7115} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/Input/Input.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace HoLLy.Memory.Input 4 | { 5 | public static class Input 6 | { 7 | // TODO: look into timed events 8 | 9 | private static readonly int StructSize = Marshal.SizeOf(typeof(InputStruct)); // should be 40, probably 10 | 11 | public static void KeyDown(VirtualKeyCode keyCode) 12 | { 13 | var input = new InputStruct { 14 | Type = 1, 15 | Data = new MixedInput { 16 | Keyboard = new KeyboardInput { 17 | KeyCode = (ushort) keyCode 18 | } 19 | } 20 | }; 21 | 22 | Native.SendInput(1, new[] {input}, StructSize); 23 | } 24 | 25 | public static void KeyUp(VirtualKeyCode keyCode) 26 | { 27 | var input = new InputStruct { 28 | Type = 1, 29 | Data = new MixedInput { 30 | Keyboard = new KeyboardInput { 31 | KeyCode = (ushort)keyCode, 32 | Flags = 0x2 33 | } 34 | } 35 | }; 36 | 37 | Native.SendInput(1, new[] {input}, StructSize); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/Patterns/PatternByte.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace HoLLy.Memory.Patterns 7 | { 8 | public struct PatternByte 9 | { 10 | public byte Val; 11 | public bool Skip; 12 | 13 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 14 | public bool Match(byte b) => Skip || b == Val; 15 | 16 | private static PatternByte Normal(byte b) => new PatternByte { Val = b }; 17 | private static PatternByte Wildcard => new PatternByte { Skip = true }; 18 | 19 | public static PatternByte[] Parse(string pattern) 20 | { 21 | //check pattern 22 | if (pattern.Split(' ').Any(a => a.Length % 2 != 0)) throw new Exception("Bad pattern"); 23 | 24 | //TODO: first split by spaces, in case user passes "FF 3 23 0" 25 | string noSpaces = pattern.Replace(" ", string.Empty); 26 | if (noSpaces.Length % 2 != 0) throw new Exception("Bad pattern"); 27 | 28 | int byteCount = noSpaces.Length / 2; 29 | var arr = new PatternByte[byteCount]; 30 | for (int i = 0; i < byteCount; i++) 31 | arr[i] = byte.TryParse(noSpaces.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out byte b) 32 | ? Normal(b) 33 | : Wildcard; 34 | 35 | return arr; 36 | } 37 | 38 | public static uint FirstNonWildcardByte(PatternByte[] pattern) 39 | { 40 | uint firstNonWildcard = 0; 41 | for (uint i = 0; i < pattern.Length; ++i) 42 | { 43 | if (pattern[i].Skip) continue; 44 | firstNonWildcard = i; 45 | break; 46 | } 47 | 48 | return firstNonWildcard; 49 | } 50 | 51 | public override string ToString() => Skip ? "??" : Val.ToString("X2"); 52 | } 53 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoLLy.MemoryLib 2 | A C# memory-accessing library 3 | 4 | ## Disclaimer 5 | This is not meant to be a general-purpose library. This is not meant to have a stable API or be feature-complete. This 6 | is simply what I used or needed in some of my projects. I'm not interested in PRs or issues related to feature requests, 7 | and no support will be given. 8 | 9 | ## Features 10 | - Signature scanning, accepting Cheat Engine style patterns. 11 | - OOP-like memory access 12 | 13 | ### Signature Scanning 14 | You give it a pattern like `"DE AD BE EF ?? ?? ?? ?? CA FE BA BE"` and it will return you the first occurence of this 15 | pattern in the process' memory. Optionally, you can also pass required memory page properties such as protection or state. 16 | 17 | ### OOP Memory Access 18 | You can "map" memory structures in an external process and access them in an intuitive manner. 19 | 20 | ```cs 21 | internal class MyExternalObject : StructureBase 22 | { 23 | public MyExternalObject(MemoryAbstraction mem, IntPtr addr) : base(mem, addr) { } 24 | 25 | protected override int PrefetchSize => 0x95; // The size of the object, if you wish to cache it 26 | 27 | public float Value1 => Float(0x10); // 32bit floating point number 28 | public int Value2 => Int(0x20); // 32bit integer 29 | public string Value3 => String(0x30); // .NET String 30 | public MyEnum Value4 => (MyEnum)Int(0x40); 31 | 32 | public MyOtherObject OtherObject => new MyOtherObject(Memory, Pointer(0xD0)); // MyOtherObject is another StructureBase 33 | 34 | public List List1 => this.List(0x48); // .NET lists are supported 35 | public List List1 => this.List(0x48); // Union-type fields naturally work too 36 | } 37 | ``` 38 | 39 | ### Input Simulation 40 | You can send keystrokes to the target process through a light wrapper over SendInput. 41 | 42 | ## License 43 | This project is licensed under the permissive MIT license. 44 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/NativeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace HoLLy.Memory 7 | { 8 | public static class NativeHelper 9 | { 10 | public static bool Is64BitProcess() => IntPtr.Size == 8; 11 | public static bool Is64BitProcess(IntPtr handle) => Is64BitMachine() && !IsWow64Process(handle); 12 | public static bool Is64BitMachine() => Is64BitProcess() || IsWow64Process(Process.GetCurrentProcess().Handle); 13 | public static bool IsWow64Process(IntPtr handle) => Native.IsWow64Process(handle, out bool wow64) && wow64; 14 | 15 | public static IEnumerable EnumerateMemoryRegions(IntPtr handle, long maxSize = int.MaxValue) 16 | { 17 | long address = 0; 18 | bool x64 = Is64BitProcess(handle); 19 | do 20 | { 21 | int result; 22 | MemoryInfo m; 23 | if (x64) { 24 | result = Native.VirtualQueryEx64(handle, (IntPtr)address, out Native.MemoryBasicInformation64 m64, (uint)Marshal.SizeOf(typeof(Native.MemoryBasicInformation64))); 25 | m = new MemoryInfo(m64); 26 | } else { 27 | result = Native.VirtualQueryEx32(handle, (IntPtr)address, out Native.MemoryBasicInformation32 m32, (uint)Marshal.SizeOf(typeof(Native.MemoryBasicInformation32))); 28 | m = new MemoryInfo(m32); 29 | } 30 | yield return m; 31 | if (address == (long)m.BaseAddress + (long)m.RegionSize) 32 | break; 33 | address = (long)m.BaseAddress + (long)m.RegionSize; 34 | } while (address <= maxSize); 35 | } 36 | 37 | public class MemoryInfo 38 | { 39 | public ulong BaseAddress; 40 | public ulong RegionSize; 41 | public Native.MemoryState State; 42 | public Native.AllocationProtect Protect; 43 | public Native.MemoryType Type; 44 | 45 | public MemoryInfo(Native.MemoryBasicInformation32 m) 46 | { 47 | BaseAddress = (ulong)m.BaseAddress.ToInt64(); 48 | RegionSize = (ulong)m.RegionSize.ToInt64(); 49 | State = m.State; 50 | Protect = m.Protect; 51 | Type = m.Type; 52 | } 53 | 54 | public MemoryInfo(Native.MemoryBasicInformation64 m) 55 | { 56 | BaseAddress = m.BaseAddress; 57 | RegionSize = m.RegionSize; 58 | State = m.State; 59 | Protect = m.Protect; 60 | Type = m.Type; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/OOP/StructureBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace HoLLy.Memory.OOP 5 | { 6 | public class StructureBase 7 | { 8 | /// 9 | /// The underlying object that handles this object's memory access. 10 | /// 11 | public MemoryAbstraction Memory { get; } 12 | 13 | private IntPtr Addr { get; } 14 | 15 | /// Is the pointer pointing to this structure null? 16 | public bool IsNull => Addr == IntPtr.Zero; 17 | public bool Prefetched => _prefetchedBytes != null; 18 | protected virtual int PrefetchSize => -1; 19 | 20 | private byte[] _prefetchedBytes; 21 | 22 | public StructureBase(MemoryAbstraction mem, IntPtr addr) 23 | { 24 | Memory = mem; 25 | Addr = addr; 26 | } 27 | 28 | /// 29 | /// Will read the entire object and cache it, preventing future on-demand memory reads 30 | /// 31 | public void Prefetch() 32 | { 33 | #if DEBUG 34 | if (PrefetchSize < 0) throw new Exception("Bad prefetch size!"); 35 | #endif 36 | if (Prefetched || PrefetchSize < 0) return; 37 | 38 | _prefetchedBytes = Memory.ReadBytes(Addr, PrefetchSize); 39 | } 40 | 41 | private IntPtr Offset(int offset) => Addr + offset; 42 | 43 | //prefetched 44 | protected IntPtr Pointer(int offset) => Prefetched ? new IntPtr(BitConverter.ToInt32(_prefetchedBytes, offset)) : Memory.ReadIntPtr(Offset(offset)); 45 | protected byte Byte(int offset) => Prefetched ? _prefetchedBytes[offset] : Memory.ReadByte(Offset(offset)); 46 | protected short Short(int offset) => Prefetched ? BitConverter.ToInt16(_prefetchedBytes, offset) : Memory.ReadShort(Offset(offset)); 47 | protected int Int(int offset) => Prefetched ? BitConverter.ToInt32(_prefetchedBytes, offset) : Memory.ReadInt(Offset(offset)); 48 | protected float Float(int offset) => Prefetched ? BitConverter.ToSingle(_prefetchedBytes, offset) : Memory.ReadFloat(Offset(offset)); 49 | protected double Double(int offset) => Prefetched ? BitConverter.ToDouble(_prefetchedBytes, offset) : Memory.ReadDouble(Offset(offset)); 50 | 51 | /// Reads a object from memory 52 | /// This cannot be cached/prefetched. 53 | protected string String(int offset) => Memory.ReadDotNetString(Offset(offset)); 54 | 55 | /// Reads a object from memory. 56 | /// This cannot be cached/prefetched. 57 | protected List List(int offset) where T : StructureBase => Memory.ReadDotNetList(Offset(offset)); 58 | 59 | //other stuff 60 | public T To() where T : StructureBase => (T)Activator.CreateInstance(typeof(T), Memory, Addr); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/MemoryAbstraction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using HoLLy.Memory.OOP; 5 | 6 | namespace HoLLy.Memory 7 | { 8 | public class MemoryAbstraction 9 | { 10 | public IntPtr Handle { get; } 11 | 12 | public MemoryAbstraction(IntPtr handle) => Handle = handle; 13 | 14 | public sbyte ReadSByte(IntPtr address) => (sbyte)ReadBytes(address, 1)[0]; 15 | public short ReadShort(IntPtr address) => BitConverter.ToInt16(ReadBytes(address, 2), 0); 16 | public int ReadInt(IntPtr address) => BitConverter.ToInt32(ReadBytes(address, 4), 0); 17 | public long ReadLong(IntPtr address) => BitConverter.ToInt64(ReadBytes(address, 8), 0); 18 | 19 | public byte ReadByte(IntPtr address) => ReadBytes(address, 1)[0]; 20 | public ushort ReadUShort(IntPtr address)=> BitConverter.ToUInt16(ReadBytes(address, 2), 0); 21 | public uint ReadUInt(IntPtr address) => BitConverter.ToUInt32(ReadBytes(address, 4), 0); 22 | public ulong ReadULong(IntPtr address) => BitConverter.ToUInt64(ReadBytes(address, 8), 0); 23 | 24 | public float ReadFloat(IntPtr address) => BitConverter.ToSingle(ReadBytes(address, 4), 0); 25 | public double ReadDouble(IntPtr address)=> BitConverter.ToDouble(ReadBytes(address, 8), 0); 26 | public IntPtr ReadIntPtr(IntPtr address)=> new IntPtr(BitConverter.ToInt32(ReadBytes(address, 4), 0)); 27 | 28 | /// 29 | /// Read a .NET string through the pointer to it 30 | /// 31 | /// The pointer to the .NET string 32 | /// 33 | public string ReadDotNetString(IntPtr address) 34 | { 35 | var pVTable = ReadIntPtr(address); 36 | var len = ReadInt(pVTable + 0x4); 37 | var buffer = ReadBytes(pVTable + 0x8, len * 2); //NOTE: not correct for codepoints larger than 2 bytes! 38 | return Encoding.Unicode.GetString(buffer); 39 | } 40 | 41 | public List ReadDotNetList(IntPtr address) where T : StructureBase 42 | { 43 | var pVTable = ReadIntPtr(address); 44 | var arrBase = ReadIntPtr(pVTable + 0x4) + 0x8; 45 | var size = ReadInt(pVTable + 0xC); 46 | 47 | // For speed, we'll read the entire chunk at once and then read the pointers from it 48 | List l = new List(size); 49 | byte[] arrData = ReadBytes(arrBase, size * 4); 50 | for (int i = 0; i < size; i++) 51 | { 52 | var ptr = BitConverter.ToInt32(arrData, i * 4); 53 | l.Add(new StructureBase(this, new IntPtr(ptr)).To()); 54 | } 55 | 56 | return l; 57 | } 58 | 59 | public byte[] ReadBytes(IntPtr address, int size) 60 | { 61 | var buffer = new byte[size]; 62 | Native.ReadProcessMemory(Handle, address, buffer, size, out _); 63 | return buffer; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/Patterns/PatternScanner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | 5 | namespace HoLLy.Memory.Patterns 6 | { 7 | public static class PatternScanner 8 | { 9 | private const int ScanStep = 0x1000; 10 | private const long MaxAddress = 0x7fffffff; 11 | 12 | /// 13 | /// Scans a memory section for a pattern, only looking in valid memory regions. 14 | /// 15 | /// A instance of the process to scan 16 | /// The pattern array to scan for 17 | /// The address, or on failure 18 | /// Whether the scan was successful or not 19 | public static bool Scan(MemoryAbstraction abs, PatternByte[] pattern, out IntPtr result) 20 | { 21 | result = IntPtr.Zero; 22 | var handle = abs.Handle; 23 | foreach (var mbi in NativeHelper.EnumerateMemoryRegions(handle).Where(a => a.State == Native.MemoryState.MemCommit)) 24 | if (Scan(handle, pattern, new IntPtr((long)mbi.BaseAddress), (int)mbi.RegionSize, out result)) 25 | return true; 26 | 27 | return false; 28 | } 29 | 30 | /// 31 | /// Scans a memory section for a pattern, only looking in memory regions matching the given 32 | /// and . 33 | /// 34 | /// A instance of the process to scan 35 | /// The pattern array to scan for 36 | /// The memory region type 37 | /// The memory region protection 38 | /// The address, or on failure 39 | /// Whether the scan was successful or not 40 | public static bool Scan(MemoryAbstraction abs, PatternByte[] pattern, Native.MemoryType memType, Native.AllocationProtect memProtect, out IntPtr result) 41 | { 42 | result = IntPtr.Zero; 43 | var handle = abs.Handle; 44 | foreach (var mbi in NativeHelper.EnumerateMemoryRegions(handle, MaxAddress).Where(a => 45 | a.Type == memType 46 | && a.Protect == memProtect 47 | && a.State == Native.MemoryState.MemCommit)) 48 | if (Scan(handle, pattern, new IntPtr((long)mbi.BaseAddress), (int)mbi.RegionSize, out result)) 49 | return true; 50 | 51 | return false; 52 | } 53 | 54 | /// 55 | /// Scans a memory section for a pattern. 56 | /// 57 | /// A handle to the process 58 | /// The pattern array to scan for 59 | /// The address to start at 60 | /// The size of the region to scan 61 | /// The address, or on failure 62 | /// Whether the scan was successful or not 63 | public static bool Scan(IntPtr handle, PatternByte[] pattern, IntPtr baseAddress, int size, out IntPtr result) 64 | { 65 | //TODO: ready for 64-bit 66 | uint step = (uint)Math.Min(size, ScanStep); 67 | uint min = (uint)baseAddress.ToInt32(); 68 | uint max = (uint)(min + size); 69 | byte[] buffer = new byte[step + pattern.Length - 1]; 70 | 71 | //skip wildcards, since they would always match 72 | uint firstNonWildcard = PatternByte.FirstNonWildcardByte(pattern); 73 | 74 | var sw = new Stopwatch(); 75 | sw.Start(); 76 | for (uint i = min; i < max; i += step) 77 | { 78 | //read buffer 79 | //TODO: limit to not go outside region? 80 | Native.ReadProcessMemory(handle, (IntPtr)i, buffer, buffer.Length, out _); 81 | 82 | //loop through buffer 83 | for (uint j = 0; j < step; ++j) 84 | { 85 | bool match = true; 86 | 87 | //loop through pattern 88 | for (uint k = firstNonWildcard; k < pattern.Length; ++k) 89 | { 90 | if (pattern[k].Match(buffer[j + k])) continue; 91 | match = false; 92 | break; 93 | } 94 | 95 | if (match) 96 | { 97 | result = (IntPtr)(i + j); 98 | sw.Stop(); 99 | Debug.WriteLine("Stopwatch sigscan: " + sw.Elapsed); 100 | return true; 101 | } 102 | } 103 | } 104 | 105 | result = IntPtr.Zero; 106 | return false; 107 | } 108 | 109 | [Conditional("DEBUG")] 110 | public static void PrintMemoryRegions(IntPtr handle) 111 | { 112 | foreach (var region in NativeHelper.EnumerateMemoryRegions(handle, MaxAddress)) 113 | Console.WriteLine($"{region.BaseAddress:X8} - {region.BaseAddress + region.RegionSize:X8}: {region.State} / {region.Protect}"); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /HoLLy.MemoryLib/Native.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using HoLLy.Memory.Input; 4 | 5 | namespace HoLLy.Memory 6 | { 7 | public static class Native 8 | { 9 | [DllImport("kernel32.dll", SetLastError = true)] 10 | public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); 11 | 12 | [DllImport("kernel32.dll", SetLastError = true)] 13 | public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, int bInheritHandle, uint dwProcessId); 14 | 15 | [DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx")] 16 | public static extern int VirtualQueryEx32(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation32 lpBuffer, uint dwLength); 17 | 18 | [DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx")] 19 | public static extern int VirtualQueryEx64(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation64 lpBuffer, uint dwLength); 20 | 21 | [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi)] 22 | public static extern bool IsWow64Process(IntPtr processHandle, out bool wow64Process); 23 | 24 | [DllImport("user32.dll", SetLastError = true)] 25 | internal static extern uint SendInput(uint numberOfInputs, InputStruct[] inputs, int sizeOfInputStructure); 26 | 27 | //for 32-bit processes 28 | [StructLayout(LayoutKind.Sequential)] 29 | public struct MemoryBasicInformation32 30 | { 31 | public IntPtr BaseAddress; //TODO: prob uint instead of IntPtr 32 | public IntPtr AllocationBase; 33 | /// 34 | /// The memory protection option when the region was initially allocated. This member is 0 if the caller 35 | /// does not have access. 36 | /// 37 | public AllocationProtect AllocationProtect; 38 | public IntPtr RegionSize; 39 | /// The state of the pages in the region. 40 | public MemoryState State; 41 | /// The access protection of the pages in the region. 42 | public AllocationProtect Protect; 43 | /// The type of pages in the region. 44 | public MemoryType Type; 45 | } 46 | 47 | //for 64-bit processes 48 | [StructLayout(LayoutKind.Sequential)] 49 | public struct MemoryBasicInformation64 50 | { 51 | public ulong BaseAddress; 52 | public ulong AllocationBase; 53 | /// 54 | /// The memory protection option when the region was initially allocated. This member is 0 if the caller 55 | /// does not have access. 56 | /// 57 | public AllocationProtect AllocationProtect; 58 | private int _alignment1; 59 | public ulong RegionSize; 60 | /// The state of the pages in the region. 61 | public MemoryState State; 62 | /// The access protection of the pages in the region. 63 | public AllocationProtect Protect; 64 | /// The type of pages in the region. 65 | public MemoryType Type; 66 | private int _alignment2; 67 | } 68 | 69 | [Flags] 70 | public enum ProcessAccessFlags : uint 71 | { 72 | Terminate = 0x0001, 73 | CreateThread = 0x0002, 74 | VirtualMemoryOperation = 0x0008, 75 | VirtualMemoryRead = 0x0010, 76 | VirtualMemoryWrite = 0x0020, 77 | DuplicateHandle = 0x0040, 78 | CreateProcess = 0x0080, 79 | SetQuota = 0x0100, 80 | SetInformation = 0x0200, 81 | QueryInformation = 0x0400, 82 | QueryLimitedInformation = 0x1000, 83 | 84 | Synchronize = 0x00100000, 85 | //All = 0x001F_0FFF, 86 | All = Terminate | CreateThread | 0x0004 | VirtualMemoryOperation 87 | | VirtualMemoryRead | VirtualMemoryWrite | DuplicateHandle | CreateProcess 88 | | SetQuota | SetInformation | QueryInformation | 0x0800 89 | | 0x001F_0000 90 | } 91 | 92 | [Flags] 93 | public enum AllocationProtect : uint 94 | { 95 | PageNoAccess = 0x00000001, 96 | PageReadonly = 0x00000002, 97 | PageReadWrite = 0x00000004, 98 | PageWriteCopy = 0x00000008, 99 | PageExecute = 0x00000010, 100 | PageExecuteRead = 0x00000020, 101 | PageExecuteReadWrite = 0x00000040, 102 | PageExecuteWriteCopy = 0x00000080, 103 | PageGuard = 0x00000100, 104 | PageNoCache = 0x00000200, 105 | PageWriteCombine = 0x00000400 106 | } 107 | 108 | [Flags] 109 | public enum MemoryState : uint 110 | { 111 | /// 112 | /// Indicates committed pages for which physical storage has been allocated, either in memory or in the 113 | /// paging file on disk. 114 | /// 115 | MemCommit = 0x1000, 116 | 117 | /// 118 | /// Indicates reserved pages where a range of the process's virtual address space is reserved without any 119 | /// physical storage being allocated. For reserved pages, the information in the 120 | /// member is undefined. 121 | /// 122 | MemReserved = 0x2000, 123 | 124 | /// 125 | /// Indicates free pages not accessible to the calling process and available to be allocated. For free 126 | /// pages, the information in the , 127 | /// , , 128 | /// and members is undefined. 129 | /// 130 | MemFree = 0x10000, 131 | } 132 | 133 | [Flags] 134 | public enum MemoryType : uint 135 | { 136 | /// Indicates that the memory pages within the region are private (that is, not shared by other processes). 137 | MemPrivate = 0x20000, 138 | 139 | /// Indicates that the memory pages within the region are mapped into the view of a section. 140 | MemMapped = 0x40000, 141 | 142 | /// Indicates that the memory pages within the region are mapped into the view of an image section. 143 | MemImage = 0x1000000, 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /HoLLy.MemoryLib/Input/VirtualKeyCode.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | namespace HoLLy.Memory.Input 4 | { 5 | /// 6 | /// The list of VirtualKeyCodes (see: http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx) 7 | /// 8 | public enum VirtualKeyCode : ushort 9 | { 10 | /// 11 | /// Left mouse button 12 | /// 13 | LBUTTON = 0x01, 14 | 15 | /// 16 | /// Right mouse button 17 | /// 18 | RBUTTON = 0x02, 19 | 20 | /// 21 | /// Control-break processing 22 | /// 23 | CANCEL = 0x03, 24 | 25 | /// 26 | /// Middle mouse button (three-button mouse) - NOT contiguous with LBUTTON and RBUTTON 27 | /// 28 | MBUTTON = 0x04, 29 | 30 | /// 31 | /// Windows 2000/XP: X1 mouse button - NOT contiguous with LBUTTON and RBUTTON 32 | /// 33 | XBUTTON1 = 0x05, 34 | 35 | /// 36 | /// Windows 2000/XP: X2 mouse button - NOT contiguous with LBUTTON and RBUTTON 37 | /// 38 | XBUTTON2 = 0x06, 39 | 40 | // 0x07 : Undefined 41 | 42 | /// 43 | /// BACKSPACE key 44 | /// 45 | BACK = 0x08, 46 | 47 | /// 48 | /// TAB key 49 | /// 50 | TAB = 0x09, 51 | 52 | // 0x0A - 0x0B : Reserved 53 | 54 | /// 55 | /// CLEAR key 56 | /// 57 | CLEAR = 0x0C, 58 | 59 | /// 60 | /// ENTER key 61 | /// 62 | RETURN = 0x0D, 63 | 64 | // 0x0E - 0x0F : Undefined 65 | 66 | /// 67 | /// SHIFT key 68 | /// 69 | SHIFT = 0x10, 70 | 71 | /// 72 | /// CTRL key 73 | /// 74 | CONTROL = 0x11, 75 | 76 | /// 77 | /// ALT key 78 | /// 79 | MENU = 0x12, 80 | 81 | /// 82 | /// PAUSE key 83 | /// 84 | PAUSE = 0x13, 85 | 86 | /// 87 | /// CAPS LOCK key 88 | /// 89 | CAPITAL = 0x14, 90 | 91 | /// 92 | /// Input Method Editor (IME) Kana mode 93 | /// 94 | KANA = 0x15, 95 | 96 | /// 97 | /// IME Hanguel mode (maintained for compatibility; use HANGUL) 98 | /// 99 | HANGEUL = 0x15, 100 | 101 | /// 102 | /// IME Hangul mode 103 | /// 104 | HANGUL = 0x15, 105 | 106 | // 0x16 : Undefined 107 | 108 | /// 109 | /// IME Junja mode 110 | /// 111 | JUNJA = 0x17, 112 | 113 | /// 114 | /// IME final mode 115 | /// 116 | FINAL = 0x18, 117 | 118 | /// 119 | /// IME Hanja mode 120 | /// 121 | HANJA = 0x19, 122 | 123 | /// 124 | /// IME Kanji mode 125 | /// 126 | KANJI = 0x19, 127 | 128 | // 0x1A : Undefined 129 | 130 | /// 131 | /// ESC key 132 | /// 133 | ESCAPE = 0x1B, 134 | 135 | /// 136 | /// IME convert 137 | /// 138 | CONVERT = 0x1C, 139 | 140 | /// 141 | /// IME nonconvert 142 | /// 143 | NONCONVERT = 0x1D, 144 | 145 | /// 146 | /// IME accept 147 | /// 148 | ACCEPT = 0x1E, 149 | 150 | /// 151 | /// IME mode change request 152 | /// 153 | MODECHANGE = 0x1F, 154 | 155 | /// 156 | /// SPACEBAR 157 | /// 158 | SPACE = 0x20, 159 | 160 | /// 161 | /// PAGE UP key 162 | /// 163 | PRIOR = 0x21, 164 | 165 | /// 166 | /// PAGE DOWN key 167 | /// 168 | NEXT = 0x22, 169 | 170 | /// 171 | /// END key 172 | /// 173 | END = 0x23, 174 | 175 | /// 176 | /// HOME key 177 | /// 178 | HOME = 0x24, 179 | 180 | /// 181 | /// LEFT ARROW key 182 | /// 183 | LEFT = 0x25, 184 | 185 | /// 186 | /// UP ARROW key 187 | /// 188 | UP = 0x26, 189 | 190 | /// 191 | /// RIGHT ARROW key 192 | /// 193 | RIGHT = 0x27, 194 | 195 | /// 196 | /// DOWN ARROW key 197 | /// 198 | DOWN = 0x28, 199 | 200 | /// 201 | /// SELECT key 202 | /// 203 | SELECT = 0x29, 204 | 205 | /// 206 | /// PRINT key 207 | /// 208 | PRINT = 0x2A, 209 | 210 | /// 211 | /// EXECUTE key 212 | /// 213 | EXECUTE = 0x2B, 214 | 215 | /// 216 | /// PRINT SCREEN key 217 | /// 218 | SNAPSHOT = 0x2C, 219 | 220 | /// 221 | /// INS key 222 | /// 223 | INSERT = 0x2D, 224 | 225 | /// 226 | /// DEL key 227 | /// 228 | DELETE = 0x2E, 229 | 230 | /// 231 | /// HELP key 232 | /// 233 | HELP = 0x2F, 234 | 235 | /// 236 | /// 0 key 237 | /// 238 | VK_0 = 0x30, 239 | 240 | /// 241 | /// 1 key 242 | /// 243 | VK_1 = 0x31, 244 | 245 | /// 246 | /// 2 key 247 | /// 248 | VK_2 = 0x32, 249 | 250 | /// 251 | /// 3 key 252 | /// 253 | VK_3 = 0x33, 254 | 255 | /// 256 | /// 4 key 257 | /// 258 | VK_4 = 0x34, 259 | 260 | /// 261 | /// 5 key 262 | /// 263 | VK_5 = 0x35, 264 | 265 | /// 266 | /// 6 key 267 | /// 268 | VK_6 = 0x36, 269 | 270 | /// 271 | /// 7 key 272 | /// 273 | VK_7 = 0x37, 274 | 275 | /// 276 | /// 8 key 277 | /// 278 | VK_8 = 0x38, 279 | 280 | /// 281 | /// 9 key 282 | /// 283 | VK_9 = 0x39, 284 | 285 | // 286 | // 0x3A - 0x40 : Udefined 287 | // 288 | 289 | /// 290 | /// A key 291 | /// 292 | VK_A = 0x41, 293 | 294 | /// 295 | /// B key 296 | /// 297 | VK_B = 0x42, 298 | 299 | /// 300 | /// C key 301 | /// 302 | VK_C = 0x43, 303 | 304 | /// 305 | /// D key 306 | /// 307 | VK_D = 0x44, 308 | 309 | /// 310 | /// E key 311 | /// 312 | VK_E = 0x45, 313 | 314 | /// 315 | /// F key 316 | /// 317 | VK_F = 0x46, 318 | 319 | /// 320 | /// G key 321 | /// 322 | VK_G = 0x47, 323 | 324 | /// 325 | /// H key 326 | /// 327 | VK_H = 0x48, 328 | 329 | /// 330 | /// I key 331 | /// 332 | VK_I = 0x49, 333 | 334 | /// 335 | /// J key 336 | /// 337 | VK_J = 0x4A, 338 | 339 | /// 340 | /// K key 341 | /// 342 | VK_K = 0x4B, 343 | 344 | /// 345 | /// L key 346 | /// 347 | VK_L = 0x4C, 348 | 349 | /// 350 | /// M key 351 | /// 352 | VK_M = 0x4D, 353 | 354 | /// 355 | /// N key 356 | /// 357 | VK_N = 0x4E, 358 | 359 | /// 360 | /// O key 361 | /// 362 | VK_O = 0x4F, 363 | 364 | /// 365 | /// P key 366 | /// 367 | VK_P = 0x50, 368 | 369 | /// 370 | /// Q key 371 | /// 372 | VK_Q = 0x51, 373 | 374 | /// 375 | /// R key 376 | /// 377 | VK_R = 0x52, 378 | 379 | /// 380 | /// S key 381 | /// 382 | VK_S = 0x53, 383 | 384 | /// 385 | /// T key 386 | /// 387 | VK_T = 0x54, 388 | 389 | /// 390 | /// U key 391 | /// 392 | VK_U = 0x55, 393 | 394 | /// 395 | /// V key 396 | /// 397 | VK_V = 0x56, 398 | 399 | /// 400 | /// W key 401 | /// 402 | VK_W = 0x57, 403 | 404 | /// 405 | /// X key 406 | /// 407 | VK_X = 0x58, 408 | 409 | /// 410 | /// Y key 411 | /// 412 | VK_Y = 0x59, 413 | 414 | /// 415 | /// Z key 416 | /// 417 | VK_Z = 0x5A, 418 | 419 | /// 420 | /// Left Windows key (Microsoft Natural keyboard) 421 | /// 422 | LWIN = 0x5B, 423 | 424 | /// 425 | /// Right Windows key (Natural keyboard) 426 | /// 427 | RWIN = 0x5C, 428 | 429 | /// 430 | /// Applications key (Natural keyboard) 431 | /// 432 | APPS = 0x5D, 433 | 434 | // 0x5E : reserved 435 | 436 | /// 437 | /// Computer Sleep key 438 | /// 439 | SLEEP = 0x5F, 440 | 441 | /// 442 | /// Numeric keypad 0 key 443 | /// 444 | NUMPAD0 = 0x60, 445 | 446 | /// 447 | /// Numeric keypad 1 key 448 | /// 449 | NUMPAD1 = 0x61, 450 | 451 | /// 452 | /// Numeric keypad 2 key 453 | /// 454 | NUMPAD2 = 0x62, 455 | 456 | /// 457 | /// Numeric keypad 3 key 458 | /// 459 | NUMPAD3 = 0x63, 460 | 461 | /// 462 | /// Numeric keypad 4 key 463 | /// 464 | NUMPAD4 = 0x64, 465 | 466 | /// 467 | /// Numeric keypad 5 key 468 | /// 469 | NUMPAD5 = 0x65, 470 | 471 | /// 472 | /// Numeric keypad 6 key 473 | /// 474 | NUMPAD6 = 0x66, 475 | 476 | /// 477 | /// Numeric keypad 7 key 478 | /// 479 | NUMPAD7 = 0x67, 480 | 481 | /// 482 | /// Numeric keypad 8 key 483 | /// 484 | NUMPAD8 = 0x68, 485 | 486 | /// 487 | /// Numeric keypad 9 key 488 | /// 489 | NUMPAD9 = 0x69, 490 | 491 | /// 492 | /// Multiply key 493 | /// 494 | MULTIPLY = 0x6A, 495 | 496 | /// 497 | /// Add key 498 | /// 499 | ADD = 0x6B, 500 | 501 | /// 502 | /// Separator key 503 | /// 504 | SEPARATOR = 0x6C, 505 | 506 | /// 507 | /// Subtract key 508 | /// 509 | SUBTRACT = 0x6D, 510 | 511 | /// 512 | /// Decimal key 513 | /// 514 | DECIMAL = 0x6E, 515 | 516 | /// 517 | /// Divide key 518 | /// 519 | DIVIDE = 0x6F, 520 | 521 | /// 522 | /// F1 key 523 | /// 524 | F1 = 0x70, 525 | 526 | /// 527 | /// F2 key 528 | /// 529 | F2 = 0x71, 530 | 531 | /// 532 | /// F3 key 533 | /// 534 | F3 = 0x72, 535 | 536 | /// 537 | /// F4 key 538 | /// 539 | F4 = 0x73, 540 | 541 | /// 542 | /// F5 key 543 | /// 544 | F5 = 0x74, 545 | 546 | /// 547 | /// F6 key 548 | /// 549 | F6 = 0x75, 550 | 551 | /// 552 | /// F7 key 553 | /// 554 | F7 = 0x76, 555 | 556 | /// 557 | /// F8 key 558 | /// 559 | F8 = 0x77, 560 | 561 | /// 562 | /// F9 key 563 | /// 564 | F9 = 0x78, 565 | 566 | /// 567 | /// F10 key 568 | /// 569 | F10 = 0x79, 570 | 571 | /// 572 | /// F11 key 573 | /// 574 | F11 = 0x7A, 575 | 576 | /// 577 | /// F12 key 578 | /// 579 | F12 = 0x7B, 580 | 581 | /// 582 | /// F13 key 583 | /// 584 | F13 = 0x7C, 585 | 586 | /// 587 | /// F14 key 588 | /// 589 | F14 = 0x7D, 590 | 591 | /// 592 | /// F15 key 593 | /// 594 | F15 = 0x7E, 595 | 596 | /// 597 | /// F16 key 598 | /// 599 | F16 = 0x7F, 600 | 601 | /// 602 | /// F17 key 603 | /// 604 | F17 = 0x80, 605 | 606 | /// 607 | /// F18 key 608 | /// 609 | F18 = 0x81, 610 | 611 | /// 612 | /// F19 key 613 | /// 614 | F19 = 0x82, 615 | 616 | /// 617 | /// F20 key 618 | /// 619 | F20 = 0x83, 620 | 621 | /// 622 | /// F21 key 623 | /// 624 | F21 = 0x84, 625 | 626 | /// 627 | /// F22 key 628 | /// 629 | F22 = 0x85, 630 | 631 | /// 632 | /// F23 key 633 | /// 634 | F23 = 0x86, 635 | 636 | /// 637 | /// F24 key 638 | /// 639 | F24 = 0x87, 640 | 641 | // 642 | // 0x88 - 0x8F : Unassigned 643 | // 644 | 645 | /// 646 | /// NUM LOCK key 647 | /// 648 | NUMLOCK = 0x90, 649 | 650 | /// 651 | /// SCROLL LOCK key 652 | /// 653 | SCROLL = 0x91, 654 | 655 | // 0x92 - 0x96 : OEM Specific 656 | 657 | // 0x97 - 0x9F : Unassigned 658 | 659 | // 660 | // L* & R* - left and right Alt, Ctrl and Shift virtual keys. 661 | // Used only as parameters to GetAsyncKeyState() and GetKeyState(). 662 | // No other API or message will distinguish left and right keys in this way. 663 | // 664 | 665 | /// 666 | /// Left SHIFT key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 667 | /// 668 | LSHIFT = 0xA0, 669 | 670 | /// 671 | /// Right SHIFT key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 672 | /// 673 | RSHIFT = 0xA1, 674 | 675 | /// 676 | /// Left CONTROL key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 677 | /// 678 | LCONTROL = 0xA2, 679 | 680 | /// 681 | /// Right CONTROL key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 682 | /// 683 | RCONTROL = 0xA3, 684 | 685 | /// 686 | /// Left MENU key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 687 | /// 688 | LMENU = 0xA4, 689 | 690 | /// 691 | /// Right MENU key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 692 | /// 693 | RMENU = 0xA5, 694 | 695 | /// 696 | /// Windows 2000/XP: Browser Back key 697 | /// 698 | BROWSER_BACK = 0xA6, 699 | 700 | /// 701 | /// Windows 2000/XP: Browser Forward key 702 | /// 703 | BROWSER_FORWARD = 0xA7, 704 | 705 | /// 706 | /// Windows 2000/XP: Browser Refresh key 707 | /// 708 | BROWSER_REFRESH = 0xA8, 709 | 710 | /// 711 | /// Windows 2000/XP: Browser Stop key 712 | /// 713 | BROWSER_STOP = 0xA9, 714 | 715 | /// 716 | /// Windows 2000/XP: Browser Search key 717 | /// 718 | BROWSER_SEARCH = 0xAA, 719 | 720 | /// 721 | /// Windows 2000/XP: Browser Favorites key 722 | /// 723 | BROWSER_FAVORITES = 0xAB, 724 | 725 | /// 726 | /// Windows 2000/XP: Browser Start and Home key 727 | /// 728 | BROWSER_HOME = 0xAC, 729 | 730 | /// 731 | /// Windows 2000/XP: Volume Mute key 732 | /// 733 | VOLUME_MUTE = 0xAD, 734 | 735 | /// 736 | /// Windows 2000/XP: Volume Down key 737 | /// 738 | VOLUME_DOWN = 0xAE, 739 | 740 | /// 741 | /// Windows 2000/XP: Volume Up key 742 | /// 743 | VOLUME_UP = 0xAF, 744 | 745 | /// 746 | /// Windows 2000/XP: Next Track key 747 | /// 748 | MEDIA_NEXT_TRACK = 0xB0, 749 | 750 | /// 751 | /// Windows 2000/XP: Previous Track key 752 | /// 753 | MEDIA_PREV_TRACK = 0xB1, 754 | 755 | /// 756 | /// Windows 2000/XP: Stop Media key 757 | /// 758 | MEDIA_STOP = 0xB2, 759 | 760 | /// 761 | /// Windows 2000/XP: Play/Pause Media key 762 | /// 763 | MEDIA_PLAY_PAUSE = 0xB3, 764 | 765 | /// 766 | /// Windows 2000/XP: Start Mail key 767 | /// 768 | LAUNCH_MAIL = 0xB4, 769 | 770 | /// 771 | /// Windows 2000/XP: Select Media key 772 | /// 773 | LAUNCH_MEDIA_SELECT = 0xB5, 774 | 775 | /// 776 | /// Windows 2000/XP: Start Application 1 key 777 | /// 778 | LAUNCH_APP1 = 0xB6, 779 | 780 | /// 781 | /// Windows 2000/XP: Start Application 2 key 782 | /// 783 | LAUNCH_APP2 = 0xB7, 784 | 785 | // 786 | // 0xB8 - 0xB9 : Reserved 787 | // 788 | 789 | /// 790 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key 791 | /// 792 | OEM_1 = 0xBA, 793 | 794 | /// 795 | /// Windows 2000/XP: For any country/region, the '+' key 796 | /// 797 | OEM_PLUS = 0xBB, 798 | 799 | /// 800 | /// Windows 2000/XP: For any country/region, the ',' key 801 | /// 802 | OEM_COMMA = 0xBC, 803 | 804 | /// 805 | /// Windows 2000/XP: For any country/region, the '-' key 806 | /// 807 | OEM_MINUS = 0xBD, 808 | 809 | /// 810 | /// Windows 2000/XP: For any country/region, the '.' key 811 | /// 812 | OEM_PERIOD = 0xBE, 813 | 814 | /// 815 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key 816 | /// 817 | OEM_2 = 0xBF, 818 | 819 | /// 820 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key 821 | /// 822 | OEM_3 = 0xC0, 823 | 824 | // 825 | // 0xC1 - 0xD7 : Reserved 826 | // 827 | 828 | // 829 | // 0xD8 - 0xDA : Unassigned 830 | // 831 | 832 | /// 833 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key 834 | /// 835 | OEM_4 = 0xDB, 836 | 837 | /// 838 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key 839 | /// 840 | OEM_5 = 0xDC, 841 | 842 | /// 843 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key 844 | /// 845 | OEM_6 = 0xDD, 846 | 847 | /// 848 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key 849 | /// 850 | OEM_7 = 0xDE, 851 | 852 | /// 853 | /// Used for miscellaneous characters; it can vary by keyboard. 854 | /// 855 | OEM_8 = 0xDF, 856 | 857 | // 858 | // 0xE0 : Reserved 859 | // 860 | 861 | // 862 | // 0xE1 : OEM Specific 863 | // 864 | 865 | /// 866 | /// Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard 867 | /// 868 | OEM_102 = 0xE2, 869 | 870 | // 871 | // (0xE3-E4) : OEM specific 872 | // 873 | 874 | /// 875 | /// Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key 876 | /// 877 | PROCESSKEY = 0xE5, 878 | 879 | // 880 | // 0xE6 : OEM specific 881 | // 882 | 883 | /// 884 | /// Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP 885 | /// 886 | PACKET = 0xE7, 887 | 888 | // 889 | // 0xE8 : Unassigned 890 | // 891 | 892 | // 893 | // 0xE9-F5 : OEM specific 894 | // 895 | 896 | /// 897 | /// Attn key 898 | /// 899 | ATTN = 0xF6, 900 | 901 | /// 902 | /// CrSel key 903 | /// 904 | CRSEL = 0xF7, 905 | 906 | /// 907 | /// ExSel key 908 | /// 909 | EXSEL = 0xF8, 910 | 911 | /// 912 | /// Erase EOF key 913 | /// 914 | EREOF = 0xF9, 915 | 916 | /// 917 | /// Play key 918 | /// 919 | PLAY = 0xFA, 920 | 921 | /// 922 | /// Zoom key 923 | /// 924 | ZOOM = 0xFB, 925 | 926 | /// 927 | /// Reserved 928 | /// 929 | NONAME = 0xFC, 930 | 931 | /// 932 | /// PA1 key 933 | /// 934 | PA1 = 0xFD, 935 | 936 | /// 937 | /// Clear key 938 | /// 939 | OEM_CLEAR = 0xFE, 940 | } 941 | } 942 | --------------------------------------------------------------------------------