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,8 +823,16 @@ impl<'a> Unpacker<'a> {
|
||||
let d = export_va as usize;
|
||||
let s = export_file_off as usize;
|
||||
let n = export_size as usize;
|
||||
// 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) ----
|
||||
// `select_dd8_formula_pe32` returns None when `.text` was not packer-dd8-
|
||||
|
||||
@@ -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 sec_table = opt_hdr.wrapping_add(opt_hdr_size);
|
||||
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 {
|
||||
sec_off: u32,
|
||||
@@ -365,11 +372,21 @@ pub fn compact_memory_image_to_pe(data: &[u8], pe_header: u32) -> Option<Vec<u8>
|
||||
break;
|
||||
}
|
||||
}
|
||||
let meaningful = if last_nonzero >= 0 {
|
||||
let mut meaningful = if last_nonzero >= 0 {
|
||||
(last_nonzero + 1) as u32
|
||||
} else {
|
||||
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 {
|
||||
align_up_u32(meaningful, FILE_ALIGNMENT)
|
||||
} else {
|
||||
@@ -433,6 +450,45 @@ pub fn compact_memory_image_to_pe(data: &[u8], pe_header: u32) -> Option<Vec<u8>
|
||||
mod tests {
|
||||
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
|
||||
/// bail instead of building .kmiat at RVA 0 — the old code zeroed
|
||||
/// `[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,
|
||||
_ => return,
|
||||
};
|
||||
let dst = match rva_to_file_off(out, export_rva) {
|
||||
Some(o) => o,
|
||||
None => return,
|
||||
let dst = match senbei_pe::parse(out)
|
||||
.and_then(|headers| senbei_pe::rva_range(out, headers, export_rva, export_size))
|
||||
{
|
||||
Ok(range) => range,
|
||||
Err(_) => return,
|
||||
};
|
||||
let src = match rva_to_file_off(stub, export_rva) {
|
||||
Some(o) => o,
|
||||
None => return,
|
||||
let src = match senbei_pe::parse(stub)
|
||||
.and_then(|headers| senbei_pe::rva_range(stub, headers, export_rva, export_size))
|
||||
{
|
||||
Ok(range) => range,
|
||||
Err(_) => return,
|
||||
};
|
||||
let n = export_size as usize;
|
||||
if dst + n <= out.len() && src + n <= stub.len() {
|
||||
out[dst..dst + n].copy_from_slice(&stub[src..src + n]);
|
||||
}
|
||||
out[dst].copy_from_slice(&stub[src]);
|
||||
}
|
||||
|
||||
/// Restore the CLR regions retained by an external-companion loader stub.
|
||||
@@ -633,6 +634,34 @@ mod tests {
|
||||
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]
|
||||
fn managed_companion_restores_rva_mapped_regions_without_overwriting_il() {
|
||||
for is_pe32_plus in [false, true] {
|
||||
|
||||
Reference in new issue
Block a user