GNU/Linux >> Belajar Linux >  >> Linux

Linux – Bagaimana Cara Membaca Dari /proc/$pid/mem Di Linux?

Linux proc(5) halaman manual memberitahu saya bahwa /proc/$pid/mem "dapat digunakan untuk mengakses halaman memori proses". Tetapi upaya langsung untuk menggunakannya hanya memberi saya

$ cat /proc/$$/mem /proc/self/mem
cat: /proc/3065/mem: No such process
cat: /proc/self/mem: Input/output error

Mengapa tidak cat dapat mencetak memorinya sendiri (/proc/self/mem )? Dan apa kesalahan "tidak ada proses seperti itu" yang aneh ketika saya mencoba mencetak memori shell (/proc/$$/mem , jelas prosesnya ada)? Bagaimana saya bisa membaca dari /proc/$pid/mem , lalu?

Jawaban yang Diterima:

/proc/$pid/maps

/proc/$pid/mem menunjukkan isi memori $pid yang dipetakan dengan cara yang sama seperti pada proses, yaitu byte pada offset x dalam pseudo-file sama dengan byte di alamat x dalam proses. Jika alamat tidak dipetakan dalam proses, membaca dari offset yang sesuai dalam file akan mengembalikan EIO (Kesalahan masukan/keluaran). Misalnya, karena halaman pertama dalam suatu proses tidak pernah dipetakan (sehingga dereferensi NULL pointer gagal dengan bersih daripada mengakses memori aktual secara tidak sengaja), membaca byte pertama /proc/$pid/mem selalu menghasilkan kesalahan I/O.

Cara 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 hak akses, kemudian 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 adalah skrip proof-of-concept yang membuang isi memorinya sendiri.

#! /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

[Berikut ini untuk kepentingan sejarah. Ini tidak berlaku untuk kernel saat ini.]

Sejak kernel versi 3.3, Anda dapat mengakses /proc/$pid/mem biasanya selama Anda mengakses hanya mengaksesnya di offset yang dipetakan dan Anda memiliki izin untuk melacaknya (izin yang sama dengan ptrace untuk akses hanya baca). Namun pada kernel yang lebih lama, ada beberapa komplikasi tambahan.

Jika Anda mencoba membaca dari mem pseudo-file dari proses lain, tidak berhasil:Anda mendapatkan ESRCH (Tidak ada proses seperti itu) kesalahan.

Izin pada /proc/$pid/mem (r-------- ) lebih liberal dari yang seharusnya. Misalnya, Anda seharusnya tidak dapat membaca memori proses setuid. Lebih jauh lagi, mencoba membaca memori proses saat proses sedang memodifikasinya dapat memberikan pembaca pandangan memori yang tidak konsisten, dan lebih buruk lagi, ada kondisi balapan yang dapat melacak versi kernel Linux yang lebih lama (menurut utas lkml ini, meskipun saya tidak tahu detailnya). Jadi pemeriksaan tambahan diperlukan:

  • Proses yang ingin dibaca dari /proc/$pid/mem harus melampirkan ke proses menggunakan ptrace dengan PTRACE_ATTACH bendera. Inilah yang dilakukan debugger ketika mereka mulai men-debug suatu proses; itu juga yang strace lakukan untuk panggilan sistem suatu proses. Setelah pembaca selesai membaca dari /proc/$pid/mem , itu harus dilepaskan dengan memanggil ptrace dengan PTRACE_DETACH bendera.
  • Proses yang diamati tidak boleh berjalan. Biasanya memanggil ptrace(PTRACE_ATTACH, …) akan menghentikan proses target (mengirimkan STOP sinyal), tetapi ada kondisi balapan (pengiriman sinyal tidak sinkron), jadi pelacak harus memanggil wait (seperti yang didokumentasikan dalam ptrace(2) ).
Terkait:Biarkan NumLock selalu aktif?

Sebuah proses yang berjalan sebagai root dapat membaca memori proses apapun, tanpa perlu memanggil ptrace , tetapi proses yang diamati harus dihentikan, atau pembacaan akan tetap mengembalikan ESRCH .

Di sumber kernel Linux, kode menyediakan entri per-proses di /proc ada di fs/proc/base.c , dan fungsi untuk membaca dari /proc/$pid/mem adalah mem_read . Pemeriksaan tambahan dilakukan oleh check_mem_permission .

Berikut beberapa contoh kode C untuk dilampirkan ke suatu proses dan membaca sepotong mem file (pemeriksaan 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 telah memposting skrip proof-of-concept untuk membuang /proc/$pid/mem di utas lain.


Linux
  1. Bagaimana Linux Menangani Beberapa Pemisah Jalur Berturut-turut (/home////username///file)?

  2. Bagaimana cara mengetahui dari folder mana suatu proses sedang berjalan?

  3. Bagaimana cara mengatur swapiness per proses untuk linux?

  1. Linux – Bagaimana Symlink /proc//exe Berbeda Dari Symlink Biasa?

  2. Linux – Bagaimana Cara Mendapatkan Alamat IPv4 Untuk Antarmuka Dari /proc?

  3. Linux – Bagaimana Cara Mengetahui Namespace Dari Proses Tertentu?

  1. Linux – Bagaimana Menguji Apakah Perangkat Blok Apakah Hanya-Baca Dari /sys Atau /proc?

  2. Bagaimana Cara Membaca Satu Pesan Sekaligus Dari /var/mail?

  3. Bagaimana cara mendapatkan jalur proses di Unix / Linux