unary_call_hook.rs (4779B) - raw


      1 use std::ffi::{c_void, CStr};
      2 
      3 use jni::{objects::{JByteArray, JMethodID, JValue}, signature::ReturnType};
      4 use nix::libc;
      5 use once_cell::sync::OnceCell;
      6 
      7 use crate::{common::{self}, def_hook, dobby_hook, sig};
      8 
      9 #[repr(C)]
     10 #[derive(Copy, Clone)]
     11 struct RefCountedSliceByteBuffer {
     12     ref_counter: *mut c_void,
     13     length: usize,
     14     data: *mut u8
     15 }
     16 
     17 #[repr(C)]
     18 struct GrpcByteBuffer {
     19     reserved: *mut c_void,
     20     type_: *mut c_void,
     21     compression: *mut c_void,
     22     slice_buffer: *mut RefCountedSliceByteBuffer
     23 }
     24 
     25 static NATIVE_LIB_ON_UNARY_CALL_METHOD: OnceCell<JMethodID> = OnceCell::new();
     26 
     27 def_hook!(
     28     unary_call,
     29     *mut c_void,
     30     |unk1: *mut c_void, uri: *const u8, grpc_byte_buffer: *mut *mut GrpcByteBuffer, unk4: *mut c_void, unk5: *mut c_void, unk6: *mut c_void| {
     31         macro_rules! call_original {
     32             () => {
     33                 unary_call_original.unwrap()(unk1, uri, grpc_byte_buffer, unk4, unk5, unk6)
     34             };
     35         }
     36 
     37         // make a local copy of the slice buffer
     38         let mut slice_buffer = *(**grpc_byte_buffer).slice_buffer;
     39 
     40         if slice_buffer.ref_counter.is_null() {
     41             return call_original!();
     42         }
     43 
     44         let java_vm = common::java_vm();
     45         let mut env = java_vm.get_env().expect("Failed to get JNIEnv");
     46 
     47         let slice_buffer_length = slice_buffer.length as usize;
     48         let jni_buffer = env.new_byte_array(slice_buffer_length as i32).expect("Failed to create new byte array");
     49         env.set_byte_array_region(&jni_buffer, 0, std::slice::from_raw_parts(slice_buffer.data as *const i8, slice_buffer_length)).expect("Failed to set byte array region");
     50 
     51         let uri_str = CStr::from_ptr(uri).to_str().unwrap();
     52 
     53         let native_request_data_object = env.call_method_unchecked(
     54             common::native_lib_instance(),
     55             NATIVE_LIB_ON_UNARY_CALL_METHOD.get().unwrap(),
     56             ReturnType::Object,
     57             &[
     58                 JValue::from(&env.new_string(uri_str).unwrap()).as_jni(),
     59                 JValue::from(&jni_buffer).as_jni()
     60             ]
     61         ).expect("Failed to call onNativeUnaryCall method").l().unwrap();
     62 
     63         if native_request_data_object.is_null() {
     64             return call_original!();
     65         }
     66 
     67         let is_canceled = env.get_field(&native_request_data_object, "canceled", "Z").expect("Failed to get canceled field").z().unwrap();
     68 
     69         if is_canceled {
     70             info!("canceled request for {}", uri_str);
     71             return std::ptr::null_mut();
     72         }
     73 
     74         let new_buffer: JByteArray = env.get_field(&native_request_data_object, "buffer", "[B").expect("Failed to get buffer field").l().unwrap().into();
     75         let new_buffer_length = env.get_array_length(&new_buffer).expect("Failed to get array length") as usize;
     76 
     77         let mut new_buffer_data = Box::new(vec![0i8; new_buffer_length]);
     78         env.get_byte_array_region(&new_buffer, 0, new_buffer_data.as_mut_slice()).expect("Failed to get byte array region");
     79 
     80         let ref_counter_struct_size = (slice_buffer.data as usize) - (slice_buffer.ref_counter as usize);
     81 
     82         //we need to allocate a new ref_counter struct and copy the old ref_counter and the new_buffer to it
     83         let new_ref = {
     84             let new_ref = libc::malloc(ref_counter_struct_size + new_buffer_length) as *mut c_void;
     85             libc::memcpy(new_ref, slice_buffer.ref_counter, ref_counter_struct_size);
     86             libc::memcpy(new_ref.offset(ref_counter_struct_size as isize), new_buffer_data.as_ptr() as *const c_void, new_buffer_length);
     87             libc::free(slice_buffer.ref_counter);
     88             new_ref
     89         };
     90 
     91         slice_buffer.ref_counter = new_ref;
     92         slice_buffer.length = new_buffer_length;
     93         slice_buffer.data = new_ref.offset(ref_counter_struct_size as isize) as *mut u8;
     94 
     95         // update the grpc byte buffer
     96         *(**grpc_byte_buffer).slice_buffer = slice_buffer;
     97 
     98         debug!("unary_call {}", uri_str);
     99 
    100         call_original!()
    101     }
    102 );
    103 
    104 pub fn init() {
    105     if let Some(signature) = sig::find_signature(
    106         &common::CLIENT_MODULE, 
    107         "A8 03 1F F8 C2 00 00 94", -0x48,
    108         "0A 90 00 F0 3F F9", -0x37
    109     ) {
    110         dobby_hook!(signature as *mut c_void, unary_call);
    111         common::attach_jni_env(|env| {
    112             NATIVE_LIB_ON_UNARY_CALL_METHOD.set(
    113                 env.get_method_id(
    114                     env.get_object_class(common::native_lib_instance()).unwrap(),
    115                         "onNativeUnaryCall", 
    116                         "(Ljava/lang/String;[B)Lme/rhunk/snapenhance/nativelib/NativeRequestData;"
    117                 ).expect("Failed to get onNativeUnaryCall method id")
    118             ).expect("unary call method already set");
    119         });
    120     } else {
    121         error!("Can't find unaryCall signature");
    122     }
    123 }