【问题标题】:Can this code be reverse-engineered to find the random seed?可以对这段代码进行逆向工程以找到随机种子吗?
【发布时间】:2017-04-29 05:45:59
【问题描述】:
local digits = {'1', '2', '3', '4', '5', '6', '8', '9'} 
math.randomseed(os.time()) 
local result = digits[math.random(8)] 
for i = 2, 50 do 
    result = result..digits[math.random(8)] 
end 
print(result)

--> 88854243421464255299891111895292628431988589634664

这是一个 Lua 脚本,旨在吐出 50 个随机数字,不包括 0 和 7。我似乎找不到 Lua 随机算法。是否可以找到 os.time() 返回的值?

通俗地说,脚本是这样工作的:

  1. 定义一个包含八个单字符串的列表。
  2. 使用自 1970 年 1 月 1 日午夜以来的秒数为伪随机算法播种。
  3. 使用伪随机算法选择 1 到 8 之间的数字,然后使用该数字从列表中选择一个项目。例如。选择的数字是七,算法选择列表中的第七项。
  4. 将该项目添加到结果的末尾。重复直到结果达到 50 位数为止。

所以因为省略了七,所以随机算法真的吐出来了:

77754243421464255288781111785282627431877578634664

但是因为缺少了七,所以七加八变成了八加九,结果如下:

88854243421464255299891111895292628431988589634664

为了澄清,我试图弄清楚随机算法如何工作以找到作为随机种子输入的密钥。

也在这里问:https://forum.roblox.com/Forum/ShowPost.aspx?PostID=215349554 在这里:https://scriptinghelpers.org/questions/42360/can-this-script-be-reverse-engineered-to-find-the-random-seed 在这里:https://crypto.stackexchange.com/questions/47027/can-this-code-be-reverse-engineered-to-find-the-random-seed

【问题讨论】:

    标签: algorithm random lua cryptography


    【解决方案1】:

    能否对该代码进行逆向工程以找到随机种子?

    也许,也许不是。这取决于math.random的实现。

    能否找到os.time()返回的值?

    当然。 os.time() is defined as(强调我的)

    time 函数在不带参数调用时返回当前日期和时间,编码为数字。 (在大多数系统中,该数字是自某个时期以来的秒数。)

    我们谈论的是 32 位整数。这很容易被暴力破解。你甚至可以假设一些界限。这可能是在上个月左右产生的,不需要寻找未来的种子。过去 30 天内只有 22 位不同的秒数。

    您可以简单地从现在到过去遍历种子,并每次生成 50 位长的随机值。然后,您只需将其与您拥有的进行比较,并在找到匹配项时停止。这应该不会超过一分钟。

    这是完整的代码:

    function GetDigits(t)
        local digits = {'1', '2', '3', '4', '5', '6', '8', '9'}
        math.randomseed(t)
        local result = digits[math.random(8)]
        for i = 2, 50 do
            result = result..digits[math.random(8)]
        end
        return result
    end
    
    ct = os.time()
    while ct > 1 do
        if ct % 100000 == 0 then
            print (ct)
        end
        if GetDigits(ct) == "88854243421464255299891111895292628431988589634664" then
            print ("found: " .. ct)
            break
        end
        ct = ct - 1
    end
    

    输出

    1493400000 1493300000 1493200000 1493100000 1493000000 1492900000 1492800000 1492700000 1492600000 1492500000 1492400000 1492300000 1492200000 1492100000 1492000000 1491900000 1491800000 1491700000 1491600000 1491500000 发现:1491404649

    这只适用于 Lua v5.1,因为在 v5.2v5.3 中的实现发生了变化。我只在 Windows 上尝试过。

    【讨论】:

    • 尝试将字符附加到表中,然后使用table.concat 生成字符串。使用该算法,Lua 必须为您尝试的每个随机种子在内存中存储 50 个不同的字符串(例如,对于 OP 的示例结果,Lua 将存储字符串“8”、“88”、“888”、“8885 ", ..., "88854243421464255299891111895292628431988589634664")。追加应该会大大减少 Lua 需要做的内存读写次数。
    • @JackTaylor 谢谢!我只是计时。在我的机器上显示的版本需要 57 秒,而您的改进版本需要 48 秒。
    • 谢谢!当我第一次运行这段代码时,这个答案似乎是准确的。我在 Windows 上的 Lua 5.1 中运行它。我的目的不是生成安全的伪随机密钥。我排除了 7 和 0,因为我将它用于我为我的心理学课进行的实验。我通过查看人们能记住多少数字来测试人们的记忆力。因为七和零在英语中各有两个音节,所以他们可能会歪曲结果。
    • 您可能会节省大量时间,方法是一次比较一个数字,并在发现不匹配时立即拒绝种子。 87.5% 的种子将在第一位失败。
    • @Iimari:我实现了你的建议here。它在我的旧 Linux 笔记本电脑上在 3.8 秒内找到随机种子。 (为了让它工作,我必须为时间 1491404649 生成一个新的 50 位目标,因为 Linux 为 Windows 提供了不同的随机数,但在链接代码中我使用了 Windows 目标。)
    【解决方案2】:

    这不是您问题的完整答案,但它可能会帮助您入门。您可以找到 Lua 的 math.random 函数 here 的 C 源代码(适用于 Lua 5.1,但其他版本类似)。 Lua 本身并不尝试生成伪随机数,而是将该任务外包给 C 标准库。

    具体来说,math.random 使用 C 的 rand 函数生成数字,math.randomseed 使用 C 的 srand 函数设置伪随​​机数生成器的种子(与 rand 在同一手册页中介绍) .这些功能在每个系统上的实现方式都不同(例如 x86 Windows 版本与 x86 Linux 版本不同,不同的芯片组会有不同的版本等),因此您必须针对您所在的每个系统分析算法有兴趣。

    有关rand 是如何实现的信息,this question 应该会给你一个开始。

    您绝对应该注意的一件事是,如果有人能猜出您在几秒钟内调用了os.time(或者他们只是与您同时调用它),那么他们将能够生成完全相同的通过将该值传递给math.randomseed,为您提供伪随机数。如果有可用的种子,最好使用熵更高的种子。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-23
      • 1970-01-01
      • 2021-09-11
      • 2013-01-08
      • 2011-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多