Linux에서 /proc/$pid/mem을 읽는 방법은 무엇입니까?

Linux에서 /proc/$pid/mem을 읽는 방법은 무엇입니까?

이것리눅스 proc(5)매뉴얼 페이지/proc/$pid/mem"프로세스 메모리에 액세스하는 데 사용할 수 있는 페이지"를 알려줍니다 . 하지만 직접 사용하려고 하면 나에게

$ cat /proc/$$/mem /proc/self/mem
cat: /proc/3065/mem: No such process
cat: /proc/self/mem: Input/output error

cat왜 내 기억( )을 프린트 할 수 없나요 /proc/self/mem? 쉘의 메모리를 인쇄하려고 할 때 발생하는 이상한 "해당 프로세스 없음" 오류는 무엇입니까( /proc/$$/mem분명 프로세스가 존재하는 것 같습니다)? 그러면 어떻게 읽을 수 있나요 /proc/$pid/mem?

답변1

/proc/$pid/maps

/proc/$pid/memShow $pid 메모리 내용은 프로세스와 동일한 방식으로 매핑됩니다. 즉, 오프셋의 바이트엑스의사 파일의 바이트는 주소의 바이트와 동일합니다.엑스진행 중입니다. 프로세스에서 주소가 매핑되지 않은 경우 파일의 해당 오프셋에서 읽으면 반환됩니다 EIO(입력/출력 오류). 예를 들어, 첫 번째 바이트를 읽으면 프로세스의 첫 번째 페이지가 매핑되지 않으므로 항상 I/O 오류가 발생합니다 . 따라서 NULL실수로 실제 메모리에 액세스하는 대신 포인터 역참조가 완전히 실패합니다./proc/$pid/mem

프로세스 메모리의 어느 부분이 매핑되어 있는지 알아내는 방법은 를 읽는 것입니다 /proc/$pid/maps. 파일에는 다음과 같이 매핑된 영역당 한 줄이 포함됩니다.

08048000-08054000 r-xp 00000000 08:01 828061     /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0          [heap]

처음 두 숫자는 영역의 경계입니다(첫 번째 및 마지막 바이트의 주소, 16진수). 다음 열에는 권한이 포함되고 파일 맵인 경우 파일에 대한 일부 정보(오프셋, 장치, inode 및 이름)가 포함됩니다. 보다proc(5)맨 페이지 또는Linux /proc/id/maps 이해더 많은 정보를 알고 싶습니다.

이는 자체 메모리의 내용을 덤프하는 개념 증명 스크립트입니다.

#! /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

[다음 내용은 역사적으로 흥미롭습니다. 현재 커널에서는 작동하지 않습니다. ]

~부터커널 버전 3.3/proc/$pid/mem, 매핑된 오프셋에만 액세스하고 권한 추적이 있는 한 정상적으로 액세스할 수 있습니다(ptrace읽기 전용 액세스의 경우). 그러나 이전 커널에는 몇 가지 추가적인 문제가 있습니다.

다른 프로세스의 의사 파일을 읽으려고 하면 mem작동하지 않습니다. ESRCH(No such process) 오류가 발생합니다.

/proc/$pid/mem( )에 대한 권한은 r--------필요한 것보다 더 허용적입니다. 예를 들어 setuid 프로세스의 메모리를 읽을 수 없어야 합니다. 또한, 프로세스가 수정하는 동안 프로세스의 메모리를 읽으려고 하면 독자가 메모리에 대해 일관되지 않은 시각을 갖게 될 수 있으며, 더 나쁜 것은 Linux 커널의 이전 버전을 추적할 수 있는 경쟁 조건이 있다는 것입니다(에 따르면).이 lml 스레드, 세부 사항은 모르지만). 따라서 추가 확인이 필요합니다.

  • 읽으려는 프로세스는 다음을 /proc/$pid/mem사용하는 프로세스에 연결되어야 합니다.ptrace플래그 와 함께 PTRACE_ATTACH. 이는 프로세스 디버깅을 시작할 때 디버거가 수행하는 작업입니다.strace프로세스에 대한 시스템 호출에 의해 수행되는 작업입니다. 판독기가 읽기를 마치면 플래그를 사용 /proc/$pid/mem하여 호출하여 분리해야 합니다 .ptracePTRACE_DETACH
  • 관찰된 프로세스는 실행 중이 아니어야 합니다. 일반적으로 호출은 ptrace(PTRACE_ATTACH, …)대상 프로세스를 중지하지만(신호 전송 STOP) 경쟁 조건(신호 전달은 비동기식)이 있으므로 추적기가 호출해야 합니다 wait(문서에 명시된 대로).ptrace(2)).

루트로 실행 중인 프로세스는 호출 없이 모든 프로세스의 메모리를 읽을 수 있지만 ptrace관찰된 프로세스는 중지되어야 합니다. 그렇지 않으면 읽기가 계속 반환됩니다 ESRCH.

Linux 커널 소스 코드에는 프로세스별 항목을 제공하는 코드가 /proc있습니다.fs/proc/base.c, 읽을 기능 /proc/$pid/mem은 다음과 같습니다mem_read. 추가 점검은 다음에 의해 수행됩니다.check_mem_permission.

다음은 프로세스에 연결하고 mem해당 파일의 블록을 읽기 위한 몇 가지 샘플 C 코드입니다(오류 검사 생략).

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다른 스레드에 덤핑 에 대한 개념 증명 스크립트를 게시했습니다..

답변2

gdb의 이 명령은 메모리를 안정적으로 덤프합니다.

gcore pid

덤프 용량이 클 수 있으므로 -o outfile현재 디렉터리에 공간이 충분하지 않은 경우 사용하세요.

답변3

실행하면 cat /proc/$$/mem변수는 $$자체 pid를 삽입하는 bash에 의해 평가됩니다. 그런 다음 cat다른 PID를 사용하여 프로그램을 실행합니다 . 결국 cat상위 프로세스의 메모리를 읽으려고 시도하게 됩니다 . bash권한이 없는 프로세스는 자신의 메모리 공간만 읽을 수 있으므로 커널은 이를 거부합니다.

예는 다음과 같습니다.

$ echo $$
17823

계산 은 $$17823입니다. 어떤 과정인지 살펴보겠습니다.

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

이것이 나의 현재 쉘입니다.

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

여기서도 $$내 쉘인 17823으로 평가됩니다. cat내 쉘의 메모리 공간을 읽을 수 없습니다.

답변4

bash를 사용하여 읽기를 수행할 수도 있습니다.dd(1)

위에서 언급한 명령 중 일부가 없는 제한적이고 기본적인 Unix 시스템을 사용하는 경우( 이와 유사한 명령 python까지 )memdump

를 사용할 수 dd(1)있으며 대부분의 제한된 Unix 환경에서 작동합니다.

프로세스의 처음 몇 바이트를 덤프하는 예:

$ dd if=/proc/1337/mem of=/tmp/dump bs=1 skip=$((0x400000)) count=128

그런 다음 사용할 수 있습니다

hexdump -Cv ./tmp/dump

관련 정보