工程趣聞 2026 年 9 月 17 日

2026-09-17 — 用稀有掉落機率逆推《異星工廠》的亂數狀態

primary=https://gegell.github.io/posts/factorio-rng/

用稀有掉落機率逆推《異星工廠》的亂數狀態

gegell's Blog · 2026-08-22

只要收集《異星工廠》裡機率極低的合成結果──例如 0.7% 才會觸發的鈾-235──連續觀察 88 次,就足以反推出遊戲內建亂數產生器的完整內部狀態,並準確預測接下來上千次的判定結果。這是開發者 gegell 在部落格文章〈Reversing Factorio's RNG〉中公開的逆向過程,他不只找出演算法本身,還做出一套幾乎每次都能產出傳奇品質物品的全自動產線。

背景:品質系統背後看不見的亂數

《異星工廠》的 Space Age 資料片加入「品質」機制:合成機台裝上品質模組後,每次生產都有機會把物品升級成更高品質,最高可到「傳奇」等級。這個判定完全由遊戲內部的亂數產生器決定,對玩家來說是完全不透明的黑盒子,唯一能做的就是堆更多生產線,靠統計上的大數法則慢慢磨出傳奇裝備。gegell 想找的,是能不能直接算出亂數產生器下一步會吐出什麼,而不是靠數量硬堆機率。

逆向過程:從反編譯找到 Taus88

gegell 先用 Ghidra 與 Binary Ninja 反編譯遊戲執行檔,並比對官方釋出的除錯符號檔(.pdb),確認遊戲用的是 taus88:一種由三組線性回饋移位暫存器(LFSR)組成、再把三者輸出做 XOR 合併的演算法。一名 Factorio 開發者也證實這個選擇,理由是「這是 Boost 函式庫裡跑最快的產生器」。三組 LFSR 的位元長度分別是 31、29、28,反編譯還原出的狀態更新函式長得像下面這樣:

a = (a << 12 ^ a >> 6) & 0x1fff ^ a >> 19 ^ a << 12;
b = (b << 4 ^ b >> 23) & 0x7f ^ b >> 25 ^ b << 4;
c = (c << 17 ^ c >> 8) & 0x1fffff ^ c >> 11 ^ c << 17;
return a ^ b ^ c;

核心技巧:用線性代數逆推內部狀態

三組 LFSR 都是定義在 GF(2)(二元體)上的線性系統,代表每一步狀態轉移都能寫成矩陣乘法。只要拿到連續幾次的輸出,就能反過來解出當下的內部狀態:把觀察到的輸出排成向量,乘上轉移矩陣的反矩陣,就還原出當時三組暫存器的值。問題是遊戲不會直接把 32 位元的亂數輸出顯示給玩家看,gegell 因此改用機率極低的合成配方(像 0.7% 的鈾-235)當探針:只要記錄某次判定有沒有觸發稀有結果,就能推出那次亂數輸出的高位元。他讓 44 座回收機並行處理維修包,總共取得 88 個位元的觀測值,剛好足夠解出三組 LFSR 合計 88 位元的完整狀態。

應用與限制:全自動傳奇產線,以及會失效的情況

算出目前狀態後,gegell 用遊戲內建的組合邏輯電路(combinator)把整套矩陣運算「蓋」進遊戲裡:即時算出目前狀態、預測接下來上千次的判定結果,再讓生產線只在預測會出傳奇的那一刻放行材料,其餘時間讓回收機消耗掉多餘的判定次數。這套技巧對速通玩家與想操控稀有掉落的模組開發者最有參考價值,因為手法本身──用低機率事件洩漏的位元反推整個 PRNG 狀態──能套用在任何共用單一亂數池、又會把判定結果間接暴露給玩家的遊戲上。要留意的是,全部判定共用同一個 generalRandomGenerator,只要有任何一次未被追蹤的呼叫發生,預測就會和實際狀態脫鉤,gegell 因此另外做了「連續兩次不符就重新校正」的機制;他也在文章裡註明,Factorio 2.1 版改動了亂數的呼叫方式,這套做法在新版本已經失效。

原始來源:gegell's Blog - Reversing Factorio's RNG


End of article
0
Would love your thoughts, please comment.x
()
x