หากคุณต้องการ จำกัด การตรวจจับเอลฟ์คุณสามารถอ่านส่วนหัวเอลฟ์ของ/proc/$PID/exe
ตัวคุณเอง มันค่อนข้างเล็กน้อย: ถ้าไบต์ที่ 5 ในไฟล์คือ 1 มันคือไบนารี 32 บิต ถ้าเป็น 2 ก็คือ 64- บิต สำหรับการเพิ่มสติตรวจ:
- ถ้า 5 ไบต์แรกคือ
0x7f, "ELF", 1
มันเป็นไบนารี ELF 32 บิต
- ถ้า 5 ไบต์แรกคือ
0x7f, "ELF", 2
: มันเป็นไบนารี 64 บิตของ ELF
- มิฉะนั้น: มันไม่สามารถสรุปได้
คุณสามารถใช้งานobjdump
ได้ แต่นั่นจะทำให้การlibmagic
พึ่งพาของคุณหายไปและแทนที่ด้วย alibelf
หนึ่ง
อีกวิธีหนึ่ง : คุณสามารถแยกวิเคราะห์/proc/$PID/auxv
ไฟล์ ตามproc(5)
:
สิ่งนี้มีเนื้อหาของข้อมูลล่ามของ ELF ที่ส่งไปยังกระบวนการในเวลา exec รูปแบบคือหนึ่ง ID แบบยาวที่ไม่ได้ลงชื่อบวกค่าแบบยาวที่ไม่ได้ลงชื่อหนึ่งรายการสำหรับแต่ละรายการ รายการสุดท้ายมีสองศูนย์
ความหมายของคีย์อยู่ใน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 สำหรับ: subshell ldd
และไบนารีเป้าหมายของคุณ ดังนั้นเราgrep
สำหรับ AT_PLATFORM แต่ให้บรรทัดสุดท้ายเท่านั้น
การแยกวิเคราะห์ auxv : หากคุณแยกวิเคราะห์auxv
โครงสร้างด้วยตัวคุณเอง (ไม่ต้องพึ่งพาตัวโหลดแบบไดนามิก) จากนั้นจะมีปริศนาเล็กน้อย: auxv
โครงสร้างตามกฎของกระบวนการที่อธิบายไว้ดังนั้นsizeof(unsigned long)
จะเป็น 4 สำหรับกระบวนการ 32 บิตและ 8 สำหรับ 64 กระบวนการบิต เราสามารถทำสิ่งนี้ให้กับเราได้ เพื่อให้สิ่งนี้ทำงานบนระบบ 32 บิตรหัสคีย์ทั้งหมดจะต้องเป็น0xffffffff
หรือน้อยกว่า บนระบบ 64 บิต 32 บิตที่สำคัญที่สุดจะเป็นศูนย์ เครื่องของ Intel นั้นเป็น endian เล็ก ๆ น้อย ๆ ดังนั้น 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.
การแยกไฟล์แผนที่ : สิ่งนี้ได้รับการแนะนำโดย Gilles แต่ก็ไม่ได้ผล นี่คือเวอร์ชั่นที่แก้ไขแล้ว มันอาศัยการอ่าน/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 kernel 2.6.0 หรือใหม่กว่าเนื่องจากauxv
ไฟล์ไม่เคยมีมาก่อน
/proc/[pid]/auxv
: "ข้อมูลล่ามของ ELF ถูกส่งไปยังกระบวนการในเวลา exec รูปแบบคือ ID ยาวที่ไม่ได้ลงชื่อและบวกค่ายาวที่ไม่ได้ลงชื่อสำหรับแต่ละรายการ" (man proc
)