java反函数_Java的随机函数的反函数

本文揭秘了Oracle/Sun Java中Random类的随机数生成器,指出了其48位种子和线性同余发生器的局限性,并提供了如何利用这些弱点来计算种子或恢复历史输出的技巧。通过实例演示了如何通过nextLong函数进行逆向工程。
摘要由CSDN通过智能技术生成

如果我们谈论的是Oracle(néeSun)

java.util.Random的实现,那么是的,一旦你知道足够的位就可以了。

随机使用48位种子和线性同余发生器。这些不是加密安全的生成器,因为微小的状态大小(可强制执行!)和输出不是随机的(许多发生器将在某些位显示小的周期长度,这意味着这些位可以很容易地预测甚至如果其他位看起来是随机的)。

随机的种子更新如下:

nextseed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)

这是一个非常简单的功能,如果您通过计算知道种子的所有位,它可以反转

seed = ((nextseed - 0xBL) * 0xdfe05bcb1365L) & ((1L << 48) - 1)

因为0x5DEECE66DL * 0xdfe05bcb1365L = 1 mod 248.由此,任何时间点的单个种子值足以恢复所有过去和将来的种子。

随机没有显示整个种子的功能,所以我们必须要有点聪明。

现在显然,使用48位种子,你必须观察至少48位的输出,或者你显然没有注入(因此可逆)的功能来使用。我们运气好:nextLong返回((long)(next(32))< 32)next(32);所以它产生64位的输出(超过我们需要的)。的确,我们可以用nextDouble(产生53位)或者只是重复调用任何其他函数。请注意,由于种子的大小有限,因此这些函数不能输出超过248个唯一值(因此,例如,下一个Long永远不会产生264-248个long)。 我们来看看nextLong吧。它返回一个数字(a< 32)b,其中a和b都是32位数量。让我们在下一个龙之前成为种子。然后,让t = s * 0x5DEECE66DL 0xBL,这样a是t的高32位,令u = t * 0x5DEECE66DL 0xBL,使得b是u的高32位。令c和d分别为t和u的低16位。 请注意,由于c和d是16位数量,我们只能强制他们(因为我们只需要一个),并且完成它。这很便宜,因为216只是65536 – 一台电脑很小。但是让我们更聪明一些,看看是否有更快的方式。 我们有(b <16)d =((a< 16)c)* 0x5DEECE66DL 11.因此,做一些代数,我们得到(b <16)〜11 - (a< < 16)* 0x5DEECE66DL = c * 0x5DEECE66DL-d,mod 248.由于c和d都是16位数量,因此c * 0x5DEECE66DL最多有51位。这有用地意味着

(b << 16) - 11 - (a << 16)*0x5DEECE66DL + (k<<48)

等于c * 0x5DEECE66DL – d,对于某些k至多为6.(有更复杂的方法来计算c和d,但是由于k上的界限很小,所以只需要强力)。

我们可以测试k的所有可能的值,直到我们得到一个值,否定余数mod 0x5DEECE66DL是16位(mod 248再次),以便我们恢复t和u的低16位。在这一点上,我们有一个完整的种子,所以我们可以使用第一个方程找到未来的种子,或使用第二个方程过去的种子。

代码演示方法:

import java.util.Random;

public class randhack {

public static long calcSeed(long nextLong) {

final long x = 0x5DEECE66DL;

final long xinv = 0xdfe05bcb1365L;

final long y = 0xBL;

final long mask = ((1L << 48)-1);

long a = nextLong >>> 32;

long b = nextLong & ((1L<<32)-1);

if((b & 0x80000000) != 0)

a++; // b had a sign bit, so we need to restore a

long q = ((b << 16) - y - (a << 16)*x) & mask;

for(long k=0; k<=5; k++) {

long rem = (x - (q + (k<<48))) % x;

long d = (rem + x)%x; // force positive

if(d < 65536) {

long c = ((q + d) * xinv) & mask;

if(c < 65536) {

return ((((a << 16) + c) - y) * xinv) & mask;

}

}

}

throw new RuntimeException("Failed!!");

}

public static void main(String[] args) {

Random r = new Random();

long next = r.nextLong();

System.out.println("Next long value: " + next);

long seed = calcSeed(next);

System.out.println("Seed " + seed);

// setSeed mangles the input, so demangle it here to get the right output

Random r2 = new Random((seed ^ 0x5DEECE66DL) & ((1L << 48)-1));

System.out.println("Next long value from seed: " + r2.nextLong());

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值