确定特定进程是 32 位还是 64 位

Fle*_*exo 15 linux 64bit elf proc

给定 2.6.x 或更新的 Linux 内核和能够同时运行 ELF32 和 ELF64 二进制文件的现有用户空间(即过去我怎么知道我的 CPU 在 Linux 下支持 64 位操作系统?)我如何确定给定的进程( PID) 是在 32 位还是 64 位模式下运行?

天真的解决方案是运行:

file -L /proc/pid/exe | grep -o 'ELF ..-bit [LM]SB'
Run Code Online (Sandbox Code Playgroud)

但该信息是否直接暴露在/proc不依赖的情况下libmagic

Ale*_*ios 23

如果你想限制自己ELF检测,就可以读取ELF头/proc/$PID/exe自己。这很简单:如果文件中的第 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 解释器信息的内容。每个条目的格式是一个无符号长 ID 加上一个无符号长值。最后一个条目包含两个零。

unsigned long键的含义在/usr/include/linux/auxvec.h. 你想要的AT_PLATFORM,就是0x00000f。不要引用我的话,但似乎该值应该被解释为 achar *以获取平台的字符串描述。

您可能会发现这个 StackOverflow 问题很有用。

另一种方法:您可以指示动态链接器 ( man ld) 转储有关可执行文件的信息。它将解码的 AUXV 结构打印到标准输出。警告:这是一个黑客,但它有效。

LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Run Code Online (Sandbox Code Playgroud)

这将显示如下内容:

AT_PLATFORM:     x86_64
Run Code Online (Sandbox Code Playgroud)

我在 32 位二进制文​​件上尝试过,结果得到了i686

工作原理:LD_SHOW_AUXV=1指示动态链接器在运行可执行文件之前转储解码的 AUXV 结构。除非你真的想让你的生活变得有趣,否则你想避免实际运行所述可执行文件。在不实际调用其main()函数的情况下加载和动态链接它的一种方法是ldd(1)在其上运行。缺点:LD_SHOW_AUXV由外壳启用,因此您将获得 AUXV 结构的转储:子外壳ldd、 和目标二进制文件。所以我们grep对于AT_PLATFORM,但只保留最后一行。

解析 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.
Run Code Online (Sandbox Code Playgroud)

解析地图文件:这是 Gilles 建议的,但不太奏效。这是一个修改过的版本。它依赖于读取/proc/$PID/maps文件。如果文件列出 64 位地址,则进程为 64 位。否则,它是 32 位。问题在于内核将通过从 4 组为一组的十六进制地址中去除前导零来简化输出,因此长度黑客不能完全奏效。awk救援:

LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Run Code Online (Sandbox Code Playgroud)

这是通过检查进程最后一个内存映射的起始地址来实现的。它们被列为12345678-deadbeef. 因此,如果进程是一个 32 位的进程,那么该地址将是八位十六进制数字长,第九位将是一个连字符。如果是 64 位的,最高地址会比这长。第 9 个字符将是一个十六进制数字。

请注意:除了第一个和最后一个方法之外,所有方法都需要 Linux 内核 2.6.0 或更新版本,因为该auxv文件以前不存在。


Gil*_*il' 6

查找范围/proc/$pid/maps。地址范围超过 32 位地址(8 个十六进制数字)或 64 位地址(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
Run Code Online (Sandbox Code Playgroud)

如果您没有访问此文件的权限,那么我认为唯一的方法是尝试分析可执行文件。(虽然您始终可以阅读/proc/$pid/stat,但为不同用户运行的进程显示的任何字段都不会显示该进程的位大小。)您可以使用 很好地猜测进程的可执行文件ps -o comm=,并在 中查找PATH- 但请注意该进程可能已经推出了不同的PATH,或者可能已经改写了它argv[0]。然后您可以分析可执行文件 - 如果您愿意假设 ELF,请查看第 5 个字节