From cb50da1ef11dac9b4788c27e53411c58b71587a4 Mon Sep 17 00:00:00 2001 From: "0xAWM.eth" <29773064+0xAWM@users.noreply.github.com> Date: Fri, 29 Sep 2023 08:02:08 +0800 Subject: [PATCH] add real balance for onchain && handle call transfer (#198) * add debug info for contract init && clippy * clippy host.rs * clippy onchain/vm.rs * add real balance for onchain && handle call transfer * clean debug code * skip to deploy FuzzLand helper contract * add test * Fix force_cache macro * real_balance as a feature --------- Co-authored-by: Chaofan Shou --- Cargo.toml | 1 + cli/src/evm.rs | 65 ++-- src/evm/contract_utils.rs | 83 ++--- src/evm/corpus_initializer.rs | 143 ++++++--- src/evm/host.rs | 490 +++++++++++++++--------------- src/evm/middlewares/middleware.rs | 22 +- src/evm/onchain/endpoints.rs | 44 ++- src/evm/onchain/onchain.rs | 233 +++++++------- src/evm/vm.rs | 69 +++-- src/executor.rs | 10 +- src/fuzzer.rs | 207 +++++++------ src/fuzzers/evm_fuzzer.rs | 10 +- tests/evm/balance/test.sol | 20 ++ 13 files changed, 780 insertions(+), 617 deletions(-) create mode 100644 tests/evm/balance/test.sol diff --git a/Cargo.toml b/Cargo.toml index 70f17499f..cc13a9e4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ print_infant_corpus = [] print_txn_corpus = [] fuzz_static = [] flashloan_v2 = [] +real_balance = [] full_trace = [] force_cache = [] use_presets = [] diff --git a/cli/src/evm.rs b/cli/src/evm.rs index 3c6270cc4..74af5f0d6 100644 --- a/cli/src/evm.rs +++ b/cli/src/evm.rs @@ -1,6 +1,9 @@ use clap::Parser; use ethers::types::Transaction; use hex::{decode, encode}; +use ityfuzz::evm::blaz::builder::{BuildJob, BuildJobResult}; +use ityfuzz::evm::blaz::offchain_artifacts::OffChainArtifact; +use ityfuzz::evm::blaz::offchain_config::OffchainConfig; use ityfuzz::evm::config::{Config, FuzzerTypes, StorageFetchingMode}; use ityfuzz::evm::contract_utils::{set_hash, ContractLoader}; use ityfuzz::evm::host::PANIC_ON_BUG; @@ -29,10 +32,6 @@ use std::collections::HashSet; use std::env; use std::rc::Rc; use std::str::FromStr; -use ityfuzz::evm::blaz::builder::{BuildJob, BuildJobResult}; -use ityfuzz::evm::blaz::offchain_artifacts::OffChainArtifact; -use ityfuzz::evm::blaz::offchain_config::OffchainConfig; - pub fn parse_constructor_args_string(input: String) -> HashMap> { let mut map = HashMap::new(); @@ -263,7 +262,7 @@ enum EVMTargetType { Glob, Address, ArtifactAndProxy, - Config + Config, } pub fn evm_main(args: EvmArgs) { @@ -342,7 +341,7 @@ pub fn evm_main(args: EvmArgs) { Vec, EVMInput, EVMFuzzState, - ConciseEVMInput + ConciseEVMInput, >, >, >, @@ -361,7 +360,7 @@ pub fn evm_main(args: EvmArgs) { Vec, EVMInput, EVMFuzzState, - ConciseEVMInput + ConciseEVMInput, >, >, >, @@ -426,7 +425,6 @@ pub fn evm_main(args: EvmArgs) { let constructor_args_map = parse_constructor_args_string(args.constructor_args); - let onchain_replacements = if args.onchain_replacements_file.len() > 0 { BuildJobResult::from_multi_file(args.onchain_replacements_file) } else { @@ -441,19 +439,31 @@ pub fn evm_main(args: EvmArgs) { let offchain_artifacts = if args.builder_artifacts_url.len() > 0 { target_type = EVMTargetType::ArtifactAndProxy; - Some(OffChainArtifact::from_json_url(args.builder_artifacts_url).expect("failed to parse builder artifacts")) + Some( + OffChainArtifact::from_json_url(args.builder_artifacts_url) + .expect("failed to parse builder artifacts"), + ) } else if args.builder_artifacts_file.len() > 0 { target_type = EVMTargetType::ArtifactAndProxy; - Some(OffChainArtifact::from_file(args.builder_artifacts_file).expect("failed to parse builder artifacts")) + Some( + OffChainArtifact::from_file(args.builder_artifacts_file) + .expect("failed to parse builder artifacts"), + ) } else { None }; let offchain_config = if args.offchain_config_url.len() > 0 { target_type = EVMTargetType::Config; - Some(OffchainConfig::from_json_url(args.offchain_config_url).expect("failed to parse offchain config")) + Some( + OffchainConfig::from_json_url(args.offchain_config_url) + .expect("failed to parse offchain config"), + ) } else if args.offchain_config_file.len() > 0 { target_type = EVMTargetType::Config; - Some(OffchainConfig::from_file(args.offchain_config_file).expect("failed to parse offchain config")) + Some( + OffchainConfig::from_file(args.offchain_config_file) + .expect("failed to parse offchain config"), + ) } else { None }; @@ -461,20 +471,16 @@ pub fn evm_main(args: EvmArgs) { let config = Config { fuzzer_type: FuzzerTypes::from_str(args.fuzzer_type.as_str()).expect("unknown fuzzer"), contract_loader: match target_type { - EVMTargetType::Glob => { - ContractLoader::from_glob( - args.target.as_str(), - &mut state, - &proxy_deploy_codes, - &constructor_args_map, - ) - } - EVMTargetType::Config => { - ContractLoader::from_config( - &offchain_artifacts.expect("offchain artifacts is required for config target type"), - &offchain_config.expect("offchain config is required for config target type"), - ) - } + EVMTargetType::Glob => ContractLoader::from_glob( + args.target.as_str(), + &mut state, + &proxy_deploy_codes, + &constructor_args_map, + ), + EVMTargetType::Config => ContractLoader::from_config( + &offchain_artifacts.expect("offchain artifacts is required for config target type"), + &offchain_config.expect("offchain config is required for config target type"), + ), EVMTargetType::ArtifactAndProxy => { // ContractLoader::from_artifacts_and_proxy( @@ -511,12 +517,15 @@ pub fn evm_main(args: EvmArgs) { ContractLoader::from_address( &mut onchain.as_mut().unwrap(), HashSet::from_iter(addresses), - builder.clone(), + builder.clone(), ) } }, only_fuzz: if args.only_fuzz.len() > 0 { - args.only_fuzz.split(",").map(|s| EVMAddress::from_str(s).expect("failed to parse only fuzz")).collect() + args.only_fuzz + .split(",") + .map(|s| EVMAddress::from_str(s).expect("failed to parse only fuzz")) + .collect() } else { HashSet::new() }, diff --git a/src/evm/contract_utils.rs b/src/evm/contract_utils.rs index 713364734..4c8fb9f64 100644 --- a/src/evm/contract_utils.rs +++ b/src/evm/contract_utils.rs @@ -8,10 +8,10 @@ use std::collections::{HashMap, HashSet}; use std::fs::File; use crate::state::FuzzState; +use bytes::Bytes; use itertools::Itertools; use std::io::Read; use std::path::Path; -use bytes::Bytes; extern crate crypto; @@ -21,19 +21,19 @@ use crate::evm::srcmap::parser::{decode_instructions, SourceMapLocation}; use self::crypto::digest::Digest; use self::crypto::sha3::Sha3; +use crate::evm::blaz::builder::{BuildJob, BuildJobResult}; +use crate::evm::blaz::offchain_artifacts::OffChainArtifact; +use crate::evm::blaz::offchain_config::OffchainConfig; +use crate::evm::bytecode_iterator::all_bytecode; +use crate::evm::host::FuzzHost; use crate::evm::onchain::abi_decompiler::fetch_abi_heimdall; +use crate::evm::vm::EVMExecutor; use hex::encode; use regex::Regex; use revm_interpreter::analysis::to_analysed; use revm_interpreter::opcode::PUSH4; use revm_primitives::Bytecode; use serde::{Deserialize, Serialize}; -use crate::evm::blaz::builder::{BuildJob, BuildJobResult}; -use crate::evm::blaz::offchain_artifacts::OffChainArtifact; -use crate::evm::blaz::offchain_config::OffchainConfig; -use crate::evm::bytecode_iterator::all_bytecode; -use crate::evm::host::FuzzHost; -use crate::evm::vm::EVMExecutor; // to use this address, call rand_utils::fixed_address(FIX_DEPLOYER) pub static FIX_DEPLOYER: &str = "8b21e662154b4bbc1ec0754d0238875fe3d22fa6"; @@ -84,7 +84,7 @@ impl ContractLoader { let mut data = String::new(); file.read_to_string(&mut data) .expect("failed to read abis file"); - return Self::parse_abi_str(&data); + Self::parse_abi_str(&data) } fn process_input(ty: String, input: &Value) -> String { @@ -111,7 +111,7 @@ impl ContractLoader { } pub fn parse_abi_str(data: &String) -> Vec { - let json: Vec = serde_json::from_str(&data).expect("failed to parse abis file"); + let json: Vec = serde_json::from_str(data).expect("failed to parse abis file"); json.iter() .flat_map(|abi| { if abi["type"] == "function" || abi["type"] == "constructor" { @@ -194,7 +194,7 @@ impl ContractLoader { proxy_deploy_codes: &Vec, constructor_args: &Vec, ) -> Self { - let contract_name = prefix.split("/").last().unwrap().replace("*", ""); + let contract_name = prefix.split('/').last().unwrap().replace('*', ""); // get constructor args let constructor_args_in_bytes: Vec = Self::constructor_args_encode(constructor_args); @@ -209,13 +209,12 @@ impl ContractLoader { deployed_address: generate_random_address(state), source_map: source_map_info.map(|info| { info.get(contract_name.as_str()) - .expect( - format!( + .unwrap_or_else(|| { + panic!( "combined.json provided but contract ({:?}) not found", contract_name ) - .as_str(), - ) + }) .clone() }), build_artifact: None, @@ -225,6 +224,7 @@ impl ContractLoader { abi: vec![], }; + println!(); println!("Loading contract {}", prefix); // Load contract, ABI, and address from file @@ -257,7 +257,7 @@ impl ContractLoader { let mut abi_instance = get_abi_type_boxed_with_address(&abi.abi, fixed_address(FIX_DEPLOYER).0.to_vec()); abi_instance.set_func_with_name(abi.function, abi.function_name.clone()); - if contract_result.constructor_args.len() == 0 { + if contract_result.constructor_args.is_empty() { println!("No constructor args found, using default constructor args"); contract_result.constructor_args = abi_instance.get().get_bytes(); } @@ -275,14 +275,14 @@ impl ContractLoader { let current_code = hex::encode(&contract_result.code); for deployed_code in proxy_deploy_codes { // if deploy_code startwiths '0x' then remove it - let deployed_code_cleaned = if deployed_code.starts_with("0x") { - &deployed_code[2..] + let deployed_code = if let Some(stripped) = deployed_code.strip_prefix("0x") { + stripped } else { deployed_code }; // match all function signatures, compare sigs between our code and deployed code from proxy - let deployed_code_sig: Vec<[u8; 4]> = extract_sig_from_contract(deployed_code_cleaned); + let deployed_code_sig: Vec<[u8; 4]> = extract_sig_from_contract(deployed_code); let current_code_sig: Vec<[u8; 4]> = extract_sig_from_contract(¤t_code); // compare deployed_code_sig and current_code_sig @@ -296,18 +296,18 @@ impl ContractLoader { } if is_match { contract_result.code = - hex::decode(deployed_code_cleaned).expect("Failed to parse deploy code"); + hex::decode(deployed_code).expect("Failed to parse deploy code"); } } } - return Self { - contracts: if contract_result.code.len() > 0 { + Self { + contracts: if !contract_result.code.is_empty() { vec![contract_result] } else { vec![] }, abis: vec![abi_result], - }; + } } // This function loads constructs Contract infos from path p @@ -330,10 +330,18 @@ impl ContractLoader { Ok(path) => { let path_str = path.to_str().unwrap(); if path_str.ends_with(".abi") { + // skip FuzzLand.abi + if path_str.ends_with("FuzzLand.abi") { + continue; + } *prefix_file_count .entry(path_str.replace(".abi", "").clone()) .or_insert(0) += 1; } else if path_str.ends_with(".bin") { + // skip FuzzLand.bin + if path_str.ends_with("FuzzLand.bin") { + continue; + } *prefix_file_count .entry(path_str.replace(".bin", "").clone()) .or_insert(0) += 1; @@ -392,7 +400,11 @@ impl ContractLoader { ContractLoader { contracts, abis } } - pub fn from_address(onchain: &mut OnChainConfig, address: HashSet, builder: Option) -> Self { + pub fn from_address( + onchain: &mut OnChainConfig, + address: HashSet, + builder: Option, + ) -> Self { let mut contracts: Vec = vec![]; let mut abis: Vec = vec![]; for addr in address { @@ -430,7 +442,7 @@ impl ContractLoader { constructor_args: vec![], // todo: fill this deployed_address: addr, source_map: None, - build_artifact + build_artifact, }); abis.push(ABIInfo { source: addr.to_string(), @@ -467,11 +479,12 @@ impl ContractLoader { abi: abi.clone(), }); - let constructor_args = hex::decode(contract_info.constructor.clone()).expect("failed to decode hex"); + let constructor_args = + hex::decode(contract_info.constructor.clone()).expect("failed to decode hex"); contracts.push(ContractInfo { name: format!("{}:{}", slug.0, slug.1), code: [more_info.deploy_bytecode.to_vec(), constructor_args.clone()].concat(), - abi: abi, + abi, is_code_deployed: false, constructor_args, deployed_address: contract_info.address, @@ -482,11 +495,10 @@ impl ContractLoader { more_info.deploy_bytecode, more_info.abi.clone(), more_info.source_map_replacements.clone(), - )) + )), }) } - Self { contracts, abis } } @@ -542,7 +554,7 @@ impl ContractLoader { // } } -type ContractSourceMap = HashMap; +// type ContractSourceMap = HashMap; type ContractsSourceMapInfo = HashMap>; pub fn parse_combined_json(json: String) -> ContractsSourceMapInfo { @@ -562,7 +574,7 @@ pub fn parse_combined_json(json: String) -> ContractsSourceMapInfo { for (contract_name, contract_info) in contracts { let splitter = contract_name.split(':').collect::>(); - let file_name = splitter.iter().take(splitter.len() - 1).join(":"); + let _file_name = splitter.iter().take(splitter.len() - 1).join(":"); let contract_name = splitter.last().unwrap().to_string(); let bin_runtime = contract_info["bin-runtime"] @@ -597,7 +609,11 @@ pub fn extract_sig_from_contract(code: &str) -> Vec<[u8; 4]> { // Solidity: check whether next ops is EQ // Vyper: check whether next 2 ops contain XOR - if bytes[pc + 5] == 0x14 || bytes[pc + 5] == 0x18 || bytes[pc + 6] == 0x18 || bytes[pc + 6] == 0x14 { + if bytes[pc + 5] == 0x14 + || bytes[pc + 5] == 0x18 + || bytes[pc + 6] == 0x18 + || bytes[pc + 6] == 0x14 + { let mut sig_bytes = vec![]; for j in 0..4 { sig_bytes.push(*bytes.get(pc + j + 1).unwrap()); @@ -605,15 +621,14 @@ pub fn extract_sig_from_contract(code: &str) -> Vec<[u8; 4]> { code_sig.insert(sig_bytes.try_into().unwrap()); } } - } code_sig.iter().cloned().collect_vec() } mod tests { use super::*; - use std::str::FromStr; use crate::skip_cbor; + use std::str::FromStr; #[test] fn test_load() { @@ -645,7 +660,7 @@ mod tests { // uniswap v2 router let code = "60c06040523480156200001157600080fd5b506040516200573e3803806200573e833981810160405260408110156200003757600080fd5b5080516020909101516001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c6155b762000187600039806101ac5280610e5d5280610e985280610fd5528061129852806116f252806118d65280611e1e5280611fa252806120725280612179528061232c52806123c15280612673528061271a52806127ef52806128f452806129dc5280612a5d52806130ec5280613422528061347852806134ac528061352d528061374752806138f7528061398c5250806110c752806111c5528061136b52806113a4528061154f52806117e452806118b45280611aa1528061225f528061240052806125a95280612a9c5280612ddf5280613071528061309a52806130ca52806132a75280613456528061382d52806139cb528061444a528061448d52806147ed52806149ce5280614f49528061502a52806150aa52506155b76000f3fe60806040526004361061018f5760003560e01c80638803dbee116100d6578063c45a01551161007f578063e8e3370011610059578063e8e3370014610c71578063f305d71914610cfe578063fb3bdb4114610d51576101d5565b8063c45a015514610b25578063d06ca61f14610b3a578063ded9382a14610bf1576101d5565b8063af2979eb116100b0578063af2979eb146109c8578063b6f9de9514610a28578063baa2abde14610abb576101d5565b80638803dbee146108af578063ad5c464814610954578063ad615dec14610992576101d5565b80634a25d94a11610138578063791ac94711610112578063791ac947146107415780637ff36ab5146107e657806385f8c25914610879576101d5565b80634a25d94a146105775780635b0d59841461061c5780635c11d7951461069c576101d5565b80631f00ca74116101695780631f00ca74146103905780632195995c1461044757806338ed1739146104d2576101d5565b806302751cec146101da578063054d50d41461025357806318cbafe51461029b576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061023a600480360360c08110156101fd57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a00135610de4565b6040805192835260208301919091528051918290030190f35b34801561025f57600080fd5b506102896004803603606081101561027657600080fd5b5080359060208101359060400135610f37565b60408051918252519081900360200190f35b3480156102a757600080fd5b50610340600480360360a08110156102be57600080fd5b8135916020810135918101906060810160408201356401000000008111156102e557600080fd5b8201836020820111156102f757600080fd5b8035906020019184602083028401116401000000008311171561031957600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f4c565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561037c578181015183820152602001610364565b505050509050019250505060405180910390f35b34801561039c57600080fd5b50610340600480360360408110156103b357600080fd5b813591908101906040810160208201356401000000008111156103d557600080fd5b8201836020820111156103e757600080fd5b8035906020019184602083028401116401000000008311171561040957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611364945050505050565b34801561045357600080fd5b5061023a600480360361016081101561046b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff610100820135169061012081013590610140013561139a565b3480156104de57600080fd5b50610340600480360360a08110156104f557600080fd5b81359160208101359181019060608101604082013564010000000081111561051c57600080fd5b82018360208201111561052e57600080fd5b8035906020019184602083028401116401000000008311171561055057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356114d8565b34801561058357600080fd5b50610340600480360360a081101561059a57600080fd5b8135916020810135918101906060810160408201356401000000008111156105c157600080fd5b8201836020820111156105d357600080fd5b803590602001918460208302840111640100000000831117156105f557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611669565b34801561062857600080fd5b50610289600480360361014081101561064057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356118ac565b3480156106a857600080fd5b506101d3600480360360a08110156106bf57600080fd5b8135916020810135918101906060810160408201356401000000008111156106e657600080fd5b8201836020820111156106f857600080fd5b8035906020019184602083028401116401000000008311171561071a57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356119fe565b34801561074d57600080fd5b506101d3600480360360a081101561076457600080fd5b81359160208101359181019060608101604082013564010000000081111561078b57600080fd5b82018360208201111561079d57600080fd5b803590602001918460208302840111640100000000831117156107bf57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d97565b610340600480360360808110156107fc57600080fd5b8135919081019060408101602082013564010000000081111561081e57600080fd5b82018360208201111561083057600080fd5b8035906020019184602083028401116401000000008311171561085257600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612105565b34801561088557600080fd5b506102896004803603606081101561089c57600080fd5b5080359060208101359060400135612525565b3480156108bb57600080fd5b50610340600480360360a08110156108d257600080fd5b8135916020810135918101906060810160408201356401000000008111156108f957600080fd5b82018360208201111561090b57600080fd5b8035906020019184602083028401116401000000008311171561092d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612532565b34801561096057600080fd5b50610969612671565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561099e57600080fd5b50610289600480360360608110156109b557600080fd5b5080359060208101359060400135612695565b3480156109d457600080fd5b50610289600480360360c08110156109eb57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356126a2565b6101d360048036036080811015610a3e57600080fd5b81359190810190604081016020820135640100000000811115610a6057600080fd5b820183602082011115610a7257600080fd5b80359060200191846020830284011164010000000083111715610a9457600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612882565b348015610ac757600080fd5b5061023a600480360360e0811015610ade57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135612d65565b348015610b3157600080fd5b5061096961306f565b348015610b4657600080fd5b5061034060048036036040811015610b5d57600080fd5b81359190810190604081016020820135640100000000811115610b7f57600080fd5b820183602082011115610b9157600080fd5b80359060200191846020830284011164010000000083111715610bb357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613093945050505050565b348015610bfd57600080fd5b5061023a6004803603610140811015610c1557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356130c0565b348015610c7d57600080fd5b50610ce06004803603610100811015610c9557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135613218565b60408051938452602084019290925282820152519081900360600190f35b610ce0600480360360c0811015610d1457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040820135916060810135916080820135169060a001356133a7565b61034060048036036080811015610d6757600080fd5b81359190810190604081016020820135640100000000811115610d8957600080fd5b820183602082011115610d9b57600080fd5b80359060200191846020830284011164010000000083111715610dbd57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff81351690602001356136d3565b6000808242811015610e5757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b610e86897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a612d65565b9093509150610e96898685613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050610f2b8583613cff565b50965096945050505050565b6000610f44848484613e3c565b949350505050565b60608142811015610fbe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061102357fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146110c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6111207f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b9150868260018451038151811061113357fe5b60200260200101511015611192576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b611257868660008181106111a257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff163361123d7f00000000000000000000000000000000000000000000000000000000000000008a8a60008181106111f157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b8b600181811061121b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166140c6565b8560008151811061124a57fe5b60200260200101516141b1565b61129682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614381915050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836001855103815181106112e257fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561132057600080fd5b505af1158015611334573d6000803e3d6000fd5b50505050611359848360018551038151811061134c57fe5b6020026020010151613cff565b509695505050505050565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484614608565b90505b92915050565b60008060006113ca7f00000000000000000000000000000000000000000000000000000000000000008f8f6140c6565b90506000876113d9578c6113fb565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506114be8f8f8f8f8f8f8f612d65565b809450819550505050509b509b9950505050505050505050565b6060814281101561154a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6115a87f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106115bb57fe5b6020026020010151101561161a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b61162a868660008181106111a257fe5b61135982878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b606081428110156116db57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061174057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146117df57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b61183d7f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061184d57fe5b60200260200101511115611192576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b6000806118fa7f00000000000000000000000000000000000000000000000000000000000000008d7f00000000000000000000000000000000000000000000000000000000000000006140c6565b9050600086611909578b61192b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506119ed8d8d8d8d8d8d6126a2565b9d9c50505050505050505050505050565b8042811015611a6e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b611afd85856000818110611a7e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1633611af77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168a8a600181811061121b57fe5b8a6141b1565b600085857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611b2d57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611bc657600080fd5b505afa158015611bda573d6000803e3d6000fd5b505050506040513d6020811015611bf057600080fd5b50516040805160208881028281018201909352888252929350611c32929091899189918291850190849080828437600092019190915250889250614796915050565b86611d368288887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611c6557fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b50519063ffffffff614b2916565b1015611d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b5050505050505050565b8042811015611e0757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611e6c57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611f0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b611f1b85856000818110611a7e57fe5b611f59858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250614796915050565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b158015611fe957600080fd5b505afa158015611ffd573d6000803e3d6000fd5b505050506040513d602081101561201357600080fd5b5051905086811015612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b50505050611d8d8482613cff565b6060814281101561217757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16868660008181106121bb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461225a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6122b87f000000000000000000000000000000000000000000000000000000000000000034888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613f6092505050565b915086826001845103815181106122cb57fe5b6020026020010151101561232a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615508602b913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061237357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156123a657600080fd5b505af11580156123ba573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61242c7f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b8460008151811061243957fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124aa57600080fd5b505af11580156124be573d6000803e3d6000fd5b505050506040513d60208110156124d457600080fd5b50516124dc57fe5b61251b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b5095945050505050565b6000610f44848484614b9b565b606081428110156125a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6126027f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150868260008151811061261257fe5b6020026020010151111561161a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610f44848484614cbf565b6000814281101561271457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b612743887f00000000000000000000000000000000000000000000000000000000000000008989893089612d65565b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519194506127ed92508a91879173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b1580156127bc57600080fd5b505afa1580156127d0573d6000803e3d6000fd5b505050506040513d60208110156127e657600080fd5b5051613b22565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561286057600080fd5b505af1158015612874573d6000803e3d6000fd5b505050506113598483613cff565b80428110156128f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168585600081811061293657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146129d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b60003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4257600080fd5b505af1158015612a56573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb612ac87f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b3257600080fd5b505af1158015612b46573d6000803e3d6000fd5b505050506040513d6020811015612b5c57600080fd5b5051612b6457fe5b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612b9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c2d57600080fd5b505afa158015612c41573d6000803e3d6000fd5b505050506040513d6020811015612c5757600080fd5b50516040805160208981028281018201909352898252929350612c999290918a918a918291850190849080828437600092019190915250899250614796915050565b87611d368289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110612ccc57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b6000808242811015612dd857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b6000612e057f00000000000000000000000000000000000000000000000000000000000000008c8c6140c6565b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b158015612e8657600080fd5b505af1158015612e9a573d6000803e3d6000fd5b505050506040513d6020811015612eb057600080fd5b5050604080517f89afcb4400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b158015612f2357600080fd5b505af1158015612f37573d6000803e3d6000fd5b505050506040513d6040811015612f4d57600080fd5b50805160209091015190925090506000612f678e8e614d9f565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614612fa4578183612fa7565b82825b90975095508a871015613005576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b8986101561305e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b505050505097509795505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60606113917f00000000000000000000000000000000000000000000000000000000000000008484613f60565b60008060006131107f00000000000000000000000000000000000000000000000000000000000000008e7f00000000000000000000000000000000000000000000000000000000000000006140c6565b905060008761311f578c613141565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c48101889052905191925073ffffffffffffffffffffffffffffffffffffffff84169163d505accf9160e48082019260009290919082900301818387803b1580156131dd57600080fd5b505af11580156131f1573d6000803e3d6000fd5b505050506132038e8e8e8e8e8e610de4565b909f909e509c50505050505050505050505050565b6000806000834281101561328d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61329b8c8c8c8c8c8c614ef2565b909450925060006132cd7f00000000000000000000000000000000000000000000000000000000000000008e8e6140c6565b90506132db8d3383886141b1565b6132e78c3383876141b1565b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561336657600080fd5b505af115801561337a573d6000803e3d6000fd5b505050506040513d602081101561339057600080fd5b5051949d939c50939a509198505050505050505050565b6000806000834281101561341c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b61344a8a7f00000000000000000000000000000000000000000000000000000000000000008b348c8c614ef2565b9094509250600061349c7f00000000000000000000000000000000000000000000000000000000000000008c7f00000000000000000000000000000000000000000000000000000000000000006140c6565b90506134aa8b3383886141b1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561351257600080fd5b505af1158015613526573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb82866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b505050506040513d60208110156135fc57600080fd5b505161360457fe5b8073ffffffffffffffffffffffffffffffffffffffff16636a627842886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561368357600080fd5b505af1158015613697573d6000803e3d6000fd5b505050506040513d60208110156136ad57600080fd5b50519250348410156136c5576136c533853403613cff565b505096509650969350505050565b6060814281101561374557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e69737761705632526f757465723a20455850495245440000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168686600081811061378957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461382857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f556e69737761705632526f757465723a20494e56414c49445f50415448000000604482015290519081900360640190fd5b6138867f00000000000000000000000000000000000000000000000000000000000000008888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061460892505050565b9150348260008151811061389657fe5b602002602001015111156138f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806154986027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061393e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397157600080fd5b505af1158015613985573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6139f77f000000000000000000000000000000000000000000000000000000000000000089896000818110611acd57fe5b84600081518110613a0457fe5b60200260200101516040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015613a7557600080fd5b505af1158015613a89573d6000803e3d6000fd5b505050506040513d6020811015613a9f57600080fd5b5051613aa757fe5b613ae682878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250614381915050565b81600081518110613af357fe5b602002602001015134111561251b5761251b3383600081518110613b1357fe5b60200260200101513403613cff565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613bf857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613bbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c5a576040519150601f19603f3d011682016040523d82523d6000602084013e613c5f565b606091505b5091509150818015613c8d575080511580613c8d5750808060200190516020811015613c8a57600080fd5b50515b613cf857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b5050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310613d7657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613d39565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613dd8576040519150601f19603f3d011682016040523d82523d6000602084013e613ddd565b606091505b5050905080613e37576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806154e56023913960400191505060405180910390fd5b505050565b6000808411613e96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180615557602b913960400191505060405180910390fd5b600083118015613ea65750600082115b613efb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000613f0f856103e563ffffffff6151f316565b90506000613f23828563ffffffff6151f316565b90506000613f4983613f3d886103e863ffffffff6151f316565b9063ffffffff61527916565b9050808281613f5457fe5b04979650505050505050565b6060600282511015613fd357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff81118015613feb57600080fd5b50604051908082528060200260200182016040528015614015578160200160208202803683370190505b509050828160008151811061402657fe5b60200260200101818152505060005b60018351038110156140be576000806140788786858151811061405457fe5b602002602001015187866001018151811061406b57fe5b60200260200101516152eb565b9150915061409a84848151811061408b57fe5b60200260200101518383613e3c565b8484600101815181106140a957fe5b60209081029190910101525050600101614035565b509392505050565b60008060006140d58585614d9f565b604080517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017815292518251600094606094938a169392918291908083835b6020831061428f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614252565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146142f1576040519150601f19603f3d011682016040523d82523d6000602084013e6142f6565b606091505b5091509150818015614324575080511580614324575080806020019051602081101561432157600080fd5b50515b614379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806155336024913960400191505060405180910390fd5b505050505050565b60005b60018351038110156146025760008084838151811061439f57fe5b60200260200101518584600101815181106143b657fe5b60200260200101519150915060006143ce8383614d9f565b50905060008785600101815181106143e257fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461442a5782600061442e565b6000835b91509150600060028a510388106144455788614486565b6144867f0000000000000000000000000000000000000000000000000000000000000000878c8b6002018151811061447957fe5b60200260200101516140c6565b90506144b37f000000000000000000000000000000000000000000000000000000000000000088886140c6565b73ffffffffffffffffffffffffffffffffffffffff1663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156144fd576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614588578181015183820152602001614570565b50505050905090810190601f1680156145b55780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156145d757600080fd5b505af11580156145eb573d6000803e3d6000fd5b505060019099019850614384975050505050505050565b50505050565b606060028251101561467b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561469357600080fd5b506040519080825280602002602001820160405280156146bd578160200160208202803683370190505b50905082816001835103815181106146d157fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b80156140be576000806147318786600186038151811061471d57fe5b602002602001015187868151811061406b57fe5b9150915061475384848151811061474457fe5b60200260200101518383614b9b565b84600185038151811061476257fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614701565b60005b6001835103811015613e37576000808483815181106147b457fe5b60200260200101518584600101815181106147cb57fe5b60200260200101519150915060006147e38383614d9f565b50905060006148137f000000000000000000000000000000000000000000000000000000000000000085856140c6565b90506000806000808473ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561486157600080fd5b505afa158015614875573d6000803e3d6000fd5b505050506040513d606081101561488b57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905060008073ffffffffffffffffffffffffffffffffffffffff8a8116908916146148d55782846148d8565b83835b9150915061495d828b73ffffffffffffffffffffffffffffffffffffffff166370a082318a6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611cfe57600080fd5b955061496a868383613e3c565b9450505050506000808573ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16146149ae578260006149b2565b6000835b91509150600060028c51038a106149c9578a6149fd565b6149fd7f0000000000000000000000000000000000000000000000000000000000000000898e8d6002018151811061447957fe5b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614aad578181015183820152602001614a95565b50505050905090810190601f168015614ada5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614afc57600080fd5b505af1158015614b10573d6000803e3d6000fd5b50506001909b019a506147999950505050505050505050565b8082038281111561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6000808411614bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806153d4602c913960400191505060405180910390fd5b600083118015614c055750600082115b614c5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b6000614c7e6103e8614c72868863ffffffff6151f316565b9063ffffffff6151f316565b90506000614c986103e5614c72868963ffffffff614b2916565b9050614cb56001828481614ca857fe5b049063ffffffff61527916565b9695505050505050565b6000808411614d19576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154736025913960400191505060405180910390fd5b600083118015614d295750600082115b614d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061544b6028913960400191505060405180910390fd5b82614d8f858463ffffffff6151f316565b81614d9657fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415614e27576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806154006025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610614e61578284614e64565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216614eeb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529151600092839283927f00000000000000000000000000000000000000000000000000000000000000009092169163e6a4390591604480820192602092909190829003018186803b158015614f9257600080fd5b505afa158015614fa6573d6000803e3d6000fd5b505050506040513d6020811015614fbc57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614156150a257604080517fc9c6539600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152898116602483015291517f00000000000000000000000000000000000000000000000000000000000000009092169163c9c65396916044808201926020929091908290030181600087803b15801561507557600080fd5b505af1158015615089573d6000803e3d6000fd5b505050506040513d602081101561509f57600080fd5b50505b6000806150d07f00000000000000000000000000000000000000000000000000000000000000008b8b6152eb565b915091508160001480156150e2575080155b156150f2578793508692506151e6565b60006150ff898484614cbf565b905087811161516c5785811015615161576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154256026913960400191505060405180910390fd5b8894509250826151e4565b6000615179898486614cbf565b90508981111561518557fe5b878110156151de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806154bf6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061520e5750508082028282828161520b57fe5b04145b61139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b8082018281101561139457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008060006152fa8585614d9f565b50905060008061530b8888886140c6565b73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561535057600080fd5b505afa158015615364573d6000803e3d6000fd5b505050506040513d606081101561537a57600080fd5b5080516020909101516dffffffffffffffffffffffffffff918216935016905073ffffffffffffffffffffffffffffffffffffffff878116908416146153c15780826153c4565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a26469706673582212206dd6e03c4b2c0a8e55214926227ae9e2d6f9fec2ce74a6446d615afa355c84f364736f6c634300060600330000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; let sigs = skip_cbor!({ - extract_sig_from_contract(code) + extract_sig_from_contract(code) .iter() .map(|x| hex::encode(x)) .collect_vec() diff --git a/src/evm/corpus_initializer.rs b/src/evm/corpus_initializer.rs index 9aba0ab7a..61686a20b 100644 --- a/src/evm/corpus_initializer.rs +++ b/src/evm/corpus_initializer.rs @@ -1,13 +1,16 @@ /// Utilities to initialize the corpus /// Add all potential calls with default args to the corpus -use crate::evm::abi::{BoxedABI, get_abi_type_boxed}; +use crate::evm::abi::{get_abi_type_boxed, BoxedABI}; use crate::evm::bytecode_analyzer; -use crate::evm::contract_utils::{ABIConfig, ABIInfo, ContractInfo, ContractLoader, extract_sig_from_contract}; +use crate::evm::contract_utils::{extract_sig_from_contract, ABIConfig, ContractLoader}; use crate::evm::input::{ConciseEVMInput, EVMInput, EVMInputTy}; use crate::evm::mutator::AccessPattern; use crate::evm::onchain::onchain::BLACKLIST_ADDR; -use crate::evm::types::{fixed_address, EVMAddress, EVMFuzzState, EVMInfantStateState, EVMStagedVMState, EVMU256, ProjectSourceMapTy}; +use crate::evm::types::{ + fixed_address, EVMAddress, EVMFuzzState, EVMInfantStateState, EVMStagedVMState, + ProjectSourceMapTy, EVMU256, +}; use crate::evm::vm::{EVMExecutor, EVMState}; use crate::generic_vm::vm_executor::GenericVM; @@ -16,36 +19,34 @@ use crate::state_input::StagedVMState; use bytes::Bytes; use libafl::corpus::{Corpus, Testcase}; -use libafl::schedulers::Scheduler; -use libafl::state::HasCorpus; -use revm_primitives::Bytecode; -use crate::fuzzer::REPLAY; -#[cfg(feature = "print_txn_corpus")] -use crate::fuzzer::DUMP_FILE_COUNT; -use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; -use std::ops::Deref; - +use crate::dump_txn; +use crate::evm::blaz::builder::BuildJobResult; +use crate::evm::onchain::abi_decompiler::fetch_abi_heimdall; use crate::evm::onchain::flashloan::register_borrow_txn; use crate::evm::presets::presets::Preset; -use crate::evm::srcmap::parser::{SourceMapLocation}; +use crate::evm::types::EVMExecutionResult; +#[cfg(feature = "print_txn_corpus")] +use crate::fuzzer::DUMP_FILE_COUNT; +use crate::fuzzer::REPLAY; +use crate::input::ConciseSerde; use hex; use itertools::Itertools; -use std::rc::Rc; -use std::time::Duration; -use crypto::sha3::Sha3Mode::Keccak256; use libafl::impl_serdeany; use libafl::prelude::HasMetadata; +use libafl::schedulers::Scheduler; +use libafl::state::HasCorpus; +use revm_primitives::Bytecode; use serde::{Deserialize, Serialize}; -use crate::{dump_file, dump_txn}; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; use std::fs::File; -use std::path::Path; -use crate::input::ConciseSerde; use std::io::Write; -use crate::evm::blaz::builder::BuildJobResult; -use crate::generic_vm::vm_executor::ExecutionResult; -use crate::evm::types::EVMExecutionResult; -use crate::evm::onchain::abi_decompiler::fetch_abi_heimdall; +use std::ops::Deref; +use std::path::Path; +use std::rc::Rc; +use std::time::Duration; + +pub const INITIAL_BALANCE: u128 = 100_000_000_000_000_000_000; // 100 ether pub struct EVMCorpusInitializer<'a> { executor: &'a mut EVMExecutor, @@ -67,7 +68,7 @@ pub struct EVMInitializationArtifacts { pub build_artifacts: HashMap, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct ABIMap { pub signature_to_abi: HashMap<[u8; 4], ABIConfig>, } @@ -76,13 +77,11 @@ impl_serdeany!(ABIMap); impl ABIMap { pub fn new() -> Self { - Self { - signature_to_abi: HashMap::new(), - } + Self::default() } pub fn insert(&mut self, abi: ABIConfig) { - self.signature_to_abi.insert(abi.function.clone(), abi); + self.signature_to_abi.insert(abi.function, abi); } pub fn get(&self, signature: &[u8; 4]) -> Option<&ABIConfig> { @@ -158,7 +157,7 @@ impl<'a> EVMCorpusInitializer<'a> { self.presets.push(preset); } - pub fn initialize(&mut self, loader: &mut ContractLoader) -> EVMInitializationArtifacts{ + pub fn initialize(&mut self, loader: &mut ContractLoader) -> EVMInitializationArtifacts { self.state.metadata_mut().insert(ABIMap::new()); self.setup_default_callers(); self.setup_contract_callers(); @@ -167,7 +166,12 @@ impl<'a> EVMCorpusInitializer<'a> { } pub fn initialize_contract(&mut self, loader: &mut ContractLoader) { + self.executor + .host + .evmstate + .set_balance(self.executor.deployer, EVMU256::from(INITIAL_BALANCE)); for contract in &mut loader.contracts { + println!(); println!("Deploying contract: {}", contract.name); let deployed_address = if !contract.is_code_deployed { match self.executor.deploy( @@ -184,6 +188,7 @@ impl<'a> EVMCorpusInitializer<'a> { } } } else { + println!("Contract {} is already deployed", contract.name); // directly set bytecode let contract_code = Bytecode::new_raw(Bytes::from(contract.code.clone())); bytecode_analyzer::add_analysis_result_to_state(&contract_code, self.state); @@ -192,13 +197,16 @@ impl<'a> EVMCorpusInitializer<'a> { .set_code(contract.deployed_address, contract_code, self.state); contract.deployed_address }; - contract.deployed_address = deployed_address; + println!( + "Contract {} deployed to: {deployed_address:?}", + contract.name + ); self.state.add_address(&deployed_address); } + println!("Deployed all contracts\n"); } - pub fn initialize_corpus(&mut self, loader: &mut ContractLoader) -> EVMInitializationArtifacts { let mut artifacts = EVMInitializationArtifacts { address_to_bytecode: HashMap::new(), @@ -210,7 +218,7 @@ impl<'a> EVMCorpusInitializer<'a> { build_artifacts: Default::default(), }; for contract in &mut loader.contracts { - if contract.abi.len() == 0 { + if contract.abi.is_empty() { // this contract's abi is not available, we will use 3 layers to handle this // 1. Extract abi from bytecode, and see do we have any function sig available in state // 2. Use Heimdall to extract abi @@ -232,7 +240,13 @@ impl<'a> EVMCorpusInitializer<'a> { let abis = fetch_abi_heimdall(contract_code) .iter() .map(|abi| { - if let Some(known_abi) = self.state.metadata().get::().unwrap().get(&abi.function) { + if let Some(known_abi) = self + .state + .metadata() + .get::() + .unwrap() + .get(&abi.function) + { known_abi } else { abi @@ -244,25 +258,39 @@ impl<'a> EVMCorpusInitializer<'a> { } } - artifacts.address_to_sourcemap.insert(contract.deployed_address, contract.source_map.clone()); - artifacts.address_to_abi.insert(contract.deployed_address, contract.abi.clone()); + artifacts + .address_to_sourcemap + .insert(contract.deployed_address, contract.source_map.clone()); + artifacts + .address_to_abi + .insert(contract.deployed_address, contract.abi.clone()); let mut code = vec![]; - self.executor.host.code.clone().get(&contract.deployed_address).map(|c| { + if let Some(c) = self + .executor + .host + .code + .clone() + .get(&contract.deployed_address) + { code.extend_from_slice(c.bytecode()); - }); + } artifacts.address_to_bytecode.insert( contract.deployed_address, - Bytecode::new_raw(Bytes::from(code)) + Bytecode::new_raw(Bytes::from(code)), ); let mut name = contract.name.clone().trim_end_matches('*').to_string(); if name != format!("{:?}", contract.deployed_address) { name = format!("{}({:?})", name, contract.deployed_address.clone()); } - artifacts.address_to_name.insert(contract.deployed_address, name); + artifacts + .address_to_name + .insert(contract.deployed_address, name); if let Some(build_artifact) = &contract.build_artifact { - artifacts.build_artifacts.insert(contract.deployed_address, build_artifact.clone()); + artifacts + .build_artifacts + .insert(contract.deployed_address, build_artifact.clone()); } #[cfg(feature = "flashloan_v2")] @@ -275,16 +303,23 @@ impl<'a> EVMCorpusInitializer<'a> { ); } - if unsafe { BLACKLIST_ADDR.is_some() - && BLACKLIST_ADDR.as_ref().unwrap().contains(&contract.deployed_address) + && BLACKLIST_ADDR + .as_ref() + .unwrap() + .contains(&contract.deployed_address) } { continue; } for abi in contract.abi.clone() { - self.add_abi(&abi, self.scheduler, contract.deployed_address, &mut artifacts); + self.add_abi( + &abi, + self.scheduler, + contract.deployed_address, + &mut artifacts, + ); } // add transfer txn { @@ -309,9 +344,8 @@ impl<'a> EVMCorpusInitializer<'a> { add_input_to_corpus!(self.state, self.scheduler, input); } } - artifacts.initial_state = StagedVMState::new_with_state( - self.executor.host.evmstate.clone(), - ); + artifacts.initial_state = + StagedVMState::new_with_state(self.executor.host.evmstate.clone()); let mut tc = Testcase::new(artifacts.initial_state.clone()); tc.set_exec_time(Duration::from_secs(0)); @@ -336,6 +370,10 @@ impl<'a> EVMCorpusInitializer<'a> { for caller in default_callers { self.state.add_caller(&caller); + self.executor + .host + .evmstate + .set_balance(caller, EVMU256::from(INITIAL_BALANCE)); } } @@ -352,6 +390,10 @@ impl<'a> EVMCorpusInitializer<'a> { Bytecode::new_raw(Bytes::from(vec![0xfd, 0x00])), self.state, ); + self.executor + .host + .evmstate + .set_balance(caller, EVMU256::from(INITIAL_BALANCE)); } } @@ -377,7 +419,7 @@ impl<'a> EVMCorpusInitializer<'a> { None => { self.state .hash_to_address - .insert(abi.function.clone(), HashSet::from([deployed_address])); + .insert(abi.function, HashSet::from([deployed_address])); } } #[cfg(not(feature = "fuzz_static"))] @@ -387,7 +429,8 @@ impl<'a> EVMCorpusInitializer<'a> { let mut abi_instance = get_abi_type_boxed(&abi.abi); abi_instance.set_func_with_name(abi.function, abi.function_name.clone()); - artifacts.address_to_abi_object + artifacts + .address_to_abi_object .entry(deployed_address) .or_insert(vec![]) .push(abi_instance.clone()); @@ -416,7 +459,7 @@ impl<'a> EVMCorpusInitializer<'a> { add_input_to_corpus!(self.state, scheduler, input.clone()); #[cfg(feature = "print_txn_corpus")] { - let corpus_dir = format!("{}/corpus", self.work_dir.as_str()).to_string(); + let corpus_dir = format!("{}/corpus", self.work_dir.as_str()); dump_txn!(corpus_dir, &input) } #[cfg(feature = "use_presets")] diff --git a/src/evm/host.rs b/src/evm/host.rs index c4c7057c4..e7ee61e68 100644 --- a/src/evm/host.rs +++ b/src/evm/host.rs @@ -1,4 +1,3 @@ -use crate::evm::bytecode_analyzer; use crate::evm::input::{ConciseEVMInput, EVMInput, EVMInputT, EVMInputTy}; use crate::evm::middlewares::middleware::{ add_corpus, CallMiddlewareReturn, Middleware, MiddlewareType, @@ -6,19 +5,14 @@ use crate::evm::middlewares::middleware::{ use crate::evm::mutator::AccessPattern; use crate::evm::onchain::flashloan::register_borrow_txn; -use crate::evm::onchain::flashloan::{Flashloan, FlashloanData}; +use crate::evm::onchain::flashloan::Flashloan; use bytes::Bytes; use itertools::Itertools; use libafl::prelude::{HasCorpus, HasMetadata, HasRand, Scheduler}; use libafl::state::State; -use primitive_types::H256; -use revm::db::BenchmarkDB; -use revm_interpreter::InstructionResult::{Continue, ControlLeak, Return, Revert}; +use revm_interpreter::InstructionResult::{Continue, ControlLeak, Revert}; -use crate::evm::types::{ - as_u64, bytes_to_u64, generate_random_address, is_zero, EVMAddress, EVMU256, -}; -use hex::FromHex; +use crate::evm::types::{as_u64, generate_random_address, is_zero, EVMAddress, EVMU256}; use revm::precompile::{Precompile, Precompiles}; use revm_interpreter::analysis::to_analysed; use revm_interpreter::{ @@ -30,7 +24,6 @@ use std::cell::RefCell; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; use std::fmt::{Debug, Formatter}; -use std::fs::OpenOptions; use std::hash::Hash; use std::hash::Hasher; use std::io::Write; @@ -40,7 +33,6 @@ use std::str::FromStr; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; -use crate::evm::uniswap::{generate_uniswap_router_call, TokenContext}; use crate::evm::vm::{ EVMState, PostExecutionCtx, SinglePostExecution, IN_DEPLOY, IS_FAST_CALL_STATIC, }; @@ -51,7 +43,6 @@ use crate::input::VMInputT; use crate::evm::abi::{get_abi_type_boxed, register_abi_instance}; use crate::evm::contract_utils::extract_sig_from_contract; use crate::evm::corpus_initializer::ABIMap; -use crate::evm::input::EVMInputTy::ArbitraryCallBoundedAddr; use crate::evm::onchain::abi_decompiler::fetch_abi_heimdall; use crate::handle_contract_insertion; use crate::state::{HasCaller, HasCurrentInputIdx, HasHashToAddress, HasItyState}; @@ -94,7 +85,6 @@ const SCRIBBLE_EVENT_HEX: [u8; 32] = [ 0xb4, 0x26, 0x04, 0xcb, 0x10, 0x5a, 0x16, 0xc8, 0xf6, 0xdb, 0x8a, 0x41, 0xe6, 0xb0, 0x0c, 0x0c, 0x1b, 0x48, 0x26, 0x46, 0x5e, 0x8b, 0xc5, 0x04, 0xb3, 0xeb, 0x3e, 0x88, 0xb3, 0xe6, 0xa4, 0xa0, ]; -pub static mut CONCRETE_CREATE: bool = false; /// Check if address is precompile by having assumption /// that precompiles are in range of 1 to N. @@ -237,7 +227,7 @@ where current_typed_bug: self.current_typed_bug.clone(), randomness: vec![], work_dir: self.work_dir.clone(), - spec_id: self.spec_id.clone(), + spec_id: self.spec_id, precompiles: Precompiles::default(), leak_ctx: self.leak_ctx.clone(), mapping_sstore_pcs: self.mapping_sstore_pcs.clone(), @@ -271,7 +261,8 @@ where VS: VMStateT, { pub fn new(scheduler: Arc>, workdir: String) -> Self { - let ret = Self { + // ret.env.block.timestamp = EVMU256::max_value(); + Self { evmstate: EVMState::new(), env: Env::default(), code: HashMap::new(), @@ -300,16 +291,14 @@ where relations_hash: HashSet::new(), current_typed_bug: Default::default(), randomness: vec![], - work_dir: workdir.clone(), + work_dir: workdir, spec_id: SpecId::LATEST, precompiles: Default::default(), leak_ctx: vec![], mapping_sstore_pcs: Default::default(), mapping_sstore_pcs_to_slot: Default::default(), jumpi_trace: 37, - }; - // ret.env.block.timestamp = EVMU256::max_value(); - ret + } } pub fn set_spec_id(&mut self, spec_id: String) { @@ -317,11 +306,7 @@ where } /// custom spec id run_inspect - pub fn run_inspect( - &mut self, - mut interp: &mut Interpreter, - mut state: &mut S, - ) -> InstructionResult { + pub fn run_inspect(&mut self, interp: &mut Interpreter, state: &mut S) -> InstructionResult { match self.spec_id { SpecId::LATEST => interp.run_inspect::, LatestSpec>(self, state), SpecId::FRONTIER => { @@ -364,7 +349,7 @@ where pub fn add_middlewares(&mut self, middlewares: Rc>>) { self.middlewares_enabled = true; - let ty = middlewares.deref().borrow().get_type(); + // let ty = middlewares.deref().borrow().get_type(); self.middlewares.deref().borrow_mut().push(middlewares); } @@ -443,7 +428,7 @@ where } } - pub fn set_codedata(&mut self, address: EVMAddress, mut code: Bytecode) { + pub fn set_codedata(&mut self, address: EVMAddress, code: Bytecode) { self.setcode_data.insert(address, code); } @@ -454,13 +439,11 @@ where pub fn set_code(&mut self, address: EVMAddress, mut code: Bytecode, state: &mut S) { unsafe { if self.middlewares_enabled { - match self.flashloan_middleware.clone() { - Some(m) => { - let mut middleware = m.deref().borrow_mut(); - middleware.on_insert(&mut code, address, self, state); - } - _ => {} + if let Some(m) = self.flashloan_middleware.clone() { + let mut middleware = m.deref().borrow_mut(); + middleware.on_insert(&mut code, address, self, state); } + for middleware in &mut self.middlewares.clone().deref().borrow_mut().iter_mut() { middleware .deref() @@ -478,11 +461,11 @@ where pub fn find_static_call_read_slot( &self, - address: EVMAddress, - data: Bytes, - state: &mut S, + _address: EVMAddress, + _data: Bytes, + _state: &mut S, ) -> Vec { - return vec![]; + vec![] // let call = Contract::new_with_context_not_cloned::( // data, // self.code.get(&address).expect("no code").clone(), @@ -519,8 +502,8 @@ where if self.relations_hash.contains(&cur_wirte_hash) { return; } - if self.relations_hash.len() == 0 { - let write_head = format!("[ityfuzz relations] caller, traget, function hash\n"); + if self.relations_hash.is_empty() { + let write_head = "[ityfuzz relations] caller, traget, function hash\n".to_string(); self.relations_file .write_all(write_head.as_bytes()) .unwrap(); @@ -540,14 +523,12 @@ where state: &mut S, ) -> (InstructionResult, Gas, Bytes) { macro_rules! push_interp { - () => { - unsafe { - self.leak_ctx = vec![SinglePostExecution::from_interp( - interp, - (out_offset, out_len), - )]; - } - }; + () => {{ + self.leak_ctx = vec![SinglePostExecution::from_interp( + interp, + (out_offset, out_len), + )]; + }}; } self.call_count += 1; if self.call_count >= unsafe { CALL_UNTIL } { @@ -556,11 +537,7 @@ where } if unsafe { WRITE_RELATIONSHIPS } { - self.write_relations( - input.transfer.source.clone(), - input.contract.clone(), - input.input.clone(), - ); + self.write_relations(input.transfer.source, input.contract, input.input.clone()); } let mut hash = input.input.to_vec(); @@ -595,11 +572,11 @@ where } self.middlewares_latent_call_actions.clear(); - if middleware_result.is_some() { - return middleware_result.unwrap(); + if let Some(m) = middleware_result { + return m; } - let mut input_seq = input.input.to_vec(); + let input_seq = input.input.to_vec(); if input.context.scheme == CallScheme::Call { // if calling sender, then definitely control leak @@ -610,13 +587,9 @@ where return (ControlLeak, Gas::new(0), Bytes::new()); } // check whether the whole CALLDATAVALUE can be arbitrary - if !self - .pc_to_call_hash - .contains_key(&(input.context.caller, self._pc, self.jumpi_trace)) - { - self.pc_to_call_hash - .insert((input.context.caller, self._pc, self.jumpi_trace), HashSet::new()); - } + self.pc_to_call_hash + .entry((input.context.caller, self._pc, self.jumpi_trace)) + .or_insert_with(HashSet::new); self.pc_to_call_hash .get_mut(&(input.context.caller, self._pc, self.jumpi_trace)) .unwrap() @@ -629,16 +602,18 @@ where > UNBOUND_CALL_THRESHOLD && input_seq.len() >= 4 { - self.current_arbitrary_calls.push( - (input.context.caller, input.context.address, interp.program_counter()), - ); + self.current_arbitrary_calls.push(( + input.context.caller, + input.context.address, + interp.program_counter(), + )); // println!("ub leak {:?} -> {:?} with {:?} {}", input.context.caller, input.contract, hex::encode(input.input.clone()), self.jumpi_trace); push_interp!(); return ( InstructionResult::ArbitraryExternalCallAddressBounded( input.context.caller, input.context.address, - input.transfer.value + input.transfer.value, ), Gas::new(0), Bytes::new(), @@ -647,13 +622,9 @@ where // control leak check assert_ne!(self._pc, 0); - if !self - .pc_to_addresses - .contains_key(&(input.context.caller, self._pc)) - { - self.pc_to_addresses - .insert((input.context.caller, self._pc), HashSet::new()); - } + self.pc_to_addresses + .entry((input.context.caller, self._pc)) + .or_insert_with(HashSet::new); let addresses_at_pc = self .pc_to_addresses .get_mut(&(input.context.caller, self._pc)) @@ -661,13 +632,11 @@ where addresses_at_pc.insert(input.contract); // if control leak is enabled, return controlleak if it is unbounded call - if CONTROL_LEAK_DETECTION == true { - if addresses_at_pc.len() > CONTROL_LEAK_THRESHOLD { - record_func_hash!(); - push_interp!(); - // println!("control leak {:?} -> {:?} with {:?}", input.context.caller, input.contract, hex::encode(input.input.clone())); - return (ControlLeak, Gas::new(0), Bytes::new()); - } + if CONTROL_LEAK_DETECTION && addresses_at_pc.len() > CONTROL_LEAK_THRESHOLD { + record_func_hash!(); + push_interp!(); + // println!("control leak {:?} -> {:?} with {:?}", input.context.caller, input.contract, hex::encode(input.input.clone())); + return (ControlLeak, Gas::new(0), Bytes::new()); } } @@ -675,41 +644,40 @@ where // find contracts that have this function hash let contract_loc_option = self.hash_to_address.get(hash.as_slice()); - if unsafe { ACTIVE_MATCH_EXT_CALL } && contract_loc_option.is_some() { - let loc = contract_loc_option.unwrap(); - // if there is such a location known, then we can use exact call - if !loc.contains(&input.contract) { - // todo(@shou): resolve multi locs - if loc.len() != 1 { - panic!("more than one contract found for the same hash"); + if unsafe { ACTIVE_MATCH_EXT_CALL } { + if let Some(loc) = contract_loc_option { + // if there is such a location known, then we can use exact call + if !loc.contains(&input.contract) { + // todo(@shou): resolve multi locs + if loc.len() != 1 { + panic!("more than one contract found for the same hash"); + } + let mut interp = Interpreter::new_with_memory_limit( + Contract::new_with_context_analyzed( + input_bytes, + self.code.get(loc.iter().next().unwrap()).unwrap().clone(), + &input.context, + ), + 1e10 as u64, + false, + MEM_LIMIT, + ); + + let ret = self.run_inspect(&mut interp, state); + return (ret, Gas::new(0), interp.return_value()); } - let mut interp = Interpreter::new_with_memory_limit( - Contract::new_with_context_analyzed( - input_bytes, - self.code.get(loc.iter().nth(0).unwrap()).unwrap().clone(), - &input.context, - ), - 1e10 as u64, - false, - MEM_LIMIT, - ); - - let ret = self.run_inspect(&mut interp, state); - return (ret, Gas::new(0), interp.return_value()); } } // if there is code, then call the code let res = self.call_forbid_control_leak(input, state); match res.0 { - ControlLeak | InstructionResult::ArbitraryExternalCallAddressBounded(_, _, _) => unsafe { - unsafe { - self.leak_ctx.push(SinglePostExecution::from_interp( - interp, - (out_offset, out_len), - )); - } - }, + ControlLeak | InstructionResult::ArbitraryExternalCallAddressBounded(_, _, _) => { + self.leak_ctx.push(SinglePostExecution::from_interp( + interp, + (out_offset, out_len), + )); + } _ => {} } res @@ -742,25 +710,25 @@ where if hash == [0x00, 0x00, 0x00, 0x00] { return (Continue, Gas::new(0), Bytes::new()); } - return (Revert, Gas::new(0), Bytes::new()); + (Revert, Gas::new(0), Bytes::new()) } fn call_precompile( &mut self, input: &mut CallInputs, - state: &mut S, + _state: &mut S, ) -> (InstructionResult, Gas, Bytes) { let precompile = self .precompiles .get(&input.contract) .expect("Check for precompile should be already done"); let out = match precompile { - Precompile::Standard(fun) => fun(&input.input.to_vec().as_slice(), u64::MAX), - Precompile::Custom(fun) => fun(&input.input.to_vec().as_slice(), u64::MAX), + Precompile::Standard(fun) => fun(input.input.to_vec().as_slice(), u64::MAX), + Precompile::Custom(fun) => fun(input.input.to_vec().as_slice(), u64::MAX), }; match out { Ok((_, data)) => (InstructionResult::Return, Gas::new(0), Bytes::from(data)), - Err(e) => ( + Err(_) => ( InstructionResult::PrecompileError, Gas::new(0), Bytes::new(), @@ -863,6 +831,8 @@ where { fn step(&mut self, interp: &mut Interpreter, state: &mut S) -> InstructionResult { unsafe { + // println!("pc: {}", interp.program_counter()); + // println!("{:?}", *interp.instruction_pointer); invoke_middlewares!(self, interp, state, on_step); if IS_FAST_CALL_STATIC { return Continue; @@ -877,6 +847,10 @@ where // 0xfd => { // println!("fd {} @ {:?}", interp.program_counter(), interp.contract.address); // } + // 0x31 | 0x47 => { + // println!("host setp balance"); + // std::thread::sleep(std::time::Duration::from_secs(3)); + // } 0x57 => { // JUMPI counter cond let br = fast_peek!(1); @@ -893,9 +867,7 @@ where if JMP_MAP[idx] == 0 { self.coverage_changed = true; } - if JMP_MAP[idx] < 255 { - JMP_MAP[idx] += 1; - } + JMP_MAP[idx] = JMP_MAP[idx].saturating_add(1); #[cfg(feature = "cmp")] { @@ -1011,7 +983,7 @@ where 0xf4 | 0xfa => 5, _ => unreachable!(), }; - unsafe { + { RET_OFFSET = as_u64(fast_peek!(offset_of_ret_size - 1)) as usize; // println!("RET_OFFSET: {}", RET_OFFSET); RET_SIZE = as_u64(fast_peek!(offset_of_ret_size)) as usize; @@ -1030,7 +1002,7 @@ where .borrow_mut() .decode_instruction(interp); } - return Continue; + Continue } fn step_end( @@ -1039,11 +1011,11 @@ where _ret: InstructionResult, _: &mut S, ) -> InstructionResult { - return Continue; + Continue } fn env(&mut self) -> &mut Env { - return &mut self.env; + &mut self.env } fn load_account(&mut self, _address: EVMAddress) -> Option<(bool, bool)> { @@ -1054,16 +1026,22 @@ where } fn block_hash(&mut self, _number: EVMU256) -> Option { - Some( - B256::from_str("0x0000000000000000000000000000000000000000000000000000000000000000") - .unwrap(), - ) + Some(B256::zero()) } - fn balance(&mut self, _address: EVMAddress) -> Option<(EVMU256, bool)> { - // println!("balance"); - - Some((EVMU256::MAX, true)) + fn balance(&mut self, address: EVMAddress) -> Option<(EVMU256, bool)> { + #[cfg(feature = "real_balance")] + { + if let Some(balance) = self.evmstate.get_balance(&address) { + return Some((*balance, true)); + } + self.evmstate.set_balance(address, self.next_slot); + Some((self.next_slot, true)) + } + #[cfg(not(feature = "real_balance"))] + { + Some((EVMU256::MAX, true)) + } } fn code(&mut self, address: EVMAddress) -> Option<(Arc, bool)> { @@ -1085,14 +1063,10 @@ where fn sload(&mut self, address: EVMAddress, index: EVMU256) -> Option<(EVMU256, bool)> { if let Some(account) = self.evmstate.get(&address) { if let Some(slot) = account.get(&index) { - return Some((slot.clone(), true)); + return Some((*slot, true)); } } Some((self.next_slot, true)) - // match self.data.get(&address) { - // Some(account) => Some((account.get(&index).unwrap_or(&EVMU256::zero()).clone(), true)), - // None => Some((EVMU256::zero(), true)), - // } } fn sstore( @@ -1118,8 +1092,8 @@ where fn log(&mut self, _address: EVMAddress, _topics: Vec, _data: Bytes) { // flag check if _topics.len() == 1 { - let current_flag = (*_topics.last().unwrap()).0; - /// hex is "fuzzland" + let current_flag = _topics.last().unwrap().0; + // hex is "fuzzland" if current_flag[0] == 0x66 && current_flag[1] == 0x75 && current_flag[2] == 0x7a @@ -1137,7 +1111,7 @@ where panic!("target bug found: {}", data_string); } self.current_typed_bug.push(( - data_string.clone().trim_end_matches("\u{0}").to_string(), + data_string.trim_end_matches('\u{0}').to_string(), (_address, self._pc), )); } @@ -1166,7 +1140,7 @@ where _target: EVMAddress, ) -> Option { self.current_self_destructs.push((_address, self._pc)); - return Some(SelfDestructResult::default()); + Some(SelfDestructResult::default()) } fn create( @@ -1174,114 +1148,112 @@ where inputs: &mut CreateInputs, state: &mut S, ) -> (InstructionResult, Option, Gas, Bytes) { - unsafe { - if unsafe { CONCRETE_CREATE || IN_DEPLOY } { - // todo: use nonce + hash instead - let r_addr = generate_random_address(state); - let mut interp = Interpreter::new_with_memory_limit( - Contract::new_with_context( - Bytes::new(), - Bytecode::new_raw(inputs.init_code.clone()), - &CallContext { - address: r_addr, - caller: inputs.caller, - code_address: r_addr, - apparent_value: inputs.value, - scheme: CallScheme::Call, - }, - ), - 1e10 as u64, - false, - MEM_LIMIT, - ); - let ret = self.run_inspect(&mut interp, state); - if ret == InstructionResult::Continue { - let runtime_code = interp.return_value(); - self.set_code(r_addr, Bytecode::new_raw(runtime_code.clone()), state); - { - // now we build & insert abi - let contract_code_str = hex::encode(runtime_code.clone()); - let sigs = extract_sig_from_contract(&contract_code_str); - let mut unknown_sigs: usize = 0; - let mut parsed_abi = vec![]; - for sig in &sigs { - if let Some(abi) = state.metadata().get::().unwrap().get(sig) { - parsed_abi.push(abi.clone()); - } else { - unknown_sigs += 1; - } - } - - if unknown_sigs >= sigs.len() / 30 { - println!("Too many unknown function signature for newly created contract, we are going to decompile this contract using Heimdall"); - let abis = fetch_abi_heimdall(contract_code_str) - .iter() - .map(|abi| { - if let Some(known_abi) = - state.metadata().get::().unwrap().get(&abi.function) - { - known_abi - } else { - abi - } - }) - .cloned() - .collect_vec(); - parsed_abi = abis; - } - // notify flashloan and blacklisting flashloan addresses - #[cfg(feature = "flashloan_v2")] - { - handle_contract_insertion!(state, self, r_addr, parsed_abi); + if unsafe { IN_DEPLOY } { + // todo: use nonce + hash instead + let r_addr = generate_random_address(state); + let mut interp = Interpreter::new_with_memory_limit( + Contract::new_with_context( + Bytes::new(), + Bytecode::new_raw(inputs.init_code.clone()), + &CallContext { + address: r_addr, + caller: inputs.caller, + code_address: r_addr, + apparent_value: inputs.value, + scheme: CallScheme::Call, + }, + ), + 1e10 as u64, + false, + MEM_LIMIT, + ); + let ret = self.run_inspect(&mut interp, state); + if ret == InstructionResult::Continue { + let runtime_code = interp.return_value(); + self.set_code(r_addr, Bytecode::new_raw(runtime_code.clone()), state); + { + // now we build & insert abi + let contract_code_str = hex::encode(runtime_code.clone()); + let sigs = extract_sig_from_contract(&contract_code_str); + let mut unknown_sigs: usize = 0; + let mut parsed_abi = vec![]; + for sig in &sigs { + if let Some(abi) = state.metadata().get::().unwrap().get(sig) { + parsed_abi.push(abi.clone()); + } else { + unknown_sigs += 1; } + } - parsed_abi + if unknown_sigs >= sigs.len() / 30 { + println!("Too many unknown function signature for newly created contract, we are going to decompile this contract using Heimdall"); + let abis = fetch_abi_heimdall(contract_code_str) .iter() - .filter(|v| !v.is_constructor) - .for_each(|abi| { - #[cfg(not(feature = "fuzz_static"))] - if abi.is_static { - return; + .map(|abi| { + if let Some(known_abi) = + state.metadata().get::().unwrap().get(&abi.function) + { + known_abi + } else { + abi } - - let mut abi_instance = get_abi_type_boxed(&abi.abi); - abi_instance - .set_func_with_name(abi.function, abi.function_name.clone()); - register_abi_instance(r_addr, abi_instance.clone(), state); - - let input = EVMInput { - caller: state.get_rand_caller(), - contract: r_addr, - data: Some(abi_instance), - sstate: StagedVMState::new_uninitialized(), - sstate_idx: 0, - txn_value: if abi.is_payable { - Some(EVMU256::ZERO) - } else { - None - }, - step: false, - - env: Default::default(), - access_pattern: Rc::new(RefCell::new(AccessPattern::new())), - #[cfg(feature = "flashloan_v2")] - liquidation_percent: 0, - #[cfg(feature = "flashloan_v2")] - input_type: EVMInputTy::ABI, - direct_data: Default::default(), - randomness: vec![0], - repeat: 1, - }; - add_corpus(self, state, &input); - }); + }) + .cloned() + .collect_vec(); + parsed_abi = abis; + } + // notify flashloan and blacklisting flashloan addresses + #[cfg(feature = "flashloan_v2")] + { + handle_contract_insertion!(state, self, r_addr, parsed_abi); } - (Continue, Some(r_addr), Gas::new(0), runtime_code) - } else { - (ret, Some(r_addr), Gas::new(0), Bytes::new()) + + parsed_abi + .iter() + .filter(|v| !v.is_constructor) + .for_each(|abi| { + #[cfg(not(feature = "fuzz_static"))] + if abi.is_static { + return; + } + + let mut abi_instance = get_abi_type_boxed(&abi.abi); + abi_instance + .set_func_with_name(abi.function, abi.function_name.clone()); + register_abi_instance(r_addr, abi_instance.clone(), state); + + let input = EVMInput { + caller: state.get_rand_caller(), + contract: r_addr, + data: Some(abi_instance), + sstate: StagedVMState::new_uninitialized(), + sstate_idx: 0, + txn_value: if abi.is_payable { + Some(EVMU256::ZERO) + } else { + None + }, + step: false, + + env: Default::default(), + access_pattern: Rc::new(RefCell::new(AccessPattern::new())), + #[cfg(feature = "flashloan_v2")] + liquidation_percent: 0, + #[cfg(feature = "flashloan_v2")] + input_type: EVMInputTy::ABI, + direct_data: Default::default(), + randomness: vec![0], + repeat: 1, + }; + add_corpus(self, state, &input); + }); } + (Continue, Some(r_addr), Gas::new(0), runtime_code) } else { - (InstructionResult::Revert, None, Gas::new(0), Bytes::new()) + (ret, Some(r_addr), Gas::new(0), Bytes::new()) } + } else { + (InstructionResult::Revert, None, Gas::new(0), Bytes::new()) } } @@ -1292,27 +1264,49 @@ where output_info: (usize, usize), state: &mut S, ) -> (InstructionResult, Gas, Bytes) { + let value = EVMU256::from(input.transfer.value); + if cfg!(feature = "real_balance") && value != EVMU256::ZERO { + let sender = input.transfer.source; + println!("call sender: {:?}", sender); + let current = if let Some(balance) = self.evmstate.get_balance(&sender) { + *balance + } else { + self.evmstate.set_balance(sender, self.next_slot); + self.next_slot + }; + // println!("call sender balance: {}", current); + if current < value { + return (Revert, Gas::new(0), Bytes::new()); + } + self.evmstate.set_balance(sender, current - value); + + let receiver = input.transfer.target; + if let Some(balance) = self.evmstate.get_balance(&receiver) { + self.evmstate.set_balance(receiver, *balance + value); + } else { + self.evmstate.set_balance(receiver, self.next_slot + value); + }; + } + let res = if is_precompile(input.contract, self.precompiles.len()) { self.call_precompile(input, state) + } else if unsafe { IS_FAST_CALL_STATIC } { + self.call_forbid_control_leak(input, state) } else { - if unsafe { IS_FAST_CALL_STATIC } { - self.call_forbid_control_leak(input, state) - } else { - self.call_allow_control_leak(input, interp, output_info, state) - } + self.call_allow_control_leak(input, interp, output_info, state) }; let ret_buffer = res.2.clone(); unsafe { if self.middlewares_enabled { - for middleware in &mut self.middlewares.clone().deref().borrow_mut().iter_mut() - { - middleware - .deref() - .deref() - .borrow_mut() - .on_return(interp, self, state, &ret_buffer); + for middleware in &mut self.middlewares.clone().deref().borrow_mut().iter_mut() { + middleware.deref().deref().borrow_mut().on_return( + interp, + self, + state, + &ret_buffer, + ); } } } diff --git a/src/evm/middlewares/middleware.rs b/src/evm/middlewares/middleware.rs index 2c9b40f28..3d43d5116 100644 --- a/src/evm/middlewares/middleware.rs +++ b/src/evm/middlewares/middleware.rs @@ -7,7 +7,6 @@ use crate::state::{HasCaller, HasItyState}; use bytes::Bytes; use libafl::corpus::{Corpus, Testcase}; use libafl::inputs::Input; -use libafl::schedulers::Scheduler; use libafl::state::{HasCorpus, HasMetadata, State}; use primitive_types::U512; use serde::{Deserialize, Serialize}; @@ -15,10 +14,10 @@ use serde::{Deserialize, Serialize}; use std::clone::Clone; use std::fmt::Debug; -use std::time::Duration; +use crate::evm::types::{EVMAddress, EVMU256}; use revm_interpreter::Interpreter; use revm_primitives::Bytecode; -use crate::evm::types::{EVMAddress, EVMU256}; +use std::time::Duration; #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Copy)] pub enum MiddlewareType { @@ -99,13 +98,16 @@ where interp: &mut Interpreter, host: &mut FuzzHost, state: &mut S, - ret: &Bytes - ) {} + ret: &Bytes, + ) { + } - unsafe fn on_insert(&mut self, - bytecode: &mut Bytecode, - address: EVMAddress, - host: &mut FuzzHost, - state: &mut S); + unsafe fn on_insert( + &mut self, + bytecode: &mut Bytecode, + address: EVMAddress, + host: &mut FuzzHost, + state: &mut S, + ); fn get_type(&self) -> MiddlewareType; } diff --git a/src/evm/onchain/endpoints.rs b/src/evm/onchain/endpoints.rs index 11603d83b..f90d83368 100644 --- a/src/evm/onchain/endpoints.rs +++ b/src/evm/onchain/endpoints.rs @@ -222,10 +222,6 @@ pub struct GetPairResponseDataPairToken { #[derive(Clone, Debug, Default)] pub struct OnChainConfig { pub endpoint_url: String, - // pub cache_len: usize, - // - // code_cache: HashMap, - // slot_cache: HashMap<(EVMAddress, EVMU256), EVMU256>, pub client: reqwest::blocking::Client, pub chain_id: u32, pub block_number: String, @@ -236,6 +232,7 @@ pub struct OnChainConfig { pub chain_name: String, + balance_cache: HashMap, pair_cache: HashMap>, slot_cache: HashMap<(EVMAddress, EVMU256), EVMU256>, code_cache: HashMap, @@ -623,6 +620,34 @@ impl OnChainConfig { } } + pub fn get_balance(&mut self, address: EVMAddress) -> EVMU256 { + if self.balance_cache.contains_key(&address) { + return self.balance_cache[&address]; + } + + let resp_string = { + let mut params = String::from("["); + params.push_str(&format!("\"0x{:x}\",", address)); + params.push_str(&format!("\"{}\"", self.block_number)); + params.push(']'); + let resp = self._request("eth_getBalance".to_string(), params); + match resp { + Some(resp) => { + let balance = resp.as_str().unwrap(); + balance.to_string() + } + None => "".to_string(), + } + }; + let balance = EVMU256::from_str(&resp_string).unwrap(); + println!( + "balance of {address:?} at {} is {balance}", + self.block_number + ); + self.balance_cache.insert(address, balance); + balance + } + pub fn get_contract_code(&mut self, address: EVMAddress, force_cache: bool) -> Bytecode { if self.code_cache.contains_key(&address) { return self.code_cache[&address].clone(); @@ -1151,6 +1176,7 @@ fn get_header() -> HeaderMap { mod tests { use super::*; use crate::evm::onchain::endpoints::Chain::{BSC, ETH}; + use crate::evm::types::EVMAddress; #[test] fn test_onchain_config() { @@ -1240,6 +1266,16 @@ mod tests { assert!(!v.address.is_zero()); } + #[test] + fn test_get_balance() { + let mut config = OnChainConfig::new(ETH, 18168677); + let v = config.get_balance( + EVMAddress::from_str("0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326").unwrap(), + ); + println!("{:?}", v); + assert!(v == EVMU256::from(439351222497229612i64)); + } + // #[test] // fn test_fetch_token_price() { // let mut config = OnChainConfig::new(BSC, 0); diff --git a/src/evm/onchain/onchain.rs b/src/evm/onchain/onchain.rs index b6f261246..a71241e05 100644 --- a/src/evm/onchain/onchain.rs +++ b/src/evm/onchain/onchain.rs @@ -1,7 +1,7 @@ use crate::evm::abi::{get_abi_type_boxed, register_abi_instance}; use crate::evm::bytecode_analyzer; use crate::evm::config::StorageFetchingMode; -use crate::evm::contract_utils::{ABIConfig, ContractLoader, extract_sig_from_contract}; +use crate::evm::contract_utils::{extract_sig_from_contract, ABIConfig, ContractLoader}; use crate::evm::input::{ConciseEVMInput, EVMInput, EVMInputT, EVMInputTy}; use crate::evm::host::FuzzHost; @@ -22,23 +22,21 @@ use libafl::prelude::{HasCorpus, HasMetadata, Input}; use libafl::state::{HasRand, State}; - use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Debug, Formatter}; use std::ops::Deref; +use crate::evm::blaz::builder::{ArtifactInfoMetadata, BuildJob}; +use crate::evm::corpus_initializer::ABIMap; use crate::evm::onchain::flashloan::register_borrow_txn; -use std::rc::Rc; -use std::str::FromStr; -use std::sync::Arc; -use bytes::Bytes; +use crate::evm::types::{convert_u256_to_h160, EVMAddress, EVMU256}; use itertools::Itertools; use revm_interpreter::Interpreter; use revm_primitives::Bytecode; -use crate::evm::blaz::builder::{ArtifactInfoMetadata, BuildJob}; -use crate::evm::corpus_initializer::ABIMap; -use crate::evm::types::{convert_u256_to_h160, EVMAddress, EVMU256}; +use std::rc::Rc; +use std::str::FromStr; +use std::sync::Arc; pub static mut BLACKLIST_ADDR: Option> = None; pub static mut WHITELIST_ADDR: Option> = None; @@ -145,17 +143,17 @@ where pub fn keccak_hex(data: EVMU256) -> String { let mut hasher = Sha3::keccak256(); let mut output = [0u8; 32]; - let mut input: [u8; 32] = data.to_be_bytes(); + let input: [u8; 32] = data.to_be_bytes(); hasher.input(input.as_ref()); hasher.result(&mut output); - hex::encode(&output).to_string() + hex::encode(output) } impl Middleware for OnChain where I: Input + VMInputT + EVMInputT + 'static, S: State - +HasRand + + HasRand + Debug + HasCaller + HasCorpus @@ -171,10 +169,10 @@ where host: &mut FuzzHost, state: &mut S, ) { - let pc = interp.program_counter(); #[cfg(feature = "force_cache")] macro_rules! force_cache { - ($ty: expr, $target: expr) => { + ($ty: expr, $target: expr) => {{ + let pc = interp.program_counter(); match $ty.get_mut(&(interp.contract.address, pc)) { None => { $ty.insert((interp.contract.address, pc), HashSet::from([$target])); @@ -189,7 +187,7 @@ where } } } - }; + }}; } #[cfg(not(feature = "force_cache"))] macro_rules! force_cache { @@ -199,6 +197,7 @@ where } match *interp.instruction_pointer { + // SLOAD 0x54 => { let address = interp.contract.address; let slot_idx = interp.stack.peek(0).unwrap(); @@ -206,9 +205,8 @@ where macro_rules! load_data { ($func: ident, $stor: ident, $key: ident) => {{ if !self.$stor.contains_key(&address) { - let storage = self.endpoint.$func(address); - if storage.is_some() { - self.$stor.insert(address, storage.unwrap()); + if let Some(storage) = self.endpoint.$func(address) { + self.$stor.insert(address, storage); } } match self.$stor.get(&address) { @@ -222,50 +220,55 @@ where }}; () => {}; } - macro_rules! slot_val { - () => {{ - match self.storage_fetching { - StorageFetchingMode::Dump => { - load_data!(fetch_storage_dump, storage_dump, slot_idx) - } - StorageFetchingMode::All => { - // the key is in keccak256 format - let key = keccak_hex(slot_idx); - load_data!(fetch_storage_all, storage_all, key) - } - StorageFetchingMode::OneByOne => self.endpoint.get_contract_slot( - address, - slot_idx, - force_cache!(self.locs, slot_idx), - ), - } - }}; - } - // - // match host.data.get_mut(&address) { - // Some(data) => { - // if data.get(&slot_idx).is_none() { - // data.insert(slot_idx, slot_val!()); - // } - // } - // None => { - // let mut data = HashMap::new(); - // data.insert(slot_idx, slot_val!()); - // host.data.insert(address, data); - // } - // } - - host.next_slot = slot_val!(); + host.next_slot = match self.storage_fetching { + StorageFetchingMode::Dump => { + load_data!(fetch_storage_dump, storage_dump, slot_idx) + } + StorageFetchingMode::All => { + // the key is in keccak256 format + let key = keccak_hex(slot_idx); + load_data!(fetch_storage_all, storage_all, key) + } + StorageFetchingMode::OneByOne => self.endpoint.get_contract_slot( + address, + slot_idx, + force_cache!(self.locs, slot_idx), + ), + }; } - + // BALANCE + #[cfg(feature = "real_balance")] + 0x31 => { + let address = convert_u256_to_h160(interp.stack.peek(0).unwrap()); + println!("onchain balance for {:?}", address); + // std::thread::sleep(std::time::Duration::from_secs(3)); + host.next_slot = self.endpoint.get_balance(address); + } + #[cfg(feature = "real_balance")] + // SELFBALANCE + 0x47 => { + let address = interp.contract.address; + println!("onchain selfbalance for {:?}", address); + // std::thread::sleep(std::time::Duration::from_secs(3)); + host.next_slot = self.endpoint.get_balance(address); + } + // CALL | CALLCODE | DELEGATECALL | STATICCALL | EXTCODESIZE | EXTCODECOPY 0xf1 | 0xf2 | 0xf4 | 0xfa | 0x3b | 0x3c => { let caller = interp.contract.address; let address = match *interp.instruction_pointer { - 0xf1 | 0xf2 | 0xf4 | 0xfa => interp.stack.peek(1).unwrap(), - 0x3b | 0x3c => interp.stack.peek(0).unwrap(), - _ => { - unreachable!() + 0xf1 | 0xf2 => { + // CALL | CALLCODE + #[cfg(feature = "real_balance")] + { + // Get balance of the callee + host.next_slot = self.endpoint.get_balance(caller); + } + + interp.stack.peek(1).unwrap() } + 0xf4 | 0xfa => interp.stack.peek(1).unwrap(), + 0x3b | 0x3c => interp.stack.peek(0).unwrap(), + _ => unreachable!(), }; let address_h160 = convert_u256_to_h160(address); if self.loaded_abi.contains(&address_h160) { @@ -278,40 +281,44 @@ where self.loaded_abi.insert(address_h160); return; } - if !self.loaded_code.contains(&address_h160) && !host.code.contains_key(&address_h160) { + if !self.loaded_code.contains(&address_h160) + && !host.code.contains_key(&address_h160) + { bytecode_analyzer::add_analysis_result_to_state(&contract_code, state); host.set_codedata(address_h160, contract_code.clone()); - println!("fetching code from {:?} due to call by {:?}", - address_h160, caller); + println!( + "fetching code from {:?} due to call by {:?}", + address_h160, caller + ); } - if unsafe { IS_FAST_CALL } || self.blacklist.contains(&address_h160) || - *interp.instruction_pointer == 0x3b || - *interp.instruction_pointer == 0x3c { + if unsafe { IS_FAST_CALL } + || self.blacklist.contains(&address_h160) + || *interp.instruction_pointer == 0x3b + || *interp.instruction_pointer == 0x3c + { return; } // setup abi self.loaded_abi.insert(address_h160); - let is_proxy_call = match *interp.instruction_pointer { - 0xf2 | 0xf4 => true, - _ => false, - }; + let is_proxy_call = matches!(*interp.instruction_pointer, 0xf2 | 0xf4); let mut abi = None; if let Some(builder) = &self.builder { println!("onchain job {:?}", address_h160); - let build_job = builder.onchain_job( - self.endpoint.chain_name.clone(), - address_h160, - ); + let build_job = + builder.onchain_job(self.endpoint.chain_name.clone(), address_h160); if let Some(job) = build_job { abi = Some(job.abi.clone()); // replace the code with the one from builder // println!("replace code for {:?} with builder's", address_h160); // host.set_codedata(address_h160, contract_code.clone()); - state.metadata_mut().get_mut::() - .expect("artifact info metadata").add(address_h160, job); + state + .metadata_mut() + .get_mut::() + .expect("artifact info metadata") + .add(address_h160, job); } } @@ -322,9 +329,7 @@ where let mut parsed_abi = vec![]; match abi { - Some(ref abi_ins) => { - parsed_abi = ContractLoader::parse_abi_str(abi_ins) - } + Some(ref abi_ins) => parsed_abi = ContractLoader::parse_abi_str(abi_ins), None => { // 1. Extract abi from bytecode, and see do we have any function sig available in state // 2. Use Heimdall to extract abi @@ -346,7 +351,9 @@ where let abis = fetch_abi_heimdall(contract_code_str) .iter() .map(|abi| { - if let Some(known_abi) = state.metadata().get::().unwrap().get(&abi.function) { + if let Some(known_abi) = + state.metadata().get::().unwrap().get(&abi.function) + { known_abi } else { abi @@ -365,64 +372,65 @@ where // check caller's hash and see what is missing let caller_hashes = match host.address_to_hash.get(&caller) { Some(v) => v.clone(), - None => vec![] + None => vec![], }; let caller_hashes_set = caller_hashes.iter().cloned().collect::>(); - let new_hashes = parsed_abi.iter().map(|abi| abi.function).collect::>(); + let new_hashes = parsed_abi + .iter() + .map(|abi| abi.function) + .collect::>(); for hash in new_hashes { if !caller_hashes_set.contains(&hash) { abi_hashes_to_add.insert(hash); host.add_one_hashes(caller, hash); } } - println!("Propagating hashes {:?} for proxy {:?}", - abi_hashes_to_add - .iter() - .map(|x| hex::encode(x)) - .collect::>(), - caller + println!( + "Propagating hashes {:?} for proxy {:?}", + abi_hashes_to_add + .iter() + .map(hex::encode) + .collect::>(), + caller ); - } else { - abi_hashes_to_add = parsed_abi.iter().map(|abi| abi.function).collect::>(); + abi_hashes_to_add = parsed_abi + .iter() + .map(|abi| abi.function) + .collect::>(); host.add_hashes( address_h160, parsed_abi.iter().map(|abi| abi.function).collect(), ); } - let target = if is_proxy_call { - caller - } else { - address_h160 - }; + let target = if is_proxy_call { caller } else { address_h160 }; state.add_address(&target); // notify flashloan and blacklisting flashloan addresses #[cfg(feature = "flashloan_v2")] { - handle_contract_insertion!(state, host, target, - parsed_abi.iter().filter( - |x| abi_hashes_to_add.contains(&x.function) - ).cloned().collect::>() + handle_contract_insertion!( + state, + host, + target, + parsed_abi + .iter() + .filter(|x| abi_hashes_to_add.contains(&x.function)) + .cloned() + .collect::>() ); } // add abi to corpus - - unsafe { - match WHITELIST_ADDR.as_ref() { - Some(whitelist) => { - if !whitelist.contains(&target) { - return; - } - } - None => {} + if let Some(whitelist) = unsafe { WHITELIST_ADDR.as_ref() } { + if !whitelist.contains(&target) { + return; } } parsed_abi .iter() .filter(|v| !v.is_constructor) - .filter( |v| abi_hashes_to_add.contains(&v.function)) + .filter(|v| abi_hashes_to_add.contains(&v.function)) .for_each(|abi| { #[cfg(not(feature = "fuzz_static"))] if abi.is_static { @@ -430,8 +438,7 @@ where } let mut abi_instance = get_abi_type_boxed(&abi.abi); - abi_instance - .set_func_with_name(abi.function, abi.function_name.clone()); + abi_instance.set_func_with_name(abi.function, abi.function_name.clone()); register_abi_instance(target, abi_instance.clone(), state); let input = EVMInput { @@ -459,14 +466,18 @@ where }; add_corpus(host, state, &input); }); - } _ => {} } } - unsafe fn on_insert(&mut self, bytecode: &mut Bytecode, address: EVMAddress, host: &mut FuzzHost, state: &mut S) { - + unsafe fn on_insert( + &mut self, + bytecode: &mut Bytecode, + address: EVMAddress, + host: &mut FuzzHost, + state: &mut S, + ) { } fn get_type(&self) -> MiddlewareType { diff --git a/src/evm/vm.rs b/src/evm/vm.rs index c8205b338..f64fbcdc8 100644 --- a/src/evm/vm.rs +++ b/src/evm/vm.rs @@ -1,6 +1,6 @@ /// EVM executor implementation use itertools::Itertools; -use std::borrow::{Borrow, BorrowMut}; +use std::borrow::Borrow; use std::cell::RefCell; use std::cmp::{max, min}; use std::collections::{HashMap, HashSet}; @@ -32,8 +32,11 @@ use primitive_types::{H256, U512}; use rand::random; use revm::db::BenchmarkDB; -use revm_interpreter::{BytecodeLocked, CallContext, CallScheme, Contract, Gas, InstructionResult, Interpreter, Memory, Stack}; use revm_interpreter::InstructionResult::{ArbitraryExternalCallAddressBounded, ControlLeak}; +use revm_interpreter::{ + BytecodeLocked, CallContext, CallScheme, Contract, Gas, InstructionResult, Interpreter, Memory, + Stack, +}; use revm_primitives::{Bytecode, LatestSpec}; use core::ops::Range; @@ -49,13 +52,13 @@ use crate::evm::middlewares::middleware::{Middleware, MiddlewareType}; use crate::evm::onchain::flashloan::FlashloanData; use crate::evm::types::{EVMAddress, EVMU256}; use crate::evm::uniswap::generate_uniswap_router_call; +use crate::evm::vm::Constraint::{NoLiquidation, Value}; use crate::generic_vm::vm_executor::{ExecutionResult, GenericVM, MAP_SIZE}; use crate::generic_vm::vm_state::VMStateT; use crate::invoke_middlewares; use crate::r#const::DEBUG_PRINT_PERCENT; use crate::state::{HasCaller, HasCurrentInputIdx, HasItyState}; use serde::de::DeserializeOwned; -use crate::evm::vm::Constraint::{NoLiquidation, Value}; use serde::{Deserialize, Serialize}; pub const MEM_LIMIT: u64 = 10 * 1024; @@ -225,11 +228,14 @@ impl PostExecutionCtx { } } -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, Default)] pub struct EVMState { /// State of the EVM, which is mapping of EVMU256 slot to EVMU256 value for each contract pub state: HashMap>, + /// Balance of addresses + pub balance: HashMap, + /// Post execution context /// If control leak happens, we add the post execution context to the VM state, /// which contains all information needed to continue execution. @@ -269,14 +275,6 @@ impl EVMStateT for EVMState { } } -impl Default for EVMState { - /// Default VM state, containing empty state, no post execution context, - /// and no flashloan usage - fn default() -> Self { - Self::new() - } -} - impl VMStateT for EVMState { /// Calculate the hash of the VM state fn get_hash(&self) -> u64 { @@ -354,15 +352,7 @@ impl VMStateT for EVMState { impl EVMState { /// Create a new EVM state, containing empty state, no post execution context pub(crate) fn new() -> Self { - Self { - state: HashMap::new(), - post_execution: vec![], - flashloan_data: FlashloanData::new(), - bug_hit: false, - self_destruct: Default::default(), - typed_bug: Default::default(), - arbitrary_calls: Default::default(), - } + Self::default() } /// Get all storage slots of a specific contract @@ -379,6 +369,16 @@ impl EVMState { pub fn insert(&mut self, address: EVMAddress, storage: HashMap) { self.state.insert(address, storage); } + + /// Get balance of a specific address + pub fn get_balance(&self, address: &EVMAddress) -> Option<&EVMU256> { + self.balance.get(address) + } + + /// Set balance of a specific address + pub fn set_balance(&mut self, address: EVMAddress, balance: EVMU256) { + self.balance.insert(address, balance); + } } /// Is current EVM execution fast call @@ -399,7 +399,7 @@ where /// Host providing the blockchain environment (e.g., writing/reading storage), needed by revm pub host: FuzzHost, /// [Depreciated] Deployer address - deployer: EVMAddress, + pub deployer: EVMAddress, /// Known arbitrary (caller,pc) pub _known_arbitrary: HashSet<(EVMAddress, usize)>, phandom: PhantomData<(I, S, VS, CI)>, @@ -752,14 +752,22 @@ where pes: leak_ctx, must_step: match r.ret { ControlLeak => false, - InstructionResult::ArbitraryExternalCallAddressBounded(_, _,_) => true, + InstructionResult::ArbitraryExternalCallAddressBounded(_, _, _) => true, _ => unreachable!(), }, constraints: match r.ret { ControlLeak => vec![], - InstructionResult::ArbitraryExternalCallAddressBounded(caller, target, value) => { - vec![Constraint::Caller(caller), Constraint::Contract(target), Value(value), NoLiquidation, + InstructionResult::ArbitraryExternalCallAddressBounded( + caller, + target, + value, + ) => { + vec![ + Constraint::Caller(caller), + Constraint::Contract(target), + Value(value), + NoLiquidation, ] } _ => unreachable!(), @@ -784,9 +792,11 @@ where .chain(self.host.current_self_destructs.iter().cloned()), ); r.new_state.arbitrary_calls = HashSet::from_iter( - vm_state.arbitrary_calls.iter().cloned().chain( - self.host.current_arbitrary_calls.iter().cloned() - ) + vm_state + .arbitrary_calls + .iter() + .cloned() + .chain(self.host.current_arbitrary_calls.iter().cloned()), ); // println!("r.ret: {:?}", r.ret); @@ -799,7 +809,7 @@ where | InstructionResult::Stop | InstructionResult::ControlLeak | InstructionResult::SelfDestruct - | InstructionResult::ArbitraryExternalCallAddressBounded(_, _,_ ) => false, + | InstructionResult::ArbitraryExternalCallAddressBounded(_, _, _) => false, _ => true, }, new_state: StagedVMState::new_with_state( @@ -857,6 +867,7 @@ where deployed_address: EVMAddress, state: &mut S, ) -> Option { + println!("deployer = 0x{} ", hex::encode(self.deployer)); let deployer = Contract::new( constructor_args.unwrap_or(Bytes::new()), code, diff --git a/src/executor.rs b/src/executor.rs index f559aca90..184a0f784 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -3,6 +3,7 @@ use std::cell::RefCell; use std::fmt::Formatter; use std::marker::PhantomData; +use crate::evm::input::EVMInput; use libafl::executors::{Executor, ExitKind}; use libafl::inputs::Input; use libafl::prelude::{HasCorpus, HasMetadata, HasObservers, ObserversTuple}; @@ -13,7 +14,6 @@ use serde::Serialize; use std::fmt::Debug; use std::ops::Deref; use std::rc::Rc; -use crate::evm::input::EVMInput; use crate::generic_vm::vm_executor::GenericVM; use crate::generic_vm::vm_state::VMStateT; @@ -30,7 +30,7 @@ where VS: Default + VMStateT, Addr: Serialize + DeserializeOwned + Debug + Clone, Loc: Serialize + DeserializeOwned + Debug + Clone, - CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde + CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde, { /// The VM executor pub vm: Rc>>, @@ -47,7 +47,7 @@ where VS: Default + VMStateT, Addr: Serialize + DeserializeOwned + Debug + Clone, Loc: Serialize + DeserializeOwned + Debug + Clone, - CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde + CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("FuzzExecutor") @@ -65,7 +65,7 @@ where VS: Default + VMStateT, Addr: Serialize + DeserializeOwned + Debug + Clone, Loc: Serialize + DeserializeOwned + Debug + Clone, - CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde + CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde, { /// Create a new [`FuzzExecutor`] pub fn new( @@ -117,7 +117,7 @@ where VS: Default + VMStateT, Addr: Serialize + DeserializeOwned + Debug + Clone, Loc: Serialize + DeserializeOwned + Debug + Clone, - CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde + CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde, { /// Get the observers fn observers(&self) -> &OT { diff --git a/src/fuzzer.rs b/src/fuzzer.rs index 559b5b4f4..8f087ad3a 100644 --- a/src/fuzzer.rs +++ b/src/fuzzer.rs @@ -1,5 +1,4 @@ /// Implements fuzzing logic for ItyFuzz - use crate::{ input::VMInputT, state::{HasCurrentInputIdx, HasInfantStateState, HasItyState, InfantStateState}, @@ -33,24 +32,23 @@ use libafl::{ }; use crate::evm::host::JMP_MAP; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; -use std::hash::{Hash, Hasher}; -use itertools::Itertools; -use libafl::prelude::HasRand; -use primitive_types::H256; -use serde_json::Value; use crate::evm::input::ConciseEVMInput; use crate::evm::vm::EVMState; use crate::input::ConciseSerde; use crate::oracle::BugMetadata; use crate::scheduler::{HasReportCorpus, HasVote}; +use itertools::Itertools; +use libafl::prelude::HasRand; +use primitive_types::H256; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::hash::{Hash, Hasher}; const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_millis(100); pub static mut RUN_FOREVER: bool = false; pub static mut ORACLE_OUTPUT: Vec = vec![]; - /// A fuzzer that implements ItyFuzz logic using LibAFL's [`Fuzzer`] trait /// /// CS: The scheduler for the input corpus @@ -67,7 +65,8 @@ pub static mut ORACLE_OUTPUT: Vec = vec![]; pub struct ItyFuzzer<'a, VS, Loc, Addr, Out, CS, IS, F, IF, IFR, I, OF, S, OT, CI> where CS: Scheduler, - IS: Scheduler, InfantStateState> + HasReportCorpus>, + IS: Scheduler, InfantStateState> + + HasReportCorpus>, F: Feedback, IF: Feedback, IFR: Feedback, @@ -103,7 +102,8 @@ impl<'a, VS, Loc, Addr, Out, CS, IS, F, IF, IFR, I, OF, S, OT, CI> ItyFuzzer<'a, VS, Loc, Addr, Out, CS, IS, F, IF, IFR, I, OF, S, OT, CI> where CS: Scheduler, - IS: Scheduler, InfantStateState> + HasReportCorpus>, + IS: Scheduler, InfantStateState> + + HasReportCorpus>, F: Feedback, IF: Feedback, IFR: Feedback, @@ -190,23 +190,30 @@ where } /// Implement fuzzer trait for ItyFuzzer -impl<'a, VS, Loc, Addr, Out, CS, IS, E, EM, F, IF, IFR, I, OF, S, ST, OT, CI> Fuzzer +impl<'a, VS, Loc, Addr, Out, CS, IS, E, EM, F, IF, IFR, I, OF, S, ST, OT, CI> + Fuzzer for ItyFuzzer<'a, VS, Loc, Addr, Out, CS, IS, F, IF, IFR, I, OF, S, OT, CI> where CS: Scheduler, - IS: Scheduler, InfantStateState> + HasReportCorpus>, + IS: Scheduler, InfantStateState> + + HasReportCorpus>, EM: EventManager, F: Feedback, IF: Feedback, IFR: Feedback, I: VMInputT, OF: Feedback, - S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCurrentInputIdx + HasRand + HasCorpus, + S: HasClientPerfMonitor + + HasExecutions + + HasMetadata + + HasCurrentInputIdx + + HasRand + + HasCorpus, ST: StagesTuple + ?Sized, VS: Default + VMStateT, Addr: Serialize + DeserializeOwned + Debug + Clone, Loc: Serialize + DeserializeOwned + Debug + Clone, - CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde + CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde, { /// Fuzz one input fn fuzz_one( @@ -252,77 +259,85 @@ pub static mut DUMP_FILE_COUNT: usize = 0; pub static mut REPLAY: bool = false; - #[macro_export] macro_rules! dump_file { - ($state: expr, $corpus_path: expr, $print: expr) => { - { - if !unsafe {REPLAY} { - unsafe { - DUMP_FILE_COUNT += 1; - } - - let tx_trace = $state.get_execution_result().new_state.trace.clone(); - let txn_text = tx_trace.to_string($state); - let txn_text_replayable = tx_trace.to_file_str($state); + ($state: expr, $corpus_path: expr, $print: expr) => {{ + if !unsafe { REPLAY } { + unsafe { + DUMP_FILE_COUNT += 1; + } - let data = format!( - "Reverted? {} \n Txn: {}", - $state.get_execution_result().reverted, - txn_text - ); - if $print { - println!("============= New Corpus Item ============="); - println!("{}", data); - println!("=========================================="); - } + let tx_trace = $state.get_execution_result().new_state.trace.clone(); + let txn_text = tx_trace.to_string($state); + let txn_text_replayable = tx_trace.to_file_str($state); - // write to file - let path = Path::new($corpus_path.as_str()); - if !path.exists() { - std::fs::create_dir_all(path).unwrap(); - } - let mut file = - File::create(format!("{}/{}", $corpus_path, unsafe { DUMP_FILE_COUNT })).unwrap(); - file.write_all(data.as_bytes()).unwrap(); + let data = format!( + "Reverted? {} \n Txn: {}", + $state.get_execution_result().reverted, + txn_text + ); + if $print { + println!("============= New Corpus Item ============="); + println!("{}", data); + println!("=========================================="); + } - let mut replayable_file = - File::create(format!("{}/{}_replayable", $corpus_path, unsafe { DUMP_FILE_COUNT })).unwrap(); - replayable_file.write_all(txn_text_replayable.as_bytes()).unwrap(); + // write to file + let path = Path::new($corpus_path.as_str()); + if !path.exists() { + std::fs::create_dir_all(path).unwrap(); } + let mut file = + File::create(format!("{}/{}", $corpus_path, unsafe { DUMP_FILE_COUNT })).unwrap(); + file.write_all(data.as_bytes()).unwrap(); + + let mut replayable_file = + File::create(format!("{}/{}_replayable", $corpus_path, unsafe { + DUMP_FILE_COUNT + })) + .unwrap(); + replayable_file + .write_all(txn_text_replayable.as_bytes()) + .unwrap(); } - }; + }}; } #[macro_export] macro_rules! dump_txn { - ($corpus_path: expr, $input: expr) => { - { - if !unsafe {REPLAY} { - unsafe { - DUMP_FILE_COUNT += 1; - } - // write to file - let path = Path::new($corpus_path.as_str()); - if !path.exists() { - std::fs::create_dir_all(path).unwrap(); - } - - let concise_input = ConciseEVMInput::from_input($input, &EVMExecutionResult::empty_result()); - - let txn_text = concise_input.serialize_string(); - let txn_text_replayable = String::from_utf8(concise_input.serialize_concise()).unwrap(); - - let mut file = - File::create(format!("{}/{}_seed", $corpus_path, unsafe { DUMP_FILE_COUNT })).unwrap(); - file.write_all(txn_text.as_bytes()).unwrap(); - - let mut replayable_file = - File::create(format!("{}/{}_seed_replayable", $corpus_path, unsafe { DUMP_FILE_COUNT })).unwrap(); - replayable_file.write_all(txn_text_replayable.as_bytes()).unwrap(); + ($corpus_path: expr, $input: expr) => {{ + if !unsafe { REPLAY } { + unsafe { + DUMP_FILE_COUNT += 1; + } + // write to file + let path = Path::new($corpus_path.as_str()); + if !path.exists() { + std::fs::create_dir_all(path).unwrap(); } + + let concise_input = + ConciseEVMInput::from_input($input, &EVMExecutionResult::empty_result()); + + let txn_text = concise_input.serialize_string(); + let txn_text_replayable = String::from_utf8(concise_input.serialize_concise()).unwrap(); + + let mut file = File::create(format!("{}/{}_seed", $corpus_path, unsafe { + DUMP_FILE_COUNT + })) + .unwrap(); + file.write_all(txn_text.as_bytes()).unwrap(); + + let mut replayable_file = + File::create(format!("{}/{}_seed_replayable", $corpus_path, unsafe { + DUMP_FILE_COUNT + })) + .unwrap(); + replayable_file + .write_all(txn_text_replayable.as_bytes()) + .unwrap(); } - }; + }}; } // implement evaluator trait for ItyFuzzer @@ -330,7 +345,8 @@ impl<'a, VS, Loc, Addr, Out, E, EM, I, S, CS, IS, F, IF, IFR, OF, OT, CI> Evalua for ItyFuzzer<'a, VS, Loc, Addr, Out, CS, IS, F, IF, IFR, I, OF, S, OT, CI> where CS: Scheduler, - IS: Scheduler, InfantStateState> + HasReportCorpus>, + IS: Scheduler, InfantStateState> + + HasReportCorpus>, F: Feedback, IF: Feedback, IFR: Feedback, @@ -352,7 +368,7 @@ where Addr: Serialize + DeserializeOwned + Debug + Clone, Loc: Serialize + DeserializeOwned + Debug + Clone, Out: Default, - CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde + CI: Serialize + DeserializeOwned + Debug + Clone + ConciseSerde, { /// Evaluate input (execution + feedback + objectives) fn evaluate_input_events( @@ -411,15 +427,15 @@ where state_idx = state.add_infant_state( &state.get_execution_result().new_state.clone(), self.infant_scheduler, - input.get_state_idx() + input.get_state_idx(), ); if self .infant_result_feedback - .is_interesting(state, manager, &input, observers, &exitkind)? { - self.infant_scheduler.sponsor_state( - state.get_infant_state_state(), state_idx, 3 - ) + .is_interesting(state, manager, &input, observers, &exitkind)? + { + self.infant_scheduler + .sponsor_state(state.get_infant_state_state(), state_idx, 3) } } @@ -449,10 +465,8 @@ where let mut testcase = Testcase::new(input.clone()); self.feedback.append_metadata(state, &mut testcase)?; corpus_idx = state.corpus_mut().add(testcase)?; - self.infant_scheduler.report_corpus( - state.get_infant_state_state(), - state_idx - ); + self.infant_scheduler + .report_corpus(state.get_infant_state_state(), state_idx); self.scheduler.on_add(state, corpus_idx)?; self.on_add_corpus(&input, unsafe { &JMP_MAP }, corpus_idx); } @@ -467,10 +481,8 @@ where let mut testcase = Testcase::new(input.clone()); let new_testcase_idx = state.corpus_mut().add(testcase)?; - self.infant_scheduler.report_corpus( - state.get_infant_state_state(), - state_idx - ); + self.infant_scheduler + .report_corpus(state.get_infant_state_state(), state_idx); self.scheduler.on_add(state, new_testcase_idx)?; self.on_replace_corpus( (hash, new_fav_factor, old_testcase_idx), @@ -515,7 +527,6 @@ where } // find the solution ExecuteInputResult::Solution => { - println!("\n\n\nšŸ˜ŠšŸ˜Š Found violations! \n\n"); let cur_report = format!( "================ Oracle ================\n{}\n================ Trace ================\n{}\n", @@ -536,14 +547,20 @@ where .open(vuln_file) .expect("Unable to open file"); f.write_all(unsafe { - ORACLE_OUTPUT.iter().map(|v| serde_json::to_string(v).expect("failed to json")) - .join("\n").as_bytes() - }).expect("Unable to write data"); + ORACLE_OUTPUT + .iter() + .map(|v| serde_json::to_string(v).expect("failed to json")) + .join("\n") + .as_bytes() + }) + .expect("Unable to write data"); f.write_all(b"\n").expect("Unable to write data"); - state.metadata_mut().get_mut::().unwrap().register_corpus_idx( - corpus_idx - ); + state + .metadata_mut() + .get_mut::() + .unwrap() + .register_corpus_idx(corpus_idx); #[cfg(feature = "print_txn_corpus")] { diff --git a/src/fuzzers/evm_fuzzer.rs b/src/fuzzers/evm_fuzzer.rs index 884feb472..c11da2897 100644 --- a/src/fuzzers/evm_fuzzer.rs +++ b/src/fuzzers/evm_fuzzer.rs @@ -92,6 +92,8 @@ pub fn evm_fuzzer( >, state: &mut EVMFuzzState, ) { + println!("\n\n ================ EVM Fuzzer Start ===================\n\n"); + // create work dir if not exists let path = Path::new(config.work_dir.as_str()); if !path.exists() { @@ -426,10 +428,12 @@ pub fn evm_fuzzer( if txn.len() < 4 { continue; } + println!("============ Execution {} ===============", idx); // [is_step] [caller] [target] [input] [value] - let (inp, call_until) = ConciseEVMInput::deserialize_concise(txn.as_bytes()) - .to_input(vm_state.clone()); + let temp = txn.as_bytes(); + let temp = ConciseEVMInput::deserialize_concise(temp); + let (inp, call_until) = temp.to_input(vm_state.clone()); printer.borrow_mut().cleanup(); unsafe { @@ -455,9 +459,9 @@ pub fn evm_fuzzer( // "new_state: {:?}", // state.get_execution_result().clone().new_state.state // ); - println!("================================================"); vm_state = state.get_execution_result().new_state.clone(); + println!("================================================"); } } diff --git a/tests/evm/balance/test.sol b/tests/evm/balance/test.sol new file mode 100644 index 000000000..580fd7da3 --- /dev/null +++ b/tests/evm/balance/test.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import "../../../solidity_utils/lib.sol"; + +contract EZ { + // https://github.com/fuzzland/ityfuzz/blob/6c41c82e1e2ae902b7b6ecf7bba563e0a638b607/src/evm/vm.rs#L866 + // init with 3 wei or more to test + constructor() payable {} + + function a() public { + payable(msg.sender).transfer(1); + } + + function b() public { + if (address(this).balance == 0) { + bug(); + } + } +}