Results 1 to 11 of 11

Thread: Reading memory from another process (ReadProcessMemory API)

  1. #1

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Reading memory from another process (ReadProcessMemory API)

    Now I know reading another process's memory is kind of a touchy subject because it could be done as part of a malicious program but this code does not demonstrate how to modify another process's memory at all, just read it. I have found a couple of cases where using ReadProcessMemory has been genuinely useful and there was no alternative method (getting an external process's command line arguments for example, which I'll post an example of soon) so thought it might be worth posting my wrapper class here.

    So anyway, I have written a fairly basic .NET class that wraps up the functionality of the ReadProcessMemory API (as well as OpenProcess and CloseHandle) so that you can read memory in a simple and easy way. My class is called NativeMemoryReader as you can see from the code below.

    Here is how you could use the class once you have defined it:
    vb.net Code:
    1. 'quick example of getting a process object for the first
    2. 'instance of notepad.exe that is found running
    3. Dim ProcessToReadFrom As Process = Process.GetProcessesByName("notepad")(0)
    4.  
    5. 'Pass the process to a new instance of our NativeMemoryReader class
    6. Dim MemoryReader As New NativeMemoryReader(ProcessToReadFrom)
    7.  
    8. 'Read 400 bytes from some random address in the process
    9. Dim MemoryBytes() As Byte = MemoryReader.ReadMemory(New IntPtr(132290), 400)
    10.  
    11. 'Dispose will close the handle, but there is a Close method as well
    12. MemoryReader.Dispose()

    Obviously that is just an example so is just reading from a random address in the process - in reality if you were going to be reading memory you would know the address that you want to start from or would be getting a pointer from some other Windows API (you will see an example of it being used in a real scenario when I post the example that shows how to get command line parameters for an external process).

    I'll post the full class definition in the next post. Tested on 32 bit Windows XP and 64 bit Windows 7
    Last edited by chris128; Jun 21st, 2010 at 05:47 AM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  2. #2

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Reading memory from another process (ReadProcessMemory API)

    If you want to use the class described in the above post, just add a new Class to your project and name it NativeMemoryReader, then copy and paste the code below into the code file for that class (replacing anything that was in there).
    vb.net Code:
    1. Imports System.Runtime.InteropServices
    2.  
    3. Public Class NativeMemoryReader : Implements IDisposable
    4.  
    5.  
    6. #Region "API Definitions"
    7.  
    8.     <DllImport("kernel32.dll", EntryPoint:="OpenProcess", SetLastError:=True)> _
    9.     Private Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAsAttribute(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As UInteger) As IntPtr
    10.     End Function
    11.  
    12.     <DllImportAttribute("kernel32.dll", EntryPoint:="ReadProcessMemory", SetLastError:=True)> _
    13.     Private Shared Function ReadProcessMemory(<InAttribute()> ByVal hProcess As System.IntPtr, <InAttribute()> ByVal lpBaseAddress As System.IntPtr, <Out()> ByVal lpBuffer As Byte(), ByVal nSize As UInteger, <OutAttribute()> ByRef lpNumberOfBytesRead As UInteger) As <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean
    14.     End Function
    15.  
    16.     <DllImport("kernel32.dll", EntryPoint:="CloseHandle", SetLastError:=True)> _
    17.     Private Shared Function CloseHandle(ByVal hObject As IntPtr) As <MarshalAsAttribute(UnmanagedType.Bool)> Boolean
    18.     End Function
    19.  
    20. #End Region
    21.  
    22.  
    23. #Region "Private Fields"
    24.  
    25.     Private _TargetProcess As Process = Nothing
    26.     Private _TargetProcessHandle As IntPtr = IntPtr.Zero
    27.     Const PROCESS_VM_READ As UInteger = 16
    28.     Const PROCESS_QUERY_INFORMATION As UInteger = 1024
    29.  
    30. #End Region
    31.  
    32.  
    33. #Region "Public Properties"
    34.  
    35.     ''' <summary>
    36.     ''' The process that memory will be read from when ReadMemory is called
    37.     ''' </summary>
    38.     Public ReadOnly Property TargetProcess() As Process
    39.         Get
    40.             Return _TargetProcess
    41.         End Get
    42.     End Property
    43.  
    44.     ''' <summary>
    45.     ''' The handle to the process that was retrieved during the constructor or the last
    46.     ''' successful call to the Open method
    47.     ''' </summary>
    48.     Public ReadOnly Property TargetProcessHandle() As IntPtr
    49.         Get
    50.             Return _TargetProcessHandle
    51.         End Get
    52.     End Property
    53.  
    54. #End Region
    55.  
    56.  
    57. #Region "Public Methods"
    58.  
    59.     ''' <summary>
    60.     ''' Reads the specified number of bytes from an address in the process's memory.
    61.     ''' All memory in the specified range must be available or the method will fail.
    62.     ''' Returns Nothing if the method fails for any reason
    63.     ''' </summary>
    64.     ''' <param name="MemoryAddress">The address in the process's virtual memory to start reading from</param>
    65.     ''' <param name="Count">The number of bytes to read</param>
    66.     Public Function ReadMemory(ByVal MemoryAddress As IntPtr, ByVal Count As Integer) As Byte()
    67.         If _TargetProcessHandle = IntPtr.Zero Then
    68.             Me.Open()
    69.         End If
    70.         Dim Bytes(Count) As Byte
    71.         Dim Result As Boolean = ReadProcessMemory(_TargetProcessHandle, MemoryAddress, Bytes, CUInt(Count), 0)
    72.         If Result Then
    73.             Return Bytes
    74.         Else
    75.             Return Nothing
    76.         End If
    77.     End Function
    78.  
    79.     ''' <summary>
    80.     ''' Gets a handle to the process specified in the TargetProcess property.
    81.     ''' A handle is automatically obtained by the constructor of this class but if the Close
    82.     ''' method has been called to close a previously obtained handle then another handle can
    83.     ''' be obtained by calling this method. If a handle has previously been obtained and Close has
    84.     ''' not been called yet then an exception will be thrown.
    85.     ''' </summary>
    86.     Public Sub Open()
    87.         If _TargetProcess Is Nothing Then
    88.             Throw New ApplicationException("Process not found")
    89.         End If
    90.         If _TargetProcessHandle = IntPtr.Zero Then
    91.             _TargetProcessHandle = OpenProcess(PROCESS_VM_READ Or PROCESS_QUERY_INFORMATION, True, CUInt(_TargetProcess.Id))
    92.             If _TargetProcessHandle = IntPtr.Zero Then
    93.                 Throw New ApplicationException("Unable to open process for memory reading. The last error reported was: " & New System.ComponentModel.Win32Exception().Message)
    94.             End If
    95.         Else
    96.             Throw New ApplicationException("A handle to the process has already been obtained, " & _
    97.                                            "close the existing handle by calling the Close method before calling Open again")
    98.         End If
    99.     End Sub
    100.  
    101.     ''' <summary>
    102.     ''' Closes a handle that was previously obtained by the constructor or a call to the Open method
    103.     ''' </summary>
    104.     Public Sub Close()
    105.         If Not _TargetProcessHandle = IntPtr.Zero Then
    106.             Dim Result As Boolean = CloseHandle(_TargetProcessHandle)
    107.             If Not Result Then
    108.                 Throw New ApplicationException("Unable to close process handle. The last error reported was: " & _
    109.                                                New System.ComponentModel.Win32Exception().Message)
    110.             End If
    111.             _TargetProcessHandle = IntPtr.Zero
    112.         End If
    113.     End Sub
    114.  
    115. #End Region
    116.  
    117.  
    118. #Region "Constructors"
    119.  
    120.     ''' <summary>
    121.     ''' Creates a new instance of the NativeMemoryReader class and attempts to get a handle to the
    122.     ''' process that is to be read by calls to the ReadMemory method.
    123.     ''' If a handle cannot be obtained then an exception is thrown
    124.     ''' </summary>
    125.     ''' <param name="ProcessToRead">The process that memory will be read from</param>
    126.     Public Sub New(ByVal ProcessToRead As Process)
    127.         If ProcessToRead Is Nothing Then
    128.             Throw New ArgumentNullException("ProcessToRead")
    129.         End If
    130.         _TargetProcess = ProcessToRead
    131.         Me.Open()
    132.     End Sub
    133.  
    134. #End Region
    135.  
    136.  
    137. #Region "IDisposable Support"
    138.  
    139.     Private disposedValue As Boolean
    140.  
    141.     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    142.         If Not Me.disposedValue Then
    143.             If Not _TargetProcessHandle = IntPtr.Zero Then
    144.                 Try
    145.                     CloseHandle(_TargetProcessHandle)
    146.                 Catch ex As Exception
    147.                     Debug.WriteLine("Error closing handle - " & ex.Message)
    148.                 End Try
    149.             End If
    150.         End If
    151.         Me.disposedValue = True
    152.     End Sub
    153.  
    154.     Protected Overrides Sub Finalize()
    155.         Dispose(False)
    156.         MyBase.Finalize()
    157.     End Sub
    158.  
    159.     ''' <summary>
    160.     ''' Releases resources and closes any process handles that are still open
    161.     ''' </summary>
    162.     Public Sub Dispose() Implements IDisposable.Dispose
    163.         Dispose(True)
    164.         GC.SuppressFinalize(Me)
    165.     End Sub
    166.  
    167. #End Region
    168.  
    169. End Class
    Last edited by chris128; Jun 10th, 2010 at 04:21 AM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  3. #3

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Reading memory from another process (ReadProcessMemory API)

    As mentioned above, here's an example of using this class for a real purpose - to get the command line arguments that an external process was started with: http://cjwdev.wordpress.com/2010/06/...ernal-process/
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  4. #4
    New Member
    Join Date
    Jul 2010
    Posts
    2

    Re: Reading memory from another process (ReadProcessMemory API)

    Excellent Post. - I've been trying to find a working example of the ReadProcessMemory Function for a while.

    I am still a bit confused about the address parameter. In your class you take two parameters - a start point address and the number of bytes you want to
    retrieve. If I want to read from the start of the process is the first parameter
    the memory address for the process or is it 1.?

    Here's what I am trying to do.

    By right clicking a process in task manager I can select "Create Dump File" and this cretes a dump file on my hard drive.I want to do this programmatically.

  5. #5

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Reading memory from another process (ReadProcessMemory API)

    Quote Originally Posted by BrainSurgeon View Post
    I am still a bit confused about the address parameter. In your class you take two parameters - a start point address and the number of bytes you want to
    retrieve. If I want to read from the start of the process is the first parameter
    the memory address for the process or is it 1.?
    Unfortunately its not that simple I'm afraid. You might get a decent understanding of the general concepts of virtual memory etc here: http://support.microsoft.com/kb/555223 but as for actually determining what address a process's virtual memory starts at and ends at, I'm not exactly sure how you do that. I made this class for use with various Windows APIs where they give you a pointer and its up to you to read the memory at that pointer, so I've never really tried to just read a big chunk of memory with it, I've always been reading from an address that was supplied to me by an API for a specific number of bytes.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  6. #6
    New Member
    Join Date
    Jul 2010
    Posts
    2

    Re: Reading memory from another process (ReadProcessMemory API)

    Thanks Chris - Love the second app (command line) this will be very useful.

    I found a solution to creating the dump file using : MiniDumpWriteDump API available inside the dbghelp.dll file.

    http://www.codeguru.com/forum/showth...&is_resolved=1

    Thanks a million.

  7. #7
    Junior Member
    Join Date
    Mar 2009
    Posts
    16

    Re: Reading memory from another process (ReadProcessMemory API)

    hi
    is it possible to read my memory per variables?
    id like to get a dictionary of all variables in the memory of my currently running application
    with the size of each variable
    how can i accomplish this?
    i need it for debugging, as the memory usage of my app is growing beyond the limits of the hosting server
    thank you very very much

  8. #8

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Reading memory from another process (ReadProcessMemory API)

    Quote Originally Posted by Yisman View Post
    hi
    is it possible to read my memory per variables?
    id like to get a dictionary of all variables in the memory of my currently running application
    with the size of each variable
    how can i accomplish this?
    i need it for debugging, as the memory usage of my app is growing beyond the limits of the hosting server
    thank you very very much
    No that's not what this is for. If you are having memory leak problems you should use something like the .NET CLR Memory Profiler to identify the objects that are taking up memory when your program is leaking memory
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  9. #9
    Junior Member
    Join Date
    Mar 2009
    Posts
    16

    Re: Reading memory from another process (ReadProcessMemory API)

    thanks
    its not technically a "leak" (see http://stackoverflow.com/questions/7...t-load-sos-clr )
    the memory can be easily reclaimed (it goes up and down)
    its just too much for the server
    anyhow i guess ill have to keep on looking
    thanks for your help anyway

  10. #10

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Reading memory from another process (ReadProcessMemory API)

    Regardless of what you want to call it, you said you wanted a way of seeing what was taking up memory in your app - that's exactly what the program that I mentioned does (and its a free download from MS)
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  11. #11
    Junior Member
    Join Date
    Mar 2009
    Posts
    16

    Re: Reading memory from another process (ReadProcessMemory API)

    yes, i see
    but this is not some code i can run from my app
    its an application that needs to be installed on the server
    something the hosting company would (rightfully) disallow
    do you know of any .net classes that can give me a list of variable memory sizes?
    such as:
    x=2 bytes
    userid=8 kb
    ProductListCache=35mb
    etc...
    thank you

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width