我在大学里上过一堂网络安全课. 而且,寻找一个秘密号码也是一个挑战. 以下是代码

#include <stdlib.h>
#include <time.h>
#include <stdio.h>

void init() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
}

int main() {
    init();
    srand(time(0));
    int secret  = 0;
    puts("Your secret: ");
    scanf("%d", &secret);
    if(secret == rand()) {
        system("/bin/sh");
    } else {
        puts("failed");
    }
}

我真的听不懂教授的解释. 任何人都能解释这个代码的含义,我怎么才能找到这个秘密号码?

推荐答案

伪随机数生成器依赖种子来生成它们的随机数:如果您使用相同的种子,您将得到相同的"随机"数序列.

请看这里:

请考虑以下代码:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    srand(0);

    printf("random number 1: %d\n", rand());
    printf("random number 2: %d\n", rand());
    printf("random number 3: %d\n", rand());
    printf("random number 4: %d\n", rand());

    return 0;
}

多次运行程序(a.out)总是生成相同的数字:

marco@Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
marco@Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
marco@Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872
marco@Marcos-MacBook-Pro-16 Desktop % ./a.out
random number 1: 520932930
random number 2: 28925691
random number 3: 822784415
random number 4: 890459872

当然,这exact个数字在用于生成数字的具体实现上会有所不同.因此,在您的系统中,数字序列可能会有所不同.然而,使用相同的种子将始终导致相同的序列.

真实系统使用"真实"(基于物理随机性)随机数和伪随机数生成器的组合,因为这样生成随机数的方式更有效.

这些数字通常是cryptographically secure pseudorandom number generators,因为这些数字用于加密操作(密码学在很大程度上依赖随机性来工作).

其基本思想是,只要初始种子是"秘密的"(未知的),您就不能将其返回并确定生成的预定义数字序列.

只需查看伪随机数生成器生成的数,就可以(并且已经完成)恢复初始种子.

Now on how to solve the exercise given by your professor:

最简单的方法是"冻结"时间,为随机数设置一个固定的种子值(如上面的代码示例所示).

由于没有一种简单的方法来做到这一点,您可以通过运行另一个程序来打印当前种子,从而只输出生成的第一个随机数(因为这是"秘密"):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand(time(0));

    printf("the secret number is %d\n", rand());

    return 0;
}

然后你可以用这个数字来"解锁"你教授给出的程序.

您必须在一秒或更短的时间内完成此操作,因为time()将返回新值every秒.

更可靠的方法是让程序在生成"随机"数后立即输入它.

以下是如何实现这一点的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

// where to put the "random" number on disk
const char *tmp_file = "/tmp/input";
// where the executable of your professor is
const char *executable = "/path/to/your/professors/executable";

void writeRandomNumberToDisk(const char *path, int number) {
    char buf[128];

    // convert int to string
    memset(buf, 0, sizeof(buf));
    snprintf(buf, sizeof(buf), "%d\n", number);

    FILE *fp = fopen(path, "w+");
    fwrite(buf, strlen(buf), 1, fp);
    fclose(fp);
}

int main(void) {
    srand(time(0));

    int secret = rand();

    printf("the secret number is %d\n", secret);

    writeRandomNumberToDisk(tmp_file, secret);

    char buf[512];

    memset(buf, 0, sizeof(buf));
    snprintf(buf, sizeof(buf), "/bin/sh -c 'cat %s | %s'", tmp_file, executable);

    printf("Now executing %s\n", buf);
    system(buf);

    return 0;
}

本质上,它将第一个"随机"数写入磁盘,然后调用将把"随机"数提供给程序的shell 程序.

您也可以使用如下命令完全绕过文件系统:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

// where the executable of your professor is
const char *executable = "/path/to/your/professors/executable";

int main(void) {
    srand(time(0));

    int secret = rand();

    printf("the secret number is %d\n", secret);

    char buf[512];

    memset(buf, 0, sizeof(buf));
    snprintf(buf, sizeof(buf), "/bin/sh -c 'printf \"%d\\n\" | %s'", secret, executable);

    printf("Now executing %s\n", buf);
    system(buf);

    return 0;
}

C++相关问答推荐

从STdin读写超过4096个字节

ISO_C_BINDING,从Fortran调用C

你能用自己的地址声明一个C指针吗?

与unions 的未定义行为

为什么在Linux(特别是Ubuntu 20.04LTS)上,POSIX共享内存对象在重启后仍然存在,然后突然变成了根用户?

如何用c语言修改shadow文件hash部分(编程)?

如何在VS 2022中正确安装额外的C头文件

';\n&39;和';\r&39;中的';\n&39;之间有什么关系?

C";中的ANN运行时判断失败#2-变量outputLayer;周围的堆栈已损坏.运行后出错

我正在try 将QSORT算法实现为C++中的泛型函数

在吉陀罗中,_2_1_和CONCAT11是什么意思?

try 判断长整数是否为素数

如何不断地用C读取文件?

是什么阻止编译器优化手写的 memcmp()?

free后内存泄漏?

子进程不会修改父进程中的统计信息

可以从指针数组中的值初始化指针吗?

在 C/C++ 中原子按位与字节的最佳方法?

定义 int a = 0, b = a++, c = a++;在 C 中定义了行为吗?

从寄存器移动到频繁访问的变量时性能意外降低