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から読み取るにはどうすればよいですか 、じゃあ?
承認された回答:
/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", '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を取得します (そのようなプロセスはありません)エラー。
/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をダンプするための概念実証スクリプトをすでに投稿しました 別のスレッドで。