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 }