mirror of
https://github.com/Momoko-Ayase/Senbei.git
synced 2026-11-03 10:31:28 -05:00
Compare commits
1
Commits
v1.3.2
..
6e233bbf18
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e233bbf18 |
No files matched your search
@@ -823,7 +823,15 @@ impl<'a> Unpacker<'a> {
|
|||||||
let d = export_va as usize;
|
let d = export_va as usize;
|
||||||
let s = export_file_off as usize;
|
let s = export_file_off as usize;
|
||||||
let n = export_size as usize;
|
let n = export_size as usize;
|
||||||
self.decompressed[d..d + n].copy_from_slice(&self.file_data[s..s + n]);
|
// Spliced companions may omit the stub's plaintext exports;
|
||||||
|
// the I/O adapter overlays those from the original stub later.
|
||||||
|
if s.checked_add(n)
|
||||||
|
.is_some_and(|end| end <= self.file_data.len())
|
||||||
|
&& d.checked_add(n)
|
||||||
|
.is_some_and(|end| end <= self.decompressed.len())
|
||||||
|
{
|
||||||
|
self.decompressed[d..d + n].copy_from_slice(&self.file_data[s..s + n]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- .text decrypt with decrypt_data8 (PE32 auto-detected formula) ----
|
// ---- .text decrypt with decrypt_data8 (PE32 auto-detected formula) ----
|
||||||
|
|||||||
@@ -331,6 +331,13 @@ pub fn compact_memory_image_to_pe(data: &[u8], pe_header: u32) -> Option<Vec<u8>
|
|||||||
let opt_hdr = pe_header.wrapping_add(24);
|
let opt_hdr = pe_header.wrapping_add(24);
|
||||||
let sec_table = opt_hdr.wrapping_add(opt_hdr_size);
|
let sec_table = opt_hdr.wrapping_add(opt_hdr_size);
|
||||||
let num_sections = get_u16(data, pe_header.wrapping_add(6)) as u32;
|
let num_sections = get_u16(data, pe_header.wrapping_add(6)) as u32;
|
||||||
|
let export_dir = opt_hdr.wrapping_add(if get_u16(data, opt_hdr) == 0x20B {
|
||||||
|
112
|
||||||
|
} else {
|
||||||
|
96
|
||||||
|
});
|
||||||
|
let export_rva = get_u32(data, export_dir);
|
||||||
|
let export_size = get_u32(data, export_dir.wrapping_add(4));
|
||||||
|
|
||||||
struct SecLayout {
|
struct SecLayout {
|
||||||
sec_off: u32,
|
sec_off: u32,
|
||||||
@@ -365,11 +372,21 @@ pub fn compact_memory_image_to_pe(data: &[u8], pe_header: u32) -> Option<Vec<u8>
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let meaningful = if last_nonzero >= 0 {
|
let mut meaningful = if last_nonzero >= 0 {
|
||||||
(last_nonzero + 1) as u32
|
(last_nonzero + 1) as u32
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
// Companion exports are overlaid after compaction. Keep their whole
|
||||||
|
// range file-backed even when the payload leaves it zero-filled.
|
||||||
|
if export_size != 0
|
||||||
|
&& let Some(end) = export_rva
|
||||||
|
.checked_sub(va)
|
||||||
|
.and_then(|delta| delta.checked_add(export_size))
|
||||||
|
&& end as usize <= section_data.len()
|
||||||
|
{
|
||||||
|
meaningful = meaningful.max(end);
|
||||||
|
}
|
||||||
let mut raw_size = if meaningful != 0 {
|
let mut raw_size = if meaningful != 0 {
|
||||||
align_up_u32(meaningful, FILE_ALIGNMENT)
|
align_up_u32(meaningful, FILE_ALIGNMENT)
|
||||||
} else {
|
} else {
|
||||||
@@ -433,6 +450,45 @@ pub fn compact_memory_image_to_pe(data: &[u8], pe_header: u32) -> Option<Vec<u8>
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compaction_keeps_export_space_without_changing_the_next_section() {
|
||||||
|
for (rva, size, expected_raw_size) in [
|
||||||
|
(0, 0, 0x200),
|
||||||
|
(0x1280, 0x181, 0x600),
|
||||||
|
(0x1f00, 0x200, 0x200),
|
||||||
|
(0xffff_fff0, 0x40, 0x200),
|
||||||
|
] {
|
||||||
|
let mut data = vec![0; 0x3000];
|
||||||
|
data[..2].copy_from_slice(b"MZ");
|
||||||
|
data[0x80..0x84].copy_from_slice(b"PE\0\0");
|
||||||
|
write_u16(&mut data, 0x86, 2);
|
||||||
|
write_u16(&mut data, 0x94, 0xe0);
|
||||||
|
write_u16(&mut data, 0x98, 0x10b);
|
||||||
|
for (offset, value) in [
|
||||||
|
(0x3c, 0x80),
|
||||||
|
(0xf8, rva),
|
||||||
|
(0xfc, size),
|
||||||
|
(0x180, 0x1000),
|
||||||
|
(0x184, 0x1000),
|
||||||
|
(0x1a8, 0x1000),
|
||||||
|
(0x1ac, 0x2000),
|
||||||
|
] {
|
||||||
|
write_u32(&mut data, offset, value);
|
||||||
|
}
|
||||||
|
data[0x1000] = 0xaa;
|
||||||
|
data[0x2000..0x200c].copy_from_slice(b"next section");
|
||||||
|
let out = compact_memory_image_to_pe(&data, 0x80).unwrap();
|
||||||
|
assert_eq!(get_u32(&out, 0x188), expected_raw_size);
|
||||||
|
let headers = senbei_pe::parse(&out).unwrap();
|
||||||
|
let next = senbei_pe::rva_range(&out, headers, 0x2000, 12).unwrap();
|
||||||
|
assert_eq!(&out[next], b"next section");
|
||||||
|
if rva == 0x1280 {
|
||||||
|
let exports = senbei_pe::rva_range(&out, headers, rva, size).unwrap();
|
||||||
|
assert!(out[exports].iter().all(|&byte| byte == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Review regression: a zero last-section VA (corrupt section table) must
|
/// Review regression: a zero last-section VA (corrupt section table) must
|
||||||
/// bail instead of building .kmiat at RVA 0 — the old code zeroed
|
/// bail instead of building .kmiat at RVA 0 — the old code zeroed
|
||||||
/// `[0, 0x7000)`, wiping the DOS/PE headers, and returned the broken image
|
/// `[0, 0x7000)`, wiping the DOS/PE headers, and returned the broken image
|
||||||
|
|||||||
@@ -128,18 +128,19 @@ pub(crate) fn overlay_exports_from_stub(out: &mut [u8], stub: &[u8]) {
|
|||||||
Some(v) if v.1 != 0 => v,
|
Some(v) if v.1 != 0 => v,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let dst = match rva_to_file_off(out, export_rva) {
|
let dst = match senbei_pe::parse(out)
|
||||||
Some(o) => o,
|
.and_then(|headers| senbei_pe::rva_range(out, headers, export_rva, export_size))
|
||||||
None => return,
|
{
|
||||||
|
Ok(range) => range,
|
||||||
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
let src = match rva_to_file_off(stub, export_rva) {
|
let src = match senbei_pe::parse(stub)
|
||||||
Some(o) => o,
|
.and_then(|headers| senbei_pe::rva_range(stub, headers, export_rva, export_size))
|
||||||
None => return,
|
{
|
||||||
|
Ok(range) => range,
|
||||||
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
let n = export_size as usize;
|
out[dst].copy_from_slice(&stub[src]);
|
||||||
if dst + n <= out.len() && src + n <= stub.len() {
|
|
||||||
out[dst..dst + n].copy_from_slice(&stub[src..src + n]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the CLR regions retained by an external-companion loader stub.
|
/// Restore the CLR regions retained by an external-companion loader stub.
|
||||||
@@ -633,6 +634,34 @@ mod tests {
|
|||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn export_overlay_requires_the_entire_range_to_be_file_backed() {
|
||||||
|
for is_pe32_plus in [false, true] {
|
||||||
|
let dirs = 0x98 + if is_pe32_plus { 112 } else { 96 };
|
||||||
|
let section = 0x98 + if is_pe32_plus { 0xf0 } else { 0xe0 };
|
||||||
|
let mut stub = managed_fixture(is_pe32_plus, 0x600);
|
||||||
|
stub[0x780..0x880].fill(0x5a);
|
||||||
|
for (stub_raw_size, out_raw_size) in
|
||||||
|
[(0x600u32, 0x600u32), (0x200, 0x600), (0x600, 0x200)]
|
||||||
|
{
|
||||||
|
let mut out = managed_fixture(is_pe32_plus, 0x400);
|
||||||
|
out[dirs..dirs + 4].copy_from_slice(&0x2180u32.to_le_bytes());
|
||||||
|
out[dirs + 4..dirs + 8].copy_from_slice(&0x100u32.to_le_bytes());
|
||||||
|
out[section + 16..section + 20].copy_from_slice(&out_raw_size.to_le_bytes());
|
||||||
|
stub[section + 16..section + 20].copy_from_slice(&stub_raw_size.to_le_bytes());
|
||||||
|
let before = out.clone();
|
||||||
|
overlay_exports_from_stub(&mut out, &stub);
|
||||||
|
if stub_raw_size == 0x600 && out_raw_size == 0x600 {
|
||||||
|
assert_eq!(&out[0x580..0x680], &[0x5a; 0x100]);
|
||||||
|
assert_eq!(&out[..0x580], &before[..0x580]);
|
||||||
|
assert_eq!(&out[0x680..], &before[0x680..]);
|
||||||
|
} else {
|
||||||
|
assert_eq!(out, before);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn managed_companion_restores_rva_mapped_regions_without_overwriting_il() {
|
fn managed_companion_restores_rva_mapped_regions_without_overwriting_il() {
|
||||||
for is_pe32_plus in [false, true] {
|
for is_pe32_plus in [false, true] {
|
||||||
|
|||||||
Reference in new issue
Block a user