/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 NULLiş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/memher 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
memBaş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/memkullanarak işleme ekleme gerekir ptraceile PTRACE_ATTACHbayrak. Bu, hata ayıklayıcıların bir süreçte hata ayıklamaya başladığında yaptığı şeydir; aynı zamanda stracebir sürecin sisteminin çağırdığı şeydir . Okuyucu, okumayı bitirdikten sonra bayrak ile /proc/$pid/memarayarak ayrılmalıdır .ptracePTRACE_DETACH
- Gözlenen işlem çalışmamalıdır. Normalde çağrı yapmak
ptrace(PTRACE_ATTACH, …)hedef işlemi durduracaktır (bir STOPsinyal 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 /prociçindedir fs/proc/base.cve okuma işlevi /proc/$pid/memolduğunu mem_read. Ek kontrol tarafından yapılır check_mem_permission.
İşte bir sürece eklemek ve memdosya 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/membaşka bir iş parçacığına dökmek için bir kavram kanıtı betiği yayınladım .