/proc/$pid/maps
/proc/$pid/mem
$ pid hafızasının içeriğini işlemdekiyle aynı şekilde gösterir, yani sözde dosyadaki x ofsetindeki bayt , işlemdeki x adresindeki bayt ile aynıdır . İşlem sırasında bir adres eşleşmezse, dosyadaki karşılık gelen uzaklıktan okuma döndürür EIO
(Giriş / çıkış hatası). Örneğin, bir işlemdeki ilk sayfa hiçbir zaman eşleştirilmediğinden (bir NULL
işaretçinin işaretinin kaldırılması, gerçek belleğe istemeden erişmeden ziyade temiz bir şekilde başarısız olması nedeniyle), ilk baytı okumak /proc/$pid/mem
her zaman bir G / Ç hatası verir.
İşlem belleğinin hangi kısımlarının haritalandığını bulmanın yolu okumaktır /proc/$pid/maps
. Bu dosya, eşlenmiş bölge başına bir satır içerir ve şöyle görünür:
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]
İlk iki sayı, bölgenin sınırlarıdır (ilk bayt ve sondan sonraki bayt adresleri, heksa cinsinden). Bir sonraki sütun izinleri içeriyorsa, bu dosya eşlemesiyse dosya hakkında (bilgi, ofset, aygıt, inode ve name) bazı bilgiler vardır. Daha fazla bilgi için proc(5)
man sayfasına veya Linux / proc / id / maps'ü anlama bölümüne bakın .
İşte kendi hafızasının içeriğini harcayan bir konsept kanıtı betiği.
#! /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
mem
Başka bir işlemin sözde dosyasından okumaya çalışırsanız , işe yaramaz: ESRCH
(Böyle bir işlem yok) hatası alırsınız .
/proc/$pid/mem
( r--------
) Üzerindeki izinler, olması gerekenden daha liberaldir. Örneğin, setuid bir işlemin hafızasını okuyamamalısınız. Ayrıca, işlem değiştirilirken bir işlemin belleğini okumaya çalışmak, okuyucuya belleğin tutarsız bir görüntüsünü verebilir ve daha da kötüsü, Linux çekirdeğinin eski sürümlerini izleyebilecek yarış koşulları vardı (buna rağmen bu lkml dizisine göre). ayrıntıları bilmiyorum). Bu yüzden ek kontroller gerekli:
- Dan okumak istiyor süreç
/proc/$pid/mem
kullanarak işleme ekleme gerekir ptrace
ile PTRACE_ATTACH
bayrak. Bu, hata ayıklayıcıların bir süreçte hata ayıklamaya başladığında yaptığı şeydir; aynı zamanda strace
bir sürecin sisteminin çağırdığı şeydir . Okuyucu, okumayı bitirdikten sonra bayrak ile /proc/$pid/mem
arayarak ayrılmalıdır .ptrace
PTRACE_DETACH
- Gözlenen işlem çalışmamalıdır. Normalde çağrı yapmak
ptrace(PTRACE_ATTACH, …)
hedef işlemi durduracaktır (bir STOP
sinyal gönderir ), ancak bir yarış durumu vardır (sinyal teslimi asenkrondur), bu nedenle izleyici çağırmalıdır wait
(belgelendiği gibi ptrace(2)
).
Kök olarak çalışan bir işlem, çağrı yapmak zorunda kalmadan herhangi bir işlemin hafızasını okuyabilir ptrace
, ancak gözlemlenen işlem durdurulmalı, yoksa okuma yine geri dönecektir ESRCH
.
Linux çekirdek kaynak, kod içinde her işlem girişlerini sağlayan /proc
içindedir fs/proc/base.c
ve okuma işlevi /proc/$pid/mem
olduğunu mem_read
. Ek kontrol tarafından yapılır check_mem_permission
.
İşte bir sürece eklemek ve mem
dosya için bir yığın okumak için bazı örnek C kodu (hata denetimi atlandı):
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);
Ben zaten /proc/$pid/mem
başka bir iş parçacığına dökmek için bir kavram kanıtı betiği yayınladım .