4

Suppose I have a compiled dynamic library: .dll, .lib, .so etc. Is it (theoretically) possible to automatically create C header file for such a library? Is there an existing tool that does that?

Intuitively it looks to me like it should be possible. After all, the linker is able to find the necessary symbols inside the dynamic library and resolve those symbols at runtime. But still, some information may be missing. If so, which one? Argument types? The return type? I know that when a C++ library is compiled without the "extern" flag, with the information about the types being embedded into the name. Would this kind of library be "reverse-engineerable" ?

Update. Thanks for all the responses -- it seems like there is a consensus that it is generally NOT possible, unless one is willing to try really hard (I guess by examining the assembly and seeing how many parameters are being popped off from stack) OR the library is compiled in the debug mode.

The purpose of this question is neither to obfuscate my own library, nor to decompile an existing one. Rather, it is a theoretical question: is such action possible for a generic library? The reason for my curiosity is that I'm trying to understand the legal implications of having a library licensed under GPL while its header files licensed under LGPL.

  • @BasileStarynkevitch The motivation is in the first two sentences: // Is it (theoretically) possible to automatically create C header file for such a library? Is there an existing tool that does that? // – rwong Oct 18 '17 at 18:43
  • That is not enough. Is it from the point of view of finding more about a library, or on the contrary to hide it more against reverse-engineering? – Basile Starynkevitch Oct 18 '17 at 18:45
  • 1
    "legal implications of having a library licensed under GPL while its header files licensed under LGPL." IANAL, but that does not seem to make any sense. Ask a better question on opensource.stackexchange.com – Basile Starynkevitch Oct 18 '17 at 19:08
  • 1
    legal advice is off-topic per help center – gnat Oct 18 '17 at 21:07
  • @gnat I understand that. Which is why I'm not asking a legal advice, I'm asking a technical question. The word "legal" only came up there because I was asked for the reason for asking this question. The question however is asked generally, and other people who have other reasons might find it useful one day. – Pasha Oct 19 '17 at 15:55
7

In general, it won't be possible (at least not with ELF files on Linux). Because type and signature information is not kept (e.g. in ELF symbol files). But C++ compilers are doing name mangling to encode some type information in their ELF symbol name. However, C compilers don't do that. And C++ name mangling doesn't tell enough (e.g. it would tell that the first argument of some function is a Foo* pointer, but it won't describe the fields inside class Foo).

For example, you can't even (reliably) know how many arguments a given function (notably a C one) is expecting, and even more their type. And some functions don't have externally visible names (e.g.static functions, but read also about visibility function attribute on Linux). Read more about ABIs (e.g. here for Linux on PCs) and calling conventions.

However, if the code has been compiled (using -g) with debug information in DWARF, it could be possible. Read also about the strip command.

And if you have additional a priori information (for example, knowing that the given library is distributed by Debian) it probably should be possible. Some projects (perhaps FOSSology, but I could be wrong) simply guessed free software libraries by comparing their constant literal strings against a previously built database of them.

BTW, what you are looking at is more or less called a decompiler and the process would be decompilation. Read also about obfuscation.

With a lot of efforts and resources (e.g. what the NSA would be capable of) many things could be in practice possible, but difficult and costly.

3

No, this is not generally possible. Libraries are self-describing in that they list all available symbols (functions and variables with external linkage). But they do not contain sufficient information about the types.

This is not just a matter of providing the names of all types, e.g. that a function receives or returns a struct Foo. To properly satisfy the calling convention we need to know the layout and specifically the alignment of that type. So we would need to embed the complete type information that would also be provided by a header. (Of course incomplete types can be elided.)

The header files can be seen as an interface description language that provide all this information.

It is of course possible to design a dynamic library format that contains all relevant information, notably JVM .class files do that.

As a historic note: C did not enforce parameter types prior to standardization with C89 (“ANSI C”). A function declared without a prototype could not be checked in any way, and the programmer would have to know the correct types. In this sense, functions in dynamic libraries still behave a lot like functions in K&R C.

3

It depends on the compilation system, and especially if only C or a C & C++ compiler, as these are aspects of the development system that are not standardized behaviors.

Some systems will define a DLL's entry points but not even detect mismatched parameter count, as the raw identifier name is exported without mangling or decoration.

This highlights that insufficient metadata exists in raw DLL mechanism to automatically infer a .h header file.

Other linkage systems capture the parameter count but not the full parameter types. For example, on windows __stdcall:

An underscore _ is prefixed to the name. The name is followed by the at sign @ followed by the number of bytes (in decimal) in the argument list. Therefore, the function declared as int func( int a, double b ) is decorated as follows: _func@12.

Note that the return type is not encoded in decoration (most languages won't support overloads where only the return type differs).

Beyond that, even name mangling of C++ does ensures only matching between caller and callee of the same signature. Thus, while all parameter types are matched to ensure a full signature match of the proper overload, actually type declarations (e.g. of structs and such) that we would expect to see in a header file are absent. Thus, only the name of a struct type will be available in the mangled/decorated name, but not that struct's members.

C++ also does not always use the name export mechanism available in DLL's, and this could go to inline methods and private methods (and theoretically virtual methods also). Note here I'm distinguishing between DLL exports (post compilation and post static linking that creates the DLL) and object modules (post compilation but before static linking).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.