[HOW TO] Vb.Net Memory Reading Part 2 menu

Shout-Out

User Tag List

Results 1 to 6 of 6
  1. #1
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [HOW TO] Vb.Net Memory Reading Part 2

    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 this addr)
    60000 - 80000 READ_ONLY (ie.can't call WriteProcessMemory on this 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
        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 size, and read the data as bytes using ReadBytes() then we can call it a lot less times and improve performance. How big can you make ReadProcessMemory() go? Well, I'm not sure, but the SYSTEM_INFO structure has a property called PageSize. Look into it. 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

    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.
    Last edited by abuckau907; 11-06-2012 at 12:12 PM.

    [HOW TO] Vb.Net Memory Reading Part 2
  2. #2
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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 Same
    dwSize Size of the region to be changed
    fwNewProtect New protection rights
    fwOldProtect Old protection rights (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)

    The final ScanBytes() function
    Code:
    Public Sub ScanAndReadAll()
       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 = _sysInfo.lpMinimumApplicationAddress
       Dim _readBuff(_sysInfo.dwPageSize - 1) As Byte 'read small pages
       Dim _bigBuff(0) As Byte 'read large pages
       Dim _actualBytesRead As Int32 = 0 ''actual length of bytes copied during ReadProcessMemory()
       Dim _oldPageProtection As UInt32 = 0 ''To restore old VirtualProtectEx() values after ReadProcessMemory
       Dim _accessRightsChanged As Boolean = False 'did we use VirtualProtectEx()?
    Do
       VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
       If _mbi.State = MemoryAllocationState.Commit Then
           'this region of ram actively being used by process (commited at least..)
           ''Can we read the data?
           If Not ((_mbi.Protect And MemoryAllocationProtectionType.PAGE_CANREAD) And Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_GUARD)) Then 'bitmask (checks for any readable type)
            ''Region not readable. Need VirtualProtect()
    	   _accessRightsChanged = True 'about to be true
    	   If _mbi.Protect And MemoryAllocationProtectionType.PAGE_CANEXECUTE Then
                   'it should remain executable! 
                  If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _oldPageProtection) Then
                      'DoOutput("execPatching 0x" & _addr.ToString("X"))
                  Else
                  'MsgBox("execPatching 0x" & _mbi.BaseAddress.ToString("X") & " FAIL?")
                  End If
               Else 'region isn't executable
                  If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_READWRITE, _oldPageProtection) Then
                      'MsgBox("readPatching 0x" & _mbi.BaseAddress.ToString("X")) 
                  Else
                      'MsgBox("readPatching 0x" & _mbi.BaseAddress.ToString("X") & " FAIL?")
                  End If
               End If
           End If
    	''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     			
       End If 
    	_addr = _mbi.BaseAddress + _mbi.RegionSize ''increment _addr to next region
            Loop While _addr.ToInt32 < _systemInfo.lpMaximumApplicationAddress
    End Sub
    That's it. You can now pretty much read anything a process might store in ram (it's executable code + any private variables).
    Add in a byte array parameter and you can search for values in memory. I won't explain all the byte loops, hopefully it makes sense.

    Code:
    Public Function ScanForBytes(ByVal buff() As Byte, Optional ByVal returnOnFirstOccurance As Boolean = False) As IntPtr()
      Dim _rtns As New List(Of IntPtr)
      _rtns.Capacity = 1000
      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
      Dim _bigBuff(0) As Byte
      Dim _actualBytesRead As Int32 = 0 ''actual length of bytes copied during ReadProcessMemory()
      Dim _oldPageProtection As UInt32 = 0 ''To restore old VirtualProtectEx() values after ReadProcessMemory
      Dim _accessRightsChanged As Boolean = False
      Dim _foundIt As Boolean = False
       Do
          VirtualQueryEx(_targetProcessHandle, _addr, _mbi, _mbiSize)
          If _mbi.State = MemoryAllocationState.Commit Then
              'this region of ram actively being used by process (commited at least..)
              ''Can we read the data?
              If Not ((_mbi.Protect And MemoryAllocationProtectionType.PAGE_CANREAD) And Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_GUARD)) Then 'bitmask (checks for any readable type)
                  'VirtualProtectEx() required to enable read access
                  _accessRightsChanged = True
                  If _mbi.Protect And MemoryAllocationProtectionType.PAGE_CANEXECUTE Then
                      'it should remain executable! 
                      If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _oldPageProtection) Then
                      'DoOutput("execPatching 0x" & _addr.ToString("X"))
                      Else
                      'DoOutput("execPatching 0x" & _addr.ToString("X") & " FAIL?")
                      End If
                  Else
                      If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_READWRITE, _oldPageProtection) Then
                      'DoOutput("readPatching 0x" & _mbi.BaseAddress.ToString("X"))
                      Else
                      'DoOutput("readPatching 0x" & _mbi.BaseAddress.ToString("X") & " FAIL?")
                      End If
                  End If
             End If
             ''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) Or _readBuff.Length <> _mbi.RegionSize Then
                         'not able to read all data, handle gracefully. do nothing :)
                         'MsgBox("ScanForBytes() RPM->ActualBytesRead too low! 0x" & _mbi.BaseAddress.ToString("X"))
                     Else
                         For xx As Int32 = 0 To _mbi.RegionSize - buff.Length
                             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
                               'found it
                             _rtns.Add(_addr + xx)
                             'MsgBox("found at 0x" & (_addr + xx).ToString("X"))
    badLabelNoSuccess:
                        Next
                     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))
               For xx As Int32 = 0 To _bigBuff.Length - buff.Length
                   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
                     'found it
                   _rtns.Add(_addr + xx)
    	       'MsgBox("found at 0x" & (_addr + xx).ToString("X"))
    badLabelNoMoreSuccess:
               Next
    
             End If 'done reading data
               '' Restore original page protection?
               If _accessRightsChanged Then
                   'MsgBox("unPatching->0x" & _addr.ToString("X"))
                   VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _oldPageProtection, _oldPageProtection)
                   _accessRightsChanged = False
               End If
           End If 
           If _returnOnFirstOccurance And _foundIt Then
    	  Return _rtns.ToArray
           End If
           _addr = _mbi.BaseAddress + _mbi.RegionSize ''increment _addr to next region
       Loop While _addr.ToInt32 < &H7FFE0000 '_sysInfo.lpMaximumApplicationAddress
           
       If _rtns.Count > 0 Then
       'we found it at least once
       Else
          DoOutput("NONE")
          _rtns.Add(IntPtr.Zero) 'indicates failure
       End If
    
       Return _rtns.ToArray ' efficiency?   
    End Function
    That's it. Add a mask parameter and another if statment in both the for/for loops and you have FindPattern. Hope that helps.
    Last edited by abuckau907; 11-06-2012 at 12:33 PM.

  3. #3
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Copy a single register...
    Code:
        Public Function GetRegisterOnce(ByVal sourceLoc As IntPtr, ByVal register As CpuRegister) As IntPtr
            Dim _codeCaveStartLoc As IntPtr = Malloc(200) 'in wow.exe ram, used to store (then run) bytecode. todo: auto-sized
            Dim _codeCaveCode(0) As Byte ' stores bytecode to inject into process
            Dim _origAsmLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 100 'executable's orig. code copied here (8 bytes)
            Dim _rtnValueLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 175 'where our asm code copies the register to
            Dim _origProcessByteCode() As Byte = ReadBytes(sourceLoc, 8) 'orig. wow.exe code (must be restored by codecave code)
            WriteBytes(_origAsmLoc, _origProcessByteCode)
            'Create codeCave byte code (copy,cleanup,return)
            'copy register to our dump location
            Dim registerAsString As String = System.Enum.GetName(GetType(CpuRegister), register) 'awk
            Dim sb As New System.Text.StringBuilder
            With sb
                'save registers (that I use) to avoid corrupting stack
                .AppendLine("push eax")
                .AppendLine("push ebx")
                .AppendLine("push edx")
                'copy our rtnValueLoc to a register
                .AppendLine("mov eax, " & _rtnValueLoc.ToInt32.ToString)
                'copy register into the [value] at rtnValueLoc
                .AppendLine("mov [eax], " & registerAsString) 'the magic happens right here
                'clean-up
                .AppendLine("mov eax, " & sourceLoc.ToInt32.ToString)
                .AppendLine("mov ebx, " & _origAsmLoc.ToInt32.ToString)
                .AppendLine("mov edx, [ebx]") 'copy 4 bytes from _origAsmLoc to exe source_loc
                .AppendLine("mov [eax], edx") ' ie. unpatch using exe's orig source code
                .AppendLine("add ebx, 4")
                .AppendLine("add eax, 4")
                .AppendLine("mov edx, [ebx]") 'copy next/last 4 bytes back into wow.exe
                .AppendLine("mov [eax], edx") '
                .AppendLine("pop edx") 'pop order is important. duh.
                .AppendLine("pop ebx")
                .AppendLine("pop eax")
    
            End With
            Dim _individualAsmStrings() As String = Split(sb.ToString, Environment.NewLine)
            If _individualAsmStrings(_individualAsmStrings.Length - 1) = "" Then ReDim Preserve _individualAsmStrings(_individualAsmStrings.Length - 2) 'chop off empty string: last call should use ASM.Append() Not AppendLine() ? works.
            Dim _cdc() As Byte 'codecave bytecode, except 5 bytes for a JMP command.
            _cdc = GetByteCode(_individualAsmStrings)
            Dim _jmpAsm(4) As Byte ' hand crafted JMP command : instead of using managed_fasm.assemble("JMP address")..Educational.
            _jmpAsm(0) = &HE9 'opcode for Relative jump
            ReDim _codeCaveCode(_cdc.Length - 1 + 5) '5 = _jmpAsm.Length in bytes, 'E9' + 4 byte ram address
    
            Dim _bts() As Byte = BitConverter.GetBytes(sourceLoc.ToInt32 - _codeCaveStartLoc.ToInt32 - _codeCaveCode.Length) 'address where codecave jmps back to. (ie. sourceLoc, but relative* because I use 'E9' for JMP not 'FF') !!!
            _bts.Reverse() 'endianness of bytecode
            Array.Copy(_bts, 0, _jmpAsm, 1, 4) 'copy the 4 byte address into the asm jmp command
            Array.Copy(_cdc, _codeCaveCode, _cdc.Length) 'copy the codecavecode(w/o jmp) to array
            Array.Copy(_jmpAsm, 0, _codeCaveCode, _codeCaveCode.Length - 5, 5) 'copy jmp command to end of array
    
            WriteBytes(_codeCaveStartLoc, _codeCaveCode) 'write the bytecode (100% complete now) into process's ram.
            ''Write Jmp command to sourceLoc. ie. WILL make it re-route
            _bts = BitConverter.GetBytes(_codeCaveStartLoc.ToInt32 - (sourceLoc.ToInt32 + 5)) 'address of beginning of codecave. +5 because in asm, JMP is relative* to the NEXT instruction. Jmp is 5 bytes long.
            _bts.Reverse() 'indianness of byte code
            Array.Copy(_bts, 0, _jmpAsm, 1, 4) '_jmpAsm is now complete, again.
            Dim scanStartTime As DateTime = Date.Now
            Dim scanTimeLapse As TimeSpan
            'enable ram to be written to
            Dim _origAccessRights As UInt32 = 0
            Dim _mbi As MEMORY_BASIC_INFORMATION
            VirtualQueryEx(_targetProcessHandle, sourceLoc, _mbi, _mbiSize)
            If Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE) Then
                'change rights
                If Not VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origAccessRights) Then
                    modPublic.DoOutput("CodeCave::CopyRegisterOnce::VirtualProtectEx fail 0x" & sourceLoc.ToString("X"))
                    Return IntPtr.Zero 'can't write to this memory?
                End If
            End If
            'if we get here, orig perms. were exec_r_w or VirtualProtect worked
            WriteBytes(sourceLoc, _jmpAsm) ' .Patch()
            'modPublic.DoOutput("scanning for rtn value...")
            Dim _origJumpLocCode As UInt64 = BitConverter.ToUInt64(_origProcessByteCode, 0) 'because orig asm is only 8 bytes i used int64. should use byte array.
            Do Until ReadUInt64(sourceLoc) = _origJumpLocCode 'do until the codecave unpatches itsself!(ie. orig code has been restored) nifty.
                scanTimeLapse = Date.Now.Subtract(scanStartTime)
                If scanTimeLapse.TotalSeconds > 10 Then
                    'we need to manually put the source Bcode back
                    WriteBytes(sourceLoc, _origProcessByteCode)
                    If _origAccessRights <> 0 Then
                        'we changed rights, change them back.
                        VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New UInt32)
                    End If
                    modPublic.DoOutput("Time limit exceeded. 10s")
                    Return IntPtr.Zero ' wow.exe code never got called. or other asm/codecavecode error?...
                End If
            Loop
            'if we get here, success!
            Dim _rtnPtr As IntPtr = ReadIntPtr(_rtnValueLoc) ' == register value !
            'modPublic.DoOutput("success: val=" & _rtnPtr.ToString("x"))
            'free mem allocated for codecave inside wow
            VirtualFreeEx(_targetProcessHandle, _codeCaveStartLoc, 200, MemoryAllocationState.Decommit)
            'restore rights?
            If _origAccessRights <> 0 Then
                VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New Int32)
            End If
            Return _rtnPtr
        End Function
    Copy all registers (well, most of the big ones)
    Code:
        Public Function GetRegistersAllOnce(ByVal sourceLoc As IntPtr) As CPU_REGISTERS
            Dim _rtnRegisters As CPU_REGISTERS
            Dim _codeCaveStartLoc As IntPtr = Malloc(200)
            Dim _codeCaveCode() As Byte ' stores bytecode to inject into process
            Dim _origAsmLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 190 'code-cave's orig. code copied here (8 bytes)
            Dim _rtnValueLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 100 'where our asm code copies the register
            Dim _origProcessByteCode() As Byte = ReadBytes(sourceLoc, 8) 'original process asm, which we replace w/ JMP 
            WriteBytes(_origAsmLoc, _origProcessByteCode)
            'copy the register to our dump location
            Dim sb As New System.Text.StringBuilder
            With sb
                .AppendLine("push eax")
                .AppendLine("push edx")
                .AppendLine("mov edx, " & _rtnValueLoc.ToInt32.ToString) 'start of rtn value loc in memory
                'copy registers into rtnValueLoc demp are
                .AppendLine("mov [edx], eax") 'copy eax
                .AppendLine("add edx, 4")
                .AppendLine("mov [edx], ebx") 'copy ebx
                .AppendLine("add edx, 4")
                .AppendLine("mov [edx], ecx") 'copy ecx
                .AppendLine("add edx, 4")
                .AppendLine("mov eax, edx")   'switch register being used as the place holder
                .AppendLine("pop edx")
                .AppendLine("mov [eax], edx") 'copy edx
                .AppendLine("add eax, 4")
                .AppendLine("mov [eax], edi") 'copy esi
                .AppendLine("add eax, 4")
                .AppendLine("mov [eax], esi") 'copy edi
                .AppendLine("add eax, 4")
                .AppendLine("mov [eax], ebp") 'copy ebp
                .AppendLine("add eax, 4")
                .AppendLine("mov [eax], esp") 'copy esp
                'clean-up
                .AppendLine("push ebx")
                .AppendLine("push edx")
                .AppendLine("mov eax, " & sourceLoc.ToInt32.ToString)
                .AppendLine("mov ebx, " & _origAsmLoc.ToInt32.ToString)
                .AppendLine("mov edx, [ebx]")
                .AppendLine("mov [eax], edx")
                .AppendLine("add ebx, 4")
                .AppendLine("add eax, 4")
                .AppendLine("mov edx, [ebx]")
                .AppendLine("mov [eax], edx")
                .AppendLine("pop edx")
                .AppendLine("pop ebx")
                .AppendLine("pop eax")
            End With
            Dim _individualAsmStrings() As String = Split(sb.ToString, Environment.NewLine)
            Dim _cdc() As Byte 'codecave bytecode, minus 5 bytes for the JMP command.
            Dim _jmpAsm(4) As Byte ' hand crafted JMP command : instead of using managed_fasm.assemble("JMP offset")..
            _jmpAsm(0) = &HE9 'opcode for relative jump
            If _individualAsmStrings(_individualAsmStrings.Length - 1) = "" Then ReDim Preserve _individualAsmStrings(_individualAsmStrings.Length - 2) 'chop off empty string at end..
            _cdc = GetByteCode(_individualAsmStrings)
            ReDim _codeCaveCode(_cdc.Length - 1 + 5) '5 = _jmpAsm.Length in bytes, 'E9' + 4 bytes. -1 for explicitness
    
            Dim _bts() As Byte = BitConverter.GetBytes(sourceLoc.ToInt32 - _codeCaveStartLoc.ToInt32 - _codeCaveCode.Length) 'address where codecave jmps back to. (ie. sourceLoc, but relative because I use 'E9' for JMP not 'FF')
            _bts.Reverse() ' endianness
            Array.Copy(_bts, 0, _jmpAsm, 1, 4) 'copy the 4 byte address into the asm command
            Array.Copy(_cdc, _codeCaveCode, _cdc.Length) 'copy the codecavecode(w/o jmp) to Array()
            Array.Copy(_jmpAsm, 0, _codeCaveCode, _codeCaveCode.Length - 5, 5) 'copy asm command to end of Array()
    
            WriteBytes(_codeCaveStartLoc, _codeCaveCode) 'write the bytecode (100% complete now) into process's ram.
            ''Write Jmp command to sourceLoc 
            _bts = BitConverter.GetBytes(_codeCaveStartLoc.ToInt32 - (sourceLoc.ToInt32 + 5)) 'address of beginning of codecave. +5 because in asm, JMP is relative to the NEXT instruction. Jmp is 5 bytes long.
            _bts.Reverse() 'indian
            Array.Copy(_bts, 0, _jmpAsm, 1, 4)
    
            Dim scanStartTime As DateTime = Date.Now
            Dim scanTimeLapse As TimeSpan
            'enable ram to be written to
            Dim _origAccessRights As UInt32 = 0
            Dim _mbi As MEMORY_BASIC_INFORMATION
            VirtualQueryEx(_targetProcessHandle, sourceLoc, _mbi, _mbiSize)
            If Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE) Then
                'change rights
                If Not VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origAccessRights) Then
                    modPublic.DoOutput("CodeCave::CopyRegisterOnce::VirtualProtectEx fail 0x" & sourceLoc.ToString("X"))
                    Return New CPU_REGISTERS 'can't write to this memory?
                End If
            End If
            'if we get here, orig perms. were exec_r_w or VirtualProtect worked
            DoOutput("Patching 0x" & sourceLoc.ToString("X"))
            WriteBytes(sourceLoc, _jmpAsm) ' .Inject() :: Write JMP command to process code --next time it's ran, our codecave gets executed!
            modPublic.DoOutput("scanning for rtn value...")
            Dim _origJumpLocCode As UInt64 = BitConverter.ToUInt64(_origProcessByteCode, 0)
    
            Do Until ReadUInt64(sourceLoc) = _origJumpLocCode
                scanTimeLapse = Date.Now.Subtract(scanStartTime)
                If scanTimeLapse.TotalSeconds > 10 Then
                    'we need to manually put the source Bcode back
                    WriteBytes(sourceLoc, _origProcessByteCode)
                    If _origAccessRights Then
                        'we changed rights, change them back.
                        VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New UInt32)
                    End If
                    DoOutput("ASM:CopyRegistersALL() Failed to be run.")
                    Return New CPU_REGISTERS
                End If
            Loop
            'if we get here, success!
            Dim _rtnBytes() As Byte = ReadBytes(_rtnValueLoc, 32)
            _rtnRegisters.eax = BitConverter.ToUInt32(_rtnBytes, 0) '' sloppy?
            _rtnRegisters.ebx = BitConverter.ToUInt32(_rtnBytes, 4)
            _rtnRegisters.ecx = BitConverter.ToUInt32(_rtnBytes, 8)
            _rtnRegisters.edx = BitConverter.ToUInt32(_rtnBytes, 12)
            _rtnRegisters.edi = BitConverter.ToUInt32(_rtnBytes, 16)
            _rtnRegisters.esi = BitConverter.ToUInt32(_rtnBytes, 20)
            _rtnRegisters.ebp = BitConverter.ToUInt32(_rtnBytes, 24)
            _rtnRegisters.esp = BitConverter.ToUInt32(_rtnBytes, 28)
            'free VirtualAllocEx memory
            VirtualFreeEx(_targetProcessHandle, _codeCaveStartLoc, 200, MemoryAllocationState.Decommit)
            'restore rights?
            If _origAccessRights Then
                VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New Int32)
            End If
            Return _rtnRegisters
        End Function
    //structs/enums
    Code:
        Public Structure CPU_REGISTERS
            Dim eax As UInt32
            Dim ebx As UInt32
            Dim ecx As UInt32
            Dim edx As UInt32
            Dim edi As UInt32
            Dim esi As UInt32
            Dim ebp As UInt32
            Dim esp As UInt32
        End Structure
        Public Enum CpuRegister As UInt32
            eax = 0
            ebx
            ecx
            edx
            edi
            esi
            ebp
            esp
        End Enum
    Last edited by abuckau907; 11-29-2012 at 10:20 AM.
    Some things that can be counted, don't matter. And some things that matter, can't be counted.

  4. #4
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ScanForValue (ie. find every occurance of your health value)
    FindPattern (ie. find bytecode inside a process)

    Code:
    #Region "Scan()"
       
        Public Function FindPattern(ByVal hexString As String, Optional ByVal returnOnFirstOccurance As Boolean = True) As IntPtr
            ''ex. format: 14 8b 11 ** ** ** ** 8b 34 ** 8b 0d ** ** ** ** 89 61
            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 _startTime = Date.Now
            DoOutput("FindPattern()")
            Dim _results() As IntPtr = ScanForBytes(_hexStringAsBytes, _mask, returnOnFirstOccurance)
    
            Dim _timeLapse As TimeSpan = Date.Now.Subtract(_startTime)
            DoOutput("Total time: " & _timeLapse.TotalSeconds & "s")
            Return _results(0) 'todo: return entire array if !returnOnFirstOccurance. lol.
        End Function
    Code:
      Public Function ScanForBytes(ByVal buff() As Byte, Optional ByVal returnOnFirstOccurance As Boolean = False) As IntPtr()
            Dim _mask(buff.Length - 1) As Byte
            For xx As Int32 = 0 To buff.Length - 1
                _mask(xx) = &H1
            Next
            Return ScanForBytes(buff, _mask, returnOnFirstOccurance)
        End Function
    
    
        Public Function ScanForBytes(ByVal buff() As Byte, ByVal mask() As Byte, Optional ByVal returnOnFirstOccurance As Boolean = False) As IntPtr()
            Dim _rtns As New List(Of IntPtr)
            If (mask.Length <> buff.Length) Or IsAttachedToProcess() = False Then
                _rtns.Add(IntPtr.Zero)
                Return _rtns.ToArray
            End If
            _rtns.Capacity = 1000
            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
            Dim _bigBuff(0) As Byte
            Dim _actualBytesRead As Int32 = 0 ''actual length of bytes copied during ReadProcessMemory()
            Dim _origPageProtection As UInt32 = 0 ''To restore old VirtualProtectEx() values after ReadProcessMemory
            Dim _foundIt As Boolean = False
            DoOutput("ScanForBytes()")
            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 Not ((_mbi.Protect And MemoryAllocationProtectionType.PAGE_CANREAD) And Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_GUARD)) Then 'bitmask (checks for any readable type)
                        'VirtualProtectEx() required to enable read access
                        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 0x" & _addr.ToString("X"))
                            Else
                                'DoOutput("execPatching 0x" & _addr.ToString("X") & " FAIL?")
                            End If
                        Else
                            If VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_READWRITE, _origPageProtection) Then
                                'DoOutput("readPatching 0x" & _mbi.BaseAddress.ToString("X"))
                            Else
                                'DoOutput("readPatching 0x" & _mbi.BaseAddress.ToString("X") & " FAIL?")
                            End If
                        End If
                    End If
                    ''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) Or _readBuff.Length <> _mbi.RegionSize Then
                                'not able to read all data, handle gracefully. do nothing :)
                                DoOutput("ScanForBytes() RPM->ActualBytesRead too low! 0x" & _mbi.BaseAddress.ToString("X"))
                            Else
                                For xx As Int32 = 0 To _mbi.RegionSize.ToInt32 - buff.Length
                                    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
                                    _foundIt = True
    badLabelNoSuccess:
                                Next
                            End If
                        Else
                            DoOutput("ScanForBytes::RPM FAIL 0x" & _mbi.BaseAddress.ToString("X"))
                        End If
                    Else
                        'large page. Read page in chunks.
                        _bigBuff = ReadLargeRamPage(_addr, _addr.ToInt32 + _mbi.RegionSize.ToInt32)
                        For xx As Int32 = 0 To _bigBuff.Length - buff.Length
                            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
                            _foundIt = True
    badLabelNoMoreSuccess:
                        Next
    
                    End If ''//page size
                    '' Restore original page protection?
                    If _origPageProtection Then
                        'DoOutput("unPatching->0x" & _addr.ToString("X"))
                        VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origPageProtection, _origPageProtection)
                        _origPageProtection = 0
                    End If
                    If returnOnFirstOccurance And _foundIt Then
                        Exit Do
                    End If
                End If ''//state=committed
                _addr = _mbi.BaseAddress.ToInt32 + _mbi.RegionSize.ToInt32 ''increment _addr to next region
            Loop While _addr.ToInt32 < &H7FFE0000 '_sysInfo.lpMaximumApplicationAddress
    
            If _rtns.Count > 0 Then
                DoOutput("Found at..")
                For Each ppp As IntPtr In _rtns
                    DoOutput("0x" & ppp.ToString("X"))
                Next
            Else
                DoOutput("Not Found")
                _rtns.Add(IntPtr.Zero)
            End If
            Return _rtns.ToArray
        End Function
    Code:
        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 fails
            Dim _sizeRemaining As Int32 = _rtnBuffSize
            Dim _byteBuff() As Byte
            ReDim _byteBuff(_rtnBuffSize - 1)
            Dim _byteBuffCurrIndex As Int32 = 0 'actual size of data to be returned
            Dim _curAddr As IntPtr = aStart
            Dim _readBuff(_systemInfo.dwPageSize) 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
                            DoOutput("ReadLargeRamChunk() RPM->ActualBytesRead too low! 0x" & _curAddr.ToString("X"))
                        Else
                            Array.Copy(_readBuff, 0, _byteBuff, _byteBuffCurrIndex, _systemInfo.dwPageSize)
                            _byteBuffCurrIndex += _systemInfo.dwPageSize
                        End If
                    Else
                        DoOutput("ReadLargeRamChunk() RPM->FAIL! 0x" & _curAddr.ToString("X"))
                        Application.DoEvents()
                        'Beep()
                        Threading.Thread.Sleep(2000)
                    End If
                    _curAddr = _curAddr.ToInt32 + _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) Or (_readBuff.Length <> _sizeRemaining) Then
                            'not able to read entire area
                            DoOutput("ReadLargeRamChunk() RPM->ActualBytesRead too low! (final chunk)")
                        Else
                            Array.Copy(_readBuff, 0, _byteBuff, _byteBuffCurrIndex, _sizeRemaining)
                            'success
                            Exit Do
                        End If
    
                    Else
                        DoOutput("ReadLargeRamChunk() RPM->FAIL! (final chunk)")
                        Application.DoEvents()
                        Beep()
                        Threading.Thread.Sleep(2000)
                    End If
                End If
            Loop
            If _byteBuffCurrIndex < _rtnBuffSize Then
                'not all data read. _byteBuff is too large. Shrink it.
                ReDim Preserve _byteBuff(_byteBuffCurrIndex + 1) ''sloppy and inefficient? rarely happens.?
            End If
    
            Return _byteBuff
        End Function
    fasm_managed.dll
    Code:
        Public Function GetByteCode(ByVal _asms() As String) As Byte()
            _ASM.Clear()
            For Each ss As String In _asms
                _ASM.AddLine(ss)
            Next
            Return _ASM.Assemble ' _ASM = fasm.managed. credits due for fasm_managed.dll. Thank you.
        End Function
    Last edited by abuckau907; 11-29-2012 at 10:49 AM.
    Some things that can be counted, don't matter. And some things that matter, can't be counted.

  5. #5
    Borretos's Avatar Private
    Reputation
    1
    Join Date
    Nov 2012
    Posts
    5
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Good lessons here!!! Really appreciate it, Thanks !!!

  6. #6
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks. I uploaded a demo project which has all this (and a little more) in it.
    http://www.ownedcore.com/forums/worl...ot-vb-net.html ([source wowFollow bot vb.net])
    Some things that can be counted, don't matter. And some things that matter, can't be counted.

Similar Threads

  1. [guide] how to create a wow bot using autoit (memory reading)
    By zamba1587 in forum WoW Memory Editing
    Replies: 17
    Last Post: 01-23-2017, 03:27 PM
  2. [HOW TO] Vb.Net Memory Reading
    By abuckau907 in forum Programming
    Replies: 7
    Last Post: 12-15-2014, 04:01 AM
  3. How do i know if a Bot is using memory reading / writing?
    By sturmtiger in forum WoW Bots Questions & Requests
    Replies: 1
    Last Post: 01-06-2011, 06:31 AM
  4. VB .Net Memory Reading Project
    By Glitchy in forum WoW Memory Editing
    Replies: 4
    Last Post: 01-22-2008, 12:37 PM
  5. How do you find memory offsets in the game?
    By koalaz2004 in forum World of Warcraft General
    Replies: 0
    Last Post: 08-18-2006, 09:40 PM
All times are GMT -5. The time now is 05:44 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search