Sudah setahun atau lebih sejak saya terakhir mengambil kelas perakitan. Di kelas itu, kami menggunakan MASM dengan perpustakaan Irvine untuk membuatnya lebih mudah diprogram.
Setelah kami mempelajari sebagian besar instruksi, ia mengatakan bahwa instruksi NOP pada dasarnya tidak melakukan apa-apa dan tidak perlu khawatir menggunakannya. Lagi pula, itu tentang ujian tengah semester dan dia memiliki beberapa contoh kode yang tidak akan berjalan dengan baik, jadi dia menyuruh kami untuk menambahkan instruksi NOP dan itu berfungsi dengan baik. Saya bertanya saya setelah kelas mengapa dan apa yang sebenarnya terjadi, dan dia bilang dia tidak tahu.
Adakah yang tahu?
Jawaban:
Sering kali
NOP
digunakan untuk menyelaraskan alamat instruksi. Ini biasanya ditemui misalnya ketika menulis Shellcode untuk mengeksploitasi buffer overflow atau kerentanan format string .Katakanlah Anda memiliki lompatan relatif ke 100 byte ke depan, dan buat beberapa modifikasi pada kode. Kemungkinannya adalah modifikasi Anda mengacaukan alamat target lompatan dan karenanya Anda juga harus mengubah lompatan relatif tersebut. Di sini, Anda dapat menambahkan
NOP
s untuk mendorong alamat target ke depan. Jika Anda memiliki beberapaNOP
s antara alamat target dan instruksi lompat, Anda dapat menghapusNOP
s untuk menarik mundur alamat target.Ini tidak akan menjadi masalah jika Anda bekerja dengan assembler yang mendukung label. Anda dapat melakukannya
JXX someLabel
(di mana JXX merupakan lompatan bersyarat) dan assembler akan menggantisomeLabel
dengan alamat label tersebut. Namun, jika Anda cukup memodifikasi kode mesin rakitan (opcodes aktual) dengan tangan (seperti yang kadang-kadang terjadi dengan menulis shellcode), Anda juga harus mengubah instruksi lompat secara manual. Anda dapat memodifikasinya, atau memindahkan alamat kode target dengan menggunakanNOP
s.Kasus penggunaan lain untuk
NOP
instruksi adalah sesuatu yang disebut kereta luncur NOP . Intinya idenya adalah untuk membuat array instruksi yang cukup besar yang tidak menimbulkan efek samping (sepertiNOP
atau menambah dan kemudian mengurangi register) tetapi menambah penunjuk instruksi. Ini berguna misalnya ketika seseorang ingin melompat ke bagian kode tertentu yang alamatnya tidak diketahui. Caranya adalah dengan menempatkan kereta luncur NOP di depan kode target dan kemudian melompat ke suatu tempat ke kereta luncur tersebut. Apa yang terjadi adalah bahwa eksekusi berlanjut dengan harapan dari array yang tidak memiliki efek samping dan ia akan meneruskan instruksi-per-instruksi hingga menyentuh bagian kode yang diinginkan. Teknik ini biasanya digunakan dalam eksploitasi buffer overflow yang disebutkan di atas dan terutama untuk melawan langkah-langkah keamanan seperti ASLR .Namun penggunaan khusus lain untuk
NOP
instruksi adalah ketika seseorang memodifikasi kode dari beberapa program. Misalnya, Anda dapat mengganti bagian dari lompatan bersyarat denganNOP
s dan dengan demikian menghindari kondisi tersebut. Ini adalah metode yang sering digunakan ketika " memecahkan " perlindungan salinan perangkat lunak. Paling sederhana itu hanya tentang menghapus konstruksi kode perakitan untukif(genuineCopy) ...
baris kode dan mengganti instruksi denganNOP
s dan .. Voa! Tidak ada pemeriksaan yang dilakukan dan salinan yang tidak asli berfungsi!Perhatikan bahwa pada dasarnya kedua contoh shellcode dan cracking melakukan hal yang sama; memodifikasi kode yang ada tanpa memperbarui alamat relatif operasi yang bergantung pada pengalamatan relatif.
sumber
Nop dapat digunakan dalam slot tunda ketika tidak ada instruksi lain yang dapat dipesan ulang untuk ditempatkan di sana.
Dalam MIPS, ini akan menjadi bug karena pada saat jr sedang membaca register v0 register v0 belum dimuat dengan nilai dari instruksi sebelumnya.
Cara untuk memperbaikinya adalah:
Ini mengisi slot dealy setelah kata load dan instruksi register lompat dengan nop sehingga instruksi kata load selesai sebelum perintah register register dijalankan.
Bacaan lebih lanjut - sedikit tentang pengisian slot keterlambatan SPARC . Dari dokumen itu:
Perhatikan opsi ketiga dalam apa yang dimasukkan ke dalam slot tunda. Bug yang Anda lihat kemungkinan seseorang mengisi salah satu hal yang tidak boleh dimasukkan ke dalam slot penundaan. Menempatkan nop di lokasi itu akan memperbaiki bug.
Catatan: setelah membaca kembali pertanyaan, ini untuk x86, yang tidak memiliki slot tunda (percabangan malah hanya menghentikan pipa). Sehingga tidak akan menjadi penyebab / solusi untuk bug tersebut. Pada sistem RISC, itu bisa menjadi jawabannya.
sumber
setidaknya satu alasan untuk menggunakan NOP adalah perataan. Prosesor x86 membaca data dari memori utama dalam blok yang cukup besar, dan mulai dari blok untuk membaca selalu selaras, jadi jika seseorang memiliki blok kode, yang akan banyak dibaca, blok ini harus disejajarkan. Ini akan menghasilkan sedikit percepatan.
sumber
0x1002
, karena masih ada 14 byte instruksi di blok 16B yang berisi alamat target, tetapi tidak baik untuk dilompati0x099D
.Satu tujuan untuk NOP (dalam perakitan umum, tidak hanya x86) itu untuk memperkenalkan penundaan waktu. Misalnya Anda ingin memprogram mikrokontroler yang harus menghasilkan beberapa LED dengan penundaan 1 detik. Penundaan ini dapat diimplementasikan dengan NOP (dan cabang). Tentu saja Anda dapat menggunakan beberapa ADD atau sesuatu yang lain, tetapi itu akan membuat kode lebih terbaca; atau mungkin Anda membutuhkan semua register.
sumber
loop
instruksi untuk menunda loop , tidak NOP.Secara umum pada 80x86, instruksi NOP tidak diperlukan untuk kebenaran program, meskipun kadang-kadang pada beberapa mesin, NOP yang ditempatkan secara strategis dapat menyebabkan kode berjalan lebih cepat. Pada 8086, misalnya, kode akan diambil dalam potongan dua-byte, dan prosesor memiliki buffer "prefetch" internal yang dapat menampung tiga potongan tersebut. Beberapa instruksi akan dieksekusi lebih cepat daripada yang bisa diambil, sementara instruksi lain akan memakan waktu untuk dieksekusi. Selama instruksi lambat, prosesor akan mencoba untuk mengisi buffer prefetch, sehingga jika beberapa instruksi berikutnya cepat mereka dapat dieksekusi dengan cepat. Jika instruksi mengikuti instruksi lambat dimulai pada batas kata genap, instruksi enam byte berikutnya akan di-prefetch; jika dimulai pada batas byte ganjil, hanya lima byte yang akan diambil sebelumnya.
Masalah penyelarasan memori semacam itu dapat memengaruhi kecepatan program, tetapi umumnya tidak memengaruhi kebenaran. Di sisi lain, ada beberapa masalah terkait prefetch pada prosesor lama di mana NOP dapat memengaruhi kebenaran. Jika suatu instruksi mengubah byte kode yang sudah lebih dulu diambil, 8086 (dan saya pikir 80286 dan 80386) akan menjalankan instruksi yang sudah ditentukan meskipun tidak lagi cocok dengan apa yang ada dalam memori. Menambahkan satu atau dua NOP di antara instruksi yang mengubah memori dan byte kode yang diubah dapat mencegah byte kode tidak diambil hingga setelah ditulis. Perhatikan, omong-omong, banyak skema perlindungan salinan mengeksploitasi perilaku semacam ini; Perhatikan juga, bahwa perilaku ini tidak dijamin. Variasi prosesor yang berbeda dapat menangani pengambilan awal yang berbeda, beberapa mungkin membatalkan byte prefetched jika memori dari mana mereka dibaca dimodifikasi, dan interupsi umumnya akan membatalkan buffer prefetch; kode akan diambil ulang ketika interupsi kembali.
sumber
Ada kasus spesifik x86 yang masih belum dijelaskan dalam jawaban lain: penanganan interupsi. Untuk beberapa gaya, mungkin ada bagian kode ketika interupsi dinonaktifkan karena kode utama berfungsi dengan beberapa data yang dibagi dengan penangan interupsi, tetapi masuk akal untuk memungkinkan interupsi antara bagian tersebut. Jika seseorang secara naif menulis
ini tidak akan memproses interupsi tertunda karena, mengutip Intel:
jadi ini harus ditulis ulang setidaknya sebagai:
Pada varian kedua, semua interupsi yang tertunda akan diproses hanya antara NOP dan CLI. (Tentu saja, bisa ada banyak varian alternatif, seperti menggandakan instruksi IMS. Tetapi NOP eksplisit lebih jelas, setidaknya untuk saya.)
sumber
NOP berarti Tidak Ada Operasi
Biasanya digunakan untuk memasukkan atau menghapus kode mesin atau untuk menunda eksekusi kode tertentu.
Juga digunakan oleh cracker dan debugger untuk mengatur breakpoints.
Jadi mungkin melakukan sesuatu seperti: XCHG BX, BX juga akan menghasilkan hal yang sama.
Bagi saya terdengar seperti ada beberapa operasi yang masih dalam proses dan karenanya menyebabkan kesalahan.
Jika Anda terbiasa dengan VB, saya bisa memberi Anda contoh:
Jika Anda membuat sistem login di vb, dan memuat 3 halaman bersama - facebook, youtube dan twitter di 3 tab berbeda.
Dan gunakan 1 tombol login untuk semua. Mungkin memberikan kesalahan jika koneksi internet Anda lambat. Yang berarti salah satu halaman belum dimuat. Jadi kami memasukkan Application.DoEvents untuk mengatasi ini. Cara yang sama dalam perakitan NOP dapat digunakan.
sumber