mirror of https://github.com/ConsenSys/mythril
commit
7e73a42051
@ -0,0 +1,25 @@ |
||||
from abc import ABC, abstractmethod |
||||
|
||||
|
||||
class BasicSearchStrategy(ABC): |
||||
__slots__ = 'work_list', 'max_depth' |
||||
|
||||
def __init__(self, work_list, max_depth): |
||||
self.work_list = work_list |
||||
self.max_depth = max_depth |
||||
|
||||
def __iter__(self): |
||||
return self |
||||
|
||||
@abstractmethod |
||||
def get_strategic_global_state(self): |
||||
raise NotImplementedError("Must be implemented by a subclass") |
||||
|
||||
def __next__(self): |
||||
try: |
||||
global_state = self.get_strategic_global_state() |
||||
if global_state.mstate.depth >= self.max_depth: |
||||
return self.__next__() |
||||
return global_state |
||||
except IndexError: |
||||
raise StopIteration |
@ -1,54 +1,67 @@ |
||||
""" |
||||
This module implements basic symbolic execution search strategies |
||||
""" |
||||
from random import randrange |
||||
from . import BasicSearchStrategy |
||||
|
||||
try: |
||||
from random import choices |
||||
except ImportError: |
||||
|
||||
class DepthFirstSearchStrategy: |
||||
# This is for supporting python versions < 3.6 |
||||
from itertools import accumulate |
||||
from random import random |
||||
from bisect import bisect |
||||
|
||||
def choices(population, weights=None): |
||||
""" |
||||
Returns a random element out of the population based on weight. |
||||
If the relative weights or cumulative weights are not specified, |
||||
the selections are made with equal probability. |
||||
""" |
||||
if weights is None: |
||||
return [population[int(random() * len(population))]] |
||||
cum_weights = accumulate(weights) |
||||
return [population[bisect(cum_weights, random()*cum_weights[-1], 0, len(population)-1)]] |
||||
|
||||
|
||||
class DepthFirstSearchStrategy(BasicSearchStrategy): |
||||
""" |
||||
Implements a depth first search strategy |
||||
I.E. Follow one path to a leaf, and then continue to the next one |
||||
""" |
||||
def __init__(self, work_list, max_depth): |
||||
self.work_list = work_list |
||||
self.max_depth = max_depth |
||||
|
||||
def __iter__(self): |
||||
return self |
||||
|
||||
def __next__(self): |
||||
""" Picks the next state to execute """ |
||||
try: |
||||
# This strategies assumes that new states are appended at the end of the work_list |
||||
# By taking the last element we effectively pick the "newest" states, which amounts to dfs |
||||
global_state = self.work_list.pop() |
||||
if global_state.mstate.depth >= self.max_depth: |
||||
return self.__next__() |
||||
return global_state |
||||
except IndexError: |
||||
raise StopIteration() |
||||
def get_strategic_global_state(self): |
||||
return self.work_list.pop() |
||||
|
||||
|
||||
class BreadthFirstSearchStrategy: |
||||
class BreadthFirstSearchStrategy(BasicSearchStrategy): |
||||
""" |
||||
Implements a breadth first search strategy |
||||
I.E. Execute all states of a "level" before continuing |
||||
""" |
||||
def __init__(self, work_list, max_depth): |
||||
self.work_list = work_list |
||||
self.max_depth = max_depth |
||||
|
||||
def __iter__(self): |
||||
return self |
||||
|
||||
def __next__(self): |
||||
""" Picks the next state to execute """ |
||||
try: |
||||
# This strategies assumes that new states are appended at the end of the work_list |
||||
# By taking the first element we effectively pick the "oldest" states, which amounts to bfs |
||||
global_state = self.work_list.pop(0) |
||||
if global_state.mstate.depth >= self.max_depth: |
||||
return self.__next__() |
||||
return global_state |
||||
except IndexError: |
||||
raise StopIteration() |
||||
|
||||
def get_strategic_global_state(self): |
||||
return self.work_list.pop(0) |
||||
|
||||
|
||||
class ReturnRandomNaivelyStrategy(BasicSearchStrategy): |
||||
""" |
||||
chooses a random state from the worklist with equal likelihood |
||||
""" |
||||
def get_strategic_global_state(self): |
||||
if len(self.work_list) > 0: |
||||
return self.work_list.pop(randrange(len(self.work_list))) |
||||
else: |
||||
raise IndexError |
||||
|
||||
|
||||
class ReturnWeightedRandomStrategy(BasicSearchStrategy): |
||||
""" |
||||
chooses a random state from the worklist with likelihood based on inverse proportion to depth |
||||
""" |
||||
|
||||
def get_strategic_global_state(self): |
||||
probability_distribution = [1/(global_state.mstate.depth+1) for global_state in self.work_list] |
||||
return self.work_list.pop(choices(range(len(self.work_list)), probability_distribution)[0]) |
||||
|
||||
|
Before Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,61 @@ |
||||
from mythril.disassembler.disassembly import * |
||||
|
||||
instruction_list = [ |
||||
{"opcode": "PUSH4", "argument": "0x10203040"}, |
||||
{"opcode": "EQ"}, |
||||
{"opcode": "PUSH4", "argument": "0x40302010"}, |
||||
{"opcode": "JUMPI"}, |
||||
] |
||||
|
||||
|
||||
def test_get_function_info(mocker): |
||||
# Arrange |
||||
global instruction_list |
||||
|
||||
signature_database_mock = SignatureDb() |
||||
mocker.patch.object(signature_database_mock, "get") |
||||
signature_database_mock.get.return_value = ["function_name"] |
||||
|
||||
# Act |
||||
function_hash, entry_point, function_name = get_function_info( |
||||
0, instruction_list, signature_database_mock |
||||
) |
||||
|
||||
# Assert |
||||
assert function_hash == "0x10203040" |
||||
assert entry_point == 0x40302010 |
||||
assert function_name == "function_name" |
||||
|
||||
|
||||
def test_get_function_info_multiple_names(mocker): |
||||
# Arrange |
||||
global instruction_list |
||||
|
||||
signature_database_mock = SignatureDb() |
||||
mocker.patch.object(signature_database_mock, "get") |
||||
signature_database_mock.get.return_value = ["function_name", "another_name"] |
||||
|
||||
# Act |
||||
function_hash, entry_point, function_name = get_function_info( |
||||
0, instruction_list, signature_database_mock |
||||
) |
||||
|
||||
# Assert |
||||
assert function_name == "**ambiguous** function_name" |
||||
|
||||
|
||||
def test_get_function_info_no_names(mocker): |
||||
# Arrange |
||||
global instruction_list |
||||
|
||||
signature_database_mock = SignatureDb() |
||||
mocker.patch.object(signature_database_mock, "get") |
||||
signature_database_mock.get.return_value = [] |
||||
|
||||
# Act |
||||
function_hash, entry_point, function_name = get_function_info( |
||||
0, instruction_list, signature_database_mock |
||||
) |
||||
|
||||
# Assert |
||||
assert function_name == "_function_0x10203040" |
@ -0,0 +1,51 @@ |
||||
{ |
||||
"suicide" : { |
||||
"_info" : { |
||||
"comment" : "", |
||||
"filledwith" : "testeth 1.5.0.dev2-52+commit.d419e0a2", |
||||
"lllcversion" : "Version: 0.4.26-develop.2018.9.19+commit.785cbf40.Linux.g++", |
||||
"source" : "src/VMTestsFiller/vmTests/suicideFiller.json", |
||||
"sourceHash" : "4622c577440f9db4b3954a1de60bf2fac55886dcb0ec4ecaf906c25bc77372e7" |
||||
}, |
||||
"callcreates" : [ |
||||
], |
||||
"env" : { |
||||
"currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", |
||||
"currentDifficulty" : "0x0100", |
||||
"currentGasLimit" : "0x0f4240", |
||||
"currentNumber" : "0x00", |
||||
"currentTimestamp" : "0x01" |
||||
}, |
||||
"exec" : { |
||||
"address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", |
||||
"caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681", |
||||
"code" : "0x33ff", |
||||
"data" : "0x", |
||||
"gas" : "0x0186a0", |
||||
"gasPrice" : "0x5af3107a4000", |
||||
"origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681", |
||||
"value" : "0x0de0b6b3a7640000" |
||||
}, |
||||
"gas" : "0x01869e", |
||||
"logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", |
||||
"out" : "0x", |
||||
"post" : { |
||||
"0xcd1722f3947def4cf144679da39c4c32bdc35681" : { |
||||
"balance" : "0x152d02c7e14af6800000", |
||||
"code" : "0x", |
||||
"nonce" : "0x00", |
||||
"storage" : { |
||||
} |
||||
} |
||||
}, |
||||
"pre" : { |
||||
"0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { |
||||
"balance" : "0x152d02c7e14af6800000", |
||||
"code" : "0x33ff", |
||||
"nonce" : "0x00", |
||||
"storage" : { |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "Function %s retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "swc_id": "115", "title": "Use of tx.origin", "type": "Warning"}], "success": true} |
||||
{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "swc_id": "115", "title": "Use of tx.origin", "type": "Warning"}], "success": true} |
||||
|
Loading…
Reference in new issue