terça-feira, 1 de julho de 2008

Bem,
nesse tutorial vou mostrar como visualizo o conteúdo de um processo na memória.

A primeira coisa a se fazer é bem obvia é pegar a lista de todos os processos 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.
Abaixo uma função que pega todos os processos que estão rodando.

'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, para ter livre acesso no processo, 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 que é 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 State(Estado), Protect(Proteção) e lType(qual é o tipo da região).
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).

'Tipo de proteção
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 como endereço base na
próxima região que será "pegada" vez que iniciar o do zero novamente.

'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 conteúdo delas
Valeuw!

http://alucard.dxs.googlepages.com/MemoryView.zip

Nenhum comentário: