2010-04-23 81 views
13

让我们看看下面的程序:崩溃与CMD行参数的程序

#include <stdlib.h> 

int main(int argc, char **argv){ 
    int a,b; 

    if (argc != 3) 
     return -1; 

    a = atoi(argv[1]); 
    b = atoi(argv[2]); 

    a = b ? a/b : 0; 

    return a; 
} 

的任务是通过命令行参数提供给程序崩溃。

+1

@Stacker:不知道,好像是一些痴呆的面试问题。 – Quixotic 2010-04-23 19:51:39

+0

我想不可能... – Kasturi 2010-04-23 19:51:45

+2

如果我正确回答,我会得到一个cookie吗?如果他们在面试中问你这个问题,希望他们不提供你这份工作。如果他们这样做,跑。 – 2010-04-23 19:52:52

回答

18

通过a作为平台的INT_MINb为-1。然后你会在任何二进制补码机上发生溢出错误,尽管这不一定是崩溃。

+0

我很惊讶地看到这个问题在面试时并不意味着安全专家。但是,无可否认,我使用Java和Python,这不是什么大问题。 – Uri 2010-04-23 20:01:34

5

这个问题的答案是:这取决于。

您需要知道的关键信息之一是atoi的实现方式以及是否符合标准。该标准对实现细节的描述很少,并且对输入输出行为更具体。让我们假设一分钟,它确实符合标准并关注实施。

有几种方法可以有效地使用,其中一种是递归的。让我们假设它是作为一个头部递归算法来实现的,这个算法强制堆栈的建立。然后我可以通过提供一个足够长的参数导致这个程序崩溃,它强制atoi足够深以堆栈溢出并因此导致应用程序崩溃。

2

你可以通过排除法,逆向操作:

1)你可以结束了零一个部门?不见得。如果b为0,则最后一个表达式为0,如果它不为0,则不会得到零除。

2)你可以提供不正确的参数数量和阵列访问崩溃?不是因为之前的argc检查

3)如果您的参数不转换为数字,atoi 应该返回一个数字值。我认为这是库规范的一部分,因此不适用于实现变体,但我可能是错的。

所以我不明白你会如何在这里崩溃。

我喜欢这个问题的唯一方法是除零部分 - 它检查你是否理解?:运算符,并且0是错误的。我不喜欢atoi部分,但没有给你访问参考手册。我必须检查文档以确保。

潜在的下溢/溢出是太棘手恕我直言。如果你正在面试一位软件安全工程师,这很好,但我不会问一个入门级的候选人,甚至只是为了一个标准的编程工作。如果您来自其他语言(例如Python),则特别困难。

更新:我做了几个参考的在线搜索,它似乎atoi应该返回0坏的输入。例如,来自MSDN

每个函数返回由解释输入的字符 作为数产生的int值 。如果 输入无法转换为该类型的值 ,则对于atoi和_wtoi,返回 值为0。

+1

回复:3)没有。将某些不能转换为int的东西传递给atoi不需要返回数字值。它调用未定义的行为。如果你这样做,一个实现可以免费崩溃你的程序,刻录你的硬盘。 – nos 2010-04-23 20:01:18

+0

@nos:是这样吗?我查了维基百科和MSDN,它似乎是另有说明:“每个函数返回通过将输入字符解释为一个数字而产生的int值。如果输入无法转换为atoi和_wtoi的返回值为0类型。” – Uri 2010-04-23 20:06:23

+1

根据C标准,是的。 “[1]函数atof,atoi,atol和atoll不需要影响 错误上的整数表达式errno的值。如果结果的值不能表示,则 的行为是未定义的。 – nos 2010-04-23 20:25:18

0

我看到的唯一可能的弱点是atoi()。也许如果它传递了足够大的字符串,它会以某种方式在它内部发生错误。除此之外,除以0覆盖参数计数。我能想到的唯一另外一件事就是通过将垃圾邮件发送到参数中来溢出操作系统缓冲区。不太可能。

0

我不知道大多数操作系统是如何传递argv数据的。它是否分配在堆栈上?它的长度本质上是有限的吗?

你能传递一个非常长的命令行参数并创建堆栈溢出吗?