【问题标题】:Segmentation Fault is given, why? (C)给出分段错误,为什么? (C)
【发布时间】:2017-03-14 23:19:02
【问题描述】:

我已经学习了大约 2 周的 C 语言,并决定尝试使用一个简单的端口扫描器。我可以毫无错误地编译代码,但是每当我尝试执行它时,都会出现分段错误。

#include<stdio.h>
#include<sys/socket.h>
#include<errno.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>

int scanPort(char hostaddr[], int port) {
    struct hostent *host;
    int err, i, sock;
    struct sockaddr_in sa;

    strncpy((char*)&sa , "" , sizeof sa);
    sa.sin_family = AF_INET;

    if (isdigit(hostaddr[0])) {
        sa.sin_addr.s_addr = inet_addr(hostaddr);
    } else if ((host = gethostbyname(hostaddr)) != 0) {
        strncpy((char*)&sa.sin_addr , (char*)host->h_addr , sizeof sa.sin_addr);
    } else {
        printf("\n[!] Failed to resolve host!\n");
        exit(1);
    }

    sa.sin_port = htons(port);
    sock = socket(AF_INET, SOCK_STREAM, 0);

    if (sock < 0) {
        printf("\n[!] Failed to create socket!\n");
        exit(1);
    }

    err = connect(sock,  (struct sockaddr*)&sa , sizeof sa);

    close(sock);

    if (err < 0) {
        return 0;
    } else {
        return 1;
    }
}

int main(int argc, char *argv[]) {
    if (argc != 4) {
        printf("usage: ./portscan [TARGET] [START PORT] [STOP PORT]\n");
        exit(0);
    }

    char host[20];
    strcpy(host, argv[1]);
    int beginport;
    int endport;

    if (isdigit(argv[2]) && isdigit(argv[3])) {
        beginport = atoi(argv[2]);
        endport = atoi(argv[3]);
    } else {
        printf("[!] Invalid port range given\n");
    }

    printf("[*] Beginning Scan...\n\n");

    int i = beginport;

    for (i; i<=endport; i++) {
        if (scanPort(host, i)) {
            printf("Port %d: Open\n", i);
        }
    }

    printf("\n[*] Scan complete!");
    return 0;
}

我知道代码中有一些不正确/不安全的函数使用,但我只是想让这个程序正常运行。这只是一个测试,不是实际使用的程序。

这是编译和执行的截图,但我认为它不会有太大帮助:

更新:我向它传递了参数,仍然出现分段错误:

更新 2:我添加了几行来评估 argc

感谢您的宝贵时间。

-默认

【问题讨论】:

  • argv 为空,因为您从未传入任何内容。
  • 你的调试器状态会更相关。
  • @ShawnicHedgehog:argv[0][1] 有效。但你说得有些对。底层数组的访问超出其边界。
  • 正如大家所说,你没有向你的程序传递任何参数。由于argv 被指定为空终止(argv[argc] == NULL),因此您基本上将NULL 传递给对strcpy 的第一次调用。永远不要假设参数被传递,检查argc的值。
  • gethostbyname 也适用于 IPv4 地址!

标签: c segmentation-fault port-scanning


【解决方案1】:

崩溃发生在这里:

if (isdigit(argv[2]) && isdigit(argv[3])) {

isdigit 函数需要一个int(实际上是一个char 转换为一个int),但是你传入一个char *。这会调用未定义的行为,在这种情况下(对您来说很幸运)表现为崩溃。

您可能想要检查每个字符串的第一个字符,因此将argv[2][0]argv[3][0] 传递给此函数。

另外,这是不正确的:

strncpy((char*)&sa.sin_addr , (char*)host->h_addr , sizeof sa.sin_addr);

strncpy 函数用于复制字符串,而不是任意字节。如果正在复制的字节中有一个空字节,则不会复制该字节之后的其他字节。请改用memcpy,它会复制准确的字节数:

memcpy((char*)&sa.sin_addr , (char*)host->h_addr , sizeof sa.sin_addr);

【讨论】:

  • 极不可能在isdigit 崩溃。当然它不能按预期工作,但char * 应该转换为int 没有问题。
  • 根据 Valgrind 的说法,这正是它崩溃的地方。上面提到的更改修复了它。
  • 好的,看起来正在进行数组查找,并且该数组中的索引是函数参数的(int) 转换。如果我#include &lt;ctype.h&gt;(顺便说一句,应该在这里完成),预处理器(gcc -E portscan.c)输出isdigit(argv[2])这个序列:((*__ctype_b_loc ())[(int) ((argv[2]))] &amp; (unsigned short int) _ISdigit)。现在崩溃是有道理的。
猜你喜欢
  • 1970-01-01
  • 2021-07-19
  • 2020-04-27
  • 2021-03-04
  • 2020-08-22
  • 1970-01-01
  • 2013-10-20
  • 1970-01-01
  • 2014-04-02
相关资源
最近更新 更多