วิธีดูไฟล์ไบนารีจาก Command Line ของ Linux

เผยแพร่แล้ว: 2022-01-29
เทอร์มินัล Linux สุดเก๋พร้อมบรรทัดข้อความสีเขียวบนแล็ปท็อป
fatmawati achmad zaenuri/Shutterstock

มีไฟล์ลึกลับ? คำสั่ง file Linux จะบอกคุณอย่างรวดเร็วว่าเป็นไฟล์ประเภทใด หากเป็นไฟล์ไบนารี คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับมันได้ file มีเพื่อนร่วมคอกที่จะช่วยคุณวิเคราะห์ เราจะแสดงให้คุณเห็นถึงวิธีการใช้เครื่องมือเหล่านี้

การระบุประเภทไฟล์

ไฟล์มักจะมีลักษณะเฉพาะที่ช่วยให้แพ็คเกจซอฟต์แวร์สามารถระบุประเภทของไฟล์ได้ เช่นเดียวกับข้อมูลที่อยู่ภายใน ไม่ควรพยายามเปิดไฟล์ PNG ในเครื่องเล่นเพลง MP3 ดังนั้นจึงมีประโยชน์และเป็นประโยชน์อย่างยิ่งที่ไฟล์จะมี ID บางรูปแบบ

นี่อาจเป็นลายเซ็นบางส่วนที่จุดเริ่มต้นของไฟล์ ซึ่งช่วยให้ไฟล์มีความชัดเจนเกี่ยวกับรูปแบบและเนื้อหา บางครั้ง ประเภทไฟล์ได้รับการอนุมานจากลักษณะเฉพาะของการจัดระเบียบข้อมูลภายใน ซึ่งเรียกว่าสถาปัตยกรรมไฟล์

ระบบปฏิบัติการบางระบบ เช่น Windows ได้รับการแนะนำโดยนามสกุลไฟล์อย่างสมบูรณ์ คุณสามารถเรียกมันว่าใจง่ายหรือไว้ใจได้ แต่ Windows จะถือว่าไฟล์ใดๆ ที่มีนามสกุล DOCX เป็นไฟล์ประมวลผลคำ DOCX จริงๆ ลินุกซ์ไม่ใช่แบบนั้น อย่างที่คุณเห็นในไม่ช้า มันต้องการการพิสูจน์และค้นดูภายในไฟล์เพื่อค้นหามัน

เครื่องมือที่อธิบายไว้ในที่นี้ได้รับการติดตั้งไว้แล้วในรุ่น Manjaro 20, Fedora 21 และ Ubuntu 20.04 ที่เราใช้ในการค้นคว้าบทความนี้ เริ่มต้นการตรวจสอบโดยใช้คำสั่ง file

การใช้ไฟล์ Command

เรามีคอลเล็กชันไฟล์ประเภทต่างๆ ในไดเร็กทอรีปัจจุบันของเรา เป็นการผสมผสานระหว่างไฟล์เอกสาร ซอร์สโค้ด ไฟล์สั่งการ และไฟล์ข้อความ

โฆษณา

คำสั่ง ls จะแสดงให้เราเห็นว่ามีอะไรอยู่ในไดเร็กทอรี และตัวเลือก -hl (ขนาดที่มนุษย์อ่านได้ รายการแบบยาว) จะแสดงขนาดของแต่ละไฟล์ให้เราทราบ:

 ls -hl 

มาลอง file เหล่านี้กันและดูว่าเราได้อะไร:

 ไฟล์ build_instructions.odt
 ไฟล์ build_instructions.pdf
 ไฟล์ COBOL_Report_Apr60.djvu 

มีการระบุรูปแบบไฟล์ทั้งสามอย่างถูกต้อง หากเป็นไปได้ file จะให้ข้อมูลเพิ่มเติมแก่เราอีกเล็กน้อย มีรายงานว่าไฟล์ PDF อยู่ในรูปแบบเวอร์ชัน 1.5

แม้ว่าเราจะเปลี่ยนชื่อไฟล์ ODT เพื่อให้มีนามสกุลด้วยค่า XYZ โดยพลการ ไฟล์ก็ยังถูกระบุอย่างถูกต้อง ทั้งภายใน Files เบราว์เซอร์ไฟล์ และบนบรรทัดคำสั่งโดยใช้ file

ระบุไฟล์ OpenDocument อย่างถูกต้องภายในเบราว์เซอร์ไฟล์ Files แม้ว่านามสกุลจะเป็น XYZ

ภายในเบราว์เซอร์ไฟล์ Files จะมีไอคอนที่ถูกต้อง บนบรรทัดคำสั่ง file จะละเว้นส่วนขยายและค้นหาภายในไฟล์เพื่อกำหนดประเภท:

 ไฟล์ build_instructions.xyz 

โฆษณา

การใช้ file กับสื่อ เช่น ไฟล์รูปภาพและเพลง มักจะให้ข้อมูลเกี่ยวกับรูปแบบ การเข้ารหัส ความละเอียด และอื่นๆ:

 ไฟล์ภาพหน้าจอ.png
 ไฟล์ภาพหน้าจอ.jpg
 ไฟล์ Pachelbel_Canon_In_D.mp3 

ที่น่าสนใจ แม้กระทั่งกับไฟล์ข้อความธรรมดา file ก็ไม่ได้ตัดสินไฟล์จากนามสกุลของมัน ตัวอย่างเช่น หากคุณมีไฟล์ที่มีนามสกุล ".c" ซึ่งมีข้อความธรรมดามาตรฐาน แต่ไม่มีซอร์สโค้ด file จะไม่เข้าใจผิดว่าเป็นไฟล์ซอร์สโค้ด C ของแท้:

 ไฟล์ function+headers.h
 ไฟล์ makefile
 ไฟล์ hello.c 

file ระบุไฟล์ส่วนหัวอย่างถูกต้อง (“.h”) ซึ่งเป็นส่วนหนึ่งของการรวบรวมไฟล์ซอร์สโค้ด C และรู้ว่า makefile เป็นสคริปต์

การใช้ไฟล์กับไฟล์ไบนารี

ไฟล์ไบนารีเป็น "กล่องดำ" มากกว่าไฟล์อื่น ไฟล์ภาพสามารถเปิดดูได้ ไฟล์เสียงสามารถเล่นได้ และไฟล์เอกสารสามารถเปิดได้ด้วยแพ็คเกจซอฟต์แวร์ที่เหมาะสม ไฟล์ไบนารีมีความท้าทายมากกว่า

ตัวอย่างเช่น ไฟล์ "hello" และ "wd" เป็นไฟล์ปฏิบัติการแบบไบนารี พวกเขาเป็นโปรแกรม ไฟล์ชื่อ “wd.o” เป็นไฟล์อ็อบเจ็กต์ เมื่อคอมไพล์ซอร์สโค้ดโดยคอมไพเลอร์ ไฟล์อ็อบเจ็กต์หนึ่งไฟล์ขึ้นไปจะถูกสร้างขึ้น ซึ่งประกอบด้วยรหัสเครื่องที่คอมพิวเตอร์จะดำเนินการในที่สุดเมื่อโปรแกรมทำงานเสร็จสิ้น พร้อมด้วยข้อมูลสำหรับตัวเชื่อมโยง ตัวเชื่อมโยงตรวจสอบแต่ละไฟล์อ็อบเจ็กต์สำหรับการเรียกใช้ฟังก์ชันไปยังไลบรารี มันเชื่อมโยงไปยังไลบรารีใด ๆ ที่โปรแกรมใช้ ผลลัพธ์ของกระบวนการนี้คือไฟล์ปฏิบัติการ

ไฟล์ “watch.exe” เป็นไฟล์ปฏิบัติการไบนารีที่ได้รับการคอมไพล์ข้ามเพื่อให้ทำงานบน Windows:

 ไฟล์ wd
 ไฟล์ wd.o
 ไฟล์สวัสดี
 ไฟล์ watch.exe 

โฆษณา

file สุดท้ายก่อนบอกเราว่าไฟล์ "watch.exe" เป็นโปรแกรมคอนโซล PE32+ ที่ปฏิบัติการได้สำหรับโปรเซสเซอร์ตระกูล x86 บน Microsoft Windows PE ย่อมาจากรูปแบบปฏิบัติการแบบพกพาซึ่งมีเวอร์ชัน 32 และ 64 บิต PE32 เป็นเวอร์ชัน 32 บิต และ PE32+ เป็นเวอร์ชัน 64 บิต

อีกสามไฟล์ถูกระบุว่าเป็นไฟล์ Executable และ Linkable Format (ELF) นี่เป็นมาตรฐานสำหรับไฟล์ปฏิบัติการและไฟล์อ็อบเจ็กต์ที่แชร์ เช่น ไลบรารี เราจะมาดูรูปแบบส่วนหัวของ ELF ในไม่ช้านี้

สิ่งที่อาจดึงดูดสายตาคุณก็คือ ไฟล์ปฏิบัติการทั้งสอง (“wd” และ “hello”) ถูกระบุว่าเป็นอ็อบเจ็กต์ที่ใช้ร่วมกันของ Linux Standard Base (LSB) และไฟล์อ็อบเจ็กต์ “wd.o” ถูกระบุว่าเป็น LSB ที่ย้ายตำแหน่งได้ คำว่า executable นั้นชัดเจนในกรณีที่ไม่มี

ไฟล์อ็อบเจ็กต์สามารถย้ายได้ ซึ่งหมายความว่าโค้ดภายในไฟล์สามารถโหลดลงในหน่วยความจำได้ทุกที่ ไฟล์เรียกทำงานถูกแสดงรายการเป็นอ็อบเจ็กต์ที่ใช้ร่วมกัน เนื่องจากตัวเชื่อมโยงถูกสร้างขึ้นจากไฟล์อ็อบเจ็กต์ในลักษณะที่สืบทอดความสามารถนี้

ซึ่งช่วยให้ระบบ Address Space Layout Randomization (ASMR) โหลดไฟล์เรียกทำงานลงในหน่วยความจำตามที่อยู่ที่เลือกได้ ไฟล์ปฏิบัติการมาตรฐานมีที่อยู่การโหลดที่เข้ารหัสไว้ในส่วนหัว ซึ่งจะกำหนดตำแหน่งที่จะโหลดลงในหน่วยความจำ

ASMR เป็นเทคนิคการรักษาความปลอดภัย การโหลดไฟล์เรียกทำงานเข้าสู่หน่วยความจำตามที่อยู่ที่สามารถคาดเดาได้ทำให้พวกมันไวต่อการโจมตี นี่เป็นเพราะว่าจุดเข้าใช้งานและตำแหน่งของหน้าที่การงาน จะเป็นที่รู้จักของผู้โจมตีเสมอ ตำแหน่งที่ปฏิบัติการอิสระ (PIE) ตำแหน่งที่อยู่ที่สุ่มเอาชนะความอ่อนแอนี้

โฆษณา

หากเราคอมไพล์โปรแกรมด้วยคอมไพเลอร์ gcc และให้ตัวเลือก -no-pie เราจะสร้างไฟล์สั่งการแบบธรรมดา

ตัวเลือก -o (ไฟล์เอาต์พุต) ช่วยให้เราระบุชื่อสำหรับไฟล์ปฏิบัติการของเรา:

 gcc -o สวัสดี -no-pie สวัสดี.c

เราจะใช้ file ในไฟล์เรียกทำงานใหม่และดูว่ามีอะไรเปลี่ยนแปลงบ้าง:

 ไฟล์สวัสดี

ขนาดของไฟล์สั่งการจะเท่ากับเมื่อก่อน (17 KB):

 ls -hl สวัสดี 

ขณะนี้ไบนารีถูกระบุว่าเป็นไฟล์ปฏิบัติการมาตรฐาน เรากำลังดำเนินการนี้เพื่อการสาธิตเท่านั้น หากคุณรวบรวมแอปพลิเคชันด้วยวิธีนี้ คุณจะสูญเสียข้อดีทั้งหมดของ ASMR

เหตุใดปฏิบัติการจึงใหญ่มาก

ตัวอย่างโปรแกรม hello ของเราคือ 17 KB ดังนั้นจึงแทบจะเรียกได้ว่าใหญ่ แต่ทุกอย่างก็สัมพันธ์กัน ซอร์สโค้ดคือ 120 ไบต์:

 แมว สวัสดี.c
โฆษณา

อะไรคือการเปรียบเทียบไบนารีหากพิมพ์หนึ่งสตริงไปที่หน้าต่างเทอร์มินัล เรารู้ว่ามีส่วนหัวของ ELF แต่นั่นมีความยาวเพียง 64 ไบต์สำหรับไบนารี 64 บิต เห็นได้ชัดว่าต้องเป็นอย่างอื่น:

 ls -hl สวัสดี 

มาสแกนไบนารีด้วยคำสั่ง strings เป็นขั้นตอนแรกง่ายๆ เพื่อค้นหาว่ามีอะไรอยู่ข้างใน เราจะไปป์ให้ less :

 สวัสดี | น้อย 

มีหลายสตริงในไบนารี นอกเหนือจาก "สวัสดี โลก Geek!" จากซอร์สโค้ดของเรา ส่วนใหญ่เป็นป้ายกำกับสำหรับภูมิภาคภายในไบนารี และชื่อและข้อมูลการเชื่อมโยงของอ็อบเจ็กต์ที่ใช้ร่วมกัน ซึ่งรวมถึงไลบรารีและฟังก์ชันภายในไลบรารีเหล่านั้นซึ่งไบนารีขึ้นอยู่กับ

คำสั่ง ldd แสดงให้เราเห็นการพึ่งพาอ็อบเจ็กต์ที่ใช้ร่วมกันของไบนารี:

 สวัสดี 

เอาต์พุตมีสามรายการ และสองรายการมีเส้นทางไดเรกทอรี (รายการแรกไม่มี):

  • linux-vdso.so: Virtual Dynamic Shared Object (VDSO) เป็นกลไกเคอร์เนลที่ช่วยให้ชุดของรูทีนพื้นที่เคอร์เนลสามารถเข้าถึงได้โดยไบนารีพื้นที่ผู้ใช้ เพื่อหลีกเลี่ยงค่าใช้จ่ายของการสลับบริบทจากโหมดเคอร์เนลของผู้ใช้ ออบเจ็กต์ที่ใช้ร่วมกันของ VDSO เป็นไปตามรูปแบบ Executable และ Linkable Format (ELF) ทำให้สามารถลิงก์แบบไดนามิกกับไบนารีขณะรันไทม์ได้ VDSO ได้รับการจัดสรรแบบไดนามิกและใช้ประโยชน์จาก ASMR ความสามารถ VDSO มีให้โดยไลบรารี GNU C มาตรฐาน หากเคอร์เนลสนับสนุนรูปแบบ ASMR
  • libc.so.6: วัตถุที่ใช้ร่วมกันของ GNU C Library
  • /lib64/ld-linux-x86-64.so.2: นี่คือตัวเชื่อมโยงแบบไดนามิกที่ไบนารีต้องการใช้ ตัวเชื่อมโยงแบบไดนามิกสอบปากคำไบนารีเพื่อค้นหาสิ่งที่ขึ้นต่อกัน มันเปิดตัววัตถุที่ใช้ร่วมกันเหล่านั้นลงในหน่วยความจำ มันเตรียมไบนารีให้ทำงานและสามารถค้นหาและเข้าถึงการพึ่งพาในหน่วยความจำได้ จากนั้นจึงเปิดโปรแกรม

ส่วนหัวของเอลฟ์

เราสามารถตรวจสอบและถอดรหัสส่วนหัวของ ELF ได้โดยใช้ยูทิลิตี้ readelf และตัวเลือก -h (ส่วนหัวของไฟล์):

 readelf -h สวัสดี 

ส่วนหัวถูกตีความสำหรับเรา

โฆษณา

ไบต์แรกของไบนารี ELF ทั้งหมดถูกตั้งค่าเป็นเลขฐานสิบหก 0x7F สามไบต์ถัดไปถูกตั้งค่าเป็น 0x45, 0x4C และ 0x46 ไบต์แรกคือแฟล็กที่ระบุไฟล์เป็นไบนารีของ ELF เพื่อให้ชัดเจน สามไบต์ถัดไปสะกดว่า "ELF" ใน ASCII:

  • คลาส: ระบุว่าไบนารีเป็นแบบ 32- หรือ 64- บิตที่ปฏิบัติการได้ (1=32, 2=64)
  • ข้อมูล: บ่งบอกถึงความสมบูรณ์ในการใช้งาน การเข้ารหัส Endian กำหนดวิธีการจัดเก็บหมายเลขหลายไบต์ ในการเข้ารหัส big-endian ตัวเลขจะถูกจัดเก็บด้วยบิตที่สำคัญที่สุดก่อน ในการเข้ารหัสแบบ little-endian ตัวเลขจะถูกจัดเก็บด้วยบิตที่มีนัยสำคัญน้อยที่สุดก่อน
  • เวอร์ชัน: เวอร์ชันของ ELF (ปัจจุบันคือ 1)
  • OS/ABI: แสดงประเภทของอินเทอร์เฟซไบนารีของแอปพลิเคชันที่ใช้งานอยู่ สิ่งนี้กำหนดอินเทอร์เฟซระหว่างสองโมดูลไบนารี เช่น โปรแกรมและไลบรารีที่ใช้ร่วมกัน
  • เวอร์ชัน ABI: เวอร์ชันของ ABI
  • ประเภท: ประเภทของไบนารีเอลฟ์ ค่าทั่วไปคือ ET_REL สำหรับทรัพยากรที่ย้ายได้ (เช่น ไฟล์อ็อบเจ็กต์), ET_EXEC สำหรับไฟล์เรียกทำงานที่คอมไพล์ด้วยแฟล็ก -no-pie และ ET_DYN สำหรับไฟล์สั่งการ ASMR-aware
  • เครื่องจักร: สถาปัตยกรรมชุดคำสั่ง นี่ระบุแพลตฟอร์มเป้าหมายที่สร้างไบนารี
  • เวอร์ชัน: ตั้งค่าเป็น 1 เสมอ สำหรับ ELF เวอร์ชันนี้
  • Entry Point Address: ที่ อยู่หน่วยความจำภายในไบนารีที่เริ่มดำเนินการ

รายการอื่นๆ คือขนาดและจำนวนของภูมิภาคและส่วนต่างๆ ภายในไบนารี เพื่อให้สามารถคำนวณตำแหน่งของพวกมันได้

การดูแปดไบต์แรกของไบนารีที่มี hexdump จะแสดงไบต์ลายเซ็นและสตริง "ELF" ในสี่ไบต์แรกของไฟล์ ตัวเลือก -C (ตามรูปแบบบัญญัติ) ทำให้เราสามารถแทนค่า ASCII ของไบต์ควบคู่ไปกับค่าเลขฐานสิบหก และตัวเลือก -n (ตัวเลข) ช่วยให้เราระบุจำนวนไบต์ที่เราต้องการดูได้:

 hexdump -C -n 8 สวัสดี 

objdump และมุมมองแบบละเอียด

หากคุณต้องการดูรายละเอียดที่สำคัญ คุณสามารถใช้คำสั่ง objdump พร้อมตัวเลือก -d (ถอดแยกชิ้นส่วน):

 objdump -d สวัสดี | น้อย 

สิ่งนี้จะแยกส่วนรหัสเครื่องที่เรียกใช้งานได้และแสดงเป็นไบต์ฐานสิบหกควบคู่ไปกับภาษาแอสเซมบลีที่เทียบเท่า ตำแหน่งที่อยู่ของลาก่อนในแต่ละบรรทัดจะแสดงทางด้านซ้ายสุด

สิ่งนี้มีประโยชน์ก็ต่อเมื่อคุณอ่านภาษาแอสเซมบลีได้ หรือคุณสงสัยว่าเกิดอะไรขึ้นหลังม่าน มีเอาต์พุตจำนวนมาก เราจึงวาง less ในไฟล์ .

รวบรวมและเชื่อมโยง

มีหลายวิธีในการรวบรวมไบนารี ตัวอย่างเช่น นักพัฒนาซอฟต์แวร์เลือกว่าจะรวมข้อมูลการดีบักหรือไม่ วิธีเชื่อมโยงไบนารียังมีบทบาทในเนื้อหาและขนาด หากการอ้างอิงไบนารีแบ่งปันวัตถุเป็นการพึ่งพาภายนอก การอ้างอิงนั้นจะเล็กกว่าการอ้างอิงที่การอ้างอิงแบบสแตติก

โฆษณา

นักพัฒนาซอฟต์แวร์ส่วนใหญ่ทราบคำสั่งที่เรากล่าวถึงในที่นี้อยู่แล้ว อย่างไรก็ตาม สำหรับคนอื่น ๆ พวกเขาเสนอวิธีง่ายๆ ในการค้นหาและดูว่ามีอะไรอยู่ในกล่องดำไบนารี