/proc/$pid/maps
/proc/$pid/memmemperlihatkan isi memori $ pid yang dipetakan dengan cara yang sama seperti dalam proses, yaitu byte pada offset x dalam file pseudo sama dengan byte pada alamat x dalam proses. Jika alamat tidak dipetakan dalam proses, bacalah dari offset yang sesuai dalam file yang dikembalikan EIO(Kesalahan input / output). Sebagai contoh, karena halaman pertama dalam suatu proses tidak pernah dipetakan (sehingga dereferencing NULLpointer gagal dengan bersih daripada mengakses memori yang sebenarnya), membaca byte pertama /proc/$pid/memselalu menghasilkan kesalahan I / O.
Cara untuk mengetahui bagian mana dari memori proses yang dipetakan adalah dengan membaca /proc/$pid/maps. File ini berisi satu baris per wilayah yang dipetakan, terlihat seperti ini:
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]
Dua angka pertama adalah batas wilayah (alamat byte pertama dan byte setelah yang terakhir, dalam heksa). Kolom berikutnya berisi izin, lalu ada beberapa informasi tentang file (offset, perangkat, inode, dan nama) jika ini adalah pemetaan file. Lihat proc(5)halaman manual atau Memahami Linux / proc / id / maps untuk informasi lebih lanjut.
Berikut ini skrip proof-of-concept yang membuang konten dari ingatannya sendiri.
#! /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
Jika Anda mencoba membaca dari file mempseudo dari proses lain, itu tidak berfungsi: Anda mendapatkan ESRCHkesalahan (Tidak ada proses seperti itu).
Izin pada /proc/$pid/mem( r--------) lebih liberal daripada yang seharusnya. Misalnya, Anda seharusnya tidak dapat membaca memori proses setuid. Lebih jauh lagi, mencoba membaca memori suatu proses ketika proses memodifikasi itu dapat memberikan pembaca pandangan yang tidak konsisten dari memori, dan lebih buruk lagi, ada kondisi ras yang dapat melacak versi Linux kernel yang lebih lama (menurut utas lkml ini , meskipun saya tidak tahu detailnya). Jadi diperlukan pemeriksaan tambahan:
- Proses yang ingin dibaca
/proc/$pid/memharus dilampirkan ke proses menggunakan ptracedengan PTRACE_ATTACHbendera. Inilah yang dilakukan para debugger ketika mereka memulai proses debug; itu juga apa yang stracedilakukan untuk panggilan sistem suatu proses. Setelah pembaca selesai membaca dari /proc/$pid/mem, pembaca harus melepaskan dengan memanggil ptracedengan PTRACE_DETACHbendera.
- Proses yang diamati tidak boleh berjalan. Biasanya panggilan
ptrace(PTRACE_ATTACH, …)akan menghentikan proses target (mengirimkan STOPsinyal), tetapi ada kondisi balapan (pengiriman sinyal asinkron), sehingga pelacak harus menelepon wait(seperti yang didokumentasikan dalam ptrace(2)).
Sebuah proses yang berjalan sebagai root dapat membaca memori proses apa pun, tanpa perlu memanggil ptrace, tetapi proses yang diamati harus dihentikan, atau pembacaan akan tetap kembali ESRCH.
Dalam sumber kernel Linux, kode menyediakan entri per-proses di /procdalam fs/proc/base.c, dan fungsi untuk membaca dari /proc/$pid/memadalah mem_read. Pemeriksaan tambahan dilakukan oleh check_mem_permission.
Berikut ini beberapa contoh kode C untuk dilampirkan ke suatu proses dan membaca sebagian dari memfilenya (pengecekan kesalahan dihilangkan):
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);
Saya sudah memasang skrip proof-of-concept untuk dibuang /proc/$pid/memdi utas lain .