Si desea limitarse a la detección ELF, puede leer el encabezado ELF de /proc/$PID/exe
usted mismo. Es bastante trivial: si el quinto byte del archivo es 1, es un binario de 32 bits. Si es 2, es de 64 bits. Para mayor control de cordura:
- Si los primeros 5 bytes son
0x7f, "ELF", 1
: es un binario ELF de 32 bits.
- Si los primeros 5 bytes son
0x7f, "ELF", 2
: es un binario ELF de 64 bits.
- De lo contrario: no es concluyente.
También podría usar objdump
, pero eso le quita su libmagic
dependencia y la reemplaza por una libelf
.
Otra forma : también puede analizar el /proc/$PID/auxv
archivo. De acuerdo a proc(5)
:
Contiene el contenido de la información del intérprete ELF que se pasó al proceso en el momento de ejecución. El formato es un ID largo sin signo más un valor largo sin signo para cada entrada. La última entrada contiene dos ceros.
Los significados de las unsigned long
teclas están en /usr/include/linux/auxvec.h
. Tú quieres AT_PLATFORM
, que es 0x00000f
. No me cite sobre eso, pero parece que el valor debe interpretarse como a char *
para obtener la descripción de la cadena de la plataforma.
Puede encontrar útil esta pregunta de StackOverflow .
Otra forma más : puede indicarle al vinculador dinámico ( man ld
) que descargue información sobre el ejecutable. Imprime en salida estándar la estructura decodificada de AUXV. Advertencia: este es un truco, pero funciona.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Esto mostrará algo como:
AT_PLATFORM: x86_64
Lo probé en un binario de 32 bits y obtuve en su i686
lugar.
Cómo funciona esto: LD_SHOW_AUXV=1
indica al Dynamic Linker que descargue la estructura decodificada de AUXV antes de ejecutar el ejecutable. A menos que realmente le guste hacer que su vida sea interesante, desea evitar ejecutar dicho ejecutable. Una forma de cargarlo y vincularlo dinámicamente sin llamar realmente a su main()
función es ejecutarlo ldd(1)
. La desventaja: LD_SHOW_AUXV
está habilitada por el shell, por lo que obtendrá volcados de las estructuras AUXV para: el subshell ldd
y su binario de destino. Entonces, grep
para AT_PLATFORM, pero solo mantenemos la última línea.
Analizando auxv : si analiza la auxv
estructura usted mismo (sin depender del cargador dinámico), entonces hay un poco de enigma: la auxv
estructura sigue la regla del proceso que describe, por sizeof(unsigned long)
lo que será 4 para procesos de 32 bits y 8 para 64 -bit procesos. Podemos hacer que esto funcione para nosotros. Para que esto funcione en sistemas de 32 bits, todos los códigos clave deben ser 0xffffffff
o menos. En un sistema de 64 bits, los 32 bits más significativos serán cero. Las máquinas Intel son pequeños endianes, por lo que estos 32 bits siguen a los menos significativos en la memoria.
Como tal, todo lo que necesita hacer es:
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.
Analizando el archivo de mapas : esto fue sugerido por Gilles, pero no funcionó. Aquí hay una versión modificada que sí. Se basa en leer el /proc/$PID/maps
archivo. Si el archivo enumera direcciones de 64 bits, el proceso es de 64 bits. De lo contrario, son 32 bits. El problema radica en que el núcleo simplificará la salida eliminando los ceros iniciales de las direcciones hexadecimales en grupos de 4, por lo que el corte de longitud no puede funcionar. awk
al rescate:
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
Esto funciona comprobando la dirección de inicio del último mapa de memoria del proceso. Están listados como 12345678-deadbeef
. Entonces, si el proceso es de 32 bits, esa dirección tendrá ocho dígitos hexadecimales y la novena será un guión. Si es de 64 bits, la dirección más alta será más larga que eso. El noveno personaje será un dígito hexadecimal.
Tenga en cuenta: todos los métodos, excepto el primero y el último, necesitan el kernel de Linux 2.6.0 o posterior, ya que el auxv
archivo no estaba allí antes.
/proc/[pid]/auxv
: "la información del intérprete ELF pasó al proceso en el momento de la ejecución. El formato es una ID larga sin signo más un valor largo sin signo para cada entrada" (man proc
).