Smali'de invoke-virtual için basit bir açıklama

Kerem Aydın·8 Temmuz 2026·⏱4 dk

invoke-virtual, bir örnek sanal yöntemi çağırmak için kullanılan bir DEX talimatıdır (obj.method() karşılığı). Belirli uygulama, vtable aracılığıyla nesnenin gerçek sınıfına göre çalışma zamanında seçilir; argümanlar register'larda iletilir ve sonuç move-result* aracılığıyla döndürülür.

invoke-virtual içindeki süslü parantezlerdeki ilk register genellikle nesnedir (this), geri kalanları ise argümanlardır.

Smali'de invoke-virtual nasıl okunur

Tipik bir Smali satırı: text invoke-virtual {v0, v1}, Lcom/example/User;->setName(Ljava/lang/String;)V

Açıklama:

  • invoke-virtual — çağrı türü (sanal).
  • {v0, v1} — register'lar: v0 — nesne referansı, v1 — argüman.
  • Lcom/example/User; — yöntemin bildirildiği sınıf (imza için).
  • setName — yöntem adı.
  • (Ljava/lang/String;)V — imza (giriş: String, dönüş: void).

Daha basit ifadeyle: bu, user.setName(name) ifadesinin düşük seviyeli eşdeğeridir; burada belirli yöntem geçersiz kılınabilir.

"Kaputun altında" neler oluyor — vtable ve dağıtım

Çağrı algoritması (basitleştirilmiş):

  1. Bir register'da (örneğin v0) nesneye referans saklanır.
  2. Bu referans üzerinden nesnenin gerçek sınıfı belirlenir (talimatta belirtilenden farklı olabilir).
  3. Sınıfın sanal yöntemler tablosu (vtable) vardır.
  4. Yöntem indeksi (DEX meta verilerinden) kullanılarak gerekli uygulama bulunur.
  5. Bulunan yöntemin koduna atlama yapılır.

Önemli: Nesne bir alt sınıfın örneği ise, Smali'de temel sınıf belirtilmiş olsa bile alt sınıfın geçersiz kıldığı yöntem çağrılır.

invoke-virtual ile sonraki move-result* arasına başka talimatlar eklenemez. Bu, DEX doğrulama hatasına neden olur.

Register'lar, move-result ve /range

DEX'te JVM yığını yoktur — her şey register'lar aracılığıyla gerçekleşir. Çağrı formu, nesneyi ve argümanları süslü parantezler içinde iletir. Yöntem bir değer döndürüyorsa, sonuç hemen invoke-virtual'dan sonra gelen move-result talimatıyla alınır.

Örnek: text invoke-virtual {p0, p1, p2}, Lpkg/Class;->sum(II)I move-result v0

Argüman çok fazla ise ve art arda register'larda bulunuyorsa, register aralığını belirten invoke-virtual/range kullanılır.

invoke-virtual'ın diğer invoke-* talimatlarından farkları

Farklılıkların kısa tablosu

Smali'deki invoke türlerinin karşılaştırılması

TalimatHangi yöntemler içinNesne gerekli miPolimorfizmJava karşılığı
invoke-virtualNormal sanal yöntemlerEvetEvetobj.method()
invoke-directYapıcılar, private, superEvetHayırnew, this(), super.method()
invoke-staticStatik yöntemlerHayırHayırClass.method()
invoke-interfaceArayüz yöntemleriEvetEvet (arayüz tablosu üzerinden)iface.method()
invoke-superSüper sınıf uygulamasını çağırmaEvetHayır (sabittir)super.method()
invoke-virtual/rangeAynı, çok sayıda argümanlaEvetEvet—

Analiz ve yamalama sırasında bu nerede işe yarar

  • İlgilenilen mantığın çağrısını bulma: Yöntem imzalarını arayıp invoke-virtual çağrılarına bakmak, yöntemin gerçekten nerede kullanıldığını anlamak için hızlı bir yoldur.
  • Hook'lar ve enjeksiyonlar (Frida, Xposed): Çağrı türünü bilmek, uygulamayı doğru şekilde ele geçirmeye yardımcı olur.
  • APK yamalama: invoke-virtual'ı başka bir çağrıyla değiştirebilir veya yöntemi değiştirebilirsiniz, ancak semantiği dikkate almanız gerekir (statik yöntemler mi yoksa örnek yöntemler mi).

Yama örneği (sonucun her zaman true olmasını sağlamak):

  • Orijinal: text invoke-virtual {v0}, Lcom/example/Feature;->isEnabled()Z move-result v2
  • Yama: text const/4 v2, 0x1 (invoke-virtual ve move-result'ı silin veya yorum satırı yapın)

Smali analiz ederken önce invoke-* türünü belirleyin, ardından çağrılan yöntemin gövdesini inceleyin — bu, anlamayı hızlandırır.

Sık yapılan hatalar

  • invoke-virtual ve move-result arasına talimat eklemeye çalışmak — doğrulama hatalarına yol açar.
  • Talimatta belirtilen sınıfın mutlaka nesnenin sınıfı olduğunu sanmak. Aslında uygulama, nesnenin gerçek türüne göre seçilir.
  • Sonucu move-result olmadan almaya çalışmak — bu durumda değer register'a aktarılmaz.

SSS

  • null üzerinde invoke-virtual çağrılırsa ne olur?
    Java'daki gibi — NullPointerException (çalışma zamanında NPE fırlatılır).

  • Bazen talimatta temel sınıf görülüyor ama başka bir sınıfın yöntemi çağrılıyor, neden?
    Talimatta imza için sınıf belirtilir; gerçek uygulama çalışma zamanında nesnenin sınıfına göre belirlenir.

  • invoke-virtual/range ne zaman kullanılır?
    Çok sayıda argüman register'larda art arda geldiğinde — /range, büyük bir register bloğunun iletimini kolaylaştırır.

  • invoke-virtual'ı invoke-static ile değiştirebilir miyim?
    Teorik olarak evet, ancak statik yöntemi hazırlamanız gerekir (örneğin, this için bir parametre eklemek) ve çağrıları ile imzaları düzeltmeniz gerekir — aksi takdirde uygulama bozulur.

Gerekirse, belirli bir Smali parçasını inceleyip hangi uygulamanın çağrılacağını ve nasıl doğru yamanacağını gösterebilirim.