code from link 2
''' <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