Gelecegi yazanlar logo

Bloga geri dön

Android

Android Uygulamalarında Dinamik Analiz -2

Geleceği Yazanlar’da Android uygulamalarında dinamik analiz tekniklerini derinlemesine inceleyerek güvenlik açıklarını tespit etmek için hemen okuyun!
Blog image

İlk yazımızda, Android uygulamalarında dinamik analiz yöntemlerini ve çeşitli araçlar kullanarak güvenlik açıklarını nasıl tespit edebileceğimizi incelemiştik. Bu yazıda ise, UnCrackable2 uygulamasının incelemesini yapacağız.


UnCrackable 2 Uygulamasını Dinamik Analiz ile Çözme

Uygulamayı analiz etmeye, her zamanki gibi, AndroidManifest.xml dosyasını inceleyerek başlıyoruz. Bu dosya, uygulamanın temel yapı taşlarını ve bileşenlerini tanımlayan önemli bir dosyadır. 


MainActivity sınıfı, uygulamanın başladığında ilk görülen ekranını temsil eder. Bu aktivite, android.intent.action.MAIN filtresi ile uygulama başlatıldığında tetiklenir. Manifest dosyasını inceledikten sonra, bir sonraki adımımız MainActivity sınıfını incelemek olacak. MainActivity, uygulamanın ana ekranını kontrol eder ve kullanıcının girdiği şifreyi doğrulamak için kullanılan mekanizmanın temelini oluşturur.

Uygulamayı açtığımızda, root kontrolü nedeniyle kapanır. İlk yazımda bunun nasıl atlatılabileceğini detaylı bir şekilde anlatmıştım. Aşağıdaki Frida scriptini çalıştırarak bu adımı geçebilirsiniz.



Frida Scripti:



Şifre Kontrolü ve MainActivity.java

Öncelikle, MainActivity.java dosyasındaki verify() fonksiyonu ve this.m.a(obj) fonksiyonu arasındaki ilişkiyi inceleyelim:

  • this.m nesnesi, CodeCheck sınıfına ait bir nesne.
  • this.m.a(obj) fonksiyonu, kullanıcı tarafından girilen şifreyi alır ve doğrular. Bu fonksiyon, aslında CodeCheck sınıfındaki bar(byte[] bArr) fonksiyonuna bağlanır.

Burada dikkat çeken nokta, bar() fonksiyonunun native (yerel) bir fonksiyon olmasıdır. Yani, bu fonksiyonun bir kısmı, Java yerine yerel kütüphanede yazılmıştır.


CodeCheck ve Bar Fonksiyonu Analizi

this.m.a(obj) fonksiyonunun çalışması sırasında, CodeCheck sınıfındaki bar(byte[] bArr) fonksiyonu devreye girer. Bu fonksiyon, yerel bir kütüphaneden çağrılarak, kullanıcının girdiği şifreyi, kütüphanede saklı olan gizli şifreyle karşılaştırır.

bar() fonksiyonu, strncmp gibi karşılaştırma fonksiyonları kullanarak şifrenin doğruluğunu kontrol eder. Yani, esas doğrulama işlemi bar() fonksiyonu içinde gerçekleşir.

Doğru şifreyi bulabilmek için yerel kütüphane olan libfoo.so dosyasını analiz etmek gereklidir. Bu modülün detaylı incelenmesi, içinde kullanılan algoritmaların ve gizli şifrenin belirlenmesine yardımcı olabilir.



libfoo.so’yu İnceleme

Adım 1: APK ve libfoo.so’yu Çıkartma

APK’dan libfoo.so’yu çıkartabilmek için, aşağıdaki adımları takip edebilirsiniz:

APK dosyasını analiz etmeye başlamadan önce, APK’yı apktool gibi bir araçla decompile etmemiz gerekiyor. APK’yı decompile etmek, içinde yer alan dosyalara ve kütüphanelere kolayca erişmemizi sağlar.

APK’yı decompile etme komutu:

  • apktool d UnCrackable-Level2.apk


Bu komut, APK dosyasını açar ve içerisindeki libfoo.so gibi yerel kütüphaneleri bulmamıza yardımcı olur. Çıkarılan dosyaların bulunduğu klasörde, libfoo.so dosyasını arayarak çıkartabilirsiniz.

  • libfoo.so dosyasını lib klasörü içerisinde armeabi-v7a, arm64-v8a ya da diğer mimariler altında bulabilirsiniz.
  • Mimari türüne göre doğru libfoo.so dosyasını seçmemiz gerekecek (örneğin, arm64-v8a).



Adım 2: Binary Ninja ile libfoo.so’yu Analiz Etme

libfoo.so dosyasını elde ettikten sonra, binary ninja gibi bir tersine mühendislik aracını kullanarak bu dosyanın içeriğini analiz edebiliriz. 

binary ninja ile analiz süreci:

  • libfoo.so dosyasını Binary Ninja’ya yükleyin. Dosyayı yükledikten sonra, içerisinde geçen belirli kod parçalarını arayarak incelemeye başlayabilirsiniz.
  • Binary Ninja’nın arama fonksiyonunu kullanarak, source code içinde yer alan ve önemli olabilecek metriklerden biri olan “CodeCheck” terimini arayabilirsiniz. Bu tür anahtar kelimeler genellikle belirli işlevlerle ilişkilidir ve analiz yaparken size yardımcı olabilir.



  • Binary Ninja, yüklediğiniz dosyanın tüm fonksiyonlarını analiz eder ve bu fonksiyonları listeler. Bu listeyi gözden geçirerek, şüpheli veya önemli fonksiyonları belirleyebilirsiniz. Bar fonksiyonunun içeriğini detaylı şekilde inceleyerek, şifre doğrulama sürecinin nasıl çalıştığını anlayabilirsiniz. Genellikle, bu tür fonksiyonlar, kullanıcı tarafından girilen veriyi (örneğin bir şifreyi) gizli bir değerle karşılaştırmak için strncmp() gibi fonksiyonlar kullanır.




Adım 3: Bar() Fonksiyonunu Anlamak

bar() fonksiyonu, kullanıcıdan alınan şifreyi gizli bir şifreyle karşılaştırmak için kullanılan yerel bir fonksiyondur. Şifre doğrulama sürecinde bar() fonksiyonu, kullanıcının girdiği şifreyi önceden belirlenmiş bir gizli şifreyle karşılaştırarak doğrulama yapar. Bu gizli şifre bellek içinde saklanır ve var_30 veya eax_2 gibi bellek alanlarında bulunur.

Şifre doğrulama, strncmp fonksiyonu kullanılarak yapılır. Bu fonksiyon, girilen şifrenin ilk 23 baytını gizli şifreyle karşılaştırır ve eşleşip eşleşmediğini kontrol eder. Bu karşılaştırma işlemi sayesinde, girilen şifrenin doğru olup olmadığını kolayca tespit edebiliriz.

Eğer kullanıcı tarafından girilen şifre, gizli şifreyle tam olarak eşleşirse, fonksiyon başarılı bir doğrulama sonucu döndürür ve result.b değeri 1 olarak ayarlanır. Eğer şifre yanlışsa, result sıfır olarak döndürülür.



Frida Scripti: Şifre Doğrulama Sürecini İzlemek

Frida ile, bar() fonksiyonunun nasıl çalıştığını dinleyebiliriz ve şifre doğrulama sürecinde hangi parametrelerin kullanıldığını takip edebiliriz. Aşağıda, şifre doğrulama sürecini izleyen bir Frida scripti örneğini bulacaksınız. Bu script, bar() fonksiyonu çağrıldığında kullanıcıdan alınan şifreyi yazdırır ve şifrenin doğru veya yanlış olduğunu konsola yazar.


Frida Scripti:


Java.perform(function() {

  send("Hooked exit()");


  var system = Java.use("java.lang.System");

  system.exit.implementation = function() {

    send("Root Bypass");

    send("Hooked function");


    Interceptor.attach(Module.getExportByName('libfoo.so', 'strncmp'), {

      onEnter(args) {

        if (Memory.readUtf8String(args[0]).startsWith("AAAAAAAAAAAAAAAAAAAAAAA")) {

          send("Secret String: " + Memory.readUtf8String(args[1]));

        }

      }

    });

  };

});Script:



  • strncmp Fonksiyonunu Dinleme

strncmp fonksiyonu, genellikle iki diziyi belirli bir uzunlukta karşılaştırmak için kullanılır. Özellikle şifre doğrulama işlemlerinde bu fonksiyon sıkça kullanılır. Frida ile bu fonksiyonu dinleyerek, şifre doğrulama sürecindeki parametreleri izleyebiliriz.



  • onEnter(args):

onEnter, strncmp fonksiyonu çağrılmadan önce çalıştırılır. Burada, args[0] kullanılarak kullanıcı tarafından girilen şifre alınır. Bu şifre bellekteki diziden okunur ve bir string olarak alınır.


  • if (Memory.readUtf8String(args[0]).startsWith("AAAAAAAAAAAAAAAAAAAAAAA"))

Kullanıcı tarafından girilen şifrenin ilk kısmı kontrol edilir. Eğer şifre, "AAAAAAAAAAAAAAAAAAAAAAA" dizisiyle başlıyorsa, bu doğru şifreyi tespit etme aşamasıdır. Bu kontrol, disassembled kodda belirtilen 23 karakterlik gizli diziyi temsil etmektedir.


  • send("Secret String: " + Memory.readUtf8String(args[1])):

Eğer şifre doğruysa ve karşılaştırma başarılıysa, ikinci parametre olan gizli şifre args[1] konsola yazdırılır. Bu, şifre doğrulama sırasında karşılaştırılan gizli şifredir ve Frida scripti sayesinde bu değeri izleyebiliriz.


Disassembled Kod ve strncmp Fonksiyonu:

Scriptin içinde bahsedilen strncmp fonksiyonu, eax_2 ve &var_30 dizilerini karşılaştırıyor. Bu karşılaştırmanın uzunluğu ise 0x17, yani 23 karakter. Bu durumda, strncmp fonksiyonu, dizilerin ilk 23 karakterini karşılaştırır.


else if (strncmp(eax_2, &var_30, 0x17) == 0)


  • Bu kısımda, iki dizi karşılaştırılır ve 0x17 (23) karakterle yapılır. Eğer bu diziler eşleşirse, doğrulama başarılı olur ve şifre doğru kabul edilir.
  • Frida scriptindeki startsWith("AAAAAAAAAAAAAAAAAAAAAAA") kontrolü de tam olarak bu 23 karakter uzunluğunda bir karşılaştırmayı yapmaktadır.



Bu yazıda, UnCrackable2 uygulamasının dinamik analizini adım adım gerçekleştirdik. Frida ve Binary Ninja gibi güçlü araçlar kullanarak, uygulamanın yerel kütüphanesi olan libfoo.so dosyasını detaylı şekilde inceledik.

Şifre doğrulama mekanizmasını analiz ederek, strncmp fonksiyonunun nasıl çalıştığını ve hangi parametrelerle işlem yaptığını tespit ettik. Frida scripti sayesinde, uygulamanın sakladığı gizli ifadeyi ele geçirdik ve doğrulama sürecini başarıyla manipüle ettik.


Ahmet Buğra Demirel

|

10 Haziran 2025