240 likes | 376 Views
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
E N D
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 pszDLLPathName); • 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 • Don’t execute DllMain or automatically load other DLLs needed by this one • LOAD_LIBRARY_AS_DATAFILE • 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 pszModuleName); • 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 DllWork #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\CurrentControlSet\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.