8

On Windows, several arguments are passed to the DllMain constructor:

BOOL WINAPI DllMain(  
  __in  HINSTANCE hinstDLL,  
  __in  DWORD fdwReason,  
  __in  LPVOID lpvReserved  
);

From hinstDLL I can get the fully qualified file name of the DLL itself using GetModuleFileName():

LPTSTR str = new TCHAR[256];  
int libNameLength = GetModuleFileName(hinstDLL, str, 256);  
delete[] str;  

In the example above, str now contains the full name of the DLL just loaded, e.g., C:\Windows\System32\MyFile.dll.

On Linux, no arguments are passed to the shared object constructor:

void `__attribute__` ((constructor)) on_load(void);

How do I get the full name of the DLL in this case? Extra credit if your solution works on Mac, too. :-)

  • I don't know that there is a good way. My question in situations like this is "Why do you want to know?". By stepping back a level you may find there's a path to your real goal without taking the step that's currently blocking you. – Omnifarious Oct 29 '09 at 08:37
  • Good question. I want to know, because I'm developing a CSP and a PKCS#11 module (DLL files) both of which need to verify their own integrity when they're loaded. Both DLL files are loaded by the OS, so my entry point is the constructor. Currently, the best idea I have for verifying the integrity of the DLL file is to calculate a hash of the DLL file in the constructor and then send that hash off to a central server which can verify the correctness of the hash. However, I need the file name of the DLL in order to be able to calculate the hash. –  Oct 29 '09 at 08:58

2 Answers2

5

I think the dladdr function might do what you want. From the man page:

The function dladdr() takes a function pointer and tries to resolve name and file where it is located. Information is stored in the Dl_info structure:

typedef struct {
    const char *dli_fname;  /* Pathname of shared object that
                               contains address */
    void       *dli_fbase;  /* Address at which shared object
                               is loaded */
    const char *dli_sname;  /* Name of nearest symbol with address
                               lower than addr */
    void       *dli_saddr;  /* Exact address of symbol named
                               in dli_sname */
} Dl_info;

If no symbol matching addr could be found, then dli_sname and dli_saddr are set to NULL.

dladdr() returns 0 on error, and non-zero on success.

So you just give it a function pointer (like the address of the constructor itself), and it will give you the filename and a bunch of other information. Here's some sample code:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

__attribute__((constructor))
void on_load(void) {
    Dl_info dl_info;
    dladdr(on_load, &dl_info);
    fprintf(stderr, "module %s loaded\n", dl_info.dli_fname);
}

EDIT: It looks like this function exists on OS X, too, with the same semantics.

Jay Conrod
  • 28,943
  • 19
  • 98
  • 110
1

One supremely ugly and horrible way to do this is to look through /proc/pid/maps and look for the mapping that encompasses the address of the on_load function being executed.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • 1
    I started going down this road yesterday, and I've not dismissed it *completely* yet, because it's currently the only viable solution I know. It sends chills down my spine, too, though. –  Oct 29 '09 at 09:00