Determine se um processo específico é de 32 ou 64 bits

2 respostas

18

Se você quiser se limitar à detecção ELF, leia o cabeçalho ELF de /proc/$PID/exe você mesmo . É bastante trivial: se o quinto byte no arquivo for 1, é um binário de 32 bits. Se é 2, é de 64 bits. Para verificação adicional de sanidade:

  1. Se os primeiros 5 bytes forem 0x7f, "ELF", 1 : é um binário ELF de 32 bits.
  2. Se os primeiros 5 bytes forem 0x7f, "ELF", 2 : é um binário ELF de 64 bits.
  3. Caso contrário: é inconclusivo.

Você também pode usar objdump , mas isso tira sua dependência de libmagic e a substitui por libelf .

Outra maneira : você também pode analisar o arquivo /proc/$PID/auxv . De acordo com proc(5) :

This contains the contents of the ELF interpreter information passed to the process at exec time. The format is one unsigned long ID plus one unsigned long value for each entry. The last entry contains two zeros.

Os significados das chaves unsigned long estão em /usr/include/linux/auxvec.h . Você quer AT_PLATFORM , que é 0x00000f . Não me cite sobre isso, mas parece que o valor deve ser interpretado como char * para obter a descrição da string da plataforma.

Você pode encontrar esta pergunta StackOverflow útil.

Ainda de outra forma : 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 recebi i686 .

Como isso funciona: LD_SHOW_AUXV=1 instrui 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ê quer evitar realmente executar o executável. Uma maneira de carregá-lo e vinculá-lo dinamicamente sem realmente chamar sua função main() é executar ldd(1) nele. A desvantagem: LD_SHOW_AUXV é ativado pelo shell, portanto, você obterá dumps das estruturas do AUXV para: o subshell, ldd e seu binário de destino. Então, nós grep para AT_PLATFORM, mas mantemos apenas a última linha.

Parsing auxv : se você mesmo analisar a estrutura auxv (não contando com o carregador dinâmico), então há um pouco de enigma: a estrutura auxv segue a regra do processo ele descreve, portanto sizeof(unsigned long) será 4 para processos de 32 bits e 8 para processos de 64 bits. Nós podemos fazer isso funcionar para nós. Para que isso funcione em sistemas de 32 bits, todos os códigos de chave devem ser 0xffffffff ou menos. Em um sistema de 64 bits, os 32 bits mais significativos serão zero. As máquinas da Intel são little endians, então esses 32 bits seguem os menos significativos da memória.

Como tal, tudo 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 direito. Aqui está uma versão modificada que faz. Ele depende da leitura do arquivo /proc/$PID/maps . Se o arquivo listar endereços de 64 bits, o processo será de 64 bits. Caso contrário, são 32 bits. O problema é que o kernel irá simplificar a saída, retirando os zeros à esquerda dos endereços hexadecimais em grupos de 4, então o comprimento não pode funcionar. awk para 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 um de 64 bits, o endereço mais alto será maior do que isso. O nono caractere será um dígito hexadecimal.

Lembre-se: todos os métodos, exceto o primeiro e o último, precisam do kernel Linux 2.6.0 ou mais recente, pois o arquivo auxv não estava lá antes.

    
por 22.12.2013 / 14:56
5

Procure em /proc/$pid/maps . Os intervalos de endereços são endereços de mais de 32 bits (8 dígitos hexadecimais) ou endereços de 64 bits (16 dígitos hexadecimais). Isso funciona para qualquer tipo de executável, não importa o formato. Você só pode obter informações sobre processos em execução como o mesmo usuário (a menos que você seja root).

if ! [ -e /proc/$pid/maps ]; then
  echo No such process
elif grep -q '^........[^-]' /proc/$pid/maps; then
  echo 64-bit
elif grep -q . /proc/$pid/maps; then
  echo 32-bit
else
  echo Insufficient permissions
fi

Se você não tem permissão para acessar este arquivo, acho que a única maneira é tentar analisar o executável. (Embora você sempre possa ler /proc/$pid/stat , nenhum dos campos mostrados para processos executados como usuários diferentes revelam o tamanho de bit do processo.) Você pode adivinhar o executável do processo com ps -o comm= , e verificar isso no PATH - mas cuidado com o processo que pode ter sido iniciado com um% diferentePATH, ou pode ter reescrito seu argv[0] . Você pode então analisar o executável - se estiver disposto a assumir o ELF, observe o 5º byte .

    
por 23.12.2013 / 01:27