Se você deseja limitar-se à detecção de ELF, pode ler o cabeçalho ELF de /proc/$PID/exesi mesmo. É bastante trivial: se o quinto byte do arquivo for 1, é um binário de 32 bits. Se for 2, é de 64 bits. Para verificação de sanidade adicional:
- Se os primeiros 5 bytes forem
0x7f, "ELF", 1: é um binário ELF de 32 bits.
- Se os primeiros 5 bytes forem
0x7f, "ELF", 2: é um binário ELF de 64 bits.
- Caso contrário: é inconclusivo.
Você também pode usar objdump, mas isso tira a sua libmagicdependência e a substitui por uma libelf.
Outra maneira : você também pode analisar o /proc/$PID/auxvarquivo. De acordo com proc(5):
Ele contém o conteúdo das informações do interpretador ELF passadas para o processo no momento da execução. O formato é um ID longo não assinado mais um valor longo não assinado para cada entrada. A última entrada contém dois zeros.
Os significados das unsigned longteclas estão em /usr/include/linux/auxvec.h. Você quer AT_PLATFORM, o que é 0x00000f. Não me cite, mas parece que o valor deve ser interpretado como um char *para obter a descrição da plataforma da string.
Você pode achar útil essa pergunta sobre StackOverflow .
Outra maneira : você pode instruir o vinculador dinâmico ( man ld) a despejar informações sobre o executável. Ele imprime na saída padrão a estrutura AUXV decodificada. Aviso: isso é um hack, mas funciona.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Isso mostrará algo como:
AT_PLATFORM: x86_64
Eu tentei em um binário de 32 bits e consegui i686.
Como isso funciona: LD_SHOW_AUXV=1instrui o Dynamic Linker a despejar a estrutura AUXV decodificada antes de executar o executável. A menos que você realmente goste de tornar sua vida interessante, você deseja evitar executar o referido executável. Uma maneira de carregá-lo e vinculá-lo dinamicamente sem realmente chamar sua main()função é executá ldd(1)-lo. A desvantagem: LD_SHOW_AUXVé ativada pelo shell, para que você obtenha despejos das estruturas AUXV para: o subshell ldd, e o seu binário de destino. Então, greppara AT_PLATFORM, mantemos apenas a última linha.
Analisando auxv : se você analisar a auxvestrutura você mesmo (sem depender do carregador dinâmico), haverá um pouco de um dilema: a auxvestrutura segue a regra do processo descrito, sizeof(unsigned long)sendo 4 para processos de 32 bits e 8 para 64 processos de bits. Podemos fazer isso funcionar para nós. Para que isso funcione em sistemas de 32 bits, todos os códigos de chave devem ser 0xffffffffou menos. Em um sistema de 64 bits, os 32 bits mais significativos serão zero. As máquinas Intel são pouco conhecidas, portanto esses 32 bits seguem os menos significativos na memória.
Como tal, tudo o que você precisa fazer é:
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.
Analisando o arquivo de mapas : isso foi sugerido por Gilles, mas não funcionou completamente. Aqui está uma versão modificada que faz. Depende da leitura do /proc/$PID/mapsarquivo. Se o arquivo listar endereços de 64 bits, o processo será de 64 bits. Caso contrário, são 32 bits. O problema reside no fato de o kernel simplificar a saída eliminando os zeros à esquerda dos endereços hexadecimais nos grupos de 4, para que o tamanho não funcione. awkpara o resgate:
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
Isso funciona verificando o endereço inicial do último mapa de memória do processo. Eles estão listados como 12345678-deadbeef. Portanto, se o processo for de 32 bits, esse endereço terá oito dígitos hexadecimais e o nono será um hífen. Se for de 64 bits, o endereço mais alto será mais longo que isso. O nono caractere será um dígito hexadecimal.
Esteja ciente: todos, exceto o primeiro e o último método, precisam do kernel Linux 2.6.0 ou mais recente, pois o auxvarquivo não estava lá antes.
/proc/[pid]/auxv: "as informações do interpretador ELF passadas para o processo no momento da execução. O formato é um ID longo não assinado mais um valor longo não assinado para cada entrada" (man proc).