kernel: harden the signature check (#1027)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use anyhow::{ensure, Result};
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
||||
pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
|
||||
pub fn get_apk_signature(apk: &str) -> Result<(u32, String)> {
|
||||
let mut buffer = [0u8; 0x10];
|
||||
let mut size4 = [0u8; 4];
|
||||
let mut size8 = [0u8; 8];
|
||||
@@ -49,9 +49,11 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
|
||||
|
||||
ensure!(size_of_block == size8, "not a signed apk");
|
||||
|
||||
let mut v2_signing: Option<(u32, String)> = None;
|
||||
let mut v3_signing: Option<(u32, String)> = None;
|
||||
loop {
|
||||
let mut id = [0u8; 4];
|
||||
let offset = 4u32;
|
||||
let mut offset = 4u32;
|
||||
|
||||
f.read_exact(&mut size8)?; // sequence length
|
||||
if size8 == size_of_block {
|
||||
@@ -61,36 +63,10 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
|
||||
f.read_exact(&mut id)?; // id
|
||||
|
||||
let id = u32::from_le_bytes(id);
|
||||
if (id ^ 0xdead_beef_u32) == 0xafa4_39f5_u32 || (id ^ 0xdead_beef_u32) == 0x2efe_d62f_u32 {
|
||||
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(i64::from(pos)))?;
|
||||
// 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(i32::from(c[0] as i8));
|
||||
}
|
||||
|
||||
// offset += j;
|
||||
|
||||
let out_size = j;
|
||||
let out_hash = (hash as u32) ^ 0x1413_1211_u32;
|
||||
|
||||
return Ok((out_size, out_hash));
|
||||
if id == 0x7109_871a_u32 {
|
||||
v2_signing = Some(calc_cert_sha256(&mut f, &mut size4, &mut offset)?);
|
||||
} else if id == 0xf053_68c0_u32 {
|
||||
v3_signing = Some(calc_cert_sha256(&mut f, &mut size4, &mut offset)?);
|
||||
}
|
||||
|
||||
f.seek(SeekFrom::Current(
|
||||
@@ -98,5 +74,47 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
|
||||
))?;
|
||||
}
|
||||
|
||||
Err(anyhow::anyhow!("Unknown error"))
|
||||
match (v2_signing, v3_signing) {
|
||||
(None, Some(s)) => Ok(s),
|
||||
(Some(s), None) => Ok(s),
|
||||
(Some(s1), Some(s2)) => {
|
||||
if s1 == s2 {
|
||||
Ok(s1)
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
"Inconsisent signature, v2: {}, v3: {}!",
|
||||
s1.1,
|
||||
s2.1
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Err(anyhow::anyhow!("Unknown signature!")),
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_cert_sha256(
|
||||
f: &mut std::fs::File,
|
||||
size4: &mut [u8; 4],
|
||||
offset: &mut u32,
|
||||
) -> Result<(u32, String)> {
|
||||
f.read_exact(size4)?; // signer-sequence length
|
||||
f.read_exact(size4)?; // signer length
|
||||
f.read_exact(size4)?; // signed data length
|
||||
*offset += 0x4 * 3;
|
||||
|
||||
f.read_exact(size4)?; // digests-sequence length
|
||||
let pos = u32::from_le_bytes(*size4); // skip digests
|
||||
f.seek(SeekFrom::Current(i64::from(pos)))?;
|
||||
*offset += 0x4 + pos;
|
||||
|
||||
f.read_exact(size4)?; // certificates length
|
||||
f.read_exact(size4)?; // certificate length
|
||||
*offset += 0x4 * 2;
|
||||
|
||||
let cert_len = u32::from_le_bytes(*size4);
|
||||
let mut cert: Vec<u8> = vec![0; cert_len as usize];
|
||||
f.read_exact(&mut cert)?;
|
||||
*offset += cert_len;
|
||||
|
||||
Ok((cert_len, sha256::digest(&cert)))
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ pub fn run() -> Result<()> {
|
||||
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);
|
||||
println!("size: {:#x}, hash: {}", sign.0, sign.1);
|
||||
Ok(())
|
||||
}
|
||||
Debug::Version => {
|
||||
|
||||
@@ -15,24 +15,25 @@ fn read_u32(path: &PathBuf) -> Result<u32> {
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
fn set_kernel_param(size: u32, hash: u32) -> Result<()> {
|
||||
fn set_kernel_param(size: u32, hash: String) -> 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}",
|
||||
"before size: {:#x} hash: {}",
|
||||
read_u32(&expeced_size_path)?,
|
||||
read_u32(&expeced_hash_path)?
|
||||
std::fs::read_to_string(&expeced_hash_path)?
|
||||
);
|
||||
|
||||
std::fs::write(&expeced_size_path, size.to_string())?;
|
||||
std::fs::write(&expeced_hash_path, hash.to_string())?;
|
||||
std::fs::write(&expeced_hash_path, hash)?;
|
||||
|
||||
println!(
|
||||
"after size: {:#x} hash: {:#x}",
|
||||
"after size: {:#x} hash: {}",
|
||||
read_u32(&expeced_size_path)?,
|
||||
read_u32(&expeced_hash_path)?
|
||||
std::fs::read_to_string(&expeced_hash_path)?
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user