특정 프로세스가 32 비트인지 64 비트인지 확인 어떻게 알 수 있습니까? )에서 지정된

ELF32 및 ELF64 바이너리를 모두 실행할 수있는 2.6.x 이상의 최신 Linux 커널 및 기존 사용자 영역 (예 : CPU가 Linux에서 64 비트 운영 체제를 지원한다는 것을 어떻게 알있습니까? )에서 지정된 프로세스를 어떻게 확인할 수 있습니까? by PID)가 32 비트 또는 64 비트 모드로 실행 중입니까?

순진한 솔루션은 다음을 실행하는 것입니다.

file -L /proc/pid/exe | grep -o 'ELF ..-bit [LM]SB'

그러나 그 정보는 /proc의존하지 않고 직접 노출 되어 libmagic있습니까?



답변

자신을 ELF 감지로 제한하려면 자신의 ELF 헤더 를 읽을 수 있습니다 /proc/$PID/exe. 파일의 5 번째 바이트가 1이면 32 비트 이진입니다. 2이면 64 비트입니다. 위생 검사 추가 :

  1. 처음 5 바이트가 0x7f, "ELF", 1: 32 비트 ELF 바이너리입니다.
  2. 처음 5 바이트 인 경우 0x7f, "ELF", 2: 64 비트 ELF 이진입니다.
  3. 그렇지 않으면 : 결정적이지 않습니다.

당신은 또한 사용할 수 objdump있지만 libmagic의존성을 없애고 그것을 libelf하나로 대체합니다 .

다른 방법 : /proc/$PID/auxv파일을 파싱 ​​할 수도 있습니다. 에 따르면 proc(5):

여기에는 실행 시간에 프로세스에 전달 된 ELF 인터프리터 정보의 내용이 포함됩니다. 형식은 하나의 부호없는 long ID와 각 항목에 대한 하나의 unsigned long 값입니다. 마지막 항목에는 두 개의 0이 있습니다.

unsigned long키 의 의미 는에 /usr/include/linux/auxvec.h있습니다. 당신은 원하는 AT_PLATFORM0x00000f. 저를 인용하지 마십시오, 그러나 char *플랫폼의 문자열 설명을 얻기 위해 값을 해석해야합니다 .

이 StackOverflow 질문이 유용 할 수 있습니다 .

또 다른 방법 : 동적 링커 ( man ld)에 실행 파일에 대한 정보를 덤프 하도록 지시 할 수 있습니다 . 디코딩 된 AUXV 구조를 표준 출력으로 인쇄합니다. 경고 : 이것은 해킹이지만 작동합니다.

LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1

이것은 다음과 같이 보일 것입니다 :

AT_PLATFORM:     x86_64

32 비트 바이너리로 시도해 보았습니다 i686.

작동 방식 : LD_SHOW_AUXV=1동적 링커가 실행 파일을 실행하기 전에 디코딩 된 AUXV 구조를 덤프하도록 지시합니다. 당신이하지 않으면 정말 당신의 인생의 재미를 만들기 위해 좋아, 당신은 실제로 피하려고 실행 실행했다. 실제로 main()함수를 호출하지 않고로드하고 동적으로 링크하는 한 가지 방법 은 해당 함수를 실행 ldd(1)하는 것입니다. 단점 LD_SHOW_AUXV은 셸에서 활성화되므로 하위 셸 ldd및 대상 바이너리 에 대한 AUXV 구조 덤프가 표시 됩니다. 그래서 우리 grep는 AT_PLATFORM 을 위해 마지막 줄만 유지합니다.

auxv 구문 분석 : auxv구조를 직접 구문 분석하면 (동적 로더에 의존하지 않음) 약간의 수수께끼가 있습니다. auxv구조는 설명하는 프로세스 규칙을 따르므로 sizeof(unsigned long)32 비트 프로세스의 경우 4 , 64의 경우 8입니다 비트 프로세스. 우리는 우리를 위해이 일을 할 수 있습니다. 이것이 32 비트 시스템에서 작동하려면 모든 키 코드가 0xffffffff이하 여야합니다 . 64 비트 시스템에서 가장 중요한 32 비트는 0입니다. 인텔 컴퓨터는 작은 엔디안이므로이 32 비트는 메모리에서 가장 중요하지 않은 컴퓨터를 따릅니다.

따라서 필요한 것은 다음과 같습니다.

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.

지도 파일 파싱 : 이것은 Gilles가 제안했지만 제대로 작동하지 않았습니다. 수정 된 버전은 다음과 같습니다. /proc/$PID/maps파일 읽기에 의존 합니다. 파일에 64 비트 주소가 나열되면 프로세스는 64 비트입니다. 그렇지 않으면 32 비트입니다. 문제는 커널이 4 그룹의 16 진 주소에서 선행 0을 제거하여 출력을 단순화하므로 길이 해킹이 제대로 작동하지 않는다는 것입니다. awk구조에 :

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

이것은 프로세스의 마지막 메모리 맵의 시작 주소를 확인하여 작동합니다. 그것들은 다음과 같습니다 12345678-deadbeef. 따라서 프로세스가 32 비트 프로세스 인 경우 해당 주소의 길이는 8 개의 16 진수이며 9 번째는 하이픈이됩니다. 64 비트 주소 인 경우 가장 높은 주소가 그보다 깁니다. 아홉 번째 문자는 16 진수입니다.

주의 : auxv파일이 이전에 없었기 때문에 첫 번째 방법과 마지막 방법을 제외한 모든 방법에는 Linux 커널 2.6.0 이상이 필요합니다 .


답변

에서 찾아보십시오 /proc/$pid/maps. 주소 범위는 32 비트 주소 (8 개의 16 진수) 또는 64 비트 주소 (16 개의 16 진수)입니다. 형식에 관계없이 모든 종류의 실행 파일에서 작동합니다. 루트가 아닌 한 동일한 사용자로 실행중인 프로세스에 대한 정보 만 얻을 수 있습니다.

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

이 파일에 액세스 할 수있는 권한이 없으면 실행 파일을 분석하는 것이 유일한 방법이라고 생각합니다. (항상 읽을 수는 있지만 /proc/$pid/stat다른 사용자로 실행되는 프로세스에 대해 표시되는 필드는 프로세스의 비트 크기를 나타내지 않습니다.)로 프로세스의 실행 파일을 잘 추측 할 수는 있지만 프로세스에서 ps -o comm=이를 찾을 수는 PATH있지만 다른 것으로 시작 PATH되었거나 다시 작성했을 수 있습니다 argv[0]. 그런 다음 실행 파일을 분석 할 수 있습니다. ELF를 원한다면 5 번째 바이트를보십시오 .