Lire/écrire/rechercher dans la mémoire virtuelle d'un processus


Propriétés du code


Date de création : 02/01/2007 à 00:33:00
7 Commentaire(s)
  violent_ken

 

Présentation


Ce code permet :
-de récupérer, sous forme de string, un nombre n désiré de bytes à un offset désiré, d'une partie de la mémoire virtuelle d'un processus (fonction ReadBytes)
-d'écrire une string à un offset précis dans la mémoire virtuelle d'un processus (fonction WriteBytes)
-de récupérer la liste des offsets contenant une string désirée (fonction de recherche qui est SearchForStringMemory)

Note : ne pas oublier de récupérer les privileges pour avoir accès à tous les processus
Note2 : ne renvoie rien et n'écrit rien si l'on pointe un offset inaccessible

 

Code


Option Explicit


'-------------------------------------------------------
'CONSTANTES
'-------------------------------------------------------
'constantes d'accès à un processus (pour OpenProcess)
Private Const SYNCHRONIZE                  As Long = &H100000
Private Const STANDARD_RIGHTS_REQUIRED      As Long = &HF0000 'aussi pour d'autres accès que les processus
Private Const PROCESS_ALL_ACCESS            As Long = (STANDARD_RIGHTS_REQUIRED Or _
                                            SYNCHRONIZE Or &HFFF)
Private Const PROCESS_VM_READ              As Long = 16
Private Const PROCESS_VM_WRITE              As Long = &H20
Private Const PROCESS_VM_OPERATION          As Long = &H8
Private Const PROCESS_QUERY_INFORMATION    As Long = 1024
Private Const PROCESS_READ_WRITE_QUERY      As Long = PROCESS_VM_READ + PROCESS_VM_WRITE + PROCESS_VM_OPERATION + PROCESS_QUERY_INFORMATION

'constantes utilisées pour déterminer le type de zone mémoire d'un processus
Private Const MEM_PRIVATE                  As Long = &H20000
Private Const MEM_COMMIT                    As Long = &H1000

Private Const INVALID_HANDLE_VALUE          As Long = -1


'-------------------------------------------------------
'APIs
'-------------------------------------------------------
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
Private Declare Sub GetSystemInfo Lib "kernel32" (lpSystemInfo As SYSTEM_INFO)
Private Declare Function GetCurrentProcess Lib "kernel32.dll" () As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, ByVal lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function VirtualQueryEx& Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long)



'-------------------------------------------------------
'TYPES ET ENUMS
'-------------------------------------------------------
Private Type MEMORY_BASIC_INFORMATION ' 28 bytes
    BaseAddress As Long
    AllocationBase As Long
    AllocationProtect As Long
    RegionSize As Long
    State As Long
    Protect As Long
    lType As Long
End Type
Private Type SYSTEM_INFO ' 36 Bytes
    dwOemID As Long
    dwPageSize As Long
    lpMinimumApplicationAddress As Long
    lpMaximumApplicationAddress As Long
    dwActiveProcessorMask As Long
    dwNumberOrfProcessors As Long
    dwProcessorType As Long
    dwAllocationGranularity As Long
    wProcessorLevel As Integer
    wProcessorRevision As Integer
End Type




'-------------------------------------------------------
'FUNCTIONS AND PROCEDURES
'-------------------------------------------------------


'-------------------------------------------------------
'lit lSize bytes dans la zone virtuelle de la mémoire d'un processus
'demande un PID
'-------------------------------------------------------
Public Function ReadBytes(ByVal PID As Long, ByVal lngOffset As Long, ByVal lngSize As Long) As String
Dim sBuf As String
Dim lByte As Long
Dim lHandle As Long
   
    '/!\ Un long suffit pour pouvoir parcourir l'ensemble des offsets possibles
    'car la taille max de la zone virtuelle est 2Go
   
    'créé un buffer
    sBuf = String$(lngSize, 0)
   
    'obtient le handle du processus
    lHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)
   
    'lit les bytes et stocke dans le buffer
    ReadProcessMemory lHandle, lngOffset, sBuf, lngSize, lByte
   
    'referme le handle
    CloseHandle lHandle
   
    ReadBytes = sBuf
End Function

'-------------------------------------------------------
'lit lSize bytes dans la zone virtuelle de la mémoire d'un processus
'demande un handle
'-------------------------------------------------------
Public Function ReadBytesH(ByVal lHandle As Long, ByVal lngOffset As Long, ByVal lngSize As Long) As String
Dim sBuf As String
Dim lByte As Long
Dim lRet As Long
   
    '/!\ Un long suffit pour pouvoir parcourir l'ensemble des offsets possibles
    'car la taille max de la zone virtuelle est 2Go
   
    'créé un buffer
    sBuf = String$(lngSize, 0)
   
    'lit les bytes et stocke dans le buffer
    lRet = ReadProcessMemory(lHandle, lngOffset, sBuf, lngSize, lByte)
   
    ReadBytesH = sBuf
End Function

'-------------------------------------------------------
'écrit une string dans la mémoire virtuelle d'un processus
'-------------------------------------------------------
Public Function WriteBytes(ByVal PID As Long, ByVal lngOffset As Long, ByVal strStringToWrite As String) As Long
Dim lHandle As Long

    'obtient le handle du processus
    lHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)

    WriteBytes = WriteProcessMemory(lHandle, lngOffset, ByVal strStringToWrite, Len(strStringToWrite), 0&)
   
    'referme le handle
    CloseHandle lHandle
End Function

'-------------------------------------------------------
'écrit une string dans la mémoire virtuelle d'un processus (à partir d'un handle)
'-------------------------------------------------------
Public Function WriteBytesH(ByVal lngHandle As Long, ByVal lngOffset As Long, ByVal strStringToWrite As String) As Long
'écrit en mémoire
    WriteBytesH = WriteProcessMemory(lngHandle, lngOffset, ByVal strStringToWrite, Len(strStringToWrite), 0&)
End Function

'-------------------------------------------------------
'obtient les différentes zones mémoire d'un processus utilisées dans la zone virtuelle
'stocke de 1 à Ubound
'-------------------------------------------------------
Public Sub RetrieveMemRegions(ByVal PID As Long, ByRef lBaseAdress() As Long, ByRef lRegionSize() As Long)
Dim lHandle As Long
Dim lPosMem As Long
Dim lRet As Long
Dim lLenMBI As Long
Dim mbi As MEMORY_BASIC_INFORMATION
Dim si As SYSTEM_INFO

    'initialise les tableaux
    ReDim lBaseAdress(0)
    ReDim lRegionSize(0)
                   
    'obtient le handle du processus
    lHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)

    lLenMBI = Len(mbi)  'taille de la structure
    GetSystemInfo si    'obtient les infos sur les adresses de début et de fin de la plage mémoire maximum
   
    lPosMem = si.lpMinimumApplicationAddress  'adresse la plus petite ==> part de là
   
    Do While lPosMem < si.lpMaximumApplicationAddress 'tant que l'adresse est inférieure à l'adresse maximale
        mbi.RegionSize = 0
       
        'obtient les infos sur les régions mémoire du processus définit par son handle hProcess
        lRet = VirtualQueryEx(lHandle, ByVal lPosMem, mbi, lLenMBI)
       
        If lRet = lLenMBI Then
       
            If (mbi.lType = MEM_PRIVATE) And (mbi.State = MEM_COMMIT) Then
                'alors utilisé par le processus
               
                If mbi.RegionSize > 0 Then
                    'région non nulle, alors on la stocke dans les tableaux résultats
                    'les redimensionne
                    ReDim Preserve lBaseAdress(UBound(lBaseAdress) + 1)
                    ReDim Preserve lRegionSize(UBound(lRegionSize) + 1)
                    'stocke à la fin
                    lRegionSize(UBound(lRegionSize)) = mbi.RegionSize
                    lBaseAdress(UBound(lBaseAdress)) = mbi.BaseAddress
                End If
               
            End If
            'continue la recherche des régions (ajoute la taille de la région à l'adresse de départ ==> donne la prochaine adresse de départ)
           
            On Error GoTo ErrCapacityGestion  'dépassement de capacité pour la dernière adresse+regiosize
           
            lPosMem = mbi.BaseAddress + mbi.RegionSize    'fait l'ajout
       
        Else
            'recherche terminée
            Exit Do
        End If
    Loop
   
ErrCapacityGestion:
  CloseHandle lHandle 'ferme le handle du processus
End Sub

'-------------------------------------------------------
'fonction de recherche de string dans un processus
'de 1 à Ubound
'-------------------------------------------------------
Public Sub SearchForStringMemory(ByVal PID As Long, ByVal sMatch As String, ByVal bCasse As Boolean, ByRef tRes() As Long)
'Utilisation de l'API CreateFile et ReadFileEx pour une lecture rapide
Dim x As Long
Dim bytAsc As Byte
Dim strBufT As String
Dim i As Long
Dim lHandle As Long
Dim LB() As Long
Dim LS() As Long

    On Error GoTo ErrGestion

    'initialise le tableau
    ReDim tRes(0)

    'on obtient les différentes régions de la mémoire du processus
    RetrieveMemRegions PID, LB(), LS()

    'on obtient le handle depuis le PID
    lHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)

    If bCasse = False Then sMatch = LCase$(sMatch)  'ne cherche que les minuscules

    For x = 1 To UBound(LS())  'pour chaque zone mémoire
   
        'obtient la string de la plage visualisée
        strBufT = ReadBytesH(lHandle, LB(x), LS(x))
       
        If bCasse = False Then strBufT = LCase$(strBufT)    'cherche que des minuscules (pas de casse respectée)
       
        'tant que la string contient le match
        While InStr(1, strBufT, sMatch, vbBinaryCompare) <> 0
            'trouvé une string ==> l'ajoute
            ReDim Preserve tRes(UBound(tRes) + 1)
                           
            tRes(UBound(tRes)) = LB(x) + InStr(1, strBufT, sMatch, vbBinaryCompare) + LS(x) - Len(strBufT) - 1
           
            'raccourci le buffer
            strBufT = Right$(strBufT, Len(strBufT) - InStr(1, strBufT, sMatch, vbBinaryCompare) - Len(sMatch) + 1)
        Wend
       
        DoEvents    'rend la main
       
    Next x
       
    Let strBufT = vbNullString

ErrGestion:
    'referme le handle
    CloseHandle lHandle
End Sub


 
 

Modifier le code

Seul les admins et l'auteur du code lui même peuvent modifier ce code.

 

Commentaires


De MadMatt le 02/01/2007 à 01:25


Ah la on reconnait un bout de ton éditeur héxa ^^

En tout cas c'est un code très interessant

 

De violent_ken le 02/01/2007 à 10:28


Cà fait plaisir de poster un bout de son projet quand ce dernier n'est pas encore fini ^^



Par contre je pense à un truc, certaines déclarations d'APIs (ReadProcessMemory par exemple) peuvent être différentes (entre plusieurs sources) en ce qui concerne le type des arguments souhaités.

Exemple : j'ai laissé du Any pour le buffer (ByVal lpBuffer As Any) alors que d'autre mettrons directement du string.

Donc va falloir faire gaffe si l'on utilise une seule déclaration pour plusieurs fonctions.



Autre chose, niveau optimisation : j'ai utilisé une méthode de "raccourcissement de buffer" pour détecter plusieurs occurences d'une même string dans une grande string. C'est à dire que si on trouve une occurence de la string à partir de la gauche (avec Instr) alors on découpe la string (on enlève la partie de la gauche) et on ré-essaye un Instr.... c'est simple à coder, mais il y a surement plus rapide.

@+

 

De MadMatt le 02/01/2007 à 13:25


Ah ouais ok j'ai pigé l'optimisation, effectivement ça ne peut etre que plus rapide.
Sinon pour trouver plus rapide, y'a le DoEvents ? Est-il vraiment nécessaire ? Enfin je veux dire est ce que l'execution de cette fonction peut dépasser 1 seconde par exemple
pour des déclarations d'api, effectivement faudra faire gaffe

 

De violent_ken le 02/01/2007 à 13:28


Disons qu'il y a un DoEvents par zone mémoire, donc au en gros de 10 à 300 DoEvents d'appelés. Soit en l'enlève complètement (mais bon, il est nécessaire quand la recherche s'effectue sur une string petite) , soit on remplace par If (x mod 10)=0 Then DoEvents.


De toutes façons, la procédure de recherche n'est en fait qu'une application des procédure de lecture, d'écriture et de listing des zones mémoire.

 

De MadMatt le 02/01/2007 à 13:35


ok ben si c'est nécessaire et que ça s'execute pas si souvent alors autant le laisser

 

De sebdraluorg le 02/01/2007 à 17:13


Salut,

Code très interessant! merci violent_ken ^^

Pour les Api genre ReadProcessMemory qui peuvent etre utilisés différement on peut mettre soit As Any et "tout" passe soit As Long et quand c'est pas un long on fait un VarPtr ou StrPtr...
Il faudrait qu'on tranche pour une methode qu'on appliquera dans tout le projet...

On peut peut etre aussi faire des test de rapidité pour voir si c'est plus rapide de passer un Any ou bien de faire un VarPtr...

Pour le DoEvents perso je n'en mettrais pas dans ce genre de boucle ou alors avec If X mod 100

++

 

De violent_ken le 02/01/2007 à 18:53


Salut, alors oui, je pense également qu'il faudrait se décider si l'on laisse Any partout ou pas.

Et faudra faire un bench aussi ^^



Pour le DoEvents, en fait çà dépend.
Le x parcours chaque zone mémoire (le buffer ayant la taille de la zone mémoire).
Donc en fonction du nombre de zones mémoire, le nombre de DoEvents éxécutés sera différent.

En moyenne, c'est environ 200.



Par contre, si l'on recherche une string très courte (1 caractère ou 2), le nombre d'opérations sur les strings sera très conséquent, et il serait judicieux de laisser la main de temps en temps (car le temps nécessaire au parcours de toute la mémoire sera assez grand)

@+

 

Ajouter un commentaire


Vous devez être connecté pour pouvoir poster un commentaire.

 
 

Valid HTML 4.01 Transitional Valid CSS

Site web de Vb System Library version 1.3
Developpement et design réalisé par : Matthieu Napoli (MadMatt)
© 2007 Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
Temps d'execution de la page : 0.054 s
www.mnapoli.fr