这是不重复关闭SO问题: How do I tell if a win32 application uses the .NET runtime
如果给定的exe文件是.net exe文件或常规WIN32 / WIN64 exe文件,我如何找到以编程方式?
问题不在于询问正在运行的进程,而在于它是关于exe文件的,而且正如标记所示,不需要用VB.net或C#编写的解决方案。
我需要一个带有签名的函数,例如:
// return true if filename is a exe file for .Net
bool IsExeFileDotNet(LPCTSTR filename)
{
...
}
答案 0 :(得分:7)
一种方法是询问PE头等以获得正确的标志。有几个链接可供进一步阅读; here和here(以及较旧的MSDN文章here)。
PE标题is available (with a license agreement)上的MS文档。
最简单的可能是list the dependent dlls(因为这仅适用于主exe)并且查找mscoree.dll的存在。导入表将包含mscoree.dll以及函数_CorExeMain
的include和entry(来自mscoree.dll)。可以在here on SO和here on GitHub, that appears to be an extensive sample以及this article (on CodeGuru)找到更多相关链接,其中包含您需要的签名BOOL IsManaged(LPTSTR lpszImageName)
的函数代码(许可证似乎限制重新发布)
答案 1 :(得分: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;
}
请注意使用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);
}
this Q+A中提到了直接戳可执行文件以在文件中查找CLR头的其他技术。他们的未来证据非常难以猜测。
答案 2 :(得分:2)
我们的想法是检查是否存在特殊的PE目录IMAGE_DIRECTORY_ENTRY_COM_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;
}