web-dev-qa-db-ja.com

特定のプロセスが32ビットか64ビットかを判別する

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

14
Flexo

ELF検出に制限したい場合は、_/proc/$PID/exe_の ELFヘッダー を自分で読み取ることができます。これは非常に簡単です。ファイルの5番目のバイトが1の場合、32ビットのバイナリです。 2の場合、64ビットです。追加の健全性チェックの場合:

  1. 最初の5バイトが_0x7f, "ELF", 1_の場合:32ビットELFバイナリです。
  2. 最初の5バイトが_0x7f, "ELF", 2_の場合:64ビットのELFバイナリです。
  3. そうでなければ:それは決定的ではありません。

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以降が必要です。

22
Alexios

/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番目のバイトを見てください です。