调用静态链接函数崩溃每次在Windows 8/10而不是7

问题 :

我已经build立了https://github.com/reorg/pg_repack项目,它生成一个二进制文件。 这个二进制文件与postgres 9.6可重新分发(我使用EntrepriseDb)。 所有在Windows 7上工作正常。我没有问题,在构build或运行期间。 但是,在Windows 8或10,应用程序总是崩溃的下列序列。 这个二进制文件是使用Visual Studio 2013在Windows 7上生成的(在Windows 10上,我尝试过使用在Windows 10上生成的一个版本,但它不会改变任何东西),在x64系统上为x64应用程序生成二进制文件,它使用dynamic基础。 为了确保我使用正确的二进制文件,我已经将所有可重新分发的二进制文件复制到我的应用程序的文件夹中。

在Windows 7上的组装细节(工作案例):

main之后几行,应用程序调用函数set_pglocale_pgservice

set_pglocale_pgservice(argv[0], "pgscripts"); 00007FF6E4B39C85 mov eax,8 00007FF6E4B39C8A imul rax,rax,0 00007FF6E4B39C8E lea rdx,[default_options+120h (07FF6E4B43B10h)] 00007FF6E4B39C95 mov rcx,qword ptr [argv] 00007FF6E4B39C9A mov rcx,qword ptr [rcx+rax] 00007FF6E4B39C9E call qword ptr [__imp_set_pglocale_pgservice (07FF6E4B40520h)] 

内存在07FF6E4B40520h

 0x00007FF6E4B40520 00000001403e1da0 .>@.... 0x00007FF6E4B40528 0000000000000000 ........ 0x00007FF6E4B40530 0000000000000000 ........ 0x00007FF6E4B40538 00007ff6e4b35348 HS.äö... 

(注:从0x7FF6E4B40000到0x00007FF6E4B40560内存包含函数地址,而mapfile说:0002:00000520 __imp_set_pglocale_pgservice postgres:postgres.exe [postgres redistributable,dynamic链接])

然后调用qword ptr [__imp_set_pglocale_pgservice(07FF6E4B40520h)]

 00000001403E1DA0 mov qword ptr [rsp+18h],rbx 00000001403E1DA5 push rdi 00000001403E1DA6 sub rsp,0C40h 00000001403E1DAD mov rax,qword ptr [1405F8C60h] 00000001403E1DB4 xor rax,rsp 00000001403E1DB7 mov qword ptr [rsp+0C30h],rax 00000001403E1DBF mov rbx,rdx 00000001403E1DC2 mov rdi,rcx 00000001403E1DC5 lea rdx,[140430540h] 00000001403E1DCC mov rcx,rbx 00000001403E1DCF call 00000001403F67FA 

然后拨打电话00000001403F67FA

 00000001403F67FA jmp qword ptr [1403F8998h] 

内存在1403F8998h

 0x00000001403F8998 00007ffe87a5cc60 `Ì¥.þ... 0x00000001403F89A0 00007ffe87a47060 `p¤.þ... 0x00000001403F89A8 00007ffe87a5f8a4 ¤ø¥.þ... 

(注意:从0x00000001403F8000到0x00000001403F8F08内存中包含函数地址,并且mapfile表示:0002:00000998 ?? _C @ _04FHBLDJDJ @?1bin?$ AA @ libpgport:path.obj [postgres redistributable,静态链接])

然后跳转到00007ffe87a5cc60

 00007FFE87A5CC60 sub rdx,rcx 00007FFE87A5CC63 test cl,7 00007FFE87A5CC66 je 00007FFE87A5CC7C 

…一切正常

在Windows 10上的组装细节(不是工作案例):

主线之后的几行,应用程序调用函数set_pglocale_pgservice

 set_pglocale_pgservice(argv[0], "pgscripts"); 00007FF7E9879C85 mov eax,8 00007FF7E9879C8A imul rax,rax,0 00007FF7E9879C8E lea rdx,[default_options+120h (07FF7E9883B10h)] 00007FF7E9879C95 mov rcx,qword ptr [argv] 00007FF7E9879C9A mov rcx,qword ptr [rcx+rax] 00007FF7E9879C9E call qword ptr [__imp_set_pglocale_pgservice (07FF7E9880520h)] 

内存在07FF7E9880520h

 0x00007FF7E9880520 00000001403e1da0 .>@.... 0x00007FF7E9880528 0000000000000000 ........ 0x00007FF7E9880530 0000000000000000 ........ 0x00007FF7E9880538 00007ff7e9875348 HS.é÷... 

(注意:从0x00007FF7E9880000到0x00007FF7E9880560内存包含函数地址,而mapfile说:0002:00000520 __imp_set_pglocale_pgservice postgres:postgres.exe [postgres redistributable,dynamic链接])

然后调用qword ptr [__imp_set_pglocale_pgservice(07FF7E9880520h)]

 00000001403E1DA0 mov qword ptr [rsp+18h],rbx 00000001403E1DA5 push rdi 00000001403E1DA6 sub rsp,0C40h 00000001403E1DAD mov rax,qword ptr [1405F8C60h] 00000001403E1DB4 xor rax,rsp 00000001403E1DB7 mov qword ptr [rsp+0C30h],rax 00000001403E1DBF mov rbx,rdx 00000001403E1DC2 mov rdi,rcx 00000001403E1DC5 lea rdx,[140430540h] 00000001403E1DCC mov rcx,rbx 00000001403E1DCF call 00000001403F67FA 

然后拨打电话00000001403F67FA

 00000001403F67FA jmp qword ptr [1403F8998h] (should call C@_04FHBLDJDJ@?1bin?$AA@ libpgport:path.obj [postgres redistributable, which is linked statically])) 

内存在1403F8998h (这里的应用程序不同于Windows 7)

 0x00000001403F8998 000000000059e6a2 ¢æY..... 0x00000001403F89A0 000000000059e6ac ¬æY..... 0x00000001403F89A8 000000000059e6b6 ¶æY..... 

(注意:0x00000001403F8998是函数中间的op代码的地址,而不是函数的地址)

 00000001403F8998 mov byte ptr [AC000000000059E6h],al 00000001403F89A1 out 59h,al 00000001403F89A3 add byte ptr [rax],al ... 

内存在000000000059e6a2h

 000000000059E69F ?? ?? 000000000059E6A0 ?? ?? 000000000059E6A1 ?? ?? 

然后跳转到000000000059e6a2 =>崩溃

在Windows 7上处理监视器的详细信息,用于加载库(这里是libpq.dll):

 [...] "16:48:40,2946466","pg_repack.exe","7216","Load Image","C:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Image Base: 0x180000000, Image Size: 0x30000" [...] 

在Windows 10(这里是libpq.dll)上的进程监视器详细信息(除了加载库之外,它们都与Windows 7非常相似)

 [...] "11:52:20,6264717","pg_repack.exe","12464","QueryOpen","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","CreationTime: 21/08/2017 11:38:04, LastAccessTime: 21/08/2017 12:06:56, LastWriteTime: 09/05/2017 06:45:07, ChangeTime: 21/08/2017 18:04:09, AllocationSize: 184 320, EndOfFile: 183 296, FileAttributes: A" "11:52:20,6265789","pg_repack.exe","12464","CreateFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Desired Access: Read Data/List Directory, Execute/Traverse, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, Delete, AllocationSize: n/a, OpenResult: Opened" "11:52:20,6266332","pg_repack.exe","12464","QuerySecurityFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Information: 0x20" "11:52:20,6266513","pg_repack.exe","12464","CreateFileMapping","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","FILE LOCKED WITH ONLY READERS","SyncType: SyncTypeCreateSection, PageProtection: PAGE_EXECUTE" "11:52:20,6266921","pg_repack.exe","12464","CreateFileMapping","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","SyncType: SyncTypeOther" "11:52:20,6267619","pg_repack.exe","12464","Load Image","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Image Base: 0x180000000, Image Size: 0x30000" "11:52:20,6274889","pg_repack.exe","12464","CreateFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Desired Access: Generic Read, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, Delete, AllocationSize: n/a, OpenResult: Opened" "11:52:20,6275293","pg_repack.exe","12464","QuerySecurityFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Information: 0x20" "11:52:20,6275471","pg_repack.exe","12464","QueryBasicInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","CreationTime: 21/08/2017 11:38:04, LastAccessTime: 21/08/2017 12:06:56, LastWriteTime: 09/05/2017 06:45:07, ChangeTime: 21/08/2017 18:04:09, FileAttributes: A" "11:52:20,6276255","pg_repack.exe","12464","CloseFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","" "11:52:20,6291170","pg_repack.exe","12464","CloseFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","" [...] "11:52:20,6539022","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","BUFFER OVERFLOW","Name: \testF" "11:52:20,6539202","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","BUFFER OVERFLOW","Name: \testF" "11:52:20,6539363","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","BUFFER OVERFLOW","Name: \testF" "11:52:20,6539512","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","BUFFER OVERFLOW","Name: \testF" "11:52:20,6539664","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","BUFFER OVERFLOW","Name: \testF" "11:52:20,6603867","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Name: \testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll" "11:52:20,6604319","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Name: \testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll" "11:52:20,6604778","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Name: \testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll" "11:52:20,6605211","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Name: \testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll" "11:52:20,6605635","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","SUCCESS","Name: \testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll" [...] 

注:我期待类似于Windows 7或类似的东西:

 "11:52:20,6539022","pg_repack.exe","12464","QueryNameInformationFile","B:\testFolder\pg_repack-master\msvc\bin\x64\Debug\libpq.dll","BUFFER OVERFLOW","Length: 63". 

所以我不知道为什么这个应用程序有一个如此奇怪的行为在Windows 8或10。如果有人会有一些解释或想法,以解决崩溃我会很好。 如果需要,请不要犹豫,询问一些细节。

Solutions Collecting From Web of "调用静态链接函数崩溃每次在Windows 8/10而不是7"

我看你的二进制包,并查看你执行pg_repack.exepostgres.exe静态导入。 和问题的根源 – 从exe文件导入。 更确切地说来自PE文件,它没有在IMAGE_FILE_HEADER标记IMAGE_FILE_DLL 。特征,因为形式扩展( exedll等不起作用)。 简而言之,我将在下一个exe文件中表示没有IMAGE_FILE_DLL PE文件的Characteristics ,但不是正式的文件扩展名

首先加载EXE DLL为不正确的 – 当EXE加载这种方式 – 入口点不叫。 并且不能被调用,因为它没有被设计为回调函数,接收DLL_PROCESS_*通知,并在最后调用ExitProcess 。 当模块的入口点没有被调用时 – 通常它没有被初始化。 假设你从EXE调用一些导出的函数,但是如果这个导出的函数使用一些数据,通常在EXE入口点初始化呢? 所以结论 – 我们可以从EXE中调用导出的函数只能从这个EXE过程中加载DLL 。 并且在每个过程中只能有一个exe (作为可执行代码)。

在第二个特定的postgres.exe没有重定位( IMAGE_FILE_RELOCS_STRIPPED标志) – 因此,这个PE只能在硬编码地址加载。 这对于EXE来说并不是问题,当几乎所有的地址空间都是空闲的时候,它总是首先映射到进程。 但是一般情况下,当PE作为DLL加载时(不是首先处理),硬编码的imagebase可能已经很忙了。 所以结论 – 你不能安全地使用任何exe文件,而无需重定位的DLL

然而,在Windows 10崩溃的根源 – 因为如果这个PE没有标志IMAGE_FILE_DLL Windows 10不解析PE (“exe”)导入。 换句话说,它处理这个PE,LoadLibraryEx ,标志为DONT_RESOLVE_DLL_REFERENCES – 不加载指定模块引用的附加可执行模块,也不解析导入。 结果这个PE没有初始化,并会在第一次导入函数调用(在你的情况这是strcmp )崩溃。

这只发生在win10上。 在胜利8.1(建立9600),赢得7导入EXE文件(加载为DLL )解决。 ( 你说你的win 8.1崩溃了 – 可能是你使用了更多的新建或更新?或者更好的检查

这个行为的最简单的测试是从Netsh.exe导出的测试exe MatchToken函数调用。 代码可以是下一个:

 #include <Netsh.h> #pragma comment(linker, "/defaultlib:Netsh.lib") MatchToken(L"*", L"*");// crash here on win 10 

在Win10上崩溃,因为MatchToken内部尝试从msvcrt.dll调用_wcsnicmp ,但在win10这个导入没有解决。 但是在win8.1,win7,win xp下 – 这个代码运行的很好。

更复杂一点的例子:

 if (HMODULE hmod = LoadLibraryW(L"wshelper.dll")) { DWORD (WINAPI * InitHelperDll)(_In_ DWORD dwNetshVersion, PVOID pReserved); if (*(void**)&InitHelperDll = GetProcAddress(hmod, "InitHelperDll")) { InitHelperDll(1, 0);// crash here on win10 only } FreeLibrary(hmod); } 

这里我们加载标准的Windows NetShell助手dll – “wshelper.dll”并调用InitHelperDll回调函数。 内部InitHelperDllNetsh.exe调用RegisterHelper函数。 但再一次,因为Netsh.exe没有初始化(导入未解决),当它在win 10中作为DLL loades – 它坠毁RegisterHelper