【问题标题】:Simulate input to STDIN with EOL使用 EOL 模拟到 STDIN 的输入
【发布时间】:2016-01-25 05:50:28
【问题描述】:

我正在测试一种方法来模拟应用程序的特定输入。 这是应用程序:

#include <stdio.h>

int main()
{
        int num1;
        char buffer[6] = {0};

        scanf("%d", &num1);
        read(0, buffer, 6);

        printf("num1 = %d\n", num1);

        for(num1=0; num1 < 6; num1++)
        {
                printf("%02X\n", buffer[num1]);
        }

        return 0;
}

我正在尝试使用以下 bash 命令模拟输入:

echo -ne "1337\\x0A\\x31\\x02\\x03\\x04\\x05\\x06" | ./test

我得到的输出如下:

num1 = 1337
00
00
00
00
00
00

如您所见,缓冲区未填充传递给 STDIN 的值。

编辑: 下面的函数只是用来说明混合I/O函数中输入自动化的想法,我通过逆向二进制文件得到这个函数,是否可以自动化输入?

感谢您的帮助。

谢谢,

【问题讨论】:

    标签: c bash user-input stdin eol


    【解决方案1】:

    您正在混合 scanf() (section 3 man page) 和 read() (section 2 man page)。 scanf() 系列函数执行缓冲读取和写入。第 2 节 read() 没有缓冲。您尝试使用read() 读取的字节已被读取并放入scanf() 正在使用的缓冲区中。

    如果您注释掉您的 scanf() 行,并将您的命令更改为

        echo -ne "\\x0A\\x31\\x02\\x03\\x04\\x05\\x06" | ./test
    

    你会得到

    num1 = 0
    0A
    31
    02
    03
    04
    05
    

    所以只使用缓冲函数或非缓冲函数。选择一个。

    【讨论】:

    • 感谢您提供宝贵的信息。其实这段代码不是我写的。我只有编译后的二进制文件,但我将其反转为您可以在上面看到的 sn-p 的简单形式。我想知道即使它们的功能混合在一起,是否有可能实现自动化。
    • @xedar,如果您对某些东西进行逆向工程,请不要使用 scanf(),它将缓冲 stdio 缓冲区中的所有输入,然后使 read() 返回 0 字节(因为这里有一个管道并且 echo 只是将您传递给它的所有字节提供给输出)。您还没有检查 read 的返回值来检查这一点,假设 read 正在读取 6 个字节。
    【解决方案2】:

    这里发生了什么?

    • echo 正在使用您在命令行中输入的字符数进行写入(当您使用 -n 标志时,它不会输出最终的 \n 字符)。
    • 您在管道上使用scanf(),因此它首先读取完整的缓冲区,然后扫描缓冲区中的整数。它执行 n = read(0, buffer, BUFSIZ); 返回 11 作为读取到 scanf 的字符数,然后 scanf 扫描缓冲区,返回 1337 作为读取的数字,并将所有超过它的字符留在缓冲区中。
    • 然后您执行 read(0, buffer, 6);,它返回 0 并且缓冲区未使用数据初始化。
    • 然后将之前未初始化的缓冲区内容打印到标准输出。

    fifos(或管道)的行为与输入终端完全不同。当您按下enter 键时,终端驱动程序只会读取完成,读取以获取一个输入行读取的实际字符数。当您使用 fifo 执行此操作时,读取器进程将被阻塞,直到将足够的字符(读取请求的实际数量)提供给该进程,然后读取返回该数字(实际上是请求的字符数)。

    如果你有检查read(2)返回值的预防措施,你应该得到实际读取字符数(应该是0作为scanf(3) 在第一次读取时已经吃掉了完整的缓冲区,因为它小于BUFSIZ 常量)

    【讨论】:

    • 感谢您的精彩回答!。我们能否得出一个结论,因为 scanf 将读取整个 stdin 缓冲区,所以无法自动化上述函数的输入?您还有其他想法可以在没有管道的情况下传递数据吗?
    • 它将尝试读取。通常情况下,当输入来自终端设备时,它只会获取到换行符为止的输入(终端甚至将 ASCII CR 转换为 ASCII LF 以符合 UNIX 约定)在这种情况下,决定数据量的终端驱动程序返回。这就是需要始终检查read(2) syscall 的返回值的原因,因为您并不总是获得所需的数据。
    【解决方案3】:

    切勿将 scanf 等 stdio 函数与 read 等低级 io 函数混合使用。 Stdio 维护一个缓冲区以提高效率,如果在您调用 scanf 时有任何额外数据可用,它可能会读取它以填充缓冲区。

    使用 fread 而不是 read。另外,不要忘记检查这些函数的返回值。

    【讨论】:

    • 谢谢 Joni,其实我没有写应用程序。这与二进制相反,我正在尝试自动化输入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    相关资源
    最近更新 更多