[C# + Win32] Memory Reading Class Example menu

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 15 of 30
  1. #1
    joetheodd's Avatar Member
    Reputation
    10
    Join Date
    Mar 2009
    Posts
    20
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [C# + Win32] Memory Reading Class Example

    Hey guys. I'm sure none of you know me as I'm new here and I've asked only one question. MMOwned seems to be a great community of like-minded individuals, and I want to give back what I've learned so far, from the forums and Googling things.

    A bit of background information on this -- I'm currently developing a small program that will read various things from memory, eventually enough to create an out-of-process bot. I haven't gotten all that far, but I'm rather proud of the classes I have for reading memory.

    I use two classes. First, the class Memory is where all the action takes place. Also, in a different namespace (WoWHack.Win32), I have another class, named Kernel32, containing the necessary Win32 functions, structs, enums, constants, etc. That makes this entirely contained -- you do nothing but give Memory a process ID, and then tell it what you want.

    Without further ado..

    Code:
    using System;                           // Array
    using System.Text;                      // UTF8, UTF16
    using System.ComponentModel;            // Win32Exception
    using System.Runtime.InteropServices;   // Marshal
    
    using WoWHack.Win32;                    // Kernel32
    
    namespace WoWHack.Utilities
    {
        /// <summary>
        /// This is a very generic class for reading a process' memory, a bit similar to a generic buffer.
        /// The process handle is opened in the constructor and closed in the deconstructor. This gives
        /// the efficiency of not calling OpenProcess and CloseHandle each time, but gives the disadvantage
        /// of needing to be constructed after the target process has been opened. However, this is a moot
        /// point considering the constructor needs a process ID anyhow.
        /// </summary>
        public class Memory
        {
            /// <summary>
            /// The ID of the process we're working with.
            /// </summary>
            private int ProcessID;
            /// <summary>
            /// A handle to process <b>ProcessID</b>. Created in the constructor and closed in the
            /// deconstructor.
            /// </summary>
            private int ProcessHandle;
    
            public Memory(int ProcessID)
            {
                this.ProcessID = ProcessID;
                System.Diagnostics.Process.EnterDebugMode();
                
                ProcessHandle = Kernel32.OpenProcess(Kernel32.OpenProcess_Access.VMRead | Kernel32.OpenProcess_Access.QueryInformation, false, ProcessID);
                if (ProcessHandle == 0)
                    throw new Win32Exception("Unable to open process ID " + this.ProcessID);
            }
    
            /// <summary>
            /// Called when this class is destroyed to free resources.
            /// </summary>
            ~Memory()
            {
                Kernel32.CloseHandle(ProcessHandle);
            }
    
            /// <summary>
            /// Reads a series of bytes, <b>length</b> long, from <b>address</b>.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <param name="length">Number of bytes to read.</param>
            /// <returns></returns>
            public byte[] ReadBytes(uint address, int length)
            {
                int returnLength;
                byte[] value = new byte[length];
                if (!Kernel32.ReadProcessMemory(ProcessHandle, address, out value, length, out returnLength))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return value;
            }
    
            /// <summary>
            /// Reads an integer from <b>address</b>.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public int ReadInt(uint address)
            {
                int returnLength = 0;
                int value = 0;
                if (!Kernel32.ReadProcessMemory(ProcessHandle, address, out value, Marshal.SizeOf(value), out returnLength))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return value;
            }
    
            /// <summary>
            /// Reads an unsigned integer from <b>address</b>.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public uint ReadUInt(uint address)
            {
                int returnLength = 0;
                int value = 0;
                if (!Kernel32.ReadProcessMemory(ProcessHandle, address, out value, Marshal.SizeOf(value), out returnLength))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return (uint)value;
            }
    
            /// <summary>
            /// Reads a long integer from <b>address</b>.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public long ReadLong(uint address)
            {
                long value = 0;
                int returnLength = 0;
                if (!Kernel32.ReadProcessMemory(ProcessHandle, address, out value, Marshal.SizeOf(value), out returnLength))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return value;
            }
    
            /// <summary>
            /// Reads an unsigned long integer from <b>address</b>.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public ulong ReadULong(uint address)
            {
                long value = 0;
                int returnLength = 0;
                if (!Kernel32.ReadProcessMemory(ProcessHandle, address, out value, Marshal.SizeOf(value), out returnLength))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return (ulong)value;
            }
    
            /// <summary>
            /// Reads a float from <b>address</b>.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public float ReadFloat(uint address)
            {
                float value = 0f;
                int returnLength = 0;
                if (!Kernel32.ReadProcessMemory(ProcessHandle, address, out value, Marshal.SizeOf(value), out returnLength))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return value;
            }
    
            /// <summary>
            /// Reads a series of bytes, starting at <b>address</b>, ending with a zero-byte.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <seealso>ReadUTF8String</seealso>
            /// <seealso>ReadUTF16String</seealso>
            /// <returns></returns>
            private byte[] ReadNullTerminatedBytes(uint address)
            {
                int returnLength = 0;
                byte[] ret = new byte[0];
                int size = 0;
                byte b = 0;
    
                while (true)
                {
                    Kernel32.ReadProcessMemory(ProcessHandle, address++, out b, Marshal.SizeOf(b), out returnLength);
                    if (b == 0)
                        return ret;
                    else
                    {
                        Array.Resize(ref ret, size + 1);
                        ret[size++] = b;
                    }
                }
            }
    
            /// <summary>
            /// Reads a UTF-8 String, starting at <b>address</b>, ending with a zero-byte.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public string ReadUTF8String(uint address)
            {
                return Encoding.UTF8.GetString(ReadNullTerminatedBytes(address));
            }
    
            /// <summary>
            /// Reads a UTF-16 String, starting at <b>address</b>, ending with a zero-byte.
            /// </summary>
            /// <param name="address">Pointer to read from.</param>
            /// <returns></returns>
            public string ReadUTF16String(uint address)
            {
                return Encoding.Unicode.GetString(ReadNullTerminatedBytes(address));
            }
    
        }
    }
    Kernel32.cs
    Code:
    using System.Runtime.InteropServices;   // DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute
                                            // StructLayout, StructLayoutAttribute
    
    namespace WoWHack.Win32
    {
        /// <summary>
        /// This entirely static class contains all the needed kernel32 functions, as well
        /// as their related enumerations and structures.
        /// </summary>
        static class Kernel32
        {
            #region OpenProcess
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern int OpenProcess(
                OpenProcess_Access dwDesiredAccess,
                [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
                int dwProcessId
            );
            public enum OpenProcess_Access : int
            {
                /// <summary>Enables usage of the process handle in the TerminateProcess function to terminate the process.</summary>
                /* 00 00 00 01 */ Terminate = 0x1,
                /// <summary>Enables usage of the process handle in the CreateRemoteThread function to create a thread in the process.</summary>
                /* 00 00 00 02 */ CreateThread = 0x2,
                /// <summary>Enables usage of the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.</summary>
                /* 00 00 00 08 */ VMOperation = 0x8,
                /// <summary>Enables usage of the process handle in the ReadProcessMemory function to' read from the virtual memory of the process.</summary>
                /* 00 00 00 10 */ VMRead = 0x10,
                /// <summary>Enables usage of the process handle in the WriteProcessMemory function to write to the virtual memory of the process.</summary>
                /* 00 00 00 20 */ VMWrite = 0x20,
                /// <summary>Enables usage of the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.</summary>
                /* 00 00 00 40 */ DuplicateHandle = 0x40,
                /// <summary>Enables usage of the process handle in the SetPriorityClass function to set the priority class of the process.</summary>
                /* 00 00 02 00 */ SetInformation = 0x200,
                /// <summary>Enables usage of the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.</summary>
                /* 00 00 04 00 */ QueryInformation = 0x400,
                /// <summary>Enables usage of the process handle in any of the wait functions to wait for the process to terminate.</summary>
                /* 00 10 00 00 */ Synchronize = 0x100000
            }
    
            #endregion OpenProcess
    
            #region CloseHandle
    
            [DllImport("kernel32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseHandle(int hObject);
    
            #endregion
    
            #region ReadProcessMemory
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool ReadProcessMemory(
             int hProcess,
             uint lpBaseAddress,
             out byte[] buffer,
             int dwSize,
             out int lpNumberOfBytesRead
            );
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool ReadProcessMemory(
             int hProcess,
             uint lpBaseAddress,
             out byte buffer,
             int dwSize,
             out int lpNumberOfBytesRead
            );
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool ReadProcessMemory(
             int hProcess,
             uint lpBaseAddress,
             out long buffer,
             int dwSize,
             out int lpNumberOfBytesRead
            );
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool ReadProcessMemory(
             int hProcess,
             uint lpBaseAddress,
             out int buffer,
             int dwSize,
             out int lpNumberOfBytesRead
            );
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool ReadProcessMemory(
             int hProcess,
             uint lpBaseAddress,
             out float buffer,
             int dwSize,
             out int lpNumberOfBytesRead
            );
    
            #endregion
    
            #region GetCurrentProcess
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern int GetCurrentProcess();
            #endregion
    
        }
    }
    Thanks to:
    lanman92 - Teaching me how to enter debug mode without ripping hairs out.
    vulcanaoc - Correction on C# naming conventions.
    deCutter and ramey - Pointing out the obvious but overlooked fact that WoW uses UTF-8 instead of ASCII.
    Whoever +rep'd me - Emotional support.
    Last edited by joetheodd; 07-21-2009 at 08:13 PM.

    [C# + Win32] Memory Reading Class Example
  2. #2
    lanman92's Avatar Active Member
    Reputation
    50
    Join Date
    Mar 2007
    Posts
    1,033
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It's much simpler to use System.Diagnostics.Process.EnterDebugMode() to, well, enter debug mode. No need for all that code. Otherwise, nice job. String reading would be a nice addition.

  3. #3
    joetheodd's Avatar Member
    Reputation
    10
    Join Date
    Mar 2009
    Posts
    20
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You've gotta be kidding me. I wrote all that ****ing code and there's a single function in the framework to do it? That's what I get for not searching. FML.

    I'll change that and add string reading in just a second. Thanks.

  4. #4
    Emuchild's Avatar Member
    Reputation
    56
    Join Date
    Oct 2007
    Posts
    311
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Lmao, joe... Very well written code though. Haha.
    Tired of proxies not working or timing out?
    TEST THEM BEFORE YOU USE THEM!
    https://www.mmowned.com/forums/general-programs/246775-testmyproxies.html :wave:

  5. #5
    joetheodd's Avatar Member
    Reputation
    10
    Join Date
    Mar 2009
    Posts
    20
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you Emuchild.

    I've pasted the new version of Memory.cs and kernel32.cs. If you got kernel32.cs before I updated, you'll need to get it again as I needed to add a new signature for ReadProcessMemory.

    Also, my memory utility thing (I love technical terms) isn't complete to the point where I'd need to read a string, so can someone confirm that the function works? Thank you!

  6. #6
    vulcanaoc's Avatar Member
    Reputation
    31
    Join Date
    Jul 2008
    Posts
    125
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice clean code.

    BTW, as per general C# naming conventions, you don't want to have a class starting with a lowercase letter. kernel32->Kernel32 <.<

  7. #7
    deCutter's Avatar Member
    Reputation
    5
    Join Date
    Apr 2009
    Posts
    17
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by joetheodd View Post
    Code:
            public string ReadString(uint address)
            {
                string value = "";
                int returnLength = 0;
                byte b = 0;
                while (true)
                {
                    kernel32.ReadProcessMemory(ProcessHandle, address, out b, Marshal.SizeOf(b), out returnLength);
                    if (b == 0)
                        break;
                    else
                        value += b;
                }
                return value;
            }
    First, this can read only ASCII stings. Wow also uses UTF16 strings, which have 2 bytes per symbol size.
    Second, the way u do it i guess is the slowest way possible to do it. U should allocate some memory, for example, using Marshal.AllocHGlobal (GC will not touch that memory since it is unmanaged) and pass a pointer to it to your ReadProcessMemory. Don`t forget to Marshal.FreeHGlobal when you are done.
    For even more perfomance (but at the cost of some memory) u can do this only once in class constructor to keep it in local variable and then use it in both versions of ReadString functions.

  8. #8
    ramey's Avatar Member
    Reputation
    45
    Join Date
    Jan 2008
    Posts
    320
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by deCutter View Post
    First, this can read only ASCII stings. Wow also uses UTF16 strings, which have 2 bytes per symbol size.
    Second, the way u do it i guess is the slowest way possible to do it. U should allocate some memory, for example, using Marshal.AllocHGlobal (GC will not touch that memory since it is unmanaged) and pass a pointer to it to your ReadProcessMemory. Don`t forget to Marshal.FreeHGlobal when you are done.
    For even more perfomance (but at the cost of some memory) u can do this only once in class constructor to keep it in local variable and then use it in both versions of ReadString functions.
    Psst, WoW uses utf-8

  9. #9
    vulcanaoc's Avatar Member
    Reputation
    31
    Join Date
    Jul 2008
    Posts
    125
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by deCutter View Post
    First, this can read only ASCII stings. Wow also uses UTF16 strings, which have 2 bytes per symbol size.
    Second, the way u do it i guess is the slowest way possible to do it. U should allocate some memory, for example, using Marshal.AllocHGlobal (GC will not touch that memory since it is unmanaged) and pass a pointer to it to your ReadProcessMemory. Don`t forget to Marshal.FreeHGlobal when you are done.
    For even more perfomance (but at the cost of some memory) u can do this only once in class constructor to keep it in local variable and then use it in both versions of ReadString functions.
    Keeping that allocated memory at the local level might cause some issues with multi-threading unless you're careful.

  10. #10
    lanman92's Avatar Active Member
    Reputation
    50
    Join Date
    Mar 2007
    Posts
    1,033
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Couldn't you use the lock keyword to prevent those issues a bit? Also, I'm not sure, but VirtualAllocEx is probably faster than using the .NET version(AllocHGlobal).

  11. #11
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wow you guys are a bit retarded.

    1) Win32 vs .NET API is nearly as fast either way. (If you don't include the extra checks in the .NET API [which 99% of the time, prevent you from making stupid mistakes])
    2) That memory reading class is pretty ugly. And quite a waste of space.
    2a) Your naming conventions suck. Period. Please go read the MS naming conventions for C#.
    2b) Your code will be a huge pain in the ass to maintain. Even on small code-bases. Learn code-reuse.
    2c) Use proper .NET code structures. Those include; the Encoding class. (Support for UTF8 and byte-length availability) The Marshal class. (Proper use, not Marshal.SizeOf(x), use sizeof(x) for those)

    Last but not least; USE A GOD DAMNED INTPTR! NOT A ****ING INT! IntPtr is the equivalent to any type of pointer in the unmanaged world. (That includes handles) Seriously, this code is just plain ugly as sin.

  12. #12
    joetheodd's Avatar Member
    Reputation
    10
    Join Date
    Mar 2009
    Posts
    20
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I haven't tested UTF16 (unicode) reading yet, but UTF-8 works correctly now. I was wondering why the ò in my name looked retarded.

    Changed the name of kernel32.cs to Kernel32.cs, as per vulcanaos' advice.

    Thanks everone.

  13. #13
    joetheodd's Avatar Member
    Reputation
    10
    Join Date
    Mar 2009
    Posts
    20
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    1) Are you suggesting I do things a different way, or were you talking to someone else?

    2) Everyone else seems to disagree.

    2a) Sorry. I'll do that when I get a chance.

    2b) I don't see how that can be at all true. I feel that this focuses 100% on code-reuse (and OOP itself)

    2c) I'm not aware of anywhere I used Marshal improperly. I've just added Encoding usage. I'll change the sizeof usage.

    Last but not least; My code doesn't use IntPtr's cause you can't do math on them, and seeing (IntPtr)((uint)this + (uint)that)) hurts my brain immensely, and is "ugly as sin".

  14. #14
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by joetheodd View Post
    1) Are you suggesting I do things a different way, or were you talking to someone else?

    2) Everyone else seems to disagree.

    2a) Sorry. I'll do that when I get a chance.

    2b) I don't see how that can be at all true. I feel that this focuses 100% on code-reuse (and OOP itself)

    2c) I'm not aware of anywhere I used Marshal improperly. I've just added Encoding usage. I'll change the sizeof usage.

    Last but not least; My code doesn't use IntPtr's cause you can't do math on them, and seeing (IntPtr)((uint)this + (uint)that)) hurts my brain immensely, and is "ugly as sin".
    IntPtr provides some fairly obvious methods to do those conversions 'cleanly' for you.

    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Text;
    
    namespace WinLib.Memory
    {
        public class MemoryReader : IDisposable
        {
            public MemoryReader(int procId)
            {
                if (procId == 0)
                {
                    throw new ArgumentException("Proccess ID cannot be 0!", "procId");
                }
    
                ProcessHandle = OpenProcess(ProcessAccess.AllAccess, false, procId);
    
                if (ProcessHandle == IntPtr.Zero)
                {
                    throw new Win32Exception("Failed to open the process for reading.");
                }
    
                Process.EnterDebugMode();
            }
    
            public IntPtr ProcessHandle { get; private set; }
    
            #region IDisposable Members
    
            public void Dispose()
            {
                if (ProcessHandle != IntPtr.Zero)
                {
                    if (!CloseHandle(ProcessHandle))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                GC.SuppressFinalize(this);
            }
    
            #endregion
    
            ~MemoryReader()
            {
                Dispose();
            }
    
            public byte[] ReadBytes(IntPtr address, uint count)
            {
                var buffer = new byte[count];
                int bytesRead;
                if (!ReadProcessMemory(ProcessHandle, address, buffer, count, out bytesRead))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
                if (bytesRead != count)
                {
                    throw new Exception("Bytes read did not match required byte count!");
                }
                return buffer;
            }
    
            public byte[] ReadBytes(uint address, uint count)
            {
                return ReadBytes(new IntPtr(address), count);
            }
    
            public T Read<T>(IntPtr address) where T : struct
            {
                object ret = default(T);
                var buffer = new byte[0];
                // We want to catch strings right here. Since they require some extra attention.
                if (typeof(T) == typeof(string))
                {
                    ret = ReadCString(address, Encoding.UTF8);
                }
                else
                {
                    // Marshal here, as we want the native byte count!
                    buffer = ReadBytes(address, (uint) Marshal.SizeOf(typeof(T)));
                }
    
                switch (Type.GetTypeCode(typeof(T)))
                {
                    case TypeCode.Object:
                        // Double check this. It *should* work. But may not. Untested
                        GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                        Marshal.PtrToStructure(handle.AddrOfPinnedObject(), ret);
                        handle.Free();
                        break;
                    case TypeCode.Boolean:
                        ret = BitConverter.ToBoolean(buffer, 0);
                        break;
                    case TypeCode.Char:
                        ret = BitConverter.ToChar(buffer, 0);
                        break;
                    case TypeCode.Byte:
                        // Will throw an argument out of range exception if 0 bytes were read.
                        // This is on purpose!
                        ret = buffer[0];
                        break;
                    case TypeCode.Int16:
                        ret = BitConverter.ToInt16(buffer, 0);
                        break;
                    case TypeCode.UInt16:
                        ret = BitConverter.ToUInt16(buffer, 0);
                        break;
                    case TypeCode.Int32:
                        ret = BitConverter.ToInt32(buffer, 0);
                        break;
                    case TypeCode.UInt32:
                        ret = BitConverter.ToUInt32(buffer, 0);
                        break;
                    case TypeCode.Int64:
                        ret = BitConverter.ToInt64(buffer, 0);
                        break;
                    case TypeCode.UInt64:
                        ret = BitConverter.ToUInt64(buffer, 0);
                        break;
                    case TypeCode.Single:
                        ret = BitConverter.ToSingle(buffer, 0);
                        break;
                    case TypeCode.Double:
                        ret = BitConverter.ToDouble(buffer, 0);
                        break;
                    case TypeCode.String:
                        // We already handled this case!
                        break;
                    default:
                        throw new NotSupportedException(string.Format("{0} is not currently supported by this function.",
                                                                      typeof(T).FullName));
                }
    
                return (T) ret;
            }
    
            public T Read<T>(uint address) where T : struct
            {
                return Read<T>(new IntPtr(address));
            }
    
            public string ReadCString(IntPtr address, Encoding encType)
            {
                // Unknown string size.
                var buffer = new List<byte>();
    
                int i = 0;
                var current = Read<byte>((uint) (address.ToInt32() + i));
                while (current != '\0')
                {
                    buffer.Add(current);
                    i++;
                    current = Read<byte>((uint) (address.ToInt32() + i));
                }
                return encType.GetString(buffer.ToArray());
            }
    
            #region PInvokes
    
            [DllImport("kernel32.dll", SetLastError = true, PreserveSig = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize,
                                                         out int lpNumberOfBytesRead);
    
            [DllImport("kernel32.dll")]
            private static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess,
                                                     [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool CloseHandle(IntPtr hObject);
    
            #endregion
    
            #region Nested type: ProcessAccess
    
            [Flags]
            private enum ProcessAccess
            {
                /// <summary>Specifies all possible access flags for the process object.</summary>
                AllAccess =
                    CreateThread | DuplicateHandle | QueryInformation | SetInformation | Terminate | VMOperation | VMRead |
                    VMWrite | Synchronize,
                /// <summary>Enables usage of the process handle in the CreateRemoteThread function to create a thread in the process.</summary>
                CreateThread = 0x2,
                /// <summary>Enables usage of the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.</summary>
                DuplicateHandle = 0x40,
                /// <summary>Enables usage of the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.</summary>
                QueryInformation = 0x400,
                /// <summary>Enables usage of the process handle in the SetPriorityClass function to set the priority class of the process.</summary>
                SetInformation = 0x200,
                /// <summary>Enables usage of the process handle in the TerminateProcess function to terminate the process.</summary>
                Terminate = 0x1,
                /// <summary>Enables usage of the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.</summary>
                VMOperation = 0x8,
                /// <summary>Enables usage of the process handle in the ReadProcessMemory function to' read from the virtual memory of the process.</summary>
                VMRead = 0x10,
                /// <summary>Enables usage of the process handle in the WriteProcessMemory function to write to the virtual memory of the process.</summary>
                VMWrite = 0x20,
                /// <summary>Enables usage of the process handle in any of the wait functions to wait for the process to terminate.</summary>
                Synchronize = 0x100000
            }
    
            #endregion
        }
    }
    Overloads are just such a headache!

    Seriously though, that's less than 200 (not including comments) lines of code to handle *every* type of read you can think of. Minus of course, pascal strings. (Does anything even use those anymore?) Includes support for using (var mr = new MemoryReader(procId)) statements.

    Notice how I only use ONE RPM signature? There's absolutely no need for more than 1. Period.

    I removed some code as it's not really relevant to this thread. (Stuff for other types of memory reading, as well as some mem->disk dumping, etc)

  15. #15
    joetheodd's Avatar Member
    Reputation
    10
    Join Date
    Mar 2009
    Posts
    20
    Thanks G/R
    1/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    /me tucks tail between the legs.

Page 1 of 2 12 LastLast

Similar Threads

  1. [c# example] memory reading
    By kantaki in forum Programming
    Replies: 6
    Last Post: 02-03-2012, 05:32 PM
  2. Replies: 1
    Last Post: 11-30-2011, 02:36 PM
  3. [Request][Bounty] WoW memory reading example script c++
    By foxlin in forum WoW Bots Questions & Requests
    Replies: 4
    Last Post: 07-27-2011, 09:08 AM
  4. [Example] Check if spell is available with memory reading
    By orby_tale in forum WoW Memory Editing
    Replies: 1
    Last Post: 11-14-2010, 05:14 PM
  5. [C++]Memory Reading Class
    By opulent in forum WoW Memory Editing
    Replies: 3
    Last Post: 05-11-2009, 06:55 AM
All times are GMT -5. The time now is 08:25 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search