Instrument WebAssembly Binaries Using Rust. This repository uses Walrus as a parse backend in order to be up-to-date with the latest wasm standards and proposals.
All done by cargo.
rWABIDB basically provides the ability to modify a wasm binary, which is also potentially useful for individual usage in other projects.
All tests under tests directory give a basic usage of the APIs.
Important: All inserted instructions should be carefully designed to maintain a still balanced stack after insertions.
rWABIDB provides a match-and-insert semantic api. It finds expressions in functions that match the Matcher Fn, and insert certain instructions before and after the matching point. A Modifier Fn can be optionally provided to modify the pre and post fragments before each insertion, allowing more dynamic capability.
Note that these targets MUST be orthogonal(Or we say the target in front is matched first).
fn instrument(&mut self, operations: &Vec<InstrumentOperation>) -> InstrumentResult
struct InstrumentOperation {
pub targets: InstrMatcher,
pub pre_instructions: Vec<Instr>,
pub post_instructions: Vec<Instr>,
pub modifier: Option<FragmentModifier>,
}
type InstrMatcher = Box<dyn Fn(&Instr) -> bool + 'static>;
type FragmentModifier = Box<dyn Fn(&(Instr, InstrLocId), &mut Vec<Instr>, &mut Vec<Instr>) + 'static>;Similar to the previous one, except it replaces the matched instructions with a call to the hook function.
fn instrument_hook(&mut self, hooks: &Vec<InstrumentHook>) -> InstrumentResult
struct InstrumentHook {
pub targets: InstrMatcher,
// Make sure the type of the hook function is identical to that of those target instructions
pub hook_id: FunctionId,
}// Add
fn add_global(&mut self, ty: ValType, mutable: bool, value: Value) -> GlobalId
fn add_memory(&mut self, shared: bool, init_pages: u64, max_pages: Option<u64>) -> MemoryId
fn add_funtion<MakerFn>(&mut self, name: Option<String>, args: &[ValType], locals: &[ValType], rets: &[ValType], func_maker: MakerFn) -> FunctionId
where MakerFn: Fn(&mut InstrSeqBuilder, &[LocalId])
fn add_export(&mut self, name: &str, item: impl Into<ExportItem>) -> ExportId
// Get
fn get_global_by_name(&mut self, name: &String) -> Option<&mut Global>
fn get_global_by_id(&mut self, id: GlobalId) -> &mut Global
fn get_memory_by_name(&mut self, name: &String) -> Option<&mut Memory>
fn get_memory_by_id(&mut self, id: MemoryId) -> &mut Memory
fn get_function_by_name(&mut self, name: &String) -> Option<&mut Function>
fn get_function_by_id(&mut self, id: walrus::FunctionId) -> &mut Function
fn get_local_by_id(&self, id: LocalId) -> &Local
fn get_export_by_id(&self, id: ExportId) -> &Exportfn print(&mut self)
fn write_binary(&mut self) -> Result<()>
fn get_binary(&mut self) -> Vec<u8>instrument() and instrument_hook() will be performed on functions in the scope. The scope contains all defined(unimport) functions of the original binary by default. You can modify the scope using following APIs.
fn function_scope_add(&mut self, func_id: FunctionId) -> bool
fn function_scope_remove(&mut self, func_id: &FunctionId) -> bool
fn function_scope_contains(&mut self, func_id: &FunctionId) -> bool
fn function_scope_clear(&mut self)A Rust version of my WABIDB. Rust is good.