vtil_parser/lib.rs
1// BSD 3-Clause License
2//
3// Copyright © 2020-2021 Keegan Saunders
4// Copyright © 2020-2021 VTIL Project
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are met:
9//
10// 1. Redistributions of source code must retain the above copyright notice, this
11// list of conditions and the following disclaimer.
12//
13// 2. Redistributions in binary form must reproduce the above copyright notice,
14// this list of conditions and the following disclaimer in the documentation
15// and/or other materials provided with the distribution.
16//
17// 3. Neither the name of the copyright holder nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//
32//! # VTIL-RustParser
33//!
34//! Read/write VTIL files in Rust.
35//!
36//! You can learn more about VTIL [here](https://github.com/vtil-project/VTIL-Core#introduction)
37//! on the main GitHub page.
38//!
39//! # Examples
40//! For a simple example of loading a VTIL routine and reading out some basic data:
41//! ```
42//! # use vtil_parser::Result;
43//! use vtil_parser::{Routine, ArchitectureIdentifier};
44//!
45//! # fn main() -> Result<()> {
46//! let routine = Routine::from_path("resources/big.vtil")?;
47//! assert_eq!(routine.header.arch_id, ArchitectureIdentifier::Amd64);
48//! # Ok(())
49//! # }
50//! ```
51//!
52//! For a more complex example, iterating over IL instructions:
53//! ```
54//! # use vtil_parser::Result;
55//! use vtil_parser::{Routine, Op, Operand, RegisterDesc, ImmediateDesc, RegisterFlags};
56//!
57//! # fn main() -> Result<()> {
58//! let routine = Routine::from_path("resources/big.vtil")?;
59//!
60//! for (_, basic_block) in routine.explored_blocks.iter().take(1) {
61//! for instr in basic_block.instructions.iter().take(1) {
62//! match &instr.op {
63//! Op::Ldd(_, Operand::RegisterDesc(op2), Operand::ImmediateDesc(op3)) => {
64//! assert!(op2.flags.contains(RegisterFlags::PHYSICAL));
65//! assert!(op3.i64() == 0);
66//! }
67//! _ => assert!(false)
68//! }
69//!
70//! assert_eq!(instr.vip.0, 0x9b833);
71//! }
72//! }
73//! # Ok(())
74//! # }
75//! ```
76
77#![allow(clippy::upper_case_acronyms)]
78#![allow(clippy::useless_conversion)]
79#![deny(missing_docs)]
80
81use memmap::MmapOptions;
82use scroll::{ctx::SizeWith, Pread, Pwrite};
83
84use indexmap::map::IndexMap;
85use std::fs::File;
86use std::path::Path;
87
88#[macro_use]
89extern crate bitflags;
90
91mod error;
92pub use error::Error;
93
94mod arch_info;
95
96mod pod;
97pub use pod::*;
98
99mod serialize;
100pub use serialize::*;
101
102mod instr_builder;
103pub use instr_builder::*;
104
105/// Helpers for dumping VTIL structures
106pub mod dump;
107
108#[doc(hidden)]
109pub type Result<T> = std::result::Result<T, error::Error>;
110
111/// VTIL routine container
112impl Routine {
113 /// Build a new VTIL routine container
114 pub fn new(arch_id: ArchitectureIdentifier) -> Routine {
115 let (routine_convention, subroutine_convention) = match arch_id {
116 ArchitectureIdentifier::Virtual => {
117 let routine_convention = RoutineConvention {
118 volatile_registers: vec![],
119 param_registers: vec![],
120 retval_registers: vec![],
121 // Not used, so it doesn't matter
122 frame_register: RegisterDesc {
123 flags: RegisterFlags::VIRTUAL,
124 combined_id: 0,
125 bit_count: 0,
126 bit_offset: 0,
127 },
128 shadow_space: 0,
129 purge_stack: true,
130 };
131 (routine_convention.clone(), routine_convention)
132 }
133 _ => unimplemented!(),
134 };
135 Routine {
136 header: Header { arch_id },
137 vip: Vip(0),
138 routine_convention,
139 subroutine_convention,
140 spec_subroutine_conventions: vec![],
141 explored_blocks: IndexMap::new(),
142 }
143 }
144
145 /// Tries to create a [`BasicBlock`], returns `None` if a block already
146 /// exists at the given address
147 pub fn create_block(&mut self, vip: Vip) -> Option<&mut BasicBlock> {
148 if !self.explored_blocks.contains_key(&vip) {
149 let basic_block = BasicBlock {
150 vip,
151 sp_offset: 0,
152 sp_index: 0,
153 last_temporary_index: 0,
154 instructions: vec![],
155 prev_vip: vec![],
156 next_vip: vec![],
157 };
158
159 self.explored_blocks.insert(vip, basic_block);
160 Some(self.explored_blocks.get_mut(&vip).unwrap())
161 } else {
162 None
163 }
164 }
165
166 /// Tries to remove a [`BasicBlock`] from the [`Routine`]
167 pub fn remove_block(&mut self, vip: Vip) -> Option<BasicBlock> {
168 self.explored_blocks.remove(&vip)
169 }
170
171 /// Tries to load VTIL routine from the given path
172 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Routine> {
173 let source = Box::new(unsafe { MmapOptions::new().map(&File::open(path.as_ref())?)? });
174 source.pread_with::<Routine>(0, scroll::LE)
175 }
176
177 /// Loads VTIL routine from a `Vec<u8>`
178 pub fn from_vec(source: &[u8]) -> Result<Routine> {
179 source.as_ref().pread_with::<Routine>(0, scroll::LE)
180 }
181
182 /// Serialize the VTIL routine container, consuming it
183 pub fn into_bytes(self) -> Result<Vec<u8>> {
184 let size = Routine::size_with(&self);
185 let mut buffer = vec![0; size];
186 buffer.pwrite_with::<Routine>(self, 0, scroll::LE)?;
187 Ok(buffer)
188 }
189}