N86 komutunun amacı ve x86 montajındaki hizalama ifadesi


15

En son bir montaj dersi aldığımdan bu yana bir yıl geçti. Bu sınıfta, programlamayı kolaylaştırmak için Irvine kütüphaneleriyle MASM kullanıyorduk.

Talimatların çoğunu geçtikten sonra, NOP talimatının aslında hiçbir şey yapmadığını ve onu kullanmaktan endişe etmeyeceğini söyledi. Her neyse, bu ara sınav ile ilgiliydi ve düzgün çalışmayan bazı örnek kodları var, bu yüzden bize bir NOP talimatı eklememizi söyledi ve iyi çalıştı. Dersten sonra neden ve ne yaptığını sordum ve bilmediğini söyledi.

Kimse biliyor mu?


NOP hiçbir şey yapmaz, ancak döngüleri tüketir. Sorunuzun sadece tahmin edebileceğimiz kod olmadan cevaplanabileceğini sanmıyorum. Benim tahminim bir NOP slayt olurdu ...
yannis

11
NOP aslında bir şey yapar. Yönerge İşaretçisini artırır.
EricSchaefer

Yanıtlar:


37

Çoğu zaman NOPtalimat adreslerini hizalamak için kullanılır. Bu genellikle, örneğin arabellek taşmasını kullanmak veya dize güvenlik açığını biçimlendirmek için Shellcode yazılırken görülür .

100 bayt ileriye doğru göreceli bir sıçrama yaptığınızı ve kodda bazı değişiklikler yaptığınızı varsayalım. Şanslarınız değişikliklerinizin atlama hedefinin adresini bozmasıdır ve böylece yukarıda belirtilen göreceli sıçramayı da değiştirmeniz gerekecektir. Burada, NOPhedef adresi ileri itmek için s ekleyebilirsiniz . NOPHedef adres ile atlama talimatı arasında birden fazla s varsa NOP, hedef adresi geriye çekmek için s'yi kaldırabilirsiniz .

Etiketleri destekleyen bir montajcı ile çalışıyorsanız bu sorun olmaz. Basitçe yapabilirsiniz JXX someLabel(burada JXX bazı koşullu atlamadır) ve birleştirici, someLabeletiketi bu etiketin adresiyle değiştirecektir . Ancak, monte edilen makine kodunu (gerçek opcode) elle değiştirirseniz (bazen kabuk kodu yazarken olduğu gibi), atlama talimatını manuel olarak da değiştirmeniz gerekir. Ya onu değiştirin ya da NOPs kullanarak hedef kod adresini taşıyın .

NOPTalimat için bir başka kullanım örneği, NOP kızağı olarak adlandırılan bir şey olacaktır . Özünde fikir, hiçbir yan etkiye neden olmayan (ör.NOPveya bir kaydı artırıp azaltarak) ancak talimat işaretçisini artırın. Bu, örneğin, adresi bilinmeyen belirli bir kod parçasına atlamak istediğinde yararlıdır. İşin püf noktası, bahsedilen NOP kızağını hedef kodun önüne yerleştirmek ve daha sonra bahsedilen kızağa bir yere atlamaktır. Olan şey, yürütmenin umarım yan etkisi olmayan diziden devam etmesidir ve istenen kod parçasına çarpana kadar talimat başına talimatı iletir. Bu teknik, yukarıda belirtilen tampon taşması istismarlarında ve özellikle ASLR gibi karşı güvenlik önlemlerinde yaygın olarak kullanılmaktadır .

NOPTalimat için bir başka özel kullanım , bir programın kodunu değiştirmektir. Örneğin, koşullu atlamaların parçalarını NOPs ile değiştirebilir ve böylece durumu atlatabilirsiniz. Bu, yazılımın kopya korumasını " kırırken " sıklıkla kullanılan bir yöntemdir . En basit haliyle, sadece kod if(genuineCopy) ...satırı için montaj kodu yapısını kaldırmak ve talimatları NOPs ve .. ile değiştirmekle ilgili .. Voilà! Hiçbir kontrol yapılmaz ve orijinal olmayan kopyalar çalışır!

Özünde hem kabuk kodu hem de çatlama örneklerinin aynı şeyi yaptığına dikkat edin; göreli adreslemeye dayanan işlemlerin göreli adreslerini güncellemeden mevcut kodu değiştirin.


2
Bu harika bir cevaptı, bunu açıklamak için zaman ayırdığınız için teşekkürler! Sonunda anlıyorum!
alvonellos

Bazı gerçek zamanlı sistemler (PLC'ler akla gelir) yeni mantığı çalışırken mevcut bir programa "yama" yapmanızı sağlar. Bu sistemler NOP'ları her küçük mantık parçasından önce bırakır, böylece yerleştirdiğiniz yeni mantığa atlayarak NOP'nin üzerine yazabilirsiniz. Yeni mantığın sonunda, değiştirdiğiniz orijinal mantığın sonuna atlayacaktır. Yeni mantığın önünde de bir NOP olacaktır, böylece yeni mantığı da değiştirebilirsiniz.
Scott Whitlock

10

Bir gecikme yuvasında , içine yerleştirilmek üzere başka bir talimatın yeniden sıralanamaması durumunda bir nop kullanılabilir .

lw   v0,4(v1)
jr   v0

MIPS'de bu bir hata olacaktır çünkü jr v0 kaydını okuduğu sırada v0 kaydı, önceki talimattan henüz gelen değerle yüklenmemiştir.

Bunu düzeltmenin yolu:

lw   v0,4(v1)
nop
jr   v0
nop

Bu, yükleme sözcüğü ve atlama yazmacı yönergelerinden sonra dealy yuvalarını bir nop ile doldurur, böylece atlama sözcüğü komutu, atlama yazmacı komutu yürütülmeden önce tamamlanır.

Daha fazla okuma - gecikme yuvalarının SPARC dolgusunda biraz . Bu belgeden:

Gecikme yuvasına ne konabilir?

  • İster dallanıp dallandırılsın, yürütülmesi gereken bazı yararlı talimatlar.
  • Yararlı olan bazı talimatlar yalnızca dallandığınızda (veya dallanmadığınızda) çalışır, ancak diğer durumda yürütüldüğünde herhangi bir zarar vermez.
  • Her şey başarısız olduğunda, bir NOP talimatı

Gecikme yuvasına NELER YAPILMAMALIDIR?

  • Şube kararının bağlı olduğu CC'yi belirleyen her şey. Şube talimatı, hemen dallanıp dallanmayacağına karar verir, ancak gecikme talimatından sonraya kadar şubeyi yapmaz. (Sadece şube gecikir, karar değil.)
  • Başka bir dal talimatı. (Bunu yaparsanız ne olur bile tanımlanmamıştır! Sonuç tahmin edilemez!)
  • Bir "set" talimatı. Bu gerçekten iki talimat, bir değil ve sadece yarısı gecikme yuvasında olacak. (Montajcı sizi bu konuda uyaracaktır.)

Gecikme yuvasına ne konulacağına dair üçüncü seçeneği not edin. Gördüğünüz hata muhtemelen gecikme yuvasına konmaması gereken şeylerden birini dolduruyordu. Bu konuma bir nop koymak, hatayı düzeltir.

Not: soruyu yeniden okuduktan sonra, bu gecikme yuvaları olmayan x86 içindi (dallanma bunun yerine sadece boru hattını durdurur). Bu yüzden hatanın nedeni / çözümü olmaz. RISC sistemlerinde cevap bu olabilirdi.


4
Sorunun x86 olarak etiketlendiğini ve x86'nın gecikme yuvaları olmadığını unutmayın. Asla, ya da olmayacak, çünkü bu büyük bir değişiklik.
MSalters

6

NOP kullanmanın en az bir nedeni hizalamadır. x86 işlemcileri ana bellekteki verileri oldukça büyük bloklarda okur ve okunacak blok başlangıcı her zaman hizalanır, bu nedenle kod bloğuna sahipse, çok okunacaksa, bu blok hizalanmalıdır. Bu az hızlanma ile sonuçlanacaktır.


Tam olarak bloğun hizalanması gerekmiyor, önceki bloğun son çift baytını almak zorunda kalmak istemiyorsunuz. Bu yüzden atlamak iyidir 0x1002, çünkü 16B'nin hizalanmış bloğunda hedef adresi içeren ancak atlamak için iyi olmayan 14 baytlık talimatlar vardır 0x099D.
Peter Cordes

3

NOP'un bir amacı (genel montajda, sadece x86'da değil) zaman gecikmeleri getirmektir. Örneğin, bazı LED'lere 1 sn gecikmeyle çıkması gereken bir mikro denetleyici programlamak istiyorsunuz. Bu gecikme NOP (ve şubeler) ile uygulanabilir. Tabii ki bazı ADD veya başka bir şey kullanabilirsiniz, ancak bu kodu daha okunamaz hale getirir; veya belki de tüm kayıtlara ihtiyacınız var.


1
Genellikle 1 saniye gibi uzun zaman dilimleri için zamanlayıcılar kullanılır. NOPS, saat - nano ve mikro saniye büyüklüğünde bir dönem için kullanılır.
mattnz

Bu sadece bir mikrodenetleyicide mantıklıdır, modern bir x86'da değil. Çoğu x86 kodu modern süperskalar sıra dışı CPU'ların boru hattı genişliğini doyurmaz, bu nedenle çoğu koddaki her talimat arasına bir NOP eklemek sadece küçük bir etkiye sahip olacaktır ("ortalama" kod için sayı olabilir 5 hayır yavaşlama ama neredeyse bir 2x yavaşlama gösteren birkaç sıkı döngüler gösteren bazı kod ile, talimatların sayısını iki katına için% 20.) Neyse, huysuz yaşlı x86 kod geleneksel olarak kullanılan gecikme döngüleri için talimat değil, NOPs. loop
Peter Cordes

3

Genel olarak 80x86'da NOP talimatları programın doğruluğu için gerekli değildir, ancak bazı makinelerde bazen stratejik olarak yerleştirilmiş bir NOP'ler kodun daha hızlı çalışmasına neden olabilir. Örneğin, 8086'da kod iki baytlık parçalar halinde getirilir ve işlemcide bu tür üç parçayı tutabilen dahili bir "ön getirme" tamponu bulunur. Bazı talimatlar getirilebildiğinden daha hızlı yürütülürken, diğer talimatların yürütülmesi biraz zaman alacaktır. Yavaş komutlar sırasında işlemci, ön alma arabelleğini doldurmayı dener, böylece sonraki birkaç talimat hızlı olsaydı hızlı bir şekilde yürütülebilirler. Yavaş talimatı izleyen talimat eşit bir sözcük sınırında başlarsa, sonraki altı bayt değerinde talimat önceden alınacaktır; tek bir bayt sınırında başlarsa, yalnızca beş bayt önceden getirilir.

Bu tür bellek hizalama sorunları program hızını etkileyebilir, ancak genellikle doğruluğu etkilemez. Öte yandan, eski NOP işlemcilerinde bir NOP'un doğruluğu etkileyebileceği önceden getirme ile ilgili bazı sorunlar vardır. Bir komut önceden getirilmiş olan bir kod baytını değiştirirse, 8086 (ve bence 80286 ve 80386) artık bellekte bulunanlarla eşleşmese bile önceden getirilmiş komutu yürütür. Belleği değiştiren talimat ile değiştirilen kod baytı arasına bir NOP veya iki eklemek, kod baytının yazılana kadar getirilmesini engelleyebilir. Bu arada, birçok kopya koruma şemasının bu tür davranışlardan yararlandığını unutmayın; bununla birlikte, bu davranışın garanti edilmediğini unutmayın. Farklı işlemci varyasyonları, ön getirmeyi farklı işleyebilir, bazıları, okundukları bellek değiştirilirse önceden getirilmiş baytları geçersiz kılabilir ve kesmeler genellikle önceden getirme arabelleğini geçersiz kılacaktır; kesmeler geri döndüğünde kod yeniden getirilir.


3

Diğer yanıtlarda hala açıklanmayan x86'ya özgü bir durum vardır: kesme işlemi. Bazı stilleri için, ana kod kesme işleyicileri ile paylaşılan bazı verilerle çalıştığından, kesmeler devre dışı bırakıldığında kod bölümleri olabilir, ancak bu bölümler arasında kesmelere izin vermek mantıklıdır. Biri safça yazarsa


    STI
    CLI

Intel'e dikkat çekerek beklemede olan kesintileri işlemez.

EĞER bayrağı ayarlandıktan sonra, işlemci sonraki komut yürütüldükten sonra harici, maskelenebilir kesintilere yanıt vermeye başlar.

bu yüzden en azından şu şekilde yeniden yazılmalıdır:


    STI
    NOP
    CLI

İkinci varyantta, bekleyen tüm kesintiler NOP ve CLI arasında işlenecektir. (Elbette, STI talimatını ikiye katlamak gibi birçok alternatif varyant olabilir. Ancak açık NOP, en azından benim için daha açıktır.)


-2

NOP İşlem Yok anlamına gelir

Genellikle makine kodu eklemek veya silmek veya belirli bir kodun yürütülmesini geciktirmek için kullanılır.

Ayrıca krakerler ve hata ayıklayıcılar tarafından kesme noktalarını ayarlamak için kullanılır.

Muhtemelen şöyle bir şey yapıyorsunuz: XCHG BX, BX de aynı şekilde sonuçlanacak.

Bana hâlâ işlemde olan az sayıda işlem varmış gibi geldi ve bu yüzden bir hataya neden oldu.

VB hakkında bilginiz varsa, size bir örnek verebilirim:

Vb'de bir giriş sistemi yaparsanız ve birlikte 3 sayfa yüklerseniz - facebook, youtube ve twitter 3 farklı sekmede.

Ve herkes için 1 giriş düğmesini kullanın. İnternet bağlantınız yavaşsa bir hata verebilir. Bu, sayfalardan birinin henüz yüklenmediği anlamına gelir. Bu yüzden bunun üstesinden gelmek için Application.DoEvents uygulamasını koyduk. NOP montajında ​​da aynı şekilde kullanılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.