String Deobfuscation with Invoke ~ Python [TR]
Selamlar, bu yazımda “Crypto Obfuscator” adlı yazılımın string korumasını Python’da dnlib ve Reflection ikilisini kullanarak nasıl deobfuscate edebileceğimizi anlattım. Maksat değişiklik olsun…
Dosya Analizi
Crypto Obfuscator’un deneme sürümü ile sadece string encryption işlemine soktuğumuz dosyayı dnSpy üzerine açalım.
Rastgele bir event’e gittiğimizde içinde bulunan stringlerin şifrelendiğini ve junk kodlar bıraktığını gördük (Junk kodların temizlenme işlemi bu yazıda yapılmayacak):
Anahtar değeri decryption methoduna parametre olarak gönderiyor ve geri dönen değer ile işini sürdürüyor.
Yapılacaklar
- Python kütüphanelerinin kurulumu (ve dnlib.dll dosyasının dahil edilmesi)
- String decryption metodunun ve sınıfının otomatik olarak bulunması
- String encrypted yerleri saptamak ve INVOKE atarak decrypted değerin alınması
- Alınan decrypted değerin yerleştirilmesi
- Kaydetme
Import ve Load
Aynı klasör içerisinde tutuyorum bütün dosyalarımı. Önce gerekli kütüphaneyi indirelim.
pip install pythonnet
Reflection kütüphanelerini import edelim.
Main bloğunda dnlib.dll dosyamızı referans olarak ekleyelim. module ve assembly adlı değişkenlerimize de obfuscated uygulamayı load edelim.
Neden ayrı ayrı iki modül yüklüyoruz konusuna ufak bir açıklama geçeyim. assembly, Reflection kütüphanesinden Invoke işlemi için yüklendi (dnlib’de bu özellik yok). module, düzenleme işlemleri için.
Decryption Metodu
Bu kısımda sadece programa decryption metodunu bulduracağız. Zaten invoke işlemi ile decrypt edeceğimiz için decryption algoritmasını yazmamıza gerek yok.
dnSpy ile tekrar açıp analiz edelim, decryption metodunun nasıl ayırt edici özellikleri varmış bakalım. Decryption metodumuz burada:
Şimdi programın okuyabileceği şekil olan IL kısmına geçelim. (Sağ Tık > Edit IL Instructions)
En ayırt edici özellikler olarak methodun
- IL instruction’larının uzunluğu
- ve 2. indexteki OpCode
IL uzunluğu = 107
- OpCode = LdcI4
- OpCode = Ldsfld
Kodumuzu açıklayalım :
- 1) Diğer fonksiyonlarımızın da erişebilmesi için iki değişkenimizi global anahtar kelimesi ile tanımlıyoruz.
- 2) https://docs.microsoft.com/en-US/dotnet/api/system.reflection.bindingflags?view=netcore-3.1
- 3) Yüklediğimiz modülün (yani obfuscated binary’nin) Type’ları yani Class’ları arasında dolaşıyoruz. Hemen altında da Type’ların methodları içerisinde…
- 4) Kodun devamında method.BODY.INSTRUCTIONS diyoruz. Dolayısıyla hata çıkartmaması için eğer bir body’si yoksa atla işlemini sağlıyoruz.
- 5) Evet, burda ilk koşulumuz olan eğer bulunduğun method’un IL sayısı 107’den az ise atla işlemini sağlıyoruz.
- 6) İkinci koşulumuzu sağlamak üzere IL’lerin arasında dolaşıyoruz.
- 7) Eğer bulunduğun instruction LdcI4 (LdcI4.1, LdcI4.2 diye gidiyor, basite indirgemek için IsLdcI4() fonksiyonunu kullanıyoruz.) ve bundan iki sonra Ldsfld OpCode’u varsa …
- 8) classInstance atama işlemini daha sonrasında decryption metodunun bulunabilmesi için atıyoruz. “for type in module.Types” ile yaptığımızın aynısının Reflection ile olan hali. Invoke edilecek metodu yani Decryption metodunu “MethodInfo” türünde alabilmek adına burdaki işlemleri yapıyoruz.
Decryptor Method
Decryption methodumuzu bulduktan sonra Decrypt metodunun yapacağı tek şey şifrelenmiş alanları bularak, işe yarayan parametreyi decryption metoduna gönderip invoke ediyoruz. Çıkan sonucu yerine yerleştiriyoruz.
Yapmamız gereken ilk şey obfuscated bölümleri tanımak. dnSpy’ı açıp bakıyoruz.
Obfuscated bir yerin IL instruction’larına baktığımızda sadece metoda sayısal bir ifade gönderildiğini göreceğiz. Ama birden çok metot böyle çalışabilir. İşte bu kısımda önceden tanımladığımız “stringMethodName” değişkeni işimize yarayacak. “call” OpCode’lu kısmın Operand’ında eğer atadığımız “stringMethodName” geçiyorsa burası obfuscated bir alandır diyebiliriz.
O zaman bunun ayırt edici özellikleri :
- Bulunduğun index LdcI4 ve bundan bir sonraki instruction OpCode’u call ise
- call OpCode’una sahip instruction’ının Operand’ı stringMethodName’i içeriyorsa
Kodu yazalım :
Şimdi yapmamız gereken şey argüman olarak göndereceğimiz şeyin değerini çekmek ve Invoke edip gelen değeri yerine yerleştirmek :
Gerekli dosyalar ve kodun tamamı :
https://github.com/Rhotav/Python-Method-Invoker