在 Fomo3D 遊戲中的中主合約 FoMo3dlong,具體代碼見 :

https://etherscan.io/address/0xa62142888aba8370742be823c1782d17a0389da1

存在訪問一個外部接口的數據

uint256 private rndExtra_= extSettings.getLongExtra();

uint256 private rndGap_= extSettings.getLongGap();

非常可惜,對於 extSettings 的合約地址:

https://etherscan.io/address/0x32967d6c142c2f38ab39235994e2ddf11c37d590

是一個閉源合約,無法看到其中的實現過程,直接讀取接口的數據,返回值均爲 0。在實現上應該設計有訪問控制。當然此處,可以分析合約的 OpCode,逆向到合約代碼。但難度較高,非我所擅長,只能另闢蹊徑。

當然也可以根據整個程序的邏輯,大致寫死一個數值。但如果還是想得到真正的參數數據改怎麼辦呢?苦心研究一天多,發現兩種不錯的方案,可以獲取正確的值。

方案一:代碼分析法

關鍵代碼分析

在 FoMo3dlong 的 activate 中有一段代碼

round_[1].strt = now + rndExtra_- rndGap_;

round_[1].end = now + rndInit_+ rndExtra_;

我們在鏈上非常容易獲取到本輪的 strt, end 的值。兩行代碼相當於兩個方程式,我們獲取到 now 值,我們就相當於解一個簡單的方程式,就可以破解到。那麼如何獲取到 now 值呢?

now 值的獲取

對於合約編程比較熟悉的同學很容易判斷出,now 值的設定就是調用 activate() 方式之時。那麼我們問題的關鍵就在於找到合約什麼時候執行 activate() 的方法

activate 方法調用。

我們通讀整個 FoMo3dlong 的實現,很容易得到下面的一個判斷,此合約在部署完成之後,一定需要做兩件事情:

1. 調用 setOtherFomo() 方法,設定另外一個遊戲玩法的合約

2. 調用 activate() 方法,激活合約,真正啓動遊戲。

那我們就要回到合約:

https://etherscan.io/address/0x32967d6c142c2f38ab39235994e2ddf11c37d590

源頭,看合約的創建是什麼時候開始的,然後依次看最近幾筆交易,肯定能發現所要的答案。很簡單我們只需要瀏覽 etherscan.io 上該合約所有的交易數據

https://etherscan.io/txs?a=0xa62142888aba8370742be823c1782d17a0389da1

非常可惜,etherscan.io 只展示最新的 10 萬筆交易,最早的交易沒了!

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

上圖看我此時的心情!

但我們是不會輕易放棄的人。繼續 google,查其它的以太坊瀏覽器。功夫不負有心人,找到一個能瀏覽合約所有交易情況的瀏覽器。

https://blockchair.com/ethereum/address/0xa62142888aba8370742be823c1782d17a0389da1

但交易太多,沒有翻頁功能,點擊到手軟,也很弄不出來,該網站的用戶體驗實在是太差。怎麼辦呢 ? 幸虧頁面的下面提供按照區塊篩選的功能。

一直追蹤,在下面的訪問地址上,看到了最原始的合約場景

https://blockchair.com/ethereum/calls?q=recipient(0xa62142888 geaba8370742be823c1782d17a0389da1),block_id(5932000..5910006)&s;=block_id(asc)

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

看第一筆,一個紅紅的 create 讓我看到了希望。把交易信息放在 etherscan 上

https://etherscan.io/tx/0xf63e775e10b0f662574ab49cd4c080ddcda8ca7d0012b5f0fbf0b03ad1c977ac

這筆交易創造出風靡一時的 Fomo3d。我們可以圍觀出很多信息:

1. 合約的第一次部署在 7 月 6 號,25 天前

2. 合約部署消耗掉了 600w+的 gas。超過不少測試網和私鏈默認的區塊 gaslimit,會出現很多部署失敗的情況。

3. 部署的時候 gasPrice 達到 82.5Gwei,整個花掉了 0.5ETH 的費用。估計當時以太坊相當堵。

順着看交易詳情,傻了!這個網站有 BUG,把不屬於這個合約的交易都歸類下面。硬着頭皮瀏覽了五六筆交易的詳情找到:

https://blockchair.com/ethereum/transaction/0x422728d092a8237a8a0544274c7268d0f1daf598c43f3e0d403c787f57a32be3

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

點擊右小腳,通過 etherscan.io 的鏈接:

https://etherscan.io/tx/0x422728d092a8237a8a0544274c7268d0f1daf598c43f3e0d403c787f57a32be3

終於發現 setOtherFomo 的調用。

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

通過這筆交易我們可以也可以觀察到不少有趣的事情:

1. 此處設置的合約地址,並不是 Fomo3dSoon 的合約地址。

設置的合約地址:

https://etherscan.io/address/0xf39e044e1ab204460e06e87c6dca2c6319fc69e3

Fomo3dSoon 的合約地址:

https://etherscan.io/address/0x4e8ecF79AdE5e2C49 B9e30D795517A81e0 Bf00 B8

2. 通過 FoMo3dlong 的代碼可以看出,用戶下注有 1% 的錢都到這邊來了,具體可以看到交易信息。可見:

https://etherscan.io/txsInternal?a=0xf9ba0955b0509ac6138908ccc50d5bd296e48d7d&p;=1

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

3. 到目前爲止,這筆錢都在這個被廢棄的合約上,大概接近 1000 個 ETH。這筆錢最終怎麼分?依照現有的邏輯,很大一部分會永遠地鎖死在合約上。但也有可能開發團隊有提幣的接口,可以被直接提走。

本以後順着這筆交易往後,就能看到 activate 的調用。可惜網站的 bug,導致連續很多的交易都跟 f3d 合約沒關係。只好放棄這條線索。

怎麼辦呢?

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

找其他相關性來解決。回過頭來在看這筆交易:

https://etherscan.io/tx/0x422728d092a8237a8a0544274c7268d0f1daf598c43f3e0d403c787f57a32be3

其 from 地址爲:

https://etherscan.io/address/0xf39e044e1ab204460e06e87c6dca2c6319fc69e3

既然此地址調用 setOtherFomo 那我們有理由猜測,activate 的也是該地址所調用。我們直接查看這個地址上所有的交易,我們終於發現一筆交易:

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

https://etherscan.io/tx/0xc6bd9c1e882064c55435227b9999ff4fb66a00f6572d5cfd3eb92b4a2c72d10e

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

此處應該有掌聲!

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

到此爲止,我們就可以根據次合約的執行時間,去設置 now 的正確值。此處涉及 utc 轉北京時間,北京時間轉 unix timestamp 等各種複雜計算,就不一一列出。最終的計算值是:

round_[1].strt = now + rndExtra_- rndGap_;

round_[1].end = now + rndInit_+ rndExtra_;

在看上面的公式,我們有了 now 值,rndInit_ 是一個小時,strt 值合約上能直接讀取到:1531080612。我用 parity 截圖如下:

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值

那 end 怎麼辦呢?有兩種方法:

  1. 猜一個大致的值,比如 start 過後 2 個小時

  2. 回溯區塊鏈到高度 5929395,獲取那時候的具體的 end 值

後一種可以具體寫程序實現,後續我會提供。

方案二:程序直接獲取

此方案曾在年初分析以太貓的程序中用到過,大家讀取一篇文章:

https://medium.com/aigang-network/how-to-read-ethereum-contract-storage-44252c8af925

即可明白原理。依據上面分析 , 正對 Fomo3dlong 的合約,我們寫了下面的分析代碼如下:

var Web3 = require(\”web3\”);

// 創建 web3 對象

var web3 = new Web3();

// 連接到以太坊節點

web3.setProvider(new Web3.providers.HttpProvider(\”http://localhost:8545\”));

let contractAddress = \’0xA62142888ABa8370742bE823c1782D17A0389Da1\’

async function asyncPrint(index) {

var p=web3.eth.getStorageAt(contractAddress, index);

var value;

try {

    value = await p;

}

catch (err) {

    console.error(err);

}

    console.log(`[${index}]` + value);

}

for (index = 0; index < 10; index++){

    asyncPrint(index);

}

}

我們設置 FoMo3dlong 的合約地址,分析前 10 個變量的值。用 node 直接運行,最終的輸入結果如下:

[0]0x000000000000000000000000f9ba0955b0509ac6138908ccc50d5bd296e48d7d

[1]0x000000000000000000000000000000000000000000000000000000000000000f

[2]0x0000000000000000000000000000000000000000000000000000000000000e10

[3]0x000000000000000000000000000000000000000000000000042e0a1276315c92

[4]0x0000000000000000000000000000000000000000000000000000000000000000

[5]0x0000000000000000000000000000000000000000000000000000000000000001

[6]0x0000000000000000000000000000000000000000000000000000000000000000

[7]0x0000000000000000000000000000000000000000000000000000000000000000

[8]0x0000000000000000000000000000000000000000000000000000000000000000

[9]0x0000000000000000000000000000000000000000000000000000000000000000

對比 FoMo3dlong 的合約代碼,去掉其中的常量(在不同的數據區),我們可以得出一個映射關係 (注意:打印出來的值是 16 進制的):

[0]—>otherF3D_(f9ba0955b0509ac6138908ccc50d5bd296e48d7d)

[1]—>rndExtra_(f)

[2]—>rndGap_ (e10)

[3]—>airDropPot_(42e0a1276315c92)

[4]—>airDropTracker_(0)

[5]—>rID_(1)

爲了驗證準確性,我們可以檢查 0,3,4,5 四個字段的值。

1. 字段 [0]:

otherF3D_ 的值也符合我們在方案一中找到的合約地址:

https://etherscan.io/address/0xf39e044e1ab204460e06e87c6dca2c6319fc69e3

2. 字段 [4],[5] 也符合我們合約上看到的值。

3. 字段 [3],airDropPot_ 非常具有代表意義,這個值隨着用戶的下注在變化,我們可以實時刷新對比一下真正鏈上獲取的數據,非常一致。

據此我們可以非常自信地判斷:

rndExtra_= 15 seconds;

rndGap_= 1 hours; //(e10=3600)

我們可以直接寫死這兩個數值,也可以做一個合約,實現相應的接口。

總結

1. 方案一雖然繁瑣,但其流程,非常值得研究,需要深入理解以太坊合約運行的內在機制方可找到一些線索。

2. 此文信息量非常大,希望能深入研究,動手做一遍流程。學會深度使用以太坊的區塊瀏覽器,學會如何用代碼跟合約就行交互,理解以太坊的運作機制和合約開發的底層邏輯。

我們有專門的羣討論區塊鏈遊戲開發,添加下面的微信,可付費入羣。

破解獲得 Fomo3d 中閉源合約 F3DExternalSettings 的返回值