これLinuxの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/mem
Show $pid メモリ内容はプロセスと同じ方法でマップされます。つまり、オフセットのバイトX擬似ファイルのバイトはアドレスのバイトと同じです。X進行中です。プロセスがアドレスがマップされていない場合、ファイルの対応するオフセットから読み取られたときに返されますEIO
(入力/出力エラー)。たとえば、最初のバイトを読み取るとプロセスの最初のページがマップされないため、常にI / Oエラーが発生します。したがって、NULL
誤って物理メモリにアクセスするのではなく、ポインタの逆参照は完全に失敗します。/proc/$pid/mem
プロセスメモリのどの部分がマッピングされているかを調べる方法は、を読むことです/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進数)。次の列には、権限が含まれ、ファイルマップの場合、ファイルに関するいくつかの情報(オフセット、デバイス、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プロセスのメモリを読み取ることはできません。また、プロセスが変更中にプロセスのメモリを読み取ろうとすると、読者がメモリに対して一貫性のない視点を持つ可能性があります。によると)。このlmlスレッド、詳細はわかりませんが)。したがって、追加の確認が必要です。
- 読みたいプロセスは、以下を
/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);
答え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