GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana cara membaca dari /proc/$pid/mem di Linux?

/proc/$pid/maps

/proc/$pid/mem menampilkan isi memori $pid yang dipetakan dengan cara yang sama seperti dalam proses, yaitu, byte pada offset x dalam pseudo-file sama dengan byte pada alamat x dalam proses. Jika alamat tidak dipetakan dalam proses, pembacaan dari offset yang sesuai dalam file mengembalikan EIO (Kesalahan masukan/keluaran). Misalnya, karena halaman pertama dalam suatu proses tidak pernah dipetakan (sehingga mendereferensi NULL pointer gagal bersih daripada tanpa sengaja mengakses memori yang sebenarnya), membaca byte pertama dari /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 terakhir, dalam hexa). 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 konten 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. Itu 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 seperti ptrace untuk akses hanya baca). Tapi di kernel lama, ada beberapa komplikasi tambahan.

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

Izin pada /proc/$pid/mem (r-------- ) lebih liberal dari yang seharusnya. Misalnya, Anda seharusnya tidak dapat membaca memori proses setuid. Selain itu, mencoba membaca memori proses saat proses memodifikasinya dapat memberi 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 diperlukan pemeriksaan tambahan:

  • Proses yang ingin membaca dari /proc/$pid/mem harus dilampirkan ke proses menggunakan ptrace dengan PTRACE_ATTACH bendera. Inilah yang dilakukan para debugger ketika mereka mulai men-debug suatu proses; itu juga apa strace tidak untuk panggilan sistem proses. Setelah pembaca selesai membaca dari /proc/$pid/mem , itu harus dilepas 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), sehingga pelacak harus memanggil wait (seperti yang didokumentasikan dalam ptrace(2) ).

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 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 sebagian dari 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 sudah memposting skrip proof-of-concept untuk membuang /proc/$pid/mem di utas lain.


Perintah ini (dari gdb) membuang memori dengan andal:

gcore pid

Dump bisa besar, gunakan -o outfile jika direktori Anda saat ini tidak memiliki cukup ruang.


Saat Anda menjalankan cat /proc/$$/mem variabel $$ dievaluasi oleh oleh bash yang menyisipkan pidnya sendiri. Ini kemudian mengeksekusi cat yang memiliki pid berbeda. Anda berakhir dengan cat mencoba membaca memori bash , proses induknya. Karena proses non-istimewa hanya dapat membaca ruang memorinya sendiri, hal ini ditolak oleh kernel.

Berikut contohnya:

$ echo $$
17823

Perhatikan bahwa $$ mengevaluasi ke 17823. Mari kita lihat proses apa itu.

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

Ini shell saya saat ini.

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

Di sini sekali lagi $$ mengevaluasi ke 17823, yang merupakan cangkang saya. cat tidak dapat membaca ruang memori shell saya.


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

  2. /proc/[pid]/pagemaps dan /proc/[pid]/maps | linux

  3. Bagaimana cara mendapatkan jumlah CPU/core di Linux dari baris perintah?

  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