Nếu bạn muốn giới hạn bản thân trong việc phát hiện ELF, bạn có thể đọc tiêu đề ELF của /proc/$PID/exe
chính mình. Nó khá tầm thường: nếu byte thứ 5 trong tệp là 1, thì đó là nhị phân 32 bit. Nếu là 2, thì là 64 bit. Để kiểm tra độ tỉnh táo thêm:
- Nếu 5 byte đầu tiên là
0x7f, "ELF", 1
: đó là nhị phân ELF 32 bit.
- Nếu 5 byte đầu tiên là
0x7f, "ELF", 2
: đó là nhị phân ELF 64 bit.
- Mặt khác: nó không kết luận.
Bạn cũng có thể sử dụng objdump
, nhưng điều đó sẽ loại bỏ libmagic
sự phụ thuộc của bạn và thay thế nó bằng một libelf
.
Một cách khác : bạn cũng có thể phân tích /proc/$PID/auxv
tệp. Theo proc(5)
:
Điều này chứa nội dung của thông tin trình thông dịch ELF được chuyển đến quá trình tại thời điểm thực thi. Định dạng là một ID dài không dấu cộng với một giá trị dài không dấu cho mỗi mục nhập. Mục cuối cùng chứa hai số không.
Ý nghĩa của các unsigned long
phím là trong /usr/include/linux/auxvec.h
. Bạn muốn AT_PLATFORM
, đó là 0x00000f
. Đừng trích dẫn tôi về điều đó, nhưng có vẻ như giá trị nên được hiểu là char *
để có được mô tả chuỗi của nền tảng.
Bạn có thể thấy câu hỏi StackOverflow này hữu ích.
Một cách khác : bạn có thể hướng dẫn trình liên kết động ( man ld
) kết xuất thông tin về tệp thực thi. Nó in ra đầu ra tiêu chuẩn cấu trúc AUXV được giải mã. Cảnh báo: đây là một hack, nhưng nó hoạt động.
LD_SHOW_AUXV=1 ldd /proc/$SOME_PID/exe | grep AT_PLATFORM | tail -1
Điều này sẽ hiển thị một cái gì đó như:
AT_PLATFORM: x86_64
Tôi đã thử nó trên hệ nhị phân 32 bit và i686
thay vào đó.
Cách thức hoạt động: LD_SHOW_AUXV=1
hướng dẫn Dynamic Linker kết xuất cấu trúc AUXV đã giải mã trước khi chạy tệp thực thi. Trừ khi bạn thực sự muốn làm cho cuộc sống của bạn thú vị, bạn muốn tránh thực sự chạy thực thi nói. Một cách để tải và tự động liên kết nó mà không thực sự gọi main()
chức năng của nó là chạy ldd(1)
trên nó. Nhược điểm: LD_SHOW_AUXV
được kích hoạt bởi trình bao, do đó, bạn sẽ nhận được các kết cấu AUXV cho: lớp con ldd
và nhị phân mục tiêu của bạn. Vì vậy, chúng tôi grep
cho AT_PLATFORM, nhưng chỉ giữ dòng cuối cùng.
Phân tích cú pháp : nếu bạn tự phân tích auxv
cấu trúc (không dựa vào bộ tải động), thì có một câu hỏi hóc búa: auxv
cấu trúc tuân theo quy tắc của quy trình mà nó mô tả, do đó sizeof(unsigned long)
sẽ là 4 cho các quy trình 32 bit và 8 cho 64 quy trình -bit. Chúng tôi có thể làm việc này cho chúng tôi. Để làm việc này trên các hệ thống 32 bit, tất cả các mã khóa phải 0xffffffff
hoặc ít hơn. Trên hệ thống 64 bit, 32 bit quan trọng nhất sẽ bằng không. Các máy của Intel là những người cuối cùng nhỏ bé, vì vậy 32 bit này tuân theo những thứ ít quan trọng nhất trong bộ nhớ.
Như vậy, tất cả những gì bạn cần làm là:
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.
Phân tích tệp bản đồ : điều này được đề xuất bởi Gilles, nhưng không hoạt động. Đây là một phiên bản sửa đổi. Nó dựa vào việc đọc các /proc/$PID/maps
tập tin. Nếu tệp liệt kê các địa chỉ 64 bit, quá trình này là 64 bit. Mặt khác, nó là 32 bit. Vấn đề nằm ở chỗ kernel sẽ đơn giản hóa đầu ra bằng cách tước các số 0 đứng đầu từ các địa chỉ hex trong nhóm 4, do đó, độ dài hack không thể hoạt động được. awk
để giải cứu:
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
Điều này hoạt động bằng cách kiểm tra địa chỉ bắt đầu của bản đồ bộ nhớ cuối cùng của quá trình. Chúng được liệt kê như thế 12345678-deadbeef
. Vì vậy, nếu quy trình là một 32 bit, địa chỉ đó sẽ dài tám chữ số và số thứ chín sẽ là dấu gạch nối. Nếu là một bit 64 bit, địa chỉ cao nhất sẽ dài hơn thế. Ký tự thứ chín sẽ là một chữ số hex.
Xin lưu ý: tất cả trừ các phương thức đầu tiên và cuối cùng đều cần Linux kernel 2.6.0 hoặc mới hơn, vì auxv
tệp này không có ở đó trước đó.
/proc/[pid]/auxv
: "thông tin trình thông dịch ELF được truyền cho quá trình tại thời điểm thực thi. Định dạng là một ID dài không dấu cộng với một giá trị dài không dấu cho mỗi mục nhập" (man proc
).