sqlite_hook.rs (2641B) - raw
1 use std::{collections::HashMap, ffi::{c_void, CStr}, mem::size_of, ptr::addr_of_mut, sync::Mutex}; 2 3 use jni::{objects::{JObject, JString}, JNIEnv}; 4 use nix::libc::{self, pthread_mutex_t}; 5 use once_cell::sync::Lazy; 6 7 use crate::{common, def_hook, dobby_hook, sig, util::get_jni_string}; 8 9 10 #[repr(C)] 11 #[derive(Clone, Copy, Debug)] 12 struct Sqlite3Mutex { 13 mutex: pthread_mutex_t 14 } 15 16 #[repr(C)] 17 struct Sqlite3 { 18 pad: [u8; 3 * size_of::<usize>()], 19 mutex: *mut Sqlite3Mutex 20 } 21 22 static SQLITE3_MUTEX_MAP: Lazy<Mutex<HashMap<String, pthread_mutex_t>>> = Lazy::new(|| Mutex::new(HashMap::new())); 23 24 def_hook!( 25 sqlite3_open, 26 i32, 27 |filename: *const u8, pp_db: *mut *mut Sqlite3, flags: u32, z_vfs: *const i8| { 28 let result = sqlite3_open_original.unwrap()(filename, pp_db, flags, z_vfs); 29 30 if result == 0 { 31 let sqlite3_mutex = (**pp_db).mutex; 32 33 if sqlite3_mutex != std::ptr::null_mut() { 34 let filename = CStr::from_ptr(filename).to_string_lossy().to_string().split("/").last().expect("Failed to get filename").to_string(); 35 debug!("sqlite3_open hook {:?}", filename); 36 37 SQLITE3_MUTEX_MAP.lock().unwrap().insert( 38 filename, 39 (*sqlite3_mutex).mutex 40 ); 41 } 42 } 43 44 result 45 } 46 ); 47 48 49 pub fn lock_database(mut env: JNIEnv, _: *mut c_void, filename: JString, runnable: JObject) { 50 let database_filename = get_jni_string(&mut env, filename).expect("Failed to get database filename"); 51 let mutex = SQLITE3_MUTEX_MAP.lock().unwrap().get(&database_filename).map(|mutex| *mutex); 52 53 let call_runnable = || { 54 env.call_method(runnable, "run", "()V", &[]).expect("Failed to call run method"); 55 }; 56 57 if let Some(mut mutex) = mutex { 58 if unsafe { libc::pthread_mutex_lock(addr_of_mut!(mutex)) } != 0 { 59 error!("pthread_mutex_lock failed"); 60 return; 61 } 62 63 call_runnable(); 64 65 if unsafe { libc::pthread_mutex_unlock(addr_of_mut!(mutex)) } != 0 { 66 error!("pthread_mutex_unlock failed"); 67 } 68 } else { 69 warn!("No mutex found for database: {}", database_filename); 70 call_runnable(); 71 } 72 } 73 74 75 pub fn init() { 76 if let Some(signature) = sig::find_signature( 77 &common::CLIENT_MODULE, 78 "FF FF 00 A9 3F 00 00 F9", -0x3C, 79 "9A 46 90 46 78 44 89 46 05 68",-0xd 80 ) { 81 debug!("Found sqlite3_open signature: {:#x}", signature); 82 dobby_hook!(signature as *mut c_void, sqlite3_open); 83 } else { 84 warn!("Failed to find sqlite3_open signature"); 85 } 86 }