İster VB olsun ister C#, ister web ister Windows uygulaması olsun yazdığımız tüm kodların derlenerek (Compile) bir EXE veya DLL haline dönüştürüldüğünü biliyoruz. Aslında .NET içerisinde yapılan işlem sizin yazdığınız herhangi bir .NET dilindeki kodun MSIL (Microsoft Intermediate Language)’a çevrilmesidir. İşte tam bu noktada akla gelen ilk soru; acaba bu çeviri işleminin tersini yapmak mümkün mü? Yani elimizdeki DLL veya EXE dosyasından yola çıkarak VB veya C# kodumuzu geri alabilir miyiz? Cevap: Evet.
Şu andan itibaren yapacaklarımız hedef olarak kullanacağınız uygulamanın lisans sözleşmesine göre yeri geldiğinde suç teşkil edebilir. O nedenle sizi özellikle uyarmak istiyorum. Çoğu zaman De-Compile işlemleri yaparkenki amacımız yazdığımız kodun nasıl derleyici tarafında MSIL’e çevrildiğini incelemek veya kaynak kodunu kaybettiğimiz ve bize ait olan bir uygulamanın kodlarına ulaşmak olacaktır. Diğer yandan lisans sözleşmesi ile aykırı düşmediği sürece farklı uygulamaları da De-Compile ederek arka planda farklı işlemlerin nasıl yapıldığını inceleme şansınız da olabilir.
.NET tarafına geçtiğimizde herhangi bir DLL veya EXE’nin aslında MSIL kodları içerdiğinden bahsetmiştik. Tabi ki bu MSIL kodları doğrudan bilgisayarlar tarafından çalıştırılabilir kodlar değiller. O nedenle içerisinde MSIL bulunan bir .NET yapısının çalışabilmesi için hedef makinede .NET Framework’ün yüklü olması gerekiyor. .NET Framework içerisindeki CLR (Common Language Runtime) bizim MSIL kodumuzu makine diline çevirerek çalışmasını sağlayacaktır. Kabaca baktığımızda De-Compile yolunda bizim ilk olarak elimizdeki DLL veya EXE içerisinden MSIL kodunu alarak çıkarmamız gerekecek. Bunun için doğrudan .NET Framework SDK paketi ile beraber gelen MSIL DisAssembler (ILDASM) uygulamasını kullanabiliriz.
IL DASM Kullanımı
Bilgisayarınıza .NET Framework SDK paketini kurduktan sonra doğrudan “Başlat” menüsünden ulaşabileceğiniz ILDASM programını Visual Studio yükleme konumu içerisinde SDK klasörü altında da bulabilirsiniz. Programı açtıktan sonra “File / Open” menüsünden istediğiniz bir .NET DLL veya EXE dosyasını açma şansınız olacaktır.Deneme amaçlı olarak gelin mini bir Windows uygulaması yazalım ve ILDASM ile açarak alacağımız sonucu görelim. Uygulamamız içerisinde birer TextBox, Button ve Label bulunacak. Basit bir şekilde düğmeye basıldığında TextBox içerisindeki değeri Label içerisine aktaracağız.
[VB]
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Label1.Text = TextBox1.Text
End Sub
End Class
[C#]
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = textBox1.Text;
}
}
}
Yukarıda yazdığımız kodlar ile oluşturduğumuz uygulamayı ILDASM ile açarak sonucu inceleyelim. Uygulamanın ilk açılan penceresinde bizim EXE’ye ait tüm sınıflar ve namespace’ler gözüküyor olacaktır. Eğer herhangi bir nesnenin tanımı veya metodu ile ilgili MSIL kodunu görmek isterseniz doğrudan çift tıklayarak yeni bir pencerede kodların açılmasını sağlayabilirsiniz.

ILDASM içerisinde EXE’mizin MSIL kodları açıkça gözüküyor
Hazırladığımız örnek uygulamanın Button_Click durumundaki MSIL kodunu bulduğumuzda aşağıdaki sonuç ile karşılaşıyoruz.
[MSIL]
.method private instance void Button1_Click(object sender,
class [mscorlib]System.EventArgs e) cil managed
{
// Code size 23 (0x17)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication1.Form1::get_Label1()
IL_0006: ldarg.0
IL_0007: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox WindowsApplication1.Form1::get_TextBox1()
IL_000c: callvirt instance string [System.Windows.Forms]System.Windows.Forms.TextBox::get_Text()
IL_0011: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
IL_0016: ret
} // end of method Form1::Button1_Click
Yukarıdaki MSIL kodu normal şartlarda CLR tarafından makine koduna çevrilerek hedef ortamda çalıştırılıyor. Artık MSIL kodumuzu aldığımıza göre bu kodu VB veya C# koduna çevirmemiz lazım. Tabi bu iş o kadar kolay değil ve tek tek elle yapılabilecek bir iş de değil. O nedenle bu sefer de farklı bir araç kullanacağız.
Reflector iş başında
Lutz Roeder tarafından yazılmış bir program olarak Reflector’ı http://www.red-gate.com/products/reflector/ adresinden bilgisayarınıza indirebilirsiniz. Program aslında bir önceki adımda anlattığım MSIL çözme işlemini de kendi içinde yapabiliyor. Bununla kalmayıp çözdüğü MSIL kodunu istediğiniz .NET diline de çevirebiliyor.
Programı çalıştırdıktan sonra “File / Open” menüsünden istediğiniz bir EXE veya DLL dosyasını seçebilirsiniz. Uygulamanın ana penceresindeki sınıf listesine hemen seçtiğiniz program da gelecektir.

Reflector ile kaynak kodunu görebiliyoruz.
Ufak bir gezinti ile istediğiniz sınıfın veya metodun koduna doğrudan ulaşabilirsiniz. Reflector arayüzündeki “Programlama Dili” seçeneğinde VB, C#, Delphi ve IL seçenekleri bulunuyor. Bir önceki bölümde hazırladığımız uygulamamızı açarak Button.Click durumundaki kodu farklı dillerde Reflector ile alıp inceleyelim.
[VB]
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
Me.Label1.Text = Me.TextBox1.Text
End Sub
[C#]
private void Button1_Click(object sender, EventArgs e)
{
this.Label1.Text = this.TextBox1.Text;
}
Yazdığımız kodlar ile Reflector’ın bize verdiği kodlar tam olarak aynı değil. Bu durum zaten çok normal. Çünkü MSIL koduna çeviri esnasında aslında çoğu şey değişiyor. Örneğin tanımladığımız değişkenlerin bize özel olan isimlendirmeleri yok oluyor veya bizim kullandığımız bazı kısa metotlar uzun şekilleri ile yazılabiliyor. Hatta özellikle VB içerisindeki casting kolaylıkları Compile esnasında farklı değişikliklere neden olabiliyor. Bu durumda De-Compile ile aldığımız kod da yazdığımız koddan biraz farklı oluyor. Yine de elimizde çalışır durumda bir kod olduğuna kesin gözü ile bakabiliriz.
Nasıl engelleriz? Obfuscation!
Herhalde çoğunuz “tüm kodlarımız gözler önünde” endişesi içerisindesiniz. Aslında durum gerçekten de öyle. Tabi bu durumun birçok faydası var. Kişisel olarak itiraf etmek gerekirse farklı yazılımları De-Compile ederek çok şey öğrendiğimi söyleyebilirim. Bir defasında da kendi ürettiğimiz bir yazılımı De-Compile etmemiz gerekmişti, gerçekten hayat kurtarmıştı. Peki bunu nasıl engelleyebiliriz? İlk olarak şunu açıkça belirtiyim, herhangi bir .NET uygulamasından MSIL kodunun alınmasını engellemenin hiçbir yolu yok. Yapabileceğimiz tek şey MSIL kodunun okunabilirliliğini azaltmak için işlevsel olarak aynı işi gören fakat daha karışık bir MSIL kodu yaratmak. Bu işlem obfuscation olarak adlandırılıyor.
Obfuscation ile ilgili sektörde çok sayıda ücretli yazılım bulabilirsiniz. Biz bunlardan Xenocode'aait Postbuild 2008 adındaki ticari yazılımı kullanarak obfuscation ile neler yapabildiğimize bakacağız. XenoCode’u ilk açtığımızda karşımıza hemen bir uygulama listesi geliyor. Bu listeye bir önceki adımda kendi hazırladığımız EXE dosyasını ekleyerek uygulamanın üst menüsünden “Protect” tabına geçiyoruz. Burada sadece Windows’da çalışacak EXE dosyalarına uygulanabilecek özel bir koruma yöntemi olan “Surpress ILDASM” seçeneğinin işaretini kaldırmamız gerek. Bu seçenek DLL’lere zaten uygulanamayacaktır. Ekranın sağ tarafında korumak istediğimiz sınıfların ve metodların bir listesini işaretleyebiliyoruz. Tüm ayarları tamamladıktan sonra uygulamanın sağ altındaki “XenoCode Application” düğmesine basıyoruz.

Obfuscation işlemi için yollardayız
Obfuscation işlemini tamamladıktan sonra sıra geldi testlerimizi yapmaya. İlk olarak uygulamamızı ILDASM ile açarak bakalım MSIL kodumuz ne hale gelmiş.
[MSIL]
.method private instance void x44d0c0526a414989(object xe0292b9ed559da7d,
class [mscorlib]System.EventArgs xfbf34718e704c6bc) cil managed
{
// Code size 23 (0x17)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication1.xaa4f033827d75b4d::get_x029e304eb4c44750()
IL_0006: ldarg.0
IL_0007: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox WindowsApplication1.xaa4f033827d75b4d::get_x77691a2cfb8f8048()
IL_000c: callvirt instance string [System.Windows.Forms]System.Windows.Forms.TextBox::get_Text()
IL_0011: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
IL_0016: ret
} // end of method xaa4f033827d75b4d::x44d0c0526a414989
Gördüğünüz gibi aslında çok büyük bir değişiklik yok. Sadece sınıfların ve metodların isimleri değiştirilerek karışık isimler verilmiş. Aynı uygulamayı Reflector ile açtığımızda ise aşağıdaki kodları elde ediyoruz.
[VB]
Private Sub x44d0c0526a414989(ByVal xe0292b9ed559da7d As Object, ByVal xfbf34718e704c6bc As EventArgs)
Me.x029e304eb4c44750.Text = Me.x77691a2cfb8f8048.Text
End Sub
[C#]
private void x44d0c0526a414989(object xe0292b9ed559da7d, EventArgs xfbf34718e704c6bc)
{
this.x029e304eb4c44750.Text = this.x77691a2cfb8f8048.Text;
}
Kodlar epey okunurluluğunu kaybetmiş durumda. Bizim örneğimizde sadece tek bir satır kod bulunduğu için neyin ne olduğunu anlamak çok zor olmuyor. Fakat binlerde satırdan oluşan uygulamaların kodlarından anlaşılabilir bir sonuç çıkarmak neredeyse imkânsız olacaktır.
Hepinize kolay gelsin.