Skip to content

Commit

Permalink
replace serde_traitobject with typetag (#210)
Browse files Browse the repository at this point in the history
* replace serde_traitobject with typetag

* Update Cargo.toml
  • Loading branch information
0xAWM authored Sep 29, 2023
1 parent 169cda6 commit b208152
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 82 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ once_cell = "1.8.0"
permutator = "0.4.3"
either = "1.8.0"
regex = "1"
typetag = "0.2.13"

# external fuzzing-based abi decompiler
heimdall = { path = "./externals/heimdall-rs/heimdall" }
Expand Down
10 changes: 8 additions & 2 deletions src/evm/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ pub enum ABILossyType {
}

/// Traits of ABI types (encoding, decoding, etc.)
pub trait ABI: CloneABI + serde_traitobject::Serialize + serde_traitobject::Deserialize {
#[typetag::serde(tag = "type")]
pub trait ABI: CloneABI {
/// Is the args static (i.e., fixed size)
fn is_static(&self) -> bool;
/// Get the ABI-encoded bytes of args
Expand Down Expand Up @@ -159,7 +160,7 @@ where
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct BoxedABI {
/// ABI wrapper
#[serde(with = "serde_traitobject")]
// #[serde(with = "serde_traitobject")]
pub b: Box<dyn ABI>,
/// Function hash, if it is 0x00000000, it means the function hash is not set or
/// this is to resume execution from a previous control leak
Expand Down Expand Up @@ -501,6 +502,7 @@ impl Input for AEmpty {
}
}

#[typetag::serde]
impl ABI for AEmpty {
fn is_static(&self) -> bool {
true
Expand Down Expand Up @@ -566,6 +568,7 @@ impl HasBytesVec for A256 {
}
}

#[typetag::serde]
impl ABI for A256 {
fn is_static(&self) -> bool {
// 256-bit args are always static
Expand Down Expand Up @@ -648,6 +651,7 @@ impl HasBytesVec for ADynamic {
}
}

#[typetag::serde]
impl ABI for ADynamic {
fn is_static(&self) -> bool {
false
Expand Down Expand Up @@ -741,6 +745,7 @@ fn set_size_concolic(bytes: *mut Box<Expr>, len: usize) {
}
}

#[typetag::serde]
impl ABI for AArray {
fn is_static(&self) -> bool {
if self.dynamic_size {
Expand Down Expand Up @@ -986,6 +991,7 @@ impl Input for AUnknown {
}
}

#[typetag::serde]
impl ABI for AUnknown {
fn is_static(&self) -> bool {
self.concrete.is_static()
Expand Down
164 changes: 84 additions & 80 deletions src/fuzzers/evm_fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use crate::{
evm::contract_utils::FIX_DEPLOYER, evm::host::FuzzHost, evm::vm::EVMExecutor,
executor::FuzzExecutor, fuzzer::ItyFuzzer,
};
use glob::glob;
use itertools::Itertools;
use libafl::feedbacks::Feedback;
use libafl::prelude::{HasMetadata, ShMemProvider};
use libafl::prelude::{QueueScheduler, SimpleEventManager};
Expand All @@ -21,11 +23,11 @@ use libafl::{
prelude::{tuple_list, MaxMapFeedback, SimpleMonitor, StdMapObserver},
Evaluator, Fuzzer,
};
use glob::glob;
use itertools::Itertools;

use crate::evm::host::{ACTIVE_MATCH_EXT_CALL, CMP_MAP, JMP_MAP, PANIC_ON_BUG, READ_MAP, WRITE_MAP, WRITE_RELATIONSHIPS};
use crate::evm::host::{CALL_UNTIL};
use crate::evm::host::CALL_UNTIL;
use crate::evm::host::{
ACTIVE_MATCH_EXT_CALL, CMP_MAP, JMP_MAP, PANIC_ON_BUG, READ_MAP, WRITE_MAP, WRITE_RELATIONSHIPS,
};
use crate::evm::vm::EVMState;
use crate::feedback::{CmpFeedback, DataflowFeedback, OracleFeedback};

Expand All @@ -37,14 +39,6 @@ use crate::evm::config::Config;
use crate::evm::corpus_initializer::EVMCorpusInitializer;
use crate::evm::input::{ConciseEVMInput, EVMInput, EVMInputT, EVMInputTy};

use crate::evm::mutator::{AccessPattern, FuzzMutator};
use crate::evm::onchain::flashloan::Flashloan;
use crate::evm::onchain::onchain::{OnChain, WHITELIST_ADDR};
use crate::evm::presets::pair::PairPreset;
use crate::evm::types::{EVMAddress, EVMFuzzMutator, EVMFuzzState, EVMU256, fixed_address};
use primitive_types::{H160, U256};
use revm_primitives::{BlockEnv, Bytecode, Env};
use revm_primitives::bitvec::view::BitViewSized;
use crate::evm::abi::ABIAddressToInstanceMap;
use crate::evm::blaz::builder::{ArtifactInfoMetadata, BuildJob};
use crate::evm::concolic::concolic_host::ConcolicHost;
Expand All @@ -55,15 +49,23 @@ use crate::evm::middlewares::call_printer::CallPrinter;
use crate::evm::middlewares::coverage::{Coverage, EVAL_COVERAGE};
use crate::evm::middlewares::middleware::Middleware;
use crate::evm::middlewares::sha3_bypass::{Sha3Bypass, Sha3TaintAnalysis};
use crate::evm::mutator::{AccessPattern, FuzzMutator};
use crate::evm::onchain::flashloan::Flashloan;
use crate::evm::onchain::onchain::{OnChain, WHITELIST_ADDR};
use crate::evm::oracles::arb_call::ArbitraryCallOracle;
use crate::evm::oracles::echidna::EchidnaOracle;
use crate::evm::oracles::selfdestruct::SelfdestructOracle;
use crate::evm::oracles::state_comp::StateCompOracle;
use crate::evm::oracles::typed_bug::TypedBugOracle;
use crate::evm::presets::pair::PairPreset;
use crate::evm::srcmap::parser::BASE_PATH;
use crate::evm::types::{fixed_address, EVMAddress, EVMFuzzMutator, EVMFuzzState, EVMU256};
use crate::fuzzer::{REPLAY, RUN_FOREVER};
use crate::input::{ConciseSerde, VMInputT};
use crate::oracle::BugMetadata;
use primitive_types::{H160, U256};
use revm_primitives::bitvec::view::BitViewSized;
use revm_primitives::{BlockEnv, Bytecode, Env};

struct ABIConfig {
abi: String,
Expand All @@ -76,7 +78,19 @@ struct ContractInfo {
}

pub fn evm_fuzzer(
config: Config<EVMState, EVMAddress, Bytecode, Bytes, EVMAddress, EVMU256, Vec<u8>, EVMInput, EVMFuzzState, ConciseEVMInput>, state: &mut EVMFuzzState
config: Config<
EVMState,
EVMAddress,
Bytecode,
Bytes,
EVMAddress,
EVMU256,
Vec<u8>,
EVMInput,
EVMFuzzState,
ConciseEVMInput,
>,
state: &mut EVMFuzzState,
) {
// create work dir if not exists
let path = Path::new(config.work_dir.as_str());
Expand Down Expand Up @@ -201,7 +215,7 @@ pub fn evm_fuzzer(
&mut scheduler,
&infant_scheduler,
state,
config.work_dir.clone()
config.work_dir.clone(),
);

#[cfg(feature = "use_presets")]
Expand All @@ -210,11 +224,12 @@ pub fn evm_fuzzer(
let mut artifacts = corpus_initializer.initialize(&mut config.contract_loader.clone());

let mut instance_map = ABIAddressToInstanceMap::new();
artifacts.address_to_abi_object.iter().for_each(
|(addr, abi)| {
artifacts
.address_to_abi_object
.iter()
.for_each(|(addr, abi)| {
instance_map.map.insert(addr.clone(), abi.clone());
}
);
});

let cov_middleware = Rc::new(RefCell::new(Coverage::new(
artifacts.address_to_sourcemap.clone(),
Expand All @@ -224,9 +239,7 @@ pub fn evm_fuzzer(

evm_executor.host.add_middlewares(cov_middleware.clone());

state.add_metadata(
instance_map
);
state.add_metadata(instance_map);

evm_executor.host.initialize(state);

Expand All @@ -236,7 +249,10 @@ pub fn evm_fuzzer(
if !state.metadata().contains::<ArtifactInfoMetadata>() {
state.metadata_mut().insert(ArtifactInfoMetadata::new());
}
let meta = state.metadata_mut().get_mut::<ArtifactInfoMetadata>().unwrap();
let meta = state
.metadata_mut()
.get_mut::<ArtifactInfoMetadata>()
.unwrap();
for (addr, build_artifact) in &artifacts.build_artifacts {
meta.add(*addr, build_artifact.clone());
}
Expand All @@ -247,21 +263,18 @@ pub fn evm_fuzzer(
bytecode,
*addr,
&mut evm_executor_ref.deref().borrow_mut().host,
state
state,
);
}
}


let mut feedback = MaxMapFeedback::new(&jmp_observer);
feedback
.init_state(state)
.expect("Failed to init state");
feedback.init_state(state).expect("Failed to init state");
// let calibration = CalibrationStage::new(&feedback);
let concolic_stage = ConcolicStage::new(
config.concolic,
config.concolic_caller,
evm_executor_ref.clone()
evm_executor_ref.clone(),
);
let mutator: EVMFuzzMutator<'_> = FuzzMutator::new(&infant_scheduler);

Expand All @@ -281,8 +294,6 @@ pub fn evm_fuzzer(

let mut stages = tuple_list!(std_stage, concolic_stage, coverage_obs_stage);



let mut executor = FuzzExecutor::new(evm_executor_ref.clone(), tuple_list!(jmp_observer));

#[cfg(feature = "deployer_is_attacker")]
Expand All @@ -294,61 +305,53 @@ pub fn evm_fuzzer(

if config.echidna_oracle {
let echidna_oracle = EchidnaOracle::new(
artifacts.address_to_abi.iter()
.map(
|(address, abis)| {
abis.iter().filter(
|abi| {
abi.function_name.starts_with("echidna_")
&& abi.abi == "()"
}
).map(
|abi| (address.clone(), abi.function.to_vec())
).collect_vec()
}
).flatten().collect_vec(),

artifacts.address_to_abi.iter()
.map(
|(address, abis)| {
abis.iter().filter(
|abi| {
abi.function_name.starts_with("echidna_")
&& abi.abi == "()"
}
).map(
|abi| (abi.function.to_vec(), abi.function_name.clone())
).collect_vec()
}
).flatten().collect::<HashMap<Vec<u8>, String>>(),
artifacts
.address_to_abi
.iter()
.map(|(address, abis)| {
abis.iter()
.filter(|abi| abi.function_name.starts_with("echidna_") && abi.abi == "()")
.map(|abi| (address.clone(), abi.function.to_vec()))
.collect_vec()
})
.flatten()
.collect_vec(),
artifacts
.address_to_abi
.iter()
.map(|(address, abis)| {
abis.iter()
.filter(|abi| abi.function_name.starts_with("echidna_") && abi.abi == "()")
.map(|abi| (abi.function.to_vec(), abi.function_name.clone()))
.collect_vec()
})
.flatten()
.collect::<HashMap<Vec<u8>, String>>(),
);
oracles.push(Rc::new(RefCell::new(echidna_oracle)));
}

if let Some(path) = config.state_comp_oracle {
let mut file = File::open(path.clone()).expect("Failed to open state comp oracle file");
let mut buf = String::new();
file.read_to_string(&mut buf).expect("Failed to read state comp oracle file");
file.read_to_string(&mut buf)
.expect("Failed to read state comp oracle file");

let evm_state = serde_json::from_str::<EVMState>(buf.as_str()).expect("Failed to parse state comp oracle file");
let evm_state = serde_json::from_str::<EVMState>(buf.as_str())
.expect("Failed to parse state comp oracle file");

let oracle = Rc::new(RefCell::new(
StateCompOracle::new(
evm_state,
config.state_comp_matching.unwrap(),
)
));
let oracle = Rc::new(RefCell::new(StateCompOracle::new(
evm_state,
config.state_comp_matching.unwrap(),
)));
oracles.push(oracle);
}

if config.arbitrary_external_call {

oracles.push(Rc::new(RefCell::new(
ArbitraryCallOracle::new(
artifacts.address_to_sourcemap.clone(),
artifacts.address_to_name.clone(),
)
)));
oracles.push(Rc::new(RefCell::new(ArbitraryCallOracle::new(
artifacts.address_to_sourcemap.clone(),
artifacts.address_to_name.clone(),
))));
}

if config.typed_bug {
Expand All @@ -367,15 +370,14 @@ pub fn evm_fuzzer(
))));
}


let mut producers = config.producers;

let objective = OracleFeedback::new(&mut oracles, &mut producers, evm_executor_ref.clone());
let wrapped_feedback = ConcolicFeedbackWrapper::new(Sha3WrappedFeedback::new(
feedback,
sha3_taint,
evm_executor_ref.clone(),
config.sha3_bypass
config.sha3_bypass,
));

let mut fuzzer = ItyFuzzer::new(
Expand All @@ -402,7 +404,10 @@ pub fn evm_fuzzer(
artifacts.address_to_name.clone(),
artifacts.address_to_sourcemap.clone(),
)));
evm_executor_ref.borrow_mut().host.add_middlewares(printer.clone());
evm_executor_ref
.borrow_mut()
.host
.add_middlewares(printer.clone());

let initial_vm_state = artifacts.initial_state.clone();
for file in glob(files.as_str()).expect("Failed to read glob pattern") {
Expand All @@ -427,7 +432,9 @@ pub fn evm_fuzzer(
.to_input(vm_state.clone());
printer.borrow_mut().cleanup();

unsafe {CALL_UNTIL = call_until;}
unsafe {
CALL_UNTIL = call_until;
}

fuzzer
.evaluate_input_events(state, &mut executor, &mut mgr, inp, false)
Expand All @@ -438,10 +445,7 @@ pub fn evm_fuzzer(
"reverted: {:?}",
state.get_execution_result().clone().reverted
);
println!(
"call trace:\n{}",
printer.deref().borrow().get_trace()
);
println!("call trace:\n{}", printer.deref().borrow().get_trace());
println!(
"output: {:?}",
hex::encode(state.get_execution_result().clone().output)
Expand Down

0 comments on commit b208152

Please sign in to comment.