Android ARM native library emulator with unidbg

Günümüzde mobil uygulamalar hem performans hem de güvenlik öncelikli işler için yaygın bir şekilde native kütüphaneleri kullanmaktalar. Native kütüphaneler’i decompile etmek java decompile etmekten çok daha zor.

Native kütüphaneler arm mimarisi olduklarından x86 mimarisine göre anlaşılmaları da çok daha zor olmakta. Bu noktada statik analizde kütüphanenin tam olarak ne iş yaptığını anlamak çok zor olabilmekte.

Dinamik analizde frida gibi farklı yöntemler kullanılabilse de her zaman arkada bir android cihaz çalıştırarak native kütüphaneyi debug etmek çok pratik bir yöntem değil. Bu sebeple farklı bir teknik kullanacağız. Bu noktada unicorn a başvuruyoruz.

Unicorn Engine ve Unidbg Nedir?

Unicorn engine multi-architecture CPU emulatorüdür. Unicorn qemu alternatifi olarak düşünülebilir. Unicorn Engine’den yararlanarak geliştirilmiş onlarca proje mevcut bu listeye şuradan erişebilirsiniz.
Bu projelerden biri de unidbg. Unidbg arm32 ve arm64 android native kütüphaneleri emulate etmenize olanak sağlıyor.

Unidbg geliştirilmeye devam edilen bir proje ve ios desteği üzerine çalışılıyor. Unidbg kurulumu için githubdan projeyi clone ediyoruz.

git clone https://github.com/zhkl0228/unidbg.git

Projeyi çalıştırmak için IntelliJ IDEA yı yüklememiz gerekiyor.
Buradan IntelliJ IDEA’yı indirebiliriz; https://www.jetbrains.com/idea/download/
Sonra tar dosyasını çıkartıp /bin klasörü altında ./idea.sh ile programı çalıştırıyoruz.

Unidbg projemizi açıp sync olmasını bekledikten sonra proje içerisinde test için oluşturulmuş kütüphaneleri inceliyoruz. src.com.bytedance.frameworks.core.encrypt altında bulunan bytedance a ait bir kütüphaneyi yada org.telegram.messenger altında telegrama ait native kütüphanelerden birini seçerek kütüphaneyi emulate edebiliriz.

Kütüphaneler’i debug edebilmek için yeni bir konfigürasyon eklememiz gerekiyor bu sebeple Add New Configuration ile yeni bir ayar oluşturuyoruz.

VM options kısmına;

-Djava.library.path=prebuilt/os -Djna.library.path=prebuilt/os

yazıyoruz fakat farklı kütüphanelerde bu ayar hata verebilir bu seeple os yazan kısmı linux64, win32, win64, osx64 ile değiştirmeniz gerekebilir.

Java kodunun iletişim kurduğu libttencrypt.so kütüphanesinin kendisinin de /unidbg/src/test/resources/example_binaries/ dizini altında olduğunu görüyoruz. Kütüphanenin ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked olduğunu da burdan görebiliriz.

Bir arm kütüphanesini android bir cihaza gerek kalmadan emulate edebiliriz.

Burada ise kütüphanenin fonksiyonlarını tespit edebilmek aldığı parametrelelerin veri tipini ve return fonksiyonunun ne tip bir veri yapısı döndüğünü tespit ettikten sonra java bytecode da bu fonksiyonu tarif etmek gerekiyor.

Örnek kütüphanemizde callStaticJniMethod ile kütüphanede çağırılan ttEncrypt([BI)[B fonksiyonunun parantez içerisindeki [BI sebebiyle bir byte array’i aldığını ve yine byte arrayi return ettiğini görebiliyoruz.

Kütüphanede sonuç odaklı olarak istediğimiz fonksiyonu hook edebileceğimiz gibi çalışma esnasında kullanılan memcpy gibi fonksiyonları da hook edebilir inceleyebiliriz.