继上篇文章之后,我们继续说说助记词靓号钱包的事情(话说Cocoa到底对靓号有多执着啊……
1.一点背景
这篇文章的起因是余弦大大提到了一例钱包被盗案,主要原因是受害者在一个钓鱼网站输入了助记词,导致了该助记词下2个钱包内的余额被盗。
上篇文章提到使用Profanity2工具生成靓号地址,最后得到的是钱包地址和对应的私钥,并不是助记词。
而大家知道,Metamask等工具在生成钱包时,首先会生成助记词,然后默认生成一个其钱包地址(Metamask叫账户)。如果有需要,可以点击“创建账户”按钮,继续创建第二个、第三个等等钱包地址,这些钱包地址都有各自的私钥。
那么助记词和私钥有什么关系呢?为什么助记词丢失,会导致Metamask下的所有钱包都被盗呢?
2.分层确定性钱包(HD Wallet)
这里就涉及到一个概念“分层确定性钱包”(Hierarchical Deterministic Wallet,简称叫HD Wallet或者HD钱包)。
HD钱包的核心来自于三个标准:BIP32、BIP44、BIP39。这里BIP的意思是Bitcoin Improvement Proposals(比特币改进提案),类似于网络领域的RFC标准。
这三个标准具体内容有兴趣的朋友可以搜一下,我这里简单总结一下:
- BIP32:通过一个随机数(被称为种子seed),按照事先确定的算法,派生出大量的私钥。这样一来,只要保管好种子,就可以管理成千上万的地址,降低的维护的成本。顺便一提,BIP32 的名称直接就叫做“分层确定性钱包”。
- BIP44:这是对BIP32的改进,在原有只支持比特币的基础上,通过在钱包内部规定路径path的方式,使钱包可以支持多条公链(如狗狗币、莱特币、以太坊等),进一步拓展了HD钱包的应用范围。例如:Metamask上以太坊的path就是m/44’/60’/0’/0/x,其中x就代表是第几个账户。
- BIP39:继续对HD钱包进行改进:由于种子冗长难记,BIP39提出了助记词的概念,将seed转换为12个或24个单词(也可以是日文、韩文甚至中文,只不过现在英文用的较多),叫做助记词。这样只要人类记住12个单词,就可以通过程序将助记词转化为种子seed,再通过种子seed根据不用路径path生成不同币种的私钥,这样就完成了从助记词到比特币、以太坊、狗狗币等各类钱包地址的逐级转化。
总结一下,HD钱包生成以太坊地址(或者账号)的步骤就是:1.先按照BIP32要求生成种子,2.根据BIP39将种子转化为人类可读的助记词,3.通过种子产生多个以太坊私钥,从而派生出对应的地址。
其中种子和助记词其实本质是一样的,因此就不难理解上面兄弟遇到的问题:丢失了助记词后,由助记词产生(其实是种子产生)的多个以太坊地址都失窃了。
3.生成助记词靓号地址
知道了原理,我们就可以通过不停枚举助记词(其实是种子),来暴力搜索靓号地址了。
找了一下好像没有现成的工具,没关系,毛主席教导我们:自己动手,丰衣足食。
这里以Cocoa熟悉的Python为例,nodejs和java也有类似库可以参考。
首先要用到一个叫hdwallet的库,它里面已经集成好了HD钱包所需的BIP标准相关代码。如果是Python 3.10以下版本,直接使用如下命令安装即可。如果是最新的Python 3.11,会遇到一些问题报错,后面有机会再聊。
pip install hdwallet
安装完成后,直接在代码里引入即可。
#!/usr/bin/env python3
from multiprocessing import Pool
from hdwallet import BIP44HDWallet
from hdwallet.cryptocurrencies import EthereumMainnet
from hdwallet.derivations import BIP44Derivation
from hdwallet.utils import generate_mnemonic
from typing import Optional
#线程数,一般几核CPU写几
THREAD_NUM = 6
#靓号地址前缀
PREFIX = '0xc0c0a'
#靓号地址后缀
SUFFIX = '8'
def to_work():
while 1:
# Generate english mnemonic words
MNEMONIC: str = generate_mnemonic(language="english", strength=128)
# Secret passphrase/password for mnemonic
PASSPHRASE: Optional[str] = None # "meherett"
# Initialize Ethereum mainnet BIP44HDWallet
bip44_hdwallet: BIP44HDWallet = BIP44HDWallet(cryptocurrency=EthereumMainnet)
# Get Ethereum BIP44HDWallet from mnemonic
bip44_hdwallet.from_mnemonic(
mnemonic=MNEMONIC, language="english", passphrase=PASSPHRASE
)
# Clean default BIP44 derivation indexes/paths
bip44_hdwallet.clean_derivation()
# Derivation from Ethereum BIP44 derivation path
bip44_derivation: BIP44Derivation = BIP44Derivation(
cryptocurrency=EthereumMainnet, account=0, change=False, address=0
)
# Drive Ethereum BIP44HDWallet
bip44_hdwallet.from_path(path=bip44_derivation)
wallet_address=bip44_hdwallet.address()
# 这里的例子是生成一个c0c0a开头8结尾的靓号地址,注意开头的0x不要忘记
if (wallet_address.startswith(PREFIX) and wallet_address.endswith(SUFFIX)):
print("Mnemonic:", bip44_hdwallet.mnemonic())
print(f"{bip44_hdwallet.path()} {wallet_address} 0x{bip44_hdwallet.private_key()}")
# Clean derivation indexes/paths
bip44_hdwallet.clean_derivation()
def main():
po = Pool(THREAD_NUM)
for i in range(THREAD_NUM):
po.apply_async(to_work)
po.close()
po.join()
if __name__ == "__main__":
main()
这是一个简单的demo版本,主体部分是根据hdwallet的官方示例代码修改的,增加了靓号判断逻辑和多线程。
后续也有改进优化的地方,比如增加EIP 55大小写校验机制(可以生成自定义大小写的靓号地址)、找到一个地址后自动停止运行(现在除非手动结束会一直跑)、改造成GPU显卡加速等等。感兴趣的朋友可以自己试试。
跪求改进代码,辛苦了偶像!
您好!
用记下的助记词导出,得到另一钱包。
能根据钱包地址生成正确的助记词吗?
不好意思,没太听懂,记下的什么助记词?为什么得到另一钱包了?