What the extension is built with, why, and how it's packaged.
| Layer | Choice |
|---|---|
| Language | Java 21 (see Runtime) |
| Build | Gradle 8.8 (wrapper), multi-project |
| Host platform | Burp Suite via the Montoya API |
| Web3 codec | web3j core 5.0.2 |
| JSON | Jackson Databind (transitive) + org.json |
| Crypto | BouncyCastle (transitive, via web3j) |
| Tests | JUnit 5 (Jupiter) + Mockito |
| Output | Self-contained ("fat") JAR loaded by Burp |
Declared in web3-decoder/build.gradle:
| Dependency | Version | Scope | Why it's here |
|---|---|---|---|
net.portswigger.burp.extensions:montoya-api |
+ (latest) |
implementation | The Burp extension API: editor tabs, suite tab, HTTP sending, persistence, logging. |
org.web3j:core |
5.0.2 |
implementation | ABI encoding/decoding (FunctionEncoder, FunctionReturnDecoder), Keccak hashing (Hash), hex utils (Numeric). The core of the decoder. |
org.json:json |
20240303 |
implementation | Lightweight JSON parsing for explorer / 4byte HTTP responses in the provider classes. |
org.junit.jupiter:junit-jupiter-api |
5.11.3 |
test | Test API. |
org.junit.jupiter:junit-jupiter-engine |
5.9.3 |
testRuntime | JUnit 5 engine. |
org.mockito:mockito-core |
5.12.0 |
test | Mocking the Montoya API and providers in unit tests. |
- Jackson Databind (
com.fasterxml.jackson.*) — the primary JSON mapper used across the codebase (ObjectMapper,JsonNode,TypeReference) for request/ response bodies, ABI parsing, and config serialization. It is pulled in via web3j. - BouncyCastle — cryptographic primitives required by web3j.
Because Jackson and BouncyCastle are transitive, a major web3j upgrade can shift their versions. They are load-bearing here, so re-test decoding after any web3j bump.
web3j provides the canonical Solidity ABI type system and codec. However, the
extension decodes against arbitrary, externally-sourced ABIs rather than
compile-time generated contract wrappers. ABIInputDecoder therefore drives web3j
reflectively:
- maps ABI JSON type strings (
uint256,bytes32,address[],tuple[], …) to web3jTypeclasses andTypeReferences at runtime; - decodes/encodes nested structs/tuples using web3j's native inner-type support
(
TypeReference(false, innerTypes)), available since web3j 4.12.1 — this replaced an earlier bytecode-generation approach and is why the project is on web3j 5.x; - renders decoded structs as ordered, named maps when component names are available.
build.gradleleavessourceCompatibility/targetCompatibilitycommented out, so compilation targets the toolchain's default.settings.gradleapplies the foojay-resolver convention plugin, allowing Gradle to auto-provision a JDK.- In practice the stack targets Java 21: web3j 5.x requires it, and Burp Suite ships and runs the extension on its own bundled JRE (21 on current releases). Build with a JDK 21 toolchain.
flowchart LR
SRC["Java sources +<br/>resources"] --> COMPILE["gradle build<br/>(compile + test)"]
COMPILE --> JARTASK["gradle jar<br/>(fat jar)"]
DEPS["runtimeClasspath<br/>(web3j, jackson, org.json, ...)"] --> JARTASK
JARTASK --> FATJAR["web3-decoder.jar<br/>(all deps bundled)"]
FATJAR --> BURP["Load in Burp:<br/>Extensions → Add → Java"]
The jar task assembles a self-contained artifact:
- bundles every runtime dependency (
configurations.runtimeClasspath→zipTree); duplicatesStrategy = EXCLUDEto tolerate overlappingMETA-INFentries;- excludes
META-INF/*.SF|*.DSA|*.RSAso bundled signed jars don't trip JAR signature verification; - sets
Main-Classtocom.nccgroup.web3decoder.decoder.ABIInputDecoder.
A convenience buildAndJar task chains build then jar.
# Build, run tests, and produce the loadable jar
./gradlew :web3-decoder:build :web3-decoder:jar
# Run only the tests
./gradlew :web3-decoder:test
# One-shot build + jar
./gradlew buildAndJarThen in Burp: Extensions → Add → Extension type: Java → select the jar.
Because Main-Class points at ABIInputDecoder, the same jar runs standalone for
quick decode/encode without Burp:
# Decode calldata against an ABI file
java -jar web3-decoder.jar path/to/abi.json 0xa9059cbb...
# Encode: ABI file, function signature, args as JSON
java -jar web3-decoder.jar path/to/abi.json "transfer(address,uint256)" '{"to":"0x...","amount":"1000"}'| Service | Used by | Purpose |
|---|---|---|
| Configured JSON-RPC node (the proxied endpoint) | Web3RequestContextDecoder, ProxyDetector |
eth_chainId (chain detection) and eth_getStorageAt (proxy slot reads). |
api.etherscan.io (Etherscan v2) + legacy explorer hosts |
EtherscanAbiProvider |
Fetch verified contract ABIs. |
api.4byte.sourcify.dev |
FourByteSignatureProvider |
Resolve unknown 4-byte selectors to candidate signatures. |
All outbound HTTP is sent through Burp's own HTTP stack (api.http().sendRequest), so
it respects Burp's upstream proxy/TLS configuration.