Exploitation Basics: x86 Assembly

Assembly programlama dili, C++, C# ve Java gibi programlama dilleri ile makine dili arasında bulunan düşük seviyeli bir programlama dilidir. Bu programlama dilinde işlemci türü ve mimarisine göre kod ve komutlar değişmektedir. Assembly dili ile donanım seviyesine erişimin çok hızlı olması nedeniyle yüksek seviyeli dillere göre çok daha hızlı çalışan uygulamalar gerçekleştirilebilmektedir. Birçok uygulamada performans ve hız gerektiren kısımlar çoğu zaman assembly ile geliştirilmiştir. Aygıt sürücüleri, video oyunları gibi alanlar bu dilin sık kullanıldığı alanlardır. Assembly dili işlemci ve işletim sistemine özel bir dil olması yazılan kodun farklı sistemlerde çalışmasına engel olabilmektedir.

Temel x86 Komutları

x86 komut setini bir blog yazısı ile anlatmak esasen pek mümkün değil. Ancak bu yazıdaki amaç debug ve tersine mühendislik işlemleri ile uğraşmak isteyenlerin inceledikleri assembly kod öbeklerinin büyük bir bölümünü anlayabilecek seviyeye gelmelerini sağlamakdır.  Daha önce bu konu ile ilgili yapılan bir incelemede Daniel Bilar (2006), 20 farklı uygulamada gerçekleştirmiş olduğu çalışmada uygulama içinde bulunan assembly komutlarının %90 lık kısmını 14 assembly komutunun doldurduğunu belirtmiş. Bu yazıda da bu komutlar üzerinden anlatımlar gerçekleştirilecektir.

Kaynak: http://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Bilar.pdf

NOP

Hiç bir işlem gerçekleştirmeyen bir makina kodudur. Programlama veya derlemede genellikle bir komutun kullanımında boşta kalan alanların doldurulmasında kullanılır. Exploit geliştirme çalışmalarında ise yazılan exploit kodunun güvenilir ve sağlam olması için bu komut  kullanılmaktadır.

PUSH/POP

PUSH/POP komutları stack alanına veri eklemek yada çıkarmak için kulanılan komutlardır. PUSH Komutu 4 byte uzunluğundaki veriyi stack’e ekler ve ESP değerini 4 azaltır. Stack büyümesini, düşük adres alanına doğru gerçekleştirdiği için çıkartma işlemi yapılmaktadır.

Aynı şekilde POP işlemi sırasında da stack alanının en üst noktasından (top of the stack) 4 byte uzunluğunda bir veri alınır ve ESP değeri 4 artırılıtr.

CALL/RET

CALL assembly komutu ile program akışı uygulamanın kod alanı içinde başka bir yerde bulunan bir fonksiyon alanına gider ve fonsiyonun işlemi tamamlandıktan sonra ana program akışı içinde kaldığı yerden devam eder. CALL ile çağırılan fonksiyonun işlemleri tamamlandıktan sonra ana kod akışında kaldığı yerden devam etmesi için çağırılan fonksiyonda RET assembly komutunun çalıştırılması gerekmektedir.
CALL Komutu çalıştırıldığında aşağıdaki işlemler gerçekleştirilmektedir.

  • Bir sonraki komut adresi stack üzerine eklenir. (Bu değer fonksiyon RET komutu ile ana fonksiyona geldiğinde kaldığı yerden devam edeceği adres bilgisidir.)
  • EIP değerine CALL komutunda gösterilen adres değeri atanır.

MOV

MOV komutu ile iki yazmaç arasında, yazmaçlarla hazfıza arasında veri taşımak veya bahsedilen bu alanlara bir değer atamak için kullanılan bir komuttur. Bu komut, memory adresleri arasında kullanılmaz. mov eax, ebxmov eax, [ebx]

LEA

LEA Komutu(Load Effective Address) etkin adresi yükle anlamındadır. MOV komutundan farklı olarak MOV komutu ile register’a bir hafızadan veya register’dan yüklersiniz. Oysa LEA komutu ile register’ao yerdeki değerideğil, oranın adresini yüklersiniz. Bu sekilde iki yada üç komut ile yapılacak bir işlemi tek bir komut ile yapabilirsiniz. Böylelikle, LEA komutu, herhangi bir register’a bir bellek adresini yükleme amacı ile kullanılmış olur.
lea register, adres lea register, [adres]

ADD/SUB

ADD ve SUB komutları isimlerinden de anlaşılacağı üzere toplama çıkartma işlemlerinde kullanılan komutlardır. İşlem sonucunda elde edilen değeri ilk operand’a yazar. add register, registeradd memory, memory…sub register, registersub memory, memory…

CMP

iki farklı değerin karşılaştırılmasında kullanılan bir komuttur. Çoğunlukla şartlı işlem gerçekleştirme öncesinde kullanılırlar. Bu komut ile iki operand karşılaştırma amacı ile birbirinden çıkartılır. Bu işlem gerçekleştirilirken kullanılan operand’ların değeri değiştirmez. Ancak işlemcide bulunan bayraklar üzerinde etkisi bulunmaktadır.CMP Operand1, Operand2Karşılaştırma işleminde bayrak durumları aşağıdaki gibi olmaktadır.

AND/OR/XOR/NOT

Bu komutlar mantıksal işlemlerin gerçekleştirilmesinde kullanılan komutlardır. Bu komutların kullanımı aşağıdaki gösterimde daha iyi anlaşılacaktır. AND Operand1, Operand2

Operand11010
Operand20110
İşlem Sonucunda Operand10010

OR Operand1, Operand2

Operand11010
Operand20110
İşlem Sonucunda Operand11110

XOR Operand1, Operand2

Operand11010
Operand20110
İşlem Sonucunda Operand11100

NOT Operand1

Operand11010
İşlem Sonucunda Operand10101

TEST

Test komutu, operand’lar üzerinde herhangi bir işlem yapmadan AND işlemi gerçekleştiren komuttur. İşlem sonucundan etkilenenlersadece bayraklardır. Etkilenen bayraklar CF OF PF SF ZF bayraklarıdır. İşlemde kullanılacak verilerin büyüklüklerinebağlı olarak TEST işleminde kullanılan opcode değerleri de farklılık gösterebilirler.test operand1, operand2Örneğin yukarıdaki işlem sonucunda eğer sonuç sıfır ise ZF değeri 1 olarak işaretlenir. Eğer operand2 değeri negatif ise SF değeri 1 olarak işaretlenir.

JMP

JMP komutu ile koşulsuz olarak, program akışı istenilen bir noktaya dönüş değeri olmaksızın yönlendirilmiş olur. Bu komutta kullanılan operand atlama yapılacak adres değerini göstermektedir.JMP operand1

JCC

JCC komutları ile belli bir şarta bağlı olarak program kodu içinde şartlı akış gerçekleştirilir. Bu komut ile EFLAG yazmacı içindeki bayrak değerlerinin durumuna göre atlama (jmp) işlemi gerçekleştirilir. Bu komutlar ile ilgili tablo aşağıda görülmektedir.

InstructionDescriptionsigned-nessFlagsshort jump codesnear jump opcodes
JOJump if overflow OF = 1700F 80
JNOJump if not overflow OF = 0710F 81
JSJump if sign SF = 1780F 88
JNSJump if not sign SF = 0790F 89
JE JZJump if equal Jump if zero ZF = 1740F 84
JNE JNZJump if not equal Jump if not zero ZF = 0750F 85
JB JNAE JCJump if below Jump if not above or equal Jump if carryunsignedCF = 1720F 82
JNB JAE JNCJump if not below Jump if above or equal Jump if not carryunsignedCF = 0730F 83
JBE JNAJump if below or equal Jump if not aboveunsignedCF = 1 or ZF = 1760F 86
JA JNBEJump if above Jump if not below or equalunsignedCF = 0 and ZF = 0770F 87
JL JNGEJump if less Jump if not greater or equalsignedSF <> OF7C0F 8C
JGE JNLJump if greater or equal Jump if not lesssignedSF = OF7D0F 8D
JLE JNGJump if less or equal Jump if not greatersignedZF = 1 or SF <> OF7E0F 8E
JG JNLEJump if greater Jump if not less or equalsignedZF = 0 and SF = OF7F0F 8F
JP JPEJump if parity Jump if parity even PF = 17A0F 8A
JNP JPOJump if not parity Jump if parity odd PF = 07B0F 8B
JCXZ JECXZJump if %CX register is 0 Jump if %ECX register is 0 %CX = 0 %ECX = 0E3

Komut Gösterimi

Assembly de bilinen farklı iki kod gösterimi bulunmaktadır. Unix türevi sistemler, AT&T komut gösterimini kullanırken, Windows sistemleri ise INTEL komut gösterimini kullanmaktadırlar. Gerekli yapılandırmalar yapıldığı taktirde Unix uygulamalarında da INTEL kod gösterimi ile çalışılabilmektedir.

Örnek INTEL kod gösterimi
4004ac: 55                     push   rbp
4004ad: 48 89 e5              mov    rbp,rsp
4004b0: 89 7d fc              mov    DWORD PTR [rbp-0x4],edi
4004b3: 48 89 75 f0           mov    QWORD PTR [rbp-0x10],rsi
4004b7: b8 00 00 00 00        mov    eax,0x0
4004bc: 5d                     pop    rbp
4004bd: c3                     ret    

Örnek AT&T kod gösterimi
4004ac: 55                     push   %rbp
4004ad: 48 89 e5              mov    %rsp,%rbp
4004b0: 89 7d fc              mov    %edi,-0x4(%rbp)
4004b3: 48 89 75 f0           mov    %rsi,-0x10(%rbp)
4004b7: b8 00 00 00 00        mov    $0x0,%eax
4004bc: 5d                     pop    %rbp
4004bd: c3                     retq

Kaynaklar:

https://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Bilar.pdf
http://x86.renejeschke.de/
http://www.unixwiz.net/techtips/x86-jumps.html

Please follow and like us:

Leave a Reply

Your email address will not be published. Required fields are marked *