วัตถุประสงค์ของการเรียนการสอน NOP และจัดแนวคำสั่งในชุดประกอบ x86


15

เป็นเวลาหนึ่งปีหรือมากกว่านั้นตั้งแต่ที่ฉันเข้าเรียนในชั้นเรียน ในชั้นเรียนนั้นเราใช้ MASM กับห้องสมุด Irvine เพื่อให้การเขียนโปรแกรมง่ายขึ้น

หลังจากที่เราได้ทำตามคำแนะนำส่วนใหญ่แล้วเขาบอกว่าคำสั่ง NOP นั้นไม่ได้ทำอะไรเลยและไม่ต้องกังวลกับการใช้มัน อย่างไรก็ตามมันเกี่ยวกับมิดเทอมและเขามีโค้ดตัวอย่างบางตัวที่ทำงานไม่ถูกต้องดังนั้นเขาจึงบอกให้เราเพิ่มคำสั่ง NOP และทำงานได้ดี ฉันถามฉันว่าทำไมฉันถึงเรียนหลังเลิกเรียนและสิ่งที่ทำจริงและเขาบอกว่าเขาไม่รู้

มีใครรู้บ้าง


NOP ไม่ทำอะไรเลย แต่ใช้รอบ ฉันไม่คิดว่าคำถามของคุณสามารถตอบได้หากไม่มีรหัสเราสามารถเดาได้เท่านั้น ดีคาดเดาของฉันจะเป็นภาพนิ่ง NOP ...
Yannis

11
NOP ทำอะไรบางอย่างจริงๆ มันเพิ่มตัวชี้คำแนะนำ
EricSchaefer

คำตอบ:


37

บ่อยครั้งที่NOPใช้เพื่อจัดตำแหน่งที่อยู่คำสั่ง นี้มักจะพบตัวอย่างเช่นเมื่อเขียนShellcodeจะใช้ประโยชน์จากหน่วยความจำล้นหรือช่องโหว่สตริงรูปแบบ

สมมติว่าคุณมีการข้ามแบบสัมพัทธ์จนถึง 100 ไบต์และทำการแก้ไขโค้ด โอกาสที่จะเกิดขึ้นคือการปรับเปลี่ยนที่อยู่ของเป้าหมายกระโดดและทำให้คุณต้องเปลี่ยนการกระโดดที่สัมพันธ์กันดังกล่าวข้างต้น ที่นี่คุณสามารถเพิ่มNOPs เพื่อผลักที่อยู่เป้าหมายไปข้างหน้า หากคุณมีหลายNOPs ระหว่างที่อยู่เป้าหมายและคำสั่งการกระโดดคุณสามารถลบNOPs เพื่อดึงที่อยู่เป้าหมายไปด้านหลัง

สิ่งนี้จะไม่เป็นปัญหาหากคุณทำงานกับแอสเซมเบลอร์ที่รองรับฉลาก คุณสามารถทำได้JXX someLabel(โดยที่ JXX มีการกระโดดแบบมีเงื่อนไข) และแอสเซมเบลอร์จะแทนที่someLabelด้วยที่อยู่ของป้ายกำกับนั้น อย่างไรก็ตามหากคุณเพียงแค่แก้ไขรหัสเครื่องประกอบ (opcodes จริง) ด้วยมือ (เพราะบางครั้งมันเกิดขึ้นกับการเขียน shellcode) คุณต้องเปลี่ยนคำสั่งการกระโดดด้วยตนเอง ไม่ว่าคุณจะปรับเปลี่ยนหรือย้ายที่อยู่รหัสเป้าหมายโดยใช้NOPs

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

อีกประการหนึ่งที่ใช้สำหรับการNOPเรียนการสอนคือเมื่อมีการปรับเปลี่ยนรหัสของบางโปรแกรม ตัวอย่างเช่นคุณสามารถแทนที่ส่วนของเงื่อนไขการกระโดดด้วยNOPs และหลีกเลี่ยงเงื่อนไขดังกล่าว นี้เป็นวิธีที่มักใช้เมื่อ " แตก " ป้องกันการคัดลอกซอฟแวร์ ที่ง่ายที่สุดมันเป็นเพียงการลบการสร้างรหัสประกอบสำหรับif(genuineCopy) ...บรรทัดของรหัสและแทนที่คำแนะนำด้วยNOPs และ .. Voilà! ไม่มีการตรวจสอบและทำสำเนาที่ไม่ใช่ของแท้!

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


2
นี่เป็นคำตอบที่ยอดเยี่ยมขอบคุณที่สละเวลาอธิบายสิ่งนี้! ในที่สุดฉันก็เข้าใจ!
alvonellos

ระบบเรียลไทม์บางตัว (PLC คำนึงถึง) ช่วยให้คุณสามารถ "แก้ไข" ตรรกะใหม่ในโปรแกรมที่มีอยู่แล้วในขณะที่ทำงานอยู่ ระบบเหล่านี้ออกจาก NOP ก่อนหน้าตรรกะเล็ก ๆ ทุกชิ้นเพื่อให้คุณสามารถเขียนทับ NOP ด้วยการข้ามไปยังตรรกะใหม่ที่คุณใส่เข้าไป ในตอนท้ายของตรรกะใหม่มันจะข้ามไปที่จุดสิ้นสุดของตรรกะเดิมที่คุณกำลังเปลี่ยน ตรรกะใหม่จะมี NOP อยู่ด้านหน้าเพื่อให้คุณสามารถแทนที่ตรรกะใหม่ได้เช่นกัน
Scott Whitlock

10

nop อาจถูกใช้ใน AA delay slotเมื่อไม่มีคำสั่งอื่นที่อาจถูกจัดลำดับใหม่ให้อยู่ในนั้น

lw   v0,4(v1)
jr   v0

ใน MIPS นี่จะเป็นข้อผิดพลาดเพราะในขณะที่ jr อ่าน register v0 register v0 ยังไม่ได้โหลดด้วยค่าจากคำสั่งก่อนหน้า

วิธีแก้ไขปัญหานี้คือ:

lw   v0,4(v1)
nop
jr   v0
nop

สิ่งนี้จะเติมสล็อต dealy หลังจากคำโหลดและกระโดดลงทะเบียนด้วยคำสั่ง nop เพื่อให้คำสั่งโหลดคำศัพท์เสร็จสมบูรณ์ก่อนที่คำสั่ง jump register จะถูกดำเนินการ

อ่านเพิ่มเติม - บิต SPARC เติมช่องล่าช้า จากเอกสารนั้น:

สิ่งที่สามารถใส่ลงในช่องเสียบล่าช้า?

  • คำแนะนำที่มีประโยชน์ที่ควรดำเนินการไม่ว่าคุณจะแยกสาขาหรือไม่ก็ตาม
  • คำสั่งบางอย่างที่มีประโยชน์จะทำงานเฉพาะเมื่อคุณแยกสาขา (หรือเมื่อคุณไม่ได้แยกสาขา) แต่จะไม่ทำอันตรายใด ๆ หากดำเนินการในกรณีอื่น
  • เมื่อทุกอย่างล้มเหลวคำสั่ง NOP

ต้องใส่อะไรลงในช่องเสียบล่าช้า?

  • อะไรก็ตามที่กำหนด CC ที่การตัดสินใจสาขาขึ้นอยู่กับ การเรียนการสอนสาขาทำให้การตัดสินใจว่าสาขาหรือไม่ทันที แต่มันไม่ได้ทำจริงสาขาจนกว่าจะหลังจากการเรียนการสอนล่าช้า (เฉพาะสาขาล่าช้าเท่านั้นไม่ใช่การตัดสินใจ)
  • คำสั่งสาขาอื่น (จะเกิดอะไรขึ้นถ้าคุณทำเช่นนี้ไม่ได้กำหนดไว้! ผลลัพธ์จะคาดเดาไม่ได้!)
  • คำสั่ง "set" นี่เป็นสองคำแนะนำไม่ใช่หนึ่งเดียวและครึ่งหนึ่งเท่านั้นที่จะอยู่ในช่วงหน่วงเวลา (แอสเซมเบลอร์จะเตือนคุณเกี่ยวกับสิ่งนี้)

หมายเหตุตัวเลือกที่สามในสิ่งที่จะใส่ลงในช่องเสียบล่าช้า ข้อผิดพลาดที่คุณเห็นอาจเป็นไปได้ว่ามีคนกรอกหนึ่งในสิ่งที่ต้องไม่ใส่ลงในช่องเสียบล่าช้า วาง nop ในตำแหน่งนั้นจะแก้ไขข้อบกพร่อง

หมายเหตุ: หลังจากอ่านคำถามอีกครั้งสิ่งนี้มีไว้สำหรับ x86 ซึ่งไม่มีช่องหน่วงเวลา เพื่อที่จะไม่เป็นสาเหตุ / แก้ไขข้อผิดพลาด สำหรับระบบ RISC นั่นอาจเป็นคำตอบ


4
โปรดทราบว่าคำถามถูกติดแท็ก x86 และ x86 ไม่มีช่วงเวลาหน่วง ไม่เคยเช่นกันเนื่องจากเป็นการเปลี่ยนแปลงที่ไม่หยุดหย่อน
MSalters

6

อย่างน้อยหนึ่งเหตุผลในการใช้ NOP คือการจัดตำแหน่ง ตัวประมวลผล x86 อ่านข้อมูลจากหน่วยความจำหลักในบล็อกที่ค่อนข้างใหญ่และจุดเริ่มต้นของบล็อกเพื่ออ่านถูกจัดแนวเสมอดังนั้นหากมีบล็อกของรหัสที่จะอ่านมากบล็อกนี้ควรจะจัดตำแหน่ง ซึ่งจะส่งผลให้การเร่งความเร็วเล็กน้อย


ไม่ใช่ว่าต้องจัดแนวบล็อก แต่คุณไม่ต้องการดึงข้อมูลไบต์คู่สุดท้ายของบล็อกก่อนหน้านี้ ดังนั้นจึงเป็นเรื่องที่ดีที่จะข้ามไป0x1002เพราะยังคงมี 14 ไบต์ของคำแนะนำในบล็อกชิด 16B ที่มีอยู่เป้าหมาย 0x099Dแต่ไม่ได้ปรับเพื่อข้ามไป
Peter Cordes

3

วัตถุประสงค์หนึ่งสำหรับ NOP (โดยทั่วไปไม่เพียง x86) เพื่อแนะนำการหน่วงเวลา ตัวอย่างเช่นคุณต้องการตั้งโปรแกรมไมโครคอนโทรลเลอร์ที่ต้องส่งออกไปยัง LED บางตัวที่มีความล่าช้า 1 วินาที ความล่าช้านี้สามารถนำมาใช้กับ NOP (และสาขา) แน่นอนคุณสามารถใช้ ADD หรืออย่างอื่น แต่นั่นจะทำให้โค้ดอ่านไม่ได้มากขึ้น หรือคุณอาจต้องลงทะเบียนทั้งหมด


1
โดยปกติแล้วจะใช้ตัวจับเวลาเป็นเวลานานเช่น 1 วินาที NOPS ใช้สำหรับยุคในลำดับความสำคัญของนาฬิกา - นาโนและไมโครวินาที
mattnz

นี้เพียงทำให้รู้สึกบนไมโครคอนโทรลเลอร์ไม่ x86 ที่ทันสมัย รหัส x86 ส่วนใหญ่ไม่ได้เพิ่มความกว้างของไพพ์ไลน์ของซีพียูที่ทันสมัยเกินคำสั่งดังนั้นการเพิ่ม NOP ระหว่างคำสั่งทุกคำสั่งในโค้ดส่วนใหญ่จะมีผลกระทบเพียงเล็กน้อย (ฉันเดาว่าอาจเป็นรหัส "เฉลี่ย" 5-20% สำหรับสองเท่าของจำนวนคำแนะนำที่มีโค้ดบางส่วนที่แสดงให้เห็นการชะลอตัว แต่ลูปแน่นไม่กี่แสดงเกือบชะลอตัว 2x.) อย่างไรก็ตามดื้อรหัส x86 เก่าที่ใช้ในประเพณีเรียนการสอนสำหรับลูปล่าช้าไม่ nops loop
Peter Cordes

3

โดยทั่วไปใน 80x86 คำสั่ง NOP นั้นไม่จำเป็นสำหรับความถูกต้องของโปรแกรมแม้ว่าบางครั้งในเครื่องบางเครื่อง NOP ที่วางอย่างมีกลยุทธ์อาจทำให้โค้ดทำงานได้เร็วขึ้น ตัวอย่างเช่นใน 8086 รหัสจะถูกดึงมาในหน่วยสองไบต์และตัวประมวลผลมีบัฟเฟอร์ "prefetch" ภายในซึ่งสามารถเก็บชิ้นส่วนดังกล่าวได้สามชิ้น คำแนะนำบางอย่างจะทำงานได้เร็วกว่าที่จะดึงข้อมูลได้ในขณะที่คำแนะนำอื่น ๆ อาจใช้เวลาสักครู่ในการดำเนินการ ในระหว่างคำสั่งช้าตัวประมวลผลจะพยายามเติมบัฟเฟอร์การดึงข้อมูลล่วงหน้าดังนั้นหากคำแนะนำสองสามข้อถัดไปนั้นรวดเร็วพวกเขาสามารถดำเนินการได้อย่างรวดเร็ว หากคำสั่งที่ตามหลังคำสั่งช้าเริ่มต้นที่ขอบเขตคำที่มีค่าคำสั่งหกไบต์ถัดไปจะถูกดึงมาล่วงหน้า หากมันเริ่มต้นบนขอบเขตไบต์คี่เพียงห้าไบต์เท่านั้นที่จะถูกดึงข้อมูลล่วงหน้า

ปัญหาการจัดตำแหน่งหน่วยความจำดังกล่าวอาจส่งผลต่อความเร็วของโปรแกรม แต่โดยทั่วไปจะไม่ส่งผลกระทบต่อความถูกต้อง ในทางตรงกันข้ามมีปัญหาที่เกี่ยวข้องกับการดึงข้อมูลล่วงหน้าในโปรเซสเซอร์รุ่นเก่าเหล่านั้นซึ่ง NOP อาจส่งผลกระทบต่อความถูกต้อง หากคำสั่งเปลี่ยนแปลงรหัสไบต์ซึ่งถูกดึงมาล่วงหน้าแล้ว 8086 (และฉันคิดว่า 80286 และ 80386) จะดำเนินการคำสั่งดึงข้อมูลล่วงหน้าแม้ว่าจะไม่ตรงกับสิ่งที่อยู่ในหน่วยความจำอีกต่อไป การเพิ่ม NOP หรือสองครั้งระหว่างคำสั่งที่เปลี่ยนหน่วยความจำและรหัสไบต์ซึ่งมีการเปลี่ยนแปลงอาจทำให้ไม่สามารถเรียกรหัสไบต์ได้จนกว่าจะมีการเขียน โปรดทราบว่าวิธีการป้องกันการทำสำเนาจำนวนมากใช้ประโยชน์จากพฤติกรรมเช่นนี้ อย่างไรก็ตามโปรดทราบว่าพฤติกรรมนี้ไม่รับประกัน การเปลี่ยนแปลงของโปรเซสเซอร์ที่แตกต่างกันอาจจัดการการดึงข้อมูลล่วงหน้าแตกต่างกัน บางหน่วยอาจทำให้การดึงข้อมูลล่วงหน้าเป็นโมฆะหากหน่วยความจำที่ถูกอ่านถูกแก้ไขและโดยทั่วไปการขัดจังหวะจะทำให้บัฟเฟอร์ prefetch ใช้ไม่ได้ รหัสจะถูกเรียกอีกครั้งเมื่ออินเตอร์รัปต์ส่งคืน


3

มีเคสเฉพาะ x86 ที่ยังไม่ได้อธิบายไว้ในคำตอบอื่น ๆ : การจัดการขัดจังหวะ สำหรับลักษณะบางอย่างอาจมีส่วนของรหัสเมื่อปิดใช้งานการขัดจังหวะเนื่องจากรหัสหลักทำงานกับข้อมูลบางอย่างที่ใช้ร่วมกับตัวจัดการขัดจังหวะ แต่มีเหตุผลที่จะอนุญาตการขัดจังหวะระหว่างส่วนดังกล่าว ถ้าใครเขียนอย่างไร้เดียงสา


    STI
    CLI

สิ่งนี้จะไม่ประมวลผลการขัดจังหวะเนื่องจากอ้างถึง Intel:

หลังจากตั้งค่าสถานะ IF แล้วตัวประมวลผลเริ่มตอบสนองต่อการอินเตอร์รัปต์ภายนอก maskable หลังจากดำเนินการคำสั่งถัดไป

ดังนั้นสิ่งนี้จะถูกเขียนใหม่อย่างน้อยเป็น:


    STI
    NOP
    CLI

ในตัวแปรที่สองอินเตอร์รัปต์ที่ค้างอยู่ทั้งหมดจะถูกประมวลผลระหว่าง NOP และ CLI (แน่นอนสามารถมีได้หลายทางเลือกเช่นเดียวกับการเพิ่มคำสั่ง STI เป็นสองเท่า แต่ NOP ที่ชัดเจนนั้นชัดเจนกว่าอย่างน้อยสำหรับฉัน)


-2

NOP หมายถึงไม่มีการใช้งาน

โดยทั่วไปจะใช้สำหรับการแทรกหรือลบรหัสเครื่องหรือเพื่อชะลอการเรียกใช้งานรหัสเฉพาะ

นอกจากนี้ยังใช้โดยแครกเกอร์และ debuggers เพื่อตั้งจุดพัก

ดังนั้นอาจทำสิ่งที่ชอบ: XCHG BX, BX จะส่งผลเหมือนกัน

เสียงสำหรับฉันราวกับว่ามีการดำเนินการบางอย่างที่ยังอยู่ระหว่างการดำเนินการและด้วยเหตุนี้มันทำให้เกิดข้อผิดพลาด

หากคุณคุ้นเคยกับ VB ฉันสามารถยกตัวอย่าง:

หากคุณสร้างระบบเข้าสู่ระบบใน vb และโหลด 3 หน้าพร้อมกัน - facebook, youtube และ twitter ใน 3 แท็บที่แตกต่างกัน

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

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