/proc/$pid/maps
/proc/$pid/mem
は、プロセスと同じ方法でマップされた$ pidのメモリの内容を示します。つまり、擬似ファイルのオフセットxのバイトは、プロセスのアドレスxのバイトと同じです。プロセスでアドレスのマッピングが解除されている場合、ファイル内の対応するオフセットからの読み取りが返されますEIO
(入出力エラー)。たとえば、プロセスの最初のページはマップされないため(NULL
ポインターの参照解除が実際のメモリに意図せずアクセスするのではなく、きれいに失敗するように)、最初のバイトを読み取ると/proc/$pid/mem
常にI / Oエラーが発生します。
プロセスメモリのどの部分がマップされているかを調べる方法は、読み取ること/proc/$pid/maps
です。このファイルには、次のようにマップされた領域ごとに1行が含まれます。
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]
最初の2つの数字は、領域の境界です(最初のバイトのアドレスと、最後のバイトのアドレス(16進数))。次の列には権限が含まれており、ファイルマッピングの場合、ファイルに関する情報(オフセット、デバイス、iノード、名前)があります。詳細については、proc(5)
manページまたは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プロセスのメモリを読み取ることはできません。さらに、プロセスの変更中にプロセスのメモリを読み取ろうとすると、リーダーにメモリの一貫性のないビューが表示される可能性があり、さらに悪いことに、古いバージョンのLinuxカーネル(このlkmlスレッドによると、詳細がわからない)。したがって、追加のチェックが必要です。
- 読み取り元
/proc/$pid/mem
のプロセスptrace
は、PTRACE_ATTACH
フラグを使用してプロセスにアタッチする必要があります。これは、プロセスのデバッグを開始するときにデバッガーが行うことです。またstrace
、プロセスのシステムコールに対しても行います。リーダーは、からの読み取りを完了すると、フラグ/proc/$pid/mem
を使用ptrace
して呼び出してデタッチする必要がありPTRACE_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
別のスレッドにダンプするための概念実証スクリプトをすでに投稿しました。