4个版本
0.2.2 | 2023年5月2日 |
---|---|
0.2.1 | 2022年1月1日 |
0.2.0 | 2020年11月15日 |
0.1.0 | 2020年9月6日 |
999 在 解析器实现 中排名
115 每月下载量
78KB
1.5K SLoC
pmw1-rs
这是一个用于操作PMW1可执行文件的Rust库。PMW1是PMODE/W DOS扩展器使用的可压缩EXE格式。
此库允许分析和解压PMW1 EXE的各个组件,主要是对象和重定位块。
示例程序
下面的程序接受一个完整的PMW1 EXE文件名(包括DOS stub),对其进行解压缩和重新压缩。在这个过程中,它将解压缩版本输出到文件,将有关EXE结构的各种数据输出到stdout,还将重新压缩版本输出到文件。
请注意,这两个文件转储都包括与原始EXE相同的DOS stub,这意味着其中只有一个可以真正运行。这是因为PMODE/W本身的压缩支持是编译时开关,因此为压缩EXE编译的stub无法运行未压缩的EXE,反之亦然。
extern crate pmw1;
use std::env::args;
use std::io::prelude::*;
use std::fs::File;
use pmw1::exe::Pmw1Exe;
fn main() -> std::io::Result<()> {
// Assume the filename of interest is the LAST argument on the command line.
let exe_name: String = args().next_back().unwrap();
// Load the whole EXE into memory...
let binary = {
println!("Opening {}...", exe_name);
let mut file = File::open(&exe_name)?;
let mut buffer: Vec<u8> = Vec::with_capacity(0x100000);
file.read_to_end(&mut buffer)?;
buffer.shrink_to_fit();
buffer
};
println!("{} is {} bytes.", exe_name, binary.len());
assert_eq!(binary[0..2],b"MZ"[..],
"{} is not an MZ executable!", exe_name);
assert!(binary.len() >= 0x1c,
"{} doesn't appear to contain a complete MZ header!",exe_name);
let mz_header = &binary[0x2..0x1c];
let mz_header: Vec<u16> = (0..mz_header.len())
.step_by(2)
.map(|i| u16::from_le_bytes([mz_header[i], mz_header[i+1]]))
.collect();
// Print out some relevant info.
println!("It begins with an MZ executable, of {} half-KiB blocks.",
mz_header[1]);
let total_block_size = mz_header[1] << 9; // Shift left to multiply by 512
let actual_mz_size =
if mz_header[0] == 0 {
println!("Last block is fully used.");
total_block_size
} else {
println!("{} bytes used in last block.", mz_header[0]);
total_block_size - 512 + mz_header[0]
} as usize;
println!("Total MZ executable size is {} bytes.", actual_mz_size);
assert!(binary.len() > actual_mz_size, "This appears to be a pure MZ executable!");
// A slice containing just the PMW1 part.
let pmw1_exe = Pmw1Exe::from_bytes(&binary[actual_mz_size..])?;
// Is it all working??
let pmw1_exe = pmw1_exe.decompress()?;
{
let mut outfile = File::create(&format!("{}.DECOMP",exe_name))?;
// Write the DOS stub back out
outfile.write_all(&binary[..actual_mz_size])?;
// And the actual PMW1 exe!
outfile.write_all(&pmw1_exe.as_bytes())?;
}
println!("{:#?}", pmw1_exe);
// Try going back the other way...
let pmw1_exe = pmw1_exe.compress()?;
{
let mut outfile = File::create(&format!("{}.RECOMP",exe_name))?;
// Write the DOS stub back out
outfile.write_all(&binary[..actual_mz_size])?;
// And the actual PMW1 exe!
outfile.write_all(&pmw1_exe.as_bytes())?;
}
Ok(())
}