-
Notifications
You must be signed in to change notification settings - Fork 740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to make Mythril analyze all functions to their regular end at RETURN/STOP? #1777
Comments
Here are the functions that I want Mythril to report: $ solc --optimize --hashes ShieldController.sol
...
======= ShieldController.sol:ShieldController =======
Function signatures:
38af3eed: beneficiary()
75b4d78c: bonus()
dc070657: changeBeneficiary(address)
c1ff808d: changeBonus(uint256)
1e761681: changeDepositAmt(uint256)
decc1a86: changeRefFee(uint256)
5b1dbd80: claimTokens(address,address,address)
baef5dfd: createShield(string,string,address,address,address,address,uint256[],address[])
10adc3f5: deleteShield(address,uint256)
b5677b42: depositAmt()
c25dd27a: emitAction(address,address,address,address,uint256,uint256,bool)
82e2fadb: getBalances(address,uint256,uint256)
08abe957: getShields()
aa6ca808: getTokens()
0c340a24: governor()
80d85911: initialize(uint256,uint256,uint256)
fc6b3204: isGov()
1c74a301: receiveOwnership()
ec2e0ab3: refFee()
2fce9884: shieldMapping(address)
f2fde38b: transferOwnership(address)
... |
Mythril visits all functions. You can prefer using bfs as a strategy to make it prioritise the breadth over depth. If your goal is to simply |
@norhh Thanks for your suggestion. However, the option ./myth analyze -f ShieldController.hex -m Function --strategy bfs
==== function visited ====
SWC ID: 0
Severity: Low
Contract: MAIN
Function name: constructor
PC address: 0
Estimated Gas Usage: 1521 - 3920
function visited
--------------------
==== function visited ====
SWC ID: 0
Severity: Low
Contract: MAIN
Function name: gasprice_bit_ether(int128) or transferFrom(address,address,uint256)
PC address: 0
Estimated Gas Usage: 2742 - 4155
function visited
--------------------
|
|
You should add |
@norhh Thanks for the hint regarding Adding Might it be the case that Mythril stops its analysis when encountering a state similar to ones seen before? Actually, the state at the end of a getter is not really the same as at the end of other getters, as they return different storage values. Is there a way to let Mythril also explore such parts of the search space? |
A quick fix for fixing the getter issue will be to solve for the first 4 bytes of calldata to get the function signature. I'll push that fix today sometime. |
Of course they do, how would the EVM otherwise return control to the calling context, with a return value? Below is the sequence of instructions for 000eb: PUSH4 0x75b4d78c ; bonus()
000f0: EQ
000f1: PUSH3 0x0002a8
000f5: JUMPI
002a8: JUMPDEST ; bonus()
002a9: CALLVALUE
002aa: DUP1
002ab: ISZERO
002ac: PUSH3 0x0002b5
002b0: JUMPI
002b1: PUSH1 0x00
002b3: DUP1
002b4: REVERT
002b5: JUMPDEST ; bonus() non-payable
002b6: POP
002b7: PUSH3 0x0002c0
002bb: PUSH1 0x34
002bd: SLOAD ; S[0x34] 0x0002c0
002be: DUP2 ; 0x0002c0 S[0x34] 0x0002c0
002bf: JUMP
002c0: JUMPDEST ; S[0x34] 0x0002c0
002c1: PUSH1 0x40
002c3: MLOAD ; fmp S[0x34] 0x0002c0
002c4: SWAP1
002c5: DUP2 ; fmp S[0x34] fmp 0x0002c0
002c6: MSTORE ; fmp 0x0002c0 # M[fmp] = S[0x34]
002c7: PUSH1 0x20
002c9: ADD ; fmp+0x20 0x0002c0 # M[fmp] = S[0x34]
002ca: PUSH3 0x00017b
002ce: JUMP
0017b: JUMPDEST
0017c: PUSH1 0x40
0017e: MLOAD ; fmp fmp+0x20 0x0002c0 # M[fmp] = S[0x34]
0017f: DUP1 ; fmp fmp fmp+0x20 0x0002c0 # M[fmp] = S[0x34]
00180: SWAP2 ; fmp+0x20 fmp fmp 0x0002c0 # M[fmp] = S[0x34]
00181: SUB ; 0x20 fmp 0x0002c0 # M[fmp] = S[0x34]
00182: SWAP1 ; fmp 0x20 0x0002c0 # M[fmp] = S[0x34]
00183: RETURN |
The |
The bytecode maps the final |
Thanks for the explanations, I think I now understand. |
Nevermind, Actually Mythril seems to detect getters at the return by matching the |
Commenting out:
|
@gsalzer , can you try it with the latest commit? |
@norhh With constructor
controller() <== not quite clear where this comes from
fallback
beneficiary()
depositAmt()
getBalances(address,uint256,uint256)
getShields()
getTokens()
governor()
initialize(uint256,uint256,uint256)
isGov()
refFee()
shieldMapping(address) but the following ones are still missing: 75b4d78c: bonus()
dc070657: changeBeneficiary(address)
c1ff808d: changeBonus(uint256)
1e761681: changeDepositAmt(uint256)
decc1a86: changeRefFee(uint256)
5b1dbd80: claimTokens(address,address,address)
baef5dfd: createShield(string,string,address,address,address,address,uint256[],address[])
10adc3f5: deleteShield(address,uint256)
c25dd27a: emitAction(address,address,address,address,uint256,uint256,bool)
1c74a301: receiveOwnership()
f2fde38b: transferOwnership(address) |
You can increase the transaction count to |
@norhh I'm puzzled. Doesn't |
Let's take a function:
It's not possible to hit
Where the transaction only ends with Also, the issue with |
Thanks for the explanation. It is definitely a valid argument in the case of source code/bytecode where Mythril may take the state of the contract, after initialization, into account. But in the case of |
You'll have to use |
Thanks regarding 75b4d78c: bonus()
baef5dfd: createShield(string,string,address,address,address,address,uint256[],address[])
c25dd27a: emitAction(address,address,address,address,uint256,uint256,bool) Functions reported even though they are not there: 0x00000001 account_info_rotate_tine(uint256)
0xf77c4791 controller()
fallback Do you have an explanation why Mythril reports |
Yes, there was the issue of |
How to add a constraint to the calldata? For example constrain the constraints.append(
tx.call_data[0:4] == symbol_factory.BitVecVal(0xa9059cbb, 32)
) |
Hi @aj3423, this is an example of how it is done: mythril/mythril/laser/ethereum/transaction/symbolic.py Lines 99 to 101 in 39b79ca
|
@norhh Thanks, this is really helpful. Btw, maybe this loop can be optimised, currently it's: mythril/mythril/laser/ethereum/transaction/symbolic.py Lines 89 to 102 in 39b79ca
It always generates 4 constraints even with a transaction sequence like
I think it should be: constraint = Bool(False)
for func_hash in func_hashes:
if func_hash == -1:
# Fallback function without calldata
constraint = Or(constraint, calldata.size < 4)
elif func_hash == -2:
# Receive function
constraint = Or(constraint, calldata.size == 0)
else:
for i in range(FUNCTION_HASH_BYTE_LENGTH):
constraint = Or(
constraint, calldata[i] == symbol_factory.BitVecVal(func_hash[i], 8)
)
constraints.append(constraint) |
I try to understand how Mythril/Laser traverses the execution traces, with the aim to let it reach the regular end of as many functions as possible. For testing, I added a module
Function
in a filemythril/analysis/module/modules/function.py
, see below for the code. Its purpose is to report the name of the current function when reaching its regular end (RETURN
). I run it asmyth analyze -f ShieldController.hex -m Function
where
ShieldController.hex
is the contract creation code at https://etherscan.io/address/0x860b3913e248e6ba352120d550567379cb48fdd6#code.The expected output are the functions listed by
solc --optimize --hashes ShieldController.sol
for contractShieldController
. However, the call above just reports theconstructor
and a functiontransferFrom(address,address,uint256)
, which does not occur inShieldController
, but seems to be a function in a contract deployed byShieldController
.Which settings are needed for Mythril/Laser (like
max-depth
,loop-bound
,call-depth-limit
,transaction-count
and the search strategy) such that it analyzes the main branches of all (or most) functions until their finalRETURN
? In the intended application, reachingRETURN
will trigger checks for that function.Contents of
mythril/analysis/module/modules/function.py
:In
mythril/analysis/module/loader.py
, I addedThe text was updated successfully, but these errors were encountered: