新版rng技术前瞻-番外篇-LCG攻击

文章部分内容参考:

https://docs.google.com/document/d/1stTJAjLmCXtqctdFOpuv4lylegcmfO8mFrptFtwqb78/edit

感谢Matthew大佬的文章和一些软件的源码能让我大致了解这一过程

1.8.9末地中涉及到的全新rng的内容已经在前几期视频中完整讲述。虽然看似完美收官,但我们也留下了一个疑问:对于16次nextInt(32)的结果反推seed,我们使用的是大神已经写好的轮子,那么其中的逻辑又是怎样的呢?

  java的Random类使用LCG(线性同余法)作为随机数的生成算法,其算法可以表示为:

                  seed = (a*seed+b)mod m

  在java中查看Random类源码可知 a = 0x5DEECE66DL,b = 11L,m = 2^48;

  有小伙伴就说了不是啊,我看到的明明是 m = (1L << 48) - 1,没错,但可以看到java使用的是 &m,可以理解思考为什么跟 mod 2^48是等价的。

  所以我们也可以看出seed虽然是个long类型,但随机结果其实只跟低48位有关;

  好的,接下来我们来仔细看看nextInt(32)的算法:

  


  可以看到首先进行的是next(31)运算,我们转到这个方法:


  先对当前种子进行一次线性同余迭代运算,然后将新种子右移17位得到r;

  之后m=31,if(bound&m==0)实际上相当于if(n&(n-1)==0),大家也可以思考为什么这样就可以判断n是2的指数;

   可以看到如果为2的指数就可以直接进行运算,这样nextInt(32)的运算可以表示为:

    (32*(seed>>>17))>>31),当然对于32而言这边>>>和>>是一样的,乘32本身意味着左移5位,所以可以理解为是seed右移了43位,同时输出的随机结果即为剩下的5位;

  那么如果我们知道nextInt(32)的一个随机结果,那么我们可以知道生成这个随机结果的48位种子的高5位,而对于低43位因为移位的原因丢失了,我们无法知道,必须要想办法解决;

  有小伙伴就会说那就把所有的可能都试一遍,选择出对的。可以是可以,但这边可能的结果有2^43种,对于普通的计算机而言不是个小数目。那么我们该怎么做呢?

  让我们先来看一个例子:

  假设我们取a=5,b=3,m=8,同时设置初始seed为0,那我们可以得到seed的变换:

  0-->3-->2-->5-->4-->7-->6-->1-->0-->3...

  可以看到出现了循环,因为在这里m太小了,形如1/7=0.14285714285714...余数的循环周期很小。

  我们把上一个seed和当前seed组成一个二维坐标点,就可以得到:

  (0,3),(3,2),(2,5),(5,4),(4,7),(7,6),(1,0)

  我们把这些点绘制在坐标轴上:

  


  感觉有些奇怪是不是,看上去他们确实是存在一定规律。。。

  那么在这里我们规定一个要求,我们需要找到一个seed,它的连续两次迭代结果大于等于5,也就是说在坐标点(x,y)要满足x>=5&&y>=5当然x和y不能超过8,那么这个区域如下图所示:


    其实我们的任务就是要找在这个方形范围内的所有整数点,然后筛选出符合要求的点,但要注意,这只是一个二维平面的简单模型,而上面讲到的的种子存在2^43次情况,全部验证筛选会导致时间过长。

  注:接下来的东西up自己也很难理解,只能说是照着翻译来大致了解思路!!!

  这些在二维平面上的所有点的集合可以称为格(Lattice),通过平移使得其中一个点位于原点,这样一个格就可以被两个基向量描述,使得格上的任何点都可以由这两个向量的整数倍得到。在这里例如选择H(1,0)为原点,这样其他点可以表示为:

A(-1,3) B(2,2) C(1,5) D(4,4) E(3,7) F(6,6) G(5,1) 

相对的方形区域的四个角的坐标点也变为(4,5),(4,8),(7,5),(7,8)

 然后选择基向量为(1,5)和(0,8),并进行如下运算:


  v为格上的一个个坐标点,-1表示逆矩阵,通过up蹩脚的线代知识求解逆矩阵后得到变换结果如下图所示:


  其中A(-1,1)B(2,-1)C(1,0)D(4,4)E(3,-1)F(6,-3)G(5,-3)

  方形区域的四个角的坐标为(4,-1.5)(4,-15/8),(7,-15/4)(7,-27/8)  

  为什么要进行这个变换?这个问题一样很难,可能还需要额外的知识点?

  有这种感觉也是对的,因为我们选择了较差的基向量,而我们注意到的是此时在变换后的方形区域(虽然这个时候应该叫他平行四边形了)中只有一个整数点了,这样子筛选的范围就变小了,这就是我们需要的目的。这是因为我们已经将整个格变换为整数坐标,两个新的基向量的整数倍能把我们带到整数坐标的任何地方。

  那么如何选择更好的基向量呢?我们的目的是为了搜索尽可能少的整数坐标,所以我们想要基向量在大小上大致相等,这样所有的东西都能更均匀地收缩。它大致对应于正交基。有个著名的算法叫做LLL reduction。(有兴趣的可以百度或者谷歌看看。。。感觉没基础要理解太难了。。。)

  使用LLL算法后选择如下一对基向量:

  


  进行跟上面相同的变换后可以得到下图:

  


  可以看到经过合适的基向量变换后变得非常简单,因为可以看到平行四边形区域的顶点的坐标差很小,横向的两个顶点横坐标在2和4之间,竖向的两个纵坐标在-1和1之间,那想都不用想直接就可以得出那个点是(3,0)。这种变换在高阶和复杂的LCG破解中显然会非常有帮助。

  在得到了正确的点,也就是F点后,通过反向运算即可获得正确的种子。

  当然有一点也很重要,没有必要非要找n个连续结果来进行破解计算,只要知道当前随机结果和下一个随机结果之间隔了多少次迭代一样可以进行破解,其实这也是1.8.9获取基岩中的思路,8个漏斗一共会吸取两次物品,相隔8gt,而通过合理控制环境就可以保证8gt内的随机迭代是一个固定的常量。

  接下来让我们回到之前源码篇的代码中来看看Matthew大佬在1.8.9LCG攻击中的做法。源码我会在最下面放出链接。

  


  这边大神将16次随机结果作为一个1x16的矩阵,这个矩阵中的每一个元素都是nextInt(32)的结果,那么上面也讲到了seed的高5位是可以知道的,而低43位未知,那么这样子就可以确定一个范围,就是代码中大家可以看到的mins和maxes,而后面要减掉bvec猜测是为了去掉一些不必要的干扰?(这边up也不是很懂)


  之后就要将处理后的mins和maxes矩阵与一对合适的基向量相乘,这边大神找出了合适的16x16基向量组合mm1,矩阵与mm1相乘,然后又得到经1x16的处理后的minVal和maxVal矩阵,但这边可以看到把低48位直接通过右移去掉了,保留的是之前的位数,为什么这样操作up也不是很清楚,但可以知道的是这样处理后的两个表示范围的矩阵几乎相同:

  我们可以输入一组从游戏中获得的随机结果:


  


  可以看到经过mm1基向量处理后的范围变得非常小,上下限几乎是一模一样,在这个范围内就可以直接筛选出合适的结果。当然知道结果后的反带也会用到一个更难以理解的矩阵magicLattice。从名字就可以看出这是个拥有魔法的矩阵。

  目前up想要完全了解还差得很远,要深入的话必然涉及到高深的数学知识。极有可能这个系列即将在这边就完全结束了,当然了,又有谁知道呢。

源码链接:

链接:https://pan.baidu.com/s/1vuYak1_iFNa6lSu8mR5oPQ 

提取码:7wv8 作者:异形龙虾 https://www.bilibili.com/read/cv5037438/ 出处:bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值