Obtenir les plages mémoires utilisées par un processus


Propriétés du code


Date de création : 07/12/2006 à 14:44:00
15 Commentaire(s)
  violent_ken

 

Présentation


Ce code permet d'obtenir les adresses et les tailles des différentes plages mémoire de la zone virtuelle d'un processus qui sont occupées.

Exemple d'utilisation :

Private Const PID = 2588

Private Sub Command1_Click()
Dim lAdd() As Long, lSiz() As Long, x As Long, s As String

RetrieveMemRegions PID, lAdd(), lSiz()
s = "Processus=[" & PID & "]" & vbNewLine

For x = 1 To UBound(lAdd())
s = s & "Adresse=[" & lAdd(x) & "] Size=[" & lSiz(x) & "]"
Next x

MsgBox s
End Sub

 

Code


Option Explicit

'-------------------------------------------------------
'//MODULE DE GESTION DES PROCESSUS ET DE LEUR MEMOIRE
'-------------------------------------------------------


'-------------------------------------------------------
'CONSTANTES
'-------------------------------------------------------
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 MEM_PRIVATE                   As Long = &H20000
Private Const MEM_COMMIT                    As Long = &H1000


'-------------------------------------------------------
'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 VirtualQueryEx& Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long)



'-------------------------------------------------------
'TYPES ET ENUMS
'-------------------------------------------------------
Public 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
Public 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


'-------------------------------------------------------
'obtient les différentes zones mémoire d'un processus utilisées dans la zone virtuelle
'-------------------------------------------------------
Public Sub RetrieveMemRegions(ByVal lPid 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, lPid)

    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


 
 

Modifier le code

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

 

Commentaires


De MadMatt le 07/12/2006 à 20:13


Excellent ça, je connaissais pas. ça peut être bien pratique pour faire un "explorateur" de mémoire vive, savoir à quel processus appartient tel bloc de mémoire... J'en ai beaucoup appris merci !

 

De violent_ken le 07/12/2006 à 20:30


Content que çà serve ;)
@+

 

De sebdraluorg le 21/04/2007 à 14:01


Yep j'cool comme fonction!

Sais tu comment on peut recuperer l'ensemble des string sans les connaitre au depart comme dans l'onglet memory de ProcessXP ?

++

 

De violent_ken le 21/04/2007 à 14:12


Oui ;)

En fait j'avais étudié un peu la question et il semble que ProcessXP fasse tout simplement une recherche dans la mémoire de string entières...


Donc j'ai ce qu'il faut ^^ : c'est la fonction SearchForStringMemory de ce code http://vbsystemlibrary.free.fr/code.php?ID=29.
C'est plus lent que ProcessXP (car VB), mais le résultat est le même (ce qui confirme que c'est bien la même méthode utilisée)

@+

 

De violent_ken le 21/04/2007 à 14:14


En fait pas du tout, la fonction que je viens de citer cherche juste une string...

Celle dont je voulais parler n'a jamais été postée, la voilà :


'=======================================================
'fonction de recherche de string complètes dans un processus
'ne cherche pas une string en particulier, mais toutes les strings qui ressemblent à des mots
'stocke dans un tableau de 1 à Ubound
'=======================================================
Public Sub SearchEntireStringMemory(ByVal PID As Long, ByVal lMinimalLength As Long, ByVal bSigns As Boolean, ByVal bMaj As Boolean, ByVal bMin As Boolean, ByVal bNumbers As Boolean, ByVal bAccent As Boolean, ByRef lngRes() As Long, ByRef strRes() As String, Optional PGB As pgrBar)
Dim strCtemp As String
Dim x As Long
Dim lngLen As Long
Dim bytAsc As Byte
Dim strBuffer As String
Dim curByte As Currency
Dim i As Long
Dim tRes() As T_RESULT
Dim lHandle As Long
Dim LB() As Long
Dim LS() As Long

On Error GoTo ErrGestion

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

'calcule la taille max (lngLen)
lngLen = 0
For i = 1 To UBound(LS())
lngLen = lngLen + LS(i)
Next i

If Not (PGB Is Nothing) Then
'on initialise la progressabr
PGB.Min = 0
PGB.Value = 0
PGB.Max = UBound(LS())
End If

'on obtient le handle depuis le PID
lHandle = GetValidHandle(PID)

'initialise le tableau
ReDim tRes(0)

'vérifie que le handle est valide
If lHandle = INVALID_HANDLE_VALUE Then
ReDim lngRes(0)
ReDim strRes(0)
Exit Sub
End If

strCtemp = vbNullString: x = 1: curByte = 0

'pour chaque zone mémoire
For x = 1 To UBound(LS())

'on récupère la string complète de cette zone mémoire
strBuffer = Me.ReadBytesH(lHandle, LB(x), LS(x))

strCtemp = vbNullString

'effectue la recherche dans la string
For i = 0 To LS(x) - 1
If (i Mod 300000) = 0 Then DoEvents 'rend un peu la main
bytAsc = Asc(Mid$(strBuffer, i + 1, 1)) 'prend un byte

If IsCharConsideredInAString(bytAsc, bSigns, bMaj, bMin, bNumbers, bAccent) Then
'caractère x est valide
strCtemp = strCtemp & Chr(bytAsc)
Else
strCtemp = Trim$(strCtemp)
If Len(strCtemp) > lMinimalLength Then
'trouvé la chaine correspondante
ReDim Preserve tRes(UBound(tRes) + 1)
tRes(UBound(tRes)).curOffset = i + LB(x) - Len(strCtemp) + 1
tRes(UBound(tRes)).strString = strCtemp
End If
strCtemp = vbNullString
End If
Next i

If Len(strCtemp) > lMinimalLength Then
'trouvé la dernière chaine possible (dernier byte compris dans cette chaine)
ReDim Preserve tRes(UBound(tRes) + 1)
tRes(UBound(tRes)).curOffset = LS(x) + LB(x) - Len(strCtemp) + 1
tRes(UBound(tRes)).strString = strCtemp
End If

If Not (PGB Is Nothing) Then PGB.Value = x 'refresh progressbar
DoEvents 'rend la main
Next x


If Not (PGB Is Nothing) Then PGB.Value = PGB.Max

Let strBuffer = vbNullString
CloseHandle lHandle 'ferme le handle du process

'maintenant, stocke dans les arrays de sortie
ReDim lngRes(UBound(tRes()))
ReDim strRes(UBound(tRes()))
For i = 1 To UBound(tRes())
If (i Mod 2000) = 0 Then DoEvents 'rend la main
lngRes(i) = tRes(i).curOffset
strRes(i) = tRes(i).strString
Next i

Exit Sub

ErrGestion:

CloseHandle lHandle 'ferme le handle du process
clsERREUR.AddError "mdlDisk.SearchStringInFile", True
End Sub

@+

 

De sebdraluorg le 21/04/2007 à 14:16


erf lol c'est sur cette source la que je voulais poster!
merci, mais j'y etais pas arrivé en fait j'ai du mal m'y prendre...

 

De sebdraluorg le 21/04/2007 à 14:17


aha ok lol je comprend mieux vais voir avec cette fonction!
Merci ^^

 

De violent_ken le 21/04/2007 à 14:21


Voici quelques compléments sur ce code :

-PGB est un objet de type pgrBar (ma progressbar stylée XP) ==> facultatif

-clsERREUR pour la gestion des erreurs ==> facultatif

-ReadBytesH ==> fonction donnée ici http://vbsystemlibrary.free.fr/code.php?ID=29

-GetValidHandle ==>
'=======================================================
'renvoie un handle de processus permettant la lecture écriture en mémoire
'=======================================================
Private Function GetValidHandle(ByVal PID As Long) As Long
GetValidHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)
End Function

-IsCharConsideredInAString ==>
'=======================================================
'détermine si un byte est considéré comme convenable en fonction
'des paramètres Afficher : min, MAJ, nbres, signes
'function utilisée directement avec les procédures de SearchStringIn...
'=======================================================
Private Function IsCharConsideredInAString(ByVal bytChar As Byte, ByVal bSigns As Boolean, ByVal bMaj As Boolean, ByVal bMin As Boolean, ByVal bNumbers As Boolean, ByVal bAccent As Boolean) As Boolean
If bMaj Then
IsCharConsideredInAString = (bytChar >= 65 And bytChar <= 90)
If IsCharConsideredInAString Then Exit Function
End If
If bMin Then
IsCharConsideredInAString = (bytChar >= 97 And bytChar <= 122)
If IsCharConsideredInAString Then Exit Function
End If
If bNumbers Then
IsCharConsideredInAString = (bytChar >= 48 And bytChar <= 57)
If IsCharConsideredInAString Then Exit Function
End If
If bSigns Then
IsCharConsideredInAString = (bytChar >= 33 And bytChar <= 47) Or _
(bytChar >= 58 And bytChar <= 64) Or (bytChar >= 91 And bytChar <= 96) Or _
(bytChar >= 123 And bytChar <= 126)
If IsCharConsideredInAString Then Exit Function
End If
If bytChar = 32 Or bytChar = 39 Then 'espace ou apostrophe
IsCharConsideredInAString = True
If IsCharConsideredInAString Then Exit Function
End If
If bAccent Then
IsCharConsideredInAString = (bytChar >= 192)
If IsCharConsideredInAString Then Exit Function
End If

IsCharConsideredInAString = False
End Function




Bon, je pense que tout çà est fortement optimisable, mais sinon çà marche et dans le principe c'est çà ;)
@+

 

De sebdraluorg le 21/04/2007 à 14:27


ah ok wai tu fais une verif sur chaque bytes...
Je pensais qu'on pouvait identifier le type d'une region...
enfin merci c'est ce que je cherchais :)

++

 

De violent_ken le 21/04/2007 à 14:30


Ouep, c'est un peu barbare ;) Des strings peuvent se cacher n'importe où dans la mémoire, donc recherche de partout.

Mais bon, en optimisant le tout, je pense que l'on peut arriver au niveau de ProcessXP (qui n'est pas très rapide, en fait)

@+

 

De sebdraluorg le 21/04/2007 à 14:36


yep je t'ai envoyer un mail sur vbfrance avec le process Viewer dont mad t'as parlé...
Donc je comptais mettre un onglet memory dans les proprietes du processus donc c'est exactement ce qu'il fallait.
Pour la vitesse j'ai pas encore essayer on verra si c'est vraiment genant on appel Eb ;)

Vais tester pour voir ce que ca donne ^^

++

 

De sebdraluorg le 21/04/2007 à 14:57


eh me manque le Type T_RESULT ??

 

De violent_ken le 21/04/2007 à 15:07


Oups, désolé :

Private Type T_RESULT
curOffset As Currency
strString As String
End Type


Par contre, ce type perso avait été créé pour les recherches dans les fichiers/disques/mémoire, donc le type Currency n'est plus utile pour la mémoire uniquement (car plage mémoire limitée à 2Go ==> rentre dans un Long)

@+

 

De sebdraluorg le 21/04/2007 à 20:00


Ok merci

J'ai fais quelques tests d'optimisation...

En fait tu recupere les bytes avec ReadProcessMemory dans une variable string
puis tu refais chaque fois un asc() + un Mid() pour avoir le bytChar

Mais tu peux demander direct un ByteArray() a ReadProcessMemory et faire tes comparaisons direct sur le tableau de byte

J'ai testé ca me semble deja bcp plus rapide meme si c'est pas encore top...
voir exemple ici http://systemzeb.free.fr/Soft/ProcessMEM.zip

pour la fonction voici ce que ca donne:

Public Function SearchEntireStringMemoryB(ByVal PID As Long, ByVal lMinimalLength As Long, ByVal bSigns As Boolean, ByVal bMaj As Boolean, ByVal bMin As Boolean, ByVal bNumbers As Boolean, ByVal bAccent As Boolean, ByRef strRes As String) As Long

Dim strCtemp As String
Dim x As Long
Dim bytAsc As Byte
Dim ByteBuff() As Byte
Dim i As Long
Dim lHandle As Long
Dim LB() As Long
Dim LS() As Long
Dim lngLen As Long
Dim lLen As Long

RetrieveMemRegions PID, LB(), LS()
lngLen = 0
For i = 1 To UBound(LS())
lngLen = lngLen + LS(i)
Next i

lHandle = GetValidHandle(PID)

If lHandle = INVALID_HANDLE_VALUE Then
Exit Function
End If

strCtemp = vbNullString

For x = 1 To UBound(LS())

ReDim ByteBuff(LS(x))
ReadProcessMemory lHandle, LB(x), VarPtr(ByteBuff(0)), LS(x), lLen
strCtemp = vbNullString

For i = 0 To lLen - 1
If IsCharConsideredInAString(ByteBuff(i), bSigns, bMaj, bMin, bNumbers, bAccent) Then
strCtemp = strCtemp & Chr(ByteBuff(i))
Else
strCtemp = Trim$(strCtemp)
If Len(strCtemp) > lMinimalLength Then
strRes = strRes & strCtemp & vbCrLf
End If
strCtemp = vbNullString
End If

Next i
Next x

Erase ByteBuff
CloseHandle lHandle

Exit Function

ErrGestion:

CloseHandle lHandle

End Function

 

De violent_ken le 21/04/2007 à 21:14


"En fait tu recupere les bytes avec ReadProcessMemory dans une variable string
puis tu refais chaque fois un asc() + un Mid() pour avoir le bytChar" ==> Tu as entièrement raison, cette erreur convertir inutilement des bytes en string ou inversement, je l'ai déjà faite plusieurs fois...

@+

 

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.017 s
www.mnapoli.fr