fixes
This commit is contained in:
@@ -24,16 +24,11 @@ pub static CLIENT_MODULE: Lazy<MappedLib> = Lazy::new(|| {
|
||||
|
||||
|
||||
pub fn set_native_lib_instance(instance: GlobalRef) {
|
||||
NATIVE_LIB_INSTANCE
|
||||
.set(instance)
|
||||
.expect("NativeLib instance already set");
|
||||
NATIVE_LIB_INSTANCE.set(instance).expect("NativeLib instance already set");
|
||||
}
|
||||
|
||||
pub fn native_lib_instance() -> GlobalRef {
|
||||
NATIVE_LIB_INSTANCE
|
||||
.get()
|
||||
.expect("NativeLib instance not set")
|
||||
.clone()
|
||||
NATIVE_LIB_INSTANCE.get().expect("NativeLib instance not set").clone()
|
||||
}
|
||||
|
||||
pub fn set_java_vm(vm: *mut jni::sys::JavaVM) {
|
||||
@@ -42,16 +37,13 @@ pub fn set_java_vm(vm: *mut jni::sys::JavaVM) {
|
||||
|
||||
pub fn java_vm() -> JavaVM {
|
||||
unsafe {
|
||||
JavaVM::from_raw(*JAVA_VM.get().expect("JavaVM not set") as *mut jni::sys::JavaVM)
|
||||
.expect("Failed to get JavaVM")
|
||||
JavaVM::from_raw(*JAVA_VM.get().expect("JavaVM not set") as *mut jni::sys::JavaVM).expect("Failed to get JavaVM")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attach_jni_env(block: impl FnOnce(&mut jni::JNIEnv)) {
|
||||
let jvm = java_vm();
|
||||
let mut env: jni::AttachGuard = jvm
|
||||
.attach_current_thread()
|
||||
.expect("Failed to attach to current thread");
|
||||
let mut env: jni::AttachGuard = jvm.attach_current_thread().expect("Failed to attach to current thread");
|
||||
|
||||
block(&mut env);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
use crate::{secstrings, util::get_jni_string};
|
||||
use jni::{objects::JObject, JNIEnv};
|
||||
use std::{error::Error, sync::Mutex};
|
||||
use jni::{objects::JObject, JNIEnv};
|
||||
use crate::{secstrings, util::get_jni_string};
|
||||
|
||||
static NATIVE_CONFIG: Mutex<Option<NativeConfig>> = Mutex::new(None);
|
||||
|
||||
pub fn native_config() -> NativeConfig {
|
||||
NATIVE_CONFIG
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.expect("NativeConfig not loaded")
|
||||
.clone()
|
||||
NATIVE_CONFIG.lock().unwrap().as_ref().expect("NativeConfig not loaded").clone()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -32,13 +27,11 @@ impl NativeConfig {
|
||||
macro_rules! get_string {
|
||||
($field:expr) => {
|
||||
match env.get_field(&obj, $field, "Ljava/lang/String;")?.l()? {
|
||||
jstring => {
|
||||
if !jstring.is_null() {
|
||||
Some(get_jni_string(env, jstring.into())?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
jstring => if !jstring.is_null() {
|
||||
Some(get_jni_string(env, jstring.into())?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -80,11 +73,10 @@ pub fn get_blocker_config() -> BlockerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_config(mut env: JNIEnv, _class: JObject, obj: JObject) {
|
||||
NATIVE_CONFIG
|
||||
.lock()
|
||||
.unwrap()
|
||||
.replace(NativeConfig::new(&mut env, obj).expect("Failed to load NativeConfig"));
|
||||
|
||||
pub fn load_config(mut env: JNIEnv, _class: JObject, obj: JObject) {
|
||||
NATIVE_CONFIG.lock().unwrap().replace(
|
||||
NativeConfig::new(&mut env, obj).expect("Failed to load NativeConfig")
|
||||
);
|
||||
|
||||
info!("Config loaded {:?}", native_config());
|
||||
}
|
||||
|
||||
@@ -36,3 +36,15 @@ macro_rules! dobby_hook {
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! dobby_hook_sym {
|
||||
($lib:expr, $sym:expr, $hook:expr) => {
|
||||
if let Some(hook_symbol) = dobby_rs::resolve_symbol($lib, $sym) {
|
||||
crate::dobby_hook!(hook_symbol, $hook);
|
||||
debug!("hooked symbol: {}", $sym);
|
||||
} else {
|
||||
panic!("Failed to resolve symbol: {}", $sym);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ extern crate log;
|
||||
|
||||
mod common;
|
||||
|
||||
mod config;
|
||||
mod hook;
|
||||
mod mapped_lib;
|
||||
mod sig;
|
||||
mod util;
|
||||
mod mapped_lib;
|
||||
mod config;
|
||||
mod sig;
|
||||
|
||||
mod modules;
|
||||
mod security;
|
||||
@@ -15,10 +15,7 @@ mod secstrings;
|
||||
|
||||
use android_logger::Config;
|
||||
use log::LevelFilter;
|
||||
use modules::{
|
||||
custom_font_hook, duplex_hook, fstat_hook, linker_hook, sqlite_hook, unary_call_hook,
|
||||
valdi_hook,
|
||||
};
|
||||
use modules::{valdi_hook, custom_font_hook, duplex_hook, fstat_hook, linker_hook, sqlite_hook, unary_call_hook};
|
||||
|
||||
use jni::{JNIEnv, JavaVM, NativeMethod};
|
||||
use jni::objects::{JObject, JString, JClass, JValue};
|
||||
@@ -169,11 +166,10 @@ fn init(mut env: JNIEnv, _class: JObject, signature_cache: JString) -> jstring {
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
// load signature cache
|
||||
|
||||
|
||||
if !signature_cache.is_null() {
|
||||
let sig_cache_str = util::get_jni_string(&mut env, signature_cache)
|
||||
.expect("Failed to convert mappings to string");
|
||||
|
||||
let sig_cache_str = util::get_jni_string(&mut env, signature_cache).expect("Failed to convert mappings to string");
|
||||
|
||||
if let Ok(signature_cache) = serde_json::from_str(sig_cache_str.as_str()) {
|
||||
sig::add_signatures(signature_cache);
|
||||
} else {
|
||||
@@ -181,11 +177,7 @@ fn init(mut env: JNIEnv, _class: JObject, signature_cache: JString) -> jstring {
|
||||
}
|
||||
}
|
||||
|
||||
common::set_native_lib_instance(
|
||||
env.new_global_ref(_class)
|
||||
.ok()
|
||||
.expect("Failed to create global ref"),
|
||||
);
|
||||
common::set_native_lib_instance(env.new_global_ref(_class).ok().expect("Failed to create global ref"));
|
||||
|
||||
let _ = common::CLIENT_MODULE;
|
||||
|
||||
|
||||
@@ -24,24 +24,21 @@ impl MappedLib {
|
||||
}
|
||||
|
||||
pub fn search(&mut self) -> Result<&Self, Box<dyn Error>> {
|
||||
procfs::process::Process::myself()?
|
||||
.maps()?
|
||||
.iter()
|
||||
.for_each(|map| {
|
||||
let pathname = &map.pathname;
|
||||
procfs::process::Process::myself()?.maps()?.iter().for_each(|map| {
|
||||
let pathname = &map.pathname;
|
||||
|
||||
if let MMapPath::Path(path_buffer) = pathname {
|
||||
let path = path_buffer.to_string_lossy();
|
||||
if let MMapPath::Path(path_buffer) = pathname {
|
||||
let path = path_buffer.to_string_lossy();
|
||||
|
||||
if path.contains(&self.name) {
|
||||
self.regions.push(MappedRegion {
|
||||
start: map.address.0,
|
||||
end: map.address.1,
|
||||
perms: map.perms,
|
||||
});
|
||||
}
|
||||
if path.contains(&self.name) {
|
||||
self.regions.push(MappedRegion {
|
||||
start: map.address.0,
|
||||
end: map.address.1,
|
||||
perms: map.perms,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if self.regions.is_empty() {
|
||||
return Err(format!("No regions found for {}", self.name).into());
|
||||
|
||||
@@ -2,41 +2,33 @@ use std::{ffi::CStr, fs};
|
||||
|
||||
use nix::libc::{self, c_uint};
|
||||
|
||||
use crate::{config, def_hook, dobby_hook, modules::util::elf};
|
||||
use crate::{config, def_hook, dobby_hook_sym};
|
||||
|
||||
def_hook!(open_hook, i32, |path: *const u8,
|
||||
flags: i32,
|
||||
mode: c_uint| {
|
||||
if let Ok(pathname) = CStr::from_ptr(path).to_str() {
|
||||
if pathname == "/system/fonts/NotoColorEmoji.ttf" {
|
||||
if let Some(font_path) = config::native_config().custom_emoji_font_path {
|
||||
if fs::metadata(&font_path).is_ok() {
|
||||
return libc::openat(
|
||||
libc::AT_FDCWD,
|
||||
font_path.as_ptr() as *const u8,
|
||||
flags,
|
||||
mode,
|
||||
);
|
||||
} else {
|
||||
warn!("custom emoji font path does not exist: {}", font_path);
|
||||
def_hook!(
|
||||
open_hook,
|
||||
i32,
|
||||
|path: *const u8, flags: i32, mode: c_uint| {
|
||||
if let Ok(pathname) = CStr::from_ptr(path).to_str() {
|
||||
if pathname == "/system/fonts/NotoColorEmoji.ttf" {
|
||||
if let Some(font_path) = config::native_config().custom_emoji_font_path {
|
||||
if fs::metadata(&font_path).is_ok() {
|
||||
return libc::openat(libc::AT_FDCWD, font_path.as_ptr() as *const u8, flags, mode);
|
||||
} else {
|
||||
warn!("custom emoji font path does not exist: {}", font_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open_hook_original.unwrap()(path, flags, mode)
|
||||
});
|
||||
open_hook_original.unwrap()(path, flags, mode)
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
pub fn init() {
|
||||
if config::native_config().custom_emoji_font_path.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let libc = elf::Elf::from_maps("/libc.so").expect("Failed to find libc.so in maps");
|
||||
|
||||
if let Some(ptr) = libc.get_symbol_address("open") {
|
||||
dobby_hook!(ptr as _, open_hook);
|
||||
} else {
|
||||
panic!("Failed to find open symbol");
|
||||
}
|
||||
}
|
||||
dobby_hook_sym!("libc.so", "open", open_hook);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ use jni::{objects::JObject, sys::jboolean, JNIEnv};
|
||||
|
||||
use crate::{common, def_hook, dobby_hook, util::get_jni_string};
|
||||
|
||||
|
||||
def_hook!(
|
||||
is_same_object,
|
||||
jboolean,
|
||||
@@ -19,15 +20,9 @@ def_hook!(
|
||||
if !env.is_instance_of(&obj1, class).unwrap() {
|
||||
return is_same_object_original.unwrap()(env, obj1, obj2);
|
||||
}
|
||||
|
||||
let obj1_class_name = env
|
||||
.call_method(&obj1, "getName", "()Ljava/lang/String;", &[])
|
||||
.unwrap()
|
||||
.l()
|
||||
.unwrap()
|
||||
.into();
|
||||
let class_name =
|
||||
get_jni_string(&mut env, obj1_class_name).expect("Failed to get class name");
|
||||
|
||||
let obj1_class_name = env.call_method(&obj1, "getName", "()Ljava/lang/String;", &[]).unwrap().l().unwrap().into();
|
||||
let class_name = get_jni_string(&mut env, obj1_class_name).expect("Failed to get class name");
|
||||
|
||||
if class_name.contains("com.snapchat.client.duplex.MessageHandler") {
|
||||
debug!("is_same_object hook: MessageHandler");
|
||||
@@ -38,11 +33,9 @@ def_hook!(
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
pub fn init() {
|
||||
common::attach_jni_env(|env| {
|
||||
dobby_hook!(
|
||||
(**env.get_native_interface()).IsSameObject.unwrap() as *mut c_void,
|
||||
is_same_object
|
||||
);
|
||||
dobby_hook!((**env.get_native_interface()).IsSameObject.unwrap() as *mut c_void, is_same_object);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,44 @@
|
||||
|
||||
use crate::{
|
||||
config::{self, native_config},
|
||||
def_hook, dobby_hook,
|
||||
modules::util::elf,
|
||||
};
|
||||
use nix::libc;
|
||||
use std::fs;
|
||||
|
||||
def_hook!(fstat_hook, i32, |fd: i32, statbuf: *mut libc::stat| {
|
||||
if let Ok(link) = fs::read_link("/proc/self/fd/".to_owned() + &fd.to_string()) {
|
||||
let link_str = link.to_string_lossy();
|
||||
let config = native_config();
|
||||
if config.disable_metrics && link_str.contains("files/blizzardv2/queues") {
|
||||
if libc::unlink((link_str.to_string() + "\0").as_ptr()) == -1 {
|
||||
warn!("Failed to unlink {}", link_str);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
use nix::libc;
|
||||
|
||||
if config.disable_bitmoji {
|
||||
if link_str.contains("com.snap.file_manager_4_SCContent") {
|
||||
use crate::{config::{self, native_config}, def_hook, dobby_hook_sym};
|
||||
|
||||
def_hook!(
|
||||
fstat_hook,
|
||||
i32,
|
||||
|fd: i32, statbuf: *mut libc::stat| {
|
||||
if let Ok(link) = fs::read_link("/proc/self/fd/".to_owned() + &fd.to_string()) {
|
||||
let link_str = link.to_string_lossy();
|
||||
let config = native_config();
|
||||
if config.disable_metrics && link_str.contains("files/blizzardv2/queues") {
|
||||
if libc::unlink((link_str.to_string() + "\0").as_ptr()) == -1 {
|
||||
warn!("Failed to unlink {}", link_str);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if link_str.contains("/files/file_manager/") {
|
||||
let lower = link_str.to_lowercase();
|
||||
if lower.contains("bitmoji") {
|
||||
|
||||
if config.disable_bitmoji {
|
||||
if link_str.contains("com.snap.file_manager_4_SCContent") {
|
||||
return -1;
|
||||
}
|
||||
if link_str.contains("/files/file_manager/") {
|
||||
let lower = link_str.to_lowercase();
|
||||
if lower.contains("bitmoji") {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fstat_hook_original.unwrap()(fd, statbuf)
|
||||
});
|
||||
fstat_hook_original.unwrap()(fd, statbuf)
|
||||
}
|
||||
);
|
||||
|
||||
pub fn init() {
|
||||
let config = config::native_config();
|
||||
if config.disable_metrics || config.disable_bitmoji {
|
||||
let libc = elf::Elf::from_maps("/libc.so").expect("Failed to find libc.so in maps");
|
||||
|
||||
if let Some(ptr) = libc.get_symbol_address("fstat") {
|
||||
dobby_hook!(ptr as _, fstat_hook);
|
||||
} else {
|
||||
panic!("Failed to find fstat symbol");
|
||||
}
|
||||
dobby_hook_sym!("libc.so", "fstat", fstat_hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,12 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::{c_void, CStr},
|
||||
sync::Mutex,
|
||||
};
|
||||
use std::{collections::HashMap, ffi::{c_void, CStr}, sync::Mutex};
|
||||
|
||||
use jni::{
|
||||
objects::{JByteArray, JString},
|
||||
JNIEnv,
|
||||
};
|
||||
use jni::{objects::{JByteArray, JString}, JNIEnv};
|
||||
use nix::libc;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{def_hook, dobby_hook, modules::util::elf};
|
||||
use crate::{def_hook, dobby_hook_sym};
|
||||
|
||||
static SHARED_LIBRARIES: Lazy<Mutex<HashMap<String, Box<Vec<i8>>>>> =
|
||||
Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
static SHARED_LIBRARIES: Lazy<Mutex<HashMap<String, Box<Vec<i8>>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
def_hook!(
|
||||
linker_openat,
|
||||
@@ -25,13 +17,8 @@ def_hook!(
|
||||
if let Some(content) = SHARED_LIBRARIES.lock().unwrap().remove(&pathname_str) {
|
||||
let memfd = libc::syscall(libc::SYS_memfd_create, "jit-cache\0".as_ptr(), 0) as i32;
|
||||
let content = content.into_boxed_slice();
|
||||
|
||||
if libc::write(
|
||||
memfd,
|
||||
content.as_ptr() as *const c_void,
|
||||
content.len() as libc::size_t,
|
||||
) == -1
|
||||
{
|
||||
|
||||
if libc::write(memfd, content.as_ptr() as *const c_void, content.len() as libc::size_t) == -1 {
|
||||
panic!("failed to write to memfd");
|
||||
}
|
||||
|
||||
@@ -49,44 +36,25 @@ def_hook!(
|
||||
}
|
||||
);
|
||||
|
||||
pub fn add_linker_shared_library(
|
||||
mut env: JNIEnv,
|
||||
_: *mut c_void,
|
||||
path: JString,
|
||||
content: JByteArray,
|
||||
) {
|
||||
pub fn add_linker_shared_library(mut env: JNIEnv, _: *mut c_void, path: JString, content: JByteArray) {
|
||||
let path = env.get_string(&path).unwrap().to_str().unwrap().to_string();
|
||||
let content_length = env
|
||||
.get_array_length(&content)
|
||||
.expect("Failed to get array length");
|
||||
let content_length = env.get_array_length(&content).expect("Failed to get array length");
|
||||
let mut content_buffer = Box::new(vec![0i8; content_length as usize]);
|
||||
|
||||
env.get_byte_array_region(content, 0, content_buffer.as_mut_slice())
|
||||
.expect("Failed to get byte array region");
|
||||
|
||||
|
||||
env.get_byte_array_region(content, 0, content_buffer.as_mut_slice()).expect("Failed to get byte array region");
|
||||
|
||||
debug!("added shared library: {}", path);
|
||||
|
||||
SHARED_LIBRARIES
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(path, content_buffer);
|
||||
SHARED_LIBRARIES.lock().unwrap().insert(path, content_buffer);
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let linker = {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
elf::Elf::from_maps("/linker64").expect("Failed to find linker64 in maps")
|
||||
}
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
elf::Elf::from_maps("/linker").expect("Failed to find linker in maps")
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(ptr) = linker.get_symbol_address("__dl___openat") {
|
||||
dobby_hook!(ptr as _, linker_openat);
|
||||
} else {
|
||||
panic!("Failed to find open symbol");
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
dobby_hook_sym!("linker64", "__dl___openat", linker_openat);
|
||||
}
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
dobby_hook_sym!("linker", "__dl___openat", linker_openat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
pub mod custom_font_hook;
|
||||
pub mod duplex_hook;
|
||||
pub mod fstat_hook;
|
||||
pub mod linker_hook;
|
||||
pub mod sqlite_hook;
|
||||
pub mod unary_call_hook;
|
||||
pub mod util;
|
||||
pub mod linker_hook;
|
||||
pub mod duplex_hook;
|
||||
pub mod sqlite_hook;
|
||||
pub mod fstat_hook;
|
||||
pub mod unary_call_hook;
|
||||
pub mod valdi_hook;
|
||||
pub mod custom_font_hook;
|
||||
|
||||
@@ -1,34 +1,25 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::{c_void, CStr},
|
||||
mem::size_of,
|
||||
ptr::addr_of_mut,
|
||||
sync::Mutex,
|
||||
};
|
||||
use std::{collections::HashMap, ffi::{c_void, CStr}, mem::size_of, ptr::addr_of_mut, sync::Mutex};
|
||||
|
||||
use jni::{
|
||||
objects::{JObject, JString},
|
||||
JNIEnv,
|
||||
};
|
||||
use jni::{objects::{JObject, JString}, JNIEnv};
|
||||
use nix::libc::{self, pthread_mutex_t};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{common, def_hook, dobby_hook, sig, util::get_jni_string};
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Sqlite3Mutex {
|
||||
mutex: pthread_mutex_t,
|
||||
mutex: pthread_mutex_t
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Sqlite3 {
|
||||
pad: [u8; 3 * size_of::<usize>()],
|
||||
mutex: *mut Sqlite3Mutex,
|
||||
mutex: *mut Sqlite3Mutex
|
||||
}
|
||||
|
||||
static SQLITE3_MUTEX_MAP: Lazy<Mutex<HashMap<String, pthread_mutex_t>>> =
|
||||
Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
static SQLITE3_MUTEX_MAP: Lazy<Mutex<HashMap<String, pthread_mutex_t>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
def_hook!(
|
||||
sqlite3_open,
|
||||
@@ -40,38 +31,27 @@ def_hook!(
|
||||
let sqlite3_mutex = (**pp_db).mutex;
|
||||
|
||||
if sqlite3_mutex != std::ptr::null_mut() {
|
||||
let filename = CStr::from_ptr(filename)
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
.split("/")
|
||||
.last()
|
||||
.expect("Failed to get filename")
|
||||
.to_string();
|
||||
let filename = CStr::from_ptr(filename).to_string_lossy().to_string().split("/").last().expect("Failed to get filename").to_string();
|
||||
debug!("sqlite3_open hook {:?}", filename);
|
||||
|
||||
SQLITE3_MUTEX_MAP
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(filename, (*sqlite3_mutex).mutex);
|
||||
SQLITE3_MUTEX_MAP.lock().unwrap().insert(
|
||||
filename,
|
||||
(*sqlite3_mutex).mutex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
pub fn lock_database(mut env: JNIEnv, _: *mut c_void, filename: JString, runnable: JObject) {
|
||||
let database_filename =
|
||||
get_jni_string(&mut env, filename).expect("Failed to get database filename");
|
||||
let mutex = SQLITE3_MUTEX_MAP
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&database_filename)
|
||||
.map(|mutex| *mutex);
|
||||
let database_filename = get_jni_string(&mut env, filename).expect("Failed to get database filename");
|
||||
let mutex = SQLITE3_MUTEX_MAP.lock().unwrap().get(&database_filename).map(|mutex| *mutex);
|
||||
|
||||
let call_runnable = || {
|
||||
env.call_method(runnable, "run", "()V", &[])
|
||||
.expect("Failed to call run method");
|
||||
env.call_method(runnable, "run", "()V", &[]).expect("Failed to call run method");
|
||||
};
|
||||
|
||||
if let Some(mut mutex) = mutex {
|
||||
@@ -91,17 +71,16 @@ pub fn lock_database(mut env: JNIEnv, _: *mut c_void, filename: JString, runnabl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn init() {
|
||||
if let Some(signature) = sig::find_signature(
|
||||
&common::CLIENT_MODULE,
|
||||
"FF FF 00 A9 3F 00 00 F9",
|
||||
-0x3C,
|
||||
"9A 46 90 46 78 44 89 46 05 68",
|
||||
-0xd,
|
||||
&common::CLIENT_MODULE,
|
||||
"FF FF 00 A9 3F 00 00 F9", -0x3C,
|
||||
"9A 46 90 46 78 44 89 46 05 68",-0xd
|
||||
) {
|
||||
debug!("Found sqlite3_open signature: {:#x}", signature);
|
||||
dobby_hook!(signature as *mut c_void, sqlite3_open);
|
||||
} else {
|
||||
panic!("Failed to find sqlite3_open signature");
|
||||
warn!("Failed to find sqlite3_open signature");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,17 @@
|
||||
use std::ffi::{c_void, CStr};
|
||||
|
||||
use jni::{
|
||||
objects::{JByteArray, JMethodID, JValue},
|
||||
signature::ReturnType,
|
||||
};
|
||||
use jni::{objects::{JByteArray, JMethodID, JValue}, signature::ReturnType};
|
||||
use nix::libc;
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::{
|
||||
common::{self},
|
||||
def_hook, dobby_hook, sig,
|
||||
};
|
||||
use crate::{common::{self}, def_hook, dobby_hook, sig};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct SliceByteBuffer {
|
||||
struct RefCountedSliceByteBuffer {
|
||||
ref_counter: *mut c_void,
|
||||
length: usize,
|
||||
data: *mut u8,
|
||||
data: *mut u8
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@@ -25,7 +19,7 @@ struct GrpcByteBuffer {
|
||||
reserved: *mut c_void,
|
||||
type_: *mut c_void,
|
||||
compression: *mut c_void,
|
||||
slice_buffer: *mut SliceByteBuffer,
|
||||
slice_buffer: *mut RefCountedSliceByteBuffer
|
||||
}
|
||||
|
||||
static NATIVE_LIB_ON_UNARY_CALL_METHOD: OnceCell<JMethodID> = OnceCell::new();
|
||||
@@ -33,12 +27,7 @@ static NATIVE_LIB_ON_UNARY_CALL_METHOD: OnceCell<JMethodID> = OnceCell::new();
|
||||
def_hook!(
|
||||
unary_call,
|
||||
*mut c_void,
|
||||
|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| {
|
||||
|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| {
|
||||
macro_rules! call_original {
|
||||
() => {
|
||||
unary_call_original.unwrap()(unk1, uri, grpc_byte_buffer, unk4, unk5, unk6)
|
||||
@@ -56,73 +45,45 @@ def_hook!(
|
||||
let mut env = java_vm.get_env().expect("Failed to get JNIEnv");
|
||||
|
||||
let slice_buffer_length = slice_buffer.length as usize;
|
||||
let jni_buffer = env
|
||||
.new_byte_array(slice_buffer_length as i32)
|
||||
.expect("Failed to create new byte array");
|
||||
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");
|
||||
let jni_buffer = env.new_byte_array(slice_buffer_length as i32).expect("Failed to create new byte array");
|
||||
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");
|
||||
|
||||
let uri_str = CStr::from_ptr(uri).to_str().unwrap();
|
||||
|
||||
let native_request_data_object = env
|
||||
.call_method_unchecked(
|
||||
common::native_lib_instance(),
|
||||
NATIVE_LIB_ON_UNARY_CALL_METHOD.get().unwrap(),
|
||||
ReturnType::Object,
|
||||
&[
|
||||
JValue::from(&env.new_string(uri_str).unwrap()).as_jni(),
|
||||
JValue::from(&jni_buffer).as_jni(),
|
||||
],
|
||||
)
|
||||
.expect("Failed to call onNativeUnaryCall method")
|
||||
.l()
|
||||
.unwrap();
|
||||
let native_request_data_object = env.call_method_unchecked(
|
||||
common::native_lib_instance(),
|
||||
NATIVE_LIB_ON_UNARY_CALL_METHOD.get().unwrap(),
|
||||
ReturnType::Object,
|
||||
&[
|
||||
JValue::from(&env.new_string(uri_str).unwrap()).as_jni(),
|
||||
JValue::from(&jni_buffer).as_jni()
|
||||
]
|
||||
).expect("Failed to call onNativeUnaryCall method").l().unwrap();
|
||||
|
||||
if native_request_data_object.is_null() {
|
||||
return call_original!();
|
||||
}
|
||||
|
||||
let is_canceled = env
|
||||
.get_field(&native_request_data_object, "canceled", "Z")
|
||||
.expect("Failed to get canceled field")
|
||||
.z()
|
||||
.unwrap();
|
||||
let is_canceled = env.get_field(&native_request_data_object, "canceled", "Z").expect("Failed to get canceled field").z().unwrap();
|
||||
|
||||
if is_canceled {
|
||||
info!("canceled request for {}", uri_str);
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let new_buffer: JByteArray = env
|
||||
.get_field(&native_request_data_object, "buffer", "[B")
|
||||
.expect("Failed to get buffer field")
|
||||
.l()
|
||||
.unwrap()
|
||||
.into();
|
||||
let new_buffer_length = env
|
||||
.get_array_length(&new_buffer)
|
||||
.expect("Failed to get array length") as usize;
|
||||
let new_buffer: JByteArray = env.get_field(&native_request_data_object, "buffer", "[B").expect("Failed to get buffer field").l().unwrap().into();
|
||||
let new_buffer_length = env.get_array_length(&new_buffer).expect("Failed to get array length") as usize;
|
||||
|
||||
let mut new_buffer_data = Box::new(vec![0i8; new_buffer_length]);
|
||||
env.get_byte_array_region(&new_buffer, 0, new_buffer_data.as_mut_slice())
|
||||
.expect("Failed to get byte array region");
|
||||
env.get_byte_array_region(&new_buffer, 0, new_buffer_data.as_mut_slice()).expect("Failed to get byte array region");
|
||||
|
||||
let ref_counter_struct_size =
|
||||
(slice_buffer.data as usize) - (slice_buffer.ref_counter as usize);
|
||||
let ref_counter_struct_size = (slice_buffer.data as usize) - (slice_buffer.ref_counter as usize);
|
||||
|
||||
//we need to allocate a new ref_counter struct and copy the old ref_counter and the new_buffer to it
|
||||
let new_ref = {
|
||||
let new_ref = libc::malloc(ref_counter_struct_size + new_buffer_length) as *mut c_void;
|
||||
libc::memcpy(new_ref, slice_buffer.ref_counter, ref_counter_struct_size);
|
||||
libc::memcpy(
|
||||
new_ref.offset(ref_counter_struct_size as isize),
|
||||
new_buffer_data.as_ptr() as *const c_void,
|
||||
new_buffer_length,
|
||||
);
|
||||
libc::memcpy(new_ref.offset(ref_counter_struct_size as isize), new_buffer_data.as_ptr() as *const c_void, new_buffer_length);
|
||||
libc::free(slice_buffer.ref_counter);
|
||||
new_ref
|
||||
};
|
||||
@@ -143,25 +104,20 @@ def_hook!(
|
||||
pub fn init() {
|
||||
if let Some(signature) = sig::find_signature(
|
||||
&common::CLIENT_MODULE,
|
||||
"AA A8 03 1F F8 ?? ?? 00 94 ?? ?? 05 91",
|
||||
-0x47,
|
||||
"0A 90 00 F0 3F F9",
|
||||
-0x37,
|
||||
"A8 03 1F F8 ?? ?? 00 94 ?? ?? ?? 91 ?? ?? ?? A9", -0x48,
|
||||
"0A 90 00 F0 3F F9", -0x37
|
||||
) {
|
||||
dobby_hook!(signature as *mut c_void, unary_call);
|
||||
common::attach_jni_env(|env| {
|
||||
NATIVE_LIB_ON_UNARY_CALL_METHOD
|
||||
.set(
|
||||
env.get_method_id(
|
||||
env.get_object_class(common::native_lib_instance()).unwrap(),
|
||||
"onNativeUnaryCall",
|
||||
"(Ljava/lang/String;[B)Lme/eternal/purrfectsnap/nativelib/NativeRequestData;",
|
||||
)
|
||||
.expect("Failed to get onNativeUnaryCall method id"),
|
||||
)
|
||||
.expect("unary call method already set");
|
||||
NATIVE_LIB_ON_UNARY_CALL_METHOD.set(
|
||||
env.get_method_id(
|
||||
env.get_object_class(common::native_lib_instance()).unwrap(),
|
||||
"onNativeUnaryCall",
|
||||
"(Ljava/lang/String;[B)Lme/eternal/purrfectsnap/nativelib/NativeRequestData;"
|
||||
).expect("Failed to get onNativeUnaryCall method id")
|
||||
).expect("unary call method already set");
|
||||
});
|
||||
} else {
|
||||
panic!("Can't find unaryCall signature");
|
||||
error!("Can't find unaryCall signature");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
use procfs::process::MMapPath;
|
||||
|
||||
pub struct Elf<'elf> {
|
||||
base_address: usize,
|
||||
elf: goblin::elf::Elf<'elf>,
|
||||
_buffer: &'elf [u8],
|
||||
}
|
||||
|
||||
impl<'elf> Elf<'elf> {
|
||||
pub fn from_maps(lib: &str) -> Option<Self> {
|
||||
let maps = procfs::process::Process::myself().ok()?.maps().ok()?;
|
||||
|
||||
for memory_map in maps.iter() {
|
||||
if let MMapPath::Path(path) = &memory_map.pathname {
|
||||
let path = path.to_string_lossy();
|
||||
|
||||
if !path.contains(lib) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let file_data = std::fs::read(path.to_string()).ok()?;
|
||||
let file_buffer = Box::leak(file_data.into_boxed_slice());
|
||||
|
||||
if let Ok(elf) = goblin::elf::Elf::parse(file_buffer) {
|
||||
return Some(Elf {
|
||||
base_address: memory_map.address.0 as usize,
|
||||
elf,
|
||||
_buffer: file_buffer,
|
||||
});
|
||||
} else {
|
||||
warn!(
|
||||
"Failed to parse ELF for library {} at address {:x}",
|
||||
lib, memory_map.address.0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_symbol_address(&self, symbol: &str) -> Option<usize> {
|
||||
for sym in &self.elf.dynsyms {
|
||||
if let Some(name) = self.elf.dynstrtab.get_at(sym.st_name) {
|
||||
if name == symbol {
|
||||
return Some(self.base_address + sym.st_value as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for sym in &self.elf.syms {
|
||||
if let Some(name) = self.elf.strtab.get_at(sym.st_name) {
|
||||
if name == symbol {
|
||||
return Some(self.base_address + sym.st_value as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1 @@
|
||||
pub mod elf;
|
||||
pub mod valdi_utils;
|
||||
|
||||
@@ -43,12 +43,7 @@ pub struct ValdiModule {
|
||||
impl ValdiModule {
|
||||
pub fn parse(buffer: Vec<u8>) -> Result<ValdiModule, Error> {
|
||||
let mut offset = 0;
|
||||
let magic = u32::from_be_bytes([
|
||||
buffer[offset],
|
||||
buffer[offset + 1],
|
||||
buffer[offset + 2],
|
||||
buffer[offset + 3],
|
||||
]);
|
||||
let magic = u32::from_be_bytes([buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]]);
|
||||
|
||||
offset += 4;
|
||||
|
||||
@@ -90,12 +85,13 @@ impl ValdiModule {
|
||||
tags.push(ModuleTag::new(has_padding, tag_buffer));
|
||||
}
|
||||
|
||||
let tags = tags
|
||||
.chunks(2)
|
||||
.map(|chunk| (chunk[0].clone(), chunk[1].clone()))
|
||||
.collect();
|
||||
let tags = tags.chunks(2).map(|chunk| {
|
||||
(chunk[0].clone(), chunk[1].clone())
|
||||
}).collect();
|
||||
|
||||
Ok(ValdiModule { tags })
|
||||
Ok(ValdiModule {
|
||||
tags,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
use super::util::valdi_utils::{ModuleTag, ValdiModule};
|
||||
use crate::{config, def_hook, dobby_hook, modules::util::elf, util::get_jni_string};
|
||||
#![allow(dead_code, unused_imports)]
|
||||
|
||||
use super::util::valdi_utils::{ValdiModule, ModuleTag};
|
||||
use std::{collections::HashMap, ffi::c_void, sync::Mutex};
|
||||
use jni::{objects::JString, JNIEnv};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::c_void,
|
||||
sync::Mutex,
|
||||
};
|
||||
use crate::{common, config, def_hook, dobby_hook, dobby_hook_sym, util::get_jni_string};
|
||||
|
||||
static AASSET_MAP: Lazy<Mutex<HashMap<usize, Vec<u8>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
static LOADER_DATA: Mutex<Option<String>> = Mutex::new(None);
|
||||
|
||||
def_hook!(aasset_get_length, i32, |arg0: *mut c_void| {
|
||||
if let Some(buffer) = AASSET_MAP.lock().unwrap().get(&(arg0 as usize)) {
|
||||
return buffer.len() as i32;
|
||||
def_hook!(
|
||||
aasset_get_length,
|
||||
i32,
|
||||
|arg0: *mut c_void| {
|
||||
if let Some(buffer) = AASSET_MAP.lock().unwrap().get(&(arg0 as usize)) {
|
||||
return buffer.len() as i32;
|
||||
}
|
||||
aasset_get_length_original.unwrap()(arg0)
|
||||
}
|
||||
aasset_get_length_original.unwrap()(arg0)
|
||||
});
|
||||
);
|
||||
|
||||
def_hook!(aasset_get_buffer, *const c_void, |arg0: *mut c_void| {
|
||||
if let Some(buffer) = AASSET_MAP.lock().unwrap().get(&(arg0 as usize)) {
|
||||
return buffer.as_ptr() as *const c_void;
|
||||
def_hook!(
|
||||
aasset_get_buffer,
|
||||
*const c_void,
|
||||
|arg0: *mut c_void| {
|
||||
if let Some(buffer) = AASSET_MAP.lock().unwrap().get(&(arg0 as usize)) {
|
||||
return buffer.as_ptr() as *const c_void;
|
||||
}
|
||||
aasset_get_buffer_original.unwrap()(arg0)
|
||||
}
|
||||
aasset_get_buffer_original.unwrap()(arg0)
|
||||
});
|
||||
);
|
||||
|
||||
def_hook!(
|
||||
aasset_manager_open,
|
||||
@@ -39,13 +45,9 @@ def_hook!(
|
||||
|
||||
let loader_data = LOADER_DATA.lock().unwrap().clone().expect("No loader data");
|
||||
|
||||
let archive_buffer: Vec<u8> =
|
||||
std::slice::from_raw_parts(asset_buffer as *const u8, asset_length as usize)
|
||||
.to_vec();
|
||||
let decompressed = zstd::stream::decode_all(&archive_buffer[..])
|
||||
.expect("Failed to decompress valdi archive");
|
||||
let mut valdi_module =
|
||||
ValdiModule::parse(decompressed).expect("Failed to parse valdi module");
|
||||
let archive_buffer: Vec<u8> = std::slice::from_raw_parts(asset_buffer as *const u8, asset_length as usize).to_vec();
|
||||
let decompressed = zstd::stream::decode_all(&archive_buffer[..]).expect("Failed to decompress valdi archive");
|
||||
let mut valdi_module = ValdiModule::parse(decompressed).expect("Failed to parse valdi module");
|
||||
|
||||
let mut tags = valdi_module.get_tags();
|
||||
let mut new_tags = Vec::new();
|
||||
@@ -56,22 +58,19 @@ def_hook!(
|
||||
continue;
|
||||
}
|
||||
|
||||
let old_file_name = name.split_once(".").unwrap().0.to_owned()
|
||||
+ rand::random::<u32>().to_string().as_str();
|
||||
let old_file_name = name.split_once(".").unwrap().0.to_owned() + rand::random::<u32>().to_string().as_str();
|
||||
tag1.set_buffer((old_file_name.to_owned() + ".js").as_bytes().to_vec());
|
||||
let original_module_path =
|
||||
path.split_once(".").unwrap().0.to_owned() + "/" + &old_file_name;
|
||||
let original_module_path = path.split_once(".").unwrap().0.to_owned() + "/" + &old_file_name;
|
||||
|
||||
let hooked_module = format!(
|
||||
"{};module.exports = require(\"{}\");",
|
||||
loader_data, original_module_path
|
||||
let hooked_module = format!("{};module.exports = require(\"{}\");", loader_data, original_module_path);
|
||||
|
||||
new_tags.push(
|
||||
(
|
||||
ModuleTag::new(true, name.as_bytes().to_vec()),
|
||||
ModuleTag::new(true, hooked_module.as_bytes().to_vec())
|
||||
)
|
||||
);
|
||||
|
||||
new_tags.push((
|
||||
ModuleTag::new(true, name.as_bytes().to_vec()),
|
||||
ModuleTag::new(true, hooked_module.as_bytes().to_vec()),
|
||||
));
|
||||
|
||||
debug!("Valdi loader injected in {}", name);
|
||||
break;
|
||||
}
|
||||
@@ -80,22 +79,22 @@ def_hook!(
|
||||
valdi_module.set_tags(tags);
|
||||
|
||||
let compressed = valdi_module.to_bytes();
|
||||
let compressed =
|
||||
zstd::stream::encode_all(&compressed[..], 3).expect("Failed to compress");
|
||||
let compressed = zstd::stream::encode_all(&compressed[..], 3).expect("Failed to compress");
|
||||
|
||||
AASSET_MAP
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(handle as usize, compressed);
|
||||
AASSET_MAP.lock().unwrap().insert(handle as usize, compressed);
|
||||
}
|
||||
handle
|
||||
}
|
||||
);
|
||||
|
||||
def_hook!(aasset_close, c_void, |handle: *mut c_void| {
|
||||
AASSET_MAP.lock().unwrap().remove(&(handle as usize));
|
||||
aasset_close_original.unwrap()(handle)
|
||||
});
|
||||
def_hook!(
|
||||
aasset_close,
|
||||
c_void,
|
||||
|handle: *mut c_void| {
|
||||
AASSET_MAP.lock().unwrap().remove(&(handle as usize));
|
||||
aasset_close_original.unwrap()(handle)
|
||||
}
|
||||
);
|
||||
|
||||
pub fn set_valdi_loader(mut env: JNIEnv, _: *mut c_void, code: JString) {
|
||||
let new_code = get_jni_string(&mut env, code).expect("Failed to get loader code");
|
||||
@@ -104,33 +103,11 @@ pub fn set_valdi_loader(mut env: JNIEnv, _: *mut c_void, code: JString) {
|
||||
|
||||
pub fn init() {
|
||||
if !config::native_config().valdi_hooks {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let lib_android =
|
||||
elf::Elf::from_maps("/libandroid.so").expect("Failed to find libandroid.so in maps");
|
||||
|
||||
if let Some(ptr) = lib_android.get_symbol_address("AAsset_getBuffer") {
|
||||
dobby_hook!(ptr as _, aasset_get_buffer);
|
||||
} else {
|
||||
panic!("Failed to find AAsset_getBuffer symbol");
|
||||
}
|
||||
|
||||
if let Some(ptr) = lib_android.get_symbol_address("AAsset_getLength") {
|
||||
dobby_hook!(ptr as _, aasset_get_length);
|
||||
} else {
|
||||
panic!("Failed to find AAsset_getLength symbol");
|
||||
}
|
||||
|
||||
if let Some(ptr) = lib_android.get_symbol_address("AAsset_close") {
|
||||
dobby_hook!(ptr as _, aasset_close);
|
||||
} else {
|
||||
panic!("Failed to find AAsset_close symbol");
|
||||
}
|
||||
|
||||
if let Some(ptr) = lib_android.get_symbol_address("AAssetManager_open") {
|
||||
dobby_hook!(ptr as _, aasset_manager_open);
|
||||
} else {
|
||||
panic!("Failed to find AAssetManager_open symbol");
|
||||
}
|
||||
dobby_hook_sym!("libandroid.so", "AAsset_getBuffer", aasset_get_buffer);
|
||||
dobby_hook_sym!("libandroid.so", "AAsset_getLength", aasset_get_length);
|
||||
dobby_hook_sym!("libandroid.so", "AAsset_close", aasset_close);
|
||||
dobby_hook_sym!("libandroid.so", "AAssetManager_open", aasset_manager_open);
|
||||
}
|
||||
|
||||
@@ -61,18 +61,8 @@ pub fn find_signatures(module_base: usize, bytes_buffer: &[u8], pattern: &str, o
|
||||
let mut mask = Vec::new();
|
||||
let mut i = 0;
|
||||
|
||||
if let Some(cache) = SIGNATURE_CACHE
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|(sig, _)| sig == pattern)
|
||||
{
|
||||
return cache
|
||||
.1
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|offset| module_base + offset)
|
||||
.collect();
|
||||
if let Some(cache) = SIGNATURE_CACHE.lock().unwrap().iter().find(|(sig, _)| sig == pattern) {
|
||||
return cache.1.clone().into_iter().map(|offset| module_base + offset).collect();
|
||||
}
|
||||
|
||||
while i < pattern.len() {
|
||||
@@ -80,7 +70,7 @@ pub fn find_signatures(module_base: usize, bytes_buffer: &[u8], pattern: &str, o
|
||||
bytes.push(0);
|
||||
mask.push('?');
|
||||
} else {
|
||||
bytes.push(u8::from_str_radix(&pattern[i..i + 2], 16).unwrap());
|
||||
bytes.push(u8::from_str_radix(&pattern[i..i+2], 16).unwrap());
|
||||
mask.push('x');
|
||||
}
|
||||
i += 3;
|
||||
@@ -102,10 +92,7 @@ pub fn find_signatures(module_base: usize, bytes_buffer: &[u8], pattern: &str, o
|
||||
}
|
||||
if found {
|
||||
if once {
|
||||
SIGNATURE_CACHE
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((pattern.to_string(), vec![i]));
|
||||
SIGNATURE_CACHE.lock().unwrap().push((pattern.to_string(), vec![i]));
|
||||
return vec![module_base + i];
|
||||
}
|
||||
results.push(module_base + i);
|
||||
@@ -113,22 +100,14 @@ pub fn find_signatures(module_base: usize, bytes_buffer: &[u8], pattern: &str, o
|
||||
i += 1;
|
||||
}
|
||||
|
||||
SIGNATURE_CACHE
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((pattern.to_string(), results.clone()));
|
||||
SIGNATURE_CACHE.lock().unwrap().push((pattern.to_string(), results.clone()));
|
||||
results
|
||||
}
|
||||
|
||||
pub fn find_signature_executable(mapped_lib: &MappedLib, pattern: &str) -> Option<usize> {
|
||||
let executable_regions = mapped_lib
|
||||
.regions
|
||||
.iter()
|
||||
.filter(|region| {
|
||||
region.perms.contains(MMPermissions::EXECUTE)
|
||||
&& region.perms.contains(MMPermissions::READ)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let executable_regions = mapped_lib.regions.iter().filter(|region| {
|
||||
region.perms.contains(MMPermissions::EXECUTE)
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
for region in executable_regions {
|
||||
let size = (region.end - region.start) as usize;
|
||||
@@ -138,27 +117,16 @@ pub fn find_signature_executable(mapped_lib: &MappedLib, pattern: &str) -> Optio
|
||||
let bytes_buffer = match read_region_bytes(module_base, size) {
|
||||
Some(buffer) => buffer,
|
||||
None => {
|
||||
warn!(
|
||||
"Unable to read executable region: {:#x} - {:#x}",
|
||||
region.start, region.end
|
||||
);
|
||||
warn!("Unable to read executable region: {:#x} - {:#x}", region.start, region.end);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let results = find_signatures(module_base, &bytes_buffer, pattern, true);
|
||||
|
||||
if results.is_empty() {
|
||||
warn!(
|
||||
"Signature not found in region: {:#x} - {:#x}",
|
||||
region.start, region.end
|
||||
);
|
||||
warn!("Signature not found in region: {:#x} - {:#x}", region.start, region.end);
|
||||
} else {
|
||||
debug!(
|
||||
"Found {} results in region: {:#x} - {:#x}",
|
||||
results.len(),
|
||||
region.start,
|
||||
region.end
|
||||
);
|
||||
debug!("Found {} results in region: {:#x} - {:#x}", results.len(), region.start, region.end);
|
||||
return Some(results[0]);
|
||||
}
|
||||
}
|
||||
@@ -167,21 +135,13 @@ pub fn find_signature_executable(mapped_lib: &MappedLib, pattern: &str) -> Optio
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_signature(
|
||||
mapped_lib: &MappedLib,
|
||||
_arm64_pattern: &str,
|
||||
_arm64_offset: i64,
|
||||
_arm32_pattern: &str,
|
||||
_arm32_offset: i64,
|
||||
) -> Option<usize> {
|
||||
pub fn find_signature(mapped_lib: &MappedLib, _arm64_pattern: &str, _arm64_offset: i64, _arm32_pattern: &str, _arm32_offset: i64) -> Option<usize> {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
return find_signature_executable(mapped_lib, _arm64_pattern)
|
||||
.map(|address| (address as i64 + _arm64_offset) as usize);
|
||||
return find_signature_executable(mapped_lib, _arm64_pattern).map(|address| (address as i64 + _arm64_offset) as usize);
|
||||
}
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
return find_signature_executable(mapped_lib, _arm32_pattern)
|
||||
.map(|address| (address as i64 + _arm32_offset) as usize);
|
||||
return find_signature_executable(mapped_lib, _arm32_pattern).map(|address| (address as i64 + _arm32_offset) as usize);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user