Link to home
Start Free TrialLog in
Avatar of shrif
shrif

asked on

LoadLibrary on DLL file that's not on disk

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.
Avatar of jhance
jhance

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.
Avatar of shrif

ASKER

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.
>>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.
Avatar of shrif

ASKER

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!

ASKER CERTIFIED SOLUTION
Avatar of Madshi
Madshi

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of shrif

ASKER

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.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of shrif

ASKER

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.
>> 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.
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.
Avatar of shrif

ASKER

I like it!  I'll try this out in a test project and let you guys know.
SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
>>>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!@


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
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
Avatar of shrif

ASKER

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.)
Avatar of shrif

ASKER

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.
Avatar of shrif

ASKER

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.
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?
Avatar of shrif

ASKER

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?

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.
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.
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


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.
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);
   }
}
Avatar of shrif

ASKER

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.