DLLs, Continued

advertisement
Win32 Programming
Lesson 20: Advanced DLL Techniques
Where are we?


We’ve looked at DLLs from a
build/link/execute perspective
But there are many different tricks you can
use to get more “bang for your buck”
Explicit DLL Loading




To use a DLL, a process must load it
We’ve looked at doing this implicitly via load
and runtime and building in the calls
Can be done when the application is running
too
The beauty of this technique is that you don’t
need to know too much about the DLL at
compile time
Explicit Loading

Simple to accomplish via LoadLibrary:



HINSTANCE LoadLibrary(PCTSTR pszDLLPat
hName);
HINSTANCE LoadLibraryEx(
PCTSTR pszDLLPathName,
HANDLE hFile,
DWORD dwFlags);
HINSTANCE is a pointer to the virtual memory
where the DLL is mapped
Parameters


hFile: Reserved for future use – must be
NULL
dwFlags: combination of
DONT_RESOLVE_DLL_REFERENCES,
LOAD_LIBRARY_AS_DATAFILE, and
LOAD_WITH_ALTERED_SEARCH_
PATH
Implications

DONT_RESOLVE_DLL_REFERENCES


LOAD_LIBRARY_AS_DATAFILE


Don’t execute DllMain or automatically load other DLLs
needed by this one
Useful if you want to load an .exe file without executing it
LOAD_WITH_ALTERED_SEARCH_ PATH

Changes the order in which directories are searched in
order to load the DLL
Explicitly unloading the DLL


BOOL FreeLibrary(HINSTANCE
hInstanceDLL);
And also:



VOID FreeLibraryAndExitThread(
HINSTANCE hinstDll,
DWORD dwExitCode);
Why?
And of course, this is all predicated on usage
counts…
Other Explicit calls

Can check to see if a DLL is already loaded via:


HINSTANCE GetModuleHandle(PCTSTR pszModuleNa
me);
Would use like this:

HINSTANCE hinstDll = GetModuleHandle("MyLib");
// DLL extension assumed
if (hinstDll == NULL) {
hinstDll = LoadLibrary("MyLib");
// DLL extension assumed
}
You can also…


Get the full path of a loaded DLL
DWORD GetModuleFileName(
HINSTANCE hinstModule,
PTSTR pszPathName,
DWORD cchPath);
Second



Once a DLL has been explicitly loaded you
need to get the address of the functions you
want
FARPROC GetProcAddress(
HINSTANCE hinstDll,
PCSTR pszSymbolName);
Where pszSymbolName is either:


The name e.g. “MyFunc”
The resource number MAKEINTRESOURCE(2)
Warning!


If you use the name, it can be slow, as you
must search through the names of all exported
things
If you use the second function,
GetProcAddress can return a non NULL value
even though it has failed…
DLLs (startup)



A DLL can have a DllMain function which is
called upon startup
This routine isn’t required – you implement it
if you need it
Note the name is case sensitive. If you use
DLLMain you’re not going to get called
Code Example
BOOL WINAPI DllMain(HINSTANCE hinstDll,
DWORD fdwReason,
PVOID fImpLoad
){
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
// The DLL is being mapped into the process's address space.
break;
case DLL_THREAD_ATTACH:
// A thread is being created.
break;
case DLL_THREAD_DETACH:
// A thread is exiting cleanly.
break;
case DLL_PROCESS_DETACH:
// The DLL is being unmapped from the process's address space.
break;
}
return(TRUE); // Used only for DLL_PROCESS_ATTACH }
hInst


hInstance passed in is where the DLL got
loaded – usually stored for later use in a
Global
Remember though that when your DllMain is
running, other DLLs may not have initialized.
Thus, don’t call other DLLs within your
DllMain
Delay-loading a DLL


You can opt to delay load an implicitly-linked
DLL
Beneficial because:


Faster startup – you can save time initializing
DLLs later when you need them
Backward compatibility – you can avoid calling
missing functions and handle the error yourself
Function Forwarding



You can forward an exported function from
one DLL to another
// Function forwarders to functions in DllWor
k
#pragma comment(linker, "/export:SomeFunc
=DllWork.SomeOtherFunc")
Pretty simple eh?
Known DLLs


Life isn’t fair… some DLLs get special
treatment
Look at:


HKEY_LOCAL_MACHINE\SYSTEM\CurrentC
ontrolSet\Control\Session Manager\KnownDLLs
These DLLs always load from the same place
Version Independence



We are all familiar with DLL Versioning
problems
Can fix using .local files. If a file called
calc.exe.local exists, for example, in the
directory in which calc.exe resides, DLLs are
loaded from that directory first
For new systems think about Side-by-Side
assemblies (see here)
Rebasing DLLs




When a module loads, it has a preferred base
address it would like to load at
However, that address is not always going to
be available
If a module is relocated, internal structures
have to be “fixed up” to deal with this new
location (why?)
This is slow
Instead


You can use the rebasing tool to modify the
DLLs so that this relocation is done on disk,
and not on the fly
Don’t ever ever *ever* rebase system DLLs
Binding a DLL



Similar in some senses to Rebasing
Improves performance
Saves the system having to fix up the module
import section
What can we do with it?

This 
Assignment





Not due until April 26th – that’s over two
weeks
NO MERCY on people who say on the 19th
“I’m stuck!”
This is somewhat tricky
I suggest you start work on it immediately…
We will look at your code in a week in SVN
and assign some points for what you’ve done
Calls…

I want you to be able to intercept the following Winsock
system calls:








connect
send
recv
closesocket
You should be able to launch an arbitrary monitored process
(specified on the Command line)
You should be able to display the calls to connect, send, recv
and closesocket along with their parameters
Have fun 
I strongly suggest you read Ch 22.
Download