SUI交互之suins域名注册参数逆向分析及脚本验证
开发语言:go
Discord交流: Link
Twitter:@ananpt0
首先我们手动注册个域名,然后去Sui Explorer查看记录:


第一次调用了合约0xf6d55ad60e110c1faf2b54c1824df19481536fd5的 base_controller模块的make_commitment_and_commit函数,该函数我们看到有两个参数,第一个是个地址字符串,第二个是个整型数组。
我们继续分析这两个参数含义,点击base_controller去到合约详情页查看合约Bytecode,找到make_commitment_and_commit函数定义:
entry public make_commitment_and_commit(Arg0: &mut BaseController, Arg1: vector, Arg2: &mut TxContext)
第一个参数为BaseController的Object ID
第二个参数是个vector,暂时还不知道是怎么生成的,这个时候我们来调试下前端,看这个参数是怎么生成并传给钱包的。
在合约Bytecode中我们看下虚拟机字节码,看到make_commitment有调用keccak256函数,我们去前端js里面搜索下看看,通过搜索我们发现在main.xxx.js中我们找到一个keccak_256调用:
我们在这一行下断点,然后点击“Register name”按钮试试,成功断下,然后我们可以发现,keccack_256参数为一个Uint8Array,由申请域名字符串+钱包地址(去除0x后16进制数组)+15位字符串,此时15位字符串我们还不知道是怎么生成的,我们可以通过调用栈回溯来找到生成的地方:
点击A下面那个匿名函数:
我们可以发现这个15位字符串是用过y.We.internet.password()生成的15位随机字符串。
所以第一个Transaction两个参数为:BaseController的Object ID,keccak256后的结果int数组。
接下来我们看看第二个Transaction:
第一步还是查看Sui Explorer记录,找到Bytecode中register函数
entry public register(Arg0: &mut BaseController, Arg1: &mut BaseRegistrar, Arg2: &mut Registry, Arg3: &Configuration, Arg4: vector<u8>, Arg5: address, Arg6: u64, Arg7: vector<u8>, Arg8: Coin<SUI>, Arg9: &mut TxContext)可以看出前4个参数分别为BaseController,BaseRegistrar(sui、move后缀的地址不一样),Registry,Configuration地址,第5个参数为注册的域名去除后缀,第6个参数为注册钱包地址,第7个参数为注册期限(一年的为365),第8个参数为15位随机字符串(第一个Transaction生成的15位随机字符串),最后一个为SUI Coin地址。
到此基本上我们已经完成了参数定义的分析,最后我们用代码来测试看看:
package main import ( "encoding/hex" "errors" "fmt" "github.com/coming-chat/go-sui/account" "github.com/coming-chat/go-sui/client" "github.com/coming-chat/go-sui/types" "golang.org/x/crypto/sha3" "golang.org/x/net/context" "math/rand" "net/url" "time" ) const DevnetRpcUrl = "https://fullnode.devnet.sui.io" var bytes []byte = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_") var (//地址通过https://explorer.sui.io查找替换 PackageID = "0xb43d7bd4394766de04ff82b8214aa8814de69a04" BaseController = "0x50ac890157d0bfda1be5d2e2a0739e75a64281c7" SUIBaseRegistrar = "0x4e2ce97c434f449785bbdce745d418c08d9f1a7f"//sui后缀 MoveBaseRegistrar = "0xdcea9fe45615172f4d2c3c74a4ed76c565014fa"//move后缀 Registry = "0x79af4acd5d1d70fbb29b724b5060c67063cae83c" Configuration = "0x1ea0f7ae66fb52e4b51dc89fe9b02e3767a9d15f" ) func init() { rand.Seed(time.Now().UnixNano()) } func RandStr(n int) string { result := make([]byte, n) for i := 0; i < n; i++ { result[i] = bytes[rand.Int31()%63] } return string(result) } func Hash(data ...[]byte) []int { hash := sha3.NewLegacyKeccak256() for _, d := range data { hash.Write(d) } hashBytes := hash.Sum(nil) intSlice := make([]int, len(hashBytes)) for i, b := range hashBytes { intSlice[i] = int(b) } return intSlice } func MakeCommitment(domain, address, solt string) []int { tmp := make([]byte, 0) tmp = append(tmp, []byte(domain)...) addr, _ := hex.DecodeString(address) tmp = append(tmp, addr...) tmp = append(tmp, []byte(solt)...) return Hash(tmp) } func MakeCommitmentAndCommit(client *client.Client, ctx context.Context, signer types.Address, commitment []int, gas *types.ObjectId, gasBudget uint64) (*types.TransactionBytes, error) { packageId, _ := types.NewAddressFromHex(PackageID) args := []any{ BaseController, commitment, } return client.MoveCall(ctx, signer, *packageId, "base_controller", "make_commitment_and_commit", args, gas, gasBudget) } func MakeCommit(mnemonic, domain string) (*types.Base64Data, string, error) { acc, _ := account.NewAccountWithMnemonic(mnemonic) signer, _ := types.NewAddressFromHex(acc.Address) addr := acc.Address[2:]//去除0x randStr := RandStr(15) hash := MakeCommitment(domain, addr, randStr) suiClient, err := client.Dial(DevnetRpcUrl) if err != nil { return nil, "", err } gasBudget := uint64(100000) txnBytes, err := MakeCommitmentAndCommit(suiClient, context.Background(), *signer, hash, nil, gasBudget) if err != nil { return nil, "", err } signedTxn := txnBytes.SignWith(acc.PrivateKey) txnResponse, err := suiClient.ExecuteTransaction(context.Background(), *signedTxn, types.TxnRequestTypeWaitForLocalExecution) if err != nil { return nil, "", err } return txnResponse.EffectsCert.Effects.Effects.TransactionDigest, randStr, nil } func Register(client *client.Client, ctx context.Context, signer types.Address, register, domain, address string, day int, randStr string, coinID string, gas *types.ObjectId, gasBudget uint64) (*types.TransactionBytes, error) { packageId, _ := types.NewAddressFromHex(PackageID) args := []any{ BaseController, register, Registry, Configuration, domain, address, day, randStr, coinID, } return client.MoveCall(ctx, signer, *packageId, "base_controller", "register", args, gas, gasBudget) } func DoRegister(mnemonic, domain, suffix, randStr string) (*types.Base64Data, error) { acc, _ := account.NewAccountWithMnemonic(mnemonic) signer, _ := types.NewAddressFromHex(acc.Address) suiClient, err := client.Dial(DevnetRpcUrl) if err != nil { return nil, err } gasBudget := uint64(1000000) reg := "" if suffix == "sui" { reg = SUIBaseRegistrar } else if suffix == "move" { reg = MoveBaseRegistrar } else { return nil, errors.New("err suffix") } txnBytes, err := Register(suiClient, context.Background(), *signer, reg, domain, acc.Address, 365, randStr, "COIN_OBJECT_ID", nil, gasBudget)//COIN_OBJECT_ID替换为你钱包中SUI Coin对象ID if err != nil { return nil, err } signedTxn := txnBytes.SignWith(acc.PrivateKey) txnResponse, err := suiClient.ExecuteTransaction(context.Background(), *signedTxn, types.TxnRequestTypeWaitForLocalExecution) if err != nil { return nil, err } return txnResponse.EffectsCert.Effects.Effects.TransactionDigest, nil } func main() { domain := ""//你要注册的域名名称 suffix := "sui"//sui或者move后缀 fmt.Printf("[+][suins]注册域名:%s.%s\n", domain, suffix) mnemonic := ""//钱包助记词 if tid, randStr, err := MakeCommit(mnemonic, domain+"."+suffix); err != nil { fmt.Println("[+]", err) } else { fmt.Printf("[+]make_commitment_and_commit done! Check https://explorer.sui.io/transactions/%s\n", url.QueryEscape(tid.String())) if rid, err := DoRegister(mnemonic, domain, suffix, randStr); err != nil { fmt.Println("[+]", err) } else { fmt.Printf("[+]register done! Check https://explorer.sui.io/transactions/%s\n", url.QueryEscape(rid.String())) } } }成功注册






