前言
今天看到一个Demo,可以为DotNet程序生成调试用的ini.
这个资料在MSDN上有 : https://msdn.microsoft.com/en-us/library/9dd8z24x(v=vs.110).aspx
我好奇的是Demo如何判断指定程序是否为DotNet程序.
特意做了一个vc的测试程序,Demo判断这不是DotNet程序,看来不是为所有程序都生成ini, 而是真的判断了指定程序是否为DotNet程序…
好奇心来了,去偷偷的看看Demo怎么实现这个功能的:)
试验结论
看导入表中是否存在mscoree.dll(程序是否依赖mscoree.dll), 作为DotNet程序的判断依据
还原的工程
// hw.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include <Dbghelp.h>
#pragma comment(lib, "Dbghelp.lib")
#define TMP_FILE_NAME "myTmpFileForDirCommand.bin"
#define DOT_NET_PROG_DEPEND_DLL "mscoree.dll"
BOOL DotNetProgProc(const char* pcFilename);
BOOL IsDotNetProg(const char* pcFilename);
BOOL IsAppDependDll(const char* pcFilename, const char* pcDllname); // 程序是否依赖指定的Dll
void MakeIniFileForDotNetProgDebug(const char* pcFilename);
int main(int argc, char* argv[])
{
int iProcCnt = 0; // 处理的DotNet程序数量
int iTmp = 0;
FILE* pFile = NULL;
char szBuf[MAX_PATH] = {'\0'};
sprintf(szBuf, "dir /aa /s /b > %s", TMP_FILE_NAME);
system(szBuf);
pFile = fopen(TMP_FILE_NAME, "r+"); // not rb+
if (NULL != pFile) {
ZeroMemory(szBuf, sizeof(szBuf));
while (fgets(szBuf, sizeof(szBuf), pFile)) {
iTmp = strlen(szBuf);
// 文本中读进来的行尾有一个'\n'
if ((iTmp > 0) && (szBuf[iTmp - 1] == '\n')) {
szBuf[iTmp - 1] = '\0'; ///< ! 过滤掉 文件中传来的\n
}
if (DotNetProgProc(szBuf)) {
printf("%s\r\n", szBuf);
iProcCnt++;
}
ZeroMemory(szBuf, sizeof(szBuf));
}
fclose(pFile);
DeleteFileA(TMP_FILE_NAME);
}
printf("process DotNet file numbers = %d\r\n", iProcCnt);
system("pause");
return 0;
/** run result
D:\test\testCSharp.exe
process DotNet file numbers = 1
请按任意键继续. . .
*/
}
BOOL DotNetProgProc(const char* pcFilename)
{
BOOL bRc = FALSE;
if (NULL != pcFilename) {
if ((NULL != strstr(pcFilename, ".exe")) || (NULL != strstr(pcFilename, ".dll"))) {
bRc = IsDotNetProg(pcFilename);
if (bRc) {
MakeIniFileForDotNetProgDebug(pcFilename);
}
}
}
return bRc;
}
BOOL IsDotNetProg(const char* pcFilename)
{
// 看导入表中是否存在mscoree.dll(程序是否依赖mscoree.dll), 作为DotNet程序的判断依据
return IsAppDependDll(pcFilename, DOT_NET_PROG_DEPEND_DLL);
}
BOOL IsAppDependDll(const char* pcFilename, const char* pcDllname)
{
BOOL bRc = FALSE;
int i = 0;
HANDLE hMap = INVALID_HANDLE_VALUE;
HANDLE hFile = INVALID_HANDLE_VALUE;
char* pImportDllFileName = NULL;
int iPos = 0;
PIMAGE_NT_HEADERS NtHeaders = NULL;
IMAGE_IMPORT_DESCRIPTOR importDescEmpty = {0}; // 空的引入表描述符
IMAGE_IMPORT_DESCRIPTOR* pImportDescCur = NULL; // 当前的引入表描述符指针
PVOID lpBaseAddress = NULL;
DWORD dwVA = 0;
DWORD dwRVA = 0;
do {
hFile = CreateFileA(pcFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
break;
}
hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (NULL == hMap) {
break;
}
lpBaseAddress = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (NULL == lpBaseAddress) {
break;
}
if (IMAGE_DOS_SIGNATURE != *(WORD*)lpBaseAddress) {
break;
}
NtHeaders = (PIMAGE_NT_HEADERS)((int)lpBaseAddress
+ * ((DWORD*)((int)lpBaseAddress + offsetof(IMAGE_DOS_HEADER, e_lfanew))));
dwRVA = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if ((0 == dwRVA) || (0xffffffff == dwRVA)) {
break;
}
dwVA = (int)ImageRvaToVa(NtHeaders, lpBaseAddress, dwRVA, 0);
for (i = 0; ; i++) {
pImportDescCur = (IMAGE_IMPORT_DESCRIPTOR*)(dwVA + sizeof(IMAGE_IMPORT_DESCRIPTOR) * i);
if (0 == memcmp(pImportDescCur, &importDescEmpty, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
break;
}
pImportDllFileName = (char*)ImageRvaToVa(
NtHeaders,
lpBaseAddress,
*(DWORD*)((int)pImportDescCur + offsetof(IMAGE_IMPORT_DESCRIPTOR, Name)),
0);
if (0 == _strcmpi(pImportDllFileName, pcDllname)) {
bRc = TRUE;
break;
}
}
} while (0);
if (lpBaseAddress) {
UnmapViewOfFile(lpBaseAddress);
lpBaseAddress = NULL;
}
if (hMap) {
CloseHandle(hMap);
hMap = NULL;
}
if (INVALID_HANDLE_VALUE != hFile) {
CloseHandle(hFile);
hFile = NULL;
}
return bRc;
}
void MakeIniFileForDotNetProgDebug(const char* pcFilename)
{
char szBuf[MAX_PATH] = {'\0'};
char* p = NULL;
if (NULL != pcFilename) {
strcpy(szBuf, pcFilename);
p = strrchr(szBuf, '.');
if (NULL != p) {
strcpy(p + 1, "ini");
WritePrivateProfileStringA(".NET Framework Debugging Control", "GenerateTrackingInfo", "1", szBuf);
WritePrivateProfileStringA(".NET Framework Debugging Control", "AllowOptimize", "0", szBuf);
}
}
}