Added TLZMA support
This commit is contained in:
parent
8565eba0f3
commit
187c271657
4 changed files with 147 additions and 1 deletions
39
Cargo.lock
generated
39
Cargo.lock
generated
|
@ -10,6 +10,27 @@ dependencies = [
|
|||
"offset-finder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
|
@ -66,6 +87,16 @@ version = "0.4.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lzma-rs"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "offset-finder"
|
||||
version = "0.1.0"
|
||||
|
@ -241,6 +272,14 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tlzma"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lzma-rs",
|
||||
"thiserror 2.0.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
|
|
|
@ -5,7 +5,8 @@ members = [
|
|||
"cursor",
|
||||
"offset-finder",
|
||||
"pe-utils",
|
||||
"restorer"
|
||||
"restorer",
|
||||
"tlzma"
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
|
@ -15,6 +16,7 @@ edition = "2021"
|
|||
[workspace.dependencies]
|
||||
goblin = "0.9.2"
|
||||
log = "0.4.22"
|
||||
lzma-rs = { version = "0.3.0", features = ["raw_decoder"] }
|
||||
patternscanner = "0.5.0"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
thiserror = "2.0.9"
|
||||
|
|
8
tlzma/Cargo.toml
Normal file
8
tlzma/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "tlzma"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
lzma-rs.workspace = true
|
||||
thiserror.workspace = true
|
97
tlzma/src/lib.rs
Normal file
97
tlzma/src/lib.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use std::io::Cursor;
|
||||
use lzma_rs::decompress::raw::{LzmaDecoder, LzmaParams, LzmaProperties};
|
||||
|
||||
const LZMA_PROP_MAX: u32 = 9 * 5 * 5;
|
||||
const LZMA_DIC_MIN: u32 = 1 << 12;
|
||||
|
||||
const PROPS_XK: u8 = 0x9d ^ 0xf3;
|
||||
const PROPS_AK: u8 = 0x65 ^ 0xa2;
|
||||
const USIZE_XK: u32 = 0x218d5a0a ^ 0xab8832cb;
|
||||
const USIZE_AK: u32 = 0x5e98c630 ^ 0x66e44294;
|
||||
const CSIZE_XK: u32 = 0x6dfc36ff ^ 0xfc4c53bf;
|
||||
const CSIZE_AK: u32 = 0xc68dd929 ^ 0x78bdb6e9;
|
||||
|
||||
const GOOD_PROPS: u32 = 0xcd386d0f ^ 0x996f3a58;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Lzma Error: {0}")]
|
||||
Lzma(#[from] lzma_rs::error::Error),
|
||||
#[error("TryFromSlice Error: {0}")]
|
||||
TryFromSlice(#[from] std::array::TryFromSliceError),
|
||||
#[error("LZMA header invalid properties: {0} must be < 225")]
|
||||
PropsTooBig(u32),
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Debug)]
|
||||
pub struct TlzmaHeader {
|
||||
pub props: [u8; 5],
|
||||
pub _1: [u8; 3],
|
||||
pub uncompressed_size: u32,
|
||||
pub compressed_size: u32,
|
||||
}
|
||||
|
||||
impl TlzmaHeader {
|
||||
pub fn tlzma_test_header(data: &[u8]) -> Result<bool, Error> {
|
||||
let tlzma: TlzmaHeader = unsafe { std::ptr::read(data.as_ptr() as *const _) };
|
||||
let good_props = u32::from_le_bytes(tlzma.props[1..].try_into()?);
|
||||
Ok(GOOD_PROPS == good_props)
|
||||
}
|
||||
|
||||
pub fn parse_header(data: &[u8]) -> Self {
|
||||
let mut tlzma: TlzmaHeader = unsafe { std::ptr::read(data.as_ptr() as *const _) };
|
||||
for i in 0..tlzma.props.len() {
|
||||
tlzma.props[i] = (tlzma.props[i] ^ PROPS_XK).wrapping_add(PROPS_AK);
|
||||
}
|
||||
tlzma.uncompressed_size = (tlzma.uncompressed_size ^ USIZE_XK).wrapping_add(USIZE_AK);
|
||||
tlzma.compressed_size = (tlzma.compressed_size ^ CSIZE_XK).wrapping_add(CSIZE_AK);
|
||||
tlzma
|
||||
}
|
||||
|
||||
pub fn get_next_chunk_offset(&self, offset: usize, data: &[u8]) -> Result<usize, Error> {
|
||||
let tmp = offset + size_of::<Self>() + self.compressed_size as usize;
|
||||
let input = &data[tmp..tmp + 16];
|
||||
match Self::tlzma_test_header(input)? {
|
||||
true => Ok(tmp),
|
||||
false => Ok(offset + self.uncompressed_size as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lzma_decode(&self, input: &[u8], offset: usize) -> Result<(Vec<u8>, u32), Error> {
|
||||
let params = self.get_params_from_props()?;
|
||||
let mut decoder = LzmaDecoder::new(params, None)?;
|
||||
let start = offset + size_of::<Self>();
|
||||
let end = start + self.compressed_size as usize;
|
||||
let mut data = Cursor::new(&input[start..end]);
|
||||
let mut output = Vec::with_capacity(self.uncompressed_size as usize);
|
||||
decoder.decompress(&mut data, &mut output)?;
|
||||
|
||||
Ok((output, self.uncompressed_size))
|
||||
}
|
||||
|
||||
fn get_params_from_props(&self) -> Result<LzmaParams, Error> {
|
||||
let mut pb = self.props[0] as u32;
|
||||
if pb >= LZMA_PROP_MAX {
|
||||
return Err(Error::PropsTooBig(pb));
|
||||
}
|
||||
|
||||
let mut dic = u32::from_le_bytes(self.props[1..].try_into()?);
|
||||
if dic < LZMA_DIC_MIN {
|
||||
dic = LZMA_DIC_MIN;
|
||||
}
|
||||
|
||||
let lc: u32 = pb % 9;
|
||||
pb /= 9;
|
||||
let lp: u32 = pb % 5;
|
||||
pb /= 5;
|
||||
|
||||
Ok(
|
||||
LzmaParams::new(
|
||||
LzmaProperties { lc, lp, pb },
|
||||
dic,
|
||||
Some(self.uncompressed_size as u64),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue