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 비트입니다. 위생 검사 추가 :
- 처음 5 바이트가
0x7f, "ELF", 1
: 32 비트 ELF 바이너리입니다. - 처음 5 바이트 인 경우
0x7f, "ELF", 2
: 64 비트 ELF 이진입니다. - 그렇지 않으면 : 결정적이지 않습니다.
당신은 또한 사용할 수 objdump
있지만 libmagic
의존성을 없애고 그것을 libelf
하나로 대체합니다 .
다른 방법 : /proc/$PID/auxv
파일을 파싱 할 수도 있습니다. 에 따르면 proc(5)
:
여기에는 실행 시간에 프로세스에 전달 된 ELF 인터프리터 정보의 내용이 포함됩니다. 형식은 하나의 부호없는 long ID와 각 항목에 대한 하나의 unsigned long 값입니다. 마지막 항목에는 두 개의 0이 있습니다.
unsigned long
키 의 의미 는에 /usr/include/linux/auxvec.h
있습니다. 당신은 원하는 AT_PLATFORM
인 0x00000f
. 저를 인용하지 마십시오, 그러나 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 번째 바이트를보십시오 .