diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index d14260d..5c56ad7 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -12,6 +12,6 @@ - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 9075e3e..cbbe561 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,8 +4,10 @@ \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..a8a2b16 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f914e84..5ae08f0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -38,4 +38,6 @@ android { dependencies { compileOnly("de.robv.android.xposed:api:82") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + implementation("io.ktor:ktor-client-core:2.3.0") + implementation("io.ktor:ktor-client-cio:2.3.0") } \ No newline at end of file diff --git a/app/src/main/kotlin/dev/beefers/vendetta/xposed/Main.kt b/app/src/main/kotlin/dev/beefers/vendetta/xposed/Main.kt index f2b6ed5..e4d4ce8 100644 --- a/app/src/main/kotlin/dev/beefers/vendetta/xposed/Main.kt +++ b/app/src/main/kotlin/dev/beefers/vendetta/xposed/Main.kt @@ -1,5 +1,11 @@ package dev.beefers.vendetta.xposed +// Java +import java.io.File + +// Kotlin +import kotlinx.coroutines.runBlocking + // Android import android.content.res.AssetManager import android.content.res.XModuleResources @@ -12,6 +18,19 @@ import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.callbacks.XC_LoadPackage +// Ktor +import io.ktor.client.* +import io.ktor.client.call.body +import io.ktor.client.engine.cio.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.client.plugins.* +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.isSuccess +import io.ktor.utils.io.reader +import java.lang.Exception + class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { private lateinit var resources: XModuleResources @@ -28,16 +47,31 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { val loadScriptFromAssets = catalystInstance.getDeclaredMethod("jniLoadScriptFromAssets", AssetManager::class.java, String::class.java, Boolean::class.javaPrimitiveType) val loadScriptFromFile = catalystInstance.getDeclaredMethod("jniLoadScriptFromFile", String::class.java, String::class.java, Boolean::class.javaPrimitiveType) - // TODO: bundle (down)loading with etag - // val cache = File(appInfo.dataDir, "cache").also { it.mkdirs() } - // val bundle = File(cache, "vendetta.js") + val cache = File(appInfo.dataDir, "cache").also { it.mkdirs() } + val bundle = File(cache, "vendetta.js") + val etag = File(cache, "vendetta_etag.txt") // TODO: loader config + // TODO: make fast. val hook = object : XC_MethodHook() { - override fun beforeHookedMethod(param: MethodHookParam) { + override fun beforeHookedMethod(param: MethodHookParam): Unit = runBlocking { Log.i("Vendetta", "beforeHookedMethod called") + try { + val client = HttpClient(CIO) { install(HttpTimeout) { requestTimeoutMillis = 3000 } } + val response: HttpResponse = client.get("https://raw.githubusercontent.com/vendetta-mod/builds/master/vendetta.js") { + headers { if (etag.exists() && bundle.exists()) append(HttpHeaders.IfNoneMatch, etag.readText()) } + } + + if (response.status.isSuccess()) { + bundle.writeText(response.bodyAsText()) + if (response.headers.contains("Etag")) etag.writeText(response.headers["Etag"] as String) + } + } catch (e: Exception) { + Log.e("Vendetta", "Failed to download Vendetta") + } + Log.i("Vendetta", "Exfiltrating Metro modules") XposedBridge.invokeOriginalMethod(loadScriptFromAssets,param.thisObject, arrayOf(resources.assets, "assets://js/modules.js", true)) Log.i("Vendetta", "Executing identity snippet") @@ -46,6 +80,11 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { override fun afterHookedMethod(param: MethodHookParam) { Log.i("Vendetta", "afterHookedMethod called") + + try { + Log.i("Vendetta", "Executing Vendetta") + XposedBridge.invokeOriginalMethod(loadScriptFromFile, param.thisObject, arrayOf(bundle.absolutePath, bundle.absolutePath, param.args[2])) + } catch(_: Exception) {} } } diff --git a/build.gradle.kts b/build.gradle.kts index 9ef8cdc..b7441e1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,8 @@ buildscript { repositories { google() + mavenCentral() + // We need jcenter for the Xposed API... jcenter() } dependencies { @@ -16,6 +18,8 @@ buildscript { allprojects { repositories { google() + mavenCentral() + // See comment in buildscript repos jcenter() } }