shazow / whatsabi

Extract the ABI (and resolve proxies, and get other metadata) from Ethereum bytecode, even without source code.
https://shazow.github.io/whatsabi/
MIT License
1.06k stars 74 forks source link

disasm: Consider using evmole as an optional backend? #80

Open shazow opened 10 months ago

shazow commented 10 months ago

evmole is doing great work at extracting selectors and guessing arguments.

cc @cdump -- do you have any thoughts/feelings about this?

cdump commented 10 months ago

I like this idea

shazow commented 9 months ago

@cdump Any chance you'd be willing to expose some of the evm implementation in the js library? I'd like to hook into a few opcodes, for example I need to keep track of SLOAD and DELEGATECALL for things like proxy detection, LOG* for events, etc.

cdump commented 9 months ago

@shazow I was thinking about this - making EVM evmole extensible, will probably add that in about 1 month.

shazow commented 9 months ago

@cdump Sounds good. Could also make it a separate package, I'd probably use it without the rest of the stuff. I like the idea of a js EVM implementation that is focused on efficiency and gas-bounded analysis. Things like ethereumjs have way too much other things to be viable for this, and I'm really not excited about separately maintaining yet another separate EVM implementation with the various upgrades coming up, but would definitely contribute to one. :)

cdump commented 9 months ago

separate package

Maybe later, I think it will be easier to start just as the evm module exports from the EVMole right now

What do you think about the following approach?

import { Vm } from 'evmole/evm/vm'
import { Element } from 'evmole/evm/element'
import { Op } from 'evmole/evm/opcodes'

class MyVm extends Vm {
  constructor(code, calldata) {
    super(code, calldata);
  }

  exec_opcode(op) {
    if (op == Op.JUMPDEST) {
      console.log('hooked JUMPDEST');
      return [1];
    }
    return super.exec_opcode(op);
  }
}

const code = '608060405260043610610033575f3560e01c8063b69ef8a814610037578063d0e30db01461005d578063dd5d521114610067575b5f80fd5b348015610042575f80fd5b5061004b5f5481565b60405190815260200160405180910390f35b610065610086565b005b348015610072575f80fd5b506100656100813660046100bb565b61009d565b345f8082825461009691906100e5565b9091555050565b8063ffffffff165f808282546100b391906100e5565b909155505050565b5f602082840312156100cb575f80fd5b813563ffffffff811681146100de575f80fd5b9392505050565b8082018082111561010457634e487b7160e01b5f52601160045260245ffd5b9291505056'

const code_arr = Buffer.from(code, 'hex')
const cd_arr = Buffer.from('b69ef8a8', 'hex')

const vm = new MyVm(code_arr, new Element(cd_arr, 'calldata'))

while (!vm.stopped) {
  const ret = vm.step()
  console.log('step gas:', ret[1]);
}
  1. export of src/evm/*.js as evm/
  2. make #exec_opcode public instead of private
  3. using all this with class inheritance - it's possible to overwrite vm methods and call original methods too (super.method())
$ node a.mjs

step gas: 3
step gas: 3
step gas: 3
step gas: 3
step gas: 2
step gas: 3
step gas: 3
step gas: 10
step gas: 2
step gas: 3
step gas: 3
step gas: 3
step gas: 3
step gas: 3
step gas: 3
step gas: 3
step gas: 10
hooked JUMPDEST
step gas: 1
step gas: 2
step gas: 3
step gas: 3
step gas: 3
step gas: 10
hooked JUMPDEST
step gas: 1
...
shazow commented 9 months ago

I'll need to prototype some code to be sure but should be a good starting point, as long as I can access the stack and memory inside the hook too (I believe it should work as-is).

Would it be possible to also get access to something like src/selectors.js:process and src/arguments.js:functionArguments?

cdump commented 9 months ago

can access the stack and memory inside the hook too

yes, you can

Would it be possible to also get access to something like src/selectors.js:process and /src/arguments.js:functionArguments?

these functions already exported, and you can import them using import {functionArguments, functionSelectors} from 'evmole' (example)

shazow commented 9 months ago

these functions already exported, and you can import them using import {functionArguments, functionSelectors} from 'evmole' (example)

I mean if we're getting access to the vm implementation, it can be useful to get access to functions that deal with vm instances as inputs (rather than the wrappers than parse bytecode into a vm again).

shazow commented 9 months ago

I respect the desire to keep the exposed API surface as small as possible. Worst case I can also fork/vendor parts that aren't exposed if necessary,

cdump commented 9 months ago

can be useful to get access to functions that deal with vm instances as inputs (rather than the wrappers than parse bytecode into a vm again)

I can think about it when you have a real example where it could be useful, but you are right—I want to keep the public API small and stable right now :)

shazow commented 9 months ago

Sounds good, let's start with just the evm stuff and we'll go from there. :)

cdump commented 9 months ago

Ok, I will finish first version of https://github.com/shazow/whatsabi/issues/80#issuecomment-1939187827 and push it to the dedicated git branch this week

shazow commented 9 months ago

@cdump Thanks! Looking forward to playing with it. :)

cdump commented 9 months ago

@shazow try https://github.com/cdump/evmole/tree/pubevm

shazow commented 9 months ago

@cdump That looks like a great start, thank you! I probably won't have time to prototype this into whatsabi until after ETHDenver though (any chance I'll see you there?)

cdump commented 9 months ago

any chance I'll see you there?

no :(