From 64d78c31bca5468096744b7ad76cfd212a3ed9b9 Mon Sep 17 00:00:00 2001 From: weishu Date: Wed, 25 Jan 2023 17:55:08 +0800 Subject: [PATCH] ksud: support set-manager (#114) * ksud: support set-manager * ksud: rework apk sign Co-authored-by: Ylarod --- userspace/ksud/src/apk_sign.rs | 103 +++++++++++++++++++++++++++++++++ userspace/ksud/src/cli.rs | 37 +++++++++++- userspace/ksud/src/debug.rs | 61 +++++++++++++++++++ userspace/ksud/src/main.rs | 2 + 4 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 userspace/ksud/src/apk_sign.rs create mode 100644 userspace/ksud/src/debug.rs diff --git a/userspace/ksud/src/apk_sign.rs b/userspace/ksud/src/apk_sign.rs new file mode 100644 index 00000000..9c5af0f3 --- /dev/null +++ b/userspace/ksud/src/apk_sign.rs @@ -0,0 +1,103 @@ +use std::io::{Read, Seek, SeekFrom}; + +use anyhow::{bail, ensure, Result}; + +pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> { + let mut buffer = [0u8; 0x10]; + let mut size4 = [0u8; 4]; + let mut size8 = [0u8; 8]; + let mut size_of_block = [0u8; 8]; + + let mut f = std::fs::File::open(apk)?; + + let mut i = 0; + loop { + let mut n = [0u8; 2]; + f.seek(SeekFrom::End(-i - 2))?; + f.read_exact(&mut n)?; + + let n = u16::from_le_bytes(n); + if n as i64 == i { + f.seek(SeekFrom::Current(-22))?; + f.read_exact(&mut size4)?; + + if u32::from_le_bytes(size4) ^ 0xcafebabeu32 == 0xccfbf1eeu32 { + if i > 0 { + println!("warning: comment length is {}", i); + } + break; + } + } + + ensure!(n != 0xffff, "not a zip file"); + + i += 1; + } + + f.seek(SeekFrom::Current(12))?; + // offset + f.read_exact(&mut size4)?; + f.seek(SeekFrom::Start(u32::from_le_bytes(size4) as u64 - 0x18))?; + + f.read_exact(&mut size8)?; + f.read_exact(&mut buffer)?; + + if &buffer != b"APK Sig Block 42" { + bail!("Can not found sig block"); + } + + let pos = u32::from_le_bytes(size4) as u64 - (u64::from_le_bytes(size8) + 0x8); + f.seek(SeekFrom::Start(pos))?; + f.read_exact(&mut size_of_block)?; + + ensure!(size_of_block == size8, "not a signed apk"); + + loop { + let mut id = [0u8; 4]; + let offset = 4u32; + + f.read_exact(&mut size8)?; // sequence length + if size8 == size_of_block { + break; + } + + f.read_exact(&mut id)?; // id + + let id = u32::from_le_bytes(id); + if (id ^ 0xdeadbeefu32) == 0xafa439f5u32 || (id ^ 0xdeadbeefu32) == 0x2efed62fu32 { + f.read_exact(&mut size4)?; // signer-sequence length + f.read_exact(&mut size4)?; // signer length + f.read_exact(&mut size4)?; // signed data length + // offset += 0x4 * 3; + + f.read_exact(&mut size4)?; // digests-sequcence length + let pos = u32::from_le_bytes(size4); + f.seek(SeekFrom::Current(pos as i64))?; + // offset += 0x4 + pos; + + f.read_exact(&mut size4)?; // certificates length + f.read_exact(&mut size4)?; // certificate length + // offset += 0x4 * 2; + + let mut hash = 1i32; + let mut c = [0u8; 1]; + + let j = u32::from_le_bytes(size4); + for _ in 0..j { + f.read_exact(&mut c)?; + hash = hash.wrapping_mul(31).wrapping_add(c[0] as i8 as i32); + } + + // offset += j; + + let out_size = j; + let out_hash = (hash as u32) ^ 0x14131211u32; + + return Ok((out_size, out_hash)); + } + + f.seek(SeekFrom::Current(i64::from_le_bytes(size8) - offset as i64))?; + } + + Err(anyhow::anyhow!("Unknown error")) +} diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index 008aeea6..637e4894 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -1,7 +1,7 @@ use anyhow::Result; use clap::Parser; -use crate::{event, module}; +use crate::{event, module, debug, apk_sign}; /// KernelSU userspace cli #[derive(Parser, Debug)] @@ -37,7 +37,27 @@ enum Commands { /// SELinux policy Patch tool Sepolicy, - /// For test + /// For developers + Debug { + #[command(subcommand)] + command: Debug, + }, +} +#[derive(clap::Subcommand, Debug)] +enum Debug { + /// Set the manager app, kernel CONFIG_KSU_DEBUG should be enabled. + SetManager { + /// manager apk path or package name + apk: String, + }, + + /// Get apk size and hash + GetSign { + /// apk path + apk: String, + }, + + /// For testing Test, } @@ -93,7 +113,18 @@ pub fn run() -> Result<()> { Commands::Install => event::install(), Commands::Sepolicy => todo!(), Commands::Services => event::on_services(), - Commands::Test => event::do_systemless_mount("/data/adb/ksu/modules"), + + Commands::Debug { command } => { + match command { + Debug::SetManager { apk } => debug::set_manager(&apk), + Debug::GetSign { apk } => { + let sign = apk_sign::get_apk_signature(&apk)?; + println!("size: {:#x}, hash: {:#x}", sign.0, sign.1); + Ok(()) + }, + Debug::Test => todo!(), + } + } }; if let Err(e) = &result { diff --git a/userspace/ksud/src/debug.rs b/userspace/ksud/src/debug.rs new file mode 100644 index 00000000..b786cb43 --- /dev/null +++ b/userspace/ksud/src/debug.rs @@ -0,0 +1,61 @@ +use anyhow::{ensure, Context, Ok, Result}; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; + +use crate::apk_sign::get_apk_signature; + +const KERNEL_PARAM_PATH: &str = "/sys/module/kernelsu"; + +fn read_u32(path: &PathBuf) -> Result { + let content = std::fs::read_to_string(path)?; + let content = content.trim(); + let content = content.parse::()?; + Ok(content) +} + +fn set_kernel_param(size: u32, hash: u32) -> Result<()> { + let kernel_param_path = Path::new(KERNEL_PARAM_PATH).join("parameters"); + let expeced_size_path = kernel_param_path.join("ksu_expected_size"); + let expeced_hash_path = kernel_param_path.join("ksu_expected_hash"); + + println!( + "before size: {:#x} hash: {:#x}", + read_u32(&expeced_size_path)?, + read_u32(&expeced_hash_path)? + ); + + std::fs::write(&expeced_size_path, size.to_string())?; + std::fs::write(&expeced_hash_path, hash.to_string())?; + + println!( + "after size: {:#x} hash: {:#x}", + read_u32(&expeced_size_path)?, + read_u32(&expeced_hash_path)? + ); + + Ok(()) +} + +fn get_apk_path(package_name: &str) -> Result { + let cmd = format!("pm path {}", package_name); + let output = Command::new("sh").arg("-c").arg(cmd).output()?; + + // package:/data/app//base.apk + let output = String::from_utf8_lossy(&output.stdout); + let path = output.trim().replace("package:", ""); + Ok(path) +} + +pub fn set_manager(pkg: &str) -> Result<()> { + ensure!( + Path::new(KERNEL_PARAM_PATH).exists(), + "CONFIG_KSU_DEBUG is not enabled" + ); + + let path = get_apk_path(pkg).with_context(|| format!("{} not exist!", pkg))?; + let sign = get_apk_signature(path.as_str())?; + set_kernel_param(sign.0, sign.1)?; + Ok(()) +} diff --git a/userspace/ksud/src/main.rs b/userspace/ksud/src/main.rs index 8e2519b5..df3cd039 100644 --- a/userspace/ksud/src/main.rs +++ b/userspace/ksud/src/main.rs @@ -4,6 +4,8 @@ mod module; mod defs; mod utils; mod restorecon; +mod debug; +mod apk_sign; fn main() -> anyhow::Result<()> { cli::run()