Eğer bir React Native veya Cordova uygulamasını standart bir tersine mühendislik aracında açarsanız, genellikle küçültülmüş (minified) ancak yine de okunabilir bir JavaScript paketi bulursunuz. Bunu formatlarsınız, API çağrılarını izlersiniz ve işiniz çoğunlukla biter. Aynı şeyi release olarak derlenmiş bir Flutter uygulamasıyla denediğinizde, tamamen farklı, çok daha karanlık bir gerçekle karşılaşırsınız: libapp.so.
AOT Derleme Duvarı
Flutter yerel (native) arayüz bileşenlerine köprü kurmaz; render motorunu (Skia veya Impeller) kullanarak her pikseli kendisi çizer. Daha da önemlisi, release modundaki Dart kodu doğrudan yerel ARM/x86 makine koduna (AOT - Ahead-of-Time) derlenir. Standart Android uygulamaları için Dalvik/ART gibi bir ara bytecode yoktur. Elde ettiğiniz şey, bir ELF paylaşımlı nesnesinin (shared object) içine paketlenmiş çıplak makine komutlarıdır.
Analist için işleri daha da kötüleştiren şey, Dart'ın derleyicisinin agresif bir şekilde optimize edilmiş olmasıdır. Meta verileri (metadata) soyar, kullanılmayan kodu kaldırır (tree shaking) ve yapıları düzleştirir. C++ binary'lerinde güvenebileceğiniz standart RTTI'yi (Çalışma Zamanı Tip Bilgisi) kaybedersiniz.
Nesne Havuzu (Object Pool) ve Isolate Mimarisi
libapp.so dosyasını Ghidra veya IDA Pro'ya yüklediğinizde, standart C tarzı fonksiyon prologları veya standart çağrı sözleşmeleri görmezsiniz. Dart kendi ABI'sini kullanır. Veriler sadece standart yazmaçlarda (registers) aktarılmaz; Dart büyük ölçüde bir Nesne Havuzuna güvenir.
Derlenmiş kod, bellek adreslerini veya dizgileri (strings) sabit kodlamak (hardcoding) yerine, bu Nesne Havuzu içindeki dizinlere başvurur. Uygulamayı derlemek için kullanılan Dart SDK sürümünün tam yapısını bilmeden, statik analiz araçları bu dizinleri anlamlı dizgilere veya fonksiyon işaretçilerine eşleyemez. Sonu gelmez bir ofset atlamaları denizi gibi görünür.
; A typical stripped Dart AOT assembly snippet looks meaningless
LDR X0, [X28, #0x10] ; Loading from the Isolate's Thread Local Storage
ADD X0, X0, #0x48 ; Offset into the object pool
BL 0x7fa28b4c ; Jump to an unresolved functionNasıl Kırarız?
Standart araçlar başarısız olur, bu yüzden özel araçlar oluşturmalı veya kullanmalıyız. doldrums veya blutter gibi araçlar, doğrudan Dart snapshot yapısını ayrıştırmak için açıkça tasarlanmıştır. Belirli Dart SDK sürümünün iç yapılarını pattern-matching ile eşleştirerek, Nesne Havuzunu çıkararak ve çapraz referansları (cross-references) yeniden inşa ederek çalışırlar. Sınıf adlarını ve metot imzalarını ancak o zaman görmeye başlayabilirsiniz.
Sonuç Yerine
Flutter farkında olmadan "bilinmezlik yoluyla güvenlik" (security through obscurity) açısından devasa bir katman sağlar. Yerel kodu tersine mühendislik yapmak hiçbir zaman imkansız olmasa da, Dart AOT'nin devasa mimari farkı çıtayı büyük ölçüde yükseltir; 30 dakikalık basit bir egzersizi, özel araçlar ve sağlam bir ABI bilgisi gerektiren, günlerce süren derin bir analize dönüştürür.