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
).hd
editar uno y le faltaba el número mágico. Puede haber información relevante allí, pero creo que estaría sujeta a cambios más frecuentes que el encabezado ELF en sí. También se introdujo en 2.6.0, por lo que no es tan omnipresente como/proc/PID/exe
. Pero lo hace tener la arquitectura de la información. Actualizaré mi respuesta.sizeof(unsigned long)
es 8 en 64 bits o 4 en 32 bits, lo que significa que para interpretarlo directamente directamente, ¡para empezar, debe saber si el proceso es de 64 bits o 32 bits!auxv
códigos clave se ajustan a 32 bitsunsigned long
, por lo que los 32 bits más significativos en una caja de 64 bits serían cero.Busque en
/proc/$pid/maps
. Los rangos de direcciones son más de direcciones de 32 bits (8 dígitos hexadecimales) o direcciones de 64 bits (16 dígitos hexadecimales). Esto funciona para cualquier tipo de ejecutable, sin importar el formato. Solo puede obtener información sobre los procesos que se ejecutan como el mismo usuario (a menos que sea root).Si no tiene permiso para acceder a este archivo, creo que la única forma es tratar de analizar el ejecutable. (Si bien siempre puede leer
/proc/$pid/stat
, ninguno de los campos que se muestran para los procesos que se ejecutan a medida que diferentes usuarios revelan el tamaño de bits del proceso). Puede adivinar el ejecutable del procesops -o comm=
y buscarlo en elPATH
, pero tenga cuidado de que el proceso puede haber sido lanzado con un diferentePATH
, o puede haber reescrito suargv[0]
. Luego puede analizar el ejecutable; si está dispuesto a asumir ELF, mire el quinto byte .fuente
vsyscall
mapa es siempre el más alto, usted podría conseguir lejos con sólo cambiarhead
atail
- los que, por desgracia, no va a funcionar porque proc no poner en prácticaseek(2)
, por lo que tendrá que ser algo más feo, comoawk /proc/self/maps -- 'END { print substr($1, 0, 9); }'