QuestionHelpVB 2010 - Signature / Pattern scanning

Posts 1–4 of 4 · Page 1 of 1
VB 2010 - Signature / Pattern scanning
Hey there,

>.<" uh, I feel embarrassed just for having to ask for help, but given I just wasted countless hours 'googleing' .. here I am.

Now then, I was hoping to implement the 'ReadProcessMemory' function into my bot, to grab certain info from the game. Right now, the bot uses OCR to grab the info as it is the only other method of getting it. Pointers / static addresses don't seem to exist in this game as I have wasted well over 20+ hours ( and 1TB~ of my precious disk space ) trying to scan for them. It was at this time that I stumbled upon a tutorial on Signature / Pattern scanning. Unfortunately it was a C++ tut, and having very little to no C++ knowledge ( or byte scanning knowledge for that matter ), I went with the next best thing and built the C++ project as a .DLL which I had hope to just reference in my project and use it's functions ( like I have done countless of times in the past ). For whatever reason it didn't work this time.. ( Perhaps because it wasn't a class but only a header, whatever the hell that is )

So, after countless tries I went back to google and after what seemed like an eternity I have managed to get my hands on what looked like a promising piece of code. (It was actually in this very section, http://www.mpgh.net/forum/showthread.php?t=259014)

However, being as lucky as I am today, this 'promising' piece of code turned into a major kick in the balls when it threw a PInvokeStackImbalance at me upon execution ( no idea as to why as it seemed to have worked for whoever wrote/requested it in the other thread ). I have read countless websites and threads, they all seem to point to incorrect PInvoke definition. I've been staring at it for quite a few hours now, and, apart from feeling stupider as this is supposedly a 'simple thing to do', haven't progressed in any way.

Here's the MDA message :
Code:
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'WindowsApplication1!WindowsApplication1.Module1::ReadProcessMemory' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Module1.vb
 
Module
Code:
Module Module1
    Public Declare Function OpenProcess Lib "KERNEL32" _
    (ByVal DesiredAccess As Int32, _
     ByVal InheritHandle As Boolean, _
     ByVal ProcessId As Int32) _
    As Int32

    Private Declare Function ReadProcessMemory Lib "KERNEL32" _
    (ByVal Handle As Int32, _
     ByVal address As Int32, _
     ByRef Value As Int32, _
     Optional ByVal Size As Int32 = 4, _
     Optional ByVal lpNumberOfBytesWritten As Int64 = 0) _
    As Long

    Public PROCESS_VM_OPERATION As Int32 = 8
    Public PROCESS_VM_READ As Int32 = 16
    Public PROCESS_VM_WRITE As Int32 = 32

    Private process_id As Int32 = 0
    Public pHandle As Integer = 0

    Public Function GetProcessId(ByVal game_name As String) As Boolean
        Dim Processes() As Process = Process.GetProcesses
        Dim process_name As String
        Dim i As Byte
        For i = LBound(Processes) To UBound(Processes)
            process_name = Processes(i).ProcessName
            If process_name = game_name Then
                process_id = Processes(i).Id
                pHandle = OpenProcess(PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, process_id)
                Return True
            End If
        Next
        If process_id = 0 Then
            Return False
        End If
        Return False
    End Function

    Public Function ReadByte(ByVal address As Int32) As Integer
        Dim value As Integer
        ReadProcessMemory(pHandle, address, value, 1, 0)
        Return value
    End Function

    Public Function AOBSCAN(ByVal GameName As String, ByVal ModuleName As String, ByVal Signature As Byte(), ByVal Mask As Byte()) As Integer
        Dim BaseAddress, EndAddress As Int32
        For Each PM As ProcessModule In Process.GetProcessesByName(GameName)(0).Modules
            If ModuleName = PM.ModuleName Then
                BaseAddress = PM.BaseAddress
                EndAddress = BaseAddress + PM.ModuleMemorySize
            End If
        Next
        Dim curAddr As Int32 = BaseAddress
        Do
            For i As Integer = 0 To Signature.Length - 1
                If ReadByte(curAddr + i) = Signature(i) Or Mask(i) = &H0 Then
                    If i = Signature.Length - 1 Then
                        MsgBox(curAddr.ToString("X"))
                        Return curAddr
                    End If
                    Continue For
                End If
                Exit For
            Next
            curAddr += 1
        Loop While curAddr < EndAddress
        Return 0
    End Function
End Module


Usage :
Code:
 Dim sigAddresses As Integer = AOBSCAN("ac_client", "ac_client.exe", New Byte() {&HFF, &H25, &HBC, &H30, &HF, &H1, &H75, &H2}, New Byte() {&HFF, &H0, &HFF, &H0, &HFF, &H0, &H0, &H0})
'Not an actual pattern and mask. Also, I'm currently just testing and trying to get it to work with a simple game ( Assault Cube )
I've literally read tens of thousands of lines of code during my google spree, my brain is so full of fuck I couldn't code a 'Hello World' app right now. So please be considerate and spare me any 'ERMAGERD L2Program' comments.

I'd really appreciate if you guys could help me get this to work, so I can see it in action, mess around with it to learn how it works and ultimately implement it into my crappy bot. Also, I'd love you forever.
Quote Originally Posted by croser View Post
Hey there,

>.<" uh, I feel embarrassed just for having to ask for help, but given I just wasted countless hours 'googleing' .. here I am.

Now then, I was hoping to implement the 'ReadProcessMemory' function into my bot, to grab certain info from the game. Right now, the bot uses OCR to grab the info as it is the only other method of getting it. Pointers / static addresses don't seem to exist in this game as I have wasted well over 20+ hours ( and 1TB~ of my precious disk space ) trying to scan for them. It was at this time that I stumbled upon a tutorial on Signature / Pattern scanning. Unfortunately it was a C++ tut, and having very little to no C++ knowledge ( or byte scanning knowledge for that matter ), I went with the next best thing and built the C++ project as a .DLL which I had hope to just reference in my project and use it's functions ( like I have done countless of times in the past ). For whatever reason it didn't work this time.. ( Perhaps because it wasn't a class but only a header, whatever the hell that is )

So, after countless tries I went back to google and after what seemed like an eternity I have managed to get my hands on what looked like a promising piece of code. (It was actually in this very section, http://www.mpgh.net/forum/showthread.php?t=259014)

However, being as lucky as I am today, this 'promising' piece of code turned into a major kick in the balls when it threw a PInvokeStackImbalance at me upon execution ( no idea as to why as it seemed to have worked for whoever wrote/requested it in the other thread ). I have read countless websites and threads, they all seem to point to incorrect PInvoke definition. I've been staring at it for quite a few hours now, and, apart from feeling stupider as this is supposedly a 'simple thing to do', haven't progressed in any way.

Here's the MDA message :
Code:
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'WindowsApplication1!WindowsApplication1.Module1::ReadProcessMemory' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Module1.vb
 
Module
Code:
Module Module1
    Public Declare Function OpenProcess Lib "KERNEL32" _
    (ByVal DesiredAccess As Int32, _
     ByVal InheritHandle As Boolean, _
     ByVal ProcessId As Int32) _
    As Int32

    Private Declare Function ReadProcessMemory Lib "KERNEL32" _
    (ByVal Handle As Int32, _
     ByVal address As Int32, _
     ByRef Value As Int32, _
     Optional ByVal Size As Int32 = 4, _
     Optional ByVal lpNumberOfBytesWritten As Int64 = 0) _
    As Long

    Public PROCESS_VM_OPERATION As Int32 = 8
    Public PROCESS_VM_READ As Int32 = 16
    Public PROCESS_VM_WRITE As Int32 = 32

    Private process_id As Int32 = 0
    Public pHandle As Integer = 0

    Public Function GetProcessId(ByVal game_name As String) As Boolean
        Dim Processes() As Process = Process.GetProcesses
        Dim process_name As String
        Dim i As Byte
        For i = LBound(Processes) To UBound(Processes)
            process_name = Processes(i).ProcessName
            If process_name = game_name Then
                process_id = Processes(i).Id
                pHandle = OpenProcess(PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, process_id)
                Return True
            End If
        Next
        If process_id = 0 Then
            Return False
        End If
        Return False
    End Function

    Public Function ReadByte(ByVal address As Int32) As Integer
        Dim value As Integer
        ReadProcessMemory(pHandle, address, value, 1, 0)
        Return value
    End Function

    Public Function AOBSCAN(ByVal GameName As String, ByVal ModuleName As String, ByVal Signature As Byte(), ByVal Mask As Byte()) As Integer
        Dim BaseAddress, EndAddress As Int32
        For Each PM As ProcessModule In Process.GetProcessesByName(GameName)(0).Modules
            If ModuleName = PM.ModuleName Then
                BaseAddress = PM.BaseAddress
                EndAddress = BaseAddress + PM.ModuleMemorySize
            End If
        Next
        Dim curAddr As Int32 = BaseAddress
        Do
            For i As Integer = 0 To Signature.Length - 1
                If ReadByte(curAddr + i) = Signature(i) Or Mask(i) = &H0 Then
                    If i = Signature.Length - 1 Then
                        MsgBox(curAddr.ToString("X"))
                        Return curAddr
                    End If
                    Continue For
                End If
                Exit For
            Next
            curAddr += 1
        Loop While curAddr < EndAddress
        Return 0
    End Function
End Module


Usage :
Code:
 Dim sigAddresses As Integer = AOBSCAN("ac_client", "ac_client.exe", New Byte() {&HFF, &H25, &HBC, &H30, &HF, &H1, &H75, &H2}, New Byte() {&HFF, &H0, &HFF, &H0, &HFF, &H0, &H0, &H0})
'Not an actual pattern and mask. Also, I'm currently just testing and trying to get it to work with a simple game ( Assault Cube )
I've literally read tens of thousands of lines of code during my google spree, my brain is so full of fuck I couldn't code a 'Hello World' app right now. So please be considerate and spare me any 'ERMAGERD L2Program' comments.

I'd really appreciate if you guys could help me get this to work, so I can see it in action, mess around with it to learn how it works and ultimately implement it into my crappy bot. Also, I'd love you forever.
The reason why you have that PInvoke error is because you have the wrong declaration of ReadProcessMemory()ⓘ.
Use these functions instead (I also added other functions, although you don't need to use all of them):
Code:
    ''' <summary> Opens an existing local process object. </summary>
    ''' <param name="dwProcessId">The identifier of the local process to be opened.
    ''' If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them.</param>
    ''' <param name="dwDesiredAccess">The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or more of the process access rights.
    ''' If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.</param>
    ''' <param name="bInheritHandle">If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.</param>
    Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As UInteger, ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
   
    ''' <summary> Closes an open object handle.</summary>
    ''' <param name="hObject">A valid handle to an open object.</param>
    Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As IntPtr) As Boolean
 

    ''' <summary> Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails.</summary>
    ''' <param name="hProcess">A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process.</param>
    ''' <param name="lpBaseAddress">A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible the function fails.</param>
    ''' <param name="lpBuffer">A pointer to a buffer that receives the contents from the address space of the specified process.</param>
    ''' <param name="nSize">The number of bytes to be read from the specified process.</param>
    ''' <param name="lpNumberOfBytesRead">A pointer to a variable that receives the number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.</param>
    '''<remarks>WriteProcessMemory copies the data from the specified buffer in the current process to the address range of the specified process. Any process that has a handle with PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the process to be written to can call the function. Typically but not always, the process with address space that is being written to is being debugged.
    '''The entire area to be written to must be accessible, and if it is not accessible, the function fails.</remarks>
    Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As IntPtr, ByVal lpBaseAddress As UInt32, ByVal lpBuffer() As Byte, ByVal nSize As UInt32, ByRef lpNumberOfBytesRead As UIntPtr) As Boolean


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    Public Function ReadLong(ByVal P As Process, ByVal memAdr As UInt32) As Long
        Return BitConverter.ToInt64(ReadBytes(P, memAdr, 8), 0)
    End Function


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    Public Function ReadFloat(ByVal P As Process, ByVal memAdr As UInt32) As Single
        Return BitConverter.ToSingle(ReadBytes(P, memAdr, 4), 0)
    End Function


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    Public Function ReadInt32(ByVal P As Process, ByVal memAdr As UInt32) As Integer
        Return BitConverter.ToInt32(ReadBytes(P, memAdr, 4), 0)
    End Function


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    Public Function ReadShort(ByVal P As Process, ByVal memAdr As UInt32) As Short
        Return BitConverter.ToInt16(ReadBytes(P, memAdr, 2), 0)
    End Function


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    Public Function ReadByte(ByVal P As Process, ByVal memAdr As UInt32) As Byte
        Return ReadBytes(P, memAdr, 1)(0)
    End Function


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    ''' <param name="startIndex">The index of the bit to read from(0 to 7).</param>
    Public Function ReadBit(ByVal P As Process, ByVal memAdr As Int32, ByVal startIndex As Integer) As Boolean
        If (startIndex <= 7 And startIndex >= 0) Then '1 Byte == 8 Bits.  
            Return ((ReadByte(P, memAdr) And (2 ^ startIndex)) <> 0) ' 2^0 = 1(00000001), 2^1 = 2(00000010), 2^2 = 4(00000100) (...);
        End If
        Return False
    End Function


    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    ''' <param name="length">The amount of bytes to read from the specified address.</param>
    Public Function ReadBytes(ByVal P As Process, ByVal memAdr As UInt32, ByVal length As UInteger) As Byte()
        Dim buffer As Byte() = New Byte(length - 1) {} 'Creates our buffer.
        Dim hProcess as IntPtr = OpenProcess(&H1F0FFF, False, P.Id) 'Creates our process handle.
        If Not ReadProcessMemory(hProcess, New IntPtr(CLng(memAdr)), buffer, length, 0) Then buffer = Nothing 'Reads the memory in that address, and writes it to the buffer. If there was an error while reading memory, then it'll return null.
        CloseHandle(hProcess) 'Closes handle to prevent errors.
        Return buffer 'Returns the buffer.
    End Function
This should fix the PInvoke error.

Also, this method of pattern scanning will be highly uneffective (external memory reading is really slow, you'll see later after testing). Let's assume you were performing this method on a block of memory with size of 0x200000 bytes. You'll take milliseconds to scan each individual byte(let's say the speed was 1 milisecond per byte).
With 1 milisecond per byte, you'd take 1 * 0x200000 = 2097152 milliseconds = 2097,152 seconds <- Do you see how slow it is?

So, reading byte per byte won't take you anywhere. I'd suggest reading the entire block at once, and then scan it in your program.

Just like zZzeta says here:
Quote Originally Posted by zZzeta/S View Post

read the whole code section at once, scan it in your local process, translate the file address to a rva and patch it.
If you have any questions, feel free to ask.

EDIT: The functions are barely readable due to the ridiculous amount of comments I added, so, sorry about that xD.
[QUOTE=zTwix0R;10105640]
Code:
    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    ''' <param name="length">The amount of bytes to read from the specified address.</param>
    Public Function ReadBytes(ByVal P As Process, ByVal memAdr As UInt32, ByVal length As UInteger) As Byte()
        Dim buffer As Byte() = New Byte(length - 1) {} 'Creates our buffer.
        Dim hProcess as IntPtr = OpenProcess(&H1F0FFF, False, P.Id) 'Creates our process handle.
        If Not ReadProcessMemory(hProcess, New IntPtr(CLng(memAdr)), buffer, length, 0) Then buffer = Nothing 'Reads the memory in that address, and writes it to the buffer. If there was an error while reading memory, then it'll return null.
        CloseHandle(hProcess) 'Closes handle to prevent errors.
        Return buffer 'Returns the buffer.
    End Function

can u give example code how to scan for byte pattern using ur class to get address? what abut mask? thank u
[QUOTE=Trentonz;10125233]
Quote Originally Posted by zTwix0R View Post
Code:
    ''' <summary> Function used to read memory. </summary>
    ''' <param name="P">The process to read memory from.</param>
    ''' <param name="memAdr">The memory address that will be read.</param>
    ''' <param name="length">The amount of bytes to read from the specified address.</param>
    Public Function ReadBytes(ByVal P As Process, ByVal memAdr As UInt32, ByVal length As UInteger) As Byte()
        Dim buffer As Byte() = New Byte(length - 1) {} 'Creates our buffer.
        Dim hProcess as IntPtr = OpenProcess(&H1F0FFF, False, P.Id) 'Creates our process handle.
        If Not ReadProcessMemory(hProcess, New IntPtr(CLng(memAdr)), buffer, length, 0) Then buffer = Nothing 'Reads the memory in that address, and writes it to the buffer. If there was an error while reading memory, then it'll return null.
        CloseHandle(hProcess) 'Closes handle to prevent errors.
        Return buffer 'Returns the buffer.
    End Function

can u give example code how to scan for byte pattern using ur class to get address? what abut mask? thank u
I'm not giving example codes. I'll try my best to explain how it works, but I don't support leeching.
By asking that, I'm 100% sure you know little to nothing regarding VB.NET(and programming in general), so I'd advise you to learn the language first.
Posts 1–4 of 4 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us