/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]
ตัวเลขสองตัวแรกคือขอบเขตของภูมิภาค (ที่อยู่ของไบต์แรกและไบต์หลังสุดเป็น hexa) คอลัมน์ถัดไปมีสิทธิ์แล้วมีข้อมูลบางอย่างเกี่ยวกับไฟล์ (ออฟเซ็ตอุปกรณ์ inode และชื่อ) หากเป็นการแมปไฟล์ ดูproc(5)
man page หรือทำความเข้าใจกับ Linux / proc / id / mapsสำหรับข้อมูลเพิ่มเติม
ต่อไปนี้เป็นสคริปต์บทพิสูจน์ถึงแนวคิดที่ทิ้งเนื้อหาในหน่วยความจำของตัวเอง
#! /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--------
) มีความเสรีมากกว่าสิ่งที่ควรเป็น ตัวอย่างเช่นคุณไม่ควรอ่านหน่วยความจำของกระบวนการ setuid นอกจากนี้พยายามอ่านหน่วยความจำของกระบวนการในขณะที่กระบวนการที่มีการปรับเปลี่ยนก็จะให้ผู้อ่านมุมมองที่ไม่สอดคล้องกันของหน่วยความจำและเลวร้ายยิ่งมีสภาพการแข่งขันที่สามารถติดตามรุ่นเก่าของลินุกซ์ (ตามหัวข้อ lkml นี้แต่ฉัน ไม่ทราบรายละเอียด) ดังนั้นจึงจำเป็นต้องมีการตรวจสอบเพิ่มเติม:
- กระบวนการที่ต้องการอ่านจาก
/proc/$pid/mem
ต้องแนบกับกระบวนการที่ใช้ptrace
กับPTRACE_ATTACH
แฟล็ก นี่คือสิ่งที่ผู้ debuggers ทำเมื่อพวกเขาเริ่มการดีบักกระบวนการ นอกจากนี้ยังเป็นสิ่งที่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
ในหัวข้ออื่น