#parser

ovba

An Office VBA project parser written in 100% safe Rust

5 releases (3 breaking)

0.4.1 Jan 4, 2024
0.4.0 Dec 7, 2020
0.3.0 Dec 3, 2020
0.2.0 Nov 30, 2020
0.1.0 Nov 29, 2020

#950 in Parser implementations

Custom license

46KB
723 lines

crates.io docs.rs tests

An Office VBA project parser written in 100% safe Rust. This is an implementation of the [MS-OVBA]: Office VBA File Format Structure protocol (Revision 9.1, published 2020-02-19).

Motivation

Binary file format parsers have historically been an attractive target for attackers. A combination of complex code logic with frequently unchecked memory accesses have had them fall victim to remote code execution exploits many times over.

Rust is a reliable ally in addressing many of these security concerns, empowering this crate to deliver a safe parser implementation.

Features

This library provides read-only access to VBA projects' metadata and source code. Notable features include:

  • Extract source code.
  • Inspect metadata, like contained modules, references, etc.

This library does not provide a way to extract the raw binary VBA project data from an Office document. This is the responsibility of client code. The companion ovba-cli tool illustrates how this can be done.

Usage

Write out all modules' source code:

use ovba::{open_project, Result};
use std::fs::{read, write};

fn main() -> Result<()> {
    let data = read("vbaProject.bin")?;
    let project = open_project(data)?;

    for module in &project.modules {
        let src_code = project.module_source_raw(&module.name)?;
        write("./out/".to_string() + &module.name, src_code)?;
    }

    Ok(())
}

List all CFB entries contained in a VBA project:

use ovba::{open_project, Result};
use std::fs::read;

fn main() -> Result<()> {
    // Read raw project container
    let data = read("vbaProject.bin")?;
    let project = open_project(data)?;
    // Iterate over CFB entries
    for (name, path) in project.list()? {
        println!(r#"Name: "{}"; Path: "{}""#, name, path);
    }

    Ok(())
}

Backwards compatibility

At this time, both API and implementation are under development. It is expected to see breaking changes before reaching a 1.0 release. With 0.X.Y releases, breaking changes are signified by a bump in the 0.X version number, leaving non-breaking changes to a bump in the Y version number.

This is a preview release. It has been published to allow others to use it, and solicit feedback to help drive future decision.

Future work

All future work is tracked here. Notable issues include:

If you are missing a feature, found a bug, have a question, or want to provide feedback, make sure to file an issue.

Dependencies

~4.5MB
~147K SLoC