CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    Nov 2003
    Posts
    2,185

    Check if DLL is managed or not

    Hi all,

    I want to find out if a DLL is managed or not. Is there a way for this (of course there is), if so, how?

    Best regards,

  2. #2
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: Check if DLL is managed or not

    A managed DLL / Application will have a primary dependency on MSCOREE.dll... So, if you open the DLL in Dependency Walker you have no problems in telling a managed library from an unmanaged one.
    Last edited by Siddhartha; May 24th, 2007 at 01:41 PM.

  3. #3
    Join Date
    Nov 2003
    Posts
    2,185

    Re: Check if DLL is managed or not

    Thanks for your answer.

    But, how can I determine this via C++ (and only a filename of the DLL)?

    Best regards,

  4. #4
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: Check if DLL is managed or not

    Actually, if you open a .NET Library / Application in a binary editor, you will see that the ASCI text "BSJB" is shortly followed by the version of the Framework that the DLL / EXE needs.

    So, depending on the presence of this search attribute, you can not only identify whether the library / executible is a managed library, but also the version of the Framework it uses.

    Note: This is actually a hack as there seems to be no API that will help you out with your requirement - but, it is reliable (so far) and you can enforce some strong checks that nobody fools your application (though, I doubt if anyone will want to do this).
    Attached Images Attached Images  

  5. #5
    Join Date
    Nov 2003
    Posts
    2,185

    Re: Check if DLL is managed or not

    Wow, thanks for this info!

    I have written a small function to determine whether a function is a .net assembly or not. It might be useful to other people as well (since I couldn't find anything on the internet about it).

    Code:
    bool IsNetAssembly(CString sFilename)
    {
    	// Declare variables
    	bool bAssembly = false;
    	bool bTagFound = false;
    	bool bVersionFound = false;
    	char szBuffer[2048];
    	char szTagBuffer[5];
    	char szVersionBuffer[4];
    	int iBytesRead = 0;
    	CFile oFile;
    
    	// Set up tag
    	strcpy(szTagBuffer, "BSJB");
    
    	// Check if file exists
    	if (!PathFileExists(sFilename))
    	{
    		// No assembly
    		return bAssembly;
    	}
    
    	// Read the contents of this file
    	if (!oFile.Open(sFilename, CFile::modeRead | CFile::shareDenyNone, NULL))
    	{
    		// No assembly
    		return bAssembly;
    	}
    
    	// Read file
    	while (iBytesRead = oFile.Read(szBuffer, 2048))
    	{
    		// Check if we can find the special tag
    		if (!bTagFound)
    		{
    			if (ValueExistsInCharBuffer((char *)&szBuffer, iBytesRead, (char *)&szTagBuffer, 4))
    			{
    				// Tag found
    				bTagFound = true;
    			}
    		}
    
    		// Check if we can find the version
    		if (bTagFound && !bVersionFound)
    		{
    			// Loop all versions (until .net framework 9
    			for (int i = 1; i < 10; i++)
    			{
    				// Set up version
    				sprintf(szVersionBuffer, "v%d.", i);
    
    				if (ValueExistsInCharBuffer((char *)&szBuffer, iBytesRead, (char *)&szVersionBuffer, 3))
    				{
    					// Version found
    					bVersionFound = true;
    				}
    			}
    		}
    
    		// Did we find both?
    		if (bTagFound && bVersionFound)
    		{
    			// This is an assembly
    			bAssembly = true;
    
    			// Don't search any longer
    			break;
    		}
    	}
    
    	// Close file
    	oFile.Close();
    
    	// Return result
    	return bAssembly;
    }
    
    //=====================================================================
    
    bool ValueExistsInCharBuffer(char * pBuffer, int iBufferSize, char * pValue, int iValueLength)
    {
    	// Loop complete buffer
    	for (int i = 0; i < iBufferSize - iValueLength; i++)
    	{
    		// Check if this part contains the value
    		for (int j = 0; j < iValueLength; j++)
    		{
    			// Check the character
    			if (pBuffer[i + j] == pValue[j])
    			{
    				// Check if we compared whole item
    				if (j == iValueLength - 1)
    				{
    					// Yes!
    					return true;
    				}
    			}
    			else
    			{
    				// Break internal loop
    				break;
    			}
    		}
    	}
    
    	// Not found
    	return false;
    }

  6. #6
    Join Date
    Feb 2000
    Location
    San Diego, CA
    Posts
    10,354

    Re: Check if DLL is managed or not


  7. #7
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: Check if DLL is managed or not

    @Tischnoetentoet: You are welcome. Good that you shared the code.
    Quote Originally Posted by kirants
    That's interesting - but I am not sure if finding exported functions is relevant to this problem.

    .NET binaries don't export any functions the way traditional Win 32 DLLs do.
    Last edited by Siddhartha; May 24th, 2007 at 03:39 PM.

  8. #8
    Join Date
    Feb 2000
    Location
    San Diego, CA
    Posts
    10,354

    Re: Check if DLL is managed or not

    Quote Originally Posted by Siddhartha
    That's interesting - but I am not sure if finding exported functions is relevant to this problem.
    Devil is in the details I wanted to point at the PE format, from which you can easily get the dependent dlls , mscoree.dll would show up there.

    The attached sample ( depends.exe ) has implemented it in a class called MODULE_DEPENDENCY_LIST. OP can simply use this class and find the dependent module name there.

  9. #9
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: Check if DLL is managed or not

    Quote Originally Posted by kirants
    I wanted to point at the PE format, from which you can easily get the dependent dlls , mscoree.dll would show up there.
    Ah, okay... Good point. May be that deserved explicit mention for the thread does not talk of dependent modules...

    As far as the current problem goes, I think the pattern finding would also help detect the .NET version that the assembly would require...

  10. #10
    Join Date
    Feb 2000
    Location
    San Diego, CA
    Posts
    10,354

    Re: Check if DLL is managed or not

    Quote Originally Posted by Siddhartha
    Ah, okay... Good point. May be that deserved explicit mention for the thread does not talk of dependent modules...
    Yeah. Sorry OP, missed it BTW, the depends sample I mentioned is in the thread link I provided.
    As far as the current problem goes, I think the pattern finding would also help detect the .NET version that the assembly would require...
    [/QUOTE]True. But is it foolproof ? I mean, how did you arrive at the pattern ?

  11. #11
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: Check if DLL is managed or not

    Quote Originally Posted by kirants
    True. But is it foolproof ?
    Today it is - tomorrow, who knows - that is why I called it a hack.

    On the otherhand - may be we can raise the same question on using a purely PE-based mechanism towards detecting .NET usage? It is theoretically possible for someone to get MSCOREE.DLL into his PE of a non-managed application...

    So, may be if one wants to fool-proof his application for a reasonably competent fool, he is better off using both techniques i.e. first look the PE up, and then look the search patterns up?
    Quote Originally Posted by kirants
    I mean, how did you arrive at the pattern ?
    By analyzing the binary contents of many managed assemblies.

    However, I must add that I analyzed the content of assemblies generated by Visual Studio only. It would be interesting to peek into a .NET assembly created by a competing compiler - though, I dare say that there aren't too many assemblies created by non-VS compilers out there.
    Last edited by Siddhartha; May 24th, 2007 at 04:17 PM.

  12. #12
    Join Date
    Oct 2002
    Location
    Germany
    Posts
    6,205

    Re: Check if DLL is managed or not

    I think I found an important piece of information w.r.t PE and .NET executibles:

    Quote Originally Posted by Wiki
    Microsoft's .NET Framework has extended the PE format with features which support the Common Language Runtime (an implementation of the .NET Virtual Machine). Among the additions are a CLR Header and CLR Data section. Upon loading a binary, the OS loader yields execution to the CLR via a reference in the PE/COFF IMPORT table. The CLR VM then loads CLR Header and Data sections.
    http://en.wikipedia.org/wiki/Portabl..._the_PE_format

    So, putting all of it together, I think the pattern actually belongs to the PE, and hence the hack is foolproof.
    Last edited by Siddhartha; May 24th, 2007 at 04:42 PM. Reason: Added last sentence...

  13. #13
    Join Date
    Feb 2000
    Location
    San Diego, CA
    Posts
    10,354

    Re: Check if DLL is managed or not

    Quote Originally Posted by Siddhartha
    I think I found an important piece of information w.r.t PE and .NET executibles:


    http://en.wikipedia.org/wiki/Portabl..._the_PE_format

    So, putting all of it together, I think the pattern actually belongs to the PE, and hence the hack is foolproof.
    This is interesting information. Based off of this link, I did some digging around and found this interesting information. One can get all this information again using just the PE structures.

    Here is a sample code that detects if a module is a managed one and also prints out the Framework version no.

    Code:
    // IsManaged.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <iostream>
    #include <windows.h>
    #include <tchar.h>
    #include <winnt.h>
    
    using namespace std;
    
    DWORD GetActualAddressFromRVA(IMAGE_SECTION_HEADER* pSectionHeader,IMAGE_NT_HEADERS* pNTHeaders, DWORD dwRVA)
    {
    	DWORD dwRet = 0;
    
    	for(int j = 0; j < pNTHeaders->FileHeader.NumberOfSections; j++,pSectionHeader++)
    	{
    		DWORD cbMaxOnDisk
                = min( pSectionHeader->Misc.VirtualSize, pSectionHeader->SizeOfRawData );
    
    		DWORD startSectRVA,endSectRVA;
    		
    		startSectRVA = pSectionHeader->VirtualAddress;
    		endSectRVA = startSectRVA + cbMaxOnDisk;
    
    		if ( (dwRVA >= startSectRVA) && (dwRVA < endSectRVA))
    		{
    			dwRet =  (pSectionHeader->PointerToRawData ) + (dwRVA - startSectRVA);
    			break;
    		}
    		
    	}
    
    	return dwRet;
    }	
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	TCHAR szPath[MAX_PATH];
    
    	if(argc < 2)
    	{
    		cout << "Please specify file name";
    		return 0;
    	}
    
    	LPTSTR lpszImageName = argv[1];
    	HANDLE hFile = CreateFile(lpszImageName, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    
    	//attempt the standard paths
    	
    	if(INVALID_HANDLE_VALUE == hFile)
    	{
    		//try to locate in windows directory
    		GetWindowsDirectory(szPath,MAX_PATH);
    		_tcscat(szPath,_T("\\"));
    		_tcscat(szPath,lpszImageName);
    		hFile = CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    	}
    
    	if(INVALID_HANDLE_VALUE == hFile)
    	{
    		//try to locate in system directory
    		GetSystemDirectory(szPath,MAX_PATH);
    		_tcscat(szPath,_T("\\"));
    		_tcscat(szPath,lpszImageName);
    		hFile = CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    	}
    
    	if(INVALID_HANDLE_VALUE != hFile)
    	{
    		//succeeded
    		HANDLE hOpenFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
    		if(hOpenFileMapping)
    		{
    			BYTE* lpBaseAddress = NULL;
    
    			lpBaseAddress = (BYTE*)MapViewOfFile(hOpenFileMapping,FILE_MAP_READ,0,0,0);
    			
    			if(lpBaseAddress)
    			{
    				//having mapped the executable to our process space, now start navigating through the sections
    
    				//DOS header is straightforward. It is the topmost structure in the PE file
    				//i.e. the one at the lowest offset into the file
    				IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)lpBaseAddress;
    
    				//the only important data in the DOS header is the e_lfanew
    				//the e_lfanew points to the offset of the beginning of NT Headers data
    				IMAGE_NT_HEADERS* pNTHeaders = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);
    
    				IMAGE_SECTION_HEADER* pSectionHeader = (IMAGE_SECTION_HEADER*)((BYTE*)pNTHeaders + sizeof(IMAGE_NT_HEADERS));
    
    				//Now, start parsing
    				//check if it is a PE file
    				
    				if(pNTHeaders->Signature == IMAGE_NT_SIGNATURE)
    				{
    					//start parsing COM table
    
    					DWORD dwNETHeaderTableLocation = pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
    
    					if(dwNETHeaderTableLocation)
    					{
    						//import data does exist for this module
    						IMAGE_COR20_HEADER* pNETHeader = (IMAGE_COR20_HEADER*)((BYTE*)pDOSHeader + GetActualAddressFromRVA(pSectionHeader,pNTHeaders,dwNETHeaderTableLocation));
    
    						if(pNETHeader)
    						{
    							cout << "This is a managed component" << "\n";
    							cout << "Framework version dependent on is : " << pNETHeader->MajorRuntimeVersion << "." << pNETHeader->MinorRuntimeVersion;
    						}
    						else
    						{
    							cout << "This is NOT a managed component" << "\n";
    						}
    					}
    					else
    					{
    						cout << "This is NOT a managed component" << "\n";
    					}
    				}
    				else
    				{
    					cout << "Not PE file\r\n";
    				}
    				UnmapViewOfFile(lpBaseAddress);
    			}
    			CloseHandle(hOpenFileMapping);
    		}
    		CloseHandle(hFile);
    	}
    	return 0;
    }
    Here are 2 very useful articles:
    Inside Windows: An In-Depth Look into the Win32 Portable Executable File Format, Part 2 -- MSDN Magazine, March 2002 - section The .NET Header
    http://www.devx.com/assets/summitdays/2679.pdf

  14. #14
    Join Date
    Nov 2003
    Posts
    2,185

    Re: Check if DLL is managed or not

    Nice code, I think that's much better than mine

    I will check it out!

    Best regards,

  15. #15
    Join Date
    Nov 2003
    Posts
    2,185

    Re: Check if DLL is managed or not

    Just to let you all know: the code provided by kirants is great and faster when large assemblies are used. With my code, the whole assembly is searched until the pattern is found. This can take a long time when a large file is used which is no assembly (which means that the whole file must be read).

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured