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 |
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 |
Implements a depth first search strategy |
||||||
I.E. Follow one path to a leaf, and then continue to the next one |
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): |
def get_strategic_global_state(self): |
||||||
""" Picks the next state to execute """ |
return self.work_list.pop() |
||||||
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() |
|
||||||
|
|
||||||
|
|
||||||
class BreadthFirstSearchStrategy: |
class BreadthFirstSearchStrategy(BasicSearchStrategy): |
||||||
""" |
""" |
||||||
Implements a breadth first search strategy |
Implements a breadth first search strategy |
||||||
I.E. Execute all states of a "level" before continuing |
I.E. Execute all states of a "level" before continuing |
||||||
""" |
""" |
||||||
def __init__(self, work_list, max_depth): |
|
||||||
self.work_list = work_list |
def get_strategic_global_state(self): |
||||||
self.max_depth = max_depth |
return self.work_list.pop(0) |
||||||
|
|
||||||
def __iter__(self): |
|
||||||
return self |
class ReturnRandomNaivelyStrategy(BasicSearchStrategy): |
||||||
|
""" |
||||||
def __next__(self): |
chooses a random state from the worklist with equal likelihood |
||||||
""" Picks the next state to execute """ |
""" |
||||||
try: |
def get_strategic_global_state(self): |
||||||
# This strategies assumes that new states are appended at the end of the work_list |
if len(self.work_list) > 0: |
||||||
# By taking the first element we effectively pick the "oldest" states, which amounts to bfs |
return self.work_list.pop(randrange(len(self.work_list))) |
||||||
global_state = self.work_list.pop(0) |
else: |
||||||
if global_state.mstate.depth >= self.max_depth: |
raise IndexError |
||||||
return self.__next__() |
|
||||||
return global_state |
|
||||||
except IndexError: |
class ReturnWeightedRandomStrategy(BasicSearchStrategy): |
||||||
raise StopIteration() |
""" |
||||||
|
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