commit 33dc0c7510ec75bff340d3a921aa447d6f7fcb32
parent 2bb055f4642bdcc02c24117be6794ac73c420e90
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Mon, 22 Apr 2024 23:35:48 +0200
feat(composer_hooks): armv7 support
Diffstat:
6 files changed, 39 insertions(+), 57 deletions(-)
diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json
@@ -772,7 +772,7 @@
"properties": {
"composer_hooks": {
"name": "Composer Hooks",
- "description": "Injects code into the Composer cross-platform UI framework (arm64 only)",
+ "description": "Injects code into the Composer cross-platform UI framework",
"properties": {
"bypass_camera_roll_limit": {
"name": "Bypass Camera Roll Limit",
@@ -780,7 +780,7 @@
},
"composer_console": {
"name": "Composer Console",
- "description": "Allows you to execute JavaScript code in Composer"
+ "description": "Allows you to execute JavaScript code in Composer (arm64 only)"
},
"composer_logs": {
"name": "Composer Logs",
diff --git a/core/src/main/assets/composer/loader.js b/core/src/main/assets/composer/loader.js
@@ -1,9 +1,3 @@
-const callExport = require('composer_core/src/DeviceBridge')[EXPORTED_FUNCTION_NAME];
-
-if (!callExport) {
- return "No export function found";
-}
-
const config = callExport("getConfig");
if (config.composerLogs) {
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/ComposerHooks.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/ComposerHooks.kt
@@ -186,21 +186,16 @@ class ComposerHooks: Feature("ComposerHooks", loadParams = FeatureLoadParams.ACT
return
}
- val hookResult = context.native.composerEval("""
- (() => { try { const EXPORTED_FUNCTION_NAME = "$exportedFunctionName"; $loaderScript
+ context.native.setComposerLoader("""
+ (() => { const callExport = require('composer_core/src/DeviceBridge')["$exportedFunctionName"]; try { $loaderScript
} catch (e) {
- return e.toString() + "\n" + e.stack;
+ try {
+ callExport("log", "error", e.toString() + "\n" + e.stack);
+ } catch (t) {}
}
- return "success";
- })()
+ })();
""".trimIndent().trim())
- if (hookResult != "success") {
- context.shortToast(("Composer loader failed : $hookResult").also {
- context.log.error(it)
- })
- }
-
if (config.composerConsole.get()) {
injectConsole()
}
@@ -221,16 +216,6 @@ class ComposerHooks: Feature("ComposerHooks", loadParams = FeatureLoadParams.ACT
}
}
- var composerThreadTask: (() -> Unit)? = null
-
- findClass("com.snap.composer.callable.ComposerFunctionNative").hook("nativePerform", HookStage.BEFORE) {
- composerThreadTask?.invoke()
- composerThreadTask = null
- }
-
- context.coroutineScope.launch {
- context.native.waitForComposer()
- composerThreadTask = ::loadHooks
- }
+ loadHooks()
}
}
\ No newline at end of file
diff --git a/native/jni/src/hooks/composer_hook.h b/native/jni/src/hooks/composer_hook.h
@@ -93,20 +93,32 @@ namespace ComposerHook {
static uintptr_t global_instance;
static JSContext *global_ctx;
+ static std::string* composer_loader;
- HOOK_DEF(JSValue, js_eval, uintptr_t instance, JSContext *ctx, uintptr_t this_obj, uint8_t *input, uintptr_t input_len, const char *filename, unsigned int flags, unsigned int scope_idx) {
+ HOOK_DEF(JSValue, js_eval, uintptr_t instance, JSContext *ctx, uintptr_t this_obj, char *input, uintptr_t input_len, const char *filename, unsigned int flags, unsigned int scope_idx) {
if (global_instance == 0 || global_ctx == nullptr) {
global_instance = instance;
global_ctx = ctx;
+ LOGD("Injecting composer loader");
+
+ composer_loader->resize(composer_loader->size() + input_len);
+ memcpy((void*) (composer_loader->c_str() + composer_loader->size() - input_len), input, input_len);
+
+ input = (char*) composer_loader->c_str();
+ input_len = composer_loader->size();
+ } else {
+ if (composer_loader != nullptr) {
+ delete composer_loader;
+ composer_loader = nullptr;
+ }
}
-
return js_eval_original(instance, ctx, this_obj, input, input_len, filename, flags, scope_idx);
}
- void waitForComposer(JNIEnv *, jobject) {
- while (global_instance == 0 || global_ctx == nullptr) {
- usleep(10000);
- }
+ void setComposerLoader(JNIEnv *env, jobject, jstring code) {
+ auto code_str = env->GetStringUTFChars(code, nullptr);
+ composer_loader = new std::string(code_str, env->GetStringUTFLength(code));
+ env->ReleaseStringUTFChars(code, code_str);
}
jstring composerEval(JNIEnv *env, jobject, jstring script) {
@@ -117,7 +129,7 @@ namespace ComposerHook {
auto script_str = env->GetStringUTFChars(script, nullptr);
auto length = env->GetStringUTFLength(script);
- auto jsvalue = js_eval_original(global_instance, global_ctx, (uintptr_t) &global_ctx->global_obj, (uint8_t *) script_str, length, "<input>", 0, 0);
+ auto jsvalue = js_eval_original(global_instance, global_ctx, (uintptr_t) &global_ctx->global_obj, (char *) script_str, length, "<eval>", 0, 0);
env->ReleaseStringUTFChars(script, script_str);
if (jsvalue.tag == JS_TAG_STRING) {
@@ -157,12 +169,11 @@ namespace ComposerHook {
}
void init() {
- if (!ARM64) return;
auto js_eval_ptr = util::find_signature(
common::client_module.base,
common::client_module.size,
- "00 E4 00 6F 29 00 80 52 76 00 04 8B",
- -0x28
+ ARM64 ? "00 E4 00 6F 29 00 80 52 76 00 04 8B" : "A1 B0 07 92 81 46",
+ ARM64 ? -0x28 : -0x7
);
if (js_eval_ptr == 0) {
LOGE("js_eval_ptr signature not found");
diff --git a/native/jni/src/library.cpp b/native/jni/src/library.cpp
@@ -2,7 +2,6 @@
#include <string>
#include <dobby.h>
#include <vector>
-#include <thread>
#include "logger.h"
#include "common.h"
@@ -33,21 +32,13 @@ bool JNICALL init(JNIEnv *env, jobject clazz) {
util::remap_sections(BUILD_PACKAGE);
- auto threads = std::vector<std::thread>();
-
- #define RUN(body) \
- threads.push_back(std::thread([&] { body; }))
-
- RUN(UnaryCallHook::init(env));
- RUN(AssetHook::init(env));
- RUN(FstatHook::init());
- RUN(SqliteMutexHook::init());
- RUN(DuplexHook::init(env));
+ UnaryCallHook::init(env);
+ AssetHook::init(env);
+ FstatHook::init();
+ SqliteMutexHook::init();
+ DuplexHook::init(env);
if (common::native_config->composer_hooks) {
- RUN(ComposerHook::init());
- }
- for (auto &thread : threads) {
- thread.join();
+ ComposerHook::init();
}
LOGD("Native initialized");
@@ -94,7 +85,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *_) {
methods.push_back({"init", "()Z", (void *)init});
methods.push_back({"loadConfig", "(L" BUILD_NAMESPACE "/NativeConfig;)V", (void *)load_config});
methods.push_back({"lockDatabase", "(Ljava/lang/String;Ljava/lang/Runnable;)V", (void *)lock_database});
- methods.push_back({"waitForComposer", "()V", (void *) ComposerHook::waitForComposer});
+ methods.push_back({"setComposerLoader", "(Ljava/lang/String;)V", (void *) ComposerHook::setComposerLoader});
methods.push_back({"composerEval", "(Ljava/lang/String;)Ljava/lang/String;",(void *) ComposerHook::composerEval});
env->RegisterNatives(env->FindClass(std::string(BUILD_NAMESPACE "/NativeLib").c_str()), methods.data(), methods.size());
diff --git a/native/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeLib.kt b/native/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeLib.kt
@@ -2,6 +2,7 @@ package me.rhunk.snapenhance.nativelib
import android.util.Log
+@Suppress("KotlinJniMissingFunction")
class NativeLib {
var nativeUnaryCallCallback: (NativeRequestData) -> Unit = {}
var nativeShouldLoadAsset: (String) -> Boolean = { true }
@@ -62,6 +63,6 @@ class NativeLib {
private external fun init(): Boolean
private external fun loadConfig(config: NativeConfig)
private external fun lockDatabase(name: String, callback: Runnable)
- external fun waitForComposer()
+ external fun setComposerLoader(code: String)
external fun composerEval(code: String): String?
}
\ No newline at end of file