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

Jab*_*cky 4 c c++ windows winapi

不是重复的问题: 如何判断win32应用程序是否使用.NET运行时.

如果给定的exe文件是.net exe文件或常规WIN32/WIN64 exe文件,我怎么能以编程方式找出?

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

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

// return true if filename is a exe file for .Net
bool IsExeFileDotNet(LPCTSTR filename)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

Nia*_*all 7

一种方法是询问PE头等以获得正确的标志.有几个链接可供进一步阅读; 这里这里(和较旧的MSDN文章在这里).

PE头上的MS文档可用(带许可协议).

最简单的可能只是列出依赖的dll(因为这仅适用于主exe)并查找mscoree.dll的存在.导入表将包含mscoree.dll以及函数的include和entry _CorExeMain(来自mscoree.dll).关于这方面的更多的链接,可以发现这里SO这里在GitHub上,这似乎是一个大量的样品,和这篇文章(上CodeGuru)与代码与签名的功能BOOL IsManaged(LPTSTR lpszImageName),你需要(许可证似乎限制重排版) .


Han*_*ant 6

旧的备用数据库是使用GetFileVersion()从文件中读取目标运行时版本.当可执行文件不包含CLR标头时,它将失败并显示ERROR_BAD_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;
}
Run Code Online (Sandbox Code Playgroud)

请注意使用USE_DEPRECATED_CLR_API_WITHOUT_WARNING来抑制弃用错误,MSCorEE api在.NET的未来主要版本中可能会消失.

不推荐使用的方法是使用ICLRMetaHost :: GetFileVersion(),缺点是它只能在机器安装了.NET 4时才能工作.今天不是一个主要问题.看起来像这样:

#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);
}
Run Code Online (Sandbox Code Playgroud)

Q + A中提到了直接戳可执行文件以在文件中查找CLR头的其他技术.他们未来的证据非常难以猜测.

  • *"他们的未来可能性很难猜测."* - 鉴于,补偿是[记录](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680305. aspx),看起来它们几乎是面向未来的.而且由于OS加载器不是经常变化的东西,所以更有理由相信,解析PE头的方法实际上同样安全. (2认同)

Art*_*zin 5

这个想法是检查特殊的 PE 目录是否IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR存在。

我最近写了类似的功能,这里是代码,你可以使用它。事实上,我已经使用了句柄的智能包装器,但这里省略了它,因此添加了 CloseHandle 的显式调用。另外,在 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 该代码肯定会从错误处理中受益。至少您应该检查 API 调用是否失败,尽管测试预期的 header magic 值也可能不是一个坏主意。 (2认同)