#exe #file-format #dos #executable #nightly #manipulating #extender

nightly pmw1

这是一个用于操作PMW1格式的可执行文件的库,它提供了EXE压缩功能,并由PMODE/W DOS扩展器使用。目前由于使用了内联汇编,需要使用nightly Rust。

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解析器实现 中排名

Download history 19/week @ 2024-04-01

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(())
}

无运行时依赖