智能合约

详细探讨栈溢出原理以及x86-32架构下函数调用中的栈帧变化。

Smart Contract

研究对象————Etheremu

Etheremu基础知识

账户

  • 外部账户(EOA)
    • 外部账户是由人创建的,可以存储以太币,是由公钥和私钥控制的账户。每个外部账户拥有一对公私钥,这对密钥用于签署交易,它的地址由公钥决定。外部账户不能包含以太坊虚拟机(EVM)代码。
    • 一个外部账户有以下特性:
      • 拥有一定的Ether
      • 可以发送交易,由私钥控制
      • 没有相关联的代码
  • 合约账户
    • 合约账户是由外部账户创建的账户,包含合约代码。合约账户的地址是由合约创建时合约创建者的地址,以及该地址发出的交易共同计算得出的。
    • 一个合约账户有以下特性
      • 拥有一定的Ether
      • 有关联代码,代码通过交易或其他合约发来的调用激活
      • 当合约被执行时,只能操作合约账户的特定存储
  • 在Etheremu中,这两种账户统称为“状态对象”,其中外部账户存储以太币余额状态,而合约账户除了余额还有智能合约及其变量的状态。通过交易的执行,这些状态对象发生变化,而 Merkle 树用于索引和验证状态对象的更新。一个以太坊的账户包含 4 个部分
    • nonce: 已执行交易总量
    • balance: 帐持币数量
    • storageRoot: 存储区哈希值
    • codeHash: 代码区哈希值
  • 两个外部账户之间的交易只是一个价值转移;而外部账户和合约账户之间的交易会激活合约账户的代码,允许进行各种操作

交易

  • 交易指的是外部账户发送到另一账户的的消息的签名数据包
  • 交易内容
    • from: 交易发送者地址
    • to: 交易接收者地址,如果为空代表创建或调用智能合约
    • value: 转移的以太币数量
    • data: 数据字段,如果存在,说明是一个创建或调用智能合约的交易
    • gaslimit: 交易允许消耗的最大gas数量
    • gasprice: 愿意发送给gas矿工的单价
    • nonce: 区分同一账户的不容交易的标记
    • hash: 以上信息生成的散列值
    • r,s,v: 签名信息
  • 交易类型:
    • 执行转账的交易
    • 创建智能合约的交易
    • 调用智能合约的交易

RPC

  • JSON-RPC是一种无状态、轻量级的远程过程调用(RPC)协议。它定义了几种数据结构及处理规则。用于实现软件应用程序与Etheremu区块链的交互

转账

  • 操作过程:
    • 生成一个交易,使用私钥签名
    • 被签名的交易被广播到P2P网络
    • 矿工将交易包含在一个块中
    • 确认资金转账

燃料(Gas)

  • 需要设置Gas的原因: 处理停机问题(无限循环)
  • Gas limit: 用户单次交易的gas上限
  • Gas price: Gas的当前单价,在交易前由用户设置,以Wei为单位
  • 交易费用: Gas*Gas_price
  • Gas消耗:
    • 对于一般交易,消耗为21000
    • 对于智能合约,取决于消耗的资源————执行的命令和使用的存储

EVM

  • 每个Etheremu节点都包含一个虚拟机,该虚拟机被称为EVM,发挥执行智能合约代码和更改并广播全局状态的作用
  • 特性:
    • 图灵完备性(存在Gas限制)
    • 无浮点数
    • 无系统时钟
  • 核心设计目标:
    • 确定性: 保证相同的输入必定有相同的输出
    • 隔离性: 合约在沙盒环境中运行,不直接访问主机系统
    • 可终止性: 通过Gas限制执行步骤
  • 结构:
    • 基于堆栈
      • 注: 栈式架构特点
        • 所有计算依赖操作数栈
        • 没有通用寄存器
        • 指令隐式操作栈
  • 内存模型:
      • 结构
        • 2字节,最深1024层
        • 易失性
    • 内存
      • 结构
        • 按字寻址的字节数组,可动态扩展
        • 易失性
      • 操作指令
        • mload(offset): 从内存偏移量处读32字节
        • mstore(offset,value): 将32字节value写入偏移量offset
      • Gas成本: 初始免费,扩容时按每32字节支付Gas
    • 存储
      • 结构
        • 每个合约有独立的持久化键值存储
        • 映射规则: 2^256个键,每个键对应一个32字节的值
      • 特性
        • 持久化: 数据永久写入区块链状态
        • 高Gas成本: 写入消耗成千乃至上万Gas
      • 操作指令
        • sstore(key,value): 从栈上依次弹出valuekey,将value存入存储中key对应的槽位
        • sload(key): 从栈顶弹出key,将存储中key对应的槽位的数据压入栈

代币合约

ERC-20代币合约

  • ERC-20是一种通用的智能合约规范,特点是每一个代币都和其他代币完全相等。它是资产通证化的最广泛使用标准
  • 包含API方法和事件
    • totalSupply: 定义token总供应量
    • balancdOf: 返回钱包地址包含的token余额
    • transfer: 从总供应中转移一定数量token并发给用户
    • transferFrom: 在用户之间传输token
    • approve: 验证是否允许在考虑总供应量的情况下分配一定的token
    • allowance: 检查是否有余额向另一个账户发送token

Uniswap

  • Uniswap是一个完成不同代币间的交易的自动化流动协议
  • 注:自动化流动协议定义
    • 自动化流动性协议是一种利用预定义的数学公式(如恒定乘积公式)和部署在区块链上的智能合约,自动管理用户贡献的资产池(流动性池),并为用户提供无需许可、去中心化、自动定价和执行的代币交换服务的系统。它完全消除了对传统订单簿和专业做市商的依赖,通过算法和社区提供的流动性实现市场功能。
  • 每个(或对)Uniswap智能合约管理着一个由两个ERC-20代币储备组成的流动池
  • 任何人都可以成为池的流动性提供者(LP),即存入基础代币来换取池代币
  • 在池中维持价格:套利
  • 货币对充当市商的角色,根据恒定乘积公式提供替换服务
  • 恒定乘积公式可以简单地表示为$x * y = k$,说明交易不能改变一对储备余额的乘积
  • $k$通常被称为不变量。这个公式对规模较大的交易的执行速度比小的要慢得多
  • 在实践中Uniswap对交易收取0.30%的费用,这笔费用被存入储备中

ERC-777代币合约

  • 被ERC-20类似,ERC-777也是一种可替换代币标准,交易时允许更复杂的交互
  • 它的最重要功能是接收hook

Etheremu安全漏洞和攻击方式

重进入攻击

  • 核心漏洞:“先提款后记账”
  • 具体实现:在提款函数(withdraw)中递归调用,在记录的存款变化前反复提取存款
  • 防御方式:
    • 检查-效果-交互模式: 按照执行检查、改变状态变量、执行与其他合同的交互的顺序运行
    • 使用修饰符锁定(互斥锁): 即设置一个标识符,当发生与其他合同交互时设置标识符,标识符重置1前无法再进行交互

调用与委托调用攻击

基本概念:调用与委托调用
  • 调用: 调用另一个智能合约中的函数
  • 委托调用: 执行来自另一个智能合约的函数,使用调用者的存储和上下文
UUPS(通用可升级代理标准)
  • 架构: 代理合约拆分

    • 示意图

    UUPSUUPS

    • 代理合约(Proxy)
      • 永久储存所有状态变量
      • 持有逻辑合约地址
      • 通过fallback函数将所有调用用delegatecall转发给逻辑合约
    • 逻辑合约(Logic)
      • 包含实际业务代码
      • 无状态
      • 可被替换(升级)
UUPS漏洞: 未初始化
  • 如果UUPS合同未初始化,那么攻击者可以调用initialize()函数,实现“攻击者成为所有者”
  • 攻击步骤
    • 攻击者成为所有者
    • 部署恶意合约
    • 劫持升级过程
    • 执行恶意代码
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计