Xác định xem một quy trình cụ thể là 32- hay 64-Bit


14

Với hạt nhân Linux 2.6.x hoặc mới hơn và vùng người dùng hiện tại có khả năng chạy cả nhị phân ELF32 và ELF64 (tức là quá khứ Làm sao tôi biết rằng CPU của tôi hỗ trợ các hệ điều hành 64 bit trong Linux? ) Làm cách nào để xác định xem một quy trình nhất định ( bởi PID) đang chạy ở chế độ 32 hoặc 64 bit?

Giải pháp ngây thơ sẽ là chạy:

file -L /proc/pid/exe | grep -o 'ELF ..-bit [LM]SB'

Nhưng đó là thông tin tiếp xúc trực tiếp trong /procmà không dựa vào libmagic?

Câu trả lời:


21

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/exechí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:

  1. Nếu 5 byte đầu tiên là 0x7f, "ELF", 1: đó là nhị phân ELF 32 bit.
  2. Nếu 5 byte đầu tiên là 0x7f, "ELF", 2: đó là nhị phân ELF 64 bit.
  3. 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ỏ libmagicsự 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/auxvtệ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 longphí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à i686thay vào đó.

Cách thức hoạt động: LD_SHOW_AUXV=1hướ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 lddvà nhị phân mục tiêu của bạn. Vì vậy, chúng tôi grepcho 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 auxvcấ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: auxvcấ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 0xffffffffhoặ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/mapstậ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ì auxvtệp này không có ở đó trước đó.


1
Hmmm, tôi tự hỏi nếu tiêu đề ELF có trong /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).
goldilocks

1
Bản thân tiêu đề không phải là. Tôi chỉ hded một và nó thiếu số ma thuật. Có thể có một số thông tin liên quan ở đó, nhưng tôi nghĩ rằng nó sẽ chịu sự thay đổi thường xuyên hơn so với tiêu đề ELF. Nó cũng được giới thiệu vào 2.6.0, vì vậy nó không phổ biến như /proc/PID/exe. Nhưng nó không có những thông tin kiến trúc. Tôi sẽ cập nhật câu trả lời của tôi.
Alexios

Phụ kiện hóa ra phức tạp hơn tôi mong đợi - sizeof(unsigned long)là 8 trên 64 bit hoặc 4 trên 32 bit, điều đó có nghĩa là để giải thích chính xác trực tiếp, bạn phải biết quá trình bắt đầu là 64 bit hay 32 bit!
Flexo

Bạn hoàn toàn đúng. Điều đó khá khó chịu. Xử lý nhanh: nếu byte 16x + y (4≤y≤7) đều bằng 0 trong tệp, bạn đang xem tệp thực thi 64 bit. Đây là một loại bùn: Tôi giả sử một máy endian nhỏ và tất cả các auxvmã khóa phù hợp với 32 bit unsigned long, do đó, 32 bit quan trọng nhất trên hộp 64 bit sẽ bằng không.
Alexios

6

Nhìn vào /proc/$pid/maps. Phạm vi địa chỉ là các địa chỉ trên 32 bit (8 chữ số thập lục phân) hoặc địa chỉ 64 bit (16 chữ số thập lục phân). Điều này làm việc cho bất kỳ loại thực thi, bất kể định dạng. Bạn chỉ có thể nhận thông tin về các quy trình đang chạy với cùng một người dùng (trừ khi bạn đã 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

Nếu bạn không có quyền truy cập tệp này, thì tôi nghĩ cách duy nhất là cố gắng phân tích tệp thực thi. (Trong khi bạn luôn có thể đọc /proc/$pid/stat, không có trường nào được hiển thị cho các quy trình đang chạy khi những người dùng khác tiết lộ kích thước bit của quy trình.) Bạn có thể đoán chính xác về quy trình thực thi của quy trình ps -o comm=và tìm kiếm trong PATH- nhưng hãy cẩn thận với quy trình có thể đã được đưa ra với một khác PATH, hoặc có thể đã viết lại nó argv[0]. Sau đó, bạn có thể phân tích tệp thực thi - nếu bạn sẵn sàng sử dụng ELF, hãy xem byte thứ 5 .


Tôi đã thử công thức của bạn và nó đã thất bại. OpenSuSE 12.2, x86-64, kernel 3.4.63-2.44 mặc định, / bin / bash. Các dòng / Proc / $ pid / maps cho nhị phân và heap đầu tiên được viết theo kiểu 32 bit, nhưng tất cả các dòng khác đều theo kiểu 64 bit. Có thể chúng được in bằng "% 08x", nhưng dù sao thì công thức này sẽ được điều chỉnh.
Lấy

Tôi nhận được hỗn hợp gồm 8, 12 và 16 giá trị trên tất cả các hộp tôi đã thử. Nếu không kiểm tra nguồn, tôi đoán là hạt nhân điều chỉnh phần đệm thành bội số thấp nhất 16 bit lớn hơn phạm vi địa chỉ cho mỗi dòng được in, do đó bạn phải tìm chuỗi ký tự hex dài nhất, sau đó kiểm tra.
Alexios

NHƯNG, vì vsyscallbản đồ luôn ở mức cao nhất, bạn có thể thoát khỏi việc thay đổi headthành tail- điều đáng buồn là sẽ không hoạt động vì Proc không thực hiện seek(2), vì vậy nó sẽ phải là thứ gì đó xấu hơn, nhưawk /proc/self/maps -- 'END { print substr($1, 0, 9); }'
Alexios

@Netch Thật vậy, tôi đã ngu ngốc nhìn vào các đường vs tòa nhà và ngăn xếp và không chú ý đến việc ánh xạ của tệp thực thi. Cảm ơn, tôi đã cập nhật để tìm kiếm bất kỳ dòng không 32 bit nào. Đáng tiếc, nó xấu hơn, nhưng đây là đáng tin cậy nhất (ít nhất là nó chắc chắn trên x86, tôi đã không kiểm tra với các kiến ​​trúc kép khác như sparc và arm).
Gilles 'SO- ngừng trở nên xấu xa'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.