[Tutorial] Ler Memória Processo

Iniciado por Alucard, 29 de Janeiro , 2008, 10:11:37 PM

tópico anterior - próximo tópico

0 Membros e 1 Visitante estão vendo este tópico.

Alucard

Bem a primeira coisa a se fazer é bem obvia é pegar a lista de processo que estão rodando.
Para tal, usamos a função CreateToolhelp32Snapshot para tirar um snapshot dos
processos.
Depois utilizamos Process32First para pegar o primeiro processo da lista.
E para mudar para o próximo processo usamos Process32Next.
Quando usamos Process32Frist ou Process32Next é necessário passar uma
variável do tipo, PROCESSENTRY32.
Nessa a estrutura é:

Private Type PROCESSENTRY32
  dwSize As Long                            'Tamanho da estrutura
  cntUsage As Long                          'Long usado sempre é zero
  th32ProcessID As Long                     'Identificador do processo
  th32DefaultHeapID As Long                 'Long usado sempre é zero
  th32ModuleID As Long                      'Long usado sempre é zero
  cntThreads As Long                        'Numero de thread executados pelo processo
  th32ParentProcessID As Long               'Identifica o process pai
  pcPriClassBase As Long                    'A base primária de qualquer thread criado pelo processo
  dwFlags As Long                           'Long usado sempre é zero
  szExeFile As String * MAX_PATH            'Nome do executável
End Type

Nessa estrutura tenho várias informações sobre o meu processo.
A função abaixo pega todos os processos:

'Pego listagem de todos os processos
Private Sub TodosProcessos()
  Dim hSnapShot               As Long             '
  Dim uProcess                As PROCESSENTRY32   'Estrutura dos processos
  Dim r                       As Long
 
  'Limpo a lista de processo
  Me.lstvProcessos.ListItems.Clear
 
  'pega um snapshot dos processos
  hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0&)
  uProcess.dwSize = Len(uProcess)
 
  'Pega o primeiro processo
  r = Process32First(hSnapShot, uProcess)
 
  'Enquanto estiver tiver um processo na lista fica no loop
  Do While r
   'Adiciona o id do processo na lista
   Me.lstvProcessos.ListItems.Add , , uProcess.th32ProcessID
   'Pega o nome do processo
   Me.lstvProcessos.ListItems.Item(Me.lstvProcessos.ListItems.Count).SubItems(1) = Left$(uProcess.szExeFile, IIf(InStr(1, uProcess.szExeFile, Chr$(0)) > 0, InStr(1, uProcess.szExeFile, Chr$(0)) - 1, 0))
   
   'Termina qualquer tipo de evento
   DoEvents
   
   'Pega o próximo processo
   r = Process32Next(hSnapShot, uProcess)
  Loop
     
  'Fecho o snapshot
  CloseHandle hSnapShot
End Sub

Bem agora temos os processos para podermos ler alguma parte da memória devemos
pegar as regiões onde esse processo se encontra.
Para isso usamos a API VirtualQueryEx nela é necessário passar o identificador
do processo.
Um ponteiro para o endereço base.
Um variável do tipo MEMORY_BASIC_INFORMATION.
E o tamanho da estrutura de MEMORY_BASIC_INFORMATION.

Para pegar o identificado do processo usamos OpenProcess passando a constante
PROCESS_ALL_ACCESS, depois (False) diz para não herdar o handle do processo atual,
depois passe a identificação do processso que deseja abrir.
Será retornado o valor do handle do process aberto.

O endereço base se inicia com 0, no loop é implementado na variável lPosMem
a soma do endereço encontrado com o tamanho da região.

    lPosMem = mbi.BaseAddress + mbi.regionSize

Bem será retornado o na variável do tipo MEMORY_BASIC_INFORMATION informações da região obtida.
A estrutura de MEMORY_BASIC_INFORMATION:

Private Type MEMORY_BASIC_INFORMATION
  BaseAddress As Long                         'Base do endereço de memória
  AllocationBase As Long                      'Contem o endereço base da memoria do processo
  AllocationProtect As Long                   'Mostra qual tipo de proteção utilizado
  regionSize As Long                          'Tamanho da região
  State As Long                               'Estado da Região
  Protect As Long                             'Tipo de proteçao
  lType As Long                               'Tipo de região
End Type

Para as informações AllocationProtect, State, Protect e lType. Usamos
as seguintes constantes para definir o que é cada coisa.

'State memory
Private Const MEM_COMMIT = &H1000  'Indicates committed pages for which physical storage has been allocated,
                                   'either in memory or in the paging file on disk.
                                 
Private Const MEM_FREE = &H10000   'Indicates free pages not accessible to the calling process and available
                                   'to be allocated. For free pages, the information in the AllocationBase,
                                   'AllocationProtect, Protect, and Type members is undefined.

Private Const MEM_RESERVE = &H2000 'Indicates reserved pages where a range of the process's virtual address
                                   'space is reserved without any physical storage being allocated.
                                   'For reserved pages, the information in the Protect member is undefined.
'Type Memory
Private Const MEM_IMAGE = &H1000000 'Indicates that the memory pages within the region are mapped into the
                                    'view of an image section.

Private Const MEM_MAPPED = &H40000 'Indicates that the memory pages within the region are mapped into the view
                                   'of a section.

Private Const MEM_PRIVATE = &H20000 'Indicates that the memory pages within the region are private
                                    '(that is, not shared by other processes).

'Tipos de paginação da memória
Private Const PAGE_NOACCESS = &H1
Private Const PAGE_READONLY = &H2
Private Const PAGE_READWRITE = &H4
Private Const PAGE_WRITECOPY = &H8
Private Const PAGE_EXECUTE = &H10
Private Const PAGE_EXECUTE_READ = &H20
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Const PAGE_EXECUTE_WRITECOPY = &H80

A função abaixo percorre toda a memória do processo.
Basicamente, inicia do zero depois lê o a primeira região pega o endereço da região
e soma com o tamanho da região o resultado da soma é usado com endereço base na
próxima região que será "pegada" vez que iniciar o loop.

'Pega as regiões de memoria
Private Sub RetrieveMemRegions(ByVal PID As Long)
  Dim lHandle                 As Long                           'Handle do processo
  Dim lPosMem                 As Long                           'Posição de memoria lida
  Dim lRet                    As Long                           'Parte de memoria lida
  Dim lLenMBI                 As Long                           'Tamanho da estrutura mbi
  Dim mbi                     As MEMORY_BASIC_INFORMATION       'Informação da região de memoria
  Dim si                      As SYSTEM_INFO                    'Informação do sisteam

  'initialise les tableaux
  'inicializa as tabelas
  ReDim lBaseAdress(0)
  ReDim lRegionSize(0)
 
  'Limpo minha lista de endereços
  Me.lstvPosicoesMemoria.ListItems.Clear
                 
  'obtient le handle du processus
  'obtém os handle do processo
  lHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)

  lLenMBI = Len(mbi)  'tamanho da estrutura
  GetSystemInfo si    'Obtém informações dos endereços de memória e da máquina
 
  'Enquanto o endereço atual não for maior do que o maior endereço atual
  Do While lPosMem < si.lpMaximumApplicationAddress
   'Limpo o tamanho
   mbi.regionSize = 0
   
   'obtém as informações da memória definida pelo handle processo (hProcess)
   VirtualQueryEx lHandle, ByVal lPosMem, mbi, lLenMBI
 
    With Me.lstvPosicoesMemoria
     'Adiciono o endereço de memoria int
     .ListItems.Add , , mbi.BaseAddress
     
     'Transformo o endereço para hexadecimal
     .ListItems.Item(.ListItems.Count).SubItems(1) = Hex(mbi.BaseAddress)
     
     'Pego o tamanho do região da memória
     .ListItems.Item(.ListItems.Count).SubItems(2) = mbi.regionSize
   
     'Seleciono qual é tipo de memória
     Select Case mbi.lType
      Case MEM_IMAGE
       .ListItems.Item(.ListItems.Count).SubItems(3) = "Memory Image"
   
      Case MEM_PRIVATE
       .ListItems.Item(.ListItems.Count).SubItems(3) = "Memory Private"
   
      Case MEM_MAPPED
       .ListItems.Item(.ListItems.Count).SubItems(3) = "Memory Mapped"
      End Select
   
    'Seleciono qual é o tipo de proteção
    Select Case mbi.Protect
     Case PAGE_EXECUTE
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Executavel"
   
     Case PAGE_EXECUTE_READ
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Execute+Read"
   
     Case PAGE_EXECUTE_READWRITE
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Execute + Read + Write"
   
     Case PAGE_EXECUTE_WRITECOPY
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Execute + WriteCopy"
   
     Case PAGE_NOACCESS
      .ListItems.Item(.ListItems.Count).SubItems(4) = "No Access"
   
     Case PAGE_READONLY
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Read Only"
   
     Case PAGE_READWRITE
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Read + Write"
   
     Case PAGE_WRITECOPY
      .ListItems.Item(.ListItems.Count).SubItems(4) = "Write Copy"
    End Select
   
    'Seleciono qual é o estado da memória
    Select Case mbi.State
     Case MEM_COMMIT
      .ListItems.Item(.ListItems.Count).SubItems(5) = "Memory Commit"
   
     Case MEM_FREE
      .ListItems.Item(.ListItems.Count).SubItems(5) = "Memory Free"
   
     Case MEM_RESERVE
      .ListItems.Item(.ListItems.Count).SubItems(5) = "Memory Reserve"
     
     End Select
    End With
   
    'Pego o posicionamento atual da memoria
    lPosMem = mbi.BaseAddress + mbi.regionSize
  Loop
End Sub

Bem já temos as regiões e os tamanho de cada, agora só falta ler as regiões
para isso usamos a API ReadProcessMemory novamente é necessário passar
o handle do processo, o endereço o buffer que receberá os dados o tamanho o
ultimo parâmetro não sei realmente para que que serve passo como 0.
Essa API não tem muito segredo não. No caso tô lendo o endereço na memória e
colocando tudo dentro de uma string.
Abaixo o código lê uma região de memória coloca em um buffer string e pega os
char e converte para Hex.

Public Sub ReadBytesH(ByVal PID As Long, ByVal lngOffset As Long, ByVal lngRegionSize As Long)
  Dim sBuf                      As String               'Buffer que recebe os valores da memoria
  Dim lByte                     As Long                 'Parametro ignorado em ReadProcessMemory
  Dim posicaoFinal              As Long                 'Contém o ultimo endereço a ser lido
  Dim lHandle                   As Long                 'Contém a identificação do processo
  Dim continua                  As Integer              'Verifica se continua
  Dim lenBuffer                 As Integer              'Tamanho do buffer lido
  Dim valoresHex                As String               'Contém os valores em hex do buffer lido
  Dim tmpContador               As Integer              'Contador temporário(para transforma em hex)

  'pego a posição final somando o endereço mais o tamanho da região
  posicaoFinal = lngOffset + lngRegionSize
 
  'Inicialização das variáveis
  continua = 1
  lenBuffer = 1
 
  'obtém os handle do processo
  lHandle = OpenProcess(PROCESS_ALL_ACCESS, False, PID)
 
  'Limpo a lista de dados
  Me.lstvDados.ListItems.Clear
 
  'Cria um buffer
  sBuf = String$(16, 0)
 
  While continua <> 0
   'pego os byte do endereço com um tamanho de 16
   continua = ReadProcessMemory(lHandle, lngOffset, sBuf, 16, lByte)
   
   With Me.lstvDados.ListItems
    'Adiciono o endereço em int
    .Add , , lngOffset
   
    'Converto o endereço para hexadecimal
    .Item(.Count).SubItems(1) = Hex(lngOffset)
   
    'Pego o tamanho do buffer (16)
    .Item(.Count).SubItems(4) = Len(sBuf)
   End With
   
   'Pego a string e retiro os caracteres chr(0)
   Me.lstvDados.ListItems.Item(Me.lstvDados.ListItems.Count).SubItems(2) = Replace(sBuf, Chr(0), "")
   
   'Inicializo o contador de string
   lenBuffer = 1
   
   While lenBuffer <= Len(sBuf)
    'Pego o valor(byte) 'eu acho' em int e transformo para hex
    valoresHex = valoresHex & " " & Hex(Asc(Mid(sBuf, lenBuffer, 1)))
   
    lenBuffer = lenBuffer + 1
   Wend
   
   'Adiciono os valores em hexadecimal
   Me.lstvDados.ListItems.Item(Me.lstvDados.ListItems.Count).SubItems(3) = valoresHex
   
   'Adiciono mais 16 no endereço atual
   lngOffset = lngOffset + 16
   
   'Inicializo o buffer que contem os valores em hex
   valoresHex = ""
  Wend
End Sub

Bem acho que é isso abaixo tem uma aplicação que só lê as regiões e o que tem nessas
regiões.
http://alucard.dxs.googlepages.com/MemoryView.zip