vb.net ReadProcessMemory part2

Posts 112 of 12 · Page 1 of 1
vb.net ReadProcessMemory part2
(same thing as part 1: re-posting from another forum I go to, incase anyone needs it. Some info may be wrong/incorrect, I'm not an expert)

The goal
To be able to scan all the memory being used by a process. Eventually being able to read all of the data and comparing it to some value. That is, to be able to find the specific location of a known value in a process's memory! ie. Scan(), and eventually FindPattern()

Basic Assumptions
You read part 1.
Probably not 64 bit compatible

If you remember from the last tutorial, each address in a process's ram has access rights associated with it. But that's not quite right. Actually the ram
(0-0xFFFFFFFF) is divided up into many chunks of many different sizes. Each chunk has specific access rights, and all addresses in that chunk have the same rights.
For example

10000 - 20000 READ_ONLY 0x10000, 0x10001, 0x1**** are all READ_ONLY
20000 - 30000 READ_ONLY
30000 - 60000 EXECUTE_READ are all EXECUTE_READWRITE (ie.can't call WriteProcessMemory on these addr)
60000 - 80000 READ_ONLY (ie.can't call WriteProcessMemory on these addr)
80000 - 10000 EXECUTE_READWRITE
10000 - FFFFF READ_WRITE are all READ_WRITE

That is totally made up. But you can see there are chunks (start address to end address) which each have access rights.Also note that each chunk, or 'region', has more properties than just Protection. Windows has a nice structure for us called MEMORY_BASIC_INFORMATION.
Basically it represents a chunk/region and has useful properties like Size. So how do we fill this nice structure with info? Another API of course, coming soon.

The MEMORY_BASIC_INFORMATION structure
Code:
 Private Structure MEMORY_BASIC_INFORMATION
        Dim BaseAddress As IntPtr          Pretty obvious. The lowest address of the page
        Dim AllocationBase As IntPtr
        Dim AllocationProtect As UInt32   Same as protect. When the region was first created 
        Dim RegionSize As IntPtr
        Dim State As UInt32                    COMMIT is the only one we care about
        Dim Protect As UInt32                  Access rights. EXECUTE_READWRITE, READONLY etc.
        Dim zType As UInt32                    IMAGE, MAPPED, PRIVATE.
 End Structure
And now to use our new struture. But how do we fill it with useful data? That api. VirtualQueryEx().
Code:
Private Declare Function VirtualQueryEx Lib "kernel32.dll" (ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByRef lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As UInt32) As Int32
hProcess Valid process handle from OpenProcess(). In my code, _targetProcessHandle
lpAddress The address we want info on. (it automatically figures out
which region that address is in,and returns the rights for that region, via lpBuffer)
lpBuffer An object of our MEMORY_BASIC_MEMORY structure. Passed BYREF.
dwLength The size of our MEMORY_BASIC_MEMORY structure in bytes

dwLength is slightly tricky. We could count all the variables in the structure, and because we know what type they are, and how big each type is in bytes, it's easy to figure out the overall size of the structure. There is also a .Net function to do this for us. In the Marshal class.
Code:
     Dim _mbi As MEMORY_BASIC_INFORMATION
     Dim _mbiSize as Int32 = System.Runtime.InteropServices.Marshal.SizeOf(_mbi)
          'or Marshal.SizeOf(New MEMORY_BASIC_INFO) and u don't need to have _mbi declared.
     
     'which we will use as
     
     VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize) 'Now _mbi's properties are filled with data.
     MsgBox("Region BaseAddress: 0x" & _mbi.BaseAddress.ToString("X") & ", size: " & _mbi.RegionSize.ToString("X"))
We will use Marshal.SizeOf(mbi) several times. This size shouldn't change so we can calculate then store it to avoid unnecessary function calls.
It's not _mbi = VirtualQuery(etc) because _mbi (lpBuffer) is passed ByRef. I hope you understand ByRef.

Ok, great. Now we can know the access rights of any address (and therefore it's region). Let's take this a step further and find out the access rights for every region. This involves looping over the entire memory range and figuring out where each region is, but how do we do that? Actually it's pretty simple. The trick is, when you add Region.Base + Region.Size you get the next Region's .Base. Seems obvious. It wasn't 2 seconds ago Here is the code to do just that.
Code:
Public Sub xxx
Dim _addr As IntPtr = IntPtr.Zero
  Do
      VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
       ''increment _addr to next region
       _addr = _mbi.BaseAddress + _mbi.RegionSize
  Loop While _addr.ToInt32 < 0xFFFFFFFF
End Sub
Admittedly, it doesn't actually do anything. Here is a loop that does *something*.
Code:
Public Sub yyy
'Don't actually run this loop. LOTS of message boxes.
Dim _addr As IntPtr = IntPtr.Zero
      Do
          VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
          MsgBox("Region  BaseAddress: " & _mbi.BaseAddress & " , size: " & _mbi.RegionSize)
           ''increment _addr to next region
          _addr = _mbi.BaseAddress + _mbi.RegionSize
      Loop While _addr.ToInt32 < 0xFFFFFFFF
End Sub
   

	note. Instead of using 0 and 0xFFFFFFFF for our start and stop addresses, I 
              recomend using SystemInfo.lpMinAddress and .lpMaxAddress.
              Just like MEMORY_BASIC_INFO and VirtualQueryEx, we create a structure
              called SYTEM_INFO and fill it with the api GetSystemInfo(), that has 
              useful properties like # of processors. See below.
Some notes
If mbi.State isn't COMMITTED, the target app ISN'T using it. You probably don't care about reading it.
mbi.Type IMAGE, SYSTEM, MAPPED. I don't know. Depending on what you need you may ignore,or focus, on some types.
Generally you can read all 3 without problems? Specific cases of not being able to??

Here is a loop that will "Analyze" every region of a process's ram.
Code:
Public Sub AnalyzeRam
Dim _addr As IntPtr = IntPtr.Zero 
Dim _mbi as MEMORY_BASIC_INFORMATION
Dim _mbiSize As Int32 = System.Runtime.InteropServices.Marshal.SizeOf(_mbi)
Dim _sysInfo As SYSTEM_INFORMATION
Dim _outputString as String = ""
        GetSystemInfo(_sysInfo)
	_addr = _sysInfo.lpMinimumApplicationAddress 
 Do
  VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
  If _mbi.State = MemoryAllocationState.Commit Then
   'This region actively being used by process
   _outputString += "Base: 0x" & _mbi.BaseAddress.ToString("X") & Environment.NewLine
   _outputString += "Size: " & _mbi.BaseAddress.ToString("X") & Environment.NewLine 'Also in hex!
   If _mbi.zType = MemoryAllocationType.MEM_PRIVATE Then
   _outputString += "[private]" & Environment.NewLine
   ElseIf _mbi.zType = MemoryAllocationType.MEM_IMAGE
   _outputString += "[image]" & Environment.NewLine
   Else
   _outputString += "[mapped]" & Environment.NewLine
   End If
   If _mbi.Protect And MemoryAllocationType.PAGE_GUARD Then
	'guard-ed. Reading will result in exception by OS.
   _outputString += "---GUARDED---"
   End If
  End If   
  'MessageBox.Show(_outputString)
  _addr = _mbi.BaseAddress + _mbi.RegionSize ''point _addr to next region
  Loop While _addr.ToInt32 < _sysInfo.lpMaximumApplicationAddress
End Sub
note. MBI.Type has been renamed to mbi.zType because of keyword name collision.
I assume you added this function to the MemoryManager class from part 1,
and that you've already called OpenProcess() successfully.

You also need these...
Code:
Private Declare Sub GetSystemInfo Lib "kernel32.dll" (ByRef lpSystemInfo As SYSTEM_INFO)
Code:
Private Structure SYSTEM_INFO
        Dim wrocessorArchitecture As Int16
        Dim wReserved As Int16
        Dim dwPageSize As Int32			 'Useful
        Dim lpMinimumApplicationAddress As Int32 'Useful
        Dim lpMaximumApplicationAddress As Int32 'Useful
        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
Code:
Private Enum MemoryAllocationProtectionType 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
        PAGE_CANREAD = PAGE_READONLY Or PAGE_READWRITE Or PAGE_EXECUTE_READ Or PAGE_EXECUTE_READWRITE
        PAGE_CANEXECUTE = PAGE_EXECUTE Or PAGE_EXECUTE_READ Or PAGE_EXECUTE_READWRITE 'Or PAGE_WRITECOPY?
        PAGE_CANWRITE = PAGE_READWRITE Or PAGE_EXECUTE_READWRITE OR PAGE_WRITECOMBINE
    End Enum
    Private Enum MemoryAllocationType As UInt32
        MEM_IMAGE = &H1000000
        MEM_MAPPED = &H40000
        MEM_PRIVATE = &H20000
    End Enum
    Private Enum MemoryAllocationState As UInt32
        Commit = &H1000
        Reserve = &H2000
        Decommit = &H4000
        Release = &H8000
        Reset = &H80000
        Physical = &H400000
        TopDown = &H100000
        WriteWatch = &H200000
        LargePages = &H20000000
    End Enum
Actually reading out all of the data (or as much as possible)
Now that we have a framework which well let us loop over each memory region, we need to actually read the data from the regions. If you remember, ReadProcessMemory() takes a Size parameter. Reading from 0-0xffffffff only Int32 or Int64 at a time would take LOTS and lots of calles to ReadProcessMemory() and that can't be efficient. If we increase the read size, then we can call it a lot less times and improve performance. How big can you make ReadProcessMemory() go? Well, I'm not sure(Look into it), but the SYSTEM_INFO structure has a property called PageSize. On my 32 bit Windows Xp with only 2g of ram, this is 4096. So apparently ReadProcessMemory() can read upto/more than 4096 bytes at a time. This kind of seems like a lot! But really it isn't. I assume this is most efficient?
My strategy is this
Code:
if mbi.RegionSize <= pageSize then
bytes = ReadProcessMemory(entire_region)
else
bytes = SecondFunctionToGetLargerPages()
end if
I'm not going to fully explain the code that copies the regions. Now that we can use ReadProcessMemory and have MemoryManager.GetBytes(), it's
just a matter of creating the correct byte arrays and how to pass them back and forth. For now we can only read regions that are marked readable (EXECUTE_READ, READWRITE, etc). Obviously. There is actually another API to change the permissions, we'll cover that later. Notice the If _mbi.Protect AND MemoryAllocation.PAGE_CANREAD? The .Protect property is actually a bit mask, so it can store several values simultaneously. I use bitmasking to check if certain values are set: readable, writable, executable.
I'm not going to explain it too much further, you have what you need.
Code:
Private Sub AnalyzeAndReadAll
     Dim _mbi As MEMORY_BASIC_INFORMATION, _sysInfo As SYSTEM_INFO
        Dim _mbiSize As Int32 = System.Runtime.InteropServices.Marshal.SizeOf(_mbi)
        GetSystemInfo(_sysInfo)
        Dim _addr As IntPtr = IntPtr.Zero
        Dim _readBuff(_sysInfo.dwPageSize - 1) As Byte 'read small pages
        Dim _bigBuff(0) As Byte 'read big pages
        Dim _actualBytesRead As Int32 = 0 'actual length of bytes copied during ReadProcessMemory()

Do
       VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
       If _mbi.State = MemoryAllocationState.Commit Then
           'this region of ram actively being used by process (commited at least..)
           If (_mbi.Protect And MemoryAllocationProtectionType.PAGE_CANREAD) And Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_GUARD)) Then 'bitmask (checks for any readable type)
		''READable and not GUARDed
                ''Read the data.
                If _mbi.RegionSize.ToInt32 <= _sysInfo.dwPageSize Then
                    'small page. Read entire page into buffer.
                    If ReadProcessMemory(_targetProcessHandle, _mbi.BaseAddress, _readBuff, _mbi.RegionSize, _actualBytesRead) Then
                        If _actualBytesRead <> _mbi.RegionSize  Then
                            'not able to read all data, handle gracefully. do nothing :)
                            'MsgBox("ScanForBytes() RPM->ActualBytesRead too low!" & _addr.ToString("X"))
                        Else
                            'do something with the data
                            'ie. compare to another byte arrar for equality ;)
                        End If

                    Else
                        'MsgBox("ScanForBytes::RPM FAIL 0x" & _mbi.BaseAddress.ToString("X"))
                    End If
                Else  'large page. Read page in chunks
                    _bigBuff = ReadLargeRamChunk(_addr, IntPtr.Add(_addr, _mbi.RegionSize.ToInt32))
                     'do something with the data
                     'ie. compare to another byte arrar for equality ;)
                End If ''//page size		
	   End If 
	_addr = _mbi.BaseAddress + _mbi.RegionSize ''increment _addr to next region
        Loop While _addr.ToInt32 < _systemInfo.lpMaximumApplicationAddress
End Sub

 Private Function ReadLargeRamRegion(ByVal aStart As IntPtr, ByVal aStop As IntPtr) As Byte()
     Dim _rtnBuffSize As Int32 = aStop.ToInt32 - aStart.ToInt32 'theoretical max size: may be smaller due to Read failures
     Dim _sizeRemaining As Int32 = _rtnBuffSize 
     Dim _byteBuff(_rtnBuffSize - 1) As Byte
     Dim _byteBuffCurrIndex As Int32 = 0 'actual size of data to be returned
     Dim _curAddr As IntPtr = aStart
     Dim _readBuff(_systemInfo.dwPageSize -1) As Byte
     Dim _actualBytesRead As Int32 = 0 '' Actual count of bytes read by ReadProcessMemory()
     'start reading
     Do

         If _sizeRemaining >= _systemInfo.dwPageSize Then
             If ReadProcessMemory(_targetProcessHandle, _curAddr, _readBuff, _systemInfo.dwPageSize, _actualBytesRead) Then
                 If _actualBytesRead <> _systemInfo.dwPageSize Then
                     'didn't read all data?! Don't append _readBuff to byteBuff. or do..
                     'MsgBox("ReadLargeRamChunk() RPM->ActualBytesRead too low! 0x" & _curAddr.ToString("X"))
                 Else
                     Array.Copy(_readBuff, 0, _byteBuff, _byteBuffCurrIndex, _actualBytesRead)
                     _byteBuffCurrIndex += _systemInfo.dwPageSize
                 End If
             Else
                 'MsgBox("ReadLargeRamChunk() RPM->FAIL! 0x" & _curAddr.ToString("X"))
             End If
             _curAddr += _systemInfo.dwPageSize
             _sizeRemaining -= _systemInfo.dwPageSize
             If _sizeRemaining = 0 Then Exit Do
         Else
             'almost at end of mem scan. 1 small piece left
              If ReadProcessMemory(_targetProcessHandle, _curAddr, _readBuff, _sizeRemaining, _actualBytesRead) Then
                 If (_actualBytesRead <> _sizeRemaining)  Then
                     'not able to read entire area
                     'MsgBox("ReadLargeRamChunk() RPM->ActualBytesRead too low! (final chunk) 0x" & _curAddr.ToString("X"))
                 Else
                     Array.Copy(_readBuff, 0, _byteBuff, _byteBuffCurrIndex, _actualBytesRead)
                     'success
                     Exit Do
                 End If

             Else
                 'MsgBox("ReadLargeRamChunk() RPM->FAIL! (final chunk) 0x" & _curAddr.ToString("X"))
             End If
         End If
     Loop
     If _byteBuffCurrIndex < _rtnBuffSize Then
       'not all data read. _byteBuff is too large. chop off extra, unused byte.
     Redim Preserve _byteBuff(_byteBuffCurrIndex + 1) 'efficiency? only occurs if read fails occur.
     Return _byteBuff
 End Function
You're now reading all the readable data from the process! Big stuff.
Notice the PAGE_CANREAD. You don't actually have to make that check, but depending on the access type of the memory region, rpm may fail. If you check CANREAD, it should* succeed.


Also, the second choice..you can call OpenProcess() every time! you want to read, or you can 'attach' once, and keep track of the handle. Obviously I chose to keep track of it, so none of my Read() functions call OpenProcess(), they used a local variable _targetProcessHandle.



The goal
To be able to scan all the memory being used by a process. Even those not marked as readable

It's actually really easy. There is yet another windows api that will change the access rights of a memory region. VirtualProtectEx().
VirtualProtectEx is just like VirtualQueryEx except that instead of reading the access rights, we're settings them! Simple, right?

Code:
    Private Declare Function VirtualProtectEx Lib "kernel32.dll" (ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As IntPtr, ByVal flNewProtect As UInt32, ByRef lpfoldProtect As UInt32) As Boolean
hProcess Same as all the others
lpAddress
dwSize
fwNewProtect New protection rights
fwOldProtect Old protection rights (byref. for restoring when finished)

Code:
'assuming _mbi has been set
Dim _oldProtects as Uint32 = 0 'BYREF. Save so we can restore rights later.
VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize,MemoryAllocationProtectionType.EXECUTE_READWRITE, _oldProtect)
One thing to note: you need to be careful of the new Protect value. If the region was marked as EXECUTEable, you better make the new protection be
executable or the program will crash when it tries to run it's code there. Same situation with WRITEable. If the region was writeable, and you change
it to read_only, the program will crash when it tries to write to it. Seems pretty obvious, but I didn't think about it my first time.

That's really all there is to it. Now inside our scan, if the memory region isn't readable, we can make it readable. One last word of advice. Remember how MBI.Protect uses bitmasks to store several values. This means it can be PAGE_READ and PAGE_GUARD at the same time. I think PAGE_GUARD is like an anti-cheat mechanism. It will flag the OS if there is an attempt to Read() if GUARD is set to true. (not necessarily anti-cheat, but can be used this way)


---------- Post added at 02:49 AM ---------- Previous post was at 02:11 AM ----------

edit: I posted that tutorial a while ago, there were quite a few (obvious) bugs, and I've since change some code. Hopefully you can spot the differences / bugs / improvements.
Scan
Code:
#Region "Scan"
    ''' <summary>
    ''' Scans a process's entire memory range for the specified hex string.
    ''' <param name="hexString">Standard search/mask technique. (** denotes a masked byte.)</param>
    ''' <param name="returnOnFirstOccurance">End scan early if value found?</param>
    ''' </summary>
    Public Function FindPattern(ByVal hexString As String, Optional ByVal returnOnFirstOccurance As Boolean = True) As IntPtr()
        ''format example: 64 8b 15 ** ** ** ** 8b 34 ** 8b 0d ** ** ** ** 89 81
        Dim _hexStringChunks() As String = hexString.Split(" ")
        Dim _hexStringAsBytes(_hexStringChunks.Length - 1) As Byte
        Dim _mask(_hexStringChunks.Length - 1) As Byte

        For xx As Int32 = 0 To _hexStringChunks.Length - 1
            If _hexStringChunks(xx) = "**" Then
                _hexStringAsBytes(xx) = &H0
                _mask(xx) = &H0 'unimportant
            Else
                _hexStringAsBytes(xx) = Byte.Parse(_hexStringChunks(xx), Globalization.NumberStyles.HexNumber)
                _mask(xx) = &H1 'important
            End If
        Next
        Dim _results() As IntPtr = ScanForByteMask(_hexStringAsBytes, _mask, returnOnFirstOccurance)
        Return _results
    End Function
    ''' <summary>
    ''' Scan a process's entire memory range for the specified array of bytes. Function always return an array(). (may specify to return when first occurance is found. If returnOnFirstOccurance=true, array.length will be 1)
    ''' </summary>
    Private Function ScanForBytes(ByVal byteBuff() As Byte, Optional ByVal returnOnFirstOccurance As Boolean = False) As IntPtr()
        If IsAttachedToProcess() = False Then
            Return New IntPtr() {IntPtr.Zero} 'user fail
        End If
        Dim _rtns As New List(Of IntPtr) 'locations (memory addresses) where the buff() was found at
        If Not returnOnFirstOccurance Then _rtns.Capacity = 1000 'could be larger. depends how many results you expect..
        Dim _mbi As MEMORY_BASIC_INFORMATION, _sysInfo As SYSTEM_INFO
        Dim _mbiSize As Int32 = Marshal.SizeOf(_mbi) ' size of mbi struct, in bytes.
        GetSystemInfo(_sysInfo)
        Dim _addr As IntPtr = IntPtr.Zero 'counter/loop control.
        Dim _readBuff(_sysInfo.dwPageSize - 1) As Byte 'small buffer to read small mem regions
        Dim _bigBuff(0) As Byte 'large buffer to read large mem regions
        Dim _actualBytesRead As Int32 = 0 ''actual length of bytes copied during ReadProcessMemory()
        Dim _origPageProtection As UInt32 = 0 ''To preserve/restore original protection values
        Dim _hasAlreadyFoundOnce As Boolean = False 'possibly end the scan early when first result found
        Dim _oldProtects As String = "" 'displayed after errorrs. as string of '0' padded bits.

        Do
            VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
            _oldProtects = ConvertMBIProtectToBinaryString(_mbi.Protect)
            If _mbi.State = MemoryAllocationState.Commit Then
                If _mbi.Protect And MemoryAllocationProtectionType.PAGE_CANREAD Then 'bitmask check for any readable type
                    ''EASY READ
                    If _mbi.Protect And MemoryAllocationProtectionType.PAGE_GUARD Then
                        DoOutput("avoided the guard at 0x" & _addr.ToString("X"))
                        GoTo badLabelSkipThisMemRegion 'BUT ITS GUARDED
                    End If
                Else
                    ''CANT READ YET
                    If _mbi.Protect And MemoryAllocationProtectionType.PAGE_COPYFORWARD Then
                        ''CANT READ AT ALL (ignore non-readable copyforward unless you really* know what you're doing. usually fails anyway)
                        DoOutput("avoided OS managed file (dll?) at 0x" & _addr.ToString("X"))
                        GoTo badLabelSkipThisMemRegion
                    Else
                        ''Enable Read
                        If _mbi.Protect And MemoryAllocationProtectionType.PAGE_CANEXECUTE Then
                            'it should remain executable! 
                            If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origPageProtection) Then
                                'DoOutput("execPatching OK 0x" & _addr.ToString("X"))
                            Else
                                DoOutput("SFB() execPatching FAIL 0x" & _addr.ToString("X"))
                                DoOutput("protect: " & _oldProtects)
                                Threading.Thread.Sleep(2500)
                                GoTo badLabelSkipThisMemRegion
                            End If
                        Else
                            If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_READWRITE, _origPageProtection) Then
                                'DoOutput("readPatching OK 0x" & _mbi.BaseAddress.ToString("X"))
                            Else
                                DoOutput("SFB() readPatching FAIL 0x" & _mbi.BaseAddress.ToString("X"))
                                DoOutput("protect: " & _oldProtects)
                                Threading.Thread.Sleep(2500)
                                GoTo badLabelSkipThisMemRegion
                            End If
                        End If
                    End If
                End If
                ''READ THE DATA
                If _mbi.RegionSize.ToInt32 <= _sysInfo.dwPageSize Then '4096 bytes. 4kb. see windows memory management for info.
                    ''READ THE DATA. small region
                    If ReadProcessMemory(_targetProcessHandle, _mbi.BaseAddress, _readBuff, _mbi.RegionSize, _actualBytesRead) Then
                        If (_actualBytesRead <> _mbi.RegionSize) Then
                            'not able to read all data, handle gracefully. do nothing :)
                            modPublic.DoOutput("SFB() RPM->ActualBytesRead too low! 0x" & _mbi.BaseAddress.ToString("X"))
                        Else
                            ''COMPARE VALUE                                      
                            For xx As Int32 = 0 To _mbi.RegionSize.ToInt32 - byteBuff.Length 'todo:  align4?
                                For yy As Int32 = 0 To byteBuff.Length - 1
                                    If byteBuff(yy) <> _readBuff(xx + yy) Then
                                        GoTo badLabelNoSuccess
                                    End If
                                Next
                                _rtns.Add(_addr.ToInt32 + xx)  'found it
                                If returnOnFirstOccurance Then
                                    _hasAlreadyFoundOnce = True
                                    Exit For
                                End If
badLabelNoSuccess:
                            Next
                        End If
                    Else
                        modPublic.DoOutput("SFB() RPM FAIL 0x" & _mbi.BaseAddress.ToString("X"))
                    End If
                Else
                    ' large region                                     
                    _bigBuff = ReadLargeRamPage(_addr, _addr.ToInt32 + _mbi.RegionSize.ToInt32)
                    For xx As Int32 = 0 To _bigBuff.Length - byteBuff.Length 'todo:  align4?
                        ''COMPARE VALUE 
                        For yy As Int32 = 0 To byteBuff.Length - 1
                            If byteBuff(yy) <> _bigBuff(xx + yy) Then
                                GoTo badLabelNoMoreSuccess
                            End If
                        Next
                        _rtns.Add(_addr.ToInt32 + xx) 'found it
                        If returnOnFirstOccurance Then
                            _hasAlreadyFoundOnce = True
                            Exit For
                        End If
badLabelNoMoreSuccess:
                    Next
                End If ''end region size
                '' RESTORE PROTECTION
                If _origPageProtection Then
                    VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origPageProtection, _origPageProtection)
                    _origPageProtection = 0
                End If
                If _hasAlreadyFoundOnce AndAlso returnOnFirstOccurance Then Exit Do
            End If ''//state=committed
badLabelSkipThisMemRegion:
            _addr = _mbi.BaseAddress.ToInt32 + _mbi.RegionSize.ToInt32 ''increment _addr to next region
        Loop While _addr.ToInt32 < _sysInfo.lpMaximumApplicationAddress

        If _rtns.Count = 0 Then _rtns.Add(IntPtr.Zero) 'pattern not found!
        Return _rtns.ToArray
    End Function
    Private Function ScanForByteMask(ByVal buff() As Byte, ByVal mask() As Byte, Optional ByVal returnOnFirstOccurance As Boolean = False) As IntPtr()
        If IsAttachedToProcess() = False Or mask.Length <> buff.Length Then
            Return New IntPtr() {IntPtr.Zero} 'user fail
        End If
        Dim _rtns As New List(Of IntPtr) 'locations (memory addresses) where the buff() was found at
        If Not returnOnFirstOccurance Then _rtns.Capacity = 1000 'could be larger. depends how many results you expect..
        Dim _mbi As MEMORY_BASIC_INFORMATION, _sysInfo As SYSTEM_INFO
        Dim _mbiSize As Int32 = Marshal.SizeOf(_mbi) ''size of memory_basic_region struct in bytes.
        GetSystemInfo(_sysInfo)
        Dim _addr As IntPtr = IntPtr.Zero 'counter/loop control.
        Dim _readBuff(_sysInfo.dwPageSize - 1) As Byte 'small buffer to read small mem regions
        Dim _bigBuff(0) As Byte 'large buffer to read large mem regions
        Dim _actualBytesRead As Int32 = 0 ''actual length of bytes copied during ReadProcessMemory()
        Dim _origPageProtection As UInt32 = 0 ''To preserve/restore original protection values
        Dim _hasAlreadyFoundOnce As Boolean = False
        Dim _oldProtects As String = "" 'displayed after errorrs. as string of bits.
        Do
            VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
            _oldProtects = ConvertMBIProtectToBinaryString(_mbi.Protect)
            If _mbi.State = MemoryAllocationState.Commit Then
                If _mbi.Protect And MemoryAllocationProtectionType.PAGE_CANREAD Then 'bitmask check for any readable type
                    ''EASY READ
                    If _mbi.Protect And MemoryAllocationProtectionType.PAGE_GUARD Then
                        'DoOutput("avoided the guard at 0x" & _addr.ToString("X"))
                        GoTo badLabelSkipThisMemRegion 'BUT ITS GUARDED
                    End If
                Else
                    ''CANT READ YET
                    If _mbi.Protect And MemoryAllocationProtectionType.PAGE_COPYFORWARD Then
                        ''CANT READ AT ALL (ignore non-readable copyforward unless you really* know what you're doing. usually fails anyway)
                        DoOutput("avoided OS managed file (dll?) at 0x" & _addr.ToString("X"))
                        GoTo badLabelSkipThisMemRegion
                    Else
                        ''Enable Read
                        If _mbi.Protect And MemoryAllocationProtectionType.PAGE_CANEXECUTE Then
                            'it should remain executable! 
                            If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origPageProtection) Then
                                'DoOutput("execPatching OK 0x" & _addr.ToString("X"))
                            Else
                                DoOutput("SFBM() execPatching FAIL 0x" & _addr.ToString("X"))
                                DoOutput("protect: " & _oldProtects)
                                Threading.Thread.Sleep(2500)
                                GoTo badLabelSkipThisMemRegion
                            End If
                        Else
                            If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_READWRITE, _origPageProtection) Then
                                'DoOutput("readPatching OK 0x" & _mbi.BaseAddress.ToString("X"))
                            Else
                                DoOutput("SFBM() readPatching FAIL 0x" & _mbi.BaseAddress.ToString("X"))
                                DoOutput("protect: " & _oldProtects)
                                Threading.Thread.Sleep(2500)
                                GoTo badLabelSkipThisMemRegion
                            End If
                        End If
                    End If
                End If
                ''READ THE DATA
                If _mbi.RegionSize.ToInt32 <= _sysInfo.dwPageSize Then '4096 bytes. 4kb. see windows memory management for info.
                    ''READ THE DATA. small region
                    If ReadProcessMemory(_targetProcessHandle, _mbi.BaseAddress, _readBuff, _mbi.RegionSize, _actualBytesRead) Then
                        If (_actualBytesRead <> _mbi.RegionSize) Then
                            'not able to read all data, handle gracefully. do nothing :)
                            modPublic.DoOutput("SFBM() RPM->ActualBytesRead too low! 0x" & _mbi.BaseAddress.ToString("X"))
                        Else
                            ''COMPARE VALUE                                      
                            For xx As Int32 = 0 To _mbi.RegionSize.ToInt32 - buff.Length 'todo:  align4?
                                For yy As Int32 = 0 To buff.Length - 1
                                    If mask(yy) <> 0 Then
                                        If buff(yy) <> _readBuff(xx + yy) Then
                                            GoTo badLabelNoSuccess
                                        End If
                                    End If
                                Next
                                _rtns.Add(_addr.ToInt32 + xx)  'found it
                                If returnOnFirstOccurance Then
                                    _hasAlreadyFoundOnce = True
                                    Exit For
                                End If
badLabelNoSuccess:
                            Next
                        End If
                    Else
                        modPublic.DoOutput("SFBM() RPM FAIL 0x" & _mbi.BaseAddress.ToString("X"))
                    End If
                Else
                    ' large region                                     
                    _bigBuff = ReadLargeRamPage(_addr, _addr.ToInt32 + _mbi.RegionSize.ToInt32)
                    For xx As Int32 = 0 To _bigBuff.Length - buff.Length 'todo:  align4?
                        ''COMPARE VALUE 
                        For yy As Int32 = 0 To buff.Length - 1
                            If mask(yy) <> 0 Then
                                If buff(yy) <> _bigBuff(xx + yy) Then
                                    GoTo badLabelNoMoreSuccess
                                End If
                            End If
                        Next
                        _rtns.Add(_addr.ToInt32 + xx) 'found it
                        If returnOnFirstOccurance Then
                            _hasAlreadyFoundOnce = True
                            Exit For
                        End If
badLabelNoMoreSuccess:
                    Next
                End If ''end region size
                '' RESTORE PROTECTION
                If _origPageProtection Then
                    VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origPageProtection, _origPageProtection)
                    _origPageProtection = 0
                End If
                If _hasAlreadyFoundOnce AndAlso returnOnFirstOccurance Then Exit Do
            End If ''//state=committed
badLabelSkipThisMemRegion:
            _addr = _mbi.BaseAddress.ToInt32 + _mbi.RegionSize.ToInt32 ''increment _addr to next region
        Loop While _addr.ToInt32 < _sysInfo.lpMaximumApplicationAddress

        If _rtns.Count = 0 Then _rtns.Add(IntPtr.Zero) 'pattern not found!
        Return _rtns.ToArray
    End Function
    ''' <summary>
    ''' Reads a region of ram (startAddress to stopAddress). CALLING code is responsible for checking memory_allocation_protection_type before calling this function.
    ''' </summary>
    ''' <param name="aStart">Beginning of scan range. (usually a memory_basic_information.BaseAddress, doesn't have to be).</param>
    ''' <param name="aStop">End of scan range. (usually memory_basic_information.BaseAddress + iSize, doesn't have to be) </param>
    ''' <returns></returns>
    ''' <remarks>Can span multiple regions, but caller should verity access rights first!</remarks>
    Private Function ReadLargeRamPage(ByVal aStart As IntPtr, ByVal aStop As IntPtr) As Byte()
        Dim _rtnBuffSize As Int32 = aStop.ToInt32 - aStart.ToInt32 'theoretical max size: may be smaller due to read failure
        Dim _returnByteBuff(_rtnBuffSize - 1) As Byte ' return results
        Dim _byteBuffCurrIndex As Int32 = 0 'counter
        Dim _readBuff(_systemInfo.dwPageSize - 1) As Byte 'temporary storage for ReadProcessMemory()
        Dim _actualBytesRead As Int32 = 0 '' actual length of bytes returned by ReadProcessMemory()
        Dim _curAddr As IntPtr = aStart
        Dim _sizeRemaining As Int32 = _rtnBuffSize '
        'start reading
        Do
            If _sizeRemaining >= _systemInfo.dwPageSize Then
                If ReadProcessMemory(_targetProcessHandle, _curAddr, _readBuff, _systemInfo.dwPageSize, _actualBytesRead) Then
                    If (_actualBytesRead <> _systemInfo.dwPageSize) Then
                        ''not able to read entire area
                        If _actualBytesRead > 0 Then 'append what little data we did read
                            Array.Copy(_readBuff, 0, _returnByteBuff, _byteBuffCurrIndex, _actualBytesRead)
                            _byteBuffCurrIndex += _actualBytesRead
                        End If
                        modPublic.DoOutput("ReadLargeRamChunk() RPM->ActualBytesRead too low! 0x" & _curAddr.ToString("X"))
                    Else
                        Array.Copy(_readBuff, 0, _returnByteBuff, _byteBuffCurrIndex, _systemInfo.dwPageSize)
                        _byteBuffCurrIndex += _systemInfo.dwPageSize
                    End If
                Else
                    modPublic.DoOutput("ReadLargeRamChunk() RPM->FAIL! 0x" & _curAddr.ToString("X"))
                End If
                _sizeRemaining -= _systemInfo.dwPageSize ' 
            Else
                'almost at end of mem scan. 1 small piece left
                If ReadProcessMemory(_targetProcessHandle, _curAddr, _readBuff, _sizeRemaining, _actualBytesRead) Then
                    If (_actualBytesRead <> _sizeRemaining) Then
                        'not able to read entire area
                        If _actualBytesRead > 0 Then 'append what little data we did read
                            Array.Copy(_readBuff, 0, _returnByteBuff, _byteBuffCurrIndex, _actualBytesRead)
                            _byteBuffCurrIndex += _actualBytesRead
                        End If
                        modPublic.DoOutput("ReadLargeRamChunk() RPM->ActualBytesRead too low! (final chunk) 0x" & _curAddr.ToString("X"))
                    Else
                        Array.Copy(_readBuff, 0, _returnByteBuff, _byteBuffCurrIndex, _sizeRemaining)
                        _byteBuffCurrIndex += _sizeRemaining
                    End If
                Else
                    modPublic.DoOutput("ReadLargeRamChunk() RPM->FAIL! (final chunk!) 0x" & _curAddr.ToString("X"))
                End If
                _sizeRemaining = 0
            End If
            If _sizeRemaining = 0 Then Exit Do
            _curAddr = _curAddr.ToInt32 + _systemInfo.dwPageSize
        Loop
        If _byteBuffCurrIndex < _rtnBuffSize Then ' ie. actual_read_length < expected_read_length
            '_returnBuff was declared too large. Shrink it.
            ReDim Preserve _returnByteBuff(_byteBuffCurrIndex - 1) ' only occurs on read failures
        End If
        Return _returnByteBuff
    End Function
    ''' <summary>
    ''' Will return a string of 0's and 1's representing a uint32 value.
    ''' </summary>
    ''' <param name="mbiProtect">Protect value of MEMORY_BASIC_INFORMATION.</param>
    ''' <returns>Return string will be left-padded with 0's so that the final length of the string is a multiple of 8</returns>
    Private Function ConvertMBIProtectToBinaryString(ByVal mbiProtect As UInt32) As String
        ''only used for user output. easier to read if they're all 8-padded
        Dim _rtnStr As String = Convert.ToString(mbiProtect, 2) 'binary string
        Dim _padNeeded As Int32 = _rtnStr.Length Mod 8 'add padding if needed
        If _padNeeded <> 0 Then
            _padNeeded = 8 - _padNeeded
            _rtnStr = New String("0", _padNeeded) & _rtnStr '' .net has a string function .Pad(). o well, already made the code.
        End If
        Return _rtnStr
    End Function
#End Region
struct/enums maybe have posted in part 1. sry. descriptions taken from msdn.com
Code:
#Region "Structs/Enum"
    Private Structure SYSTEM_INFO
        Dim wrocessorArchitecture As Int16
        Dim wReserved As Int16
        Dim dwPageSize As Int32
        Dim lpMinimumApplicationAddress As Int32
        Dim lpMaximumApplicationAddress As Int32
        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
    Private Structure MEMORY_BASIC_INFORMATION
        Dim BaseAddress As IntPtr
        Dim AllocationBase As IntPtr
        Dim AllocationProtect As UInt32
        Dim RegionSize As IntPtr
        Dim State As UInt32
        ''' <summary>
        ''' See the MemoryAllocationProtectionType enum. for values
        ''' </summary>
        ''' <remarks>no remarks anywhere.</remarks>
        Dim Protect As UInt32
        Dim zType As UInt32
    End Structure
    Public Enum MemoryAllocationProtectionType As UInt32
        ''' <summary>
        ''' Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation.
        ''' </summary>
        PAGE_NOACCESS = &H1             'ALWAYS LEAVE ALONE
        ''' <summary>
        ''' Enables read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation.
        ''' </summary>
        PAGE_READONLY = &H2             'HACKRW
        ''' <summary>
        ''' Enables read-only or read/write access to the committed region of pages.
        ''' </summary>
        PAGE_READWRITE = &H4            'HACKRW
        ''' <summary>
        ''' Enables read-only or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process. 
        ''' </summary>
        PAGE_WRITECOPY = &H8            'DONT  phux with writeoncopy
        ''' <summary>
        ''' Enables execute access to the committed region of pages. An attempt to read from or write to the committed region results in an access violation. -microsoft.com
        ''' </summary>
        PAGE_EXECUTE = &H10             'HACKRW
        ''' <summary>
        ''' Enables execute or read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation.
        ''' </summary>
        PAGE_EXECUTE_READ = &H20        'HACKRW 
        ''' <summary>
        ''' Enables execute, read-only, or read/write access to the committed region of pages.
        ''' </summary>
        PAGE_EXECUTE_READWRITE = &H40   'HACKRW
        ''' <summary>
        ''' Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process.
        ''' </summary>
        PAGE_EXECUTE_WRITECOPY = &H80   'DONT phux with writeoncopy
        ''' <summary>
        ''' Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time access alarm.
        ''' </summary>
        ''' 
        PAGE_GUARD = &H100              'HACKRW
        ''' <summary>
        ''' Sets all pages to be non-cachable. Applications should not use this attribute except when explicitly required for a device.
        ''' </summary>
        PAGE_NOCACHE = &H200
        ''' <summary>
        ''' Sets all pages to be write-combined.Applications should not use this attribute except when explicitly required for a device.
        ''' </summary>
        PAGE_WRITECOMBINE = &H400
        ''' <summary>
        ''' Allowed to call ReadProcessMemory() without needing VirtualProtectEx().
        ''' </summary>
        PAGE_CANREAD = PAGE_READONLY Or PAGE_READWRITE Or PAGE_WRITECOPY Or PAGE_EXECUTE_READ Or PAGE_EXECUTE_READWRITE Or PAGE_EXECUTE_WRITECOPY
        PAGE_CANEXECUTE = PAGE_EXECUTE Or PAGE_EXECUTE_READ Or PAGE_EXECUTE_READWRITE Or PAGE_EXECUTE_WRITECOPY
        PAGE_CANWRITE = PAGE_READWRITE Or PAGE_EXECUTE_READWRITE 'excludes 'copy on write' regions.
        ''' <summary>
        ''' Generally we should leave copy-forward memory alone, except maybe for reading. But only if it is originally marked as readable! Careful with VirtualProtectEx...it can/will fail, and/or cause misc. (memory related) bugs.
        ''' </summary>
        PAGE_COPYFORWARD = PAGE_WRITECOPY Or PAGE_EXECUTE_WRITECOPY Or PAGE_WRITECOMBINE
    End Enum
    Private Enum MemoryAllocationType As UInt32
        MEM_IMAGE = &H1000000
        MEM_MAPPED = &H40000
        MEM_PRIVATE = &H20000
    End Enum
    Private Enum MemoryAllocationState As UInt32
        Commit = &H1000
        Reserve = &H2000
        Decommit = &H4000
        Release = &H8000
        Reset = &H80000
        Physical = &H400000
        TopDown = &H100000
        WriteWatch = &H200000
        LargePages = &H20000000
    End Enum
    Private Enum ProcessAccessProtectionType As UInt32
        ''' <summary>
        ''' Required to terminate a process using TerminateProcess.
        ''' </summary>
        PROCESS_TERMINATE = &H1
        ''' <summary>
        ''' Required to create a thread.
        ''' </summary>
        ''' <remarks></remarks>
        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 read memory in a process using ReadProcessMemory.
        ''' </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.
        ''' </summary>
        PROCESS_QUERY_LIMITED_INFORMATION = &H1000
        ''' <summary>
        ''' Required to wait for the process to terminate using the wait functions.
        ''' </summary>
        PROCESS_SYNCHRONIZE = &H100000
        ''' <summary>
        ''' Enables read/write to most of the process. Exclueds copyforward, non-readable regions. 
        ''' </summary>
        ''' <remarks></remarks>
        PROCESS_ALLACCESS = &H1F0FFF
    End Enum
and of course the
write functions
Code:
    Public Function WriteByte(ByVal addr As IntPtr, ByVal aByte As Byte) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, New Byte() {aByte}, 1, vbNull) 'awk array decl :/
    End Function
    Public Function WriteInt16(ByVal addr As IntPtr, ByVal data As Int16) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 2, vbNull)
    End Function
    Public Function WriteInt32(ByVal addr As IntPtr, ByVal data As Int32) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, vbNull)
    End Function
    Public Function WriteInt64(ByVal addr As IntPtr, ByVal data As Int64) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, vbNull)
    End Function
    Public Function WriteUInt16(ByVal addr As IntPtr, ByVal data As UInt16) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 2, vbNull)
    End Function
    Public Function WriteUInt32(ByVal addr As IntPtr, ByVal data As UInt32) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, vbNull)
    End Function
    Public Function WriteUInt64(ByVal addr As IntPtr, ByVal data As UInt64) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, vbNull)
    End Function
    Public Function WriteFloat(ByVal addr As IntPtr, ByVal data As Single) As Boolean
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, vbNull)
    End Function
    Public Function WriteDouble(ByVal addr As IntPtr, ByVal data As Double) As String
        Return WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, vbNull)
    End Function
    Public Function WriteIntPtr(ByVal addr As IntPtr, ByVal ptr As IntPtr) As Boolean
        Dim _bytes(IntPtr.Size - 1) As Byte

        If IntPtr.Size = 4 Then
            _bytes = BitConverter.GetBytes(Convert.ToUInt32(ptr))
            Return WriteProcessMemory(_targetProcessHandle, addr, _bytes, 4, vbNull)
        Else
            _bytes = BitConverter.GetBytes(Convert.ToUInt64(ptr))
            Return WriteProcessMemory(_targetProcessHandle, addr, _bytes, 8, vbNull)
        End If
    End Function
    Public Function WriteUnicodeString(ByVal addr As IntPtr, ByVal str As String) As Boolean
        Dim _bytes() As Byte = System.Text.Encoding.Unicode.GetBytes(str)
        Return WriteProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, vbNull)
    End Function
    Public Function WriteAsciiString(ByVal addr As IntPtr, ByVal str As String) As Boolean
        Dim _bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(str)
        Return WriteProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, vbNull)
    End Function
    Public Function WriteBytes(ByVal addr As IntPtr, ByVal bytes() As Byte) As Boolean
        Dim _writeLength As Int32 = 0
        If WriteProcessMemory(_targetProcessHandle, addr, bytes, bytes.Length, _writeLength) Then
            If _writeLength = bytes.Length Then
                Return True
            Else
                DoOutput("MemoryManager::WriteBytes() writeLength < buff.size")
                Return False
            End If
        Else
            Return False 'wpm failed!
        End If
    End Function
DoOutput() is just a public Sub. Just adds the (msg) to a multi-line text box. Debugging output basically, which I highly recomend for stuff like this.
Code:
    Public Sub DoOutput(ByVal msg As String, Optional ByVal printTime As Boolean = True)
        If frmMain.txtOutput.TextLength > 5000 Then '' change 50k to something lower to consume less ram. 
            Dim _bracLoc As Int32 = frmMain.txtOutput.Text.IndexOf("[", 2500)
            'remove (about) the first 1/2 of the text, keeping the most recent messages.
            frmMain.txtOutput.Text = "******************" & Environment.NewLine & Mid(frmMain.txtOutput.Text, _bracLoc) ''append old msgs
        End If
        If printTime Then
            frmMain.txtOutput.AppendText("[" & Date.Now.ToString("h-m-s") & "]" & msg & Environment.NewLine)
        Else
            frmMain.txtOutput.AppendText(msg & Environment.NewLine)
        End If

        Application.DoEvents()
    End Sub
'set displayTime = false for exact formatting (when seconds goes from 60 to 0, a jagged effect happens)
'Don't credit me in your apps, I don't want to be associated with your 'hacks'. Including my name in the source
'would be nice, but, as I found 1/2 of this info on google and made the other half up..all to the good.
'I did work hard on ScanForBytes and FindPattern tho.

If you have any (relevant) questions/comments, feel free.
@abuckau907
can you please write down an example
how to use the scan method to scan full memory (of game) by value and list all addresses in a list box
thanks
Is there any one can answer my question ???
No. So stop asking. The code is right up there...

Private Function ScanForBytes(ByVal byteBuff() As Byte, Optional ByVal returnOnFirstOccurance As Boolean = False) As IntPtr()

[whybother]
Code:
Dim _rtnAddrs() As IntPtr

Dim _myData() As Byte = {0x11, 0x22, 0x33, 0x44 } '' BitConvert class for converting primitive types to a byte array 

_rtnAddrs = ScanForBytes(_myData,false) '' false = find every occurance

''That's it... to view the results maybe..

For Each fcktrd as IntPtr In _rtnAddrs
MsgBox("Result found at 0x" & fcktrd.ToString("X"))
Next
[/why]
Code:
Private Sub Button9_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button9.Click

        Try

            Dim GaMe As Process() = Process.GetProcessesByName(TextBox19.Text)

            Dim pHandle As IntPtr = GaMe(0).Handle

            Dim _memManager As New RAMManager_32

            If _memManager.TryAttachToProcess(TextBox19.Text) Then
                
                'this is my value i want to scan for it
                Dim MyInt16 As Integer = TextBox1.Text

                Dim MyBytes As Byte() = BitConverter.GetBytes(MyInt16)

                Dim result() As IntPtr = _memManager.ScanForBytes(MyBytes, False)

                For Each Test As IntPtr In result
                    MsgBox("Result found at 0x" & Test.ToString("X"))
                Next
                ' Done using MemoryManager for reading. Close it.
                _memManager.DetachFromProcess()
                
            Else
                MessageBox.Show("MemoryManager unable to attach to 3D Pinball for ram reading")
            End If

        Catch ex As Exception

        End Try

    End Sub
nothing happened
and nothing will happen
i knew that it is not working nothing of this class is working np i will try to find another way
Catch ex As Exception
MsgBox("Nothing happened")
End Try

maybe ask a specific question, or give a specific problem, not just "nothing happened." -- I thought that was common sense.


Dim GaMe As Process() = Process.GetProcessesByName(TextBox19.Text)

Dim pHandle As IntPtr = GaMe(0).Handle

Game(0).Handle will throw an exception if TextBox19.Text wasn't a valid running process name. Was wondering why you had it in a try block.
And the MyInt16 As Integer = .Text will be your next problem. GL.
Private Sub Button9_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button9.Click

Dim _memManager As New RAMManager_32

If _memManager.TryAttachToProcess(TextBox19.Text) Then

Dim MyBytes As Byte() = BitConverter.GetBytes(1000)

Dim result() As IntPtr = _memManager.ScanForBytes(MyBytes, False)

For Each Test As IntPtr In result
MsgBox("Result found at 0x" & Test.ToString("X"))
Next
' Done using MemoryManager for reading. Close it.
_memManager.DetachFromProcess()
'MessageBox.Show("Your current 3D Pinball score is: " & _myScore.ToString())
Else
MessageBox.Show("MemoryManager unable to attach to 3D Pinball for ram reading")
End If

End Sub


now this is the problem :

Mixed mode assembly is built against another version of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.
Problem isn't in the code I posted...you probably added a reference to another memory library....one that uses fasm_managed maybe...

You can create a new project and make it for .net framework 3.5 to remove the error.
Quote Originally Posted by abuckau907 View Post
Problem isn't in the code I posted...you probably added a reference to another memory library....one that uses fasm_managed maybe...

You can create a new project and make it for .net framework 3.5 to remove the error.
Thanks

it is working good but can you explain why i have to use .net framework 3.5

and how to make this class work with .net framework 4.0

or the problem is not in the class

is the problem because of this dll > fasm_managed > so i need to change it

or what to do exactly to to make my project work with .net framework 4.0
This is a tutorial, not a classroom. If you have questions, create a new post.
I will not answer any more of your questions in this thread unless it's directly related to the code I posted.

"is the problem because of this dll > fasm_managed > so i need to change it"
TRY! Remove the reference to fasm_managed and see if the error goes away...
Posts 112 of 12 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Need help?