SİTE 
            İÇİ ARAMA | 
       
      
        | 
            
         | 
       
     
                    
                                     	
        
        
        
        
                    
    
                    
    
                    
    
      
         Anket | 
       
      
        
	        
              
                .NET Yeniliklerini Takip Etmek Sizin İçin Nekadar Önemli ?
                      
                        
                      
                
                    
                  
            
                    Diğer anketler ve sonuçları için  tıklayın.
                    | 
               
               
         | 
       
     
                    
    
                    
                     
                 | 
                
                    
    
        
            | 
                
             | 
         
        
            | 
                 
             | 
         
        
            | 
                Yeni bir decompile aracı : FOX
             | 
         
        
            
                
                    
                        | 
                            
                            C#nedir?com üyelerinden ve forum moderatörlerinden Ozcan Değirmenci tarafından geliştirilen ve Amerikan firması Xenocode'da satılan Fox Kod Analiz aracının final sürümü çıktı. C#nedir?com forumlarında tartışılmaya başlanan bu fikir artık dünya çapında en çok kullanılan decompiler aracı olma yolunda emin adımlarla ilerliyor. Özcan Değirmenci Fox'un serüvenini sizler için kaleme aldı...
                         | 
                     
                 
                
                
Özcan Değirmenci, 
  C#nedir?com üyelerinin özellikle de C#nedir?com forumlarını takip eden üyelerimizin 
  yakından tanıdığı isim. Bundan yaklaşık 1.5 yıl önce forumlarda derlenmiş .NET 
  uygulamalarının ILden C# yada başka bir .NET diline rahatlıkla dönüştürülebileceği 
  üzerine tartışmalar geçiyordu. Bu tartışmalar kimini memnun derken kimini mutsuz 
  ediyordu. Her fırsatta .NET platformunun IL kodunu gizleme gibi bir amacı olmadığını 
  vurgulayan Özcan Değirmenci decompile işleminin rahatlıkla yapılabileceğini 
  düşünüyordu. Forumda decompile işlemleri üzerine derin tartışmalar yaşanırken 
  Özcan Değirmenci daha sonra dünyadaki sayılı decompilerların arasına girecek 
  olan aracını kodlamaya başlamıştı bile. Aradan bir iki ay geçti ve fikri C#nedir?com 
  forumlarında çıkan ve Fox adını koyduğu decompiler aracının ilk sürümünü yine 
  C#nedir?com forumlarında duyurdu. Bir çok üyemiz bu projede testçi olarak yer 
  aldı ve Foxun gelişimine katkıda bulundu. Nihayet Foxun çalışabilen versiyonu 
  çıktığında bir çok kişi tarafından denendi ve beğenildi. Beğenenlerden biriside 
  merkezi Seattleda (USA) bulunan kod koruma ve decompile konusunda uzman bir 
  firma olan Xenocode oldu. 
  Böylece Foxun bu gelişimi C#nedir?com forumlarından çıkarak Xenocode firmasının 
  ticari bir uygulamasına dönüştü. Evet, Fox tüm hakları ile Özcan Değirmenci 
  tarafından Xenocode firmasına satıldı. 
   
  Fox Decompiler aracının 14 günlük deneme sürümünü http://www.xenocode.com/Products/Fox/ 
  adresinden indirebilirsiniz. 
   
  Fox aracının C#nedir?comdaki gelişim evresini merak ediyorsanız aşağıdaki bağlantılarda 
  geçen bazı tartışmaları okuyabilirsiniz. 
   
  Decompiler 
  mevzusunun tartışıldığı mesajları 
   
  Fox 
  ile ilgili tartışmalar
  
Yine 
  Fox hakkında mesajlar  
   
  ....  
   
  Ayrıca http://www.csharpnedir.com/forum2/search_form.asp 
  adresindeki arama kutucuğuna "fox" yada "decompiler" kelimelerini 
  yazıp aratırsanız daha fazla içeriğe erişebilirsiniz. 
   
  
   
      | 
    Şimdi 
      binlerce kişi tarafından trial versiyonun indirildiğini belirten Özcan Değirmenci 
      gelen tepkilerden oldukça memnun olduğunu belirtiyor. Değirmenci, son versiyonu 
      geçtiğimiz günlerde yayınlanan Foxun serüvenini ve gelişim aşamalarını 
      birazda teknik detaylarını C#nedir?com için kaleme aldı. Bundan sonrasını 
      kendisinden dinleyelim : 
       
      "Bundan 1,5 sene öncesinde 
      www.csharpnedir.com forumlarında 
      ilk defa tartıştığımız ve duyurusunu yaptığımız Fox o tarihte yazılmaya 
      başlandı. İlk 5 ay kadar çok vaktim olmadığı için bakamadım. Ama daha sonraki 
      4 ay süresinde bu konuya daha fazla vakit ayırıp Fox’un ilk betasını çıkarttım. 
      Fox o zamanlar cok daha işin başında olduğu için decompile ederken bir çok 
      hatalar alıyorduk. Çünkü decompile mantığında metadata ları okumak işin 
      en basit kısmıdır. MetaDatalar okunduktan sonra o metadatal arı ayıklayıp(parse) 
      anlamlı tablolarda ortaya çıkardıktan sonra bir methodun gövdesini dosya 
      içinden okuyup daha sonra bu gövdeyi anlaşılır kod haline çevirmek en zor 
      kısmıdır." 
       
      Özcan Değirmenci | 
   
 
 
Foxun Serüveni  
 
Bu makalede sizlere 
kısaca Fox’un gelişme sürecini, bir decompiler nasıl yazılırı ve decompilerlardan 
nasıl korunuluru anlatmaya çalışacağım. Konuyu elimden geldiği kadar kısaca anlatmaya 
çalıştım ancak yinede uzun bir makale olduğu için hepinizden özür dilerim… Microsoft’un en 
  yeni ve en gözde yazılım geliştirme platformu olan .NET ilk çıktığında benimde 
  içine dahil olduğum bir çok insan bu platformdaki açıklara dikkat bile etmeden 
  platformun onlara sağladığı geniş imkanlara ve program yazmadaki rahatlıklarına 
  kapılıp bu platforma geciş yaptı. Aslında JAVA programcıları için çok fazla 
  ses getirdiği söylenmesede özellikle Visual Basic yada ASP kullanan yazılım 
  geliştiricileri açısından .NET gerçekten büyük bir devrimdi. Aslında coğu programcı 
  sadece sözlere kanıp .NET ile uğraşmaya başladı bile diyebiliriz. Ortada herşeyin 
  çok daha kolay yapıldığına dair sözler dolaşıyordu ama yinede kimse olayı çokta 
  bilmiyordu. Ancak zaman geçtikçe görüldüki Microsoft cidden doğruyu söylemişti. 
  Platform gerçekten çok esnek davranıyordu. Ve yine beklenmedik şekilde çok az 
  bug ile ve en azından Microsoft platformlarının hepsi ile son derece uyumlu 
  çalışıyordu. Bütün bunların yanında birde dünyanın belkide o zaman kadarki en 
  sağlam editörüde .NET geliştiricilerinden yana olunca ortaya tam bir şaheser 
  çıktı diye düşünüyorduk. Ne ilk çalışmadaki bekleme nede editörün aşırı hafıza 
  kullanımı bizim açımızdan bir sorun değildi. O zamanlar bende .NET’i ilk duyduğumda 
  merak etmiş ve direk onla ilgilenmeye başlamıştım. Ancak daha sonra zaman geçtikçe 
  bu platformdaki açıklar üzerine düşünmeye başladım. Aslında kendi kendime düşünmekten 
  ziyade bir arkadaşın tavsiyesi uzerine indirdiğim ‘Anakrino’ 
  programı ile şoke olmuştum. Programla kendi yazdığım exe nin kodlarını hemen 
  hemen ayni şekilde görüntüleyebiliyordum. Decompiler sözcüğü ile ilk defa o 
  zamanlar haşır neşir oldum. Bu sözcük beni yeni program yazmaya başlamış biri 
  olarak çok etkilemişti. Açıkcası karizmatik geldi bile denilebilir. 
   
  O günden sonra bu konu uzerine biraz daha ilgilenir oldum. Daha sonrasında yine 
  bir arkadaşım sayesinde Reflector’la tanıştım. ‘Reflector’ 
  ‘Anakrino’ya göre daha iyi decompile eden bir araçtı. Hatta daha sonra Lutz 
  Roeder’den öğrendiğime göre Anakarino ile Reflector aslında aynı 
  amaçla beraber başlamışlar ancak daha sonra aralarındaki anlaşmazlıktan dolayı 
  Saurik ayrılmış ve kendi bir tool çıkarmış ve Reflector ayrı bir tool olarak 
  çıkmış. Bu her iki decompilerın yapabildikleri gerçekten çok ilginç gelmişti 
  bana.  
   
  Aradan geçen zamanlar esnasında decompilerlar bir çok insan tarafından hala 
  yeni yeni duyulmaya başlıyordu ki bu nedenle www.csharpnedir.com’da 
  bu konuda bir çok soru çıkmaya başlamıştı. Bu sorularda daha çok bunların ne 
  kadar rahatsız edici olduğu üzerine tartışıyorduk. Ama benim için hayatta en 
  sevmediğim şey belkide başkalarının yaptıkları üzerine konuşmak olduğu için 
  o zamanlar bende bir tane decompiler aracı yazmaya karar verdim. İşte yaklaşık 
  bundan 1,5 sene öncesinde www.csharpnedir.com forumlarında ilk defa tartıştığımız 
  ve duyurusunu yaptığımız Fox o tarihte yazılmaya başlandı. İlk 5 ay kadar çok 
  vaktim olmadığı için bakamadım. Ama daha sonraki 4 ay süresinde bu konuya daha 
  fazla vakit ayırıp Fox’un ilk betasını çıkarttım. Fox o zamanlar cok daha işin 
  başında olduğu için decompile ederken bir çok hatalar alıyorduk. Çünkü decompile 
  mantığında metadata ları okumak işin en basit kısmıdır. MetaDatalar okunduktan 
  sonra o meta dataları parse edip anlamlı tablolarda ortaya çıktıktan sonra bir 
  methodun gövdesini dosya içinden okuyup daha sonra bu gövdeyi anlaşılır kod 
  haline çevirmek en zor kısmıdır. Bu esnada gövde okunup IL ifadeleri ortaya 
  çıktıktan sonra bir compilerin bu kodları nasıl oluşturabileceğini düşünüp 
  buna göre ters işlem yapıp ortaya anlaşılır kod çıkartmak gerekir. İşte işin 
  en zor kısmı olan bu kısım surekli gelişmesi gereken bir kısımdır ki yeni çıkmış 
  bir decompilerda bu tip hatalardan kaynaklı hatalar oluşması çok normaldir. 
  Ancak isimlerini buraya yazamayacağım kadar çok arkadaş o zamanlar www.cshaprnedir.com’daki 
  yazılarımı görmezden gelmeyip bana testler konusunda destek çıktılar. Bu esnada 
  Fox biraz daha gelişti ve son beta 1.0.8 versiyonu ortaya çıktı. 
   
  Bu noktada benim için aslında olayın çok daha ileri gitmesi için bir sebep yok 
  görünüyordu. Çünkü ben istediğim şeyi gösterip bunu bir Türk’ün de isterse yapabileceğini 
  ispatlamıştım. Hatta bir ara Fox’un Open Source olup olmaması konusunda yaptığım 
  anket nedeni ile Reflector’un yazarı ‘Lutz Roeder’ den bile tepki alıcak kadar 
  ismi duyulmuştu o zamanlar. Ayrıca istediğimizde neler yapabileceğimizin de 
  bir göstergesi olmuştu. Programcılık yaparken tek ihtiyacımız olan şey cesaret 
  edip başlamaktir. Ben Fox’u yazacağım dediğimde hiç unutmam bir arkadaşım bana 
  “Bence bunu siteden duyurma çünkü ne yapacağını bile bilmeden duyurup da yapamazsan 
  insanlara karşı sorumlu olursun” demişti. Belki kendi açısından haklı idi ama 
  benim kendi düşünceme göre bir işi yapmayı istemek ve başlamak onu yapmakla 
  hemen hemen ayni şeydir. Gerisi sadece zaman meselesidir. Nitekim öylede oldu; 
  işe başlarken meta datalar hakkında çok bilgisi olmayan, CodeDom u doğru dürüst 
  sınıflandırmayı bile bilmeyen, IL den çok çok az anlayan biri olarak elimdeki 
  4 Microsoft dökümanı sayesinde bütün bunlar zamanla çözüldü ve ortaya bir decompiler 
  aracı çıktı. Beta sürümünden sonra çıkan başka terslikler ve engeller nedeni 
  ile Fox o beta asamaşında uzun süre kalmak zorunda kaldı. Ancak bir süre sonra 
  Fox konusunda “XenoCode” benle gürüşmek istedi ve Fox’u tüm hakları ile satın 
  almak istediklerini belirtti. Yapılan görüşmeler sonucunda Fox’u satın aldılar 
  ve bende onlar icin Fox’u geliştirmeye devam ettim. Fox o günden sonra ‘Xenocode 
  Fox’ oldu. Bügün ise Fox şu anda en iyi .NET decompiler olarak lanse edilen 
  ve 2 haftada 20.000 download!a ulaşan bir program oldu. Bu beklenmedik başarı 
  bügün Xenocode’u ve beni Fox’u daha da geliştirmeye itiyor. 
  
  
   
  Şu anda bir çok decompilerın çözemediği yada Label’larla çözdüğü kodları bile 
  daha anlamlı kodlar haline çevirebilen Fox bunun yanında “Export Visual 
  Studio .NET 2005” özelliği ile de ilgi çekiyor. Bu özellik sayesinde 
  Fox verilen bir exe yada dll’i sanki siz onu proje yapıp da sonra build etmişsiniz 
  gibi geriye dönüşük Proje dosyasını oluşturuyor. Bu esnada Component, Form, 
  UserControl gibi designer destekli class’ları anlıyor varsa bunların resx dosyalarını 
  onlarla ilişkilendiriyor ve hatta AssemblyInfo.cs, csproj ve sln dosyalarını 
  bile otomatik üretebiliyor. Oluşan bu projeye VS.NET ile açıp tekrar buil edebilirsiniz 
  hemde hiç kod değiştirmenize gerek kalmadan. .NET 2.0 la gelen Genericslere 
  tam desteği var. Her türlü DllImport yada Marshaled call ifadelerini 
  tam manası ile çözüyor. Normal attribute çözümüni yapabildiği gibi; return: 
  ve param: attribitute türlerinide çözebiliyor. Ayrıca sınıfların Base ve Derived 
  tiplerini gösterebiliyor. Text Search yapabiliyor. .resources dosyalarını tam 
  manası ile çözüp resx leri oluşturabiliyor. System.Resources.ResourceReader 
  1.0 ve 2.0 versiyonuna tam desteği var. Yani bu ResourceReader ların hangisi 
  için hazırlanmış .resources dosyası olursa olsun onu tam bir resx şeklinde çözebiliyor. 
  Bilinen resx data tiplerinin yanında application/x-microsoft.net.object.binary.base64 
  ve application/x-microsoft.net.object.bytearray.base64 her ikisinede desteği 
  mevcut. Unicode textleri otomatik algılayıp ona göre yazabiliyor. Ayrıca hyperlinked 
  görüntü sayesinde istediğiniz tip yda üye elemana tek tıkla ulaşabiliyorsunuz. 
  C#, VB.NET ve IL dillerinde dönüşüm yapabiliyor. Yine C# ve VB.NET dillerinin 
  her ikisindede Export edebilme özelliği mevcut. Ayrıca Tab Page görünümü sayesinde 
  aynı kodu iki dilde açıp karşılaştırma yapabilirsiniz. Ayrıca Fox da oto casting 
  vardır. Yani decompile edilen kodda method call lar kontrol edilir ve eğer tipler 
  uyumsuzsa otomatik casting kodları ekler. Bunun gibi daha bir çok decompile 
  stratejisini yapısında barındırır. 
   
     
   
  Fox’un aslında biz Türk programcılar için en önemli özelliği ise bizimde istediğimizde 
  bir şeyler yapabildiğimizdir ve sonuçta yaptığımız şey dünya standartlarında 
  ses getirecek cinsten bile olabilir. Zaten Fox’u yazarken bunu göstermeyi düsünüyordum 
  ve sanıyorum bugün bunu az çok ispatlamış bulunuyoruz. Dünyanın üzerine en cok 
  yatırım yapılan platformlarından birinde yazdığınız tüm kodları sanki build 
  edilmemiş gibi çözen bir ürün.
  
 
Fox ve benzeri 
  programlar çoğu yazılımcı tarafından eleştirilselerde emin olduğum bir şey varki 
  bu eleştirenlerin hemen hemen hepsi bu araçları kullandığıdır. Bu araçlar eleştiriliyor 
  çünkü; onların gözünde başkasının kodunu çalmaya yarayan araçlar. Fox onların 
  günlerce olan emeğine hiç aldırmaksızın tüm kodu çözmek için yaklaşık bir kaç 
  dakika harcıyor ve onların yaklaşık 1 yıllık emeğini çalıyor. Aslında olay benim 
  gözümde bu şekilde canlanmıyor. Benim gözümde ise Fox ve benzeri decompilerlar 
  birer kurtarıcı. Bir windows programcısı olarak Fox hem benim yapabileceklerimi 
  sürekli geliştiriyor hemde bir çok kez beni günlerce uğraşacağım bir şeyi cok 
  daha kısa sürede yapmama imkan sağlıyor. Örneğin bir windows kontrolünde yapmaya 
  calıştığım bir şeyin neden olmadığı konusunda takıldığımda Fox’la System.Windows.Forms.dll’ini 
  çözüp o control’ün kodlarına bakıp bu hatanın nereden kaynakladığını çok rahat 
  bulabiliyorum. Yada örneğin AxWebBroser tarzında basit bir browser objesi yazmak 
  için shdocvw.dll’i açıp içinden gerekli COM interfacelerine bakıp benzerlerini 
  yazıp kendim AxHost dan bir control türeterek istediğim işlevi yapacak bir Web 
  Browser türetebiliyorum. Bunlar işin cok basit kısımları. Bence bundan da önemli 
  olan şey Fox’dan öncede decompiler araçları vardı. Yani Fox’un olmaması durumu 
  değiştirmez. Birde kötü niyetli kullanımlar bizi bağlamaz. Eğer biz herşeyin 
  kötü niyetli kullanılacağını düşünüp ona göre davranmaya kalkarsak sonuçta üretim 
  yapmakdan çıkar adam akıllı işler yapamayız. Bu tip araçları kullanmaya başladığınızda 
  sizlerde işinize ne kadar yaradıklarının farkına varıcaksınız ve cidden böyle 
  bir araca sahip olduğunuz için sevineceksiniz. En azından ben kendi adıma Fox 
  yada benzeri araçlarsız program yazmamın daha zor olucağına inanıyorum. 
   
    
   
  Şimdi yukardaki uzun Fox hikayesinden çıkıp isterseniz bu decompile olayında 
  biraz daha işin içine girip bazı ip uçları vererek bu işi nasıl yaptığımızı 
  detaylandıralım. Tabii burada çok kısa değinebilmemiz ancak mümkün. Detayları 
  atlamak şartı ile olayın kısa mantığını anlatmak bile yeteri kadar uzun olucaktır. 
  100.000 satır kodu olan bir programın yaptığını burada detaylı anlatmak da çok 
  mantıklı olmasa gerek. 
  
Biraz 
  da teknik detay ... 
   
  .NET Dosyaları birer PE(Portable Executable) dosyalarıdır. Bu dosyalar ilk iki 
  byte’ında 0x5a4d “MZ” değerini taşımak zorundadırlar. Daha sonra 0x3c offsetindeki 
  4 byte ise bize bu dosyanın PE flagının yerini belirtir. Buradan okunan 4 byte’ın 
  bize verdiği integer degerdeki offset e gidip 4 byte okuduğumuzda ‘PE\0\0’ yani 
  0x00004550 değerinin olması gerekiyor. Bu kontroller yapıldıktan sonra dosyanın 
  PE dosyası olup olmadığı anlaşılır. Daha sonra ise bu dosyadan COFF (Common 
  Object File Format) Headerı okunur. Bu header bize bu dll in hangi tipde makinalarda 
  calışması için compile edildiği, bazı COFF flaglarını ve OptionalHeaderSize 
  gibi bazı gerekli bilgilerini verir. Bu optional header size sayesinde 
  dosyanın DataSectionlarının offsetlerini bulabiliriz. COFF Header dan hemen 
  sonrasında ise OptionalHeaderlar gelir. Bunları üçe ayırabiliriz. StandartFields, 
  NTSpecificFields ve DataDirectories. StandartFields bize dosyanın exe yada dll 
  olduğunu belirten BaseOfCode (0x00400000 exe, 0x10000000 dll), exe ise EntryPoint 
  inin RVA (Relative Virtual Address) ini, CodeSize ını (genelde text section’ın 
  boyutu, daha dogrusu tum code sectionlarının toplam boyutu) gibi bazı önemli 
  fieldlar barındırır. NTSpecificFields ImageBase(dll, exe, CE_Exe), Section bilgileri, 
  SubSystem (WındowsGui, WindowsCui, Native etc.etc.), DllCharacteristic gibi 
  bazi bilgileri barındırır. DataDirectories ise; Export Table, Import Table, 
  Resource Table, Exception Table, Certificate Table gibi Image Data Directorylerin 
  boyutu ve RVA larını barındırır.
  
Daha sonra DataSection 
  RVA sına gidip buradan SectionHeaderlarını okuyabiliriz. Bir .NET çıktısında 
  COFFHeader da belirtilen NumberOfSections kadar section header vardır. Her section 
  header o section’ın RVAsını, RawDataSize gibi bilgileri barındırır. Bu headerları 
  kullanarak aradığımız bir RVAnın bu dosyada hangi section’a denk düştüğünü bulup 
  ona göre bu section’ın RVA sı + bizim aradığımız RVA şeklinde aradığımız yere 
  ulaşabiliriz.
  
Daha sonrasında 
  bu dosyanın CLIHeaderını DataDirectoryler listesindeki CLIHeader ın RVA sına 
  giderek okuyabiliriz. CLIHeader Meta Data, Resources, StrongNameSignature, CodeManagerTable, 
  VtableFixups, ExportAddressTableJumps, ManagedNativeHeader gibi ImageDataDirectoryleri 
  ve bazı flagları barındırır.
  
CLIHeader dan sonra 
  MetaData ları okuyabilmek için MetaDataHeader’ı okumamız gerekir. Bunun için 
  CLIHeader’ın Meta Data ImageDirectory sinin RVA sına gidip okuma işlemini gerçekleştirmemiz 
  gerekir. Meta Data header bazı flagların yanında en önemli olarak bize bu dosyanın 
  Heaplerinin bilgilerini verir. Bir .NET dosyasında 5 tane heap header vardır. 
  Bunlar; StringsHeap(#Strings), BlobHeap(#Blobs), GUIDHeap(#Guids), USHeap(#US) 
  ve Tables Heap(#-, #~ ) dir. Sırası ile açıklamak gerekirse;  
   
  StringHeap: dosyadaki stringlerin tutulduğu yerdir. Örneğin 
  method isimleri, method reference isimleri, field reference isimleri, field 
  isimleri hep burada tutulurlar.  
    
  BlobHeap: Bloblar komplike data yapılarıdır. Burada bir byte[] şeklinde 
  bulunan signaturelar çözülerek kullanıldıkları yere göre değişik anlamlar içeren 
  veriler barındırırlar. Örneğin bir method’a ait referans için o method’un tokeni 
  yada signature’ı gibi. .NET 2.0 la birlikte gelen Genericsler sayesinde bu heap’in 
  önemi daha da arttı ve artık burada TypeInstanceların ve Method Instantiations’lar 
  da tutulmaya başlandı ki bunlar bir generic type dan yeni bir type instance 
  yarattığınızda veya bir method’un generic çağrılmasında o instance’ın çözülebilmesi 
  için gerekli type signature’ları barındırır.  
   
  GUIDHeap: Programda kullandığınız GUID’leri barındırır.  
   
  USHeap: User String’leri yani kullanıcı tanımlı mesaj yada benzeri 
  stringleri içinde barındırır.  
   
  Tables Heap: MetaData Tablelarını barındırır.  
   
  Şimdi sıra MetaData Tablelarının kaçar elaman barındırdığını okumaya geldi. 
  Bunu okumak icin #~ yani TablesHeap header’da belirtilen offset e gideriz ve 
  orada sırası ile tüm table’ların kaç tane eleman barındırdığını okuruz. Daha 
  sonra sting heap’e gider ve oradan tüm stringleri okuruz. String heap de stringler 
  ‘\0’ yani Null Terminated string array şeklinde barındırılır. Daha sonra blob 
  heap’e gider ve blobları okuruz. Bloblar sırası ile dizilmiş şekildedirler. 
  Her blob’un ilk başında onun encode edilmiş şekilde kaç byte’dan oluştuğu vardır. 
  Bu byte sayısı kadar byte[] ise onun datasını barındırır. Sonrada Guid heap’e 
  gider ve oradan 16 şar byte lık arrayler şeklinde guidleri okuruz. Daha sonra 
  US Heap’e gideriz ve yine blob da olduğu gibi peşpeşe gelen row lar şeklinde 
  her row un başında encode edilmiş int şeklinde kaç byte olduğunu okur sonrada 
  o kadar byte[] şeklinde string’i okuruz.
  
Burada kısaca .NET 
  in data tutma şeklinede değinmek gerekirse. .NET öncelikle çok sık kullanılan 
  data tutma şekillerinden biri encode edilmiş inttir. Encode edilmiş int dediğimiz 
  yapı ile int değerinin en az byte kullanılarak tutulması amaçlanmıştır. Bunu 
  şu şekilde çözümleyebiliriz. 
   
  int DecodeInt32(BinaryReader reader) 
  { 
             int 
  value = reader.ReadByte(); 
   
             if 
  ((value & 0x80) == 0) 
                        return 
  value; 
   
             if 
  (value == 0xff) 
                        return 
  -1; 
   
             if 
  ((value & 0xc0) == 0x80) 
                        return 
  ((value & 0x3f) << 8) | reader.ReadByte());
  
            return 
  ((value & 0x3f) << 24) | (reader.ReadByte() << 16)  
                                              | 
  (reader.ReadByte() << 8) | reader.ReadByte(); 
  }
  
.NET dosyalarında 
  bir GUID, Blob yada String Indexi ise 2 yada 4 bytelık bir sayısal değer olarak 
  tutulur. Bunu bulmak için MetaData Header da okuduğumuz HeapSizes değerini kullanabiliriz.
  
int stringLength 
  = (int) (((HeapSizes & 0x01) != 0) ? 4 : 2); 
  int guidLength = (int) (((HeapSizes & 0x02) != 0) ? 4 : 2); 
  int blobLength = (int) (((HeapSizes & 0x04) != 0) ? 4 : 2);
  
Buna göre eğer 
  .NET dosyasında herhangi bir yerde örneğin Blob okumamız gerektiğinde bu dosyanın 
  blupLengthine bakarız ve eğer 2 ise 2 byte okuruz aksi takdirde 4 byte okuruz. 
  Bu sayede .NET dosyasının boyutu küçültülmüş oluyor.
  
Yine aynı şey Meta 
  Data Tablelarında da geçerlidir.
  
MetaData Table 
  Header da bulunan 64 int elemanlı Rows dizisi bize bu dosyanın MetaDataTablelarının 
  her birindeki eleman sayılarını veriyordu. Buradan hareketle hangi Tableda 
  kaç eleman olduğuna bakarız ve eğer eleman sayısı 0xffff den küçükse bu durumda 
  2 bytelık bir değer büyükse 4 byte lık bir değer okuruz.
  
Örneklemek gerekirse 
  eğer dosya içinde bir TypeRef okumamız gerektiğinde TypeRef tableında yani 
  1. index deki Row countuna bakarız eger bu sayı 0xffff den kuçukse bu durumda 
  2 byte lık bir değer okuruz aksi halde 4 bytelık bir değer okuruz. Okuduğumuz 
  bu değer o table dan bir index i belirtir.
  
Şimdi kaldığımız 
  yerden devam edicek olursak. Heap okumasını tamamladığımıza göre şimdi sıra 
  en önemli yerlerden biri olan MetaData Tablelarını okumaya geldi. .NETte tanımlı 
  44 tane MetaDataTable vardır. Bunları yazmak ve önemlilerini kısaca yazmak gerekirse;
  
Module 
  = 0: 
   
  Module leri barındırır. Bir dll yada exe içinde birden fazla module barındırabilir. 
  Genelde bu sayı 1 dir. Yani her .NET exe sinde ve dll inde bir tane modül vardır. 
  Module Table ındaki her bir row için sırası ile: Generation, Name, MvId, EncId, 
  EncBaseId olmak üzere 5 tane colon vardır. 
   
  TypeRef = 1:   
   
  Bu assembly haricinde başka bir assemblyden çağrılan ve kullanılan tüm Type 
  Reference lar için birer row girilir. Örneğin siz int a diye bir değişken tanımladığınızda 
  burada otomatikman int için bir row oluşturulur. Çünkü int bir başka assembly 
  de (mscorlib.dll) tanımlıdır ve oradan kullanılır. TypeRef tableında her bir 
  row için: ResolutionScope, Name ve Namespace olmak üzere üç kolon mevcuttur.
  
TypeDef 
  = 2 : 
   
  Bu assembly içinde tanımladığınız tüm typelardır. Yani class, delegate, struct 
  ve enumlar burada birer row seklinde tutulurlar. Her bir TypeDef için sırası 
  ile Flags, Name, Namespace, Extends, FieldList ve MethodList olmak üzere 6 tane 
  colon bulunur.
  
FieldPointer 
  = 3 :  
  Field = 4 : 
   
  Bu assembly içindeki tüm TypeDeflerin herbirinin içindeki tüm fieldlar bu table 
  da bulunur. Yani yarattığınız tum class, struct ve enumlar içindeki fieldlar 
  buraya konulur. TypeDef deki type tanımlamalarındaki FieldList bu table da bir 
  index E karşılık gelir. Yani o typedef in fieldlarının bu table da hangi index 
  den başladığını bu sayede bulabilir ve fieldları buradan okuyabilirsiniz. Field 
  table ında her field için sırası ile; Flags, Name ve Signature olmak üzere 3 
  colon vardır.
  
MethodPointer 
  = 5: 
  MethodDef = 6: 
    
  Bu assembly içindeki yarattığınız tüm TypeDeflerin herbirinin içindeki tüm methodlar 
  bu table da bulunur. Yani yarattığınız tüm class, delegate ve struct ların methodları 
  buraya konulur. TypeDef deki type tanımlamalarınındaki MethodList bu table da 
  bir indexe karşılık gelir. Yani o typedef in methodlarının bu table da hangi 
  index den başladığını bu sayede bulabilir ve methodları buradan okuyabilirisiniz. 
  MethodDef table’ında her bir methoddef için sırası ile; RVA, ImplFlags, Flags, 
  Name, Signature ve ParamList olmak üzere 6 colon vardır.
  
ParamPointer 
  = 7 :  
  Param = 8 : 
   
  Bu assembly içinde yarattığınız tüm Type Def lerde yazdığınız tüm Methodların 
  kullandığı parametreler buraya konulur. Yani MethodDef table ındaki her method 
  un varsa parametreleri buraya konulur. MethodDef deki her row un ParamList i 
  bu tableda bir index’e denk gelir. Böylece o methodun parametreleri buradan 
  okuyabilirsiniz. Param table’ında her parametre için sırası ile; Flags, Sequence 
  ve Name olmak üzere üç kolon vardır.  
   
  InterfaceImpl = 9 : 
   
  Bir TypeDef in hangi interface leri implement ettiğini bulmak için kullanılır. 
  Yani her eğer bir Type Def bir interface i implement ediyorsa; Örneğin class 
  MyClass : IDisposable gibi; bu durumda bir row bu table da oluşur. Bu tabeldaki 
  her bir row da sırası ile Class ve Interface olmak üzere iki kolon vardır. Bu 
  kolonlardan ilki hangi TypeDef için bu row un olduğunu belirtir ki bizim örneğimizde 
  bu MyClass ve ikincisi ise TypeDef yada TypeRef tableında ki bir row a karşılık 
  gelerek hangi interface olduğunu bulmamızı sağlar. Tabi bizim örneğimizde IDisposable.
  
MemberRef 
  = 0xA : 
   
  Herhangi bir TypeDef, TypeRef, ModuleRef, MethodDef veya TypeSpec içindeki bir 
  member’a referas sağlamak adına kullanılır diyebiliriz. Burada her bir member 
  için oluşan row da sırası ile Class, Name ve Signature olmak üzere 3 kolon barındırır. 
  Burada Class hangi table la alakalı olduğunu bildirir. 
  
Constant 
  = 0xB : 
   
  Tanımladığınız constantlar burada birer row şeklinde belirtilirler. Burad aher 
  bir row Type, Parent ve Value olmak üzere 3 kolon vardır. Burada Type burada 
  tutulan değerin Native Element Tipini belirtir. Parent ise Field, Parametre 
  yada Property table ında bir index belirtir. Value ise bir blob indexini belirtir.
  
CustomAttribute 
  = 0xC : 
   
  Tanımladığınız tüm CustomAttributelar burada bulunur. Her custom attribute için 
  Parent, Type ve Value olmak üzere 3 colon vardır. Parent MethodDef, Field, TypeRef, 
  TypeDef, Param, InterfaceImpl, MemberRef, Module, DeclSecurity, Property, Event 
  StandAloneSig, ModuleRef, TypeSpec, Assembly, AssemblyRef, File, ExportedType 
  ve ManifestResource tablelarından birinde bir index belirtir. Type ise TypeDef, 
  TypeRef, MethodDef, MemberRef ve UserStrin den herhangi birinde bir index belirtir. 
  Value ise blob şeklinde Value yu belirtir.
  
FieldMarshal 
  = 0xD,  
  DeclSecurity = 0xE,  
  ClassLayout = 0xF,  
  FieldLayout = 0x10,  
  StandAloneSig = 0x11,  
  EventMap = 0x12 : 
   
  EventMap bir relation table’ıdır diyebiliriz. Bu table da Event’ler ve bunların 
  hangi TypeDef e ait oldukları ilişkilendirilmiştir. Her bir EventMap row unda 
  sırası ile Parent ve EventList olmak üzere iki colon vardır. Parent hangi TypeDef 
  in eventleri olduğunu EventList de event tableında bir index belirtir.
  
EventPointer 
  = 0x13,  
  Event = 0x14 : 
   
  Assembly içindeki tüm TypeDef lerinizde tanımladığınız tüm eventler burada birer 
  row şeklinde girilir. Her bir event row unda sırası ile EventFlags, Name ve 
  EventType olmak üzere 3 colon vardır. EventFlag flagları, Name ismini ve EventType 
  da TypeDef yada TypeRef içindeki bir row da o eventin Handler tipini belirtir.
  
PropertyMap 
  = 0x15 : 
   
  EventMap in benzeri şekilde buda Property – TypeDef arasındaki iliskileri belirler. 
  Yani hangi Property nin hangi TypeDef a ait olduğunu belirtir. Her bir PropertyMap 
  rowunda Parent ve PropertyList olmak üzere iki kolon bulunur. Bu komonlardan 
  ilki hangi TypeDef in Propertyleri için bu row un olduğunu PropertyList ise 
  hangi indexden itibaren Propertylerin başladığını belirtir.
  
PropertyPointer 
  = 0x16, 
  Property = 0x17 : 
    
  Tüm property tanımları bu table da olurlar. Bu table daki her bir property için 
  Flags, Name ve Type olmak üzere 3 colon mevcuttur. Type colonu bir blob index 
  belirtir. Bu blobdan okunan değeri çözerek bu Property nin Type ını ve parametrelerinin 
  typelarını bulabiliriz.
  
MethodSemantics 
  = 0x18 : 
   
  Her bir event’in yada Property nin bildiginiz gibi içi aslında methodlardır. 
  Yani 
   
  public int MyProperty 
  { 
          get {return _MyProperty;} 
          set {_MyProperty = value;}  
  } 
   
  şeklindeki bir property aslında iki ayrı methoddur. 
   
  public int get_MyProperty() {return _MyProperty;} 
   
  ve 
   
  public void set_MyProperty(int value) {_MyProperty = value;} 
   
  işte bu table bir property ile onun MethodDef lerini yada bir Eventle onun MethodDef 
  leri arasındaki ilişkilendirmeyi yapmakta kullanılır. Her bir MethodSemantics 
  row unda sırası ile Semantics, Method ve Association olmak üzere 3 colondan 
  oluşur. Semantics flagları, Method methoddef tableında bri index i ve Association 
  ise Event veya Property table’ında bir index belirtir.
  
MethodImpl 
  = 0x19, 
  ModuleRef = 0x1A: 
   
  Bir assembly içinde kullandığınız DllImport lar nedeni ile hangi dll lere refernas 
  taşıyorsanız onların herbirine burada bir row eklenir. Bu sayede DllImport çözümlerinde 
  hangi modülden bu method’un çağrıldığını bulabiliriz. Her bir ModuleRef Name 
  olmak üzere bir colondan oluşur.
  
TypeSpec 
  = 0x1B: 
   
  Bir Type’ın signaturedan çözülmesini sağlamak için bir blob index belirtir. 
  Bu blob’un çözümlenmesi ile ortaya bir Type çıkar. Her TypeSpec de bulunan rowlar 
  sadece Blob’dan bir index barındırırlar.
  
ImplMap 
  = 0x1C, 
  FieldRVA = 0x1D: 
   
  Static olan field tanımlamalarının değerlerini barındırır. Yani static yazdığınız 
  field’ın cctor methodunda yüklenen ilk değerini tutar. Herbir FieldRVA rowu 
  RVA ve Field olmak üzere iki kolondan oluşur.
  
EncodingLog = 0x1E, 
  
  
EncodingMap = 0x1F, 
  
  
Assembly 
  = 0x20: 
   
  Bu dosya içinde tanımlı bulunan tüm Assembly’ler burada birer row şeklinde bulunur. 
  Genelde birden fazla olmaz. Her AssemblyRow HashAlgId, Major, Minor, Revision, 
  Build Flags, PublicKey, Name ve Culture olmak üzere 9 colondan oluşur.
  
AssemblyProcessor 
  = 0x21,  
  AssemblyOS = 0x22,  
  AssemblyRef = 0x23 : 
   
  Assemblyniz içinde diğer assemblylere taşıdığınız her bir Assembly Referans’ı 
  burada bir row şeklinde tutulur. Örneğin mscorlib.dll, System.dll gibi. Her 
  AssemblyRef row unda sırası ile Major, Minor, Revision, Build, Flags, PublicKey 
  Name, Culture ve HashValue olmak üzere 9 colon vardır.
  
AssemblyRefProcessor 
  = 0x24: 
  AssemblyRefOS = 0x25: 
  File = 0x26: 
  ExportedType = 0x27: 
  ManifestResource = 0x28: 
   
  Her bir manifest resource için bir row buraya kaydedilir. Her manifest resource’un 
  sırası ile Offset, Flags, Name ve Implementation olmak üzere 4 colon u vardır.
  
NestedClass 
  = 0x29: 
   
  Nested classları tutmanızda yardımcı olurlar. Nested class’lar direk namespace 
  içerisinde değilde bir class’ın altında bulunan classlardır. Aslında onlarda 
  TypeDef de birer row olarka tutulurlar ancak burada onlarla onların Declaring 
  Type ları arasındaki ilişkilendirme tutulur. Her bir NestedClass rowunda sırası 
  ile NestedClass ve EnclosingClass olam üzere 2 colon vardır. 
   
  GenericParam = 0x2A: 
   
  Generic parametreler burada tutulurlar. Her bir Generic Parametre sırası ile 
  Number, Flags, Owner ve Name olmak üzere 4 colondan oluşur.
  
MethodSpec 
  = 0x2B: 
   
  Burada generic methodların Instantiation ları tutulur. Her bir MethodSpec row’unda 
  sırası ile Method ve Instantiation olmak üzere iki colon vardır.
  
GenericParamConstraint 
  = 0x2C: 
   
  Burada herhangi bir Generic Parametresinin Constraintleri tutulur. Herbir row 
  Owner ve Constraint olmak üzere iki colon’dan oluşur. 
  ---- 
   
  Bu tableların hepsini detayları ile açıklarsak safalar dolusu döküman oluşur. 
  Ben sadece burada birkaç tanesini açıkladım. Bunlar en önemli olanlar diyeceğim 
  ama diğerleride bunlar kadar önemli sayılırlar. Ayrıca yine burada çok fazla 
  kolonlarına değinmedim. Kolon çözümlemeleride aslında bazı durumlarda kompleksleşebilir. 
  O nedenle çok girmeyeceğim bu konuya ama şu kadarını söyliyeyim işte MetaData 
  Table lar dediğimiz şeyler bunlardır. Yani bir Assembly içindeki tüm herşey 
  bu tablelarda tanımlıdır. Ve tüm bu tablelar birbirleri ile ilişkilidir. CLR 
  bunları çalışma zamanında ilişkilendirip buna göre çalıştırır. 
  
Şimdi 
  bu konuda çok kısa bir örnek yazalım daha detaylı olsun ve anlamaya yardımcı 
  olsun; Bir Assembly’miz olsun ve içinde iki tane classımız tanımlı olsun 
   
  public class MyClass 
  { 
         int _MyField = 0 ; 
         Colors _Color = Colors.Red ;
  
        public 
  MyClass() 
         {
  
        }
  
        public 
  string DoOperation(bool parameter) 
         { 
                if 
  (parameter) 
                       return 
  “True”; 
                else 
                       return 
  “False”; 
         }
  
        [Browsable(false)] 
         public int MyProperty 
         { 
                get 
  {return _MyField;} 
                set 
  {_MyField = value;} 
         }
  
        public 
  Colors Color 
         { 
                get 
  {return _Color;} 
                set 
  {_Color = value;} 
         } 
  }
  
public enum Colors 
  { 
         Red, 
         Green, 
         Blue 
  }
  
 şimdi yazdığımız 
  assembly’de sadece yukardaki tiplerin olduğunu düşündüğümüzde bu assembly’ nin 
  meta data tableları şu şekilde oluşucaktır.
  
TypeDef; 
  Flags ........... Name ....... Namespace ...... Extends 
  ..... FieldList .... MethodList 
  1                          MyClass* 
        MyNamespace*   0                        1 
                        1 
  1                          Colors* 
            MyNamespace*   1 
                        3 
                         0
  
 
  TypeRef: 
  ResolutionScope ............. Name ................ 
  Namespace 
  0x23000001                               Int32* 
                          System* 
  0x23000001                               Boolean* 
                     System* 
  0x23000002                      BrowsableAttrıbute* 
       System.ComponentModel* 
  ....
  
 
  MethodDef: 
  RVA .... ImplFlags .... Flags ... Name .......... 
  Signature ... ParamList 
  ...            0                          6 
                DoOperation* 
          3                        1 
  ...            0                          6 
             get_MyProperty* 
       4                        1 
  ...            0                          6            
  set_MyProperty*      6                        1 
  ...            0                          6 
                  get_Color 
               12 
                        2 
  ...            0                          6 
                  set_Color 
                24 
                       2 
  ...            0                    0x806 
                 .ctor* 
                     48 
                       2
  
Field: 
  Flags ................ Name ............... 
  Signature 
  1                                _MyField* 
                           67 
  1                                _Color* 
                         
       45 
  1                                _Red* 
                            
      456 
  1                                _Green* 
                             
  33 
  1                                _Blue* 
                        
         97
  
 
  Param: 
  Flags ............... Sequence ............ Name 
  1                                        0                           
  parameter* 
  1                                        0                           
  value* 
  1                                        0                           
  value*
  
Property: 
  Flags ............... Name ................ Type 
  0x200                   MyProperty* 
                     ... 
  0x200                         Color* 
                           ...
  
PropertyMap: 
  Parent .............. PropertyList 
  0x00000001                     1
  
CustomAttribute: 
  Parent .............. Type ................ Value 
  0x17000001      0x01000003                    ...
  
MethodSemantics: 
  Semantics ........... Method .............. Association 
  0x0002                       
  2                                      0x17000001 
  0x0001                       
  3                                       
  0x17000001 
  0x0002                       
  4                                      0x17000002 
  0x0001                       
  5                                       
  0x17000002
  
Assembly: 
  HashAlgId .. Major .. Minor .. Revision .. Flags .. 
  PublicKey .. Name ....... Culture 
  0x8004                 
  1            1                 5345 
       0x8000          0 
             MyAssembly* 
         0
  
AssemblyRef: 
  Major .. Minor .. Revision .. Build .. Flags .. PublicKey 
  ........ Name ........... Culture  
  2                 0 
                   0                 
  0             1 
   b77a5c561934e089* mscorlib*              0 
  2                0 
                   0 
                   0 
              1 b77a5c561934e089* 
  System*                 0
  
Yanında * işareti 
  olanlar aslında heaplerden okunan indexler olucak ama ben return değerlerini 
  yazdım. 
   
  İşte yukarda yazdığımız basit bir Assembly Build edildikten sonra Meta Data 
  Table ları yaklaşık olarak bu şekilde oluşacaktır. Listeyi elle hazırladığım 
  için belki bir kaç ufak hata olabilir ama sonuçta bu tarz birşeyler ortaya çıkıcaktır. 
  
  
Tabi bu yapı aslında 
  daha da komplike bir şekilde olur ama ben örnek olsun diye basitce anlattım 
  ve bu sırada birçok meta data table’ınıda yazmadım. Gerçekte ise oluşturduğumuz 
  type lar, referansları, attributeları, methodlar, parametreler, düşünüldükçe 
  bu yapının nasıl bir hal aldığı daha çok anlaşılacaktır.
  
Kısaca yukardaki 
  gibi çözdüğümüz meta data sayesinde elimizde bu assembly’nin tam çözümlenmiş 
  Type ve Member yapısı oluşur. Yani bir nevi Reflection la çözülen yapının aynısı.
  
Şimdi sıra bir 
  methodun decompile edilmesine geldi. Bir methodun decompile edilebilmesi için 
  o method’un Body’sini yani methodun iç kısmını okumamız gerekir. Bunun için 
  Method’un RVA’sına gidilir ve okuma yapılır. Okuma işlemi method’un büyüklüğüne 
  göre iki formatta olur. FatFormat (buyuk methodlar, try catch veya local variable 
  barındıran methodlar) ve Tiny format. Tiny formatta method da sectionlar yoktur 
  ve Code’lar buradan okunur. FatFormatta ise methodun kodu birden fazla section’a 
  bölünür ve oradan sırası ile okunur. Aslında try catch kullandığınızda yada 
  variable kullandığınızda method otomatikman FatFormatta olur. Çünkü TinyFormatta 
  try catch ve Lacal Variable yoktur.
  
Method RVA’sını 
  o RVA yı kapsayan sectiondan bulup o position’a gidip oradan Method Body’sini 
  okuduğumuzda elimizde byte[] şeklinde bir data oluşacaktır. Okunan bu byte[] 
  şeklindeki data o methodun core datasıdır. Şimdi bunu işlemek gerekir. Aslında 
  okunan bu byte[] tum IL datasıdır. Bunun için once IL’yi biraz inceleyelim. 
  IL opcode lardan oluşur yani bir komut gibi düşünürsek bir işlemi ifade eden 
  bir data ve eger varsa bunun aldığı bir data sonrasındada o data olucak sekilde 
  dizilirler. IL de her bir opcode’un bir Operand Type’ı vardır. 
   
  Bu Operand Typelar;
  
OperandType.InlineNone: 
  Operand dan sonra herhangi bir data olmaz. Sıradaki Operand’a geçilir.
  
OperandType.ShortInlineBrTarget: 
  Operand dan sonra bir sbyte lık data target belirtir. Bu operand tipi branch 
  yani zıplama operand larında olur ve zıplamanın olacağı adresi belirtir. Yani 
  goto ... gibi düşünebilirsiniz. 
  
OperandType.InlineBrTarget: 
  Operand dan sonra 4 byte lık bir integer data target belirtir. Bu operand tipi 
  branch yani zıplama operandlarında olur ve zıplamanın olacağı adresi belirtir. 
  Aynı ShortInlineBrTarget gibidir ancak tek fark gidilcek adres 4 byte la ifade 
  edilir.
  
OperandType.ShortInlineI: 
  Operand dan sonra bir sbyte lık data vardır. 
  
OperandType.InlineI: 
  Operand dan sonra 4 bytelık bir integer data vardır
  
OperandType.InlineI8: 
  Operand dan sonra 8 bytelık bir long data vardır
  
OperandType.ShortInlineR: 
  Operand dan sonra bir single data vardır
  
OperandType.InlineR: 
  Operand dan sonra bir double değer vardır 
   
  OperandType.InlineString: Operand dan sonra 4 bytelık bir integer 
  string’in US Heap deki index’ini belirtir. Burada önemli olan bu index’in ilk 
  20 bit’i kullanılır. Yani (reader.ReadInt32() & 0x000fffff) le dönen değer 
  bize US Heap’deki index’i verir. Buradan okunan indexdeki string değeri bu operand 
  için data olarak kullanılır.
  
OperandType.ShortInlineVar: 
  Operand dan sonra bir byte lık data vardır
  
OperandType.InlineVar: 
  Operand dan sonra 2 bytelık unsigned short değer okunur. Bu değer bir index 
  belirtir. Bu index bu method içinde tanımlanan local variable indexidir. Yani 
  sonuçta bu index’deki variable bu operand’in datasıdır.
  
OperandType.InlineSig: 
  OperandType.InlineMethod: 
  OperandType.InlineField: 
  OperandType.InlineType: 
  OperandType.InlineTok: Operand dan sonra 4 bytelık bir int değer okunur. 
  Bu int değer aslında bir tokendir. Bu token’in ilk byte’ı bize hangi MetaTable 
  olduğunu bulmamızı sağlar ve son 3 byte’ı ise o tabledaki index değerini verir. 
  Yani;
  
 int token = reader.ReadInt32(); 
  int table = ((token & 0xff000000) >> 24); 
  int index = (token & 0x00ffffff);
  
 buradan çıkan 
  sonuca göre örneğin table = 1 ve index = 1 ise bu bize; 1 nolu table in 1. item’ı 
  demek oluyor. Buda 1 nolu table TypeRef ve bunun 1. item’ı. Yalnız unutmamak 
  gerekirki MetaData Table larda indexler 1 den başlar. Bu nedenle 1. item demek 
  aslında 0. index deki itemdır. Yani burada bu Opcode un datası TypeRef table’ının 
  0. index deki TypeRefdir.
  
OperandType.InlineSwitch: 
  Operand switch operandıdır. Yani switch ve bunun case leri belirli bir mantıkda 
  sıralanır. Bunun cözümlenme mantığı ise ilk 4 byte bu switch’in kaç case’i olduğunu 
  gösterir. Daha sonra bu case sayısı kadar her case’in target’ini yani hangi 
  ofset’e zıpladığını belirten 4 bytelık targetlar vardır.
  
 int[] cases = 
  new int[reader.ReadInt32()]; 
   
  for (int i = 0; i < cases.Length; i++) 
        cases[i] = reader.ReadInt32(); 
   
  Buradan çıkan sonuca göre cases array şeklinde switch in case lerini belirtir 
  ve bu operandın datası olur. 
   
  Bu operand tiplerine göre body den okuduğumuz code’u çözerir.
  
Yani code array 
  de donerken sırası ile önce opcode’u okuruz. Sonra bu opcode’un OperandType 
  ına göre sonraki datasını (varsa) okuruz ve sonra yeni bir operand’a geçeriz. 
  Burada önemli bir diğer nokta ise operandlardır. .NET’te iki tip operand vardır. 
  Bunlardan ilki tek byte’lık operandlar diğerleri ise 2 byte’lik operandlardır. 
  Bunun için önce bir byte okuruz eger bu byte 0xFE degilse bu demekki o tek byte’lık 
  bir operand’dır. Yok eğer bu byte 0xFE ise bu durumda o operand’ı çözmek için 
  sonraki byte da okunur ve ilk okunan ile orlanır.
  
byte operand = 
  reader.ReadByte(); 
  if (operand == 0xfe) 
  { 
          byte next = reader.ReadByte(); 
          operand = next | 0xfe; 
  }
  
Bunu yaptikdan 
  sonra da yukardaki gibi operand datası okunur.
  
Şimdi şu ana kadar 
  biz bir dosyayı aldık onun headerlarını okuduk, sonra onun meta data table larını 
  okuduk ve şimdi de bir method bodysini okuyup onun opcodelarını yani IL kodlarını 
  çıkarttık.
  
İşte bundan sonra 
  asıl zor kısım yani onun CodeDom’unu yani expression ve statementlarını oluşturmak 
  kalıyor. Burası konusunda cok bilgi veremeyeceğim. Ama burada önemli olan her 
  opcode türü için yapılacak işlemler ve bunların stack da tutulmasını yaparak 
  bir geri cözümleme yapmak. Bu ilk çözümlemede ortaya çıkan kod çok okunabilir 
  birşey olmayacaktır. Daha sonra compilerın ürettiği kodları düşünerek tersi 
  işlemle anlamlı okunaklı bir kod üretilmesi gerekir.
  
 
  Örneğin bir branch gördüğümüzde eğer bu contional branch’sa bunu if, while, 
  do while, for gibi bir şeye uydurmak gibi çözümleme yapılmalıdır. Dahada detaylandırcak 
  olursak;
  
Örneğin kodumuz 
  şu şekilde olsun : 
   
  L_0043: br.s L_0072 
  L_0045: ldarg.0  
  L_0046: ldfld ......  
  L_004b: ldarg.0  
  L_004c: ldarg.0  
  ……………………..  
  L_006e: ldloc.0  
  L_006f: ldc.i4.1  
  L_0070: add  
  L_0071: stloc.0  
  L_0072: ldloc.0  
  L_0073: ldarg.0  
  L_0074: call … 
  L_0079: callvirt … 
  L_007e: blt.s L_0045 
  L_0080: ldc.i4.0  
   
  gibi bir kodumuz olduğunu düşünürsek burada 0043 deki br.s yani branch short 
  bir Branch operand dır ve sonrasında 1 bytelık bir daha (target) alır. Şimdi 
  o kod bize L_0072. ofset e zıplamamızı söylüyor. Oraya gidip baktığımızda onun 
  öncesinde 006e den itibaren
  
ldloc.0 -> 0. 
  local variable i evaluation stack a yükle) 
  ldc.i4.1 -> Int32 olarak 1 sayısal değerini evaluation stacke koyar 
  add -> İki değeri toplar ve sonucu evaluation stacke koyar 
  stloc.0 -> Stackdan bir değer Pop eder ve onu 0. local variable’a atar
  
Şimdi burada yapılan 
  işlem aslında şunun gibi birşey , a diye bir sayısal değişkenimiz olsun ve bu 
  bizim local variable larımızın 0. index dekisi olsun. Yani ilk tanımlanan Local 
  variable. Bu kod bu durumda şu demek oluyor.
  
a = a + 1; 
  ki buda  
  a += 1; 
  ki buda 
  a++; ‘le aynı şeydir…
  
Gördüğünüz gibi o 
zıplamanın adresinden önce bir i++ işlemi oluyor. L_0072 den aşşağıya doğru devam 
ettiğimizde ise yine 0. variable ın 0073 de stack e yüklendiğini görüyoruz. L_007e 
de ise bir conditional zıplama görüyoruz. 
blt.s L_0045 -> eğer ilk değer diğerinden küçükse calışır. 
  Yani ilk değer diğerinden küçükse L_0045 e geri dönüyor.
  
İşte bu şekilde kodu detaylı incelediğimizde ortaya şu çıkıyor;
  
 for (int i = 0; i < …Count; i++) 
  { 
        ….. 
  } 
   
  gibi bir kod. İşte bu şekilde yapılan dünya kadar işlem sonucunda IL kodu ancak 
  anlaşılır bir kod çıkartır ortaya.
  
Burada bir diğer önemli nokta ise .NET teki tüm statement ve 
  expressionlara çok iyi hakim olmak gerekir. Yani tüm expressionların nasıl çalıştığını 
  output un ne olduğu gibi.
  
Örneğin;  
  lock statement’ının aslında System.Threading.Monitor.Enter la başlatılan bir 
  monitor ve System.Threading.Monitor.Exit lede çıkıldığını bilmek gerekirki bu 
  method’a bir call olduğunda otomatikman lock statement oluşturulmalı. 
  
  
 Yada foreach’in aslında IEnumerator ve IEnumerable la alakalı 
olduğunu ve bunun mantığının .. 
IEnumerator enumerator1 = obj.GetEnumerator(); 
  try  
  { 
         while (enumerator1.MoveNext()) 
         { 
                int 
  data = (int)enumerator1.Current; 
                ///// 
         } 
  } 
  finaly 
  { 
         if (enumerator1 is IDisposable) 
         { 
                ((IDisposable)enumerator1).Dispose(); 
         } 
  } 
   
  şeklinde olması gerektiğini bilmek gerekir.
  
Bir diğer önemli nokta. CodeDom’un çok iyi oluşturulması gerekir. Yani tam 
  bir modelleme yapılması gerekir. Sonuçlar ortaya modellenmiş şekilde çıktığında 
  ise artık geriye tek bir iş kalmış olucak ki oda bu model’i render etmek. Bunun 
  içinde her dil için bir renderer yazmak yeterli olucaktır. Ani C#, VB.NET gibi. 
  Bu dillerin herbirinde bu modellenmiş kodlar farklı şekilde çıktı verir.
  
Burada kod model’e bir örnek olarak isterseniz if, else kalıbını verelim.
  
public interface IConditionStatement : IStatement 
  { 
        IBlockStatement Then {get;set;} 
        IBlockStatement Else {get;set;} 
        IStatement Condition {get;set;} 
  } 
  
yine bir diğer kod model objesi olan SizeOfuda verelim...
  
public interface ISizeOfExpression : IExpression 
  { 
        ITypeName Type {get;set;} 
  } 
   
  İşte bunun gibi varolan tum expression ve statementlarin codemodelini oluşturmak 
  çok önemli. Çünkü biz decompile ederken bu codemodeli oluşturuz ki bu sayede 
  elimizde codedom oluşmuş olur.
  
Daha sonra renderer her expression ve statement’ı yeri geldiğinde render ederiz.
  
Örnegin C#Renderer SizeOF Expression’ı gördüğünde sizeof(expression.Type) şeklinde 
  bir işlem uygular. 
   
  Sonuç olarak Fox’un hikayesine değindikten sonra nasıl decompile yapılabileceğini 
  az çok göstermiş oldum. Umarım anlaşılır olmuştur. Aslında bütün bunlar olayın 
  sadece yüzeysel bir anlatımı. Bu konuda uğraşmak isteyenlerin daha detaylı çalışma 
  yapmaları gerekecek. Çünkü her bir meta data table’ının kendine ait özel specific 
  durumları bunların çözümü, yaklaşık 50 civarında expression, 10 civarında Type 
  bütün bunlar hepsi ayrı ayrı çözümlenmeli. Bütün bu anlattıklarımdan sonra umarım 
  herkes .NET’in ve CLR nin hangi mantıkla çalıştığını az çok anlamışlardır. Bizim 
  yaptığımız aslında CLR’nin yaptığına benzer birşey olduğu için engellemenin 
  çok fazla yolu yok.
  
Ancak yinede herkese kodlarını korumak için ellerinden geleni yapmalarını tavsiye 
  ederim. Şu anda bir çok kod koruma aracı mevcut. Bu kod koruma araçlarından 
  hangisinin daha uygun olduğunu belirlerken asla unutmamanız gereken şey ise 
  Obfuscation’ın bir işe yaramayacağı. Çünkü obfuscate etmek sadece ama sadece 
  rename etmektir. Yani örneğin bizim TypeDef table’ındaki bir TypeDef’i okuduğumuzu 
  varsayalım. Obfuscate işlemi uygulandığında USHeap ve StringHeap deki stringler 
  obfuscate edilip _1, _2 yada a, b gibi birşeyler olucak. Yani sadece String 
  ve USHeap de bir şeyler değişicek. Zaten decompiler araçları bunları sadece 
  ama sadece isimleri gösterirken kullanıyor. Yukardada söylediğim gibi asla textler 
  üzerinden işlem olmaz. Bir TypeDef’in name ini okurken bize sadece bir index 
  değeri gelir. Bu StringHeap deki bir index dir ve gidip oradan o text’i alır 
  yazarız. Onun haricinde o TypeDef’i cağıran hiçbir yerdede bu isimle işlem yapılmaz. 
  Direk TypeDef table’ında o TypeDef’in indexi ile işlem yapılırlar. İşte bu nedenle 
  yapmanız gereken koruma tool’unuzu seçerken obfuscate etmesine göre değil exktra 
  özelliklerine göre seçmeniz. Bu konuda benim tavsiyem Fox’u satın alan Xenocode’un 
  diğer tool’u olan PostBuild’dir. PostBuildde .NET kodlarınızı direk Native koda 
  çevirebilme şansınız var. Bu sayede artık ortada MetaData lar kalmadığı için 
  Fox yada Reflector’un çözmeside mümkün olmayacaktır.
  
Hepinize kolay gelsin iyi çalışmalar.
  
Özcan DEĞİRMENCİ 
  [email protected]
  
             | 
         
        
            | 
                
                 
	
                        
                    
 
             | 
         
        
            | 
                 
             | 
         
        
            | 
                
             | 
         
        
            | 
                 
             | 
         
        
            | 
                SON 10 Haber
             | 
         
        
            | 
                
             | 
         
     
                 |