Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何确定exe文件是.Net exe还是常规exe?_C++_C_Windows_Winapi - Fatal编程技术网

C++ 如何确定exe文件是.Net exe还是常规exe?

C++ 如何确定exe文件是.Net exe还是常规exe?,c++,c,windows,winapi,C++,C,Windows,Winapi,这不是以下问题的重复: 如何通过编程确定给定的exe文件是.net exe文件还是常规WIN32/WIN64 exe文件 问题不是询问正在运行的进程,而是询问一个exe文件,正如标签所示,不需要用VB.net或C#编写解决方案 我需要一个带有签名的函数,例如: // return true if filename is a exe file for .Net bool IsExeFileDotNet(LPCTSTR filename) { ... } 一种方法是询问PE报头等是否有正确

这不是以下问题的重复:

如何通过编程确定给定的exe文件是.net exe文件还是常规WIN32/WIN64 exe文件

问题不是询问正在运行的进程,而是询问一个exe文件,正如标签所示,不需要用VB.net或C#编写解决方案

我需要一个带有签名的函数,例如:

// return true if filename is a exe file for .Net
bool IsExeFileDotNet(LPCTSTR filename)
{
   ...
}

一种方法是询问PE报头等是否有正确的标志。有几个链接可供进一步阅读;和(和一篇旧的MSDN文章)

PE标题上的MS文档


最简单的方法可能是(因为这仅适用于主exe)并查找mscoree.dll的存在。导入表将包括mscoree.dll和函数
\u CorExeMain
(来自mscoree.dll)的include和条目。您可以找到更多关于此的链接,并使用您需要的签名为BOOL IsManaged(LPTSTR lpszImageName)的函数的代码(许可证似乎限制重新发布)。

旧的待机模式是从文件中读取目标运行时版本。当可执行文件不包含CLR头时,它将失败,并出现错误\u BAD \u FORMAT。可在部件的任何位和任何目标体系结构中工作。您必须像这样使用它:

#define USE_DEPRECATED_CLR_API_WITHOUT_WARNING
#include <mscoree.h>
#pragma comment(lib, "mscoree.lib")
#include <assert.h>

bool IsExeFileDotNet(LPCWSTR filename)
{
    WCHAR buf[16];
    HRESULT hr = GetFileVersion(filename, buf, 16, NULL);
    assert(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
    return hr == S_OK;
}
#include <Windows.h>
#include <metahost.h>
#include <assert.h>
#pragma comment(lib, "mscoree.lib")

bool IsExeFileDotNet(LPCWSTR filename)
{
    ICLRMetaHost* host;
    HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (void**)&host);
    assert(SUCCEEDED(hr));
    if (hr == S_OK) {
        WCHAR buf[16];
        DWORD written;
        hr = host->GetVersionFromFile(filename, buf, &written);
        assert(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
        host->Release();
    }
    return SUCCEEDED(hr);
}
\define USE\u已弃用\u CLR\u API\u无警告
#包括
#pragma注释(lib,“mscoree.lib”)

#包括。很难猜测它们将来的可靠性。

我们的想法是检查是否存在特殊的PE目录
IMAGE\u directory\u ENTRY\u COM\u DESCRIPTOR

我最近写了类似的函数,这里的代码,你可以使用它。事实上,我已经为句柄使用了一个智能包装器,但这里省略了它,所以添加了CloseHandle的expicit调用。另外,在ReadFile/SetFilePointer调用之后检查错误也是一个好主意。无论如何,我希望它能有用:

BOOL IsDotNetApp(LPCWSTR szPath)
{
    HANDLE hFile = CreateFileW(szPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if (INVALID_HANDLE_VALUE == hFile)
        return FALSE;

    DWORD temp;

    IMAGE_DOS_HEADER IMAGE_DOS_HEADER_;
    ReadFile(hFile, &IMAGE_DOS_HEADER_, sizeof(IMAGE_DOS_HEADER_), &temp, NULL);

    SetFilePointer(hFile, IMAGE_DOS_HEADER_.e_lfanew, NULL, FILE_BEGIN);

    const int nNtHeaderMaxSize = sizeof(IMAGE_NT_HEADERS64);
    BYTE NT_HEADERS[nNtHeaderMaxSize];
    ReadFile(hFile, NT_HEADERS, nNtHeaderMaxSize, &temp, NULL); 

    PIMAGE_NT_HEADERS pNT_HEADERS = (PIMAGE_NT_HEADERS)NT_HEADERS;
    BOOL bRes;
    if (pNT_HEADERS->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
    {
        bRes = 0 != ((PIMAGE_NT_HEADERS32)NT_HEADERS)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
    }
    else if (pNT_HEADERS->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
    {
        bRes = 0 != ((PIMAGE_NT_HEADERS64)NT_HEADERS)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
    }
    else
    {
        // Unknown header type
        bRes = FALSE;
    }

    CloseHandle(hFile);

    return bRes;
}

可能是的。您还可以查询exe的依赖项列表,以确定其依赖项之一是否需要.Net-链可能很长,这取决于您需要这些信息做什么。如果只是exe,则更简单,如果整个过程需要.Net,则需要检查所有依赖项.Net可执行文件是引导.Net的常规win32应用程序。不完全确定PE头是否会给出这方面的提示。没有一个副本是真正详尽的。那些看起来很安全的人自己使用.NET(这个问题并没有问这个问题)。而那些可以归结为解析PE头的文件与官方文档没有链接,甚至没有关于OS加载器如何确定是否需要加载CLR的非官方信息。我正在投票重新打开。此链接可能会让您开始,您将需要验证“混合模式”exe(即使用
/clr
编译),但您的答案可能更简单,需要查找导出的函数
\u CorExeMain
。看起来标题的MS规范在这里;“很难猜测它们是否能证明未来。”-考虑到偏移量的存在,看起来它们几乎可以证明未来。由于操作系统加载器不是经常变化的东西,因此我们更有理由相信,解析PE头的方法实际上也同样安全。CLR头将始终以这种方式定位的假设已经是一种延伸。尤其是CoreCLR正在转向Linux和OSX,即PE格式意味着bean的操作系统。我们的口号是永远避免依赖于实现细节,而是使用有文档记录的api。虽然您总体上是对的,但我一点也不相信,您的两个解决方案中的任何一个都知道如何解释非PE图像。或者Windows上的.NET宿主API是否实现了ELF解析器?显然,随着CLR主机的移植,API也将被移植。换句话说,这个答案中的解决方案也无法识别国外平台的.NET程序集。如今,它们的功能并不比解析PE头更强大。这在将来可能会改变,但不会引入/后端口到.NET 4 framework中,并且需要在客户端机器上更新.NET安装。很高兴知道,有一个官方的方法存在,以防您可以假设存在.NET4安装。代码肯定会从错误处理中获益。至少您应该检查API调用是否失败,尽管测试预期的头魔法值也不是一个坏主意。