我发现了一个Windows漏洞吗?

5

在使用“C:\Program Files (x86)”时,我遇到了一个奇怪的问题,涉及到该路径下的某个程序。我使用了一个测试程序来重现这种行为。

    int _tmain(int argc, _TCHAR* argv[])
{
    wprintf(L"%d\n", argc);
    for (int i = 0; i < argc; i++) {
        wprintf(L"%s\n", argv[i]);
    }
    return 0;
}

该程序计算并返回所有命令行参数(包括用于识别程序的程序路径)。我将其命名为“HelloWorld.exe”,因为我很匆忙。
对于三种可能运行程序的方式,它给出了两个不同的结果,而我原本期望的是相同的结果。
当我从自己的目录中运行HelloWorld.exe时,输出为:
1
HelloWorld.exe

输出结果是正确的和预期的。

当我从另一个位置运行位于“P:\Test (x86)”中的HelloWorld.exe,并使用带引号的路径时,输出是

1
P:\Test (x86)\HelloWorld.exe

输出结果也是正确的,这是预期的。

然而,当我从另一个位置运行HelloWorld.exe并使用带有转义空格和括号的路径时,程序被找到了(即路径是正确的),但输出结果是错误的:

2
P:\Test
(x86)\HelloWorld.exe

由于某种原因,在

P:\Test\^ ^(x86^)\HelloWorld.exe

中转义的空格变成了可读作运算符的空格,因此在Windows将该路径作为一个字符串读取后找到该程序之前,决定将其视为两个字符串,然后再创建程序引用的数组。

这种行为在Windows XP(x86)和Windows Server 2008 R2(x64)中都会出现。我认为它存在于所有(NT)版本的Windows中。


谁投票关闭?这是一个有效的编程问题! - Andrew J. Brehm
1个回答

5

更新:

哎呀,或许这只是Windows中的一个错误(或者说缺陷)。

我刚刚编写了一个简单的测试程序,它只是调用GetCommandLine()并将其打印到控制台上。

我使用以下命令进行调用:

test The^ rain^ in^ Spain^ falls^ mainly^ on^ the^ plain^ ^(or^ so^ they^ say^).

这是输出结果:

test  The rain in Spain falls mainly on the plain (or so they say).

所以我猜运行时库根本没有看到这些插入符号,你唯一的选择就是告诉用户改用引号而不是转义字符。


不,这不是Windows的错误。这是您的C运行时库中的错误(尽管在这种情况下,我可能更喜欢使用“缺陷”或“不足”这个术语)。

Windows正在处理转义字符并定位可执行文件。但它并没有将命令行分成参数。Windows并非调用您的main函数(或此例中的_tmain)。它只是在PE头中定义的入口点处启动进程。在此位置上有一些C库代码(或者是对它的动态调用),其中包括在其他启动任务中调用内核32函数GetCommandLine(),然后在空格上分割它,尊重引号,但显然不支持插入符转义。

这并不令人感到惊讶。我不认为大多数人知道您可以在Windows命令行中使用插入符转义字符。我肯定不知道。

如果这对您造成了真实的问题,即有人真正使用插入符转义字符来调用您的程序,那么您可以告诉他们停止使用,或编写自己的命令行解析例程,将其传递给GetCommandLine()的输出,并忽略在main中传递给您的任何内容。


请注意,如果您的输出(如果在此处正确打印)表明“test”和其余部分被视为两个不同的字符串,即插入符号起到了转义空格的作用。 - Andrew J. Brehm
将您的代码更改为在字符串之间插入换行符?第一个字符串(指程序路径)和第二个字符串之间有两个空格,在所有其他位置都有一个空格,这是我猜测的。 - Andrew J. Brehm
显然,克拉数不会传递到目标程序,而是由cmd.exe处理(并移除)。这是预期的。 - Harry Johnston
1
可以说这是命令处理器中的一个错误;它不应该接受脱字符转义空格作为指定可执行文件路径的方式。当然,解决方法很简单 - 不要在命令行中使用脱字符转义空格。 - Harry Johnston
@Andrew:这里没有两个字符串,只有一个字符串。"test The rain in Spain..." 这是 GetCommandLine() 的返回值。你可以用最简单的程序进行测试:int main(){printf("%s", GetCommandLine());} 带着和不带着插入符号调用它,输出结果是一样的。在可执行文件名和命令行其余部分之间插入额外的空格确实很奇怪,但它并不是你所想象的那样。 - P Daddy
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接