2010-05-20 25 views
14

¿Cómo se quita de cuerdas/ofuscar un binario compilado compilado? El objetivo es evitar que las personas lean los nombres de las funciones/métodos en el interior.¿Cómo eliminar las cadenas de un binario (.so)

Es una biblioteca dinámica (.so) compilado a partir de código C++ para Android con las herramientas NDK (incluye CCG)

compilo con -O3 y ya utilizar arm-eabi-strip -g mylib.so para eliminar símbolos de depuración, pero cuando lo haga strings mylib.so todo los nombres de las funciones/métodos todavía son legibles.

Respuesta

22

Estas cadenas están en la tabla de símbolos dinámicos , que se utiliza cuando la biblioteca se carga en tiempo de ejecución. readelf -p .dynstr mylib.so mostrará estas entradas.

strip -g eliminará los símbolos de depuración, pero no puede eliminar las entradas de la tabla de símbolos dinámicos, ya que pueden ser necesarios en el tiempo de ejecución. Su problema es que tiene entradas en la tabla de símbolos dinámicos para funciones que nunca serán llamadas desde fuera de su biblioteca. A menos que usted lo diga, el compilador/enlazador no tiene manera de saber qué funciones forman parte de la API externa (y por lo tanto necesitan entradas en la tabla de símbolos dinámicos) y qué funciones son privadas para su biblioteca (y por lo tanto no necesitan entradas en la tabla de símbolos dinámicos), por lo que solo crea entradas de tabla de símbolos dinámicos para todas las funciones no estáticas.

Hay dos formas principales que puede informar al compilador que funciona son privadas.

  1. Marque las funciones privadas static. Obviamente, esto solo funciona para funciones que solo se necesitan en una sola unidad de compilación, aunque para algunas bibliotecas esta técnica podría ser suficiente.

  2. Utilice el atributo gcc "visibility" para marcar las funciones como visibles u ocultas. Tiene dos opciones: marcar todas las funciones privadas como ocultas o cambiar la visibilidad predeterminada a oculta utilizando la opción del compilador -fvisibility=hidden y marcar todas las funciones públicas como visibles. Esta última es probablemente la mejor opción para usted, ya que significa que no tiene que preocuparse por agregar accidentalmente una función y olvidarse de marcarla como oculta.

Si usted tiene una función:

int foo(int a, int b); 

continuación, la sintaxis para el marcado oculto es:

int foo(int a, int b) __attribute__((visibility("hidden"))); 

y la sintaxis para el marcado visible es:

int foo(int a, int b) __attribute__((visibility("default"))); 

Para más detalles, vea this document, que es una excelente fuente de información sobre este tema.

+0

¡Gran respuesta! Necesito probar eso ... El how-to también es genial, pero es bastante largo. ¡Muchas gracias! –

-2

Son inevitables. Esas cadenas son el medio por el cual el cargador vincula bibliotecas compartidas en tiempo de ejecución.

+0

No estoy hablando de las funciones exportadas para acceder a la biblioteca, sino a las funciones internas. ¿Es inevitable mostrarlos? –

+1

Ah, entonces su línea de comando 'arm-eabi-gcc' me está confundiendo. La opción '-g' usualmente _adds_ depura símbolos. –

+0

disculpa el error tipográfico, no es 'gcc' sino' strip' ... déjame corregir esto. –

5

hay algunas commercial obfuscators la que lograr esto. Básicamente, vuelven a escribir todos los símbolos sobre la marcha. Algo como esto:

void foo() 

convierte

void EEhj_y33() // usually much, much longer and clobbered 

Los nombres de variables también se les da el mismo tratamiento, al igual que los miembros de las estructuras/sindicatos (dependiendo de qué nivel de ofuscación se establece).

mayoría de ellos trabajan mediante el escaneo de su base de código, el establecimiento de un diccionario a continuación, sustituyendo líos confusos para los nombres de símbolos en la salida, que luego pueden ser compilados como de costumbre.

No recomiendo el uso de ellos, pero están disponibles. Simplemente ofuscar nombres de símbolos significativos es no que va a detener a alguien que está decidido a descubrir cómo funciona su biblioteca/programa. Además, no podrá hacer nada con alguien que rastree las llamadas al sistema. En serio, ¿cuál es el punto? Algunos argumentan que ayuda a mantener el 'observador casual' en la bahía, se argumenta que alguien corriendo ltracestrace y strings es típicamente cualquier cosa menos casual.

A menos que decir literales de cadena, no símbolos? No hay nada que pueda hacer al respecto, a menos que almacene los literales en un formato cifrado que el código debe descifrar antes de usar. Eso no es solo un desperdicio, sino un desperdicio atroz que no proporciona ningún beneficio en absoluto.

+0

Gracias! La ofuscación es mejor que nada; mi código consiste principalmente en algoritmos complejos, y su implementación y ajuste, que de alguna manera son otorgados por los nombres de las funciones, hace una gran parte del valor del software. Por otro lado, dejar las llamadas del sistema identificables no es un problema. –

2

Suponiendo que está especificando correctamente una visibilidad oculto a g ++ para todos los archivos de origen (como otros críticos han recomendado), hay una posibilidad de que pudiera estar ejecutando en este GCC error: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38643

Trate volcar el símbolos en su binario que se muestran (readelf -Wa mylib.so | c++filt | less); si solo ves símbolos vtable y VTT después de demandar, entonces el error gcc podría ser tu problema.

Editar: si puede, intente con GCC 4.4.0 o posterior, ya que parece estar arreglado allí.

+0

-fvisibility = oculto en GCC (V4.4.0) + trabajo de brazo-eabi-strip -s. gracias –

Cuestiones relacionadas