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 }