Ajuda, ler e escreve na memoria com Delphi

Iniciado por rodlg, 28 de Fevereiro , 2008, 05:36:46 PM

tópico anterior - próximo tópico

0 Membros e 2 Visitantes estão vendo este tópico.

rodlg

bom
amigos eu ate sei ler escrever na memoria de processo,offline.
mas eu tenho um duvida, como fazer isso em memoria dinamica. com pointer + offset.
se alguem saber e poder me ajudar agradeço

cebolaaa

Alocação Dinâmica em Delphi

Hi,

Particularmente, não gosto muito de Delphi. Todavia, sei que trata-se de uma linguagem relativamente fácil, poderosa e que tem sido utilizada por muitos.
Fazendo algumas comparações com a linguagem C, decidi escrever um pequeno artigo abordando a alocação dinâmica de memória em Delphi, já que havia feito um outro em C.

Retomando o que é a alocação dinâmica, podemos dizer que se trata de uma técnica que nos permite reservar uma quantidade determinada de memória que será utilizada por um variável, em tempo de execução.

Apenas para lembrar, quando declaramos uma variável como a abaixo, é reservado um determinado espaço na memória - que é retirado de uma região denominada HEAP, parte de memória livre - suficiente para esta tal variável:

var
x: Integer;


Considerando que a plataforma em que está se programando é de 32 bits, uma variável do tipo Integer - tipo que a variável "x" pertence - ocupa 4 bytes.

Este espaço é definido na compilação do programa.

O princípio da alocação dinâmica está justamente ai, variáveis estatáticas (como a variável "x" por exemplo) têm um espaço reservado a elas durante a compilação, variáveis dinâmicas (aquelas geradas por alocação, também dinâmica) têm este espaço reservado durante a execução do programa, isto é, em run-time..

Para podermos alocar memória, devemos declarar um ponteiro para um determinado tipo.

Em Delphi, declaramos um ponteiro da seguinte forma:
var
NOME_PONTEIRO: ^tipo

ou

var
NOME_PONTEIRO: Ptipo

Onde "tipo" seria o tipo de variável. Exs: integer, char, etc.

Exemplos:
var
p: ^Integer; // Um ponteiro para inteiro

var
p: PInteger; // Também um ponteiro para inteiro


Podemos utilizar o seguinte cojunto de funções:

» New e Dispose
» GetMem ou AllocMem e FreeMem.

As funções New e Dispose são utilizadas para alocar e liberar memória, respectivamente. E as outras funções, também =)

Mas qual seria a diferença? A diferença está na forma como a alocação é feita. Utilizamos a função New() para alocar memória em um ponteiro para uma variável cujo tamanho é conhecido, isto é, que o compilador consegue identificar quantos bytes este tipo de dado ocupa na memória. A função Dispose() é utilizada para liberar memória alocada em ponteiro através de New().

Já as funções GetMem() e AllocMem() são utilizadas para alocar memória em ponteiros para tipos de dado onde o compilador desconhece seus respectivos tamanhos ou se optarmos por especificar este tamanho manualmente.
A função FreeMem() é utilizada para liberar memória alocada pela função GetMem() ou AllocMem(). Mas qual a diferença entre estas últimas?
A diferença entre GetMem() e AllocMem() é que, enquanto GetMem() não preenche a memória alocada com ZEROS, AllocMem() o faz. Há, também, uma pequena diferença quanto à sintaxe das funções, que será vista mais adiante.

Vamos ver o primeiro exemplo - utilizando as funções New() e Dispose()
var
p: ^Integer;
begin
New(p);
p^ := 10;
ShowMessage('O valor de "p" é: ' + IntToStr(p^));
Dispose(p);
end;

Passo a passo:
p: ^Integer;


Declaramos um ponteiro para inteiro.

O tamanho de um inteiro é reconhecido pelo compilador, portanto, podemos utilizar a função New() para alocar memória:
New(p);

Abaixo nós atribuímos um valor qualquer à variável alocada:
p^ := 10;


Por que fizemos "p^ := 10" e não "p := 10" ?

Simplesmente pelo fato de que "p" é um ponteiro para inteiro, e não uma variável comum do tipo inteiro =)

Quando temos um ponteiro, para atribuir um valor, fazemos
NOME_PONTEIRO^ := valor;

Abaixo nós mostramos o valor da variável:
ShowMessage('O valor de "p" é: ' + IntToStr(p^));


Note novamente que utilizamos "p^" para acessarmos o valor do ponteiro. E note ainda que utilizamos uma função auxiliar - IntToStr(). Utilizamos esta função para converter um valor de Inteiro (tipo do ponteiro) para String, que é o tipo de argumento que a função ShowMessage() requere.

Após o uso do ponteiro devemos liberar a memória que foi alocada nele:
Dispose(p);



Poderíamos resumir o uso em:
New(PONTEIRO); // Alocar memória em "PONTEIRO"
Dispose(PONTEIRO); // Liberar memória previamente alocado em "PONTEIRO"

Mas o que aconteceria caso não houvesse memória suficiente para alocar no ponteiro? No caso, uma exceção seria gerada - EOutOfMemory, memória insuficiente - e teríamos que tratá-la Veja:
var
p: ^Integer;
begin
try
New(p);
except
ShowMessage('Memória insuficiente');
ExitProcess(0);
end;
p^ := 10;
ShowMessage('O valor de "p" é: ' + IntToStr(p^));
Dispose(p);
end;

Veja o trecho:
try
New(p);
except
ShowMessage('Memória insuficiente');
ExitProcess(0);
end;


O programa tenta alocar a memória necessária em "p". Caso ocorra algum erro, o programa exibe uma mensagem e encerra.

Vejamos agora como utilzar as funções GetMem(), AllocMem() e FreeMem().

Como já se sabe, GetMem() e AllocMem() são utilizadas para alocar memória.
Geralmente, utilizamos estas funções para alocar memória em variáveis do tipo Char, mais especificamente em ponteiros para Char - caracteres na linguagem C".
Muitas funções da API do Windows requerem este tipo de dado para retornar valores, como por exemplo a função GetWindowsDirectory() que retorna o diretório do Windows.

Em situação normal teríamos:
var
p:array[0..255] of char;
begin
GetWindowsDirectory(p,255);
ShowMessage(p);
end;

Note que "p" é um array do tipo "char" - uma string em C.
Com alocação dinâmica, poderíamos fazê-lo da seguinte forma:
var
p:PChar;
begin
GetMem(p,255);
GetWindowsDirectory(p,255);
ShowMessage(p);
FreeMem(p);
end;


Vamos ver o que ocorre:
p:PChar;

Como se sabe, temos um ponteiro para "char" (equivale a 'char *' em C, que também poderia ser escrito na seguinte forma:
p:^Char;

Mas eu acho mais bonito "PChar" =).

GetMem(p,255);

Acima, nós alocamos 255 bytes no ponteiro "p", ou 255 elementos no ponteiro, assim como o array declarado anteriormente:
p:array[0..255] of char;

O diretório do windows é armazenado na variável através da função:
GetWindowsDirectory(p,255);


Note que não precisamos fazer "p^", pois a função GetWindowsDirectory() requer justamente um array ou ponteiro para char como argumento. Note que o segundo parâmetro da função é a quantidade de memória que alocamos no ponteiro.

O valor é mostrado por:
ShowMessage(p);


A função ShowMessage() converte o valor no formato String em C para String em Delphi, automaticamente =)

Após o uso do ponteiro, liberamos o espaço alocado:
FreeMem(p);

Vejamos como utilizar a função AllocMem() ao invés de GetMem():
var
p:PChar;
begin
p := AllocMem(255);
GetWindowsDirectory(p,255);
ShowMessage(p);
FreeMem(p);
end;

Visualmente, a diferença é pouca. Vamos destacar a linha:
p := AllocMem(255);


Ai está diferença. Enquanto na função GetMem() é o ponteiro é passado como um argumento, não função AllocMem() atribuímos a ele, o valor de retorno - endereço para o primeiro byte alocado.

Outro detalge é que, o ponteiro "p" terá cada byte inicializado com o byte ZERO ou NULO, o que não era feito com GetMem().
A memória também é através da função FreeMem().

Se você reparar bem, não verificamos por possível falha na alocação. Assim como a função New(), caso não exista espaço suficiente para alocar uma variável utilizando as funções GetMem() ou AllocMem(), a exceção "EOutOfMemory" seria gerada.

Para verificar, fazemos:
var
p:PChar;
begin
try
p := AllocMem(255); // Note que poderíamos utilizar também: GetMem(p,255);
except
ShowMessage('Memória insuficiente');
ExitProcess(0);
end;
GetWindowsDirectory(p,255);
ShowMessage(p);
FreeMem(p);
end;


Da maneira acima, um erro na alocação culminaria com a saída do programa.

Embora seja muito recomendado o uso da função New() para alocar dinamicamente tipos de varíaveis conhecidas, já que será alocada a quantidade de bytes correta para o tipo, podemos utilizar GetMem() ou AllocMem() ao invés. Veja:
var
p:PInteger;
begin
try
GetMem(p,sizeof(Integer));
except
ShowMessage('Memória insuficiente');
ExitProcess(0);
end;
p^ := 10; // Atribuímos o valor 10 à variável
ShowMessage('O valor é: ' + IntToStr(p^)); // Mostramos o valor
FreeMem(p);
end;

Neste caso, alocamos o número de bytes que uma variável do tipo Integer ocupa:
GetMem(p,sizeof(Integer));


A função sizeof() retorna o tamanho em bytes que de tipo variável ou estrutura =)


Resumindo o uso das funções, teríamos:
GetMem(PONTEIRO,TAMANHO_EM_BYTES);
PONTEIRO := AllocMem(TAMANHO_EM_BYTES);

E para liberar a memória alocado:
FreeMem(PONTEIRO);

[TEXTO 100% RETIRADO DO SITE: http://www.wesk.org/textos/programacao/delphi/]


Alucard

Hi... não sei se é realmente o que você quer mas pelo o que entendi
você quer saber como acessar a memória de um processo para ler e escrever usando um ponteiro... fiz um tutorial de como pegar todos os endereços de um processo no tutorial explica o uso das apis...
agora para escrever na memória de um processo utiliza a api
WriteProcessMemory - http://msdn.microsoft.com/en-us/library/ms681674(VS.85).aspx

Que se parece muito com ReadProcessMemory que é explicada no tutorial
Fiz o tutorial com base no visual basic 6

http://www.darkers.com.br/forum/index.p ... 878.0.html

valeu