windows – 为什么我的无CRT应用程序会在启动时间歇性崩溃?

例如,这个应用程序:

#define _WIN32_WINNT 0x0500

#include <windows.h>

int __stdcall NoCRTMain(void) 
{
    int result;

    PWSTR lpCmdLine = GetCommandLine();

    for (;;)
    {
        if (*lpCmdLine == L'"') 
        {
            lpCmdLine++;
            for (;;)
            {
                if (*lpCmdLine == L'"') break;
                if (*lpCmdLine == L'\0') break;
                lpCmdLine++;
            }
        }
        if (*lpCmdLine == L' ') break;
        if (*lpCmdLine == L'\0') break;
        lpCmdLine++;
    }

    while (*lpCmdLine == ' ') lpCmdLine++;

    result = MessageBox(NULL,lpCmdLine,L"Scripting Engine",MB_OK | MB_SYstemMODAL);

    if (result != IDOK) for (;;) Sleep(INFINITE);

    ExitProcess(0);
}

作为64位应用程序构建在Visual Studio 2010中,没有C运行时,这种方法非常有效 – 大部分时间都是如此.有时它会在启动时开始崩溃,没有明显的原因.在运行应用程序中的任何代码之前发生此崩溃(请参阅下文).

当问题发生时,它仅针对可执行文件的特定实例,即特定可执行文件发生.文件的逐字节相同副本将正常运行.重新启动计算机时,问题可能(将?)消失.我正在运行测试以尝试可靠地重现问题,以便我可以确定问题发生的环境,例如,只有安装了Visual Studio?只有安装了防病毒软件?但到目前为止,除了运气不好之外,我还没有通过任何程序来重现问题.

大多数情况下,调试显示kernel32!BaseThreadInitThunk正在调用无效地址而不是NoCRTMain的地址,尽管最近的一些运行早于失败,显然是在加载DLL时.

我相信我已经跟踪了问题,在加载模块时,ImageBase设置不正确.在工作实例上,相对于可执行模块的0x00D8的内存转储,从winnt.h构造_IMAGE_OPTIONAL_HEADER64:

00000001`3f5900d8 0b 02 0a 00 00 02 00 00 00 06 00 00 00 00 00 00 
00000001`3f5900e8 00 10 00 00 00 10 00 00 00 00 59 3f 01 00 00 00

显示ImageBase(最后8个字节)包含模块起始地址,在本例中为1`3f590000.在失败的实例上,相同的内存转储

00000001`3fc600d8 0b 02 0a 00 00 02 00 00 00 06 00 00 00 00 00 00 
00000001`3fc600e8 00 10 00 00 00 10 00 00 00 00 8f 3f 01 00 00 00

表明ImageBase不是预期的1`3fc60000,而是1`3f8f0000.

这似乎发生在调试器可以检查进程的最早点之前,因此我不确定如何继续.也许我需要做内核调试?我目前有一个VMWare vSphere虚拟机出现问题,我有一个我可以恢复的快照,所以我可以负担得起实验.

所以:

>有没有人知道这种行为的原因,更重要的是,如何预防?
>是我对内存转储错误的解释?
>任何调试/故障排除建议?

编译器选项:

/Zi /nologo /W3 /WX- /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS"
/D "_UNICODE" /D "UNICODE" /Gm- /EHsc /MT /GS- /Gy /fp:precise /Zc:wchar_t
/Zc:forScope /Fp"x64\Release\sehalt.pch" /Fa"x64\Release\" /Fo"x64\Release\"
/Fd"x64\Release\vc100.pdb" /Gd /errorReport:queue

链接器选项:

/OUT:"C:\documents\code\w7lab-scripting\sehalt\x64\Release\sehalt.exe"
/INCREMENTAL:NO /NOlogo "kernel32.lib" "user32.lib" "gdi32.lib"
"winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib"
"oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /NODEFAULTLIB
/MANIFEST /ManifestFile:"x64\Release\sehalt.exe.intermediate.manifest"
/ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG
/PDB:"C:\documents\code\w7lab-scripting\sehalt\x64\Release\sehalt.pdb"
/SUBSYstem:WINDOWS /OPT:REF /OPT:ICF 
/PGD:"C:\documents\code\w7lab-scripting\sehalt\x64\Release\sehalt.pgd"
/LTCG /TLBID:1 /ENTRY:"NoCRTMain" /DYNAMICBASE /NXCOMPAT
/MACHINE:X64 /ERRORREPORT:QUEUE

PS:看看我的哪些应用程序已经以这种方式失败,哪些不是,我怀疑问题只发生在小于一页(4096字节)的可执行文件中.

解决方法

一年过去了,我终于有信心声称Hans的建议完美无缺:如果应用程序是使用/ DYNAMICBASE构建的:NO和/ FIXED:YES选项,则问题不会发生.

相关文章

Windows2012R2备用域控搭建 前置操作 域控主域控的主dns:自...
主域控角色迁移和夺取(转载) 转载自:http://yupeizhi.blo...
Windows2012R2 NTP时间同步 Windows2012R2里没有了internet时...
Windows注册表操作基础代码 Windows下对注册表进行操作使用的...
黑客常用WinAPI函数整理之前的博客写了很多关于Windows编程的...
一个简单的Windows Socket可复用框架说起网络编程,无非是建...