Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-3

435 views

Published on

BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-3

Published in: Engineering
  • Be the first to comment

BTRisk X86 Tersine Mühendislik Eğitim Sunumu - Bölüm-3

  1. 1. X86 TERSİNE MÜHENDİSLİK EĞİTİMİ BÖLÜM-3 İSTANBUL blog.btrisk.com @btrisk /btrisktv /btrisk
  2. 2. OYUN 6. AŞAMA
  3. 3. İÇ İÇE DÖNGÜLER • İç içe döngülerin analizini kolaylaştırmak için renklendirme ve gruplama yöntemlerinden faydalanabiliriz. • Gruplama ve Analiz Metodu Önerisi  Kalın mavi çizgiyi bul (döngü çizgisi)  Kalın çizginin ok başından geriye doğru takip et o Eğer bunu yaparken bir başka kalın mavi çizgiye rastlarsan önce iç döngüyü grupla  Döngüyü grupla  Tüm döngüler gruplandıktan sonra fonksiyonun başından itibaren analiz etmeye başla o Pseudo Code ile tespitleri not et o Tekrar grupla ve analize devam et ÖN BİLGİ
  4. 4. VERİ YAPILARI [STRUCTURES] • Assembly kodu içinde belli bir adresin offset'ine erişim gözlendiğinde bu bir veri yapısı [structure] kullanımına işaret olabilir. • Bu durumda okunabilirliği artırmak için IDA'nın veri yapıları imkanından faydalanabiliriz. • İç içe döngüler ile birlikte bu konuyla ilgili uygulama örneğini gerçekleştireceğiz. ÖN BİLGİ
  5. 5. VERİ YAPILARI [STRUCTURES] ÖN BİLGİ Veri yapılarının anlamlandırılmasıyla ilgili aşağıdaki kod parçasının Assembly'ye dönüşümü ve veri yapısını IDA'da modelledikten sonra bunu koda yansıtma örneğini görebilirsiniz.
  6. 6. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO #include <stdio.h> typedef struct veriYapisi { int rakam; int faktoriyel; struct veriYapisi *sonraki; } bilesen; bilesen bilesen1 = { 5, 0, NULL }; bilesen bilesen2 = { 7, 0, &bilesen1 }; bilesen bilesen3 = { 3, 0, &bilesen2 }; bilesen bilesen4 = { 4, 0, &bilesen3 }; bilesen bilesen5 = { 2, 0, &bilesen4 }; bilesen bilesen6 = { 8, 0, &bilesen5 }; int main() { int i,j; bilesen *cursor = &bilesen6; int rakam; for (i = 1; i<=6; i++) { cursor->faktoriyel = 1; for (j = 1; j <= cursor->rakam; j++) { cursor- >faktoriyel = cursor->faktoriyel * j; } cursor = cursor->sonraki; } cursor = &bilesen6; for (i = 1; i<=6; i++) { printf("%d faktoriyel = %dn", cursor- >rakam, cursor->faktoriyel); cursor = cursor->sonraki; } getchar(); return 0; } Örnek olarak inceleyeceğimiz kodumuzda içinde [2] INTEGER ve bir [STRUCT POINTER] barındıran bir veri yapısını kullanacağız. Bu veri yapılarından oluşmuş bir dizi veriyi [GLOBAL] değişken olarak tanımladık ve [OFFSET]'leri bir zincir liste oluşturacak biçimde ayarladık.
  7. 7. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Bir [CURSOR] kullanarak zincir liste [LINKED LIST] üzerinden gezerken [faktoriyel] alanlarına [rakam] verisinin faktoriyelini hesaplayarak yazıyoruz.
  8. 8. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Derlenmiş kodumuzu IDA ile açalım.
  9. 9. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Kodu sadeleştirmek için döngüleri gruplama yoluna gideceğiz. Bunun için daha önce de belirlediğimiz gibi önce iç içe döngülerde en iç döngülere yönlenmemiz lazım. Genel yaklaşım olarak fonksiyonun sonuna en yakın döngüden gruplamaya başlayabiliriz. Kodun sonundaki döngüyü oluşturan 3 bloğu [CTRL] tuşunu basılı tutarak seçelim.
  10. 10. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Seçtiğimiz blokları aynı renge boyamak için sağ klikleyerek [Set node color] seçeneğini seçelim.
  11. 11. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Seçtiğimiz blokları renklendirelim.
  12. 12. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Blokları gruplayıp tek bir kutu şeklinde ifade etmek için sağ klikleyip [Group nodes] seçeneğini seçelim.
  13. 13. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Grubumuza [DONGU_1] adını verebiliriz.
  14. 14. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO [DONGU_1] grubunun toplanmış hali soldaki gibi olacaktır.
  15. 15. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Kalan bölümdeki kodları incelediğimizde iç içe 2 döngü olduğunu görebiliriz. Bunlardan içte olanını oluşturan blokları seçip renklendirelim.
  16. 16. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Yeni grubumuza [DONGU_2] adını verebiliriz.
  17. 17. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Bu grubu da toplayarak kodu sadeleştirmeye devam edelim.
  18. 18. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Son olarak dıştaki döngüyü oluşturan blokları seçelim ve renklendirelim.
  19. 19. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Son grubumuzu da [DONGU_3] olarak adlandırıp toplayalım. Görüleceği gibi kod analiz için oldukça sadeleşti, şimdi sıra kod bloklarının oluşturduğu grupları adım adım açarak anlamlandırmakta.
  20. 20. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Demo uygulamamızı diğer örneklerde olduğu gibi detaylı olarak incelemeyeceğiz. Ancak [var_C] değişkenine atanan offset adresine çift tıklayarak bu alanda bulunan verilere göz atalım.
  21. 21. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO IDA için bu [.data] section'ında bulunan bu alanın özel bir anlamı yok, o nedenle BYTE BYTE görüntülüyor veriyi.
  22. 22. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Diyelimki detaylı bir analiz yaptık ve bu veri yapısının [3] adet DWORD'den oluştuğu kanaatine vardık. Bu durumda veri alanları üzerinde [d] tuşuna [3] defa basarak veriyi [DWORD – dd] formatına çevirebiliriz.
  23. 23. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Oluşturduğumuz ilk veri yapısı bloğunun son alanındaki offset bilgisinden faydalanarak zincir listeyi oluşturan diğer veri yapısı alanlarını da ortaya çıkarabiliriz.
  24. 24. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Detaylı kod analizi ve veri yapılarını inceleyerek ortaya çıkardığımız bilgileri koda yansıtabilmek ve kodun okunabilirliğini artırabilmek için önce IDA'ya bir veri yapısı tanımı yapmamız gerekir.
  25. 25. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO [INSERT] tuşuna basarak yeni oluşturacağımız veri yapısının adını [VERI_YAPISI] verelim.
  26. 26. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO [d] tuşuna basarak veri yapısını oluşturan alanları tanımlayalım ve [d] tuşuna 2 defa daha basarak bu veri alanlarının büyüklüklerini [DWORD]'e dönüştürelim.
  27. 27. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Kodu detaylı olarak incelediğimizi, [var_C] lokal değişkeninde bulunan veri yapısı adresinin önce [EAX] register'ına aktarıldığını ve bunun [+4] byte offset'inde de tespit ettiğimiz bir alanın var olduğunu bildiğimizi varsayalım.
  28. 28. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO [4] rakamını tıkladıktan sonra sağ klikleyerek context menü'yü açalım. Burada tanımladığımız veri yapısını seçerek kodun anlaşılabilirliğini artıralım.
  29. 29. ÖN BİLGİ İÇ İÇE DÖNGÜLER VE VERİ YAPILARI DEMO Kod yanda görüldüğü gibi bir veri yapısının içindeki bir bileşene referans verildiğini belirtecek hale gelerek anlaşılırlığı artacaktır.
  30. 30. 6. AŞAMA Ana fonksiyonda 4. aşama olarak tahmin ettiğimiz fonksiyonun içine girelim.
  31. 31. 6. AŞAMA Bu fonksiyon diğerlerine nazaran oldukça kompleks ve çok sayıda döngü içeriyor. Bu döngülerin bazıları da iç içe [nested] döngüler gibi görünüyor. NOT: IDA'nın döngüleri daha belirgin hale getirmek için KOYU MAVİ çizgiler kullandığından daha önce bahsetmiştik.
  32. 32. 6. AŞAMA Karmaşık bir kodla karşı karşıya olduğumuzda, ki iç içe döngüler içeren bir kod karmaşık olabilir, belli kod bölümlerini renklendirerek diğer bölümlerden ayrıştırmak isteyebiliriz. İç içe döngüleri daha anlaşılabilir hale getirmek için yapılabilecek bir diğer uygulama döngüleri oluşturan kod bölümlerini gruplamak ve bu grupları kapatmak olabilir
  33. 33. 6. AŞAMA İç içe döngüleri kapatmaya en içteki döngülerden başlamalıyız. Bir genelleme yapamayız ancak en içteki döngülerin sıklıkla bulundukları bölüm fonksiyondan çıkış noktasına yakın olan alanlardır. Öyleyse [RETN] instruction'ına yakın olan döngüye bir göz atabilir ve bu kod alanlarını renklendirebiliriz.
  34. 34. 6. AŞAMA En içteki döngüyü oluşturan kod bloklarını renklendirelim. Renklendirmeye [CMP] instruction'ını barındıran test bölümünden başlayıp sayacın artırıldığı kod bölümüne kadar devam edelim.
  35. 35. 6. AŞAMA Döngümüze test bloğundan önce gelen "initialization" bloğunu da ekleyelim. Bu kod karmaşasında bu bölümü bulmak zor olsa da kod akış kollarını takip ederek ve sayaç olarak kullanılan lokal değişken veya register'ı highlight ederek bu bloğu da bulabiliriz.
  36. 36. 6. AŞAMA Döngü kod bloklarını gruplamadan önce [CTRL] tuşuna basılı tutarak blokları seçelim. Blokların başlık bölümlerinin griye dönmesi seçme işleminin başarılı olduğunu gösterir.
  37. 37. 6. AŞAMA Seçilen tüm kod bloklarını gruplamadan önce [SAĞ KLİK]leyerek context menü'nün açılmasını sağlayalım ve [Group nodes] seçeneğini seçelim.
  38. 38. 6. AŞAMA Oluşturacağımız gruba bir isim vermemiz gerekiyor. Döngüler üzerinde çalıştığımız için bu grubu [DONGU_1] olarak isimlendirebiliriz.
  39. 39. 6. AŞAMA Bu kod bloğunu grupladığımızda kodun anlaşılabilirliğine katkıda bulunmuş olduk.
  40. 40. 6. AŞAMA İç içe döngüleri basitleştirmek için içten dışa doğru bir yaklaşımın doğru olacağını söylemiştik. Şimdi [DONGU_1]'in bir dışındaki döngüyü gruplamaya çalışalım. Renklendirmeyi kullanmak blokları ayrıştırmak için duyduğumuz ihtiyaca bağlı, ancak biz tüm döngüleri netleştirmek için boyamaya devam edebiliriz.
  41. 41. 6. AŞAMA Yine [CTRL] tuşunu basılı tutarken grubun parçası olan kutuları seçebiliriz ve sağ klik ile gelen Context Menü'den faydalanarak bu kutuları [node] gruplayabiliriz.
  42. 42. 6. AŞAMA Bu grubu da [DONGU_2] olarak isimlendirebiliriz.
  43. 43. 6. AŞAMA 2. döngüyü de gruplandırdıktan sonra bir üst döngünün daha olduğunu görebiliriz. Ancak sol taraftaki kod bloklarına baktığımızda bu bacakta da iç içe döngüler var gibi görünüyor. Önce iç döngüleri gruplama prensibimiz gereği üst seviyedeki döngüye geçmeden önce [DONGU_2] seviyesindeki diğer alanları da sadeleştirmemizde fayda var.
  44. 44. 6. AŞAMA Sol taraftaki döngünün bileşenlerini tespit etmeye çalışalım.
  45. 45. 6. AŞAMA Bu grubu da daha kolay ayrıştırmak için farklı bir renge boyayalım. Döngüleri gruplarken "initialization" kutularını da dahil ettiğimize dikkat edin.
  46. 46. 6. AŞAMA Bu grubumuza da [DONGU_3] adını verelim.
  47. 47. 6. AŞAMA Döngüleri grupladıkça kodun nasıl daha kolay anlaşılabilir hale geldiğine dikkat edin. Elbette hatalı grupladığımız veya yanlış yerden başladığımız durumlar olabilir, ancak bu grupları tekrar oluşturma imkanımız var. [DONGU_3]'ü grupladıktan sonra bu grubu da içine alan bir başka döngü olduğunu görebiliyoruz.
  48. 48. 6. AŞAMA [DONGU_3] 'ü de içine alan döngü bloğunu renklendirelim.
  49. 49. 6. AŞAMA Son grubumuza da [DONGU_4] adını verelim.
  50. 50. 6. AŞAMA Yeni bir iç döngüyü belirleyelim. Döngüleri sunum sayfasında incelemek daha zor, IDA ekranında daha rahat biçimde analizimizi gerçekleştirebiliriz.
  51. 51. 6. AŞAMA Yeni grubumuzu renklendirelim.
  52. 52. 6. AŞAMA Bu gruba da [DONGU_5] adını verelim.
  53. 53. 6. AŞAMA [DONGU_5]'i de içine alan bir üst döngüyü belirleyelim.
  54. 54. 6. AŞAMA Yeni grubumuzu renklendirelim.
  55. 55. 6. AŞAMA Bu gruba da [DONGU_6] adını verelim.
  56. 56. 6. AŞAMA Tüm döngüleri gruplandırdıktan sonra kod çok basit bir hale geldi. Şimdi yeri geldikçe grupları açarak nasıl bir algoritma barındırdıklarını incelemeye geçebiliriz.
  57. 57. 6. AŞAMA Fonksiyonumuz başlarında [var_C] değişkenimize bir offset adresi atanıyor.
  58. 58. 6. AŞAMA Bu offset'e geldiğimizde anlamlı bir bilgi göremiyoruz, en azından bize anlam ifade edebilecek ASCII bir veri barındırmıyor bu alan.
  59. 59. 6. AŞAMA Bu offset'in ne olduğunu bilmesek de [var_C] lokal değişkenine erişilen diğer noktalarda bu değişkenin bir adres bilgisi barındırdığını belirtmemizde fayda var.
  60. 60. 6. AŞAMA Bu değişkeni [BILINMEYEN_OFFSET] olarak isimlendirebiliriz.
  61. 61. 6. AŞAMA Bu bloktaki çağrılan fonksiyonlara göz attığımızda daha önceden analiz ettiğimiz bir fonksiyona rastlıyoruz. Fonksiyonun işlevini hatırlamak için tekrar [ALTI_INT_OKU] fonksiyonunu ziyaret edelim.
  62. 62. 6. AŞAMA Bu fonksiyon kendisine verilen bir string'in içinden okuduğu 6 INTEGER değeri 2. parametre olarak aldığı adres ve sonrasındaki alanlara yazıyordu.
  63. 63. 6. AŞAMA [ASAMA_6] fonksiyonumuz tek parametre alıyor görünüyor.
  64. 64. 6. AŞAMA Kodu anlamlandırmak amacıyla bu parametrenin adını [PRM_GIRDI] olarak düzenleyelim.
  65. 65. 6. AŞAMA Fonksiyon parametresi ile verilen değerin [ALTI_INT_OKU] fonksiyonu çağrılmadan hemen önce atandığı lokal değişkenin adını [L_PRM_GIRDI] olarak düzenleyebiliriz. Bu alan aynı zamanda [ALTI_INT_OKU] fonksiyonuna verilen 1. parametre.
  66. 66. 6. AŞAMA [ALTI_INT_OKU] fonksiyonu ile ilgili 2 parametre aldığı ve 2. parametrenin de okunan 6 INTEGER'ın yazılması için kullanılacağını biliyoruz. Bu nedenle stack'te bu adresin yazılacağı alana [L_PTR_INT_GECICI] adını verebiliriz.
  67. 67. 6. AŞAMA Stack'te [ALTI_INT_OKU] fonksiyonuna verilen adresin kendisi ise [var_38] alanının adresi. Bu alanı da [L_PTR_INT] olarak adlandırabiliriz. Bu adres okunan INTEGER değerlerinin arka arkaya yazılacağı alanın başlangıç adresi.
  68. 68. 6. AŞAMA [DONGU_6] grubunu açtığımızda döngünün sayacı olarak [var_5C] alanının kullanıldığını rahatlıkla görebiliyoruz.
  69. 69. 6. AŞAMA Bu alanı anlamlandırmak için adını [VAR_I] olarak değiştirelim. Burada sayacın [0] ile initialize edildiğini, [5] ve daha altı olduğu durumlarda (yani <6) döngüde kalmaya devam edildiğini görebiliyoruz.
  70. 70. 6. AŞAMA Grubun en altındaki blokta sayacımızın "1" artırıldığını [INC] görebiliyoruz.
  71. 71. 6. AŞAMA PSEUDO CODE (yani kod benzeri deyimlerle ifade etme) yaklaşımı ile analiz ettiğimiz algoritmanın netleştirilmesi yöntemini daha önce de kullanmıştık. Bu yönteme bu fonksiyon gibi çok karmaşık fonksiyonlarda daha da fazla ihtiyacımız var. O nedenle algoritmanın analiz ettiğimiz bölümleri için bu yöntemi kullanacağız. PSEUDO CODE int girdi[6] for(VAR_I=0;VAR_I<6;VAR_I++) { ... }
  72. 72. 6. AŞAMA Eklediğimiz yorum satırında da görüldüğü gibi okunan INTEGER'lar [0] veya daha küçük olamazlar.
  73. 73. 6. AŞAMA Hemen aşağıdaki blokta da okunan INTEGER değerlerinin [6]'dan büyük olamayacaklarını görebiliyorz.
  74. 74. 6. AŞAMA PSEUDO CODE int girdi[6] for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME()
  75. 75. 6. AŞAMA [DONGU_6] içinde [DONGU_5]'i barındırıyor. Dış döngüyü analiz ettikten sonra onun içindeki döngüye geçebiliriz.
  76. 76. 6. AŞAMA [DONGU_5]'in sayacı olarak [var_60] lokal değişkeninin kullanıldığını görüyoruz. [var_60] önce "[VAR_I]+1" ile initialize ediliyor. [6]'dan küçük olduğu müddetçe de iç döngüde kalmaya devam ediyor uygulama.
  77. 77. 6. AŞAMA Kodu daha okunur hale getirebilmek için [var_60] değişkeninin adını [VAR_J] olarak değiştirelim.
  78. 78. 6. AŞAMA Daha önce de bahsettiğimiz [VAR_J] değişkeninin bir üst döngünün sayacı olan [VAR_I] sayacına [1] eklenerek initialize edildiği kod bölümü.
  79. 79. 6. AŞAMA Yine daha önce bahsettiğimiz [VAR_J] değişkeninin [5]'in üzerine çıkması halinde döngüden çıktığı kod bölümü.
  80. 80. 6. AŞAMA Dıştaki döngü [6] INTEGER değerinin üzerinden dönerken, içteki döngü de incelenmekte olan INTEGER değerinden sonra gelen değerler üzerinden dönüyor. Eğer bu değerler birbirleri ile aynı ise oyun sonlanıyor. Dolayısıyla girilen [6] INTEGER'ın birbirlerinden farklı olmak zorunda olduğunu söyleyebiliriz.
  81. 81. 6. AŞAMA [VAR_J] sayacımızın artırıldığı (VAR_J++] kod bölümü.
  82. 82. 6. AŞAMA PSEUDO CODE int girdi[6] for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME()
  83. 83. 6. AŞAMA [DONGU_5] kod grubunu incelememiz bittiğine göre kod karmaşıklığını azaltmak üzere tekrar geriye toplayabiliriz.
  84. 84. 6. AŞAMA Aynı şekilde [DONGU_6] grubunu da geriye toplayabiliriz. Sıra [DONGU_4] grubunda.
  85. 85. 6. AŞAMA [DONGU_6] grubu toplandıktan sonra IDA yine eskisi gibi görünecek.
  86. 86. 6. AŞAMA Şimdi [DONGU_4]'ü [Ungroup] ederek incelemeye başlayabiliriz.
  87. 87. 6. AŞAMA Şimdi [DONGU_4]'ü [Ungroup] ederek incelemeye başlayabiliriz. Derleyicimiz sayaç olarak yine [VAR_I]'yı kullanmayı uygun görmüş. Bu döngüde de benzer biçimde [VAR_I] [0] ile initialize ediliyor , sayaç her döngüde [1] artırılıyor ve indeks [6]'dan küçük ise döngüde kalmaya devam ediliyor.
  88. 88. 6. AŞAMA PSEUDO CODE int girdi[6] for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++)
  89. 89. 6. AŞAMA Bu haliyle döngünün son bloğunu anlamlandıramıyoruz, [var_10] ve [var_58] lokal değişkenlerinin ne için kullanıldığına dair bir fikrimiz yok. O yüzden iç döngü olan [DONGU_3] döngüsünü incelemeye başlayabiliriz.
  90. 90. 6. AŞAMA [DONGU_3]'ün içinde [BILINMEYEN_OFFSET] adresi tekrar karşımıza çıktı. [var_10] lokal değişkenine atanan adres de bu offset adresi. Bu yüzden bu offset'teki verinin ne olduğunu anlamaya çalışırsak iyi olur.
  91. 91. 6. AŞAMA Tekrar hatırlamak için [BILINMEYEN_OFFSET] lokal değişkenine ilgili adresin ilk atandığı fonksiyonun başlarındaki kod bölümüne göz atabiliriz.
  92. 92. 6. AŞAMA [0x40304C] adresini tekrar ziyaret edelim. Daha önce de bu alanın byte'lara bölünmüş halde pek bir anlam ifade etmediğini değerlendirmiştik. Ancak aşağıya ve yukarıya doğru offset adreslerine benzer veriler olduğunu görebiliyoruz.
  93. 93. 6. AŞAMA [BILINMEYEN_OFFSET] lokal değişkeninin değeri [var_10] lokal değişkenine atandıktan sonra bu değişkene referans veren diğer kod bölümlerine göz atalım.
  94. 94. 6. AŞAMA Kodun alt bölümlerinde [var_10] lokal değişkeninde bulunan adresin [+8] offset'inde bulunan bir DWORD değerin [EAX] register'ına atandığını ve bunun da tekrar [var_10] lokal değişkenine atandığını görüyoruz. Bu durumda [BILINMEYEN_OFFSET] adresindeki verileri DWORD değerlerine dönüştürmeyi düşünebiliriz.
  95. 95. 6. AŞAMA Veri tipinin üzerine tıkladıktan sonra [d] tuşuna [2] defa basarak byte'ları DOUBLE WORD'lere [dd] dönüştürebiliriz. Art arda 3 DWORD verisi oluşturduğumuzda son DWORD'ün bir başka offset'in adresini içerdiğini görebiliyoruz.
  96. 96. 6. AŞAMA Şimdi aynı işlemi ortaya çıkardığımız offset olan [0x403040] adresine atlayarak gerçekleştirelim.
  97. 97. 6. AŞAMA Bu adresteki 3. DWORD değeri de [0x403034] değerini içeriyor. Bu da bir adrese benziyor. Aynı işlemi bu adreste de gerçekleştirelim.
  98. 98. 6. AŞAMA Aynı işlemi gerçekleştirdiğimiz 6. alanda son DWORD değeri [0] olarak karşımıza çıkıyor. Bu noktadan sonra tekrar aynı işlemi uygulayamıyoruz.
  99. 99. 6. AŞAMA Son incelemelerimizden sonra bir veri yapısıyla [STRUCTURE] karşı karşıya olduğumuzu söyleyebiliriz. IDA PRO, kodu daha anlaşılır hale getirebilmek için veri yapılarını ifade edebileceğimiz bir imkan sağlıyor. Bu imkanı kullanabilmek için [Structures] penceresine geçelim.
  100. 100. 6. AŞAMA Yeni bir veri yapısı eklemek için [INSERT] tuşuna basalım.
  101. 101. 6. AŞAMA Yeni bir veri yapımızın adını [VERI_YAPISI] olarak verelim.
  102. 102. 6. AŞAMA [VERI_YAPISI] isimli veri yapımız ekranda ortaya çıktı. Şimdi veri yapımızın içeriğini tanımlayalım.
  103. 103. 6. AŞAMA Açıkçası veri yapısının alanlarını henüz net olarak anlayamadık. Ancak her bir veri yapısının 3 adet [DWORD] içerdiğini düşünüyoruz. Bir [DATA veri yapısı bileşeni oluşturmak için [D] tuşuna basalım.
  104. 104. 6. AŞAMA [DATA] alanının büyüklüğünün [DWORD] olduğunu belirtmek için veri alanını [D] tuşu ile oluşturduktan sonra 2 defa [d] tuşuna basalım ve bu alanı [dd] olarak belirleyelim. Daha sonra ne amaçla kullanıldığını henüz bilmediğimiz bu alana üzerine tıkladıktan ve [N] tuşuna bastıktan sonra [ALAN_1] adını verelim.
  105. 105. 6. AŞAMA Yeni veri alanlarını eklemek için ALTTAKİ [VERI_YAPISI] adına tıkladıktan sonra [D] tuşuna basalım. Bu şekilde 3 [DWORD] alan tanımladıktan sonra son alana [NEXT_OFFSET] adını verelim. Çünkü bu alanın bir offset adresi barındırdığından eminiz ve son veri yapısının 3. DWORD alanında [0] yani [NULL] değerinin bulunması da karşımızda bir zincir liste [LINKED LIST] olma ihtimalini güçlendirdi.
  106. 106. 6. AŞAMA Bu offset'in veri yapısının bir alanı olduğunu belirtmek için [8] rakamına tıkladıktan sonra sağ klikleyerek context menü'sünü açalım ve [VERI_YAPISI.NEST_OFFSET] seçeneğini tıklayalım.
  107. 107. 6. AŞAMA Bu işlemden sonra kod daha okunaklı hale gelecek ve aktarılan verinin bir veri yapısının bir bileşeni olduğunu daha rahat anlayabileceğiz.
  108. 108. 6. AŞAMA Bu noktada ilk offset'in bir zincir listenin ilk zinciri olduğunu varsayabiliriz.
  109. 109. 6. AŞAMA Bu nedenle [BILINMEYEN_OFFSET] lokal değişken adını [LISTE_BASI] olarak değiştirelim.
  110. 110. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++)
  111. 111. 6. AŞAMA [LISTE_BASI] adresi [var_10] lokal değişkenine atandıktan sonra her bir döngüde zincir liste içindeki bir sonraki bileşenin [NEXT_OFFSET] adresinin [var_10] adresine atandığını görebiliyoruz.
  112. 112. 6. AŞAMA Yazılımlarda genellikle zincir listenin üzerinde çalışılan bileşeninin adresinin tutulduğu değişkene [CURSOR] adı verilir. Biz de [var_10] lokal değişkenini bu şekilde adlandırabiliriz.
  113. 113. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI
  114. 114. 6. AŞAMA Bu döngüde daha önceden [VAR_J] olarak adlandırdığımız sayacın kullanıldığını, önce [1] değeri ile initialize edildiğini, her döngüde girdi olarak verilen INTEGER ARRAY'inin [VAR_I] indeksindeki değerin [VAR_J] değeri ile karşılaştırıldığını , bu değer [VAR_J] değerini aşıncaya kadar [CURSOR]'ün bir sonraki bileşene işaret edecek şekilde ilerletildiğini ve tabi ki [VAR_J] değerinin artırıldığını görebiliyoruz.
  115. 115. 6. AŞAMA Burada [L_PTR_INT] lokal değişkeninin fonksiyonun başında okuduğumuz [6] INTEGER değerinin yazıldığı INTEGER ARRAY'inin başlangıç adresini işaret ettiğini tekrar hatırlayalım.
  116. 116. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM
  117. 117. 6. AŞAMA Veri yapılarına da bakarak bu karmaşık kod bölümünü anlamlandırmaya çalıştığımızda bizim gireceğimiz INTEGER dizisindeki her bir rakam için zincir listenin başından itibaren girilen rakam indeksine kadar ilerleneceği sonucuna varabiliriz. Peki zincirin bu bileşenine gelindiğinde ne olarak, bunu analizimizin devamında anlamayı ümit ediyoruz.
  118. 118. 6. AŞAMA Evet bu bölümler oldukça karmaşık, ancak odaklanarak dikkatli incelediğimizde yeni oluşturulan bir lokal değişken array'inin ilgili [VAR_I] indeksi için mevcut [CURSOR]'ümüzün değerinin yazıldığını anlayabiliriz.
  119. 119. 6. AŞAMA Bu nedenle [var_58] lokal değişkenine [OFFSET_ARRAY] adını verelim.
  120. 120. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR
  121. 121. 6. AŞAMA [DONGU_3]'ü analiz ettik ve bu sırada bir üst döngü olan [DONGU_4]'ün eksik kalan kod bölümünü de anlamlandırmış olduk. Bu nedenle [DONGU_3] kod grubunu tekrar toplayabiliriz.
  122. 122. 6. AŞAMA [DONGU_4]'ü incelememiz de bittiğine göre onu da kapatabiliriz. Şimdi sıra [DONGU_2]'de.
  123. 123. 6. AŞAMA [DONGU_2] grubunu açmak için bu grubu seçerek sağ klikleyip [Ungroup nodes] seçeneğini tıklayalım.
  124. 124. 6. AŞAMA [DONGU_2] grubunda [OFFSET_ARRAY]'in başlangıç adresindeki değer önce [LISTE_BASI] alanına yazılıyor, nihai olarak da [CURSOR] değişkenine yazılıyor. Yani [CURSOR] [OFFSET_ARRAY]'in ilk bileşenini taşıyacak biçimde yenileniyor. [LISTE_BASI] değişkeni ise artık [OFFSET_ARRAY]'in ilk bileşenini içerecek biçimde güncelleniyor.
  125. 125. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0]
  126. 126. 6. AŞAMA Bu döngüde [VAR_I] değişkeni sayaç olarak kullanılıyor ve [1] olarak initialize ediliyor. Döngüden çıkış koşulu da [VAR_I] değişkeninin [6]'dan küçük olması (çünkü 5'ten büyük olursa döngü devam ediyor)
  127. 127. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++)
  128. 128. 6. AŞAMA Biraz karmaşık olan son kod bloğunda önce [CURSOR] pointer'ı [EDX] register'ına yazılıyor. Daha sonra [OFFSET_ARRAY]'inin [1]'den başlatılmış olan [VAR_I] sayacı kadar içerideki bileşenin değeri [CURSOR]'ın işaret ettiği zincir liste bileşeninin [8] byte offset'ine yazılıyor. Bu offset'in ne olduğunu daha önce analiz etmiş ve [Structures] penceresinde tanımlamıştık. Bu tanımlamayı buraya da aktaralım.
  129. 129. 6. AŞAMA [8] rakamının üzerine tıklayıp sağ klikleyerek bu veriyi anlamlandırmak üzere [VERI_YAPISI.NEXT_OFFSET] seçeneğini klikleyelim.
  130. 130. 6. AŞAMA Bu anlamlandırmayı yaptıktan ve dikkatle inceledikten sonra bu bölümde gerçekleşen olayın [CURSOR] ile işaret edilen zincir liste bileşeninin [NEXT_OFFSET] alanının [OFFSET_ARRAY]'deki bir sonraki zincir bileşen adresi ile güncellenmesi olduğunu görebiliriz.
  131. 131. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I]
  132. 132. 6. AŞAMA Bu güncellemeden hemen sonra da [CURSOR] işaret ettiği zincir bileşeninin [NEXT_OFFSET] adresi ile güncelleniyor. Bir başka alternatif de [OFFSET_ARRAY]'den bu adresin alınması olabilirdi.
  133. 133. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I] CURSOR=CURSOR->NEXT_ITEM
  134. 134. 6. AŞAMA Bu döngüyü de incelememiz de bittiğine göre bu grubu da kapatabiliriz. Şimdi sıra [DONGU_1]'de.
  135. 135. 6. AŞAMA [DONGU_1] grubunu açmak için bu grubu seçelim ve sağ klikle açalım.
  136. 136. 6. AŞAMA [DONGU_1]'in başlarında sayaç'ın sıfırlanmasından önce [CURSOR]'ün işaret ettiği son zincir bileşeni üzerinde bir işlem daha yapıldığını görüyoruz.
  137. 137. 6. AŞAMA [8] offset'ini işaretlediğimizde benzer bir işlemin aşağı bölümde de yapıldığını daha rahat görebiliyoruz.
  138. 138. 6. AŞAMA Bu kod bölümlerini daha anlamlı hale getirmek için veri yapısına referans verme imkanımızı tekrar kullanıyoruz.
  139. 139. 6. AŞAMA [CURSOR]'ün işaret ettiği son zincir bileşeninin [NEXT_OFFSET] alanına [0], yani pek çok uygulama dilindeki ifadesiyle [NULL] atandığını görüyoruz. Bu zincir listelerdeki son bileşen için uygulanan tipik bir yöntem.
  140. 140. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I] CURSOR=CURSOR->NEXT_ITEM CURSOR->NEXT_ITEM=NULL
  141. 141. 6. AŞAMA Sonraki adımda [LISTE_BASI] değişkeni [CURSOR]'a atanıyor. Yeni liste başımız bizim gireceğimiz [6] rakamdan ilkinin işaret ettiği bileşendi ve biz yeni sıralamayı [OFFSET_ARRAY] aracılığı ile oluşturmuştuk.
  142. 142. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I] CURSOR=CURSOR->NEXT_ITEM CURSOR->NEXT_ITEM=NULL CURSOR=LISTE_BASI
  143. 143. 6. AŞAMA Bu döngüde sayaç olarak [VAR_I] değişkeni kullanılıyor. [0] ile initialize edilen [VAR_I] değeri [4]'ü geçtiğinde içinde bulunduğumuz [ASAMA_6] fonksiyonunun sonuna geliyoruz. Döngünün en alt bloğunda da [VAR_I] değişkeninin [1] artırıldığını görebiliyoruz.
  144. 144. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I] CURSOR=CURSOR->NEXT_ITEM CURSOR->NEXT_ITEM=NULL CURSOR=LISTE_BASI for(VAR_I=0;VAR_I<5;VAR_I++)
  145. 145. 6. AŞAMA Döngümüzün yaptığı asıl test bu bölümde gerçekleşiyor, çünkü eğer hata yapmış isek uygulama hata alarak sonlanıyor. Bu bölümde yapılan şey [CURSOR]'ın o anda işaret ettiği bileşenin ilk DWORD'ü ile bu bileşenin [NEXT_OFFSET] alanı ile referans verdiği sonraki bileşenin ilk DWORD'ünün karşılaştırılması işlemi. Eğer MEVCUT bileşenin [1.] DWORD'ünün değeri listedeki SONRAKİ bileşenin [1.] DWORD'ünden DAHA BÜYÜK ise [HATALI_DENEME] fonksiyonu çağrılıyor.
  146. 146. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I] CURSOR=CURSOR->NEXT_ITEM CURSOR->NEXT_ITEM=NULL CURSOR=LISTE_BASI for(VAR_I=0;VAR_I<5;VAR_I++) if(CURSOR > CURSOR->NEXT_ITEM) HATALI_DENEME()
  147. 147. 6. AŞAMA Döngünün son bloğunda zincir bileşenlerinin [+8] offset'ine bir başka referans daha var.
  148. 148. 6. AŞAMA Bu bölümü de anlamlandırmak için veri yapısı referansımızı kullanalım.
  149. 149. 6. AŞAMA PSEUDO CODE int girdi[6] struct { int ALAN_1 int ALAN_2 int next_item } item; item LISTE_BASI = 0X40304C for(VAR_I=0;VAR_I<6;VAR_I++) if (girdi[VAR_I] <= 0 || girdi[VAR_I] > 6) HATALI_DENEME() for(VAR_J=VAR_I+1; VAR_J<6;VAR_J++) if(girdi[VAR_I]==girdi[VAR_J]) HATALI_DENEME() for(VAR_I=0;VAR_I<6;VAR_I++) item CURSOR = LISTE_BASI for(VAR_J=1; VAR_J<girdi[VAR_I];VAR_J++) CURSOR=CURSOR->NEXT_ITEM OFFSET_ARRAY[VAR_I]=CURSOR LISTE_BASI=OFFSET_ARRAY[0] CURSOR=OFFSET_ARRAY[0] for(VAR_I=1;VAR_I<6;VAR_I++) CURSOR->NEXT_ITEM=OFFSET_ARRAY[VAR_I] CURSOR=CURSOR->NEXT_ITEM CURSOR->NEXT_ITEM=NULL CURSOR=LISTE_BASI for(VAR_I=0;VAR_I<5;VAR_I++) if(CURSOR > CURSOR->NEXT_ITEM) HATALI_DENEME() CURSOR=CURSOR->NEXT_ITEM
  150. 150. 6. AŞAMA Zincir listemizi daha önceden analiz etmiş ve offset'leri çözerek tüm bileşenleri belirlemiştik. [DONGU_1]'de bileşenlerin ilk alanlarındaki değerler birbirleriyle karşılaştırılıyordu.
  151. 151. 6. AŞAMA İlk alanın değerlerini HEX gösterimden ONDALIK gösterime geçirmek için [ALAN_1]'in üzerine tıkladıktan sonra sağ klikleyerek [Field type][Number][Decimal] seçeneklerini seçebiliriz. Daha sonra bu veri yapısını tespit ettiğimiz zincir liste ile ilişkilendireceğiz.
  152. 152. 6. AŞAMA [ALAN_1]'in veri tipini [DECIMAL] olarak belirledikten sonra [VERI_YAPISI]'nın görüntüsü yukarıdaki gibi olacaktır.
  153. 153. 6. AŞAMA [VERI_YAPISI]'nın son DWORD'ünün de bir başka [VERI_YAPISI]'na işaret eden bir OFFSET olduğunu biliyoruz. Bu bilgiyi de veri yapısı üzerine aktarmak için son alanı tıklayıp sağ klikledikten sonra [Field type][Offset][Offset (struct) ...] seçeneğini seçiyoruz.
  154. 154. 6. AŞAMA Karşımıza çıkan menüde tanımlanmış olan tek veri yapısı olan [VERI_YAPISI] çıkacaktır. Bu veri yapısını seçerek offset'in işaret ettiği [Structure] tipini de IDA'ya öğretmiş olacağız.
  155. 155. 6. AŞAMA [VERI_YAPISI]'nın son görüntüsü yukarıdaki gibi olacaktır.
  156. 156. ALT+Q 6. AŞAMA Veri alanlarını tanımladığımız veri yapıları ile ilişkilendirmek için ilgili veri alanının üzerinde tıkladıktan sonra [ALT+Q] tuşlarına basabiliriz. Daha sonra karşımıza çıkan [Structure] listesinden ilgili olanı seçerek bu kalıbı veri alanı ile ilişkilendirmiş oluruz.
  157. 157. 6. AŞAMA Zincir listemizi oluşturan bileşenleri ilgili [Structure] ile ilişkilendirdikten sonra veri tipleri de [Structure] üzerinde tanımladığımız gibi görüntülenmiş olacaktır. İlk alanları [DECIMAL] olarak tanımladığımız için şimdi ONDALIK olarak görülebileceklerdir.
  158. 158. 6. AŞAMA Veri yapılarını ilk alanlarındaki değerlerine göre sıralarsak [ASAMA_6] için girmemiz gereken dizi [2 4 1 6 3 5] olacaktır.
  159. 159. 6. AŞAMA
  160. 160. NE ÖĞRENDİK Karmaşık kod bloklarını analiz etme hakkında • Kod bloklarını renklendirme • Kod bloklarını gruplama • İç içe döngüleri en içten başlayarak inceleme yöntemi Veri yapılarını anlamlandırma ve kod okunabilirliğini artırma hakkında • IDA'da structure tanımı yapma • Tespit edebildiğimiz veri yapısı bileşenlerinin formatlarını structure içinde tanımlama • Structure bilgisini kod içine verilen referanslara aktarma • Structure bilgisini veri blokları üzerine aktarma

×