Jika Anda ingin membatasi diri Anda untuk deteksi ELF, Anda dapat membaca judul ELF dari /proc/$PID/exe
diri Anda sendiri. Ini cukup sepele: jika byte ke-5 dalam file adalah 1, itu adalah biner 32-bit. Jika 2, 64-bit. Untuk pemeriksaan kewarasan tambahan:
- Jika 5 byte pertama adalah
0x7f, "ELF", 1
: ini adalah biner ELF 32 bit.
- Jika 5 byte pertama adalah
0x7f, "ELF", 2
: itu adalah biner ELF 64 bit.
- Jika tidak: tidak dapat disimpulkan.
Anda juga bisa menggunakan objdump
, tetapi itu menghilangkan libmagic
ketergantungan Anda dan menggantinya dengan yang lain libelf
.
Cara lain : Anda juga dapat mem-parsing /proc/$PID/auxv
file. Menurut proc(5)
:
Ini berisi isi informasi penerjemah ELF yang diteruskan ke proses pada waktu exec. Formatnya adalah satu ID panjang yang tidak ditandatangani ditambah satu nilai panjang yang tidak ditandatangani untuk setiap entri. Entri terakhir berisi dua nol.
Arti unsigned long
kunci ada di /usr/include/linux/auxvec.h
. Anda ingin AT_PLATFORM
, yang 0x00000f
. Jangan mengutip saya tentang itu, tetapi tampaknya nilai harus ditafsirkan sebagai char *
untuk mendapatkan deskripsi string dari platform.
Anda mungkin menemukan pertanyaan StackOverflow ini bermanfaat.
Namun cara lain : Anda dapat menginstruksikan dynamic linker ( man ld
) untuk membuang informasi tentang executable. Ini mencetak ke output standar struktur AUXV yang di-decode. Peringatan: ini peretasan, tetapi berhasil.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Ini akan menunjukkan sesuatu seperti:
AT_PLATFORM: x86_64
Saya mencobanya pada biner 32-bit dan i686
sebagai gantinya.
Bagaimana ini bekerja: LD_SHOW_AUXV=1
menginstruksikan Dynamic Linker untuk membuang struktur AUXV yang didekodekan sebelum menjalankan executable. Kecuali Anda benar - benar ingin membuat hidup Anda menarik, Anda ingin benar-benar menjalankan kata executable. Salah satu cara untuk memuat dan menautkannya secara dinamis tanpa benar-benar memanggil main()
fungsinya adalah dengan menjalankannya ldd(1)
. The downside: LD_SHOW_AUXV
diaktifkan oleh shell, sehingga Anda akan mendapatkan kesedihan dari struktur AUXV untuk: subkulit ldd
,, dan biner target Anda. Jadi kami grep
untuk AT_PLATFORM, tetapi hanya menjaga baris terakhir.
Parsing auxv : jika Anda menguraikan auxv
struktur sendiri (tidak mengandalkan loader dinamis), maka ada sedikit teka-teki: auxv
struktur mengikuti aturan proses yang dijelaskan, sehingga sizeof(unsigned long)
akan menjadi 4 untuk proses 32-bit dan 8 untuk 64 proses-bit. Kita dapat membuat ini bekerja untuk kita. Agar ini bekerja pada sistem 32-bit, semua kode kunci harus 0xffffffff
atau kurang. Pada sistem 64-bit, 32 bit yang paling signifikan adalah nol. Mesin Intel adalah endian kecil, jadi 32 bit ini mengikuti yang paling tidak signifikan dalam memori.
Dengan demikian, yang perlu Anda lakukan adalah:
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.
Mem-parsing file peta : ini disarankan oleh Gilles, tetapi tidak berhasil. Ini versi modifikasi yang bisa. Itu bergantung pada membaca /proc/$PID/maps
file. Jika file mencantumkan alamat 64-bit, prosesnya adalah 64 bit. Kalau tidak, itu 32 bit. Masalahnya terletak pada kernel yang akan menyederhanakan output dengan melepaskan nol terkemuka dari alamat hex dalam kelompok 4, sehingga panjang hack tidak bisa bekerja. awk
untuk menyelamatkan:
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
Ini berfungsi dengan memeriksa alamat awal dari peta memori terakhir dari proses. Mereka terdaftar seperti 12345678-deadbeef
. Jadi, jika prosesnya 32-bit, alamat itu akan menjadi delapan digit hex, dan kesembilan akan menjadi tanda hubung. Jika itu 64-bit, alamat tertinggi akan lebih lama dari itu. Karakter kesembilan akan menjadi digit hex.
Waspadalah: semua kecuali metode pertama dan terakhir membutuhkan kernel Linux 2.6.0 atau yang lebih baru, karena auxv
file tersebut tidak ada sebelumnya.
/proc/[pid]/auxv
: "informasi penerjemah ELF diteruskan ke proses pada waktu exec. Formatnya adalah satu ID panjang yang tidak ditandatangani ditambah satu nilai panjang yang tidak ditandatangani untuk setiap entri" (man proc
).hd
mengedit satu dan tidak memiliki nomor ajaib. Mungkin ada beberapa informasi yang relevan di sana, tapi saya pikir itu akan lebih sering berubah daripada header ELF itu sendiri. Itu juga diperkenalkan di 2.6.0, jadi itu tidak cukup di mana-mana/proc/PID/exe
. Tetapi memang memiliki informasi arsitektur. Saya akan memperbarui jawaban saya.sizeof(unsigned long)
adalah 8 pada 64 bit atau 4 pada 32 bit yang berarti bahwa untuk menafsirkannya secara langsung Anda harus tahu apakah prosesnya 64 bit atau 32 bit untuk memulainya!auxv
kode kunci sesuai dengan 32-bitunsigned long
, sehingga 32-bit paling signifikan pada kotak 64-bit akan menjadi nol.Lihat
/proc/$pid/maps
. Rentang alamat lebih dari alamat 32-bit (8 digit heksadesimal) atau alamat 64-bit (16 digit heksadesimal). Ini berfungsi untuk semua jenis yang dapat dieksekusi, apa pun formatnya. Anda hanya bisa mendapatkan informasi tentang proses yang berjalan sebagai pengguna yang sama (kecuali jika Anda root).Jika Anda tidak memiliki izin untuk mengakses file ini, maka saya pikir satu-satunya cara adalah mencoba menganalisis yang dapat dieksekusi. (Meskipun Anda selalu dapat membaca
/proc/$pid/stat
, tidak ada bidang yang ditampilkan untuk proses yang berjalan karena pengguna yang berbeda mengungkapkan ukuran bit proses.) Anda dapat menebak dengan baik proses yang dapat dieksekusi denganps -o comm=
, dan mencari hal itu diPATH
- tetapi berhati-hatilah karena prosesnya mungkin telah diluncurkan dengan berbedaPATH
, atau mungkin telah ditulis ulangargv[0]
. Anda kemudian dapat menganalisis executable - jika Anda mau mengasumsikan ELF, lihat byte ke-5 .sumber
vsyscall
peta selalu yang tertinggi, Anda bisa lolos dengan hanya mengubahhead
ketail
- yang, sayangnya, tidak akan bekerja karena proc tidak melaksanakanseek(2)
, sehingga harus menjadi sesuatu jelek, sepertiawk /proc/self/maps -- 'END { print substr($1, 0, 9); }'