Rehber UPX Manuel Unpacking - Packer Nedir, Nasıl Çalışır?

Merhaba,

Bu rehberde temel olarak packing ve unpacking nedir, ne için yapılır değinmeye çalışacağım. Ayrıca konuyu daha anlaşılır kılmak adına UPX ile packlenmiş bir yazılımı basitçe manuel nasıl unpack edebileceğinizi göstereceğim.

Ama öncelikle işin mantığını anlamamız gerekiyor. Bunun için öncelikle kendimize soralım. Packing nedir, programlar neden packlenir ve tersine mühendisler tarafından unpack edilmeye çalışılır? Aslında bunun cevabını kendi kendimize de verebiliriz.

Packing adından da anlaşılacağı üzere genel itibariyle bir programı başka bir program ile paketleyerek yaptığımız şeye deniliyor. Genellikle bunu yapanlar programının kırılmasını istemeyen kimseler, çeşitli string bilgilerini gizlemek isteyenler, boyut düşürenler, programın hangi dil ile yazıldığının ortaya çıkmasını engellemek isteyenler, decompile edilmesini engellemek isteyenler, zararlı yazılım analizinde süreci sekteye uğratma ve anti analiz çabaları şeklinde daha uzun uzun çeşitli kullanımları sayabiliriz.

Packerlar genel itibariyle iki şekilde çalışır. Ana programınız özel bir algoritma yardımıyla sıkıştırılır ve bunu açabilecek bir diğer programın içerisine dahil edilir. Çalıştırma esnasındaysa öncelikle çıkartıcı program devreye girer, programın kendisini belleğe çıkartıp kendisi aradan çıkar. Daha sonra program çalıştırılır. Bu tüm packerlarda aynı olmasa da genel itibariyle UPX gibi basit mantıkla çalışanlarda böyle işler. Dikkat, çıkarma işlemi diskte değil bellekte gerçekleşiyor. Bunu da karıştırılmaması için belirtmiş olalım.

Velhasıl kelam, durumu daha iyi anlatmak için bir örnek vermek istiyorum. C dilinde printf kullanarak basitçe konsol mesajı görüntüleyen bir program yazalım. Ben burada Embarcadero Dev C++ kullandım IDE olarak. Siz sormadan söylemiş olalım 😊 Programın içinde ayrıca “gizlibilgi” adında bir değişken tanımlayıp içine birkaç şey yazdım.

Programı derleyip çalıştırdım, gizlibilgi içindeki string ifadeyi ekrana bastırmadığımız için yazmadı gördüğünüz gibi. Şu anlık gizli bilgimiz gerçekten de gizli sanki? Peki bu bilgi programdan bir şekilde elde edilebilir mi? İsterseniz haydi ona bakalım.

1.PNG


Ta daa. Aşırı gizli bilgimiz programı sıradan “HxD” gibi bir Hex Editör aracılığıyla açınca ortaya çıkıyor. Neden mi? Çünkü program bunu derlenince sandığınız gibi buhar edip yok etmiyor, içinde bir yerde illa ki saklıyor. Bir de isterseniz bir sonraki görselde dosyamızı basit bir packer olan UPX ile packleyip bakalım.

1.1.PNG


Bunun için basitçe upx.exe –best unpacketbeni.exe komutunu veriyorum. Bütün bunları anlatmamın nedeni, bir program neden packleniyor onu anlamanız.

2.PNG


Şimdi packlenmeyen program ile packlenmiş olan programı DiE (DetectItEasy) üzerine atıp string değerlerini karşılaştıralım.

Soldaki packlenmeyen programın stringlerine baktığımızda oldukça temiz ve olması gerektiği gibi olduğunu görüyoruz. Gizli bilgimiz tamamen ufak bir göz atmayla elde edilebiliyor. Sağda ise UPX ile packlediğimiz hali yer alıyor. Stringler afedersiniz ama yamulmuş. Gördüğünüz gibi gizli bilgimizin ufak bir kısmı ortada, bazı noktaları ise eksik. Hafif daha aşağı kaydırıp biraz daha bakalım.

3.PNG


Durumu daha fazla izah etmeme gerek var mı bilmiyorum.

4.PNG


Basitçe packing, unpacking nedir ve neden yapılır anladıysak yavaşça UPX ile packlenen bir program “manuel” nasıl unpack edilir detaylıca değinmeye başlayalım. Normalde UPX’in yine kendisini kullanarak bunu yapabilirsiniz ama yüksek boyutlu dosyalar söz konusu olduğunda sıkıntı olabiliyor. Bazenleri de her türlü manuele başvurmak zorunda kalabiliyorsunuz.

Bir programı unpack etmeye çalışmadan önce dosyanın kendisinden elde edebileceğiniz kadar bilgiyi elde etmelisiniz. Zira unpack işlemini buna uygun şekilde yapacaksınız. Genel itibariyle birçoğu konunun başında anlattığım mantıkla çalışıyor fakat yine de zaman kaybetmemek adına kontrol etmelisiniz.

4.1.PNG


Şimdi ameliyata geçebiliriz.

Dosyamız 32-bit. Yani 32-bit bir debugger kullanmamız gerekiyor. Ben bu iş için x32DBg isimli debugger hoşuma gittiği için onu kullanacağım. Programımızı sürükleyip atalım. X64/X32DBg yazılımları programı debug etmeden önce her zaman ntdll.dll modülünden başlar. Bizim işimiz ntdll.dll ile değil, programın kendisiyle.

Bu nedenle yukarıdaki ok işaretini kullanarak veya kısayolları kullanarak programı bir kere basıp çalıştırıyoruz.

5.PNG


Evet nihayet programa düştük. İş göreceğim yer burası ve karşımızda bazı Assembly kodlarını görüyorum. Burada şimdi dosyamızı unpack edebilmek için packerların nasıl çalıştığını aklımıza getirmemiz gerekiyor.

Ne demiştik bir packer genelde öncelikle bir programı alır sıkıştırıp diğerinin içine dahil eder, daha sonra çıkartıcı bizim programımızı belleğe çıkartıp aradan çıkar.

X86 Assembly de stack’e veri girişini ve çıkışını ne ile sağlıyoruz hatırlayalım. Evet, pushad (Push All General Registers-Double) ve popad (Pop All General Registers Double) ile. Demek ki UPX, öncelikle verileri stack alanına pushluyor, daha sonra popad ile çıkartıp çalıştırıyor. Kendisi de RET ile bize elveda edip süreci asıl programa devrediyor.

Şu lanet siyah pencereyi aşağıya atıp detaylıca bakmaya başlayalım şimdi.

6.PNG


Şu anda gördüğünüz gibi program çalışmaya başladığında bizi x32dbg 00450F28 adresine atmış. Bu adreste JMP yani Assembly’de atla komutunu ifade eden bir kod var. jmp unpacketbeni.450F44 ile programımız 00450F44 adresindeki ret c komutuna atlıyor. Stack’e baktığımızda halen ntdll.dll de olduğumuzu görüyoruz. Yani özetle programımız bir sonraki çalıştırmamızda bizi istediğimiz yere, yani verileri pushladığı yere ulaştıracak.

Bir kere daha yukarıdaki ok işaretine basıp devam edelim.

7.png


Hopp, işte burası yani 00450D80 aradığımız yer. Programın çalışmadan önce pushlandığı yeri bulduk. İşte bizim programımız burada içe aktarılıyor. Stack’e baktığımızda kernel32.dll ile iş görüldüğünü fark ediyoruz.

E pushlandığına göre, çıkarılması yani poplanması da lazım bunun. Yani programın bittiği noktayı bulmalıyız. Bunun için fazla saçmalamadan aşağıya doğru hafif hafif kaydırıyoruz.

8.PNG


Evet popad’ı bulduk. Aslında hiç kaybetmemiştik, hatırlarsanız buraya iki resim önce bakıyorduk. Adreslere bakarsanız yine oraya geldiğimizi anlayabilirsiniz. Bundan sonrasına dikkatli bakalım şimdi zira ilk program burada bitiyor. Daha sonra asıl programımıza illa bir yerde atlanması gerekiyor.

00450F1A adresindeki push 0 benim dikkatimi çekiyor. Ve onun altındaki JNE unpacketbeni.450F1A. Bu tarz debuggerlarda çalışırken program aşağıdan yukarıya çalışır her zaman. JNE yani Jump Not Equal, eşit değilse atla diyor. Push 0 olana kadar atlama ve çalışması devam edecek programın, 0 olduğunda da atlamayıp düz devam edecek.

Push 0, yani bir sonraki çalıştırmamızda program 00450F1A adresine atlama yapmayacak aksine 00450F23’da yer alan jmp unpacketbeni.4014C0 komutu ile 4014C0'dan devam edecek.

9.PNG


Bahsi geçen 00450F23 adresinin üstüne gelelim. Görüyoruz ki içi boş, yani hava civa. Program henüz pushad kısmında duruyor onu da unutmayalım. Demek ki çalışınca burayı dolduracak. Yani UPX aradan çekilecek 004014C0 adresinde gerçek has program çalışacak.

10.png


Bunun için ne yapıyoruz? Direkt şimdi ok işaretinden çalıştırırsak program çalışmasını bitirir, debugger da kapanır. Bu yüzden SUB ESP yazan satıra masaya yumruğumuzu vurarak bir breakpoint koyalım. Yavaş vurun ama sonra eliniz falan kırılır sorumluluk kabul etmiyorum.

Daha sonra da ok işaretinden çalıştıralım.

11.PNG


Ta daaa, breakpoint attığımız yerde programımız durdu ve istediğimiz yere atladı. Artık özgürüz. Gördüğünüz gibi 004014C0 artık boş değil, içinde gerçek programımız var. Hemen iki tık ile 004014C0 adresine gidelim. Mouse tekerleğini kaydırarak gitmeye çalışmayın, yamulursunuz benden bilmeyin.

12.png


İşte gerçek programımız. Şimdi yapmamız gereken x32/x64dbg aracının en sevdiğim yanı olan Scylla’sını kullanarak burayı dump etmek.

13.PNG


CTRL+I diyoruz ve Scylla’mızı açıyoruz. Dump diyerek kaydediyoruz.

14.PNG


Şimdi programı açmaya gidiyy.

NE AÇMASI MÜBAREK İNSAN. Import table ayarlamadın, DLL’leri içeri aktarmadın. Programı bu haliyle çalıştırırsan aha da aşağıdaki gibi bir şeyle karşılaşırsın. Windows sana hayırlı işler diyip yolu gösterir.

15.PNG


Ne yapıyoruz bunun için, Scylla’ya tekrar gidiyoruz ve önce IAT Autoresearch sonra Get Imports ve Fix Dump diyip dump ettiğimiz dosyayı seçerek programımıza API’lerimizi dahil edip import table ayarını yapmış oluyoruz.

16.PNG


Programımız unpacketbeni_dump_SCY.exe adıyla kaydoluyor. Çalıştırıp bakalım artık hata veriyor mu?

Vermiyor. Tebrikler, kendi başınıza ele güne minnet etmeden UPX’i manuel unpack ettiniz.

17.PNG


Bir de Detect It Easy üzerine atıp bakalım isterseniz. Gördüğünüz gibi tertemiz. Artık debugger’ı kapatabilirsiniz.

18.PNG


Umarım faydalı olmuştur diye düşünüyorum.

Bu yazıyı eğer sonuna kadar sabırla okuyup uyguladıysanız bir nebze packerların çalışma mantığını kavramışsınızdır. Bu sadece işin kaymağı, basit kısmı. Daha gelişmiş packerlar söz konusu olduğunda unpack etmesi de zorlaşabiliyor. Fakat zamanla kurcalaya kurcalaya, araştıra araştıra olacak ve öğrenilecek şeyler bunlar.

Selametle kalın :)
 
Son düzenleme:
Mesela limit türev gibi mi? 12. Sınıfım.
Algoritma, yukarıda denildiği gibi fonksiyonlar, kare kökleri, üslü sayılar, bazı yerlerde doğrusal cebir gibi, asal sayılar, Kriptoloji vb. daha çeşitlendiirlebilir de bunlar temelde baya bir yeterli.
 

Geri
Yukarı