.NET için De-Compile işlemleri ve Obfuscation

0 dakikada yazıldı

33167 defa okundu

Düzenle

İ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
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.
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ş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.