Если вы хотите ограничить себя обнаружение 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, переданной процессу во время исполнения. Формат - один длинный беззнаковый идентификатор плюс одно длинное без знака для каждой записи. Последняя запись содержит два нуля.
Значения unsigned longключей в /usr/include/linux/auxvec.h. Вы хотите AT_PLATFORM, что есть 0x00000f. Не цитируйте меня по этому поводу, но, похоже, значение следует интерпретировать как a, 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инструктирует Dynamic Linker сбросить декодированную структуру AUXV перед запуском исполняемого файла. Если вы действительно не хотите сделать свою жизнь интересной, вы не должны запускать указанный исполняемый файл. Один из способов загрузить и динамически связать его без фактического вызова его main()функции - запустить ldd(1)его. Оборотная сторона: LD_SHOW_AUXVвключена оболочкой, поэтому вы получите дампы структур AUXV для: subshell lddи вашего целевого двоичного файла . Так что мы grepза AT_PLATFORM, но сохраняем только последнюю строчку.
Разбор auxv : если вы анализируете auxvструктуру самостоятельно (не полагаясь на динамический загрузчик), то возникает небольшая загадка: auxvструктура следует правилу процесса, который она описывает, поэтому sizeof(unsigned long)будет 4 для 32-битных процессов и 8 для 64 процессы. Мы можем сделать эту работу для нас. Чтобы это работало в 32-битных системах, все коды клавиш должны быть 0xffffffffили меньше. В 64-битной системе наиболее значимые 32 бита будут равны нулю. Машины Intel имеют младший порядок, поэтому эти 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.
Разбор файла карт : это было предложено Жилем, но не совсем сработало. Вот модифицированная версия, которая делает. Это полагается на чтение /proc/$PID/mapsфайла. Если файл содержит 64-битные адреса, процесс будет 64-битным. В противном случае это 32 бита. Проблема заключается в том, что ядро упростит вывод, удалив начальные нули из шестнадцатеричных адресов в группах по 4, поэтому взлом длины не может работать. 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-битный, этот адрес будет иметь длину восемь шестнадцатеричных цифр, а девятый будет дефисом. Если это 64-битный, самый высокий адрес будет длиннее. Девятый символ будет шестнадцатеричной цифрой.
Имейте в виду: для всех, кроме первого и последнего методов, требуется ядро Linux 2.6.0 или новее, поскольку auxvфайла там не было раньше.
/proc/[pid]/auxv: «Информация интерпретатора ELF, переданная процессу во время выполнения. Формат - один длинный беззнаковый идентификатор и одно длинное значение без знака для каждой записи» (man proc).