Click here to Skip to main content
6,595,854 members and growing! (19,329 online)
Email Password   helpLost your password?
Desktop Development » Shell and IE programming » General     Intermediate License: The Code Project Open License (CPOL)

Restricting DLL loading

By JBoschen

How to restrict a shell extension from being loaded during the development process.
VC6Win2K, WinXP, Win2003, Dev
Posted:18 Aug 2004
Views:38,619
Bookmarked:29 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
23 votes for this article.
Popularity: 6.52 Rating: 4.79 out of 5
1 vote, 4.3%
1

2

3
2 votes, 8.7%
4
20 votes, 87.0%
5

Background

During the development of a shell extension, you have little control over when your extension can and cannot be loaded. This becomes rather annoying as you try to rebuild and are prevented from doing so because the file is in use. There does exist a set of registry keys to help with this problem, but they don't exactly make the process developer friendly.

The solution I'll present is simple and effective. I've been using it for some time and thought I'd share it with the community.

The Solution

The shell loads all extensions by calling the KERNEL32.DLL function, LoadLibrary, with the path of the DLL as registered in the registry. LoadLibrary goes through the process of loading the DLL into the address space of the calling process, typically explorer.exe with shell extensions, resolving other library imports, and finally calling the DLL's entry point function, DllMain. DllMain performs any initialization and returns a BOOL value of TRUE or FALSE to indicate success or failure. If FALSE is returned, the system immediately detaches the DLL from the process, unloads and closes it, and returns NULL to the caller of LoadLibrary to indicate that the DLL was not loaded successfully. So with this knowledge, we have a sure fire way of preventing a DLL from being loaded by a process. The remaining trick is to specify exactly which processes, or more specifically, which modules can or cannot load the DLL. Enter IsDebuggerPresent and GetModuleHandle.

Being that you are the one developing the DLL, you have a good idea of exactly which modules you do or do not want loading your DLL. For one, it is a fairly safe assumption that if the calling process is being debugged, then you want your DLL to be loaded. But there are also some processes that need to load the DLL, such as REGSVR32.EXE, which typically do not run in the context of a debugger. To support both cases, we have two functions available from KERNEL32.DLL. IsDebuggerPresent, which returns TRUE when the calling process is being debugged and FALSE otherwise. And GetModuleHandle which returns the HMODULE of the specified module if it is loaded in the process, and NULL otherwise. So with these two functions, we create a rule that states:

If the process is being debugged, or if the process contains a known module, allow DllMain to succeed and return TRUE, otherwise fail DllMain and return FALSE.

The Code

  • Part 1 - Known Modules

    We first need to create a list of modules that are permitted to load the DLL in all contexts. This will include applications such as REGSVR32.EXE so that the DLL can use its registration features, other applications which might need to load the DLL for things such as resource acquisition, or other modules which utilize the DLL as part of a package or feature, such as DLLHOST.EXE or SVCHOST.EXE.

    /*********************************************************
     *  _szUnrestrictedModules
     *      Modules which can load this library.
     */
    LPCTSTR _szUnrestrictedModules[] =
    {
        _T("REGSVR32.EXE"),
        _T("SVCHOST.EXE")
    };
  • Part 2 - Compiler control

    Next, we want a compiler flag to disable this feature for release builds or for when we do not want to restrict the DLL from loading.

    /*********************************************************
     * When the _LOADRESTRICTIONS_ON flag is defined, DllMain 
     * succeeds for the following conditions:
     *  1) The process is being debugged.
     *  2) One of the modules listed in _szUnrestrictedModules 
     *     is loaded in the process.
     * 
     * This prevents apps like the shell from loading and 
     * locking the module, preventing new builds. The 
     * _szUnrestrictedModules is needed so that non-debug apps 
     * like regsvr32 can load the module.
     * 
     * Defining _LOADRESTRICTIONS_OFF will disable this 
     * functionality.
     */
    #ifndef _LOADRESTRICTIONS_OFF
        #define _LOADRESTRICTIONS_ON
    #endif
  • Part 3 - Validation

    Finally, we want a function to perform the restriction checks.

    /*********************************************************
     *  _IsUnrestrictedProcess
     *      Checks if the current process is allowed to load 
     *      this module.
     */
    BOOL __stdcall _IsUnrestrictedProcess( ) throw()
    {
      if ( ::IsDebuggerPresent() )
      {
        return ( TRUE );
      }
    
      for ( size_t idx = 0; idx < 
            (sizeof(_szUnrestrictedModules) / sizeof(LPCTSTR));
            idx++ )
      {        
        /* Check for the module by attempting to retrieve 
         * its HMODULE */
        if ( NULL != 
             ::GetModuleHandle(_szUnrestrictedModules[idx]) )
        {
            return ( TRUE );
        }
      }
     
      return ( FALSE );
    }

Now, all that remains is to call the _IsUnrestrictedProcess function from DllMain and succeed or fail accordingly.

extern "C" BOOL WINAPI DllMain( HINSTANCE hInstance,
                                DWORD dwReason, 
                                LPVOID lpReserved )
{
    /* Do load restrictions, if enabled */
#ifdef _LOADRESTRICTIONS_ON
  if ( !_IsUnrestrictedProcess() )
  {
    return ( FALSE );
  }
#endif

  /* Perform other initialization here if necessary */

  return ( TRUE );
}

And there we have it. Adding this code to a shell extension DLL prevents it from being loaded except for those conditions that we specify. This allows rebuilds without waiting for the system to unload the DLL.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

JBoschen


Member

Occupation: Web Developer
Location: United States United States

Other popular Shell and IE programming articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 10 of 10 (Total in Forum: 10) (Refresh)FirstPrevNext
GeneralThis does not work on vista PinmemberJaved Akhtar Ansari20:01 24 Nov '08  
GeneralRe: This does not work on vista PinmemberJaved Akhtar Ansari20:42 24 Nov '08  
GeneralRe: This does not work on vista PinmemberJaved Akhtar Ansari20:50 24 Nov '08  
GeneralThanks ! PinmemberGuimaSun13:56 10 Sep '04  
GeneralExcellent PinmemberICBM20:25 24 Aug '04  
GeneralRe: Excellent PinprotectorHeath Stewart9:50 26 Aug '04  
GeneralRe: Excellent Pinmemberfeeadded8:07 10 Sep '04  
GeneralWith .NET? PinsitebuilderUwe Keim19:09 22 Aug '04  
GeneralRe: With .NET? PinprotectorHeath Stewart11:26 26 Aug '04  
GeneralBrilliant !! PinmemberWREY7:40 20 Aug '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 18 Aug 2004
Editor: Smitha Vijayan
Copyright 2004 by JBoschen
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project