ฉันจะแยกรหัสเครื่อง 16 บิต x86 ดิบได้อย่างไร


91

ฉันต้องการแยกชิ้นส่วน MBR (512 ไบต์แรก) ของดิสก์ x86 ที่สามารถบู๊ตได้ที่ฉันมี ฉันคัดลอก MBR ไปยังไฟล์โดยใช้

dd if=/dev/my-device of=mbr bs=512 count=1

ข้อเสนอแนะสำหรับยูทิลิตี้ Linux ที่สามารถแยกไฟล์ได้mbrหรือไม่?

คำตอบ:


109

คุณสามารถใช้ objdump ตามบทความนี้ไวยากรณ์คือ:

objdump -D -b binary -mi386 -Maddr16,data16 mbr

คุณช่วยอธิบายได้ไหมว่าตัวเลือกที่คุณระบุมีไว้ทำอะไร?
Hawken

11
หรือแทน--target คือ "แยกส่วนเนื้อหาของทุกส่วน"; หรือจะบังคับให้อ่านเป็นรูปแบบรหัสวัตถุที่ระบุ (ไม่ใช่เอลฟ์ แต่เป็นไบนารีดิบในกรณีของเรา); จะระบุสถาปัตยกรรมที่จะใช้ (ในไฟล์ของเราไม่มีส่วนหัวที่มีข้อมูลส่วนโค้ง) เป็นตัวเลือกของ disassembler; ใช้เพื่อ "ระบุขนาดแอดเดรสเริ่มต้นและขนาดตัวถูกดำเนินการ" (ปฏิบัติกับรหัสเป็น i8086 หนึ่งในเอนจินดิสซึม x86 สากล)-b-D-b bfdname--target=bfdname-m machine-M optionsaddr16,data16
osgx

30

เครื่องมือ GNU เรียกว่าobjdumpตัวอย่างเช่น:

objdump -D -b binary -m i8086 <file>

คุณยังสามารถตั้งค่าตัวเลือกต่างๆสำหรับสถาปัตยกรรมและไวยากรณ์ได้ ตัวอย่างเช่น-m i386หรือ-Mintel,x86-64. i8086เป็นสถาปัตยกรรมเก่าและการใช้โค้ดสมัยใหม่อาจให้ผลลัพธ์ที่ไม่คาดคิด นอกจากนี้การระบุx86-64ว่า-Mอาจเป็นความคิดที่ดีในปัจจุบันเนื่องจากเครื่องจำนวนมากเป็น 64 บิต ส่งintelต่อเพื่อ-Mเปลี่ยนไวยากรณ์เป็นสไตล์ Intel แทนที่จะเป็นสไตล์ AT&T เริ่มต้นซึ่งคุณอาจต้องการหรือไม่ก็ได้
GDP2

24

ฉันชอบndisasmเพื่อจุดประสงค์นี้ มาพร้อมกับแอสเซมเบลอร์ NASM ซึ่งฟรีและโอเพ่นซอร์สและรวมอยู่ในที่เก็บแพ็คเกจของ linux distros ส่วนใหญ่


ฉันชอบคำตอบนี้ดีกว่า ใช้งานง่ายกว่าและฉันสามารถติดตั้ง nasm บน OS X ได้ - ไม่มี objdump และฉันไม่ต้องการสร้างจากแหล่งที่มา

23
ndisasm -b16 -o7c00h -a -s7c3eh mbr

คำอธิบาย - จาก ndisasm manpage

  • -b= ระบุโหมด 16-, 32- หรือ 64 บิต ค่าเริ่มต้นคือโหมด 16 บิต
  • -o= ระบุที่อยู่ในการโหลดตามสัญญาสำหรับไฟล์ ตัวเลือกนี้ทำให้ ndisasm รับแอดเดรสที่แสดงไว้ที่ขอบด้านซ้ายมือและที่อยู่เป้าหมายของการกระโดดและการโทรที่สัมพันธ์กับพีซี
  • -a = เปิดใช้งานโหมดการซิงค์อัตโนมัติ (หรืออัจฉริยะ) ซึ่ง ndisasm จะพยายามเดาว่าควรจะทำซิงโครไนซ์ที่ใดโดยการตรวจสอบที่อยู่เป้าหมายของการกระโดดแบบสัมพัทธ์และเรียกมันว่าแยกชิ้นส่วน
  • -s= ระบุแอดเดรสการซิงโครไนซ์ด้วยตนเองดังนั้น ndisasm จะไม่ส่งออกคำสั่งเครื่องใด ๆ ซึ่งครอบคลุมไบต์ทั้งสองด้านของแอดเดรส ดังนั้นคำสั่งที่เริ่มต้นที่ที่อยู่นั้นจะถูกถอดประกอบอย่างถูกต้อง
  • mbr = ไฟล์ที่จะถอดประกอบ

สิ่งนี้ทำอะไรเมื่อเทียบกับ ndisasm แบบธรรมดา? คุณช่วยอธิบายตัวเลือกได้ไหม
Hawken

4
คุณช่วยอธิบายได้ไหมว่าตัวเลือกเหล่านั้นหมายถึงอะไรและมีหน้าที่อย่างไร การทำความเข้าใจคำตอบนั้นดีกว่าการรับคำตอบ
เลื่อน

-b specifies 16-, 32- or 64-bit mode. The default is 16-bit mode. -o is the notional load address for the file. This option causes ndisasm to get the addresses it lists down the left hand margin, and the target addresses of PC-relative jumps and calls, right. -s specifies a synchronisation address, such that ndisasm will not output any machine instruction which encompasses bytes on both sides of the address. Hence the instruction which starts at that address will be correctly disassembled.
Janus Troelsen

15

starblueและhlovdalทั้งสองมีส่วนของคำตอบที่เป็นที่ยอมรับ หากคุณต้องการแยกส่วนโค้ด i8086 ดิบคุณมักต้องการไวยากรณ์ของ Intel ไม่ใช่ไวยากรณ์ AT&T ด้วยดังนั้นให้ใช้:

objdump -D -Mintel,i8086 -b binary -m i386 mbr.bin
objdump -D -Mintel,i386 -b binary -m i386 foo.bin    # for 32-bit code
objdump -D -Mintel,x86-64 -b binary -m i386 foo.bin  # for 64-bit code

หากรหัสของคุณคือ ELF (หรือ a.out (หรือ (E) COFF)) คุณสามารถใช้รูปแบบย่อ:

objdump -D -Mintel,i8086 a.out  # disassembles the entire file
objdump -d -Mintel,i8086 a.out  # disassembles only code sections

สำหรับรหัส 32 บิตหรือ 64 บิตให้ละเว้น,8086; ส่วนหัวของ ELF มีข้อมูลนี้อยู่แล้ว

ndisasmตามที่แนะนำโดยjameslinก็เป็นทางเลือกที่ดีเช่นกัน แต่objdumpโดยปกติแล้วจะมาพร้อมกับระบบปฏิบัติการและสามารถจัดการกับสถาปัตยกรรมทั้งหมดที่ GNU binutils รองรับ (ส่วนเหนือของที่รองรับโดย GCC) และโดยปกติเอาต์พุตจะสามารถป้อนเข้า GNU ได้as(โดยปกติแล้ว ndisasm สามารถ จะถูกป้อนเข้าไปnasmแน่นอน)

Peter Cordesแนะนำว่า“ objconv ของ Agner Fogนั้นดีมาก ทำให้ป้ายกำกับเป้าหมายสาขาทำให้ง่ายต่อการเข้าใจว่าโค้ดทำอะไร สามารถแยกส่วนออกเป็นไวยากรณ์ NASM, YASM, MASM หรือ AT&T (GNU)”

มัลติมีเดียไมค์แล้วพบข้อมูลเกี่ยวกับ--adjust-vma; สิ่งที่ndisasmเทียบเท่าคือ-oตัวเลือก

ในการแยกชิ้นส่วนให้พูดsh4รหัส (ฉันใช้หนึ่งไบนารีจาก Debian เพื่อทดสอบ) ใช้สิ่งนี้กับ GNU binutils (ตัวแยกชิ้นส่วนอื่น ๆ เกือบทั้งหมดถูก จำกัด ไว้ที่แพลตฟอร์มเดียวเช่น x86 พร้อมndisasmและobjconv):

objdump -D -b binary -m sh -EL x

-mเป็นเครื่องและ-ELหมายเล็ก ๆ น้อย ๆ Endian (สำหรับsh4ebใช้-EBแทน) ซึ่งมีความเกี่ยวข้องสำหรับสถาปัตยกรรมที่มีอยู่ใน endianness อย่างใดอย่างหนึ่ง


2
objconv ของ Agner Fogสวยมาก ทำให้ป้ายกำกับเป้าหมายสาขาทำให้ง่ายต่อการเข้าใจว่าโค้ดทำอะไร สามารถแยกส่วนเป็นไวยากรณ์ NASM, YASM, MASM หรือ AT&T (GNU)
Peter Cordes

มันสร้างขึ้นได้ดีทันทีบน GNU / Linux สำหรับฉัน แต่ใช่มันเป็น x86 / x86-64 เท่านั้นซึ่งแตกต่างจาก GNU binutils อย่างไรก็ตามมีคำแนะนำเฉพาะ x86 ที่ดีมากมายที่จะเพิ่มเป็นความคิดเห็นเช่นเมื่อคำนำหน้าขนาดตัวถูกดำเนินการอาจทำให้เกิด LCP-Stall ในตัวถอดรหัสของ CPU Intel โดยทั้งหมดระบุไว้ในคำตอบของคุณ จุดประสงค์หลักประการหนึ่งของการแสดงความคิดเห็นคือการช่วยให้ผู้โพสต์ปรับปรุงคำตอบของพวกเขาไม่ใช่แค่เป็นสิ่งที่ผู้ชมในภายหลังต้องอ่านด้วย
Peter Cordes

1
@PeterCordes ใช่ฉันมี MirBSD เป็น OS หลัก;)
mirabilos

@PeterCordes แต่ดูเหมือนว่าจะไม่สามารถแยกชิ้นส่วนไบนารีดิบได้ใช่ไหม? ฉันต้องสร้างไฟล์ ELF เพียงเล็กน้อยเพื่อให้สามารถป้อนคำสั่งมากมายลงไปได้ แต่บางทีฉันอาจพลาดบางตัวเลือกไป?
Ruslan

1
@Ruslan: IDK คำถามที่น่าสนใจ ฉันมักจะใช้ objdump หรือถ้าฉันต้องการป้ายกำกับสาขาgcc -O3 -masm=intel -fverbose-asm -S -o- | lessเนื่องจากฉันมักจะพยายามปรับแต่งแหล่งที่มา C เพื่อรวบรวมเป็น asm ที่ดี
Peter Cordes

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.