2

I'm going to ship a to static library to a customer. To maximize the privacy of the library I have restricted symbols for the static library using the technique provided by @ypsu Symbol hiding in static libraries built with Xcode

However, the above mentioned method only restrict the user from calling the hidden functions, the name of the hidden function names are still visible to "nm" or "strings".

The names for hidden function are very sensitive. How do I hide or remove this information from the static library ?

prgbenz
  • 1,129
  • 4
  • 13
  • 27

1 Answers1

3

I have lately approached the same problem. I decided to rename all public symbols to it's md5sum so that the names are not visible to the user, including the filenames. A following example tries to demonstrate it:

cat >priv.c <<EOF
#include <stdio.h>
void priv() { printf("Hello, private function\n"); }
EOF

cat >interface.c <<EOF
void priv();
void interface() { priv(); }
EOF

cat >main.c <<EOF
void interface();
int main() {
    interface();
}
EOF

cat >compile.sh <<EOF3
#!/bin/bash   

namespace="namespace_"

# compile to object files
gcc -c -o priv.o priv.c
gcc -c -o interface.o interface.c

# rename the object file so the names of files are not visible
nofilename="$(echo "nofilenames" | md5sum | cut -d' ' -f1).o"
ld -relocatable priv.o interface.o -o "$nofilename"

# create the static library
ar rcs static.a "$nofilename"

# list of interface symbols    
public_symbols=( interface )

# list of private symbols - all symbols except interface symbols
private_symbols=($(
    nm static.a | sed '/^[0-9]\+ T /!d; s///' |
    sort | comm -13 <(printf "%s\n" "${public_symbols[@]}" | sort) -
))

# strip unused symbols, leave only interface symbols
strip_args=($(printf " -K %s " "${public_symbols[@]}"))
strip --strip-unneeded --strip-debug "${strip_args[@]}" static.a

# rename all private symbols with it's md5sum
objcopy_args=($(
    printf "%s\n" "${private_symbols[@]}" |
    while IFS= read -r sym; do
        new="${namespace}$(echo "$sym" | md5sum | cut -d' ' -f1)"
        # replace the symbol with it's md5sum
        echo --redefine-sym "$sym=$new"
        # make the symbol local
        echo -L "$new"
    done
))
objcopy "${objcopy_args[@]}" static.a

gcc main.c static.a 

# testing    
set -x
nm static.a
strings static.a
./a.out
EOF3

The ./compile.sh script would output:

+ nm static.a

b8c84a861a264dfcb24ebf32892484dd.o:
                 U _GLOBAL_OFFSET_TABLE_
0000000000000013 T interface
0000000000000000 t namespace_6b2f60f631c17ca910498adb47387adf
                 U puts
+ strings static.a
!<arch>
/               0           0     0     0       18        `
interface
//                                              36        `
b8c84a861a264dfcb24ebf32892484dd.o/
/0              0           0     0     644     1744      `
Hello, private function
GCC: (Arch Linux 9.3.0-1) 9.3.0
GCC: (Arch Linux 9.3.0-1) 9.3.0
namespace_6b2f60f631c17ca910498adb47387adf
puts
interface
_GLOBAL_OFFSET_TABLE_
.symtab
.strtab
.shstrtab
.rela.text
.rodata
.rela.eh_frame
.data
.bss
.comment
.note.GNU-stack
+ ./a.out
Hello, private function

The priv symbol was renamed to namespace_6b2f60f631c17ca910498adb47387adf and source files were combined into one b8c84a861a264dfcb24ebf32892484dd.o object file with ld -relocatable. I am open to more suggestions on how to improve such script.

The template shown emerged into a bigger script ,ar_hide_symbols.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111