ReVanced Bytecode ve Resource Patch Yazımı
Uygulamaların üzerinde değişiklik yapabiliyoruz ama bunlar sadece değiştirilen Android paketi halinde kapalı bir şekilde var oluyor. Yapılan değişiklikleri göstersek dahi, paylaşılan paket dosyasının sadece o değişikliklere sahip olduğu kesin değil. Bir ReVanced yaması, bir değişikliğin nasıl ve nereyi etkilediğini açık bir şekilde gösterir ve herkes yamaları uygulayabilir. Öncelikle, geliştirme ortamını hazırlayalım.
Araçlar
Geliştirme Ortamı
Bir dizin oluşturup revanced-cli
ve revanced-patches
depolarını klonlayın.
1
2
3
4
5
6
7
8
9
10
11
12
mkdir revanced && cd revanced
repositories=(
"revanced-cli"
"revanced-patches"
"revanced-integrations" (isteğe bağlı)
"revanced-patcher" (isteğe bağlı)
)
for repository in "${repositories[@]}" ; do
git clone -b dev --single-branch --depth 1 https://github.com/revanced/$repository
done
Patches projesinin dizininde ./gradlew build
komutunu çalıştırın.
Authentication hatası alıyorsanız bağlantıdan
read:packages
iznine sahip bir token oluşturun. Verilen tokeni kullanıcı dosyasında.gradle
dizinindegradle.properties
içerisine (yoksa oluşturarak) ekleyin.
1
2
gpr.user = <github kullanıcı adı>
gpr.key = <token>
API check failed for project revanced-patches hatası alırsanız
./gradlew apidump
komutunu çalıştırıp tekrar build edin.
BUILD SUCCESSFUL yazısını gördüyseniz kurulum tamamlandı.
IntelliJ’de Kurulum
IDEA’da CLI projesi açılıp Gradle senkronizasyon işlemi tamamlandıktan sonra MainCommand.kt
dosyasında üçgen sembolü gözüküyor olmalı.
Ardından Proje Yapısı > Modüller kısmından patches projesini modül olarak ekleyin.
Konfigürasyon
Pencereyi kapattıktan sonra Çalıştırma/Ayıklama Konfigürasyonları ayarlarından yeni bir Kotlin konfigürasyonu oluşturun. Ana sınıfı app.revanced.cli.command.MainCommandKt
olarak ayarlayın.
Program komutları kısmını aynı terminalde CLI kullanıyormuş gibi yazıyoruz.
1
2
3
patch
-p ..\revanced-patches\patches\build\libs\patches-<version>.rvp
..\to-be-patched.apk
Gradle türünde bir Before launch komutu ekleyin. Proje olarak patches projesini seçin ve komutlar kısmına build
yazın.
Debug Süreci
Projedeki patchlerden birine debug noktası koyarak düzgün çalışmakta olduğunu kontrol edin. Konfigürasyonda to-be-patched.apk
yerine patchlemek istediğiniz Android paketi ismi ve patches
projesinin versiyonu doğru şekilde yazılmış olmalı. Ben revanced.app sitesindeki önerilen versiyonu kullanacağım, dolayısıyla konfigürasyon şu şekilde. Ayrıca APK nodpi olmalıdır.
1
2
3
patch
-b ..\revanced-patches\patches\build\libs\patches-5.2.1-dev.5.rvp
..\com.google.android.youtube_19.47.53.apk
Patchlemekte olduğunuz uygulamaya uygun olanlardan birine debug noktası koyup başarılı bir şekilde durduğunu gördüyseniz başka bir şeye ihtiyaç kalmadı.
Patch Anatomisi
Patchlerin çoğu BytecodePatch ve ResourcePatch yöntemini kullanır. Bytecode, uygulamanın smali kodunda; Resource, Android’in uygulama kaynakları (resources.arsc)
kısmında değişiklik yapmaya yarar. İkisi birlikte de kullanılabilir (özel ayarlara sahip olan patchlerde bunu görebilirsiniz). Sonradan eklenen Hex patch desteğiyse byte değerleri üzerinde değişikliği mümkün kılar. Byte seviyesinde değişiklik, uygulamanın farklı dillerde yazılmış decode edilemeyen kütüphaneler (native library) kullanması durumunda gerekiyor. Örneğin Unity IL2CPP yöntemini getirerek oyunların incelenmesini zorlaştırmıştır.
RawResourcePatch
benzer isimdeki yöntemle aynı işe yarıyor, sadeceresources
dosyasını decode etmeden daha hızlı bir şekilde patchlemek için mevcut.
Bu rehberde temel düzeyinde Bytecode ve Resource patch işlemini anlatacağım.
Parmak İzi
Patchleme işlemi gerçekleşmeden önce yapılması gereken, hedef dosyanın/fonksiyonun/satırların nerede olduğunu belirtmektir. Bu noktada parmak izi yöntemi devreye girer. Bir fonksiyona ait dönüş değeri (void, int)
, erişim belirteçleri (PUBLIC, STATIC)
ve aldığı parametreler gibi değerleri belirterek, değiştireceğimiz noktayı hedefleriz.
Şu şekilde değerler belirtmiş olsaydık:
1
2
3
returnType = "V",
access = AccessFlags.PUBLIC,
parameters = listOf("Z"),
Bu izden anlaşılan; void
değer döndüren, PUBLIC
erişimli ve BOOLEAN
(smali kodunda Z) türünde parametre alan bir fonksiyon hedef alınmıştır. Geri dönen fingerprint
türündeki nesne BytecodePatch constructor fonksiyonuna içerisine parametre olarak sunulur.
1
2
3
4
5
object SomePatch : BytecodePatch(
setOf(SomeFingerprint)
) {
// ...
}
Ek bir bilgi olarak, parmak izi yöntemlerinin verimlilik sıralaması şu şekilde:
- En Hızlı:
[strings]
belirteciyle. Verilen dizelerden en az biri tam eşleşme sağlamalıdır. - Daha Hızlı:
[accessFlags]
,[returnType]
ve[parameters]
seçenekleri sağlanarak. - Hızlı:
[accessFlags]
ve[returnType]
kombinasyonu. - En Yavaş: Sadece
[custom]
ve[opcodes]
kullanarak.
İz yazarken istediğiniz parametreleri kullanabilirsiniz.
Patch İskeleti
Patch constructor fonksiyonunda ve içerisinde metadata bilgileri belirtilir.
1
2
3
4
5
6
7
8
9
10
val `patchName` = bytecodePatch(
name = "Some patch",
description = "Does some thing.",
) {
compatibleWith("com.some.app")
execute {
...
}
}
name
: Patch ismi. Belirteç olarak kullanılır. İsimsiz olursa PatchBundleLoader tarafından tanınmaz ama diğer patchler bağlılık olarak kullanabilir.description
: Patch açıklaması.compatibleWith
: Uygulamanın paket adı.
Dizin Yapısı
Patchler, revanced-patches/src/main/kotlin/app/revanced/patches/<uygulama-adı>
şeklinde düzene koyulur. Patch ismi işlevinden gelmektedir. Objektif bir dilde açıklama yazılır (örn. ‘Shorts butonunu gizler’). Parmak izi, olabildiğince az ve öz yazılır. Verilen izin, birçok sürümde geçerli olacak şekilde oluşturulması patchi daha erişilebilir ve kapsamlı hale getirecektir.
Patch Yazımı
Rehberde kullanılmak üzere yazdığım ufak bir patchme
uygulaması bulunmakta. Bir metin kutusu ve butondan oluşuyor. İstenilen parolayı girdiğinizde doğru olduğunu belirten bir toast mesajı çıkarıyor. Bu uygulamayı patchleyerek her parolayı doğru kabul etmesini sağlayacağız.
JADX ile İnceleme
Bağlantıdan patchme.apk
dosyasını indirin. Uygulamayı açıp göz atabilirsiniz. Okumaya devam etmeden hangi noktalarda açık olabileceğini düşünün.
Uygulamayı JADX ile açın. dev.seaque.patchme
paketinin MainActivity
dosyasında mantık kısmı bulunmakta. Burada, boolean türünde değer döndüren isUnlocked
fonksiyonu göze çarpıyor. Parmak izinde bunu hedef alacağız. Parmak izi, smali koduna göre yazılır.
.method isUnlocked(Ljava/lang/String;)Z
.registers 3
.param p1, "input" # Ljava/lang/String;
.line 37
const-string v0, "VWF!ac3Gq&"
invoke-virtual {v0, p1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
return v0
.end method