/proc/$pid/maps
/proc/$pid/mem
$ pid की मेमोरी की सामग्री को उसी तरह से दिखाता है जैसे प्रक्रिया में, यानी, छद्म फ़ाइल में ऑफसेट x पर बाइट प्रक्रिया में पता x पर बाइट के समान है। यदि कोई पता प्रक्रिया में बंद है, तो फाइल रिटर्न EIO
(इनपुट / आउटपुट त्रुटि) में संबंधित ऑफसेट से पढ़ना । उदाहरण के लिए, चूँकि किसी प्रक्रिया में पहला पृष्ठ कभी मैप नहीं किया जाता है (ताकि एक NULL
संकेतक को निष्क्रिय करने से अनायास ही वास्तविक स्मृति तक पहुँचने में असफलता मिलती है), /proc/$pid/mem
हमेशा I / O त्रुटि प्राप्त करने के पहले बाइट को पढ़ना ।
यह पता लगाने का तरीका है कि मेमोरी की प्रक्रिया के किन हिस्सों को मैप किया जाता है /proc/$pid/maps
। इस फ़ाइल में प्रति मैप की गई एक पंक्ति है, जो इस प्रकार है:
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]
पहले दो नंबर क्षेत्र की सीमाएं हैं (पहले बाइट के पते और आखिरी के बाद बाइट, हेक्सा में)। अगले कॉलम में अनुमतियाँ हैं, फिर फ़ाइल (ऑफ़सेट, डिवाइस, इनोड और नाम) के बारे में कुछ जानकारी है यदि यह फ़ाइल मैपिंग है। देखें proc(5)
आदमी पेज या समझौता लिनक्स / proc / आईडी / नक्शे और जानकारी के लिए।
यहां एक प्रूफ-ऑफ-कॉन्सेप्ट स्क्रिप्ट है जो अपनी मेमोरी की सामग्री को डंप करता है।
#! /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
किसी अन्य प्रक्रिया के छद्म फ़ाइल से पढ़ने की कोशिश करते हैं , तो यह काम नहीं करता है: आपको कोई ESRCH
(ऐसी कोई प्रक्रिया नहीं) त्रुटि मिलती है ।
अनुमतियाँ /proc/$pid/mem
( r--------
) मामले की तुलना में अधिक उदार हैं। उदाहरण के लिए, आपको एक सेट्युइड प्रक्रिया की मेमोरी पढ़ने में सक्षम नहीं होना चाहिए। इसके अलावा, एक प्रक्रिया की मेमोरी को पढ़ने की कोशिश करते हुए, प्रक्रिया को संशोधित करते हुए यह पाठक को स्मृति का एक असंगत दृश्य दे सकता है, और इससे भी बदतर, ऐसी दौड़ स्थितियां थीं जो लिनक्स कर्नेल के पुराने संस्करणों का पता लगा सकती थीं ( इस lkml थ्रेड के अनुसार , हालांकि मैं विवरण नहीं जानते)। तो अतिरिक्त जांच की जरूरत है:
- जिस प्रक्रिया से पढ़ना चाहता है , उसे ध्वज के साथ
/proc/$pid/mem
प्रक्रिया का उपयोग करना चाहिए । यह तब होता है जब डिबगर किसी प्रक्रिया को डीबग करना शुरू करते हैं; यह एक प्रक्रिया के सिस्टम कॉल के लिए क्या करता है। एक बार पाठक से पढ़ना समाप्त कर लेने के बाद , उसे ध्वज के साथ बुलाकर अलग करना चाहिए ।ptrace
PTRACE_ATTACH
strace
/proc/$pid/mem
ptrace
PTRACE_DETACH
- देखी गई प्रक्रिया चल नहीं रही होगी। आम तौर पर कॉल
ptrace(PTRACE_ATTACH, …)
करने से लक्ष्य प्रक्रिया बंद हो जाएगी (यह एक STOP
संकेत भेजता है ), लेकिन एक दौड़ की स्थिति है (संकेत वितरण अतुल्यकालिक है), इसलिए ट्रेसर को कॉल करना चाहिए wait
(जैसा कि दस्तावेज में है ptrace(2)
)।
रूट के रूप में चल रही एक प्रक्रिया किसी भी प्रक्रिया की मेमोरी को पढ़ सकती है, बिना कॉल किए ptrace
, लेकिन देखी गई प्रक्रिया को रोकना होगा, या रीड अभी भी वापस आ जाएगा ESRCH
।
लिनक्स कर्नेल स्रोत में, प्रति-प्रक्रिया प्रविष्टियाँ प्रदान करने वाला कोड /proc
है fs/proc/base.c
, और इससे पढ़ने के लिए फ़ंक्शन /proc/$pid/mem
है mem_read
। द्वारा अतिरिक्त जाँच की जाती है check_mem_permission
।
यहाँ कुछ नमूना C कोड एक प्रक्रिया से जुड़ा है और इसकी mem
फ़ाइल का एक हिस्सा पढ़ने के लिए है (त्रुटि की जाँच छोड़ दी गई):
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);
मैंने पहले से ही एक /proc/$pid/mem
और थ्रेड पर डंपिंग के लिए एक प्रूफ-ऑफ-कॉन्सेप्ट स्क्रिप्ट पोस्ट की है ।