ci: update debug signing secrets

This commit is contained in:
ΞTΞRNAL
2026-01-16 12:31:17 +05:30
parent 7889fb2ac8
commit 3f11e09a00
9 changed files with 8 additions and 772 deletions

View File

@@ -1,287 +0,0 @@
#![allow(dead_code, unused_imports)]
use super::util::composer_utils::{ComposerModule, ModuleTag};
use std::{collections::HashMap, ffi::{c_void, CStr}, sync::{atomic::{AtomicPtr, Ordering}, Mutex}};
use jni::{objects::JString, sys::jobject, JNIEnv};
use once_cell::sync::Lazy;
use crate::{common, config, def_hook, dobby_hook, dobby_hook_sym, sig, util::get_jni_string};
const JS_TAG_BIG_DECIMAL: i64 = -11;
const JS_TAG_BIG_INT: i64 = -10;
const JS_TAG_BIG_FLOAT: i64 = -9;
const JS_TAG_SYMBOL: i64 = -8;
const JS_TAG_STRING: i64 = -7;
const JS_TAG_MODULE: i64 = -3;
const JS_TAG_FUNCTION_BYTECODE: i64 = -2;
const JS_TAG_OBJECT: i64 = -1;
const JS_TAG_INT: i64 = 0;
const JS_TAG_BOOL: i64 = 1;
const JS_TAG_NULL: i64 = 2;
const JS_TAG_UNDEFINED: i64 = 3;
const JS_TAG_UNINITIALIZED: i64 = 4;
const JS_TAG_CATCH_OFFSET: i64 = 5;
const JS_TAG_EXCEPTION: i64 = 6;
const JS_TAG_FLOAT64: i64 = 7;
#[repr(C)]
struct JsString {
/*
original structure :
struct JSString {
struct JSRefCountHeader {
int ref_count;
};
uint32_t len : 31;
uint8_t is_wide_char : 1;
uint32_t hash : 30;
uint8_t atom_type : 2;
uint32_t hash_next;
union {
uint8_t str8[0];
uint16_t str16[0];
} u;
};
*/
pad: [u32; 4],
str8: [u8; 0],
str16: [u16; 0],
}
#[repr(C)]
#[derive(Copy, Clone)]
union JsValueUnion {
int32: i32,
float64: f64,
ptr: *mut c_void,
}
#[repr(C)]
#[derive(Copy, Clone)]
struct JsValue {
u: JsValueUnion,
tag: i64,
}
static AASSET_MAP: Lazy<Mutex<HashMap<usize, Vec<u8>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
static COMPOSER_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;
}
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;
}
aasset_get_buffer_original.unwrap()(arg0)
}
);
def_hook!(
aasset_manager_open,
*mut c_void,
|arg0: *mut c_void, arg1: *const u8, arg2: i32| {
let handle = aasset_manager_open_original.unwrap()(arg0, arg1, arg2);
let path = Lazy::new(|| CStr::from_ptr(arg1).to_str().unwrap());
if !handle.is_null() && path.starts_with("bridge_observables") {
let asset_buffer = aasset_get_buffer_original.unwrap()(handle);
let asset_length = aasset_get_length_original.unwrap()(handle);
debug!("asset buffer: {:p}, length: {}", asset_buffer, asset_length);
let composer_loader = COMPOSER_LOADER_DATA.lock().unwrap().clone().expect("No composer 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 composer archive");
let mut composer_module = ComposerModule::parse(decompressed).expect("Failed to parse composer module");
let mut tags = composer_module.get_tags();
let mut new_tags = Vec::new();
for (tag1, _) in tags.iter_mut() {
let name = tag1.to_string().unwrap();
if !name.ends_with("src/utils/converter.js") {
continue;
}
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 hooked_module = format!("{};module.exports = require(\"{}\");", composer_loader, original_module_path);
new_tags.push(
(
ModuleTag::new(128, name.as_bytes().to_vec()),
ModuleTag::new(128, hooked_module.as_bytes().to_vec())
)
);
debug!("composer loader injected in {}", name);
break;
}
tags.extend(new_tags);
composer_module.set_tags(tags);
let compressed = composer_module.to_bytes();
let compressed = zstd::stream::encode_all(&compressed[..], 3).expect("Failed to compress");
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)
}
);
#[cfg(target_arch = "aarch64")]
static GLOBAL_INSTANCE: AtomicPtr<c_void> = AtomicPtr::new(std::ptr::null_mut());
#[cfg(target_arch = "aarch64")]
static GLOBAL_CTX: AtomicPtr<c_void> = AtomicPtr::new(std::ptr::null_mut());
#[cfg(target_arch = "aarch64")]
static JS_EVAL_ORIGINAL2: Lazy<Mutex<Option<unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void, *mut u8, usize, *const u8, u32) -> JsValue>>> = Lazy::new(|| Mutex::new(None));
def_hook!(
js_eval,
*mut c_void,
|arg0: *mut c_void, arg1: *mut c_void, arg2: *mut c_void, arg3: *const u8, arg4: *const u8, arg5: *const u8, arg6: *mut c_void, arg7: u32| {
#[cfg(target_arch = "aarch64")]
{
GLOBAL_INSTANCE.store(arg0, Ordering::Relaxed);
GLOBAL_CTX.store(arg1, Ordering::Relaxed);
}
js_eval_original.unwrap()(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
);
pub fn set_composer_loader(mut env: JNIEnv, _: *mut c_void, code: JString) {
let new_code = get_jni_string(&mut env, code).expect("Failed to get composer loader code");
COMPOSER_LOADER_DATA.lock().unwrap().replace(new_code);
}
#[allow(unreachable_code, unused_variables)]
pub unsafe fn composer_eval(env: JNIEnv, _: *mut c_void, script: JString) -> jobject {
#[cfg(target_arch = "aarch64")]
{
let mut env = env;
let script_str = match get_jni_string(&mut env, script) {
Ok(s) => s,
Err(_) => return std::ptr::null_mut(),
};
if JS_EVAL_ORIGINAL2.lock().unwrap().is_none() || GLOBAL_INSTANCE.load(Ordering::Relaxed).is_null() || GLOBAL_CTX.load(Ordering::Relaxed).is_null() {
if let Ok(s) = env.new_string("Composer hook not initialized") {
return s.into_raw();
}
return std::ptr::null_mut();
}
let script_length = script_str.len();
let js_value = {
let js_eval_fn = JS_EVAL_ORIGINAL2.lock().unwrap();
let global_instance = GLOBAL_INSTANCE.load(Ordering::Relaxed);
let global_ctx = GLOBAL_CTX.load(Ordering::Relaxed);
js_eval_fn.unwrap()(
global_instance,
global_ctx,
std::ptr::null_mut(),
(script_str + "\0").as_ptr() as *mut u8,
script_length,
"<eval>\0".as_ptr(),
0
)
};
let result: String = if js_value.tag == JS_TAG_STRING {
let string = js_value.u.ptr as *mut JsString;
match CStr::from_ptr((*string).str8.as_ptr() as *const u8).to_str() {
Ok(s) => s.to_string(),
Err(_) => "[invalid string]".to_string(),
}
} else if js_value.tag == JS_TAG_INT {
js_value.u.int32.to_string()
} else if js_value.tag == JS_TAG_BOOL {
if js_value.u.int32 == 1 { "true" } else { "false" }.to_string()
} else if js_value.tag == JS_TAG_NULL {
"null".to_string()
} else if js_value.tag == JS_TAG_UNDEFINED {
"undefined".to_string()
} else if js_value.tag == JS_TAG_OBJECT {
"[object]".to_string()
} else if js_value.tag == JS_TAG_FLOAT64 {
js_value.u.float64.to_string()
} else if js_value.tag == JS_TAG_EXCEPTION {
"Failed to evaluate script".to_string()
} else {
format!("[unknown tag {}]", js_value.tag)
};
if let Ok(s) = env.new_string(result) {
return s.into_raw();
}
}
std::ptr::null_mut()
}
pub fn init() {
if !config::native_config().composer_hooks {
return
}
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);
#[cfg(target_arch = "aarch64")]
{
let signature = sig::find_signature(
&common::CLIENT_MODULE,
"00 E4 00 6F 29 00 80 52 76 00 04 8B", -0x28,
"A1 B0 07 92 81 46", -0x7
).or_else(|| {
warn!("primary js_eval signature failed, trying fallback");
sig::find_signature(
&common::CLIENT_MODULE,
"00 E4 00 6F ?? ?? ?? ?? ?? ?? ?? ??", -0x28,
"?? ?? ?? ?? ?? ??", -0x7
)
});
if let Some(signature) = signature {
dobby_hook!(signature as *mut c_void, js_eval);
unsafe {
*JS_EVAL_ORIGINAL2.lock().unwrap() = Some(std::mem::transmute(js_eval_original.unwrap()));
}
debug!("js_eval {:#x}", signature);
} else {
warn!("Unable to find js_eval signature");
}
}
}

View File

@@ -1,141 +0,0 @@
use std::{io::Error, string::FromUtf8Error};
#[derive(Debug, Clone)]
pub struct ModuleTag {
tag_type: u8,
buffer: Vec<u8>,
}
impl ModuleTag {
pub fn new(module_type: u8, buffer: Vec<u8>) -> ModuleTag {
ModuleTag {
tag_type: module_type,
buffer,
}
}
pub fn to_string(&self) -> Result<String, FromUtf8Error> {
Ok(String::from_utf8(self.buffer.clone())?)
}
pub fn get_tag_type(&self) -> u8 {
self.tag_type
}
pub fn get_size(&self) -> usize {
self.buffer.len()
}
pub fn get_buffer(&self) -> &Vec<u8> {
&self.buffer
}
pub fn set_buffer(&mut self, buffer: Vec<u8>) {
self.buffer = buffer;
}
}
#[derive(Debug, Clone)]
pub struct ComposerModule {
tags: Vec<(ModuleTag, ModuleTag)>, // file name => file content
}
impl ComposerModule {
pub fn parse(buffer: Vec<u8>) -> Result<ComposerModule, Error> {
let mut offset = 0;
let magic = u32::from_be_bytes([buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]]);
offset += 4;
if magic != 0x33c60001 {
return Err(Error::new(std::io::ErrorKind::InvalidData, "Invalid magic"));
}
// skip content length
offset += 4;
let mut tags = Vec::new();
loop {
if offset >= buffer.len() {
break;
}
fn read_u24(buffer: &Vec<u8>, offset: &mut usize) -> Result<u32, Error> {
let b1 = buffer[*offset] as u32;
let b2 = buffer[*offset + 1] as u32;
let b3 = buffer[*offset + 2] as u32;
*offset += 3;
Ok(b1 | (b2 << 8) | (b3 << 16))
}
let tag_size = read_u24(&buffer, &mut offset)?;
let tag_type = buffer[offset];
offset += 1;
let tag_buffer = buffer[offset..offset + tag_size as usize].to_vec();
offset += tag_size as usize;
let padding = 4 - (tag_size % 4);
if padding != 4 {
offset += padding as usize;
}
tags.push(ModuleTag::new(tag_type, tag_buffer));
}
let tags = tags.chunks(2).map(|chunk| {
(chunk[0].clone(), chunk[1].clone())
}).collect();
Ok(ComposerModule {
tags,
})
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut tag_buffer = Vec::new();
fn write_u24(buffer: &mut Vec<u8>, value: u32) {
buffer.push((value & 0xff) as u8);
buffer.push(((value >> 8) & 0xff) as u8);
buffer.push(((value >> 16) & 0xff) as u8);
}
fn write_tag(buffer: &mut Vec<u8>, tag: ModuleTag) {
write_u24(buffer, tag.get_size() as u32);
buffer.push(tag.get_tag_type());
buffer.extend(tag.get_buffer());
let padding = 4 - (tag.get_size() % 4);
if padding != 4 {
for _ in 0..padding {
buffer.push(0);
}
}
}
for (tag1, tag2) in &self.tags {
write_tag(&mut tag_buffer, tag1.clone());
write_tag(&mut tag_buffer, tag2.clone());
}
let mut buffer = Vec::new();
buffer.extend_from_slice(&[0x33, 0xc6, 0, 1]);
buffer.extend_from_slice(&(tag_buffer.len() as u32).to_le_bytes());
buffer.extend(tag_buffer);
buffer
}
pub fn get_tags(&self) -> Vec<(ModuleTag, ModuleTag)> {
self.tags.clone()
}
pub fn set_tags(&mut self, tags: Vec<(ModuleTag, ModuleTag)>) {
self.tags = tags;
}
}