mythril--arbitrary_jump.py(任意跳转)
arbitrary_jump.py(任意跳转)
该模块包含对于任意跳转的检测代码。
"""This module contains the detection code for Arbitrary jumps."""
import logging
from mythril.analysis.solver import get_transaction_sequence, UnsatError
from mythril.analysis.module.base import DetectionModule, Issue, EntryPoint
from mythril.analysis.swc_data import ARBITRARY_JUMP
from mythril.laser.ethereum.state.global_state import GlobalState
log = logging.getLogger(__name__) #记录日志
# 搜索跳转到字节码中的任意位置
DESCRIPTION = """
Search for jumps to arbitrary locations in the bytecode
"""
# 继承自DetectionModule (DetectionModule位于mythril.analysis.module.base.py)
"""
There are several class properties that expose information about the detection modules
- name: The name of the detection module # 检测模块的名称
- swc_id: The SWC ID associated with the weakness that the module detects # 与模块检测到的弱点关联的 SWC ID
- description: A description of the detection module, and what it detects # 检测模块及其检测内容的说明
- entry_point: Mythril can run callback style detection modules, or modules that search the statespace.
[IMPORTANT] POST entry points severely slow down the analysis, try to always use callback style modules
- pre_hooks: A list of instructions to hook the laser vm for (pre execution of the instruction)
- post_hooks: A list of instructions to hook the laser vm for (post execution of the instruction)
"""
class ArbitraryJump(DetectionModule):
"""This module searches for JUMPs to a user-specified location.""" # 此模块搜索到用户指定位置的 JUMP
name = "Caller can redirect execution to arbitrary bytecode locations"
swc_id = ARBITRARY_JUMP # “127”
description = DESCRIPTION
entry_point = EntryPoint.CALLBACK # CALLBACK = 2
pre_hooks = ["JUMP", "JUMPI"]
def reset_module(self):
"""
Resets the module by clearing everything
:return:
"""
super().reset_module() # 使用父模块的reset_module()方法
def _execute(self, state: GlobalState) -> None:
"""
:param state:
:return:
"""
# 获取此全局状态的当前指令 instruction_list:反汇编 evm 字节码并返回指令列表。
if state.get_current_instruction()["address"] in self.cache:
return
self.issues.extend(self._analyze_state(state))
@staticmethod
def _analyze_state(state):
"""
:param state:
:return:
"""
jump_dest = state.mstate.stack[-1] # 要跳转的地址
if jump_dest.symbolic is False: # 判断是不是符号化,是符号化的话就是不确定的,可以根据输入改变,会跳到不同的地址
return []
# Most probably the jump destination can have multiple locations in these circumstances
try:
"""
约束条件有:
UGE(max_calldata_size, transaction.call_data.calldatasize)
UGE(
symbol_factory.BitVecVal(1000000000000000000000, 256),
world_state.starting_balances[transaction.caller],
)
UGE(
symbol_factory.BitVecVal(100000000000000000000, 256),
world_state.starting_balances[account.address],
)
"""
# transaction_sequence 如果不为空,说明有解,说明存在问题
transaction_sequence = get_transaction_sequence(
state, state.world_state.constraints
)
except UnsatError:
return []
issue = Issue(
contract=state.environment.active_account.contract_name,
function_name=state.environment.active_function_name,
address=state.get_current_instruction()["address"],
swc_id=ARBITRARY_JUMP,
title="Jump to an arbitrary instruction",
severity="High",
bytecode=state.environment.code.bytecode,
description_head="The caller can redirect execution to arbitrary bytecode locations.",
description_tail="It is possible to redirect the control flow to arbitrary locations in the code. "
"This may allow an attacker to bypass security controls or manipulate the business logic of the "
"smart contract. Avoid using low-level-operations and assembly to prevent this issue.",
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
transaction_sequence=transaction_sequence,
)
return [issue]
detector = ArbitraryJump()

浙公网安备 33010602011771号