ELF32とELF64の両方のバイナリを実行できる2.6.x以降のLinuxカーネルと既存のユーザーランドがある場合(つまり、過去 のCPUがLinuxで64ビットオペレーティングシステムをサポートしていることをどのようにして知ることができますか? )特定のプロセス(PIDによる)が32ビットモードと64ビットモードのどちらで実行されているかを確認するにはどうすればよいですか?
素朴な解決策は以下を実行することです:
file -L /proc/pid/exe | grep -o 'ELF ..-bit [LM]SB'
しかし、その情報は直接/proc
に依存せずにlibmagic
?
ELF検出に制限したい場合は、_/proc/$PID/exe
_の ELFヘッダー を自分で読み取ることができます。これは非常に簡単です。ファイルの5番目のバイトが1の場合、32ビットのバイナリです。 2の場合、64ビットです。追加の健全性チェックの場合:
0x7f, "ELF", 1
_の場合:32ビットELFバイナリです。0x7f, "ELF", 2
_の場合:64ビットのELFバイナリです。objdump
を使用することもできますが、これによりlibmagic
依存関係が取り除かれ、libelf
依存関係に置き換えられます。
別の方法:_/proc/$PID/auxv
_ファイルを解析することもできます。 proc(5)
によれば:
これには、実行時にプロセスに渡されるELFインタープリター情報の内容が含まれます。形式は、1つのunsigned long IDと各エントリの1つのunsigned long値です。最後のエントリには2つのゼロが含まれています。
_unsigned long
_キーの意味は_/usr/include/linux/auxvec.h
_にあります。 _AT_PLATFORM
_、つまり_0x00000f
_が必要です。引用しないでください。ただし、プラットフォームの文字列の説明を取得するには、値を_char *
_として解釈する必要があります。
このStackOverflowの質問 が役立つかもしれません。
まだ別の方法:実行可能ファイルに関する情報をダンプするように動的リンカー(_man ld
_)に指示できます。デコードされたAUXV構造を標準出力に出力します。警告:これはハックですが、機能します。
_LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
_
これは次のようになります。
_AT_PLATFORM: x86_64
_
32ビットのバイナリで試して、代わりに_i686
_を取得しました。
仕組み:_LD_SHOW_AUXV=1
_は、実行可能ファイルを実行する前に、デコードされたAUXV構造をダンプするようダイナミックリンカーに指示します。あなたが本当にあなたの人生を面白くしたいのでなければ、あなたは実際に実行した実行可能ファイルを避けたいです。実際にmain()
関数を呼び出さずにロードして動的にリンクする1つの方法は、その関数でldd(1)
を実行することです。欠点:_LD_SHOW_AUXV
_はシェルによって有効になるため、サブシェル、ldd
、およびターゲットバイナリのAUXV構造のダンプを取得できます。したがって、AT_PLATFORMの場合はgrep
ですが、最後の行のみを保持します。
Parsing auxv:ダイナミックローダーに依存せずにauxv
構造体を自分で解析する場合、少し難解があります。auxv
構造体はルールに従います説明するプロセスのsizeof(unsigned long)
は、32ビットプロセスの場合は4、64ビットプロセスの場合は8になります。これは私たちのために働くことができます。これが32ビットシステムで機能するためには、すべてのキーコードが_0xffffffff
_以下でなければなりません。 64ビットシステムでは、最上位の32ビットはゼロになります。 Intelマシンはリトルエンディアンなので、これらの32ビットはメモリ内で最下位のものに続きます。
したがって、必要なことは次のとおりです。
_1. Read 16 bytes from the `auxv` file.
2. Is this the end of the file?
3. Then it's a 64-bit process.
4. Done.
5. Is buf[4], buf[5], buf[6] or buf[7] non-zero?
6. Then it's a 32-bit process.
7. Done.
8. Go to 1.
_
マップファイルの解析:これはGillesによって提案されましたが、うまくいきませんでした。これは変更されたバージョンです。 _/proc/$PID/maps
_ファイルの読み取りに依存します。ファイルに64ビットアドレスがリストされている場合、プロセスは64ビットです。それ以外の場合は32ビットです。問題は、カーネルが4のグループの16進アドレスから先行ゼロを取り除いて出力を簡略化するため、長さのハックがうまく機能しないことです。 awk
が救助に:
_if ! [ -e /proc/$pid/maps ]; then
echo "No such process"
else
case $(awk </proc/$pid/maps -- 'END { print substr($1, 0, 9); }') in
*-) echo "32 bit process";;
*[0-9A-Fa-f]) echo "64 bit process";;
*) echo "Insufficient permissions.";;
esac
fi
_
これは、プロセスの最後のメモリマップの開始アドレスをチェックすることで機能します。それらは_12345678-deadbeef
_のようにリストされます。したがって、プロセスが32ビットの場合、そのアドレスは8桁の16進数で、9番目はハイフンになります。 64ビットの場合、最上位アドレスはそれより長くなります。 9番目の文字は16進数です。
注意:auxv
ファイルが以前になかったため、最初と最後のメソッドを除くすべてのメソッドにはLinuxカーネル2.6.0以降が必要です。
/proc/$pid/maps
をご覧ください。アドレス範囲は、32ビットアドレス(8桁の16進数)または64ビットアドレス(16桁の16進数)を超えています。これは、どのような形式の実行可能ファイルでも機能します。同じユーザーとして実行されているプロセスに関する情報のみを取得できます(rootでない場合)。
if ! [ -e /proc/$pid/maps ]; then
echo No such process
Elif grep -q '^........[^-]' /proc/$pid/maps; then
echo 64-bit
Elif grep -q . /proc/$pid/maps; then
echo 32-bit
else
echo Insufficient permissions
fi
このファイルにアクセスする権限がない場合、実行可能ファイルを分析するのが唯一の方法だと思います。 (いつでも/proc/$pid/stat
を読み取ることができますが、異なるユーザーが実行しているプロセスに対して表示されるフィールドはどれも、プロセスのビットサイズを明らかにしません。)ps -o comm=
を使用してプロセスの実行可能ファイルを正確に推測し、これはPATH
にあります—ただし、プロセスが別のPATH
で起動されているか、またはargv[0]
が書き直されている可能性があることに注意してください。次に、実行可能ファイルを分析できます— ELFを想定する場合は、 5番目のバイトを見てください です。