-
Notifications
You must be signed in to change notification settings - Fork 20
Home
微生 edited this page Oct 27, 2024
·
2 revisions
Welcome to the rnidbg wiki!
const PID: u32 = 2667; // 系统调用getpid()的返回值
const PPID: u32 = 2427; // getppid()
let emulator = AndroidEmulator::create_arm64(PID, PPID, "com.tencent.mobileqq:MSF", data);
let memory = emulator.memory();
let mut libc = Box::new(Libc::new());
libc.set_system_property_service(Rc::new(Box::new(move |name| match name {
"ro.build.version.sdk" => Some(device_info.build_version.clone()),
"persist.sys.timezone" => Some("Asia/Shanghai".to_string()),
"gsm.version.baseband" => Some("MOLY.LR12A.R3.MP.V79.P10".into()),
_ => {
if option_env!("FUQIULUO_DEBUG") == Some("1") {
info!("unresolved property: {}", name)
}
panic!("name={}", name)
}
})));
memory.add_hook_listeners(libc);
目前的libc只能监听并劫持部分调用,大部分调用使用从安卓环境提取的so文件转译执行实现,后续将移除该so文件!
let system_base_path = emulator.get_base_path().to_string();
let file_system = emulator.get_file_system();
file_system.set_file_resolver(Box::new(move |_, path, flags, mode| {
if path == "/data/user/0/com.tencent.mobileqq/files/5463306EE50FE3AA/6FAcBa17D93747A5" {
if flags == OFlag::O_RDONLY {
if let Ok(file) = File::open(format!("{}/6FAcBa17D93747A5", base_path)) {
return Some(FileIO::File(LinuxFileIO::new_with_file(
file,
path,
flags.bits(),
12345,
StMode::APP_FILE
))); // 返回真实环境的文件
}
return None;
} else if flags == (OFlag::O_WRONLY | OFlag::O_CREAT | OFlag::O_TRUNC) {
let file = File::create(format!("{}/6FAcBa17D93747A5", base_path)).unwrap();
return Some(FileIO::File(LinuxFileIO::new_with_file(
file,
path,
flags.bits(),
12345,
StMode::APP_FILE
))); // 根据flags要求,创建文件
} else {
if option_env!("FUQIULUO_DEBUG") == Some("1") {
info!("unresolved file_resolver: path={}, flags={:?}, mode={}", path, flags, mode);
}
panic!("unsupported flags: {:?}", flags);
}
}
if path == "/sdcard/Android/.android_lq" {
return None // 文件不存在返回None
}
if path == "/sdcard/Android/" {
return Some(FileIO::Direction(Direction::new(VecDeque::new(), path))) // 返回空文件夹
}
if path == "/proc/self/cmdline" || path == format!("/proc/{}/cmdline", PID) {
return Some(FileIO::Bytes(ByteArrayFileIO::new(b"com.tencent.mobileqq:MSF\0".to_vec(), path.to_string(), 12345, flags.bits(), StMode::APP_FILE))) // 内存数据假装一个文件
}
if path == "/data/app/~~vbcRLwPxS0GyVfqT-nCYrQ==/com.tencent.mobileqq-xJKJPVp9lorkCgR_w5zhyA==/lib/arm64" {
let mut files = VecDeque::new();
files.push_back(DirectionEntry::new(true, "libfekit.so"));
files.push_back(DirectionEntry::new(true, "libwtecdh.so"));
files.push_back(DirectionEntry::new(true, "libmmkv.so"));
files.push_back(DirectionEntry::new(true, "libQSec.so"));
files.push_back(DirectionEntry::new(true, "libqimei.so"));
return Some(FileIO::Direction(Direction::new(files, path)))
} // 返回带有子文件和子目录的文件夹
if option_env!("FUQIULUO_DEBUG") == Some("1") {
info!("unresolved file_resolver: path={}, flags={:?}, mode={}", path, flags, mode);
panic!("unresolved file_resolver: path={}, flags={:?}, mode={}", path, flags, mode);
} else {
return None
}
}));
let vm = emulator.get_dalvik_vm();
vm.set_class_resolver(ClassResolver::new(vec![
"com/tencent/mobileqq/qsec/qsecprotocol/ByteData",
"com/tencent/mobileqq/qsec/qsecdandelionsdk/Dandelion",
"com/tencent/mobileqq/qsec/qseccodec/SecCipher",
"com/tencent/mobileqq/qsec/qsecurity/QSec",
"com/tencent/mobileqq/sign/QQSecuritySign$SignResult",
"com/tencent/mobileqq/sign/QQSecuritySign",
"com/tencent/mobileqq/channel/ChannelManager",
]));
pub struct MyJni {
}
impl<T: Clone> Jni<T> for MyJni {
fn resolve_method(
&self,
vm: &mut DalvikVM64<T>,
class: &Rc<DvmClass>,
name: &str,
signature: &str,
is_static: bool,
) -> bool {
if class.name == "java/lang/String" {
if name == "<init>" && signature == "([BLjava/lang/String;)V" && !is_static {
return true;
}
if name == "hashCode" && signature == "()I" && !is_static {
return true;
}
}
return true // 判断方法是否存在,不存在将会抛出异常给模拟调用中的二进制文件
}
fn resolve_filed(
&self,
vm: &mut DalvikVM64<T>,
class: &Rc<DvmClass>,
name: &str,
signature: &str,
is_static: bool,
) -> bool {
if class.name == "android/os/Build$VERSION"
&& name == "SDK_INT"
&& signature == "I"
&& is_static
{
return true;
}
return true
}
fn call_method_v(
&self,
vm: &mut DalvikVM64<T>,
acc: MethodAcc,
class: &Rc<DvmClass>,
method: &DvmMethod,
instance: Option<&mut DvmObject>,
args: &mut VaList<T>,
) -> JniValue {
if acc.contains(MethodAcc::CONSTRUCTOR) {
if class.name == "java/lang/String" {
if method.name == "<init>" && method.signature == "([BLjava/lang/String;)V" {
let result = String::from_utf8(args.get::<Vec<u8>>()).unwrap();
let charset = args.get::<String>();
return DvmObject::String(result).into();
}
}
}
panic!("?")
}
fn get_field_value(
&self,
vm: &mut DalvikVM64<T>,
class: &Rc<DvmClass>,
field: &DvmField,
instance: Option<&mut DvmObject>,
) -> JniValue {
// do something
}
fn set_field_value(
&self,
vm: &mut DalvikVM64<T>,
class: &Rc<DvmClass>,
field: &DvmField,
instance: Option<&mut DvmObject>,
value: JniValue,
) {
// do something
}
}
let mut jni = Box::new(MyJni::new());
vm.set_jni(jni);
let dm = vm
.load_library(
emulator.clone(),
&format!("{}/libfql.so", base_path),
true,
)
.map_err(|e| eprintln!("failed to load_library: {}", e))
.unwrap();
let context = vm
.resolve_class_unchecked("android/content/Context")
.1
.new_simple_instance(vm);
let dtn = vm
.resolve_class_unchecked("com/baidu/XXX/dt/Dtn")
.1
.new_simple_instance(vm);
dtn.call_method(
emulator,
vm,
"initContext",
"(Landroid/content/Context;Ljava/lang/String;)V",
vec![
JniValue::Object(context.clone()),
"/data/user/0/com.baidu.map/files/5463306EE50FE3AA".into(),
],
);
let qq_security_sign = vm
.resolve_class_unchecked("com/tencent/mobileqq/sign/QQSecuritySign")
.1
.new_simple_instance(vm);
if let DvmObject::ObjectRef(ref_id) = qq_security_sign {
vm.remove_global_ref(ref_id);
}