/proc/$pid/maps
/proc/$pid/mem
mostra o conteúdo da memória de $ pid mapeado da mesma forma que no processo, ou seja, o byte no deslocamento x no pseudo-arquivo é o mesmo que o byte no endereço < em> x no processo. Se um endereço não for mapeado no processo, a leitura do deslocamento correspondente no arquivo retornará EIO
(erro de entrada / saída). Por exemplo, como a primeira página em um processo nunca é mapeada (para que a referência a um ponteiro NULL
falhe de forma limpa, em vez de acessar a memória real acidentalmente), ler o primeiro byte de /proc/$pid/mem
sempre gera um erro de E / S. p>
A maneira de descobrir quais partes da memória do processo estão mapeadas é ler /proc/$pid/maps
. Este arquivo contém uma linha por região mapeada, com esta aparência:
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]
Os dois primeiros números são os limites da região (endereços do primeiro byte e byte após o último, em hexa). A próxima coluna contém as permissões, então há algumas informações sobre o arquivo (offset, device, inode e name) se este for um mapeamento de arquivo. Veja a página do manual proc(5)
ou Compreendendo o Linux / proc / id / maps para obter mais informações.
Aqui está um script de prova de conceito que despeja o conteúdo de sua própria memória.
#! /usr/bin/env python
import re
maps_file = open("/proc/self/maps", 'r')
mem_file = open("/proc/self/mem", 'r', 0)
for line in maps_file.readlines(): # for each mapped region
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
if m.group(3) == 'r': # if this is a readable region
start = int(m.group(1), 16)
end = int(m.group(2), 16)
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
print chunk, # dump contents to standard output
maps_file.close()
mem_file.close()
/proc/$pid/mem
Se você tentar ler o pseudo arquivo mem
de outro processo, ele não funcionará: você receberá um erro ESRCH
(Nenhum processo desse tipo).
As permissões em /proc/$pid/mem
( r--------
) são mais liberais do que deveria ser o caso. Por exemplo, você não deveria poder ler a memória de um processo setuid. Além disso, tentar ler a memória de um processo enquanto o processo está modificando isso poderia dar ao leitor uma visão inconsistente da memória, e pior, havia condições de corrida que poderiam rastrear versões mais antigas do kernel Linux (de acordo com este encadeamento lkml , embora eu não saiba os detalhes). Por isso, são necessárias verificações adicionais:
- O processo que deseja ler de
/proc/$pid/mem
deve anexar ao processo usandoptrace
com o sinalizadorPTRACE_ATTACH
. Isso é o que os depuradores fazem quando começam a depurar um processo; é também o questrace
faz com as chamadas do sistema de um processo. Depois que o leitor terminar de ler/proc/$pid/mem
, ele deverá ser desanexado chamandoptrace
com o sinalizadorPTRACE_DETACH
. - O processo observado não deve estar em execução. Normalmente, chamar
ptrace(PTRACE_ATTACH, …)
interromperá o processo de destino (envia um sinalSTOP
), mas há uma condição de corrida (a entrega do sinal é assíncrona), portanto o rastreador deve chamarwait
(conforme documentado emptrace(2)
).
Um processo executado como root pode ler a memória de qualquer processo, sem precisar chamar ptrace
, mas o processo observado deve ser interrompido ou a leitura ainda retornará ESRCH
.
Na origem do kernel do Linux, o código que fornece entradas por processo em /proc
está em fs/proc/base.c
, e a função para ler a partir de /proc/$pid/mem
é mem_read
. A verificação adicional é realizada por check_mem_permission
.
Aqui está um exemplo de código C para anexar a um processo e ler um fragmento do arquivo mem
(verificação de erro omitida):
sprintf(mem_file_name, "/proc/%d/mem", pid);
mem_fd = open(mem_file_name, O_RDONLY);
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, NULL, 0);
lseek(mem_fd, offset, SEEK_SET);
read(mem_fd, buf, _SC_PAGE_SIZE);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
Eu já publiquei um script de prova de conceito para jogando /proc/$pid/mem
em outro thread .