Como proteger tu programa [By karmany]

Iniciado por ANTRAX, Febrero 20, 2010, 02:47:41 AM

Tema anterior - Siguiente tema

0 Miembros y 3 Visitantes están viendo este tema.

PRÓLOGO

Después de recibir varias consultas sobre este tema, hemos decicido abrir este nuevo post, dando a conocer principalmente a los programadores los distintos sistemas para proteger sus aplicaciones:

-Protecciones que pueden implementar ellos mismos en sus programas...
-Programas gratuitos que pueden utilizar para empaquetar sus aplicaciones
-Programas de pago..
-Consejos...

Nosotros sabemos que a una persona con buenos conocimientos, cualquier protección le es indiferente, porque no hay nada infalible, pero vamos a mostrar las distintas formas que conocemos.

¿Por qué abrimos este post? Pues porque la gente que diariamente trabaja con Ingeniería Inversa es la gente que se enfrenta con las protecciones actuales y sabe cuáles son las más difíciles (que no imposibles) y cuáles puede aconsejar...

Un saludo y esperamos que os pueda servir de guía antes de decidiros por una u otra opción...

INTRODUCCIÓN

Varias de las preocupaciones de un programador a la hora de distribuir su aplicación pueden ser:

-Disminuir el tamaño de la misma todo lo posible
-Crear licencias para usuarios registrados
-Crear versión DEMO
-Proteger la aplicación para que no sean usadas licencias ilícitas

 

Primeramente, y antes de todo, hay que comentar unos detalles que todo programador debe saber:
-Ningún programa es incrackeable.
-Hay protecciones fáciles,...., difíciles, ...., muy difíciles y muy muy difíciles, pero no imposibles.
-Muchos programadores piensan que por no tener el código fuente, al cracker le va a resultar más complicado estudiar la aplicación. Ya les puedo asegurar a todos los que piensen así: que se equivocan al 100%. Si analizaramos cualquier programa compilado con cualquier lenguaje de programación, llegaríamos a ver secuencias de 0 y 1 que el procesador entiende directamente. Pero existen muchos programas denominados desensambladores que lo que hacen es convertir esa secuencia de 0 y 1 en código ensamblador. El cracker domina este lenguaje.
-A parte de la ayuda que es un desensamblador, se unen los debugger que son herramientas para la depuración del código. Estos debuggers a día de hoy, están muy desarrollados y les puedo asegurar que su aplicación será incapaz de detectarlos.
-Las personas que comienzan su andadura por el mundo de la Ingeniería Inversa son denominadas Newbies. Y no hay que subestimar a nadie.
-Existen en la actualidad muchísimos programas para proteger y/o reducir tu aplicacion, estos programas se denominan empacadores, empaquetadores o en inglés packers.
-En este tutorial vamos a hablar principalmente de aplicaciones a 32 bits en ejecutadas en Microsoft Windows.

Después de todo esto seguro que ya sabrás que tienes dos opciones:
-Implementar tú mismo la protección en tu aplicación
-Utilizar uno de los muchos empacadores que existen

Implementar uno mismo la protección:
Como ya se puede uno imaginar, hay que crear licencias y una versión demo. Es realmente una labor un tanto costosa, pero con toda la información que hay en Internet seguro que puedes conseguir una base para comenzar. Hay muchas personas que ya tienen el código fuente preparado para distintos software y lo que hacen es modificar ciertos parámetros y así los nombre-contraseña también son diferentes.

Utilizar un packer:
La utilización de estos programas tiene una gran ventaja: que en la mayoría de ellos se pueden ya crear licencias, versiones demo, protecciones contra desensamblados/debuggers, e incluso la disminución del tamaño de la aplicación consideramente.
Por contra, si quieres crear una aplicación comercial, en la mayoría de ellos deberás comprar el producto, lo que requiere que tu aplicación aumente también de precio.
También se debe tener en cuenta que los packers que hace unos años eran muy complicados, actualmente han sido analizados hasta su último bit y gente Newbie es capaz incluso de enfrentarse a este tipo de protecciones. Pero todo esto lo veremos con más detenimiento después.

Hablaremos un poco de los métodos anti debugger/desensambladores

Protecciones contra debuggers/desensambladores

Sea cual sea la opción elegida de las dos mostradas, se suelen implementar distintas medidas contra el desensamblado del código o contra debuggers.


Protección de packers:

A día de hoy, los softwares para empaquetar aplicaciones están muy avanzados y no hace falta decir que existen empresas que dedican su tiempo en seguir investigando estos métodos. De este modo, y cada vez más a menudo, los nuevos packers que aparecen son obras de arte muy difíciles de romper y seguramente toda protección que se te ocurra ya ha sido investigada hasta la saciedad.
Sin embargo, cada protección, sea hecha por el usuario o sea utilizando software especializado es un mundo diferente y cada una tiene su complejidad.

Por otro lado, como los software de protección han avanzado tanto, pues también los que depuran las aplicaciones han avanzado tanto o más camino; conocen la mayoría de protecciones utilizadas y cada vez aparecen más herramientas de ayuda que hacen la depuración de programas una tarea muy sencilla. No hace falta decir que hay personas con unos conocimientos muy elevados y no solamente en el ámbito donde se mueven generalmente los software (ring3) sino a niveles donde trabaja el Sistema Operativo o incluso ¡por debajo de él!.


Desde hace muchos años se vienen estudiando formas para que sea más complicado acceder al código y poder utilizar dicha información; sin ir más lejos recuerdo perfectamente juegos de aventuras conversacionales de mi antiguo ZX Spectrum a 128K donde se encriptaban las cadenas de texto para que con un debugger no fuera tan sencillo encontrar la "palabra clave".

Actualmente, según mi opinión y mi experiencia, los software para empaquetar aplicaciones no se preocupan tanto en evitar que se pueda desensamblar/debuggear el código, sino lo que hacen es:
-Uso de Máquinas Virtuales para la creación del código
-Creación de zonas dinámicas de memoria donde se ejecutará parte de código.
-Código ofuscado: con mucho código inútil de más para evitar que se entienda el desensamblado. Esto hará aumentar de tamaño tu aplicación.
-Emulan la funciones y por consiguiente las llamadas a las mismas, por ejemplo si en nuestro código hemos hecho una llamada a MessageBox, pues la API MessageBox será totalmente emulada y posiblemente ofuscada.
-El mismo packer ejecuta las primeras instrucciones de tu programa y devuelve el control al mismo después, por lo tanto, conocer todo ese código que ya se ha ejecutado es un problema grandísimo. Si son sólo unos bytes los que han desaparecido se denomina Stolen Bytes, si por el contrario es gran parte de código se denomina Stolen Code.
-Suele ser muy fácil llegar a la comprobación de Nombre-Serial, pero han creado tantísimo código y tal complejidad a la hora de analizar un nombre-serial válido que es dificilísimo encontrarlo y por tal motivo se prefiere reparar el programa.
-Y algunas cosas más que iré añadiendo...

El lector dirá, y ¿qué consiguen con todo eso? Pues está muy claro:
1º- Hacen tan difícil encontrar un nombre-serial que el cracker seguramente desestimará esta opción porque requiere muchas horas y días de análisis.
2º-Imaginemos que al cabo solamente de 2 minutos encontramos un salto (que en ensamblador puede ser "je") que salta cuando estamos registrados pero que no salta cuando no lo estamos. Bien, sabiendo esto podríamos modificar el salto y se puede pensar que el asunto está arreglado... Aquí está la dificultad, que como la aplicación está empacada tú no puedes modificar ese "je" por un "jne" porque ese "je" todavía no existe y probablemente sea ejecutado en una memoria dinámica (que con cada ejecución varía) que el packer crea a la hora de descomprimirse.
3º-Al emular la funciones (IAT - Tabla de Importaciones), es muy difícil saber cuáles son y por lo tanto al intentar reconstruirlo puede resultar extremadamente complicado.
4º-El uso de Máquinas Virtuales hace muy difícil saber el camino que el packer está tomando.
5º-Como cada packer es un mundo diferente pues también sus protecciones.

En resumen de todo esto:
Para descomprimir un programa empacado, es necesario llegar y pararse en el punto de entrada del programa original (OEP), arreglar la IAT, reparar los Stolen Code o Stolen Bytes, el código que se ejecuta fuera de la memoria de la aplicación introducirlo dentro etc... Se trata de quitar el packer de la aplicación y dejar solamente esta última.
Es decir, un trabajo muy laborioso pero que en determinados casos como es un trabajo repetitivo con la práctica lo puedes resolver en unas cuantas horas.

Seguro que después de haber metido toda esta parrafada algunos no saben ni de lo que he hablado, bueno solamente hay que quedarse con lo más importante y si de verdad quieres indagar en el tema releer todo lo que he escrito o preguntar en el foro. Todo lo comentado suelen ser las protecciones habituales de packers comerciales. Y... a nivel de implementar uno mismo su protección ¿cómo se puede evitar el desensamblado/debugger?

Proteger uno mismo su aplicación:

Después de lo que se ha comentado, alguno pensará... pero si está todo estudiado ¿qué protección puedo yo poner a mi aplicación?
Aquí viene la invención de cada persona. Hay gente que tiene muy buenas e innovadoras ideas.

Siempre se han utilizado técnicas muy conocidas por todo el mundo como pueden ser:
-Uso de la API IsDebuggerPresent que se encuentra en la librería kernell32.dll. Es la más conocida por todo el mundo, simplemente se llama a esta API y si el resultado de la misma es 1 hay debugger, si es 0 no hay debugger.
-Retardo en la ejecución de código: es decir, si por ej. en cargar tu aplicación tiene que pasar solamente 1 segundo y han pasado 45 segundos --> ¡hay debugger!. Esto se suele hacer de varias formas: usando la función GetTickCount o usando funciones que te devuelven la fecha actual, incluídos segundos: GetLocalTime, GetSystemTime. Seguro que tú conoces muchas más formas. Te puedo indicar una muy curiosa que yo he usado de prueba y funciona perfectamente y es en ensamblador con la instrucción RDTSC. Esta última instrucción es interesante ya que si se ejecuta dos veces una detrás de otra, verás que el resultado de ambas es prácticamente igual, sin embargo, si ha pasado determinado tiempo entre la ejecución de la primera RDTSC y la segunda los valores son totalmente diferentes.
-En Window, el registro FS apunta hacia una estructura llamada Thread Information Block (TIB). Esta compleja estructura tiene otras y más complejas estructuras y en ella podemos tener información de si un Debugger está depurando la aplicación o no.
Ejemplos: GlobalFlags sería en ensamblador implementado de la siguiente forma:

mov eax, dword ptr fs:[30h]
mov eax, dword ptr ds:[eax+68h]

Si el resultado es cero --> no hay debugger
Si el resultado es distinto de cero --> hay debugger
Del mismo modo hay otras formas similares: ProcessHeap Flag, PEB_LDR_DATA etc...

-Podemos hacer uso de distintas API: ZwQueryInformationProcess, ZwSetInformation Thread, ZwQuerySystemInformation... Hay cosas muy curiosas incluso utilizando la función CsrGetProcessId que se encuentra ni más ni menos que en ntdll.dll. De este último ejemplo tengo uno hecho en ASM por si alguien quiere analizarlo.

-Podemos también investigar si se está usando algún debugger examinando los procesos que se están ejecutando. Esto se suele hacer de dos formas:
*Utilizando la API CreateToolhelp32Snapshot desde el primer proceso Module32First y después yendo uno por uno con Process32Next.
*Utilizando EnumProcesses que devuelve un array con el PID de cada uno de los procesos. Hay que observar que podemos también ver los procesos que cada proceso está ejecutando.

-Podemos buscar por el nombre o clase de ventana. Para esto utilizamos la API FindWindow.

-Evitar el uso de Breakpoints. Los Breakpoints, utilizados por un debugger, son lugares en donde el debugger para porque el usuario ha modificado una instrucción por INT3 (interrupción). Esto es una ayuda considerable, ya que se pueden poner muchos BP (breakpoints) en lugares adecuados para el análisis del código. En tu código si programas en ASM, puedes comprobar en sitios determinados, si se ha modificado la instrucción por un INT3. También es posible llamar a la API VirtualProtect y modificar las propiedades de determinada sección. Los BP serán borrados.

-Detección de Hardware Breakpoints. Un debugger puede poner infinidad de BP, pero solamente puede poner 4 HBP (Hardware Breakpoints). Son muy útiles, más cuando los BP normales fallan. Muchos packers lo que hacen es detectar estos HBP para saber si hay debugger o no. Para esto hay que entender antes las SEH o manejo estructurado de excepciones. De este tema tan interesante, hice un tutorial bastante completo para entender las SEH:
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Después de que hayas leído ese tute, ya puedo seguir con la explicación de cómo se detectan los HBP. Un packer normalmente hace lo siguiente:
*Crea una excepción cualquiera
*Se ejecuta el manejador de excepciones que él mismo tiene preparado
*Desde el manejador de excepciones puede acceder directamente a los HBP.
*Si hay HBP --> hay debugger

-Bugs. Este tema es obvio. Al igual que hay bugs en grandes proyectos, pues también hay bugs en herramientas para la depuración de programas. Determinados programas hacen uso de estos bugs para que el programa crashee.
Sin ir más lejos, OllyDBG 1.10 tiene un bug archiconocido por todo el mundo que es el siguiente: Utilizar la API OutputDebugStringA y pasarle como parámetro una cadena "%s....." de tamaño igual a 100, es decir, cien %s. OllyDBG 1.10 no puede continuar. Como véis hay gente que también estudia todas estas cosas.

Bueno, estas son las más conocidas técnicas antidebugging. Realmente existen muchísimas, que seguro ni yo conoceré, pero para entender un poco todo este misterio con las anteriores sobra.

Estas técnicas son las más habituales y que todo el mundo más o menos conoce. Entonces, ¿no es bueno ponerlas en nuestra aplicación? ¿van a ser siempre detectadas? En el siguiente apartado lo veremos...

Herramientas para la depuración

Yo sé que todo esto que estoy explicando, si el lector nunca ha trabajado con Ingeniería Inversa, pues puede resultar complicado... de todos modos lo más difícil ya ha sido explicado, ahora vienen cosas "menos técnicas"

Muchas herramientas para el cracking ya reconocen estos métodos comentados.

Para tener una idea de la "fuerza" de algunos programas explicaré el archiconocido OllyDBG:
OllyDBG es un debugger a 32 bits (en ring3) potentísimo. Yo casi me atrevo a decir que para ring3 es el mejor. Desde su aparición, que al principio no causó buena sensación, fue sumando adeptos y su despegue ha sido brutal. Tiene una opción que es la posibilidad de insertar plugins... así que programadores de todo el mundo han hecho millones de plugins para este debugger. Unos plugins que hacen que OllyDBG sea una herramienta esencial e invisible a todo: sólo con un click de ratón, es posible anular ¡todas las protecciones anti-debugger que vimos en el apartado anterior!.
Con esto demuestro la magnitud de este programa. Es impresionante.

Hasta ahora sólo he comentado la existencia de dos herramientas: debuggers y desensambladores, sin embargo, existen muchísimas más que hacen que todo cracker tenga las cosas bien fáciles.

No todas estas herramientas están preparadas para detectar los trucos anti-debugger/desensambladores que vimos en el apartado anterior, así que es bueno por este motivo poner siempre algún tipo de protección de las ya vistas.

Hay herramientas específicas incluso para cada lenguaje de programación con que la aplicación haya sido compilada. Por ejemplo para programas compilados con Visual Basic hay aplicaciones como VB Decompiler, VB Reformer, SmartCheck (de verdad éste último es impresionante) etc.. para compilaciones con Delphi o Borland C++ tenemos Dede, E2A, MiniDe etc...
Todos estos programas ofrecen una ayuda al debugger muy precisa, con lo cual, el cracker rápidamente llega a la "zona caliente" que le interesa. Excepto Smartcheck que también actúa como "debugger", los demás normalmente trabajan analizando el código, por lo cuál determinadas protecciones anti-debugger no valen para nada.

Cada programa, cuando está ya compilado hay que tratarlo de forma muy diferente, por ej. un programa que haya sido compilado con Visual Basic ya se sabe que necesita de su librería de apoyo para funcionar , un programa en Delphi tiene bastante código ya que incorpora todo lo necesario en él para funcionar, los programas en NET suelen resultar muy requetefáciles de romper e incluso encontrar seriales también suele ser tarea relativamente sencilla.
Personalmente los programas en Delphi o Borland C++ me resultan los más difícultosos a la hora de analizar ya que cuando se realiza alguna función no se realiza directamente, sino que se envía un valor (normalmente 0 o 1) a un lugar de la memoria y posteriormente ese valor será tratado, me explico:
Si nosotros queremos activar un botón, por ej. en ensamblador haremos:
Call Activar_botón
Simplemente ejecutando esa subrutina (Activar_botón) el botón se activará.

Si ahora lo hacemos en Delphi o en Borland C++:
Call Activar_botón
Al pasar esa subrutina el botón NO se activa!! simplemente en un lugar de la memoria se habrá puesto un 1 y ese 1 será el que haga activar el botón más tarde.

Como se observa cada programa y según con qué lenguaje de programación fue escrito hay que tratarlo de forma muy diferente.

En todos estos casos, debes ver con qué lenguaje de programación trabajas y de este modo puedes implementar en tu aplicación alguna medida contra estas herramientas.

Como comenté antes existen debuggers (OllyDBG por ejemplo) que son invisibles a todo. Incluso algunos utilizan drivers para ejecutarse por debajo de donde las aplicaciones trabajan: ring3.
Yo pienso que es por este motivo que, como comenté al principio, los software especializados en protecciones no se preocupan tanto de poner trampas anti-debugger sino en "romper" el ejecutable para que no sea recompuesto... esta es la misión del cracker: recomponer el ejecutable que ha sido desmenuzado por un packer.

Voy a bajar el "listón" para que se entienda perfectamente:
-Un packer tiene dentro de sí mismo al ejecutable que se ha protegido. El packer se va descomprimiendo poco a poco, desencriptándose, realizando chequeos anti-debugger etc... hasta que llega un momento, cuando se ha descomprimido del todo que pasa la ejecución al programa que se ha protegido... y ¡zas! ahí entra el cracker a jugar. En ese mismo momento es cuando el cracker para todo y reconstruye poco a poco el puzzle. Como ya se sabe hay puzzles fáciles, y muy difíciles. Sin embargo, con tiempo todo puzzle se puede hacer.

Ese momento en el que ya se ha descomprimido todo y pasa a ejecutarse la aplicación protegida, es diferente también según qué compilador hayamos utilizado, por ej. en Visual Basic suele ser muy fácil llegar a este punto.

LLegados hasta aquí, ya sé que muchos se preguntan... pero yo quiero hacer mis protecciones y quiero fabricar un programa DEMO y licencia y.... ahora lo veremos en el siguiente apartado.

Quiero hacer yo mismo mi propia protección

Este apartado lo podríamos llamar consejos de gente que trata con "Ingeniería Inversa". Consejos para que tu aplicación sea más difícil de analizar.

Cuando se implanta una licencia, hay que tener presente que esa licencia es para un usuario y normamente es así:
1-Nombre del usuario
2-Contraseña del usuario

Ambas tienen una relación que sólo debe conocer el autor de la aplicación. Hay otros programas que simplemente con poner un serial ya está registrado correctamente. Me basaré en el primer caso: Nombre y contraseña.

Caso 1 - Protección (0 a 10): 1

Muchos programadores ponen la relación nombre-contraseña muy difícil de analizar: pasan los datos de nombre al valor ASCII que corresponda y realizan infinidad de operaciones matemáticas. Hasta aquí muy bien, pero...
después de realizar esas operaciones matemáticas comprueban directamente ese resultado con el serial. Ahí está la debilidad: si se compara directamente con el serial será muy fácil encontrarlo, simplemente hay que pararse en la comparación y veremos la contraseña correcta.
Puedo asegurar que infinidad(requetemuchísimos) de programas hacen esto comentado.

¿Cómo se puede arreglar?
Pues bien, todo programador debe saber una cosa lo más básico de todo: si el serial verdadero aparece directamente en memoria por cualquier causa, en menos de lo que canta un gallo será encontrado por cualquier Newbie.
Hay que evitar sea como sea la comparación directa del serial. Hay muchas formas, una por ej. sencilla es poner el valor ASCII también al serial y realizar otra serie de operaciones matemáticas...

Caso 2 - Protección (0 a 10): 2
Imaginemos un programa que la licencia para mi es:
Nombre: karmany
Serial: 1234
El chequeo que hace para la comprobación es:
Código:
Nombre: karmany --> pasa a valor ASCII --> operaciones matemáticas --> resultado final: 564
Serial: 1234 --> pasa a valor ASCII --> operaciones matemáticas --> resultado final: 564
Como se observa. ya no se compara el serial directamente pero tiene asímismo una gran debilidad: debe comparar esos resultados: 564
Esto en ensamblador aparecerá también como una comparación y aunque no tengamos el serial podemos modificar directamente el resultado de la comparación porque es una comparación: registrado- no registrado. Estaría crackeado en poco tiempo por un Newbie recién iniciado.
Hay que evitar esas comparaciones.

Caso 3 - Protección (0 a 10): 2-3
Imáginemos que tenemos el caso 2 en el que cuando introducimos una contraseña falsa nos aparece un mensaje que dice: "Contraseña no válida"
Sabemos que para el registro hay que comparar los 564 pero ¡hay que encontrarlos primero!
Lo primero que hace un cracker es ver: las 'string references', es decir, las cadenas de texto. Normalmente cualquier cadena de texto que se utilice en un programa, aparece literalmente en el mismo. Por este motivo, si cuando un usuario pone una contraseña correcta, aparece un mensaje que dice: "Gracias por registrarse" no dude ni un segundo que lo que primero va a buscar el cracker son esas palabras. Y cuando las encuentre irá directamente a parar a la comparación de 564 con 564.
Por todo esto que estoy comentando, hay que evitar las cadenas de texto literales.
Tú eres programador, esto te lo dejo a tí, hay mil formas.

Si partimos del Caso 2 y hemos eliminado toda referencia de texto, ya estamos protegiendo nuestra aplicación contra un número de Newbies. Sin embargo, este último, aunque tenga muy poca experiencia, con el tiempo encontrará esa comparación 564 con 564 y la modificará.


Caso 4 - Protección (0 a 10): 2-3
Partimos del Caso 3.
¿Qué ocurre cuando hemos introducido un código correcto? Muchos programas modifican cierto byte de ellos mismos de tal modo que si está el registro correcto el byte es 1 y si no está registrado el byte es 0.
Estamos en el Caso 4 y ya no resulta fácil encontrar un nombre-serial válido, pues el programador hace millones de operaciones matemáticas para obtener esos 564.
El cracker puede optar por dos sencillas opciones:
-modificar la comparación de 564 para que cualquier nombre-serial valga
-ver después cuál es el byte que se pone a 1 cuando nos registramos.

Sabiendo esta segunda forma, el cracker directamente modificará permanentemente ese byte a 1 y ya no hay que poner ningún nombre-serial porque ya será una versión registrada.

Caso 5 - Protección (0 a 10): 5-...
Cada persona es diferente así que lo que a mí me parece fácil a otro le parecerá difícil y viceversa.
Para mí un protección 5 ya es un tema para estrujarse las neuronas.
Partimos del caso anterior pero cuando está registrado ya no depende sólo de un byte. Para hacer esto podemos hacer que de vez en cuando sea comparado el nombre-serial, pero tenemos el problema de siempre: llegamos a la comparación de antes: 564 que hay que eliminar.
En ensamblador las comparaciones directas suelen hacerse con la instrucción cmp y después viene un salto por ejemplo "je" o "jne". El cracker lo primero que probará será modificar tras la comparación el "je" por un "jne" o viceversa.

Sólo pensando un poco se le pueden ocurrir a uno muchísimas formas de evitar que se compare directamente 564 con 564. Por ejemplo, con el nombre realizamos operaciones, con el serial lo mismo. Después realizamos operaciones con los valores obtenidos dando un valor de resultado. Con ese resultado podemos desencriptar parte de código. El problema de esto es que ese valor es siempre el mismo para cualquier nombre-serial.

Se pueden también realizar diversos chequeos, por ej. se puede examinar si la comparación 564 con 564 ha sido modificada, en tal caso no mostrar un mensaje inmediato ya que alerta al cracker y el mensaje le sirve de guía.

Se pueden realizar chequeos CRC, se pueden utilizar archivos para la licencia (keyfiles) donde cada archivo licencia es diferente según usuario.

Si no se te ocurre ninguna forma de ocultar la comparación 564 puedes hacer una cosa y es hacer esa comparación en memoria dinámica ya que ahí el cracker no puede modificar el "je" por "jne" porque en el ejecutable no existe todavía.

Si tu programa requiere actualizaciones de cualquier tipo, lo tienes bastante fácil porque según el usuario-serial tú puedes permitir la descarga o no de actualizaciones, aunque el programa esté crackeado.


Hay muchas formas que deben salir de tu imaginación. Cada programa es un mundo, como cada persona. Incluso para saber proteger una aplicación puedes analizar tutoriales de cracking, que te enseñarán las protecciones más comunes que se suelen utilizar.

Enlaces - Opinión personal

Como hemos aprendido, lo que siempre y en toda aplicación hay que evitar son las comparaciones directas tanto de serial malo-serial bueno como comparación registrado-no registrado. Eliminando asímismo las referencia a cadenas de texto haremos que nuestra aplicación ya no esté al alcance de todo Newbie. Después para aprender más recomiendo leer tutoriales de Ingeniería Inversa y así se aprenderán nuevas técnicas más complejas. Tal vez tú que estás leyendo esto seas un futuro programador de packers.
Podemos valernos de métodos sencillos que incorporan algunos compiladores para hacer que nuestra aplicación pueda ser algo más segura, por ejemplo en Visual Basic podemos compilar nuestra aplicación con P-Code que es bastante más difícil de manejar que el Código Nativo y mucha gente incluso no sabrá ni por dónde empezar.

Existen gran número de aplicaciones para empaketar nuestro programa, hay bastantes gratuitos pero siempre hay que leerse las condiciones porque en la mayoría ponen que si tu aplicación es comercial el packer no es gratuito.
Yo estoy asimismo trabajando actualmente en un "compresor" que quiero hacer gratuito para todo el mundo, que sea muy fácil de manejar y no sea por comandos, que trabaje en ensamblador (con toda la rapidez posible), y siempre y ante todo que sea gratuito sea o no sea el programa vuestro de pago.

El packer más conocido en todo el mundo es probablemente UPX.
Como ya sabrás, UPX es excelente para disminuir tu ejecutable de forma extraordinaria, por contra es muy fácil descomprimirlo: para Newbies recién comenzados en este Arte.

Intenté hacer una lista de packers, pero es tantísima la información y la gran cantidad de packers existentes, que me ha sido imposible continuar investigando uno por uno para poner enlaces de descarga o páginas web.
Así que he encontrado un enlace que seguro que os sorprende. Ojalá el enlace dure mucho tiempo:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Opinión personal:
karmany: personalmente siempre he estado en desacuerdo con aquellas personas que crackean programas y luego distribuyen el crack por la red. No entiendo esta finalidad.
Sin embargo, pienso que determinados programas también ponen un precio bastante elevado a la aplicación, pero bueno, es tan amplio el mercado que a día de hoy casi cualquier programa que se necesite, se puede encontrar gratuito por la red.

Siempre he creído y cada día más, que no hay desperdiciar muchísimo tiempo en intentar proteger nuestra aplicación, porque solamente que haya un cracker de nivel medio-bajo con ganas de crackear lo conseguirá en poco tiempo, pero tampoco hay dejar que un Newbie recién iniciado sepa hacerlo.
También es cierto que el uso de packers hacen aumentar considerablemente la dificultad, pero como ya se comentó, hará aumentar también el precio de la aplicación. Sin embargo, packers difíciles han sido muy analizados, Armadillo es un claro ejemplo.

Por otro lado, también ocurre que si la protección es difícil, el cracker puede cansarse de analizarla y dejarla apartada. Lo digo por experiencia.
A fin de cuentas, es el programador el que tiene que pensar todo esto.

Finalmente creo que una de las cosas positivas que hacen los cracks es que la aplicación sea utilizada por mucha gente y así distribuida. Si un programa fuera incrackeable sólo lo utilizarían los usuarios registrados ya que mucha gente lo desecharía por sólo usarlo un determinado tiempo.

Un ejemplo que se me ocurre a día de hoy es el antivirus NOD32. Ha tenido desde hace un tiempo un éxito rotundo. Como hasta hace poco fue crackeado satisfactoriamente, pues habrá sido utilizado por millones de personas, sin embargo actualmente no permiten la descarga de actualizaciones mas que a usuarios realmente registrados, por este motivo estoy convencido que muchísimas personas dejarán de utilizarlo. Pero bueno...

Esto es ya otro tema...
Después de todo, espero que hayas obtenido información que no sabías y puedas decidir lo que quieres o no hacer.

Fuente: Elhacker.[NET]