以太坊安全之EVM与短地址攻击
- 格式:docx
- 大小:13.41 KB
- 文档页数:6
0引言中本聪提出比特币使用的区块链技术实际上是一种特殊的电子账本,账本中公开记录着从区块链建立之初的每一条转帐记录。
这是一种去中心化的账本,其完全不依赖中心监管机构的工作,能够完全独立的完成交易的发生和确认,降低了由于单一节点风险引起的安全问题。
事实上,由于区块链的用户、买卖双方实际是互相不信任的节点,交易双方均不信任对方能够单独正确记录交易,则衍生出了基于运算能力保证的确认机制,用户、交易、矿工三者构成了基本的加密货币交易。
加密货币本质上是区块链技术的一个小的应用方面,此外,依托于区块链中记录信息的不可更改的特性,我们可以在不依赖第三方公证机构的前提下,永久性记录用户双方发生的一切交易、操作、合同等权威性文件、信息。
而传统的公证技术往往依赖第三方权威机构的参与,其中第三方机构公信力决定了公正文件的可信度。
而基于区块链智能合约的新一代合同、能够摆脱对第三方机构权威的依赖,在增强合约、信息可信度的同时,能够减少实际公证过程的人力物力财力的消耗。
以太坊提供给开发者和用户一套能够构建去中心化应用的完整技术平台。
比特币提供了完整的端到端加密交易系统,使用者能够使用其完成完整的交易。
以太坊相较于比特币来说,除了提供传统的类似于比特币的交易记录能力——以太币外,同时能够用于创建去中心化的程序、自治组织和智能合约。
至今,以太坊已经在金融、物联网、智能电网、游戏开发、智能合同等多领域被广泛应用。
智能合约是以太坊应用平台的核心,本质上是以公开的形式随着区块链一同部署在应用网络之中的一段程序代码。
能够根据设定的规则,完成决策、资料储存以及以太币的传输。
智能合约提供验证及执行智能合约本身所设定的条件,对整个网络的公开性与透明性,允许在没有第三方的情况下完成可信交易,同时这些交易具有高度的匿名性。
尽管智能合约设计本身目的在于减少可能存在的风险问题。
但是,类似于以太坊的智能合约仍存在设计上的缺陷,攻击者能够利用设计漏洞,对其进行攻击,导致大量经济损失。
以太坊工作原理以太坊是一个基于区块链技术的分布式计算平台,它被认为是比特币的进一步发展。
以太坊可以执行自动化智能合约并使用加密货币以太(Ether)作为支付方式。
它不仅仅是一个数字货币,更被认为是一种新兴的智能合约平台。
以太坊的工作原理是基于以太坊虚拟机(EVM)和以太坊的编程语言Solidity。
以太坊虚拟机可以理解和执行Solidity编写的智能合约。
这些智能合约就是一组自动执行规则,它们被存储在以太坊区块链上。
每个智能合约都有独特的地址,即以太坊中的智能合约地址。
以太坊区块链是由一个个区块组成的。
每个区块中都包含了前一段时间内交易的记录和当前时间的哈希值,这个哈希值作为下一个区块的前缀。
每个节点都要验证哈希值是否正确,如果验证通过则会将该区块添加到自己的区块链中。
在以太坊中,挖矿者通过计算哈希值来创建新的区块,并通过竞拍方式获得新的以太。
以太坊分为两种账户:外部账户和智能合约账户。
外部账户可以由个人持有并控制,用于发送以太货币和进行交易。
智能合约账户则是由智能合约程序控制的特殊账户,这些账户可以自主执行智能合约中的代码逻辑,与其他智能合约和外部账户互动。
执行一个智能合约需要消耗以太币的燃料(gas)。
燃料相当于执行合约逻辑所需要的计算能力,消耗的燃料越多,执行代价也就越高。
以太坊的燃料机制可以防止智能合约无限制地执行,从而保证了以太坊的安全性和稳定性。
以太坊的去中心化实现了用于交易的智能合约和分布式计算。
以太坊可以减少部分的中间人环节,自动执行计算任务和交易,并保证其安全性和数据一致性。
这种去中心化的理念也是区块链技术的核心所在。
总结一下,以太坊是一个去中心化的分布式计算平台,主要由以太坊虚拟机、Solidity编程语言和智能合约组成。
它的区块链技术实现了数字货币交易和智能合约自动执行,并通过燃料机制保证了其安全性和稳定性。
以太坊被认为是区块链技术的一个新进展,它的出现拓宽了区块链应用领域。
以太坊智能合约运行原理以太坊是一个分布式的区块链平台,它允许开发者创建和部署智能合约。
智能合约是一种在区块链上自动执行的计算机程序,它定义了参与方之间的规则和协议。
合约创建阶段:在创建智能合约之前,开发者需要使用一种称为Solidity的编程语言编写合约代码。
Solidity是以太坊的官方合约编程语言,类似于JavaScript。
合约中定义了合约的功能和行为。
合约编写完成后,合约代码被编译成一种称为EVM(以太坊虚拟机)字节码的形式,字节码是一种与具体硬件和操作系统无关的中间代码。
合约部署阶段:合约部署是将合约代码和一些元数据(如创建者地址、合约名称等)写入区块链的过程。
在以太坊中,每个智能合约都有一个唯一的地址,该地址用于在区块链上识别和调用合约。
合约部署时,用户需要支付一定的矿工费用(也称为Gas)用于执行合约和写入区块链。
Gas是以太坊中用于测量计算和存储成本的计量单位,用于防止滥用和占用过多的资源。
矿工费用的大小取决于合约的复杂性和执行成本。
矿工费用越高,合约的执行优先级越高,被打包到区块中的速度越快。
合约执行阶段:合约部署完成后,用户可以通过发送交易来调用合约的函数。
交易包括合约地址、函数调用和相关参数。
当交易被发送到网络中时,矿工会将交易打包到一个新的区块中,并开始执行智能合约。
在执行阶段,矿工会根据交易中的调用参数在以太坊虚拟机(EVM)中执行合约的字节码。
EVM是以太坊的运行环境,可以模拟真实计算机的功能。
它具有一组指令集、内存、存储和栈,用于执行合约代码。
执行合约的过程类似于执行传统的计算机程序,包括读取和写入数据、进行算术和逻辑操作等。
合约可以与外部数据进行交互,并根据条件和逻辑执行相应的操作。
如果合约执行完成,执行结果(如状态改变、返回值等)会被写入区块链中。
在以太坊中,智能合约的执行需要消耗一定的燃料(Gas)。
燃料是一种测量执行成本的单位,用于支付矿工费用和防止无限循环等滥用。
目录目录 (1)1概述 (3)1.1编写目的 ................................................................................................................ 错误!未定义书签。
1.2术语和缩写 ............................................................................................................ 错误!未定义书签。
1.3参考资料 ................................................................................................................ 错误!未定义书签。
2VoLTE概念介绍 . (3)3VoLTE架构 (3)4VoLTE UE注册流程和呼叫流程 (10)5VoLTE中的承载 (13)5.1QCI 5建立流程 (15)5.2QCI1建立流程 (19)5.3VoIP 业务流建立及通话过程简化版(4G to 4G) (21)6VoLTE语音编/解码标准 (23)6.1AMR编码特点 (23)6.2AMR业务模型 (24)6.3AMR速率对应的GBR速率 (24)6.3.1GBR速率计算细节 (24)6.3.2GBR速率总结 (30)7VoLTE 评价指标 (31)7.1时延和丢包率概念 (31)7.2VoLTE 容量 (32)7.3语音质量评价 (32)7.4影响VoIP的因素 (33)7.4.1时延 (33)7.4.2抖动 (33)7.4.3丢包率 (34)8VoLTE无线技术 (34)8.1Semi-Persistent Scheduling (34)8.2TTI Bundling (35)8.3ROHC (38)8.4SRVCC (39)8.5RLC配置 (40)8.6DRX (40)VoLTE 新技术培训1 概述2 VoLTE 概念介绍VoIP 是Voice Over Internet Protocol 的简称,意为在Internet 上传输语音。
以太坊的知识总结1. 介绍以太坊是一种开源的、去中心化的基于区块链技术的平台,旨在为用户提供智能合约的开发和执行环境。
它于2015年由Vitalik Buterin提出并开始开发,现已成为最受欢迎的智能合约平台之一。
2. 区块链和智能合约2.1 区块链以太坊基于区块链技术,区块链是由一个个区块组成的分布式数据库。
每个区块包含交易数据和一些元数据,通过哈希函数与前一个区块链接在一起,形成了不可篡改的链式结构。
这意味着一旦数据被写入区块链,就无法被修改或删除,使得区块链具有高度的安全性。
2.2 智能合约智能合约是以太坊平台的核心概念之一。
它是一种在区块链上执行的自动化合约,其中包含可以触发、验证和执行特定条件的代码。
智能合约可以用于创建和管理数字资产、进行投票和选举、执行金融契约等。
与传统的合约不同,智能合约完全通过代码实现,并且具备自动化执行的能力,不需要第三方进行监管或执行。
3. 以太坊的核心组件3.1 以太坊虚拟机(EVM)以太坊虚拟机(EVM)是以太坊平台的运行环境,用于执行智能合约。
EVM提供了一个安全的执行环境,并使用以太坊的本地货币——以太币(Ether)来支付执行智能合约的费用。
3.2 以太币(Ether)以太币(Ether)是以太坊平台的本地货币,用于支付交易费用和执行智能合约。
以太币可以通过挖矿或交易获得。
以太币的供应是有限的,总量不会超过1亿枚。
3.3 智能合约语言以太坊支持多种智能合约语言,最常用的是Solidity。
Solidity是一种与以太坊兼容的高级语言,类似于JavaScript,用于编写智能合约代码。
使用Solidity,开发人员可以定义合约的状态和行为,并通过以太坊虚拟机执行。
4. 以太坊的功能和应用4.1 去中心化应用(DApps)以太坊的一个重要功能是支持去中心化应用(DApps)的开发。
DApps是一种基于区块链的应用程序,具备传统应用程序的功能,但去除了中心化服务器,通过区块链网络中的节点共同维护和执行程序。
对以太坊虚拟机(EVM)EVM是智能合约的运行环境作为区块验证协议的一部分,参与网络的每个节点都会运行EVM,审查节点会检查验证正在验证的区块中列出的交易,并运行EVM中交易触发的代码EVM是沙盒封装的,并且是完全隔离的,即EVM中运行的代码是无法访问网络、文件系统和其他的进程,甚至合约之间的访问也是相互受到限制合约以字节码格式存在于区块链上合约通常以高级语言(solidity)编写,通过EVM编译器编译为字节码,最终通过客户端部署到区块链网络中EVM和账户以太坊中有两类账户:外部账户和合约账户,他们共用EVM中同一个地址空间无论账户是否存储代码,两类账户对于EVM来说处理方式是一样的每个账户在EVM中都有一个键值队形式的持久化存储。
其中key和value的长度都是256位,称之为存储空间(storage)EVM和交易交易是指一个账户发送到另一个账户的消息,消息包含二进制数据(payload)和以太币如果目标账户含有代码,这个代码就会在EVM中执行,并以payload作为入参,这就是合约的调用如果目标账户是零账户(账户地址是0x000。
),这个交易就会创建一个一个新合约,这个用来创建合约的交易的payload会被转换为EVM字节码并执行,执行的输出作为合约代码永久存储EVM和gas合约被交易触发调用时,指令会在全网的每个节点上执行,这需要消耗算力成本,每一个指令的执行都会有特定的消耗,gas是用来量化表示这个成本的消耗一经创建,每一笔交易都会按照一定数量的gas预支付一笔费用,目的是限制交易所需要的工作量和为交易支付手续费EVM执行交易的时候,gas会按照特定的规则逐渐耗尽gas price是交易发送者设置的一个数值,作为发送者预先支付的手续费的单价,如果交易完成之后,gas还有剩余,会原路返回无论执行到什么位置,一旦gas被耗尽(比如降为负值)将会触发out-of-gas的异常,当前调用帧(call frame)所做的所有状态修改就会回滚EVM数据存储storage每一个账户都会有一个持久化的存储空间,称之为storage,这是一个将256位字映射到256位的key-value存储区,可以理解为合约的数据库永久存储在区块链中,由于永久保存合约状态变量,因此读写的gas开销也是最大的Memory(内存)每一次消息的调用,合约会临时获取一块干净的内存空间生命周期仅为整个方法的执行期间,函数的调用回收,因为仅仅保存临时变量,所以gas的开销较小Stack(栈)EVM不是基于寄存器的,而是基于栈的,因此所有的计算都是在一个被称为栈(stack)的区域执行存放部分局部值类型的变量,几乎免费使用的内存,但是会有数量的限制EVM指令集所有指令都是针对“256位的字”这个基本的数据类型来进行操作具备常用的算数、位、逻辑和比较操作,也可以做到有条件和无条件跳转合约可以访问当前区块的相关属性,比如区块的高度和时间戳消息调用(Massage calls)合约可以通过消息调用的方式来调用其它合约或者发送以太币到非合约账户合约可以决定在其内部的消息调用中,对于剩余的gas,应该发送和保留多少如果在内部消息调用时发生了out-of-gas异常(或者其它任何的异常),这将由一个被压入栈顶的错误值所指明;此时,只有与该内部消息调用一起发送的gas会被消耗掉委托调用(Delegatecall)一种特殊类型的消息调用目标地址的代码将会在发起调用的合约的上下文中执行,并且msg.sender和msg.value 不会变可以由实现“库”(library):可以反复使用的代码库放到一个合约的存储上,通过委托调用引入相应代码合约的创建和自毁通过一个特殊的消息调用create calls,合约可以创建其它合约(不是简简单单的调用零地址)合约代码从区块链上移除的唯一的方式就是合约在合约地址上执行自毁操作selfdestruct;合约账户剩余的以太币会发送指定的目标,然后其存储和代码都会从状态中被移除。
evm指令集扩展原理-回复EVM (Ethereum Virtual Machine) 是以太坊区块链的核心组成部分,负责执行智能合约和处理交易。
EVM 的指令集定义了可执行的指令以及每个指令的操作码和操作数。
EVM 指令集可以通过扩展来增加新的功能和灵活性,这使得开发人员能够更好地满足复杂智能合约的需求。
EVM 指令集扩展原理涉及四个主要方面:指令集设计、操作码定义、操作数处理和虚拟机解析。
接下来,我们将详细介绍这四个方面的内容,以帮助读者更好地理解EVM 指令集扩展的原理和过程。
首先,指令集的设计是EVM 指令集扩展的关键。
在设计指令集时,需要考虑到智能合约的需求以及底层虚拟机的计算能力。
指令集应该具备足够的灵活性和功能扩展性,以满足不同智能合约的需求。
同时,指令集的设计还需要考虑到指令之间的依赖关系和执行的效率。
接下来,操作码的定义是指令集扩展的核心。
每个操作码对应一条指令,定义了指令的具体功能和操作。
操作码的设计和定义应该遵循虚拟机的规范,并考虑到指令的执行效率和资源消耗。
在定义操作码时,需要考虑到指令的输入和输出,以及指令的异常处理和错误处理。
然后,操作数的处理是指令集扩展的关键步骤之一。
操作数是指令的输入和输出,用于指令之间的数据传递和计算。
在处理操作数时,需要考虑到不同数据类型的转换和操作,以及操作数的大小和精度。
操作数的处理需要遵循虚拟机的规范,并保证指令的正确执行和计算结果的准确性。
最后,虚拟机的解析是指令集扩展的最终步骤。
虚拟机负责解析指令集并执行指令。
在解析指令时,虚拟机需要根据操作码和操作数来确定指令的具体功能和操作。
虚拟机还需要考虑到指令的执行顺序和依赖关系,以确保指令的正确执行和计算结果的准确性。
在解析指令时,虚拟机还需要考虑到指令的异常处理和错误处理,以保证指令的执行安全和稳定性。
综上所述,EVM 指令集扩展原理涉及指令集设计、操作码定义、操作数处理和虚拟机解析。
这四个方面共同构成了EVM 指令集扩展的基本原理和过程。
以太坊智能合约原理以太坊智能合约是一种基于区块链技术的编程形式,用于在以太坊网络上执行的自动化合约。
它是使用Solidity编程语言编写的,Solidity是一种面向合约的编程语言,专门用于以太坊智能合约的开发。
以太坊智能合约的原理是基于区块链技术的去中心化特性。
每个以太坊节点都有一个完整的复制账本,称为“状态树”。
智能合约通过在状态树中进行存储和执行,实现了去中心化的交易和合约自动执行。
在以太坊中,智能合约是以一种特殊的交易方式进行部署的。
智能合约在部署时会生成一个唯一的合约地址,该地址用于标识该合约在区块链中的位置。
一旦部署完成,智能合约就可以被其他用户通过发送交易来调用。
智能合约的执行是通过以太坊虚拟机(Ethereum Virtual Machine,EVM)来实现的。
EVM是以太坊网络上的一个虚拟计算机,能够执行以太坊智能合约的字节码指令。
智能合约具有与传统合约相似的特性,如自动执行和条件触发。
但与传统合约不同的是,以太坊智能合约是以代码的形式存在的,因此具有更高的可编程性和可扩展性。
智能合约可以在以太坊上执行复杂的逻辑,并根据事先设定的条件自动执行相应的操作。
以太坊智能合约的执行是通过矿工节点验证和打包交易的方式实现的。
当用户发送交易来调用智能合约时,矿工节点会将该交易验证并打包到一个区块中。
一旦区块被其他节点验证通过,并添加到区块链上,智能合约的执行结果就会被确定下来,并在整个网络上可见。
总结而言,以太坊智能合约是基于区块链技术的自动化合约,通过Solidity语言编写,并在以太坊网络上执行。
它利用区块链的去中心化特性,借助以太坊虚拟机的支持实现智能合约的自动化执行。
它具有高度的可编程性和可扩展性,为实现各种复杂逻辑的自动化服务提供了可能。
以太坊的技术原理和应用以太坊是一种开源的分布式计算平台,它使用了区块链技术来实现去中心化的智能合约系统。
以太坊的目标是成为一个全球化的通用计算机,每个人都能够在上面开发和运行各种应用程序。
本文将介绍以太坊的技术原理和应用。
一、以太坊的技术原理以太坊的机制与比特币类似,都是通过共识算法来实现交易的确认和区块的建立。
比特币使用的是POW(Proof of Work)算法,而以太坊则使用的是POS(Proof of Stake)算法。
在POS算法中,每个区块的记账节点是由所有参与者中抽取的,这意味着将更多的权力投入到了普通用户手中,可以更好地保证整个系统的安全性。
以太坊的智能合约是其最大的特色之一。
智能合约是一种基于代码的自动执行机制,类似于现实世界中的合约。
智能合约的执行结果是不可更改的,具有高度的可靠性。
以太坊的智能合约可以实现各种复杂的功能,如数字货币的发行、授权的管理、物联网设备的控制等。
以太坊的去中心化应用(Dapp)是建立在智能合约基础上的,其核心是去中心化的协议。
协议可以被看作是一种规则,它用于协调参与者之间的交互和通信。
在以太坊中,协议由智能合约实现,并通过分布式网络向所有节点广播。
去中心化应用利用这些协议来实现不同的功能,如去中心化交易所、去中心化的社交网络、去中心化的资金管理平台等。
二、以太坊的应用1.加密货币以太坊是数字货币的原生网络,它的基石是以太币(Ether)。
以太币是在以太坊网络上进行的交易和智能合约的运行的一种内部货币。
以太坊的设计者旨在创建一种比比特币更灵活、更可扩展的数字货币。
2.身份认证身份认证是一个具有挑战性的领域,以太坊可以借助智能合约和去中心化的标识来解决这个问题。
以太坊的Ethereum Name Service(ENS)是一种去中心化的域名服务,它可以将一个易于记忆的域名与一个以太坊地址相关联。
ENS可以使身份认证更加便捷和安全。
3.预测市场以太坊可以与预测市场结合,这意味着用户可以通过投注赌注来预测某些事件是否会发生。
前言以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台,通过其专用加密货币以太币(ETH)提供去中心化的以太坊虚拟机(EVM)来处理点对点合约。
EVM(Ethereum)虚拟机),以太坊虚拟机的简称,以太坊的核心之一。
智能合约的创建和执行都由EVM来完成,简单来说,EVM是一个状态执行的机器,输入是solidity编译后的二进制指令和例程的状态数据,输出是异步状态的改变。
以太坊短地址攻击,最初由Golem团队于2017年4月提出,是由于EVM的设计缺陷导致的突破。
ERC20代币标准定义的转账函数如下:function transfer(address to uint256 value) public returns (bool success)如果前缀的to是末尾前缀的短地址,则EVM在后面字节补足地址,而最后的value值不足则用0填充,导致实际转出的代币数值倍增。
本文从以太坊原始代码的角度分析EVM重叠是如何处理执行智能合约字节码的,并简要分析短地址攻击的原理。
EVM原始分析evm.goEVM源码的位于go-ethereum/core/vm/目录下,在evm.go中定义了EVM结构体,并实现了EVM.Call,EVM.CallCode,EVM.DelegateCall,EVM.StaticCall四种方法来调用智能合约,EVM.Call实现了基本的合约调用的功能,三种后面与方法EVM.Call略有区别,但最终都调用run函数来解析执行智能合约EVM呼叫// Call executes the contract associated with the addr with the given input as// parameters. It also handles any necessary value transfer required and takes// the necessary steps to create accounts and reverses the state in case of an// execution error or failed value transfer.//hunya// 基本的合约调用func (evm *EVM) Call(caller ContractRef addr common.Address input []byte gas uint64 value*big.Int) (ret []byte leftOverGas uint64 err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil gas nil }// Fail if we're trying to execute above the call depth limitif evm.depth > int(params.CallCreateDepth) { return nil gas ErrDepth } // Fail if we're trying to transfer more than the available balanceif !evm.Context.CanTransfer(evm.StateDB caller.Address() value) { return nil gas ErrInsufficientBalance }var ( to = AccountRef(addr) snapshot = evm.StateDB.Snapshot() )if !evm.StateDB.Exist(addr) { precompiles := PrecompiledContractsHomestead ifevm.chainRules.IsByzantium { precompiles = PrecompiledContractsByzantium } if evm.chainRules.IsIstanbul { precompiles = PrecompiledContractsIstanbul } if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 { // Calling a non existing account don't do anything but ping the tracerif evm.vmConfig.Debug && evm.depth == 0{ evm.vmConfig.Tracer.CaptureStart(caller.Address() addr false input gas value) evm.vmConfig.Tracer.CaptureEnd(ret 0 0 nil) } return nil gas nil }evm.StateDB.CreateAccount(addr) } evm.Transfer(evm.StateDB caller.Address() to.Address() value) // Initialise a new contract and set the code that is to be used by the EVM.// The contract is a scoped environment for this execution context only.contract := NewContract(caller to value gas) contract.SetCallCode(&addrevm.StateDB.GetCodeHash(addr) evm.StateDB.GetCode(addr))// Even if the account has no code we need to continue because it might be a precompilestart := time.Now()// Capture the tracer start/end events in debug mode// debug模式会捕获tracer的start/end事件if evm.vmConfig.Debug && evm.depth == 0{ evm.vmConfig.Tracer.CaptureStart(caller.Address() addr false input gas value)defer func() { // Lazy evaluation of the parametersevm.vmConfig.Tracer.CaptureEnd(ret gas-contract.Gas time.Since(start) err) }() }ret err = run(evm contract input false)//hunya// 调用run函数执行合约// When an error was returned by the EVM or when setting the creation code// above we revert to the snapshot and consume any gas remaining. Additionally// when we're in homestead this also counts for code storage gas errors.if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { eGas(contract.Gas) } } return ret contract.Gas err}EVM.CallCode// CallCode executes the contract associated with the addr with the given input// as parameters. It also handles any necessary value transfer required and takes// the necessary steps to create accounts and reverses the state in case of an// execution error or failed value transfer.//// CallCode differs from Call in the sense that it executes the given address'// code with the caller as context.//hunya// 类似solidity中的call函数,调用外部合约,执行上下文在被调用合约中func (evm *EVM) CallCode(caller ContractRef addr common.Address input []byte gas uint64 value *big.Int) (ret []byte leftOverGas uint64 err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil gas nil }// Fail if we're trying to execute above the call depth limitif evm.depth > int(params.CallCreateDepth) { return nil gas ErrDepth } // Fail if we're trying to transfer more than the available balanceif !evm.CanTransfer(evm.StateDB caller.Address() value) { return nil gas ErrInsufficientBalance }var ( snapshot = evm.StateDB.Snapshot() to = AccountRef(caller.Address()) ) // Initialise a new contract and set the code that is to be used by the EVM.// The contract is a scoped environment for this execution context only.contract := NewContract(caller to value gas) contract.SetCallCode(&addrevm.StateDB.GetCodeHash(addr) evm.StateDB.GetCode(addr))ret err = run(evm contract input false)//hunya// 调用run函数执行合约if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { eGas(contract.Gas) } } return ret contract.Gas err}EVM.DelegateCall// DelegateCall executes the contract associated with the addr with the given input// as parameters. It reverses the state in case of an execution error.//// DelegateCall differs from CallCode in the sense that it executes the given address'// code with the caller as context and the caller is set to the caller of the caller.//hunya// 类似solidity中的delegatecall函数,调用外部合约,执行上下文在调用合约中func (evm *EVM) DelegateCall(caller ContractRef addr common.Address input []byte gas uint64) (ret []byte leftOverGas uint64 err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil gas nil } // Fail if we're trying to execute above the call depth limitif evm.depth > int(params.CallCreateDepth) { return nil gas ErrDepth }var ( snapshot = evm.StateDB.Snapshot() to = AccountRef(caller.Address()) )// Initialise a new contract and make initialise the delegate valuescontract := NewContract(caller to nil gas).AsDelegate() contract.SetCallCode(&addrevm.StateDB.GetCodeHash(addr) evm.StateDB.GetCode(addr))ret err = run(evm contract input false)//hunya// 调用run函数执行合约if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { eGas(contract.Gas) } } return ret contract.Gas err}EVM.StaticCall// StaticCall executes the contract associated with the addr with the given input// as parameters while disallowing any modifications to the state during the call.// Opcodes that attempt to perform such modifications will result in exceptions// instead of performing the modifications.//hunya// 与EVM.Call类似,但不允许执行会修改永久存储的数据的指令func (evm *EVM) StaticCall(caller ContractRef addr common.Address input []byte gas uint64) (ret []byte leftOverGas uint64 err error) { if evm.vmConfig.NoRecursion && evm.depth > 0{ return nil gas nil } // Fail if we're trying to execute above the call depth limitif evm.depth > int(params.CallCreateDepth) { return nil gas ErrDepth }var ( to = AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) // Initialise a new contract and set the code that is to be used by the EVM.// The contract is a scoped environment for this execution context only.contract := NewContract(caller to new(big.Int) gas) contract.SetCallCode(&addrevm.StateDB.GetCodeHash(addr) evm.StateDB.GetCode(addr))// We do an AddBalance of zero here just in order to trigger a touch.// This doesn't matter on Mainnet where all empties are gone at the time of Byzantium// but is the correct thing to do and matters on other networks in tests and potential// future scenariosevm.StateDB.AddBalance(addr bigZero)// When an error was returned by the EVM or when setting the creation code// above we revert to the snapshot and consume any gas remaining. Additionally// when we're in Homestead this also counts for code storage gas errors.ret err = run(evm contract input true)//hunya// 调用run函数执行合约if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { eGas(contract.Gas) } } return ret contract.Gas err}run函数前半段是判断是否基于太坊内置预编译的特殊合约,有单独的运行方式后半段则是对于一般的合约调用解释器interpreter去执行调用[MISSING IMAGE: , ]interpreter.go解释器相关代码在interpreter.go中,interpreter是一个接口,目前只有EVMInterpreter这一个具体实现[MISSING IMAGE: , ]合约EVM.Call汇率引入Interpreter.Run来到EVMInpreter.RunEVMInterpreter的Run方法代码编码,其中处理执行合约字节码的主循环如下:[MISSING IMAGE: , ]大部分代码主要是检查准备运行环境,执行合约字节码的核心代码主要是以下3行op = contract.GetOp(pc)operation := in.cfg.JumpTable[op]......res err = operation.execute(&pc in contract mem stack)......interpreter的主要工作实际上只是通过JumpTable查找指令,从而实现一个翻译解析的作用最终的执行是通过调用operation对象的execute方法jump_table.gooperation的定义放在jump_table.go中[MISSING IMAGE: , ]jump_table.go中还定义了JumpTable和多种不同的指令集[MISSING IMAGE: , ]在基本指令集中有三个处理input的指令,分别是CALLDATALOAD,CALLDATASIZE和CALLDATACOPY[MISSING IMAGE: , ]jump_table.go中的代码同样只是决议解析的功能,提供了指令的查找,定义了每个指令具体的执行函数Instructions.goinstructions.go中是所有指令的具体实现,上述三个函数的具体实现如下:[MISSING IMAGE: , ]这三个函数的作用分别是从input加载参数入栈,获取input大小,复制input中的参数到内存我们重点关注opCallDataLoad函数是如何处理input中的参数入栈的opCallDataLoad函数调用getDataBig函数,预期contract.Input,stack.pop()和big32,将结果转为big.Int入栈[MISSING IMAGE: , ]getDataBig函数以stack.pop()栈顶元素作为初始索引,截取input中big32大小的数据,然后初始化common.RightPadBytes处理并返回其中涉及到的另外两个函数math.BigMin和common.RightPadBytes如下://file: go-thereum/common/math/big.gofunc BigMin(x y *big.Int) *big.Int { if x.Cmp(y) > 0 { return y } return x}//file: go-ethereum/common/bytes.gofunc RightPadBytes(slice []byte l int) []byte { if l <= len(slice) { return slice } //右填充0x00至l位padded := make([]byte l) copy(padded slice)return padded}分析到这里,基本上已经能很明显看到问题所在了RightPadBytes会将函数传入的字节切片向左向右填充至l位长度,而l的英文被传入的big32,即32位长度所以在短地址攻击中,调用的transfer(address to uint256 value)函数,如果to是低位更改的地址,由于EVM在处理时是固定截取32位长度的,因此重复value数值高位补的0算进to的末端,而在截取value时由于位数不足32位,则右填充0x00至32位,最终导致转账的value 指数级增长测试与复现编写一个简单的合约来测试pragma solidity ^0.5.0;contract Test { uint256 internal _totalSupply;mapping(address => uint256) internal _balances;event Transfer(address indexed from address indexed to uint256 value);constructor() public { _totalSupply = 1 * 10 ** 18; _balances[msg.sender] =_totalSupply; }function totalSupply() external view returns (uint256) { return _totalSupply; }function balanceOf(address account) external view returns (uint256) { return_balances[account]; }function transfer(address touint256 value) public returns (bool) { require(to != address(0)); require(_balances[msg.sender] >= value); require(_balances[to] + value >= _balances[to]);_balances[msg.sender] -= value; _balances[to] += value; emit Transfer(msg.sender to value); }}混音部署,调用transfer发起正常的转账[MISSING IMAGE: , ]input为0xa9059cbb00000000000000000000000071430fd8c82cc7b991a8455fc6ea5b37a06d393f000000000 0000000000000000000000000000000000000000000000000000001直接尝试短地址攻击,减少去转账地址的后两位,会发现并不能通过,remix会直接报错[MISSING IMAGE: , ]这是因为web3.js做了验证,web3.js是用户与以太坊互连相互的中介原始码复现通过二进制函数复现如下:[MISSING IMAGE: , ]实际复现根据如何完成实际场景的攻击,可以参考文末的链接[1],利用web3.eth.sendSignedTransaction绕过过限制实际上,web3.js做的校准仅在显着式转移转账地址的函数,如web3.eth.sendTransaction这种,像web3.eth.sendSignedTransaction,web3.eth.sendRawTransaction这种指向的参数是序列化后的数据的就校正不了,是可以完成短地址攻击的,兴趣的可以自己尝试,这里就不多写了PS:文中分析的go-ethereum原始码版本是commit-fdff182,原始码与最新版本有些出入,但最新版本的也未修复这种缺陷(可能官方不认为这是缺陷?),分析思路依然可以沿用思考以太坊曾经EVM并没有修复短地址攻击的这么一个缺陷,而是直接在web3.js里对地址做的校验,目前各种合约或多或少也做了弥补,所以虽然EVM可能可以复现,但实际场景中问题应该不大,但如果是开放RPC的中断可能还是会存在这种风险另外还有一个点,按一下EVM的这种机制,易受攻击的应该换一个transfer(address touint256 value)这个点,只是因为这个函数是ERC20代币标准,而且参数的设计恰好能导致涉及金额的短地址攻击,并且在其他的一些非代币合约,如竞猜,游戏类的合约中,一些非转账类的事务处理函数中,如果不对类似地址这,种的参数做长度校正,可能也存在类似的短地址攻击的风险,也可能并不重复地址,可能还有其他的利用方式还没挖掘出来。