특정 프로세스가 32 비트인지 64 비트인지 확인


14

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있습니까?

답변:


21

자신을 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 이상이 필요합니다 .


1
흠, ELF 헤더가 다음과 같은지 궁금합니다 /proc/[pid]/auxv. "ELF 인터프리터 정보가 실행 시간에 프로세스에 전달되었습니다. 형식은 하나의 부호없는 long ID와 각 항목에 대한 하나의 unsigned long 값" ( man proc)입니다.
goldilocks

1
헤더 자체는 그렇지 않습니다. 방금 hd하나를 썼는데 마법 번호가 부족했습니다. 관련 정보가있을 수 있지만 ELF 헤더 자체보다 자주 변경 될 수 있다고 생각합니다. 또한 2.6.0에서 도입되었으므로 유비쿼터스가 아닙니다 /proc/PID/exe. 그러나 않는 아키텍처 정보가 있습니다. 답변을 업데이트하겠습니다.
Alexios

auxv는 내가 기대했던 것보다 까다로운 것으로 판명되었습니다 .64 sizeof(unsigned long)비트에서 8 비트 또는 32 비트에서 4 비트는 직접 해석하기 때문에 프로세스가 64 비트인지 32 비트인지 알아야합니다!
Flexo

당신 말이 맞아요 꽤 성가신 일입니다. 빠른 휴리스틱 : 파일에서 16x + y (4≤y≤7) 바이트가 모두 0이면 64 비트 실행 파일을보고있는 것입니다. 이것은 작은 문제입니다. 작은 엔디안 머신을 가정하고 모든 auxv키 코드가 32 비트에 적합 unsigned long하므로 64 비트 상자에서 가장 중요한 32 비트는 0이 될 것입니다.
Alexios

6

에서 찾아보십시오 /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 번째 바이트를보십시오 .


레시피를 테스트했는데 실패했습니다. OpenSuSE 12.2, x86-64, 커널 3.4.63-2.44-default, / bin / bash. 바이너리 및 첫 번째 힙에 대한 / proc / $ pid / maps 행은 32 비트 스타일로 작성되지만 다른 모든 힙은 64 비트 스타일로 작성됩니다. "% 08x"를 사용하여 인쇄되었을 가능성이 있지만이 레시피는 조정해야합니다.
Netch

내가 시도한 모든 상자에 8, 12 및 16 니블 값이 혼합되어 있습니다. 소스를 확인하지 않고 커널은 패딩이 인쇄 된 각 줄의 주소 범위보다 16 비트의 가장 작은 배수로 패딩을 조정하므로 가장 긴 16 진수 문자를 찾은 다음 확인해야합니다.
Alexios

이후하지만, vsyscall지도는 항상 최고입니다, 당신은 단지 변화 멀리 얻을 수 headtail-하는, 슬프게도, PROC 작업을 구현하지 않을 것이기 때문에 seek(2)이 같은 뭔가 추악한 일해야합니다, 그래서awk /proc/self/maps -- 'END { print substr($1, 0, 9); }'
알렉 시우스

@Netch 실제로, 나는 vsyscall과 stack 행을 어리석게 보았으며 실행 파일의 매핑에주의를 기울이지 않았습니다. 감사합니다, 32 비트가 아닌 라인을 찾도록 업데이트되었습니다. 동정, 그것은 더 추악하지만 이것은 가장 안정적입니다 (적어도 x86에서는 확실합니다. 나는 sparc 및 arm과 같은 다른 이중 아키텍처로는 확인하지 않았습니다).
Gilles 'SO- 악마 그만해
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.