Визначте, чи є конкретний процес 32- або 64-розрядним


14

З огляду на 2.6.x або новіше ядро ​​Linux та наявну користувальницьку область, яка здатна запускати як бінарні файли ELF32, так і ELF64 (тобто добре минуло. Як мені знати, що мій процесор підтримує 64-бітні операційні системи під Linux? ), Як я можу визначити, чи є даний процес ( за 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, переданої в процес у виконаний час. Формат - це один неподписаний довгий ідентифікатор плюс одне довге неподписане значення для кожного запису. Останній запис містить дві нулі.

Значення 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файлу раніше не було.


1
Гммм, мені цікаво, чи знаходиться заголовок ELF /proc/[pid]/auxv: "Інформація інтерпретатора ELF, передана процесу в exec час. Формат - це один неподписаний довгий ідентифікатор плюс одне довге неподписане значення для кожного запису" ( man proc).
золотинки

1
Сам заголовок не є. Я щойно hdредагував його, і йому не вистачало чарівного номера. Там може бути якась відповідна інформація, але я думаю, що вона може зазнавати більш частих змін, ніж сам заголовок ELF. Він також був представлений в 2.6.0, тому він не настільки всюдисущий /proc/PID/exe. Але це дійсно є інформація про архітектурі. Я оновлю свою відповідь.
Олексій

auxv виявився складнішим, ніж я сподівався, - sizeof(unsigned long)це 8 на 64 біт або 4 на 32 біт, що означає, що для правильного його інтерпретації ви повинні знати, чи для цього процес має 64 біт або 32 біт!
Flexo

Ви абсолютно праві. Це дуже дратує. Швидке евристичне: якщо у байтах 16x + y (4≤y≤7) всі файли нульові, ви шукаєте 64-бітний виконуваний файл. Це хитрість: я припускаю, що маленька ендіанська машина, і що всі auxvключові коди відповідають 32-розрядному unsigned long, тож найбільш значущі 32-бітові 64-бітні коробки будуть нульовими.
Алексіос

6

Загляньте /proc/$pid/maps. Діапазони адрес - це понад 32-бітні адреси (8 шістнадцяткових цифр) або 64-бітні адреси (16 шістнадцяткових цифр). Це працює для будь-якого типу виконуваного файлу, незалежно від формату. Ви можете отримати інформацію лише про процеси, які виконуються як той самий користувач (якщо ви не root).

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 за замовчуванням, / bin / bash. Рядки / proc / $ pid / map для двійкової та першої купи написані у 32-бітовому стилі, але всі інші - у 64-бітному стилі. Ймовірно, вони надруковані за допомогою "% 08x", але все одно цей рецепт має бути скоригований.
Netch

Я отримую суміш 8, 12 та 16-ніблівних значень у всіх полях, з якими я пробував. Не перевіряючи джерело, я здогадуюсь, що ядро ​​налаштовує прокладку до найменшого кратного 16-бітового діапазону, що перевищує діапазон адрес для кожного надрукованого рядка, тому вам доведеться знайти найдовшу послідовність шістнадцяткових символів, а потім перевірити.
Олексій

АЛЕ, оскільки vsyscallкарта завжди найвищі, ви могли б піти тільки зі зміною headдо tail- які, до жаль, не буде працювати , тому що процедура не виконує seek(2), так що це повинно бути що - то потворним, якawk /proc/self/maps -- 'END { print substr($1, 0, 9); }'
Алексіос

@Netch Дійсно, я тупо дивився на лінії vsyscall та stack і не звертав уваги на відображення виконуваного файлу. Дякую, я оновив пошук будь-якої не 32-бітної лінії. Вибачте, це більш бридке, але це найнадійніший (принаймні, це впевнений хід на x86, я не перевіряв інших подвійних архітектур, таких як sparc і arm).
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.