16

For VC, I can write a DEF file and use the 'NONAME' directive to leaving only the ordinal number in dll's export table.

How could I do the same thing with gcc and ELF format shared library?

Or, is there something equivalent in ELF shared library like the ordinal number in a PE format DLL? If not, how could I hide the exported symbol's name within a shared library?

======================================

UPDATE: Some additional descriptions:

In Windows, you can export a function by only place a integer ID (the ordinal) with an empty name.

To show it, the normal layout for a dll's export table looks like this: http://home.hiwaay.net/~georgech/WhitePapers/Exporting/HowTo22.gif.

the "NONAME" one looks like this: http://home.hiwaay.net/~georgech/WhitePapers/Exporting/HowTo23.gif.

Notice the functions name are "N/A" in the second picture. Here is a full explaination of it: hxxp://home.hiwaay.net/~georgech/WhitePapers/Exporting/Exp.htm.

======================================

UPDATE: A lot of thanks for everyone who make me advice. Finally, I decide to keeping use static library on linux/posix platforms. But extract the small "special part" (which is using some features not suitable for static lib, e.g: TLS Slot, etc.) to a normal shared-library. Because the small normal shared-library only doing few things, and these work are totally insensitive, so there is no need to obscure/hide its APIs.

I think it's the simplest way to solve my problem :-D

ASBai
  • 724
  • 2
  • 7
  • 17
  • if I striped a dynamic symbol from the .so file, could I call it again from another application by using something like an ordinal number? – ASBai Mar 10 '12 at 18:04
  • 1
    The point is that most Linux people don't know what a `NONAME` directive means in the Windows world (at least I don't, since I never used or coded for Windows). So you should explain what that means (and what is an "ordinal number in a PE"). More generally, explain what you really want to achieve, without reference to how Windows is doing it. – Basile Starynkevitch Mar 10 '12 at 18:36
  • 1
    Your comments on the various answers include more detailed information than the question. You should consider editing your question to include this information. – André Caron Mar 10 '12 at 18:39
  • Ok, you are right Basile, I'll append some additional explanation for it. But in short words: I neet export an function but hide its name. – ASBai Mar 10 '12 at 18:41
  • 1
    But exporting a function and hiding its name is, in the Linux world, a contradiction in itself. You'll have a header file for your library, and that header file mention exported functions by *names* (otherwise, that function is not exported, even if by some dirty tricks it could be made reachable). – Basile Starynkevitch Mar 10 '12 at 18:43
  • @ASBai: I added links in your question to clarify what the terms and abbreviations mean. – André Caron Mar 10 '12 at 18:45
  • @BasileStarynkevitch: then, your answer to the last part of the question is "no, there is no equivalent to PE ordinal numbers in the ELF format, symbols are only resolved by name", which indirectly answers the question "is there a way to do it with GCC?" (there is no such thing, so there is no compiler support for it). – André Caron Mar 10 '12 at 18:46
  • @BasileStarynkevitch: "and that header file mention exported functions by names". Yes, In windows the "symbol name -> ordinal number" mapping is done by the supporting .lib (i.e: lib*.a) file automatically. – ASBai Mar 10 '12 at 18:55
  • But you really really should explain what you really want to achieve in Linux, not just trying to mimick Windows's behavior. – Basile Starynkevitch Mar 10 '12 at 19:10

5 Answers5

16

The previous answers regarding attribute ((visibility ("hidden"))) is good when you want to maintain the code long term, but if you only have a few symbols that you want visible and want a quick fix... On the symbols that you want to export use, add

__attribute__ ((visibility ("default"))) 

Then you can pass -fvisibility=hidden to the compiler

There is a thorough explanation here:

http://gcc.gnu.org/wiki/Visibility

Edit: An alternative would be to build a static library/archive (make .a archive with ar -cru mylib.a *.o) or combine the objects into a single object file according to this combine two GCC compiled .o object files into a third .o file

If you are asking "Why combine object files instead of just making a static library?" ... because the linker will treat .o files differently than .a files (I don't know why, just that it does), specifically it will allow you to link a .o file into a shared library or a binary even if all of the symbols are hidden (even the ones you are using) This has the added benefit of reducing startup times (one less DSO and a lot less symbols to look up) and binary size (the symbols typically make up ~20% of the size and stripping only takes care of about half of that - just the externally visible parts)

for binaries strip --strip-all -R .note -R .comment mybinary

for libraries strip --strip-unneeded -R .note -R .comment mylib.so

More on the benefits of static linking here: http://sta.li/faq but they don't discuss licensing issues which are the main reason not to use a static library and since you are wanting to hide your API, that may be an issue

Now that we know have an object that is "symbol clean", it is possible to use our combined object to build a libpublic.so by linking private.o and public.c (which aliases/exports only what you want public) into a shared library.

This method lends itself well to finding the "extra code" that is unneeded in your public API as well. If you add -fdata-sections -ffunction-sections to your object builds, when you link with -Wl,--gc-sections,--print-gc-sections , it will eliminate unused sections and print an output of what was removed.

Edit 2 - or you could hide the whole API and alias only the functions you want to export

alias ("target")

The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified. For instance,

void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias ("__f")));

defines f' to be a weak alias for __f'. In C++, the mangled name for the target must be used. It is an error if `__f' is not defined in the same translation unit.

Not all target machines support this attribute.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
technosaurus
  • 7,676
  • 1
  • 30
  • 52
  • Let me say again: I need export the API (so it could not be "hidden"). I need EXPORT an api WITHOUT name! Just like VC's "NONAME" directive in DEF file. Is there any "NONAME" equivalent for GCC? – ASBai Mar 10 '12 at 18:25
  • This doesn't answer the question (see updated information and clarifications). Also, the link does not provide an example that exports a function "by ordinal" or by any other mechanism than by its name. – André Caron Mar 10 '12 at 19:25
  • did you want to set up an alias symbol then? that way you can export it and hide the real one(s)? – technosaurus Mar 10 '12 at 20:16
  • @technosaurus: Yes, set an alias name is also acceptable for me. :-) Could I use the version script to setting up aliases? And whether the linker (ld) could auto mapping the real name to alias one? – ASBai Mar 11 '12 at 05:13
  • I edited my post with how to alias, I always found the version script method to be cumbersome and difficult to keep track of ... but then again I use geany as my "IDE"... It occurred to me though, that I have never added multiple attributes, so I'm not sure if a function can be "alias" && "default" visibility. – technosaurus Mar 11 '12 at 06:08
  • I'm currently using static library. But static lib has some problem too, e.g: my app support plugin mechanism, plugin is implement by shared-library. If I use static lib to provide underlayer services, then the app and all plugins must be linked with this static lib. – ASBai Mar 11 '12 at 06:26
  • More worse: the app will create and destroy threads dynamically, and the underlayer static lib need to use some TLS slots. Because the Plugin is static linked with underlayer lib, it has to use same TLS slot too. TLS resource in a plugin should be released if: 1. a thread will be finished; or 2. the plugin will be uninstalled. It is hard to do because all thread need to be informed and interrupted (to run the TLS release code) when a plugin being uninstall. – ASBai Mar 11 '12 at 06:31
  • @technosaurus: thanks, and I will give it a try :-) But how could I assign alias to a class and its methods? Did the linker will take care of the original name -> alias mapping automatically? – ASBai Mar 11 '12 at 06:36
  • @technosaurus: "In C++, the mangled name for the target must be used. " ok, I know how to define a alias for c++ methods then. And the original name -> alias mapping must done manually by myself, right? i.e: I must use alias name to call a method in the caller app? :-( – ASBai Mar 11 '12 at 06:49
10

You could consider using GCC function attribute for visibility and make it hidden, i.e. adding __attribute__((visibility ("hidden"))) at many appropriate places in your header file.

You'll then hide thus your useless symbols, and keep the good ones.

This is a GCC extension (perhaps supported by other compilers like Clang or Icc).

addenda

In the Linux world, a shared library should export functions (or perhaps global data) by their names, as published in header files. Otherwise, don't call these functions "exported" -they are not!

If you absolutely want to have a function in a shared library which is reachable but not exported, you could register it in some way (for instance, putting the function pointer in some slot of a global data, e.g. an array), this means that you have (or provide) some function registration machinery. But this is not an exported function anymore.

To be more concrete, you could have in your main program a global array of function pointers

 // in a global header.h
  // signature of some functions
 typedef void signature_t(int, char*);
 #define MAX_NBFUN 100
 // global array of function pointers
 extern signature_t *funtab[MAX_NBFUN];

then in your main.c file of your program

 signature_t *funtab[MAX_NBFUN];

Then in your shared object (.e.g. in myshared.c file compiled into libmyshared.so) a constructor function:

 static my_constructor(void) __attribute__((constructor));

 static myfun(int, char*); // defined elsewhere is the same file
 static void 
 my_constructor(void) { // called at shared object initialization
    funtab[3] = myfun;
 }

Later on your main program (or some other shared object) might call

 funtab[3](124, "foo");

but I would never call such things "exported" functions, only reachable functions.

See also C++ software like Qt, FLTK, RefPerSys, GCC, GTKmm, FOX-Toolkit, Clang, etc.... They all are extendable thru plugins or callbacks or closures (and internally a good C++ compiler would emit and optimize calls to closures for C++ lambda expressions). Look also inside interpreters like Python, fish, Lua, or GNU guile, you can extend them with C++ code.

Consider also generating machine code on the fly and using it in your program. Libraries like asmjit or libgccjit or LLVM or GNU lightning could be helpful.

On Linux, you might generate at runtime some C++ code into /tmp/generated.cc, compile that code into a /tmp/generated-plugin.so plugin by forking (perhaps with system(3) or popen(3)...) some command like g++ -Wall -O -fPIC -shared /tmp/generated.cc -o /tmp/generated-plugin.so then use dlopen(3) and dlsym(3). Use then extern "C" functions, and see the C++ dlopen minihowto. You might be interested in __attribute__((constructor)).

My personal experience (in past projects that I am not allowed to mention here, but are mentioned on my web page) is that you can on Linux generate many hundred thousands plugins. I would still dare mention my manydl.c program (whose GPLv3+ license allows you to adapt it to C++).

At the conceptual level, reading the GC handbook might be helpful. There is a delicate issue in garbage collecting code (or plugins).

Read also Drepper's paper How to write shared libraries, see elf(5), ld(1), nm(1), readelf(1), ldd(1), execve(2), mmap(2), syscalls(2), dlopen(3), dlsym(3), Advanced Linux Programming, the Program Library HOWTO, the C++ dlopen mini-howto, and Ian Taylor's libbacktrace.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Say, I have a API which was named as 'my_func', I MUST call it from another application. So, I MUST export it to the dll's export table (means it could not be hidden). I just Do not want to exposing API's name. in VC and PE DLL, I could achieve it by only exporting the ordinal, but how could I do the same thing with gcc and elf .so? – ASBai Mar 10 '12 at 17:54
  • 1
    So, you "have an API" (I am not sure to understand that phrase as you do). Why can't you add appropriate GCC `__attribute__((visibility ("hidden")))` appropriately in the header files of your API (you could use a macro to help you)? Or "is having an API" means something else to you? – Basile Starynkevitch Mar 10 '12 at 17:56
  • I need export the API (so I could not "hidden" it), but only with an ordinal number or something equivalent, not the api name. i.e: exporting an API without name. – ASBai Mar 10 '12 at 18:15
  • You'll just hide all the "useless" symbols, and keep the important ones visible... – Basile Starynkevitch Mar 10 '12 at 18:22
  • I'm already using -fvisibilty=hidden to hide all symbol and only expose useful APIs by __attribute__ ((visibility ("default"))). And my question is: How to export them WITHOUT the function name? – ASBai Mar 10 '12 at 18:32
  • In VC, I can use the "NONAME" directive to export an function only by an integer number (the "ordinal") without the function's name. How could I do it with gcc/so? – ASBai Mar 10 '12 at 18:32
  • @BasileStarynkevitch: the DLL exports table can be accessed by name and by ordinal. You can hide the function's name and only export the symbol by ordinal (this is usually done for embedded resources such as icons to hide the original file name). I think ASBai is doing this for his entire public API. – André Caron Mar 10 '12 at 18:37
  • I believe you cannot do that (publishing a function by some number only inside a shared object). The closest you could do is to declare an array of function pointers in your main program, and fill some slots inside in your library initialization functions (e.g. the "constructor" ones). – Basile Starynkevitch Mar 10 '12 at 18:38
  • @André Caron: Yeah, that's exactly what I want to do :-) – ASBai Mar 10 '12 at 18:58
  • So, sounds like I must implement my own Import Address Table (or some mechanism like it)? It's really a big project for me, because I have a few thousands APIs to export. :-( – ASBai Mar 10 '12 at 19:09
  • 2
    No, I believe you should ask what is your real issue and solve it in the ordinary Linux way. You are thinking it a too Windows centric manner, and that won't work well on Linux (and probably, vice versa). The standard Linux way is to have, inside your shared objects, thousands of exported functions (with their name visible to applications linking or dynamically loading with `dlopen` your shared library). – Basile Starynkevitch Mar 10 '12 at 19:12
  • My concern is: expose the API name will make the hacker more easy to crack my license protection. So I should expose the information as little as possible. The name of a function usually expose too more clues for antagonist. – ASBai Mar 10 '12 at 19:20
  • @André Caron: I think at least it could raise the hacker's crack cost :-) – ASBai Mar 10 '12 at 19:26
  • The goal of my anti-crack protection is not absolutely safe. My goal is combine multiple skills to raise the crack cost as high as possible. The ultimate effect is make cracking cost higher than reimplementing one. – ASBai Mar 10 '12 at 19:34
  • 1
    Did you consider the opposite solution: make your library a free software (e.g. under GPLv3 license)? – Basile Starynkevitch Mar 10 '12 at 19:43
  • 1
    But your trick, if implemented in a library, makes debugging programs to the legitimate users of your library more difficult... – Basile Starynkevitch Mar 10 '12 at 19:49
  • @Basile Starynkevitch: The user doesn't need to use this library directly, they could use the product by B/S UI or by a set of RESTful WebAPI. :-) – ASBai Mar 11 '12 at 05:04
  • @Basile Starynkevitch: Make or not make the library open source this not a big problem. However, the problem is: I need to protect my Application which is depending on this library. And the App could not be opensourced. – ASBai Mar 11 '12 at 05:07
9

To hide the meaning of the exported functions on UNIX, you can just obfuscate their names with simple renaming, by using #defines. Like this:

#define YourGoodFunction_CreateSomething              MeaninglessFunction1
#define YourGoodFunction_AddSomethingElseToSomething  lxstat__
#define YourGoodFunction_SaveSomething                GoAway_Cracker
#define YourGoodFunction_ReleaseSomething             Abracadabra

and so on.

In a case of a few functions it can be done by hands. If you need thousands, you should use code generation.

  1. get the list of your real function names, use grep, awk, cut, etc.
  2. prepare a dictionary of the meaningless names
  3. write a script (or binary) generator which will output a C header file with #defines as shown above.

The only question is how you can get the dictionary. Well, I see a few options here:

  • you could ask your co-workers to randomly type on their keyboards ;-)
  • generate a random strings like: read(/dev/urandom, 10-20 bytes) | base64
  • use some real dictionary (general English, specific domain)
  • collect real system API names and change them a bit: __lxstat -> lxstat__

this is limited only by your imagination.

Alexander
  • 91
  • 1
  • 1
1

You can write a version-script and pass it to the linker to do this.

A simple script looks like this:

testfile.exp:

{
global:
  myExportedFunction1;
  myExportedFunction2;

local: *;
}

Then link your executable with the following options:

  -Wl,--version-script=testfile.exp

When applied to a shared library this will still list the symbols in the .so file for debugging purposes, but it is not possible to access them from the outside of the library.

Nils Pipenbrinck
  • 83,631
  • 31
  • 151
  • 221
  • so, the myExportedFunction1 and myExportedFunction2 are still appeared as the shared-library's dynamic symbol? What should I do if I want to exporting these two APIs without symbol name? In Windows we could export an API only by its ordinal number, is there an equivalent for ELF .so file? – ASBai Mar 10 '12 at 18:09
  • there are no ordinals in ELF .so files, only the symbol names. – Nils Pipenbrinck Mar 10 '12 at 21:41
0

I was looking for a solution for the same problem. So, far I couldn't find a robust solution. However, as a prove of concept I used objcopy to achieve desired results. Basically, after compiling an object file I redefine some of its symbols. Then the translated object file is used to build the final shared object or executable. As a result the class/method names that could be used as a hint to reverse engineer my algorithm are completely renamed by some meaningless names m1,m2,m3.

Here is the test I used to ensure that the idea works:

Makefile:

all: libshared_object.so executable.exe

clean:
    rm *.o *.so *.exe

libshared_object.so : shared_object.o
    g++ -fPIC --shared -O2 $< -o $@
    strip $@

shared_object.o : shared_object.cpp interface.h
    g++ -fPIC -O2 $< -c -o $@
    objcopy --redefine-sym _ZN17MyVerySecretClass14secret_method1Ev=m1 \
            --redefine-sym _ZN17MyVerySecretClass14secret_method2Ev=m2 \
            --redefine-sym _ZN17MyVerySecretClass14secret_method3Ev=m3 $@


executable.exe : executable.o libshared_object.so
    g++ -O2 -lshared_object -L. $< -o $@
    strip $@

executable.o : executable.cpp interface.h
    g++ -O2 -lshared_object -L. $< -c -o $@
    objcopy --redefine-sym _ZN17MyVerySecretClass14secret_method1Ev=m1 \
            --redefine-sym _ZN17MyVerySecretClass14secret_method2Ev=m2 \
            --redefine-sym _ZN17MyVerySecretClass14secret_method3Ev=m3 $@

run: all
    LD_LIBRARY_PATH=. ./executable.exe

interface.h

class MyVerySecretClass
{
private:
    int secret_var;
public:
    MyVerySecretClass();
    ~MyVerySecretClass();
    void secret_method1();
    void secret_method2();
    void secret_method3();
};

shared_object.cpp

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include "interface.h"

MyVerySecretClass::MyVerySecretClass()
    : secret_var(0)
{}

MyVerySecretClass::~MyVerySecretClass()
{
    secret_var = -1;
}

void MyVerySecretClass::secret_method1()
{
    ++secret_var;
}

void MyVerySecretClass::secret_method2()
{
    printf("The value of secret variable is %d\n", secret_var);
}

void MyVerySecretClass::secret_method3()
{
    char cmdln[128];
    sprintf( cmdln, "pstack %d", getpid() );
    system( cmdln );
}

executable.cpp

#include "interface.h"

int main ( void )
{
    MyVerySecretClass o;
    o.secret_method1();
    o.secret_method2();
    o.secret_method1();
    o.secret_method2();
    o.secret_method1();
    o.secret_method2();
    o.secret_method3();
    return 0;
}
Vahagn
  • 1
  • 2
  • Here is a simpler way to hide a interface: 1. define a interface class; 2. implement (derived from) the interface on a dll/so module, but not export it; 3.only export one api within the dll/so, like: "void* CreateInstance()", it return a pointer to you interface class; 4.call this api from your main excutable image. – ASBai Mar 05 '15 at 15:59
  • How ever, I've tired a more complicate but "elegant" way: launch the code using MapViewOfFileEx / mmap with the execute permission and run it by myself. In this way, you need init everything by yourself, and solve the pending IAT entry, etc. I finally found it's too complicated for a portable multi-platform app, and lack the portability for some platform (e.g.: chrome NaCL) :-( – ASBai Mar 05 '15 at 16:09
  • Hiding function using virtual tables is ok.. However, the point is what to do if the product is already implemented and you cannot modify it. Simply because its too big. The obfuscation looks the only alternative to linking everything statically. I was looking for a tool that will allow to obfuscate C++ names automatically, without extra effort. Yet, I couldn't find one. So, I came up with an approach that would allow to do it. – Vahagn Mar 06 '15 at 18:15
  • The beauty of this method is that you could encrypt method names and use the encrypted name as a symbol. Which would allow you for example to decrypt a stack trace and debug application, while you keep your stack trace completely unreadable for others. – Vahagn Mar 06 '15 at 18:20
  • I'm expecting a tool which could change a '.so' module's export symbols table, rename them to some meaning less thing, and adjust import table of the "consumer application" (who are using that module) automatically. We only need this tool could deal with the ELF format, because on windows we can use the NONAME directive in a .DEF file. – ASBai Mar 09 '15 at 12:21