Skip to content

Commit

Permalink
chore: add get_bytecode, get_calldata to args
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon-Becker committed Jul 27, 2024
1 parent 9ac619a commit 9b84172
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 76 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions crates/cfg/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ pub(crate) mod graph;

use alloy::primitives::Address;
use eyre::eyre;
use heimdall_common::{
ether::{bytecode::get_bytecode_from_target, compiler::detect_compiler},
utils::strings::StringExt,
};
use heimdall_common::{ether::compiler::detect_compiler, utils::strings::StringExt};
use heimdall_vm::core::vm::VM;

use petgraph::{dot::Dot, Graph};
Expand Down Expand Up @@ -53,7 +50,8 @@ pub async fn cfg(args: CFGArgs) -> Result<CFGResult, Error> {

// get the bytecode from the target
let start_fetch_time = Instant::now();
let contract_bytecode = get_bytecode_from_target(&args.target, &args.rpc_url)
let contract_bytecode = args
.get_bytecode()
.await
.map_err(|e| Error::FetchError(format!("fetching target bytecode failed: {}", e)))?;
debug!("fetching target bytecode took {:?}", start_fetch_time.elapsed());
Expand Down
8 changes: 8 additions & 0 deletions crates/cfg/src/interfaces/args.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use clap::Parser;
use derive_builder::Builder;
use eyre::Result;
use heimdall_common::ether::bytecode::get_bytecode_from_target;
use heimdall_config::parse_url_arg;

#[derive(Debug, Clone, Parser, Builder)]
Expand Down Expand Up @@ -40,6 +42,12 @@ pub struct CFGArgs {
pub timeout: u64,
}

impl CFGArgs {
pub async fn get_bytecode(&self) -> Result<Vec<u8>> {
get_bytecode_from_target(&self.target, &self.rpc_url).await
}
}

impl CFGArgsBuilder {
pub fn new() -> Self {
Self {
Expand Down
1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ tracing-subscriber = "0.3.18"
eyre = "0.6.12"
alloy-json-abi = "0.7.6"
alloy = { version = "0.1.3", features = ["full", "rpc-types-debug", "rpc-types-trace"] }
async-trait = "0.1.51"

[[bin]]
name = "heimdall"
Expand Down
55 changes: 53 additions & 2 deletions crates/cli/src/log_args.rs → crates/cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! clap [Args](clap::Args) for logging configuration.
// Mostly taken from [reth](https://github.com/paradigmxyz/reth)
use clap::{Parser, Subcommand};

use clap::{ArgAction, Args, ValueEnum};
use heimdall_cache::CacheArgs;
use heimdall_config::ConfigArgs;
use heimdall_core::{
heimdall_cfg::CFGArgs, heimdall_decoder::DecodeArgs, heimdall_decompiler::DecompilerArgs,
heimdall_disassembler::DisassemblerArgs, heimdall_dump::DumpArgs,
heimdall_inspect::InspectArgs,
};
use heimdall_tracing::{
tracing_subscriber::filter::Directive, FileWorkerGuard, HeimdallTracer, LayerInfo, LogFormat,
Tracer,
Expand All @@ -12,6 +18,51 @@ use std::{
};
use tracing::{level_filters::LevelFilter, Level};

#[derive(Debug, Parser)]
#[clap(name = "heimdall", author = "Jonathan Becker <[email protected]>", version)]
pub struct Arguments {
#[clap(subcommand)]
pub sub: Subcommands,

#[clap(flatten)]
pub logs: LogArgs,
}

#[derive(Debug, Subcommand)]
#[clap(
about = "Heimdall is an advanced Ethereum smart contract toolkit for forensic and heuristic analysis.",
after_help = "For more information, read the wiki: https://jbecker.dev/r/heimdall-rs/wiki"
)]
#[allow(clippy::large_enum_variant)]
pub enum Subcommands {
#[clap(name = "disassemble", about = "Disassemble EVM bytecode to assembly")]
Disassemble(DisassemblerArgs),

#[clap(name = "decompile", about = "Decompile EVM bytecode to Solidity")]
Decompile(DecompilerArgs),

#[clap(name = "cfg", about = "Generate a visual control flow graph for EVM bytecode")]
CFG(CFGArgs),

#[clap(name = "decode", about = "Decode calldata into readable types")]
Decode(DecodeArgs),

#[clap(name = "config", about = "Display and edit the current configuration")]
Config(ConfigArgs),

#[clap(name = "cache", about = "Manage heimdall-rs' cached files")]
Cache(CacheArgs),

#[clap(name = "dump", about = "Dump the value of all storage slots accessed by a contract")]
Dump(DumpArgs),

#[clap(
name = "inspect",
about = "Detailed inspection of Ethereum transactions, including calldata & trace decoding, log visualization, and more"
)]
Inspect(InspectArgs),
}

/// The log configuration.
#[derive(Debug, Args)]
#[clap(next_help_heading = "LOGGING")]
Expand Down
64 changes: 7 additions & 57 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,24 @@
pub(crate) mod log_args;
pub(crate) mod args;
pub(crate) mod output;

use args::{Arguments, Subcommands};
use clap::Parser;
use eyre::{eyre, Result};
use log_args::LogArgs;
use heimdall_cache::cache;
use output::{build_output_path, print_with_less};
use tracing::info;

use clap::{Parser, Subcommand};

use heimdall_cache::{cache, CacheArgs};
use heimdall_common::utils::{
hex::ToLowerHex,
io::file::write_file,
version::{current_version, remote_nightly_version, remote_version},
};
use heimdall_config::{config, ConfigArgs, Configuration};
use heimdall_config::{config, Configuration};
use heimdall_core::{
heimdall_cfg::{cfg, CFGArgs},
heimdall_decoder::{decode, DecodeArgs},
heimdall_decompiler::{decompile, DecompilerArgs},
heimdall_disassembler::{disassemble, DisassemblerArgs},
heimdall_dump::{dump, DumpArgs},
heimdall_inspect::{inspect, InspectArgs},
heimdall_cfg::cfg, heimdall_decoder::decode, heimdall_decompiler::decompile,
heimdall_disassembler::disassemble, heimdall_dump::dump, heimdall_inspect::inspect,
};

#[derive(Debug, Parser)]
#[clap(name = "heimdall", author = "Jonathan Becker <[email protected]>", version)]
pub struct Arguments {
#[clap(subcommand)]
pub sub: Subcommands,

#[clap(flatten)]
logs: LogArgs,
}

#[derive(Debug, Subcommand)]
#[clap(
about = "Heimdall is an advanced Ethereum smart contract toolkit for forensic and heuristic analysis.",
after_help = "For more information, read the wiki: https://jbecker.dev/r/heimdall-rs/wiki"
)]
#[allow(clippy::large_enum_variant)]
pub enum Subcommands {
#[clap(name = "disassemble", about = "Disassemble EVM bytecode to assembly")]
Disassemble(DisassemblerArgs),

#[clap(name = "decompile", about = "Decompile EVM bytecode to Solidity")]
Decompile(DecompilerArgs),

#[clap(name = "cfg", about = "Generate a visual control flow graph for EVM bytecode")]
CFG(CFGArgs),

#[clap(name = "decode", about = "Decode calldata into readable types")]
Decode(DecodeArgs),

#[clap(name = "config", about = "Display and edit the current configuration")]
Config(ConfigArgs),

#[clap(name = "cache", about = "Manage heimdall-rs' cached files")]
Cache(CacheArgs),

#[clap(name = "dump", about = "Dump the value of all storage slots accessed by a contract")]
Dump(DumpArgs),

#[clap(
name = "inspect",
about = "Detailed inspection of Ethereum transactions, including calldata & trace decoding, log visualization, and more"
)]
Inspect(InspectArgs),
}

#[tokio::main]
async fn main() -> Result<()> {
let args = Arguments::parse();
Expand Down
4 changes: 1 addition & 3 deletions crates/common/src/ether/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ use alloy::primitives::{bytes::Bytes, Address};
use eyre::{eyre, Result};
use std::fs;

/// Given a target from the CLI, return bytecode of the target.
/// TODO: this can probably be a trait method so we can do something like target.try_get_bytecode()
/// TODO: move to CLI, since its only used in CLI
/// Given a target, return bytecode of the target.
pub async fn get_bytecode_from_target(target: &str, rpc_url: &str) -> Result<Vec<u8>> {
// If the target is an address, fetch the bytecode from the RPC provider.
if let Ok(address) = target.parse::<Address>() {
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/ether/calldata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::utils::strings::decode_hex;
use alloy::primitives::TxHash;
use eyre::{bail, eyre, Result};

/// Given a target from the CLI, return calldata of the target.
/// Given a target, return calldata of the target.
pub async fn get_calldata_from_target(target: &str, rpc_url: &str) -> Result<Vec<u8>> {
// If the target is a transaction hash, fetch the calldata from the RPC provider.
if let Ok(address) = target.parse::<TxHash>() {
Expand Down
4 changes: 2 additions & 2 deletions crates/decode/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use alloy_dyn_abi::{DynSolCall, DynSolReturns, DynSolType};
use eyre::eyre;
use heimdall_common::{
ether::{
calldata::get_calldata_from_target,
signatures::{score_signature, ResolveSelector, ResolvedFunction},
types::parse_function_parameters,
},
Expand Down Expand Up @@ -44,7 +43,8 @@ pub async fn decode(mut args: DecodeArgs) -> Result<DecodeResult, Error> {

// get the bytecode from the target
let start_fetch_time = Instant::now();
let mut calldata = get_calldata_from_target(&args.target, &args.rpc_url)
let mut calldata = args
.get_calldata()
.await
.map_err(|e| Error::FetchError(format!("fetching target calldata failed: {}", e)))?;
debug!("fetching target calldata took {:?}", start_fetch_time.elapsed());
Expand Down
8 changes: 8 additions & 0 deletions crates/decode/src/interfaces/args.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use clap::Parser;
use derive_builder::Builder;
use eyre::Result;
use heimdall_common::ether::calldata::get_calldata_from_target;
use heimdall_config::parse_url_arg;

#[derive(Debug, Clone, Parser, Builder)]
Expand Down Expand Up @@ -43,6 +45,12 @@ pub struct DecodeArgs {
pub skip_resolving: bool,
}

impl DecodeArgs {
pub async fn get_calldata(&self) -> Result<Vec<u8>> {
get_calldata_from_target(&self.target, &self.rpc_url).await
}
}

impl DecodeArgsBuilder {
pub fn new() -> Self {
Self {
Expand Down
4 changes: 2 additions & 2 deletions crates/decompile/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use alloy_json_abi::JsonAbi;
use eyre::eyre;
use heimdall_common::{
ether::{
bytecode::get_bytecode_from_target,
compiler::detect_compiler,
signatures::{score_signature, ResolvedError, ResolvedFunction, ResolvedLog},
types::to_type,
Expand Down Expand Up @@ -60,7 +59,8 @@ pub async fn decompile(args: DecompilerArgs) -> Result<DecompileResult, Error> {

// get the bytecode from the target
let start_fetch_time = Instant::now();
let contract_bytecode = get_bytecode_from_target(&args.target, &args.rpc_url)
let contract_bytecode = args
.get_bytecode()
.await
.map_err(|e| Error::FetchError(format!("fetching target bytecode failed: {}", e)))?;
debug!("fetching target bytecode took {:?}", start_fetch_time.elapsed());
Expand Down
8 changes: 8 additions & 0 deletions crates/decompile/src/interfaces/args.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use clap::Parser;
use derive_builder::Builder;
use eyre::Result;
use heimdall_common::ether::bytecode::get_bytecode_from_target;
use heimdall_config::parse_url_arg;

#[derive(Debug, Clone, Parser, Builder)]
Expand Down Expand Up @@ -47,6 +49,12 @@ pub struct DecompilerArgs {
pub timeout: u64,
}

impl DecompilerArgs {
pub async fn get_bytecode(&self) -> Result<Vec<u8>> {
get_bytecode_from_target(&self.target, &self.rpc_url).await
}
}

impl DecompilerArgsBuilder {
pub fn new() -> Self {
Self {
Expand Down
7 changes: 3 additions & 4 deletions crates/disassemble/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::time::Instant;

use crate::{error::Error, interfaces::DisassemblerArgs};
use eyre::eyre;
use heimdall_common::{ether::bytecode::get_bytecode_from_target, utils::strings::encode_hex};
use heimdall_common::utils::strings::encode_hex;
use heimdall_vm::core::opcodes::Opcode;
use tracing::{debug, info};

Expand All @@ -14,9 +14,8 @@ pub async fn disassemble(args: DisassemblerArgs) -> Result<String, Error> {

// get the bytecode from the target
let start_fetch_time = Instant::now();
let contract_bytecode = get_bytecode_from_target(&args.target, &args.rpc_url)
.await
.map_err(|e| eyre!("fetching target bytecode failed: {}", e))?;
let contract_bytecode =
args.get_bytecode().await.map_err(|e| eyre!("fetching target bytecode failed: {}", e))?;
debug!("fetching target bytecode took {:?}", start_fetch_time.elapsed());

// iterate over the bytecode, disassembling each instruction
Expand Down
8 changes: 8 additions & 0 deletions crates/disassemble/src/interfaces/args.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use clap::Parser;
use eyre::Result;
use heimdall_common::ether::bytecode::get_bytecode_from_target;
use heimdall_config::parse_url_arg;

#[derive(Debug, Clone, Parser)]
Expand Down Expand Up @@ -48,6 +50,12 @@ pub struct DisassemblerArgsBuilder {
output: Option<String>,
}

impl DisassemblerArgs {
pub async fn get_bytecode(&self) -> Result<Vec<u8>> {
get_bytecode_from_target(&self.target, &self.rpc_url).await
}
}

impl Default for DisassemblerArgsBuilder {
fn default() -> Self {
Self::new()
Expand Down

0 comments on commit 9b84172

Please sign in to comment.