2010-08-14 19 views
5

Mi cliente me pidió que escribiera un archivo ejecutable encriptado personalizado para evitar el agrietamiento fácil del sistema de licencias. Ahora, entiendo que esto es una falsa sensación de seguridad, pero a pesar de esto él insistió en ello.¿Ejecutar datos como código?

Así, Desenterré mis conocimientos de ejecutables portátiles y se acercó con esta idea:

  • Cifrar el ejecutable
  • palillo de esto al final de un ejecutable cargador junto con su tamaño
  • El el cargador descifra los datos
  • Copia el código en una página asignada con VirtualAlloc que tiene permisos ejecutables
  • Encuentra el punto de entrada de la aplicación
  • Salta allí y estamos listos.

Tengo un problema con la parte de saltar allí. ¿Cómo puedo hacer eso? Si tuviera que establecer un puntero a la función, ¿cuál sería la firma? ¿La firma de la función main() del ejecutable cargado? ¿O necesito recurrir al montaje?

Entiendo que podría ser necesario corregir las direcciones absolutas después de cargar el código. ¿Cómo compruebo si es necesario y cómo realizo esto?

Editar: Trabajando en Windows y compilando con GCC. Puedo cambiar el compilador de Microsoft si es necesario.

Edit2: Para aclarar: SÉ que en su mayor parte no tiene sentido. Creo que representa cualquier tipo de DRM. Depende de mi cliente decidir, y todavía lo quiere a pesar de que yo le advierto sobre esto.

Gracias de antemano.

+0

Su solución tipada en mi punto de vista es un poco problemático, ¿qué pasa con sus funciones salta a otras funciones? Se han corregido otras direcciones y veo muchos problemas con esta solución, como ¿dónde están las bibliotecas vinculadas estáticas? ¿Quién usa el código encypted? – Svisstack

+0

Yo diría, si realmente quieres DRM. Cómpralo. ¿Por qué? Incluso si tienes 'algo' funcionando. ¿Qué haces en seis meses cuando está roto? Mantenerse al día con las galletas es un trabajo de tiempo completo. –

+0

Eso depende de mi cliente para decidir. Realmente no me importa si toma malas decisiones. Honestamente lo advertí y todavía lo quiere. –

Respuesta

4

Como han mencionado otros, simplemente cargar todo el archivo EXE en una sección de datos y vincularlo en el tiempo de ejecución es una tarea difícil; Sin embargo, aquí hay otra opción.

Tome su entrada EXE; encuentre su código y secciones de datos inicializados (incluyendo constante). Cambie el nombre de estas secciones y conviértelos a secciones de datos inicializados de lectura-escritura; Encriptar los contenidos. Ahora agregue un nuevo segmento de código que contenga su talón de descifrado y cambie el punto de entrada allí. Este apéndice debe desencriptar los segmentos en el lugar, luego cambiar su protección a lo que sea apropiado para su tipo, y saltar al punto de entrada original.

Esto evita tener que implementar todas las funciones de un cargador de PE completo, ya que las tablas de importación no están cifradas, y por lo tanto el cargador de Windows normal se encargará de usted.

Cabe señalar, por supuesto, que este tipo de enfoque ingenuo no sobrevivirá a un ataque concertado en ningún momento: un atacante puede simplemente volcar la memoria del proceso para obtener el código descifrado original. Para evitar esto, es probable que necesite encriptar y descifrar el código de manera continua, momento en el que el manejo de PE es lo que menos le preocupa.

+0

Eso tiene sentido. Entonces, si incluyo una nueva sección en el archivo ejecutable y actualizo las tablas de sección y el punto de entrada, simplemente puedo saltar al código descifrado porque el cargador del sistema operativo se encargó de las importaciones y reubicaciones (si es necesario). –

+1

Básicamente, sí, excepto las reubicaciones que no se manejarán si están en la sección en cuestión. Así que asegúrese de que sea un EXE no reubicable. Imports tiene una sección separada de stubs en archivos PE, creo ... (no estoy seguro, probablemente deberías comprobar esto :) – bdonlan

+0

+1 ataque de volcado de memoria;) –

0

usted debería ser capaz de c-estilo de emitir su dirección a un puntero de función, y lo llaman:

typedef void (*MyPtr)(); 

MyPtr p = (MyPtr)1234; 
p(); 
11

Desafortunadamente, saltando al punto de entrada de su código es el menor de sus preocupaciones. Un archivo Portable Executable (PE) (que es el formato de archivo utilizado para los archivos EXE y DLL en Windows) no es algo que simplemente pueda cargar en un solo bloque de memoria y luego ejecutar. Su cargador PE personalizada tendría que hacerse cargo de los siguientes puestos de trabajo:

  • Cargar las distintas secciones de código y datos en el archivo PE en bloques de memoria separados.

  • Resuelva las dependencias de la tabla de importación para cargar las DLL de las que depende su EXE.

  • Realizar reubicaciones.

Obtener todos los detalles correctos probablemente sea un trabajo bastante complicado. Sugeriría que busque una herramienta que pueda comprar que tenga este tipo de cifrado EXE.

Editar: Una búsqueda rápida en Google sugiere es posible que desee echar un vistazo a la siguiente:

  • EXECryptor (patentada)

  • RLPack (patentada)

  • UPX (GPL) Este solo comprime, por lo que yo entiendo, pero puede usar The Source para agregar encriptación (si la GPL es compatible con sus necesidades).

Seguramente haya más herramientas como estas, esto es solo el resultado de una búsqueda rápida.

Otra edición:

revista de MSDN un artículo de Matt Pietrek llama "Una mirada en profundidad en el formato portable ejecutable Win32 Archivo" (Part 1, Part 2). Contiene mucha información sobre el formato de archivo PE que debería ser útil para usted. Un dato interesante: las versiones recientes del enlazador de Microsoft parecen omitir las reubicaciones de bases para EXEs de forma predeterminada. Es probable que desee indicar al vinculador que vuelva a colocarlos porque es probable que su contenedor EXE ya esté cargado en la dirección de carga preferida de su carga útil. Alternativamente, podría tratar de darle a su contenedor EXE una dirección de carga preferida exótica donde, con suerte, no interfiera con el EXE de carga útil.

También encontré un page that discusses a rudimentary PE file compressor. Sin embargo, no parece ser completamente general y probablemente requiera un trabajo adicional antes de poder usarlo.

+0

Conozco algunas de estas herramientas, y las sugerí para el cliente, pero buscó desempaquetadores en Google para cada uno de ellos y siente que necesita uno personalizado. Incluso si no puedo emprender la tarea, me gustaría aprender sobre ella, ya que me parece un tema muy interesante. ¿Podría sugerirme algún material sobre esos puntos que mencionó? Especialmente reubicaciones. –

+0

@sztomi: He agregado algunos enlaces para obtener más información. Para más información sobre reubicaciones, eche un vistazo a la Parte 2 del artículo de Matt Pietrek. –

+0

@sztime: el proyecto "WINE" (http://www.winehq.org/) ha implementado el cargador de PE para Linux, por lo que probablemente pueda estudiar la fuente al menos. MPlayer (http://www.mplayerhq.hu/design7/news.html) ha utilizado algún tipo de código (probablemente de wine) para cargar windows dll en la plataforma de Linux.De todos modos, esto se puede hacer, pero si se trata de una "defensa de protección contra copia", se puede descifrar y se RASGUIRÁ si el producto es lo suficientemente bueno. Cualquiera que tenga acceso a su exe puede (intentar) descifrarlo evitando la protección o desempaquetándolo. – SigTerm

4

Además de todo el alboroto y la molestia de cargar correctamente una imagen PE, también tendrá que preocuparse por Data Execution Protection que está destinado a evitar hacer esto mismo.

No olvide que esto también puede parecer un comportamiento de malware para algunas herramientas antivirus y antimalware.

+6

La protección de ejecución de datos solo se aplica a las páginas de datos; si asigna una página usando VirtualAllocEx() con uno de los indicadores PAGE_EXECUTE_ *, podrá ejecutar código desde allí. –

+2

Para ampliar esto: DEP no está destinado a prevenir la carga y ejecución intencionadas de código; está destinado a evitar la ejecución accidental (o más probable) maliciosa del código de las páginas de datos, p. un ataque de desbordamiento de búfer que ejecuta código de la pila. Crear y ejecutar su propio código sobre la marcha es un comportamiento legítimo: los compiladores JIT son un ejemplo destacado. –

+0

Tiene usted razón, Martin, miré la documentación del DEP antes de la pregunta. –

1

Su solución mecanografiada en mi punto de vista es poco problemática, ¿qué pasa con sus funciones salta a otras funciones? Se han corregido otras direcciones y veo muchos problemas con esta solución, como dónde están las bibliotecas vinculadas estáticas del código cifrado.

Creo que se puede hacer algo como:

  1. Transporte un archivo DLL encriptados, con su montaje secreto
  2. Cifrar ella en un directorio tmp
  3. hacer LoadLibrary en esta DLL
  4. desbloqueo archivo y eliminar del sistema?
+1

Sí, así es como lo he visto hecho. La DLL encriptada se puede almacenar incluso en los recursos de .exe. También es posible que desee evitar que la DLL extraída funcione de forma independiente haciendo que pase por las funciones en su .exe principal a través de una tabla de salto que se transfiere para realizar la mayoría de las operaciones. Pero probablemente sea mejor que compre este tipo de cosas de todos modos. – Rup

-3

No se pueden ejecutar datos como el código en la mayoría del sistema operativo, gracias a gdt, la tabla de descriptores globales que divide los datos del código. Si intenta ejecutar datos, el procesador emite una excepción.

+0

Hasta hace muy poco, el permiso de lectura y el permiso de ejecución eran lo mismo en x86. –

+0

Solo porque el sistema operativo no usó GDT como deberían, no significa que sean lo mismo. Verifique en wikipedia o en las hojas de datos de Intel – Charlie

+0

El GDT no se puede utilizar para este propósito en el modelo de memoria plana (utilizado por todos los sistemas operativos x86 comunes) porque solo hay un segmento que contiene todo el espacio de direcciones planas. El bit NX (http://en.wikipedia.org/wiki/NX_bit) cumple el mismo objetivo en el nivel de la tabla de páginas, pero solo se introdujo con la serie 5x0J de Prescott (http://en.wikipedia.org/wiki/ Pentium_4) en 2004. –

1

El cargador descifra los datos

Esto lo dice todo.

Para que el cargador pueda descifrar los datos, también debe contener (o al menos conocer) la clave de descifrado.

Por lo tanto, si distribuye físicamente este cargador a sus usuarios, tendrán pleno acceso tanto al código del cargador como a la clave utilizada.

Quizás esto es lo que quiere decir "falso sentido de seguridad"?

Como su cliente parece ser obstinado o simplemente ignorante, ¿por qué no crear una pequeña demostración de descifrado que muestra claramente los defectos en su forma de pensar?

+0

La ofuscación de código * does * "work", suponiendo que prevenir * algún * cracking hace que algunas personas compren la aplicación completa, es cuestión de adivinar cómo se ve la curva y poner la cantidad de esfuerzo adecuada. –

Cuestiones relacionadas