composer_hook.rs (8777B) - raw
1 #![allow(dead_code, unused_imports)] 2 3 use super::util::composer_utils::{ComposerModule, ModuleTag}; 4 use std::{collections::HashMap, ffi::{c_void, CStr}, sync::Mutex}; 5 use jni::{objects::JString, sys::jobject, JNIEnv}; 6 use once_cell::sync::Lazy; 7 use crate::{common, config, def_hook, dobby_hook, dobby_hook_sym, sig, util::get_jni_string}; 8 9 const JS_TAG_BIG_DECIMAL: i64 = -11; 10 const JS_TAG_BIG_INT: i64 = -10; 11 const JS_TAG_BIG_FLOAT: i64 = -9; 12 const JS_TAG_SYMBOL: i64 = -8; 13 const JS_TAG_STRING: i64 = -7; 14 const JS_TAG_MODULE: i64 = -3; 15 const JS_TAG_FUNCTION_BYTECODE: i64 = -2; 16 const JS_TAG_OBJECT: i64 = -1; 17 const JS_TAG_INT: i64 = 0; 18 const JS_TAG_BOOL: i64 = 1; 19 const JS_TAG_NULL: i64 = 2; 20 const JS_TAG_UNDEFINED: i64 = 3; 21 const JS_TAG_UNINITIALIZED: i64 = 4; 22 const JS_TAG_CATCH_OFFSET: i64 = 5; 23 const JS_TAG_EXCEPTION: i64 = 6; 24 const JS_TAG_FLOAT64: i64 = 7; 25 26 #[repr(C)] 27 struct JsString { 28 /* 29 original structure : 30 struct JSString { 31 struct JSRefCountHeader { 32 int ref_count; 33 }; 34 uint32_t len : 31; 35 uint8_t is_wide_char : 1; 36 uint32_t hash : 30; 37 uint8_t atom_type : 2; 38 uint32_t hash_next; 39 40 union { 41 uint8_t str8[0]; 42 uint16_t str16[0]; 43 } u; 44 }; 45 */ 46 pad: [u32; 4], 47 str8: [u8; 0], 48 str16: [u16; 0], 49 } 50 51 #[repr(C)] 52 #[derive(Copy, Clone)] 53 union JsValueUnion { 54 int32: i32, 55 float64: f64, 56 ptr: *mut c_void, 57 } 58 59 #[repr(C)] 60 #[derive(Copy, Clone)] 61 struct JsValue { 62 u: JsValueUnion, 63 tag: i64, 64 } 65 66 static AASSET_MAP: Lazy<Mutex<HashMap<usize, Vec<u8>>>> = Lazy::new(|| Mutex::new(HashMap::new())); 67 static COMPOSER_LOADER_DATA: Mutex<Option<String>> = Mutex::new(None); 68 69 def_hook!( 70 aasset_get_length, 71 i32, 72 |arg0: *mut c_void| { 73 if let Some(buffer) = AASSET_MAP.lock().unwrap().get(&(arg0 as usize)) { 74 return buffer.len() as i32; 75 } 76 aasset_get_length_original.unwrap()(arg0) 77 } 78 ); 79 80 def_hook!( 81 aasset_get_buffer, 82 *const c_void, 83 |arg0: *mut c_void| { 84 if let Some(buffer) = AASSET_MAP.lock().unwrap().get(&(arg0 as usize)) { 85 return buffer.as_ptr() as *const c_void; 86 } 87 aasset_get_buffer_original.unwrap()(arg0) 88 } 89 ); 90 91 def_hook!( 92 aasset_manager_open, 93 *mut c_void, 94 |arg0: *mut c_void, arg1: *const u8, arg2: i32| { 95 let handle = aasset_manager_open_original.unwrap()(arg0, arg1, arg2); 96 97 let path = Lazy::new(|| CStr::from_ptr(arg1).to_str().unwrap()); 98 if !handle.is_null() && path.starts_with("bridge_observables") { 99 let asset_buffer = aasset_get_buffer_original.unwrap()(handle); 100 let asset_length = aasset_get_length_original.unwrap()(handle); 101 debug!("asset buffer: {:p}, length: {}", asset_buffer, asset_length); 102 103 let composer_loader = COMPOSER_LOADER_DATA.lock().unwrap().clone().expect("No composer loader data"); 104 105 let archive_buffer: Vec<u8> = std::slice::from_raw_parts(asset_buffer as *const u8, asset_length as usize).to_vec(); 106 let decompressed = zstd::stream::decode_all(&archive_buffer[..]).expect("Failed to decompress composer archive"); 107 let mut composer_module = ComposerModule::parse(decompressed).expect("Failed to parse composer module"); 108 109 let mut tags = composer_module.get_tags(); 110 let mut new_tags = Vec::new(); 111 112 for (tag1, _) in tags.iter_mut() { 113 let name = tag1.to_string().unwrap(); 114 if !name.ends_with("src/utils/converter.js") { 115 continue; 116 } 117 118 let old_file_name = name.split_once(".").unwrap().0.to_owned() + rand::random::<u32>().to_string().as_str(); 119 tag1.set_buffer((old_file_name.to_owned() + ".js").as_bytes().to_vec()); 120 let original_module_path = path.split_once(".").unwrap().0.to_owned() + "/" + &old_file_name; 121 122 let hooked_module = format!("{};module.exports = require(\"{}\");", composer_loader, original_module_path); 123 124 new_tags.push( 125 ( 126 ModuleTag::new(128, name.as_bytes().to_vec()), 127 ModuleTag::new(128, hooked_module.as_bytes().to_vec()) 128 ) 129 ); 130 131 debug!("composer loader injected in {}", name); 132 break; 133 } 134 135 tags.extend(new_tags); 136 composer_module.set_tags(tags); 137 138 let compressed = composer_module.to_bytes(); 139 let compressed = zstd::stream::encode_all(&compressed[..], 3).expect("Failed to compress"); 140 141 AASSET_MAP.lock().unwrap().insert(handle as usize, compressed); 142 } 143 handle 144 } 145 ); 146 147 def_hook!( 148 aasset_close, 149 c_void, 150 |handle: *mut c_void| { 151 AASSET_MAP.lock().unwrap().remove(&(handle as usize)); 152 aasset_close_original.unwrap()(handle) 153 } 154 ); 155 156 #[cfg(target_arch = "aarch64")] 157 static mut GLOBAL_INSTANCE: Option<*mut c_void> = None; 158 #[cfg(target_arch = "aarch64")] 159 static mut GLOBAL_CTX: Option<*mut c_void> = None; 160 161 #[cfg(target_arch = "aarch64")] 162 static mut JS_EVAL_ORIGINAL2: Option<unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void, *mut u8, usize, *const u8, u32) -> JsValue> = None; 163 164 def_hook!( 165 js_eval, 166 *mut c_void, 167 |arg0: *mut c_void, arg1: *mut c_void, arg2: *mut c_void, arg3: *const u8, arg4: *const u8, arg5: *const u8, arg6: *mut c_void, arg7: u32| { 168 #[cfg(target_arch = "aarch64")] 169 { 170 GLOBAL_INSTANCE = Some(arg0); 171 GLOBAL_CTX = Some(arg1); 172 } 173 js_eval_original.unwrap()(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) 174 } 175 ); 176 177 pub fn set_composer_loader(mut env: JNIEnv, _: *mut c_void, code: JString) { 178 let new_code = get_jni_string(&mut env, code).expect("Failed to get composer loader code"); 179 COMPOSER_LOADER_DATA.lock().unwrap().replace(new_code); 180 } 181 182 #[allow(unreachable_code, unused_variables)] 183 pub unsafe fn composer_eval(env: JNIEnv, _: *mut c_void, script: JString) -> jobject { 184 #[cfg(target_arch = "aarch64")] 185 { 186 let mut env = env; 187 188 let script_str = get_jni_string(&mut env, script).expect("Failed to get script"); 189 let script_length = script_str.len(); 190 191 let js_value = JS_EVAL_ORIGINAL2.expect("No js eval found")( 192 GLOBAL_INSTANCE.expect("No global instance found"), 193 GLOBAL_CTX.expect("No global context found"), 194 std::ptr::null_mut(), 195 (script_str + "\0").as_ptr() as *mut u8, 196 script_length, 197 "<eval>\0".as_ptr(), 198 0 199 ); 200 201 let result: String = if js_value.tag == JS_TAG_STRING { 202 let string = js_value.u.ptr as *mut JsString; 203 CStr::from_ptr((*string).str8.as_ptr() as *const u8).to_str().unwrap().into() 204 } else if js_value.tag == JS_TAG_INT { 205 js_value.u.int32.to_string() 206 } else if js_value.tag == JS_TAG_BOOL { 207 if js_value.u.int32 == 1 { "true" } else { "false" }.into() 208 } else if js_value.tag == JS_TAG_NULL { 209 "null".into() 210 } else if js_value.tag == JS_TAG_UNDEFINED { 211 "undefined".into() 212 } else if js_value.tag == JS_TAG_OBJECT { 213 "[object]".into() 214 } else if js_value.tag == JS_TAG_FLOAT64 { 215 js_value.u.float64.to_string() 216 } else if js_value.tag == JS_TAG_EXCEPTION { 217 "Failed to evaluate script".into() 218 } else { 219 "[unknown tag ".to_owned() + &js_value.tag.to_string() + "]".into() 220 }; 221 222 return env.new_string(result).unwrap().into_raw() 223 } 224 225 return env.new_string("Architecture not supported").unwrap().into_raw(); 226 } 227 228 pub fn init() { 229 if !config::native_config().composer_hooks { 230 return 231 } 232 233 dobby_hook_sym!("libandroid.so", "AAsset_getBuffer", aasset_get_buffer); 234 dobby_hook_sym!("libandroid.so", "AAsset_getLength", aasset_get_length); 235 dobby_hook_sym!("libandroid.so", "AAsset_close", aasset_close); 236 dobby_hook_sym!("libandroid.so", "AAssetManager_open", aasset_manager_open); 237 238 #[cfg(target_arch = "aarch64")] 239 { 240 if let Some(signature) = sig::find_signature( 241 &common::CLIENT_MODULE, 242 "00 E4 00 6F 29 00 80 52 76 00 04 8B", -0x28, 243 "A1 B0 07 92 81 46", -0x7 244 ) { 245 dobby_hook!(signature as *mut c_void, js_eval); 246 247 unsafe { 248 JS_EVAL_ORIGINAL2 = Some(std::mem::transmute(js_eval_original.unwrap())); 249 } 250 251 debug!("js_eval {:#x}", signature); 252 } else { 253 warn!("Unable to find js_eval signature"); 254 } 255 } 256 } 257