Export function from dll by ordinal only does not hide function name

4.4k views Asked by At

In Visual Studio I want to export function from dll by ordinal only. In source I define function to be:

int my_function() { return 101; }     // without declspec(dllexport)

In the .def file:

LIBRARY MyDll
    EXPORTS
        my_function @ 1 NONAME        // NONAME, export directory will not contain function name

In main program I use it like this:

#pragma comment(lib, "MyDll.lib")

declspec(dllimport) int my_function();

int main(int argc, char* argv[])
{
    int a = my_function();

    return 0;
}

The code compiles and links fine. NONAME attribute is documented to export function by ordinal only.

Export directory of MyDll has NumberOfNames set to zero, so dll itself does not contain name information. Exe file imports function by ordinal value, so exe also does not contain name information.

I tried different configurations (debug, release), still program links fine. Maybe lib file contains some sort of mapping between function names and ordinals? I read that lib file contains function thunks, so we can have something like this inside lib file:

my_function @ 1:
    jmp IAT[0]
my_another_function @ 2:
    jmp IAT[1]

And in-file exe import table:

OriginalFirstThunk           FirstThunk
 0x80000001 (@ 1)          0x80000001 (@ 1)   // ordinal 1 will go through IAT[0]
 0x80000002 (@ 2)          0x80000002 (@ 2)   // ordinal 2 will go through IAT[1]

And in-memory exe import table:

OriginalFirstThunk           FirstThunk
 0x80000001 (@ 1)             IAT[0]
 0x80000002 (@ 2)             IAT[1]

If so then in order to hide function name we should provide only dll file, and that means user will need to load dll with LoadLibrary and use GetProcessAddress? What I am missing here?

1

There are 1 answers

0
Harry Johnston On

From Exporting Functions from a DLL by Ordinal Rather Than by Name on MSDN:

If you want to optimize your DLL's file size, use the NONAME attribute on each exported function. With the NONAME attribute, the ordinals are stored in the DLL's export table rather than the function names. This can be a considerable savings if you are exporting many functions.

In other words, NONAME only affects the DLL, not the import library. So the behaviour you are observing is as-intended.

From the documentation for EXPORTS:

The optional keyword PRIVATE prevents entryname from being included in the import library generated by LINK.

So if you use both PRIVATE and NONAME you should get the results you want. However, this defeats the purpose of providing an import library in the first place, at least as far as that particular function goes. It might be useful if you want some functions that can be accessed via the import library, and some that can only be accessed via GetProcAddress.

You might prefer to provide an alias for the function that the end users can use to link to it, e.g.,

LIBRARY MyDll
    EXPORTS
        function1=my_function @ 1 NONAME
        function2=my_other_function @ 2 NONAME

This should put the fake names "function1" and "function2" into the import library so that the end users can link to the functions using those names, while still hiding the secret names "my_function" and "my_other_function" in both the import library and the DLL. (Not that I understand why the names need to be secret in the first place, but YMMV.)

Disclaimer: I haven't tried this myself, this answer is based solely on the documentation.