Results 1 to 1 of 1
  1. #1
    abuckau907's Avatar
    Join Date
    Dec 2012
    Gender
    male
    Location
    other side of the wire
    Posts
    1,342
    Reputation
    162
    Thanks
    239
    My Mood
    Cold

    Basic External Memory Library for vb.net - ReadProcessMemory & WriteProcessMemory

    For anyone who wants to start playing with memory reading and writing. (copy-pastable - should compile for 32bit and 64. ofc if you compile for 32 bit, don't try to access a 64 bit program- it won't work).

    Not much of a tut., but here's a few notes.

    1. You MUST be 'Attached' to the process before you can read or write to it's memory. The Attach() function expects a process ID and returns a boolean indicating success/fail.
    -Behind the scenes Attach() calls OpenProcess() and tries to obtain a 'unique handle to the process' (which is required for all of the virtual memory functions: ReadProcessMemory, WriteProcessMemory, VirtualQueryEx, VirtualProtectEx, etc). You must get a handle from OpenProcess() before you can read/modify a process's memory.

    2. Detach() will automatically be called when the MemoryManager object is disposed (thnx IDisposable). Not very important, but could be.

    3. Most Importantly - You must already understand the vb.net language, and have a basic grasp on virtual memory.

    usage:
    Code:
    Dim _targetID As Int32 = ****
    Dim _memMgr As New MemoryManager()
    ..
    
    If _memMgr.AttachToProcess(_targetID) Then
      MessageBox.Show("Attach Success!")
      ''After this point we can read/write
      Else
      MessageBox.Show("Attach Fail. Access Denied?")
    End If
    usage:
    Code:
    Dim _addr As IntPtr = New IntPtr(&H12345678)
    
    If _memMgr.IsAttached() Then
      Dim xx as Int16 = _memMgr.ReadInt16(_addr)
      Dim yy as Int32 = _memMgr.ReadInt32(_addr)
      Dim zz as Int64 = _memMgr.ReadInt64(_addr)
      Dim ff as Single = _memMgr.ReadFloat(_addr)
      Dim str As String = _memMgr.ReadAsciiString(_addr,25)
    
      _memMgr.WriteInt32(_addr, 1000000) '' write 1,000,000
    End If
    --------------------------------------------------

    a couple ways to find our target process' ID - based on Main Window Title
    Code:
            For Each proc As Process In Process.GetProcesses()
                If proc.MainWindowTitle = "Calculator" Then
                    ''This is our target process
                    'use proc.Id
                End If
            Next
    based on Process Name
    Code:
            For Each proc As Process In Process.GetProcesses()
                If proc.ProcessName = "calc" Then
                    ''This is our target process
                    'use proc.Id
                End If
            Next
    based on Process Name (again)
    Code:
            Dim _procs() As Process = Process.GetProcessesByName("calc")
            If _procs.Length = 0 Then
                ''no results returned. Process not found.
            Else
                '' at least 1 process found.
                ''use _procs(0).Id
            End If
    --------------------------------------------------

    I broke the code into 2 parts - 1 is a few Windows APIs/structs/enums, and the other is the MemoryManager class.

    WinApi class. Feel free to declare all of this inside the MemoryManager class if you'd like.
    Code:
    Public Class WinApi
    #Region "Windows(R) Functions"
        Public Declare Sub GetSystemInfo Lib "kernel32" (ByRef lpSystemInfo As SystemInfo)
        Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As IntPtr) As Boolean
        Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAcess As UInt32, ByVal bInheritHandle As Boolean, ByVal dwProcessId As Int32) As IntPtr
        Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer() As Byte, ByVal iSize As Int32, ByRef lpNumberOfBytesRead As Integer) As Boolean
        Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpbaseAddress As IntPtr, ByVal lpBuffer As Byte(), ByVal nSize As Int32, ByRef dwNumberOfBytesWritten As Int32) As Boolean
    
        Public Declare Function VirtualProtectEx Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As Int32, ByVal dwNewProtect As UInt32, ByRef dwOldProtect As UInt32) As Boolean
        Public Declare Function VirtualQueryEx Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByRef lpMemoryBasicInformation As MemoryBasicInformation, ByVal dwLength As Int32) As UInt32
    
    #End Region
    #Region "Structs"
        
        Public Structure SystemInfo
            Dim wProcessorArchitecture As Int16
            Dim wReserved As Int16
            Dim dwPageSize As Int32
            Dim lpMinimumApplicationAddress As IntPtr
            Dim lpMaximumApplicationAddress As IntPtr
            Dim dwActiveProcessorMask As Int32
            Dim dwNumberOfProcessors As Int32
            Dim dwProcessorType As Int32
            Dim dwAllocationGranularity As Int32
            Dim wProcessorLevel As Int16
            Dim wProcessorRevision As Int16
        End Structure
        Public Structure MemoryBasicInformation
            Dim BaseAddress As IntPtr
            Dim AllocationBase As IntPtr
            Dim AllocationProtect As UInt32
            Dim RegionSize As IntPtr
            Dim State As UInt32
            Dim Protect As UInt32
            Dim AllocationType As UInt32
        End Structure
    
    #End Region
    #Region "Enums"
    
        Public Enum MemoryAllocationProtection As UInt32
            PAGE_NOACCESS = &H1
            PAGE_READONLY = &H2
            PAGE_READWRITE = &H4
            PAGE_WRITECOPY = &H8
            PAGE_EXECUTE = &H10
            PAGE_EXECUTE_READ = &H20
            PAGE_EXECUTE_READWRITE = &H40
            PAGE_EXECUTE_WRITECOPY = &H80
            PAGE_GUARD = &H100
            PAGE_NOCACHE = &H200
            PAGE_WRITECOMBINE = &H400
        End Enum
        Public Enum MemoryAllocationType As UInt32
            MEM_IMAGE = &H1000000
            MEM_MAPPED = &H40000
            MEM_PRIVATE = &H20000
        End Enum
        Public Enum MemoryAllocationState As UInt32
            COMMIT = &H1000
            RESERVE = &H2000
            DECOMMIT = &H4000
            RELEASE = &H8000
            RESET = &H80000
            PHYSICAL = &H400000
            TOP_DOWN = &H100000
            WRITE_WATCH = &H200000
            LARGE_PAGES = &H20000000
        End Enum
        Public Enum ProcessAccess As UInt32
            ''Function descriptions taken from msdn.com
            ''' <summary>
            ''' Required to terminate a process using TerminateProcess.
            ''' </summary>
            PROCESS_TERMINATE = &H1
            ''' <summary>
            ''' Required to create a thread.
            ''' </summary>
            PROCESS_CREATE_THREAD = &H2
            ''' <summary>
            ''' Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
            ''' </summary>
            PROCESS_VM_OPERATION = &H8
            ''' <summary>
            ''' Required to read memory in a process using ReadProcessMemory.
            ''' </summary>
            PROCESS_VM_READ = &H10
            ''' <summary>
            ''' Required to write to memory in a process using WriteProcessMemory.
            ''' </summary>
            PROCESS_VM_WRITE = &H20
            ''' <summary>
            ''' Required to duplicate a handle using DuplicateHandle.
            ''' </summary>
            PROCESS_DUP_HANDLE = &H40
            ''' <summary>
            ''' Required to create a process.
            ''' </summary>
            PROCESS_CREATE_PROCESS = &H80
            ''' <summary>
            ''' 	Required to set memory limits using SetProcessWorkingSetSize.
            ''' </summary>
            PROCESS_SET_QUOTA = &H100
            ''' <summary>
            ''' 	Required to set certain information about a process, such as its priority class (see SetPriorityClass).
            ''' </summary>
            PROCESS_SET_INFORMATION = &H200
            ''' <summary>
            ''' Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).
            ''' </summary>
            PROCESS_QUERY_INFORMATION = &H400
            ''' <summary>
            ''' Required to suspend or resume a process.
            ''' </summary>
            PROCESS_SUSPEND_RESUME = &H800
            ''' <summary>
            ''' Required to retrieve certain information about a process (see GetExitCodeProcess, GetPriorityClass, IsProcessInJob, QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. Windows Server 2003 and Windows XP:  This access right is not supported.
            ''' </summary>
            PROCESS_QUERY_LIMITED_INFORMATION = &H1000
            ''' <summary>
            ''' Required to wait for the process to terminate using the wait functions.
            ''' </summary>
            PROCESS_SYNCHRONIZE = &H100000
        End Enum
    
    #End Region
    End Class
    MemoryManager Class
    Code:
    Public Class MemoryManager
        Implements IDisposable
    #Region "Private"
        Private _isAttached As Boolean = False ''required for most non-shared functions.
        Private _targetProcessId As Int32 = 0
        Private _targetProcessHandle As IntPtr = IntPtr.Zero ''Returned from winapi.OpenProcess()
        Private _mainModuleBase As IntPtr = IntPtr.Zero
        Private _systemInfo As WinApi.SystemInfo '' Useful information about cpu and ram.  Stored to avoid excessive lookup.
        Private _mbiSize As Int32 = 0 '' SizeOf(WinAPI.MEMORY_BASIC_INFORMATION) in bytes. Stored to avoid excessive lookup.
    
        Public Sub New()
            ''Store these values in the class so they don't have to be calculated/looked up each time they are used.
            WinApi.GetSystemInfo(_systemInfo) '' Useful info about cpu and ram.
            _mbiSize = System.Runtime.InteropServices.Marshal.SizeOf(New WinApi.MemoryBasicInformation) ''size of the struct in bytes
        End Sub
    #End Region
    
        Public Function AttachToProcess(ByVal processId As Int32) As Boolean
            If _isAttached Then
                Return False ''Already attached... True would be misleading because processId might not == _targetProcessId. 
            Else
                For Each proc As Process In Process.GetProcesses()
                    If proc.Id = processId Then
                        _targetProcessHandle = WinApi.OpenProcess(WinApi.ProcessAccess.PROCESS_VM_WRITE Or WinApi.ProcessAccess.PROCESS_VM_READ Or WinApi.ProcessAccess.PROCESS_VM_OPERATION Or WinApi.ProcessAccess.PROCESS_QUERY_INFORMATION, False, processId)
                        If _targetProcessHandle = IntPtr.Zero Then
                            ''OpenProcess() failed. Problem with processId or OpenAccess level.
                            Return False
                        Else
                            ''OpenProcess() success. Permissions Granted.
                            _isAttached = True
                            _targetProcessId = processId
                            _mainModuleBase = proc.MainModule.BaseAddress
                            Return True
                        End If
                    End If
                Next
                ''If falls through, processId not found
                MessageBox.Show("MemoryManager::AttachToProcess() Process Id not found: " & processId.ToString())
                Return False
            End If
        End Function
        Public Sub DetachFromProcess()
            If _isAttached Then
                If _targetProcessHandle <> IntPtr.Zero Then
                    WinApi.CloseHandle(_targetProcessHandle) '' we are done with handle. OS can free/re-use it.
                End If
                _isAttached = False
                _targetProcessId = 0
                _targetProcessHandle = IntPtr.Zero
            End If
        End Sub
        Public ReadOnly Property IsAttached() As Boolean
            Get
                Return _isAttached
            End Get
        End Property
        Public ReadOnly Property MainModuleBase As IntPtr
            Get
                Return _mainModuleBase
            End Get
        End Property
    #Region "Read"
        Public Function ReadByte(ByVal addr As IntPtr) As Byte
            Dim _byte(0) As Byte '' Awkward. ReadProcessMemory delcared to take a byte array instead of an IntPtr. Both are an address.
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _byte, 1, New Int32)
            Return _byte(0)
        End Function
        Public Function ReadInt16(ByVal addr As IntPtr) As Int16
            Dim _bytes(1) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 2, New Int32)
            Return BitConverter.ToInt16(_bytes, 0)
        End Function
        Public Function ReadInt32(ByVal addr As IntPtr) As Int32
            Dim _bytes(3) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 4, New Int32)
            Return BitConverter.ToInt32(_bytes, 0)
        End Function
        Public Function ReadInt64(ByVal addr As IntPtr) As Int64
            Dim _bytes(7) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 8, New Int32)
            Return BitConverter.ToInt64(_bytes, 0)
        End Function
        Public Function ReadUInt16(ByVal addr As IntPtr) As UInt16
            Dim _bytes(1) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 2, New Int32)
            Return BitConverter.ToUInt16(_bytes, 0)
        End Function
        Public Function ReadUInt32(ByVal addr As IntPtr) As UInt32
            Dim _bytes(3) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 4, New Int32)
            Return BitConverter.ToUInt32(_bytes, 0)
        End Function
        Public Function ReadUInt64(ByVal addr As IntPtr) As UInt64
            Dim _bytes(7) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 8, New Int32)
            Return BitConverter.ToUInt64(_bytes, 0)
        End Function
        Public Function ReadFloat(ByVal addr As IntPtr) As Single
            Dim _bytes(3) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 4, New Int32)
            Return BitConverter.ToSingle(_bytes, 0)
        End Function
        Public Function ReadDouble(ByVal addr As IntPtr) As Double
            Dim _bytes(7) As Byte
            If _isAttached Then WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 8, New Int32)
            Return BitConverter.ToDouble(_bytes, 0)
        End Function
        ''' <summary>
        ''' Reads an Ascii string from the target process's ram.
        ''' </summary>
        ''' <param name="addr">Beginning address of the string.</param>
        ''' <param name="maxLength">Max length of string if unknown. Must be > 0</param>
        Public Function ReadAsciiString(ByVal addr As IntPtr, ByVal maxLength As Int32) As String
            If Not (_isAttached AndAlso (maxLength > 0)) Then
                Return String.Empty '' fail. not attached to any process (or maxLength = 0).
    
            End If
            Dim _bytes(maxLength - 1) As Byte
            Dim _bytesRead As Int32 = 0
            If WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, maxLength, _bytesRead) Then
                Return System.Text.Encoding.ASCII.GetString(_bytes, 0, _bytesRead)
            Else
                Return String.Empty ''rpm failed
            End If
        End Function
        ''' <summary>
        ''' Read a Unicode string from the target process's ram.
        ''' </summary>
        ''' <param name="addr">Beginning address of the string.</param>
        ''' <param name="maxLength">Max length of string if unknown. Must be > 0</param>
        Public Function ReadUnicodeString(ByVal addr As IntPtr, ByVal maxLength As Int32) As String
            If Not (_isAttached AndAlso (maxLength > 0)) Then
                Return String.Empty '' fail. not attached to any process (or maxLength = 0).
            End If
            maxLength = maxLength * 2 '' 2  bytes per character. TODO: "Unicode" ?
            Dim _bytes(maxLength - 1) As Byte
            Dim _bytesRead As Int32 = 0
            If WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, _bytesRead) Then
                Return System.Text.Encoding.Unicode.GetString(_bytes, 0, _bytesRead)
            Else
                Return String.Empty '' rpm failed.
            End If
        End Function
        ''' <summary>
        ''' Reads an array of bytes from the target process's ram into a pre-declared buffer.
        ''' </summary>
        ''' <param name="byteBuff">Must be large enough, will not be re-sized!</param>
        ''' <param name="size">Number of bytes to read.</param>
        ''' <param name="actualBytesRead">Byref. Returns the actual number of bytes read.</param>
        Public Function ReadBytes(ByVal addr As IntPtr, ByRef byteBuff() As Byte, ByVal size As Int32, ByRef actualBytesRead As Int32) As Boolean
            Return WinApi.ReadProcessMemory(_targetProcessHandle, addr, byteBuff, size, actualBytesRead)
        End Function
    #End Region
    #Region "Write"
        Public Function WriteByte(ByVal addr As IntPtr, ByVal aByte As Byte) As Boolean
            Dim _bts() As Byte = {aByte} '' Awkward. Winapi function is declared as array() instead of as IntPtr
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, _bts, 1, New Int32)
        End Function
        Public Function WriteInt16(ByVal addr As IntPtr, ByVal data As Int16) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 2, New Int32)
        End Function
        Public Function WriteUInt16(ByVal addr As IntPtr, ByVal data As UInt16) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 2, New Int32)
        End Function
        Public Function WriteInt32(ByVal addr As IntPtr, ByVal data As Int32) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, New Int32)
        End Function
        Public Function WriteInt64(ByVal addr As IntPtr, ByVal data As Int64) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, New Int32)
        End Function
        Public Function WriteUInt64(ByVal addr As IntPtr, ByVal data As UInt64) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, New Int32)
        End Function
        Public Function WriteFloat(ByVal addr As IntPtr, ByVal data As Single) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, New Int32)
        End Function
        Public Function WriteDouble(ByVal addr As IntPtr, ByVal data As Double) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, New Int32)
        End Function
        Public Function WriteAsciiString(ByVal addr As IntPtr, ByVal str As String, ByRef actualBytesWritten As Int32) As Boolean
            Dim _bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(str)
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, actualBytesWritten)
        End Function
        Public Function WriteUnicodeString(ByVal addr As IntPtr, ByVal str As String, ByRef actualBytesWritten As Int32) As Boolean
            Dim _bytes() As Byte = System.Text.Encoding.Unicode.GetBytes(str)
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, actualBytesWritten)
        End Function
        Public Function WriteBytes(ByVal addr As IntPtr, ByVal bytes() As Byte, ByRef actualBytesWritten As Int32) As Boolean
            Return WinApi.WriteProcessMemory(_targetProcessHandle, addr, bytes, bytes.Length, actualBytesWritten)
        End Function
    #End Region
    #Region "Hack"
        Public Function GetMemRegions() As WinApi.MemoryBasicInformation()
            Dim _rtnBlocks As New List(Of WinApi.MemoryBasicInformation)
            Dim _curBase As Int64 = _systemInfo.lpMinimumApplicationAddress.ToInt64
            Dim _curMbi As WinApi.MemoryBasicInformation
    
            Try
                Do
                    If WinApi.VirtualQueryEx(_targetProcessHandle, New IntPtr(_curBase), _curMbi, _mbiSize) = 0 Then
                        Exit Do
                    End If
                    If _curMbi.State = WinApi.MemoryAllocationState.COMMIT Then 'this page actively being used by the target process
                        _rtnBlocks.Add(_curMbi)
                    End If
                    _curBase += _curMbi.RegionSize.ToInt64
                Loop While _curBase < _systemInfo.lpMaximumApplicationAddress.ToInt64
            Catch ex As Exception
                MessageBox.Show("MemoryManager::GetMemRegions() Threw an Exception. Please give this message to tech support -->" & Environment.NewLine _
                              & "Current memory region info:" & Environment.NewLine _
                              & ".baseAddress: 0x" & _curMbi.BaseAddress.ToString("X") & Environment.NewLine _
                              & ".size: " & _curMbi.RegionSize.ToString() & " bytes" & Environment.NewLine _
                              & ".protect: " & _curMbi.Protect & Environment.NewLine _
                              & ".type: " & _curMbi.AllocationType & Environment.NewLine _
                              & "state: " & _curMbi.State & Environment.NewLine & Environment.NewLine _
                              & "System error message (also important): " & Environment.NewLine _
                              & ex.Message & Environment.NewLine & "Thank you. ")
            End Try
    
            Return _rtnBlocks.ToArray()
        End Function
        ''TODO: FindBytes(), FindPattern() and more.
    #End Region
    
    #Region "IDisposable Support"
        Private disposedValue As Boolean ' To detect redundant calls
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    DetachFromProcess()
                End If
            End If
            Me.disposedValue = True
        End Sub
        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
    #End Region
    
    End Class
    It's a few lines of code. Feel free to ask questions. A generic function would turn 100 lines of code into 15, but maybe this is more clear for people who are new/haven't used generics. Comments appreciated.
    Last edited by abuckau907; 01-05-2014 at 04:30 PM. Reason: formatting cleanup
    'Some things that can be counted, don't matter. And some things that matter, can't be counted' - A.E.
    --
     

    My posts have some inaccuracies/are wrong/wrong keyword(s) used.
    They're (maybe) pretty close, and I hope they helped you, not created confusion. Take with grain of salt.

    -if you give rep, please leave a comment, else it means less.

Similar Threads

  1. [Outdated] How to use and best settings for 'MW3 .NET External ESP v2.4 [1.7.413]' by master131
    By Plyable in forum Call of Duty Modern Warfare 3 Tutorials
    Replies: 21
    Last Post: 07-18-2012, 08:27 PM
  2. [Help] PTC for vb.net BASICS ??
    By user44 in forum CrossFire Hack Coding / Programming / Source Code
    Replies: 8
    Last Post: 11-24-2010, 02:10 PM
  3. pb Kick corrupt file/memory (81353) for cod4 V1.7 with hacks.
    By benna696 in forum Call of Duty 4 - Modern Warfare (MW) Hacks
    Replies: 4
    Last Post: 05-12-2009, 01:09 PM
  4. I need DirectX10 SDK for VB.net
    By radnomguywfq3 in forum Suggestions, Requests & General Help
    Replies: 0
    Last Post: 11-11-2007, 10:12 PM
  5. Basic MPGH trainer (Up for 30 Minutes)
    By scooby107 in forum WarRock - International Hacks
    Replies: 17
    Last Post: 05-01-2007, 12:17 AM

Tags for this Thread