Solved

LoadLibrary on DLL file that's not on disk

Posted on 2001-08-15
32
2,647 Views
Last Modified: 2013-12-03
I'd like to know how I can call LoadLibrary and load a DLL file that's not physically located on any disk.  LoadLibrary loads a DLL file that's on disk and takes the files path name as a parameter.  I have the contents of the DLL in memory and would like LoadLibrary to load the DLL from memory instead.

As far as I can see, I have the following options.  I'd like some advice on which way to go and if anyone's got a better idea.

1.  Create my own network redirector and use a UNC path to LoadLibrary, having the redirector return the data to LoadLibrary from the in-memory-image
    NEGATIVE: A lot of work to create a redirector.

2.  Create a URL Moniker (protocol) that knows how to retrieve the data from memory and then pass in the URL to LoadLibrary (i.e. myurl://file.dll)
    NEGATIVE: LoadLibrary internally may call a low-enough level API to open the actual file where the API bypasses URL mapping -- that is, LoadLibrary may only work if it's an actual mounted file system.

3.  Use INJLIB or Microsoft's own "Detours" library to trap calls the CreateFile (or whatever), as they are called by LoadLibrary and return a file HANDLE that'll actually retrieve the file from memory.  Perhaps the HANDLE returned is a named-pipe and if that doesn't work. perhaps the calls to Read() are also trapped to return the data.  Depending on how much support LoadLibrary needs.
    NEGATIVES: The "Detours" library can't be used to do this on non-NT systems.  INLIB can be used, but the versions that are currently available on the Net (from May '94 issue of MSJ) only supported NT (no Windows 95 back then).  The author of INJLIB supposedly has updated INJLIB to work under newer Win32 OSs, but I can't seem to find that anywhere.

4.  Write the memory contents to disk and then call LoadLibrary.
    NEGATIVES:  There's no way to delete the file after calling LoadLibrary on it.  At least it didn't work when I tried it (yes, I called FreeLibrary on it.)
    WORKAROUND FOR NEGATIVE:
    Use MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT (and corresponding technique for 95/98/me) to mark the file for deletion after reboot.

Okay, I've rambled on enough about this.  I'd like to hear some opinions about which way I should go and why.

It's hard to pronounce a "right answer" for this type of questions, so I guess the only thing I can do is give it to the person that gives me the best argument for a particular approach (weighing complexity vs. functionality, of course.)

I consider this a pretty advanced topic, so I'll set it for 300 points.
0
Comment
Question by:shrif
  • 10
  • 6
  • 4
  • +4
32 Comments
 
LVL 32

Expert Comment

by:jhance
ID: 6391123
This is an interesting question....

Perhaps you could comment on why you are wanting to do this.  Knowing what you are trying to do might spur some alternate ideas into my mind.
0
 
LVL 1

Author Comment

by:shrif
ID: 6391129
I need to download a DLL from a web site on an Intranet and call an exported function in it.  The client cannot leave temp files around.
0
 
LVL 32

Expert Comment

by:jhance
ID: 6391142
>>The client cannot leave temp files around.

Why not?  Most systems today have megabytes of temp files lying about all over the place.  

I also don't understand why you can't delete the DLL when you are finished with it.  The file should be free to be deleted after you call FreeLibrary() on it.  But I'll have to admit that I've not tried this.
0
 
LVL 1

Author Comment

by:shrif
ID: 6391159
You know what, this is why I didn't originally state the reason behind it.

I am looking for a technical solution not someone's opinion of what I ought to do or not do.  Keep your opinions to yourself if you don't have a constructive solution to my problem.

I am only looking for technical answers -- I am not interested in whether you feel I should or shouldn't do something.

Thank you!

0
 
LVL 20

Accepted Solution

by:
Madshi earned 60 total points
ID: 6391576
>> 3.  Use INJLIB or Microsoft's own "Detours" library to trap calls the CreateFile (or whatever) [...] NEGATIVES: The "Detours" library can't be used to do this on non-NT systems.  INLIB can be used, but the versions that are currently available on the Net (from May '94 issue of MSJ) only supported NT (no Windows 95 back then).  The author of INJLIB supposedly has updated INJLIB to work under newer Win32 OSs, but I can't seem to find that anywhere.

Look here for my package, which is something like DetoursEx for winNT/2k/XP/9x/ME:

http://help.madshi.net/Data/madCodeHook.htm

The documentation is for the Delphi version of my package, but it's also available for ya C++ programmers.

However, I'm not sure how many APIs you will have to hook in order to get this whole thing running. LoadLibrary really goes VERY deep... CreateFile is only one part of it. As far as I know CreateFile internally uses memory mapped files for loading dlls - and as far as I know, it doesn't call CreateFileMapping, but instead an internal function, something like InternalCreateFileMapping, which is not exported...   :-(

>> 4.  Write the memory contents to disk and then call LoadLibrary. NEGATIVES:  There's no way to delete the file after calling LoadLibrary on it.  At least it didn't
work when I tried it (yes, I called FreeLibrary on it.)

This is exactly the point where we should work at. Normally when you load a dll and then unload it again, you *CAN* delete it. I'm 100% sure about that. There can be several reasons, why it's different in your case:

(1) Maybe the dll called LoadLibrary for itself, so your FreeLibrary call only deferenced the loader count, but didn't really unload the dll. Please check GetModuleHandle after having called FreeLibrary to make sure the dll is really detached from your process.
(2) Maybe the dll is loaded into other processes. This can be the case if the dll is using SetWindowsHookEx or other methods to go into remote processes.
(3) Maybe the dll uses some APIs which are very sensitive. E.g. if your dll uses MCI and doesn't cleanly uninit it, the dll remains in use until the next reboot.

I would suggest investing time into finding out why you can't delete the dll - because you should be able to. And that would be absolutely the easiest and best solution for you. No hacking into deep system APIs...

Regards, Madshi.
0
 
LVL 1

Author Comment

by:shrif
ID: 6391614
Regards,
    Thanks.  I'll give you more info on not being able to delete the DLL.  Okay, the new DLL is called temp.dll.  I have another DLL call main.dll.  Say a process implictly loads main.dll (by linking to main.lib, the import library).  When the process is invoked, main.dll's DllMain() gets called.  In there, in the "process attach", I create temp.dll and call LoadLibrary on it, caching the returned hinstance.  When the process terminates, it calls main.dll's DllMain() with "process detach".  In there, I call FreeLibrary on the cached hinstance of temp.dll and verify that no one else has the DLL loaded.  Right after the call to FreeLibrary, I attempt to delete temp.dll, but it fails.  However, if the process invokes some well-known routine in main.dll, which in turns does the same logic as above, calling FreeLibrary on the hinstance, then temp.dll *can* be deleted.

I believe that the same behavior occurs when the process loads main.dll explictly (via a call to LoadLibrary).

Now, I did this first about 6 years ago and at the time I was testing under NT 3.51 and the newly released Windows 95 and don't recall if the behavior was on both systems.  Suffice it to say, the solution should work on all Win32 systems.

Thanks for madCodeHook -- I'll check it out.
0
 
LVL 5

Assisted Solution

by:FengYuan
FengYuan earned 60 total points
ID: 6391645
5. Simulate LoadLibrary on the DLL yourself.

   5.1 Allocate a big enough virtual memory block, preferably at the preferred address of the DLL.
   5.2 Unpack the DLL into the memory, according to section alignment. Patch relocation if relocated.
   5.3 Load new DLLs needed by the DLL (use normal LoadLibrary).
   5.4 Patch DLL's import table.
   5.5 Call DLL's entry point.

www.fengyuan.com
0
 
LVL 1

Author Comment

by:shrif
ID: 6391664
FengYuan,
     I'm not sure if reimplementing much of the loader is really the best strategy -- I wouldn't really know where to start doing something like that.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6391684
>> In there, I call FreeLibrary on the cached hinstance of temp.dll and verify that no one else has the DLL loaded.

Please call GetModuleFileName(cachedhinstance) before calling FreeLibrary to verify that the cached hinstance is correct (probably it is, just to be sure). Then please after having called FreeLibrary call GetModuleHandle('test.dll') to check whether the dll is still loaded. It should not.

>> Right after the call to FreeLibrary, I attempt to delete temp.dll, but it fails.

What does GetLastError say?

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6391694
Hi FengYuan,

hmmm... what if the dll internally calls GetModuleFileName with its own HInstance value to find out the full path where the dll file is loaded from? That call would fail, would it not? I mean, your suggestion is not guaranteed to work with all dlls, some dlls might not work correctly because GetModuleFileName (and related APIs) fail, or am I wrong? Apart from that I do like your suggestion...

Regards, Madshi.
0
 
LVL 1

Author Comment

by:shrif
ID: 6391705
I like it!  I'll try this out in a test project and let you guys know.
0
 
LVL 30

Assisted Solution

by:Zoppo
Zoppo earned 60 total points
ID: 6391755
Hi shrif,

I don't know which OS you're working on, but in following article it's mentioned that
at least with Win98 you can't call FreeLibrary() within DllMain within DLL_PROCESS_DETACH:
http://support.microsoft.com/support/kb/articles/Q214/7/84.ASP

hope that helps,

ZOPPO
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6391807
Good link, Zoppo! What does that mean? It's evidently not recommended to do any LoadLibrary/FreeLibrary calls in DllMain within PROCESS_ATTACH/DETACH events. So the solution to the problem is "simply" to do the loading & freeing at another location in your program.

Regards, Madshi.
0
 
LVL 32

Expert Comment

by:jhance
ID: 6392088
>>>I am looking for a technical solution not someone's
>>>opinion of what I ought to do or not do.  Keep your
>>>opinions to yourself if you don't have a constructive
>>>solution to my problem.

>>>I am only looking for technical answers -- I am not
>>>erested in whether you feel I should or shouldn't
>>>do something.


Well just EXCUSE ME for trying to understand your problem and help!@


0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 5

Expert Comment

by:FengYuan
ID: 6393880
6. Dummy DLL.

   6.1 Wipe out code/data in the DLL.
   6.2 Write to disk.
   6.3 LoadLibrary the DLL.
   6.4 Restore old code/data.

www.fengyuan.com
0
 
LVL 9

Assisted Solution

by:ShaunWilde
ShaunWilde earned 60 total points
ID: 6394922
I just ran the following code snippet

#include "stdafx.h"
#include <windows.h>

int main(int argc, char* argv[])
{
     ::CopyFile("dllunload.dll","dlltemp.dll",FALSE);
     HMODULE hModule=::LoadLibrary("dlltemp.dll");
     ::FreeLibrary(hModule);
     ::DeleteFile("dlltemp.dll");
     return 0;
}


and the dlltemp was unloaded fine and deleted.
0
 
LVL 15

Assisted Solution

by:NickRepin
NickRepin earned 60 total points
ID: 6402905
Most easiest way, not elegant though - just because the Windows does not allow to do anything else.

In DLL_PROCESS_DETACH, create the .BAT file and call CreateProcess() on it.

-----------------
@echo off
again:
del drive:\path\temp.dll
if not exist drive:\path\temp.dll goto quit
echo waiting
echo waiting
... several times
echo waiting
echo waiting
goto again

quit:
del drive:\path\nameOfTheBatFileItself.bat
--------------

This BAT file will delete the DLL first, then itself second.
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 6402921
There is no way to really free another dll inside DLL_PROCESS_DETACH, so the bat file is the only option, in my humble opinion. CreateProcess() should use DETACHED_PROCESS of course.

This solution is a universal one for any vesion of Windows, and it is much more reliable that any API interception - detour etc.

Of course if you have time you can improve your skills by writting URL monikers or network redirectors. The only disadvantage is that they are separate programs that need to be distributed, installed etc.

As to the memory-based DDLs, I wish this could be possible. Unfortunately the 100% emulation is not possible, at least without a need to hack Windows. It means this way is not reliable as well.
0
 
LVL 1

Author Comment

by:shrif
ID: 6402939
Thanks Nick.
The batch file way is my current approach.  I actually use a tiny win16 program that gets launched and waits and tries 256 times to delete a given exe.  It's win16 because the same solution was used for both win16/win32 programs (yes, this is old code.)
0
 
LVL 1

Author Comment

by:shrif
ID: 6402940
Madshi,
     Your madCodeHook looks pretty awesome.  I'll give it a try.  If it works, I'll use that approach.  I'll let you know.

Thanks.
0
 
LVL 1

Author Comment

by:shrif
ID: 6402960
Madshi,
     Your madCodeHook looks pretty awesome.  I'll give it a try.  If it works, I'll use that approach.  I'll let you know.

Thanks.
0
 
LVL 9

Expert Comment

by:ShaunWilde
ID: 6403146
my earlier code snippet - shows that FreeLibrary does unload the dll - I even experimented by adding GetProc addresses and calling code before calling FreeLibrary - still unloaded and deleted.

do you have anything else in your code keeping the library loaded or file locked? Have you closed all the handles that you used to create the file on the disk?
0
 
LVL 1

Author Comment

by:shrif
ID: 6403696
Shaunn, when you posted the comment of which you speak, it was obvious that you didn't read the previous comments because there I explained the conditions under which FreeLibrary wasn't working with me.  I didn't bother to respond to you because I just got through explaining it in a comment prior to yours.

Then, another user, Zoppo, confirmed my findings by posting the knowledgebase article describing the scenario.

Did you miss that comment, too?

0
 
LVL 20

Expert Comment

by:Madshi
ID: 6403831
Some thoughts:

(1) Are both the process and the main.dll written by you? Then why don't you simply export a function from main.dll, which unloads and deletes test.dll. You can then call this exported function from the process, before you close the process. That would be by far the easiest and cleanest solution (at least IMHO).

(2) If you want to play with madCodeHook, I would suggest using a different approach then the one you thought about. Simulating a DLL load from memory is too difficult, I think. Why not hooking PostQuitMessage and ExitProcess? You can then in the callback function unload the test.dll and delete it - and then thereafter call continue with PostQuitMessage/ExitProcess. However, I think this is overkill. I like (1) much more. Or alternatively Nick's batch solution.

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6403837
Shaun, as far as I understand your code (I'm not too sure, because I'm a Delphi programmer) you're doing all the stuff in the initialization of an application. The problem that shrif has occurs in the finalization of a dll. That are quite different things.
0
 
LVL 9

Expert Comment

by:ShaunWilde
ID: 6404023
Shrif

> it was obvious that you didn't read the previous
> comments because there I explained the conditions under
> which FreeLibrary wasn't working with me

I was responding to the comment

<snip>

4.  Write the memory contents to disk and then call LoadLibrary.
   NEGATIVES:  There's no way to delete the file after calling LoadLibrary on it.  At least it didn't
work when I tried it (yes, I called FreeLibrary on it.)

</snip>


the fact I missed your ramble about app -> dll -> dll - was due to the fact I didn't refresh seeing the question - and then posting the comment

However since the comment about not using FreeLibrary in DllMan is mentioned in the helpfile see FreeLibrary (which I assumed you read) and that you didn't respond to Zoppos comment - I assumed that it didn't apply in your case

so no it wasn't obvious that I hadn't read the above comments quite the opposite - I had read them but misinterprted you lack of response to other comments

The fact is you might as well do what madshi suggested and rework your code - something jhance would have mentioned earlier - eg tell us what you want to do and we'll see how to do it - rather then go a really complex route - a slight rework of your code would be a lot easier


0
 
LVL 15

Expert Comment

by:NickRepin
ID: 6405306
There is another possibility, but it is a hack.

UnmapViewOfFile(LPCVOID(hTempDll));
CloseHandle(hSomeInternalFileHandleForTempDll);
DeleteFile("temp.dll")

hSomeInternalFileHandleForTempDll is a file handle which is obtained via CreateFile("Temp.Dll") by Windows loader. It is possible to enumerate all opened handles and find the handle which is associated with a given file name.
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 6405456
This works on my NT4

#include <windows.h>
#include <iostream.h>
#include <conio.h>

void main()
{
   HINSTANCE hTempDll=LoadLibrary("b.dll");
   if(!hTempDll)
   {
      cout<<"Cannot load DLL"<<endl;
      return;
   }

   CHAR buf[MAX_PATH];
   GetModuleFileName(hTempDll,buf,sizeof(buf));

   if(!DeleteFile(buf))
   {
      cout<<"1st DeleteFile failed - as expected"<<endl;
   }

   UnmapViewOfFile(hTempDll);
   
   if(DeleteFile(buf))
   {
      cout<<"Deleted!"<<endl;
      FreeLibrary(hTempDll);
   }
}
0
 
LVL 1

Author Comment

by:shrif
ID: 6408475
Holy smoke, Nick!  That's incredible.

Do you want a job?

:)

Thanks.  Let me give this a shot and I'll get back to you.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Mixed results 10 69
Microsoft Query from QuickBooks 9 56
Is COM supported from Apache 1 38
Need more details 5 85
This article shows how to make a Windows 7 gadget that accepts files dropped from the Windows Explorer.  It also illustrates how to give your gadget a non-rectangular shape and how to add some nifty visual effects to text displayed in a your gadget.…
This article shows how to make a Windows 7 gadget that extends its U/I with a flyout panel -- a window that pops out next to the gadget.  The example gadget shows several additional techniques:  How to automatically resize a gadget or flyout panel t…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now