У меня есть неуправляемое консольное приложение С++, в котором я использую srand() и rand(). Мне это не нужно для решения конкретной проблемы, но мне было любопытно: хранится ли исходное семя, переданное в srand(), где-то в памяти, к которому я могу запросить? Есть ли способ выяснить, что это за семя?
Узнайте, чем был засеян генератор случайных чисел в C++
Ответы (4)
Семя не требуется сохранять, требуется только последнее возвращенное случайное число.
Вот пример из справочной страницы:
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
Если у вас есть простой линейный конгруэнтный генератор, для которого у вас есть несколько значений, это дает систему уравнений:
v1 = ( seed * a + b ) % m
v2 = ( v1 * a + b ) % m;
v3 = ( v2 * a + b ) % m;
...
Если вы знаете первое значение, вы можете вернуться в последовательности назад:
seed = (v1 - b)/a (mod m)
Вы не знаете уникальное семя, вы знаете его только по модулю m (что обычно хорошо, поскольку (0 ‹ seed ‹ m) в любом случае). Если v1 - b отрицательное, вам нужно добавить m до тех пор, пока оно снова не станет положительным.
Вы также можете взглянуть на китайскую теорему об остатках, хотя это не точное совпадение.
Я не знаю, каков ваш уровень владения сборкой или есть ли у вас доступ к исходному коду/символам отладки для неуправляемого приложения, но за пределами такого рода ухищрений нет реального способа определить исходное начальное значение. Весь смысл генераторов случайных чисел состоит в том, чтобы придумать способ выдавать вам непредсказуемые числа — связь между любыми двумя заданными вызовами rand() не должна быть выводимой. В криптографически сильных генераторах псевдослучайных чисел будет считаться серьезным недостатком способность угадывать начальное число на основе сгенерированного случайного числа.
Самый простой способ сделать это - запустить приложение под отладчиком и установить точку останова, где вызывается srand()
, а затем просто посмотреть на переданный параметр.
Далее будет дизассемблировать приложение и выяснить обстоятельства случайного звонка. Вполне возможно, что оно засеяно текущим временем — тогда вы можете попробовать несколько догадок (вероятно, вы можете сузить их до нескольких тысяч или около того) и посмотреть, дают ли они ту же последовательность случайных чисел, которую использует приложение. . (Конечно, это предполагает, что у вас есть какой-то способ узнать, каковы генерируемые случайные значения). Также возможно, что семя все время что-то глупое, например «0».
Теоретически нет — начальное значение используется для вычисления следующего случайного значения, и это значение (теоретически) используется для начального заполнения следующего случайного числа и так далее.
С точки зрения безопасности, возможность заглянуть в начальное число (будь то исходное или новое) является серьезной проблемой безопасности, поэтому я ожидаю, что вы не сможете заглянуть в него, даже если оно должно где-то храниться.