Se vuoi limitarti al rilevamento ELF, puoi leggere l' intestazione ELF di /proc/$PID/exe
te stesso. È abbastanza banale: se il 5 ° byte nel file è 1, è un file binario a 32 bit. Se è 2, è a 64 bit. Per un ulteriore controllo di integrità:
- Se i primi 5 byte sono
0x7f, "ELF", 1
: è un binario ELF a 32 bit.
- Se i primi 5 byte sono
0x7f, "ELF", 2
: è un binario ELF a 64 bit.
- Altrimenti: è inconcludente.
Potresti anche usare objdump
, ma questo toglie la tua libmagic
dipendenza e la sostituisce con una libelf
.
Un altro modo : puoi anche analizzare il /proc/$PID/auxv
file. Secondo proc(5)
:
Questo contiene il contenuto delle informazioni sull'interprete ELF trasmesse al processo al momento dell'esecuzione. Il formato è un ID lungo senza segno più un valore lungo senza segno per ogni voce. L'ultima voce contiene due zeri.
I significati delle unsigned long
chiavi sono dentro /usr/include/linux/auxvec.h
. Tu vuoi AT_PLATFORM
, che è 0x00000f
. Non citarmi su questo, ma sembra che il valore debba essere interpretato come a char *
per ottenere la descrizione della stringa della piattaforma.
Questa domanda StackOverflow può essere utile.
Ancora un altro modo : puoi istruire il linker dinamico ( man ld
) a scaricare informazioni sull'eseguibile. Stampa sull'output standard la struttura AUXV decodificata. Attenzione: questo è un trucco, ma funziona.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Questo mostrerà qualcosa di simile:
AT_PLATFORM: x86_64
L'ho provato su un binario a 32 bit e ho ottenuto i686
invece.
Come funziona: LD_SHOW_AUXV=1
indica a Dynamic Linker di scaricare la struttura AUXV decodificata prima di eseguire l'eseguibile. A meno che non ti piaccia davvero rendere la tua vita interessante, vuoi evitare di eseguire effettivamente detto eseguibile. Un modo per caricarlo e collegarlo dinamicamente senza effettivamente chiamarne la main()
funzione è eseguirlo ldd(1)
. Il rovescio della medaglia: LD_SHOW_AUXV
è abilitato dalla shell, quindi otterrai dump delle strutture AUXV per: la subshell ldd
e il tuo binario di destinazione. Quindi siamo grep
per AT_PLATFORM, ma manteniamo solo l'ultima riga.
Analisi ausiliaria : se analizzi tu stesso la auxv
struttura (non basandoti sul caricatore dinamico), allora c'è un po 'di enigma: la auxv
struttura segue la regola del processo che descrive, quindi sizeof(unsigned long)
saranno 4 per i processi a 32 bit e 8 per 64 processi a bit. Possiamo farlo funzionare per noi. Affinché ciò funzioni su sistemi a 32 bit, tutti i codici chiave devono essere 0xffffffff
o meno. Su un sistema a 64 bit, i 32 bit più significativi saranno zero. I computer Intel sono piccoli endian, quindi questi 32 bit seguono quelli meno significativi in memoria.
Pertanto, tutto ciò che devi fare è:
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.
Analizzare il file delle mappe : questo è stato suggerito da Gilles, ma non ha funzionato del tutto. Ecco una versione modificata che lo fa. Si basa sulla lettura del /proc/$PID/maps
file. Se il file elenca gli indirizzi a 64 bit, il processo è a 64 bit. Altrimenti, sono 32 bit. Il problema sta nel fatto che il kernel semplifica l'output rimuovendo gli zero iniziali dagli indirizzi esadecimali in gruppi di 4, quindi l'hacking di lunghezza non può funzionare del tutto. awk
Al salvataggio:
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
Funziona controllando l'indirizzo iniziale dell'ultima mappa di memoria del processo. Sono elencati come 12345678-deadbeef
. Quindi, se il processo è a 32 bit, quell'indirizzo avrà una lunghezza di otto cifre esadecimali e il nono sarà un trattino. Se è a 64 bit, l'indirizzo più alto sarà più lungo di quello. Il nono carattere sarà una cifra esadecimale.
Attenzione: tutti tranne il primo e l'ultimo metodo richiedono il kernel Linux 2.6.0 o successivo, poiché il auxv
file non era presente prima.
/proc/[pid]/auxv
: "le informazioni sull'interprete ELF sono passate al processo al momento dell'esecuzione. Il formato è un ID lungo senza segno più un valore lungo senza segno per ogni voce" (man proc
).