From 77810cd904564918aa52acadd438b85392ba425b Mon Sep 17 00:00:00 2001 From: Amsyar Rasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Sat, 27 May 2023 02:15:38 +0000 Subject: [PATCH] Payloading to JS --- app/src/main/assets/js/identity.js | 3 -- app/src/main/assets/js/modules.js | 10 ----- app/src/main/assets/js/preinit.js | 13 +++++++ .../main/kotlin/com/pyoncord/xposed/Main.kt | 38 ++++++++++++------- 4 files changed, 37 insertions(+), 27 deletions(-) delete mode 100644 app/src/main/assets/js/identity.js delete mode 100644 app/src/main/assets/js/modules.js create mode 100644 app/src/main/assets/js/preinit.js diff --git a/app/src/main/assets/js/identity.js b/app/src/main/assets/js/identity.js deleted file mode 100644 index 8f18304..0000000 --- a/app/src/main/assets/js/identity.js +++ /dev/null @@ -1,3 +0,0 @@ -globalThis.__pyoncord_loader_payload = { - name: "PyoncordXposed", -} \ No newline at end of file diff --git a/app/src/main/assets/js/modules.js b/app/src/main/assets/js/modules.js deleted file mode 100644 index d4310d7..0000000 --- a/app/src/main/assets/js/modules.js +++ /dev/null @@ -1,10 +0,0 @@ -const oldObjectCreate = this.Object.create; -globalThis.Object.create = (...args) => { - const obj = oldObjectCreate.apply(globalThis.Object, args); - if (args[0] === null) { - globalThis.modules = obj; - globalThis.Object.create = oldObjectCreate; - } - - return obj; -}; \ No newline at end of file diff --git a/app/src/main/assets/js/preinit.js b/app/src/main/assets/js/preinit.js new file mode 100644 index 0000000..15d61a0 --- /dev/null +++ b/app/src/main/assets/js/preinit.js @@ -0,0 +1,13 @@ +let originalObjectCreate = Object.create + +Object.create = function create(proto) { + let ret = originalObjectCreate.apply(this, arguments) + if (proto === null) { + Object.create = originalObjectCreate + return modules = ret + } + + return ret +} + +Object.freeze = Object diff --git a/app/src/main/kotlin/com/pyoncord/xposed/Main.kt b/app/src/main/kotlin/com/pyoncord/xposed/Main.kt index 71132ff..f36dae8 100644 --- a/app/src/main/kotlin/com/pyoncord/xposed/Main.kt +++ b/app/src/main/kotlin/com/pyoncord/xposed/Main.kt @@ -40,15 +40,17 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { const val LOG_TAG = "Pyoncord" const val DEFAULT_BUNDLE_ENDPOINT = "https://raw.githubusercontent.com/pyoncord/pyoncord/builds/pyoncord.js" - val pyoncord = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "pyoncord").apply { mkdirs() } + val PYONCORD_DIR = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "pyoncord").apply { mkdirs() } - val cache = File(pyoncord, "cache").apply { mkdirs() } + val CACHE_DIR = File(PYONCORD_DIR, "cache").apply { mkdir() } + val DRAWABLES_DIR = File(PYONCORD_DIR, "drawables").apply { mkdir() } + + val bundle = File(PYONCORD_DIR, "pyoncord.js") + val etag = File(PYONCORD_DIR, "etag") - val bundle = File(cache, "pyoncord.js") - val etag = File(cache, "etag") - - // val fontsDir = File(pyoncord, "fonts") - val drawablesDir = File(pyoncord, "drawables") + val loaderPayloadJson = buildJsonObject { + put("loader", "PyoncordXposed") + } } private lateinit var resources: XModuleResources @@ -73,6 +75,8 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { }) } + fun createEvalFile(code: String, identifier: String) = File(CACHE_DIR, "$identifier.js").apply { writeText(code) } + fun restartApp() = with(appActivity.applicationContext) { val intent = packageManager.getLaunchIntentForPackage(packageName)!! @@ -130,7 +134,7 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { if (path.contains("/pyoncord/")) { // We do a little hack :P val actualPath = path.substringAfter("/pyoncord/") - args[0] = File(pyoncord, actualPath).absolutePath + args[0] = File(PYONCORD_DIR, actualPath).absolutePath } } } @@ -147,7 +151,7 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { val storageDirs = storageDirsField.get(thisObject) as HashMap if (dir == "documents" && path.startsWith("pyoncord/")) { val docsDir = File(storageDirs["documents"] as String).toPath() - args[1] = docsDir.relativize(File(pyoncord.parentFile, path).toPath()).toString() + args[1] = docsDir.relativize(File(PYONCORD_DIR.parentFile, path).toPath()).toString() } } } @@ -167,7 +171,7 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { // Custom fonts val fontHook = object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam): Unit = with(param) { - File(pyoncord, args[1] as String).takeIf { it.exists() }?.let { + File(PYONCORD_DIR, args[1] as String).takeIf { it.exists() }?.let { Log.d(LOG_TAG, "Overriding font from ${args[1]} to $it") result = if (method.name == "createFromAsset") Typeface.createFromFile(it.absolutePath) else Font.Builder(it) } @@ -193,7 +197,7 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { val name = param.args[1] as? String ?: return val uri = uriCache.getOrPut(name) { - File(drawablesDir, "$name.png").takeIf { it.exists() }?.let { + File(DRAWABLES_DIR, "$name.png").takeIf { it.exists() }?.let { Uri.fromFile(it) } ?: Uri.EMPTY } @@ -209,9 +213,15 @@ class Main : IXposedHookZygoteInit, IXposedHookLoadPackage { // TODO: Loader config val hook = object: XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) = with(param) { - // Load pre-patches and identity - XposedBridge.invokeOriginalMethod(loadScriptFromAssets, thisObject, arrayOf(resources.assets, "assets://js/modules.js", true)) - XposedBridge.invokeOriginalMethod(loadScriptFromAssets, thisObject, arrayOf(resources.assets, "assets://js/identity.js", true)) + val payloadFile = createEvalFile("PYONCORD_LOADER_PAYLOAD=${Json.encodeToString(loaderPayloadJson)}", "payload") + + // Load pre-patches and payload + XposedBridge.invokeOriginalMethod(loadScriptFromAssets, thisObject, arrayOf(resources.assets, "assets://js/preinit.js", true)) + XposedBridge.invokeOriginalMethod( + loadScriptFromFile, + thisObject, + arrayOf(payloadFile.absolutePath, "pyoncord-payload", true) + ) // Invoke the original method XposedBridge.invokeOriginalMethod(method, thisObject, args)