GNU/Linux >> Linux Esercitazione >  >> Linux

Come posso leggere da /proc/$pid/mem sotto Linux?

/proc/$pid/maps

/proc/$pid/mem mostra il contenuto della memoria di $pid mappato allo stesso modo del processo, cioè il byte all'offset x nello pseudo-file è uguale al byte all'indirizzo x nel processo. Se un indirizzo non è mappato nel processo, la lettura dall'offset corrispondente nel file restituisce EIO (Errore di ingresso/uscita). Ad esempio, poiché la prima pagina in un processo non viene mai mappata (in modo che la dereferenziazione di un NULL puntatore fallisce in modo pulito piuttosto che accedere involontariamente alla memoria effettiva), leggendo il primo byte di /proc/$pid/mem restituiscono sempre un errore di I/O.

Il modo per scoprire quali parti della memoria del processo sono mappate è leggere /proc/$pid/maps . Questo file contiene una riga per regione mappata, simile a questa:

08048000-08054000 r-xp 00000000 08:01 828061     /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0          [heap]

I primi due numeri sono i confini della regione (indirizzi del primo byte e del byte dopo l'ultimo, in esadecimale). La colonna successiva contiene i permessi, quindi ci sono alcune informazioni sul file (offset, dispositivo, inode e nome) se si tratta di un file mapping. Vedi il proc(5) pagina man o Understanding Linux /proc/id/maps per ulteriori informazioni.

Ecco uno script proof-of-concept che scarica il contenuto della propria memoria.

#! /usr/bin/env python
import re
maps_file = open("/proc/self/maps", 'r')
mem_file = open("/proc/self/mem", 'rb', 0)
output_file = open("self.dump", 'wb')
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
        output_file.write(chunk)  # dump contents to standard output
maps_file.close()
mem_file.close()
output_file.close()

/proc/$pid/mem

[Quanto segue è per interesse storico. Non si applica ai kernel correnti.]

Dalla versione 3.3 del kernel, puoi accedere a /proc/$pid/mem normalmente fintanto che accedi accedi solo agli offset mappati e hai il permesso di rintracciarlo (stesse autorizzazioni di ptrace per l'accesso in sola lettura). Ma nei kernel più vecchi c'erano alcune complicazioni aggiuntive.

Se provi a leggere dal mem pseudo-file di un altro processo, non funziona:ottieni un ESRCH (Nessun processo di questo tipo) errore.

I permessi su /proc/$pid/mem (r-------- ) sono più liberali di quanto dovrebbe essere. Ad esempio, non dovresti essere in grado di leggere la memoria di un processo setuid. Inoltre, provare a leggere la memoria di un processo mentre il processo la sta modificando potrebbe dare al lettore una visione incoerente della memoria e, peggio ancora, c'erano race condition che potevano rintracciare versioni precedenti del kernel Linux (secondo questo thread lkml, sebbene io non conosco i dettagli). Quindi sono necessari ulteriori controlli:

  • Il processo che vuole leggere da /proc/$pid/mem deve allegare al processo utilizzando ptrace con il PTRACE_ATTACH bandiera. Questo è ciò che fanno i debugger quando iniziano a eseguire il debug di un processo; è anche ciò che strace fa alle chiamate di sistema di un processo. Una volta che il lettore ha finito di leggere da /proc/$pid/mem , dovrebbe staccarsi chiamando ptrace con PTRACE_DETACH bandiera.
  • Il processo osservato non deve essere in esecuzione. Normalmente chiama ptrace(PTRACE_ATTACH, …) interromperà il processo di destinazione (invia un STOP segnale), ma c'è una race condition (la consegna del segnale è asincrona), quindi il tracciante dovrebbe chiamare wait (come documentato in ptrace(2) ).

Un processo eseguito come root può leggere la memoria di qualsiasi processo, senza dover chiamare ptrace , ma il processo osservato deve essere interrotto, altrimenti la lettura restituirà comunque ESRCH .

Nel sorgente del kernel Linux, il codice che fornisce voci per processo in /proc è in fs/proc/base.c e la funzione per leggere da /proc/$pid/mem è mem_read . Il controllo aggiuntivo viene eseguito da check_mem_permission .

Ecco alcuni esempi di codice C da allegare a un processo e leggerne un pezzo di mem file (controllo degli errori omesso):

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);

Ho già pubblicato uno script proof-of-concept per scaricare /proc/$pid/mem su un altro thread.


Questo comando (da gdb) scarica la memoria in modo affidabile:

gcore pid

I dump possono essere grandi, usa -o outfile se la tua directory attuale non ha abbastanza spazio.


Quando esegui cat /proc/$$/mem la variabile $$ viene valutato da bash che inserisce il proprio pid. Quindi esegue cat che ha un pid diverso. Ti ritroverai con cat cercando di leggere la memoria di bash , il suo processo genitore. Poiché i processi non privilegiati possono solo leggere il proprio spazio di memoria, questo viene negato dal kernel.

Ecco un esempio:

$ echo $$
17823

Nota che $$ restituisce 17823. Vediamo di che processo si tratta.

$ ps -ef | awk '{if ($2 == "17823") print}'
bahamat  17823 17822  0 13:51 pts/0    00:00:00 -bash

È il mio guscio attuale.

$ cat /proc/$$/mem
cat: /proc/17823/mem: No such process

Anche qui $$ valuta 17823, che è la mia shell. cat non riesco a leggere lo spazio di memoria della mia shell.


Linux
  1. Linux:come leggere da /proc/$pid/mem sotto Linux?

  2. Linux – In che modo il collegamento simbolico /proc//exe differisce dai collegamenti simbolici ordinari?

  3. Linux:come ottenere l'indirizzo IPv4 per un'interfaccia da /proc?

  4. Linux – Collegamento di /proc/mnt a /proc/mounts?

  5. Linux:come scoprire lo spazio dei nomi di un particolare processo?

Come uccidere un processo in Linux

Linux:ottenere informazioni sull'utilizzo della memoria di un processo da /proc/pid/smaps?

Linux:come verificare se un dispositivo a blocchi è di sola lettura da /sys o /proc?

Una guida al file system '/proc' in Linux

/proc/cpuinfo e /proc/meminfo in Linux

Come impostare lo swapiness per processo per Linux?