Якщо ви хочете обмежити себе виявлення 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
. Не цитуйте мене з цього приводу, але, здається, значення слід інтерпретувати як а, 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 для: нижньої оболонки 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, передана процесу в exec час. Формат - це один неподписаний довгий ідентифікатор плюс одне довге неподписане значення для кожного запису" (man proc
).