Si vous souhaitez vous limiter à la détection ELF, vous pouvez lire l'en- tête ELF de /proc/$PID/exe
vous - même. C'est assez banal: si le 5ème octet du fichier est 1, c'est un binaire 32 bits. Si c'est 2, c'est 64 bits. Pour une vérification supplémentaire de la santé mentale:
- Si les 5 premiers octets sont
0x7f, "ELF", 1
: c'est un binaire ELF 32 bits.
- Si les 5 premiers octets sont
0x7f, "ELF", 2
: c'est un binaire ELF 64 bits.
- Sinon: ce n'est pas concluant.
Vous pouvez également utiliser objdump
, mais cela supprime votre libmagic
dépendance et la remplace par une libelf
autre.
Une autre façon : vous pouvez également analyser le /proc/$PID/auxv
fichier. Selon proc(5)
:
Il contient le contenu des informations d'interpréteur ELF transmises au processus au moment de l'exécution. Le format est un ID long non signé plus une valeur longue non signée pour chaque entrée. La dernière entrée contient deux zéros.
Les significations des unsigned long
touches sont là /usr/include/linux/auxvec.h
. Vous voulez AT_PLATFORM
, ce qui est 0x00000f
. Ne me citez pas à ce sujet, mais il semble que la valeur devrait être interprétée comme un char *
pour obtenir la description de la chaîne de la plate-forme.
Vous pouvez trouver cette question StackOverflow utile.
Encore une autre façon : vous pouvez demander au linker dynamique ( man ld
) de vider les informations sur l'exécutable. Il imprime sur la sortie standard la structure AUXV décodée. Attention: c'est un hack, mais ça marche.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Cela montrera quelque chose comme:
AT_PLATFORM: x86_64
Je l'ai essayé sur un binaire 32 bits et l'ai obtenu à la i686
place.
Comment cela fonctionne: LD_SHOW_AUXV=1
demande au Dynamic Linker de vider la structure AUXV décodée avant d'exécuter l'exécutable. À moins que vous n'aimiez vraiment rendre votre vie intéressante, vous voulez éviter d' exécuter réellement ledit exécutable. Une façon de le charger et de le lier dynamiquement sans réellement appeler sa main()
fonction est de l'exécuter ldd(1)
. L'inconvénient: LD_SHOW_AUXV
est activé par le shell, vous obtiendrez donc des vidages des structures AUXV pour: le sous-shell ldd
, et votre binaire cible. Nous avons donc grep
pour AT_PLATFORM, mais ne gardons que la dernière ligne.
Analyse Auxv : si vous analysez la auxv
structure vous-même (sans compter sur le chargeur dynamique), il y a un peu d'énigme: la auxv
structure suit la règle du processus qu'elle décrit, elle sizeof(unsigned long)
sera donc 4 pour les processus 32 bits et 8 pour 64 processus de bits. Nous pouvons faire en sorte que cela fonctionne pour nous. Pour que cela fonctionne sur les systèmes 32 bits, tous les codes clés doivent être 0xffffffff
ou moins. Sur un système 64 bits, les 32 bits les plus significatifs seront nuls. Les machines Intel sont peu endians, donc ces 32 bits suivent les moins significatifs en mémoire.
À ce titre, il vous suffit de:
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.
Analyser le fichier de cartes : cela a été suggéré par Gilles, mais n'a pas vraiment fonctionné. Voici une version modifiée qui le fait. Il repose sur la lecture du /proc/$PID/maps
fichier. Si le fichier répertorie les adresses 64 bits, le processus est de 64 bits. Sinon, c'est 32 bits. Le problème réside dans le fait que le noyau simplifiera la sortie en supprimant les zéros de tête des adresses hexadécimales en groupes de 4, de sorte que le hack de longueur ne peut pas tout à fait fonctionner. awk
à la rescousse:
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
Cela fonctionne en vérifiant l'adresse de départ de la dernière carte mémoire du processus. Ils sont listés comme 12345678-deadbeef
. Donc, si le processus est de 32 bits, cette adresse comportera huit chiffres hexadécimaux et le neuvième sera un tiret. S'il s'agit d'un 64 bits, l'adresse la plus élevée sera plus longue que cela. Le neuvième caractère sera un chiffre hexadécimal.
Attention: toutes les méthodes sauf la première et la dernière ont besoin du noyau Linux 2.6.0 ou plus récent, car le auxv
fichier n'était pas là auparavant.
/proc/[pid]/auxv
: "les informations d'interpréteur ELF transmises au processus au moment de l'exécution. Le format est un ID long non signé plus une valeur longue non signée pour chaque entrée" (man proc
).hd
éditer un et il lui manquait le chiffre magique. Il peut y avoir des informations pertinentes ici, mais je pense qu'elles seraient sujettes à des changements plus fréquents que l'en-tête ELF lui-même. Il a également été introduit dans 2.6.0, il n'est donc pas aussi omniprésent que/proc/PID/exe
. Mais il contient les informations sur l'architecture. Je mettrai à jour ma réponse.sizeof(unsigned long)
est 8 sur 64 bits ou 4 sur 32 bits, ce qui signifie que pour l'interpréter correctement directement, vous devez savoir si le processus est 64 bits ou 32 bits pour commencer!auxv
codes clés correspondent à un 32 bitsunsigned long
, donc le 32 bits le plus significatif sur une boîte de 64 bits serait zéro.Regardez
/proc/$pid/maps
. Les plages d'adresses sont sur des adresses 32 bits (8 chiffres hexadécimaux) ou des adresses 64 bits (16 chiffres hexadécimaux). Cela fonctionne pour tout type d'exécutable, quel que soit le format. Vous pouvez uniquement obtenir des informations sur les processus exécutés en tant que même utilisateur (sauf si vous êtes root).Si vous n'avez pas la permission d'accéder à ce fichier, alors je pense que la seule façon est d'essayer d'analyser l'exécutable. (Bien que vous puissiez toujours lire
/proc/$pid/stat
, aucun des champs affichés pour les processus exécutés en tant qu'utilisateurs différents ne révèle la taille en bits du processus.) Vous pouvez faire une bonne estimation de l'exécutable du processus avecps -o comm=
, et le rechercher dans lePATH
- mais attention que le processus peut avoir été lancé avec un autrePATH
, ou peut avoir été réécritargv[0]
. Vous pouvez ensuite analyser l'exécutable - si vous êtes prêt à assumer ELF, regardez le 5ème octet .la source
vsyscall
carte est toujours le plus haut, vous pouvez vous contenter de changer justehead
pourtail
- qui, malheureusement, ne fonctionnera pas parce que proc n'implémente passeek(2)
, donc ça va être quelque chose plus laid, commeawk /proc/self/maps -- 'END { print substr($1, 0, 9); }'