Jeśli chcesz ograniczyć się do wykrywania ELF można przeczytać nagłówek ELF o /proc/$PID/exe
siebie. Jest to dość trywialne: jeśli 5. bajt w pliku ma wartość 1, jest to 32-bitowy plik binarny. Jeśli to 2, to jest 64-bit. W celu dodatkowego sprawdzenia poczytalności:
- Jeśli pierwsze 5 bajtów to
0x7f, "ELF", 1
: 32-bitowy plik binarny ELF.
- Jeśli pierwsze 5 bajtów to
0x7f, "ELF", 2
: 64-bitowy plik binarny ELF.
- W przeciwnym razie: jest to niejednoznaczne.
Możesz także użyć objdump
, ale to usuwa twoją libmagic
zależność i zastępuje ją libelf
jedną.
Inny sposób : możesz także parsować /proc/$PID/auxv
plik. Według proc(5)
:
Zawiera zawartość informacji interpretera ELF przekazywanych do procesu w czasie wykonywania. Format to jeden bez znaku długi identyfikator plus jedna bez znaku długa wartość dla każdego wpisu. Ostatni wpis zawiera dwa zera.
Znaczenie unsigned long
kluczy jest w /usr/include/linux/auxvec.h
. ChceszAT_PLATFORM
, co jest 0x00000f
. Nie cytuj mnie, ale wygląda na to, że wartość należy interpretować jako char *
opis łańcucha dla platformy.
Możesz znaleźć przydać to pytanie StackOverflow .
Jeszcze inny sposób : możesz poinstruować linker dynamiczny (man ld
), aby zrzucił informacje o pliku wykonywalnym. Drukuje na standardowe wyjście zdekodowaną strukturę AUXV. Ostrzeżenie: jest to włamanie, ale działa.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
To pokaże coś takiego:
AT_PLATFORM: x86_64
Próbowałem na 32-bitowym pliku binarnym i dostałem i686
zamiast tego .
Jak to działa: LD_SHOW_AUXV=1
instruuje Dynamic Linker, aby zrzucił zdekodowaną strukturę AUXV przed uruchomieniem pliku wykonywalnego. Jeśli naprawdę nie chcesz, aby twoje życie było interesujące, chcesz uniknąć uruchamiania wspomnianego pliku wykonywalnego. Jednym ze sposobów ładowania i dynamicznego łączenia go bez wywoływania jego main()
funkcji jest uruchomienie ldd(1)
go. Wada: LD_SHOW_AUXV
jest włączona przez powłokę, więc otrzymasz zrzuty struktur AUXV dla: podpowłoki ldd
i docelowego pliku binarnego. Więc mamy grep
AT_PLATFORM, ale zachowujemy tylko ostatnią linię.
Parsowanie Auxv : jeśli parsujeszauxv
strukturę samodzielnie (nie polegając na dynamicznym module ładującym), to jest trochę zagadki: auxv
struktura postępuje zgodnie z zasadą opisanego procesu, więc sizeof(unsigned long)
będzie 4 dla procesów 32-bitowych i 8 dla 64 -bitowe procesy. Możemy sprawić, aby to działało dla nas. Aby działało to w systemach 32-bitowych, wszystkie kody kluczy muszą być 0xffffffff
mniejsze lub mniejsze. W systemie 64-bitowym najbardziej znaczące 32 bity będą wynosić zero. Maszyny Intela są małymi endianami, więc te 32 bity podążają za najmniej znaczącymi w pamięci.
W związku z tym wszystko, co musisz zrobić, to:
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.
Analiza pliku map : Gilles zasugerował, ale nie całkiem działał. Oto zmodyfikowana wersja, która działa. Polega na odczytaniu /proc/$PID/maps
pliku. Jeśli plik zawiera adresy 64-bitowe, proces ma 64 bity. W przeciwnym razie jest to 32 bity. Problem polega na tym, że jądro uprości dane wyjściowe, usuwając wiodące zera z adresów szesnastkowych w grupach po 4, więc hack długości nie może do końca działać. awk
na pomoc:
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
Działa to poprzez sprawdzenie adresu początkowego ostatniej mapy pamięci procesu. Są wymienione jak 12345678-deadbeef
. Tak więc, jeśli proces jest 32-bitowy, adres będzie miał osiem cyfr szesnastkowych, a dziewiąty będzie łącznikiem. Jeśli jest to wersja 64-bitowa, najwyższy adres będzie dłuższy. Dziewiąty znak będzie cyfrą szesnastkową.
Pamiętaj: wszystkie oprócz pierwszej i ostatniej metody wymagają jądra Linuksa 2.6.0 lub nowszego, ponieważ auxv
pliku nie było wcześniej.
/proc/[pid]/auxv
: „informacja interpretera ELF przekazywana do procesu w czasie wykonywania. Format to jeden długi identyfikator bez znaku plus jedna długa wartość bez znaku dla każdego wpisu” (man proc
).hd
zredagowałem jedną i brakowało jej magicznej liczby. Mogą tam być istotne informacje, ale myślę, że będą podlegać częstszym zmianom niż sam nagłówek ELF. Został również wprowadzony w wersji 2.6.0, więc nie jest tak wszechobecny jak/proc/PID/exe
. Ale ma informacje o architekturze. Zaktualizuję moją odpowiedź.sizeof(unsigned long)
ma 8 na 64 bity lub 4 na 32 bity, co oznacza, że aby poprawnie zinterpretować go bezpośrednio, musisz wiedzieć, czy proces jest 64-bitowy, czy 32-bitowy!auxv
kody kluczy pasują do 32-bitówunsigned long
, więc najbardziej znaczące 32-bity na 64-bitowym pudełku będą wynosić zero.Zajrzyj do środka
/proc/$pid/maps
. Zakresy adresów obejmują ponad 32-bitowe adresy (8 cyfr szesnastkowych) lub adresy 64-bitowe (16 cyfr szesnastkowych). Działa to dla każdego rodzaju pliku wykonywalnego, bez względu na format. Możesz uzyskać informacje tylko o procesach działających jako ten sam użytkownik (chyba że jesteś rootem).Jeśli nie masz uprawnień dostępu do tego pliku, myślę, że jedynym sposobem jest próba analizy pliku wykonywalnego. (Chociaż zawsze możesz czytać
/proc/$pid/stat
, żadne z pól pokazanych dla procesów działających jako różni użytkownicy nie ujawniają wielkości bitów procesu). Możesz dobrze zgadnąć, jaki jest wykonywalny procesps -o comm=
i patrząc na toPATH
- ale uważaj na ten proces mógł zostać uruchomiony z innymPATH
kodem lub mógł go przepisaćargv[0]
. Następnie możesz przeanalizować plik wykonywalny - jeśli chcesz założyć ELF, spójrz na 5 bajt .źródło
vsyscall
mapa jest zawsze najwyższa, możesz uniknąć zmiany po prostuhead
natail
- co, niestety, nie zadziała, ponieważ proc nie działaseek(2)
, więc będzie musiało być coś brzydszego, jakawk /proc/self/maps -- 'END { print substr($1, 0, 9); }'