Está en la página 1de 8

CODIGO FUENTE: CLIPPER

PROTECCION DE NUESTRAS
APLICACIONES
•Pablo Martínez Morillas•
El esfuerzo del desarrollo de una aplicación, exige una mínima recompensa. Las empresas
productoras de software y los programadores más modestos, ven como el esfuerzo de meses
(a veces años) para conseguir una aplicación más o menos decente no tiene ni siquiera la
recompensa de que éstos puedan decidir cuándo su producto puede ser libremente copiado
(freeware) y cuando no, debido a la piratería informática. Así, se van aplicando métodos de
protección cada vez más sofisticados para evitar la copia de las aplicaciones de los discos
de instalación o de los programas una vez instalados. Protecciones que a veces pueden ser
múltiples, y que van desde las más sofisticadas a las más simples.

Para los programadores que se mueven en el entorno de los lenguajes dBase, y


concretamente los que se han introducido en el mundo del lenguaje Clipper, a continuación
se muestra un trozo de código con el que se consigue una protección simple pero efectiva.
Esta protección puede evitar la copia de los programas de nuestras aplicaciones una vez
instaladas en disco fijo, y de los discos de nuestras aplicaciones (si éstos son copiados
simplemente con utilidades del sistema) incluyéndola en nuestro programa de instalación.
Se basa en el reconocimiento del número de serie de volumen que el sistema da a nuestros
discos fijos y disquetes al ser formateados. También incluye una protección para delimitar
el número de instalaciones. Esto se consigue utilizando, entre otras, algunas funciones
Clipper de bajo nivel.

CODIGO FUENTE:

*--------------------------------------------------------------
* INSTALAR
* Programa para instalación de aplicativos con protección
*--------------------------------------------------------------
CLS
PRIVATE lVer:=.F. // Conmutador para decidir si la función SustiExe()
actúa para la protección por nº de serie o por nº de instalaciones.
PRIVATE cStrGrab:="" // Cadena a grabar en rutina sustitución contenido
variable para protección.
* --------------------------------------------------------------
* PROTECCIÓN DEL PROGRAMA INSTALAR ...
* --------------------------------------------------------------
* === VARIABLES RUTINA PROTECCIÓN POR NUMERO DE SERIE VOLUMEN ===
PRIVATE cp1ml:="ÉÅ..û..mé" // variable cuyo contenido inicial será
sustituido por el nº de serie de volumen del disquete para protección de
INSTALAR.EXE.
PRIVATE c1ptk:="ÉÅ..û..mé" // variable cuyo contenido inicial será
sustituido por el número de serie del volumen del disco fijo una vez
instalado el aplicativo a proteger.
* > cp1ml y c1ptk tienen que tener el mismo número de caracteres que la
cadena que mandemos al fichero .EXE, en este caso serán 9 caracteres =
caracteres del nº de serie del disco a substituir en el fichero .EXE al
valor inicial de cp1ml y c1ptk.
PRIVATE cNumSeDisk:= SPACE(9) // Nº de Serie Volumen recogido del eco de
VOL.
* ======= VARIABLES PARA PROTECCION POR NUMERO DE INSTALACIONES ======
* Contador de nº de instalaciones:
PRIVATE nInstalacion:=0
* Cadena que contiene 3 caracteres codificados que representan el nº de
la última instalación efectuada. Estos tres caracteres (los 3 últimos de
cCic ÏÏÏ) son '000' codificados:
PRIVATE cInstalacion:=" "
* Número máximo de instalaciones:
PRIVATE nMaxInst:=3
* Valor de inicio de la variable que contiene en sus 3 últimos caracteres
el contador del nº de instalaciones:
PRIVATE cCic:="%_. /_È_—ÏÏÏ"
* Valor para condición de seguir o no ejecución devuelto por VERNINST():
PRIVATE lSeguir:=.T.
* ========= OBTENCION Nº SERIE VOLUMEN ==========
* Se envia al fichero m00zxw el mensaje del comando VOL del MS-DOS.
RUN VOL > m00zxw // El fichero (m00zxw) contendrá el mensaje del eco de
VOL.
* cNumSeDisk toma los 9 caracteres correspondientes al num. de serie del
disco.
cNumSeDisk:=SUBST(MEMOREAD("m00zxw"),-11,9)
cNumSeDisk=CODIF(cNumSeDisk)
* Se borra el fichero Volume.TXT una vez obtenido el num.serie del disco.
ERASE m00zxw
*
* ======= PROTECCION DE INSTALAR.EXE POR Nº SERIE VOLUMEN =========
*
IF cp1ml="ÉÅ..û..mé"
* Se envian a INIT los par metros NOMBRE_FICHERO_EXE_A_PROTEGER y la
variablea cPAMM que contendr inicialmente un valor cualquiera de 9
caracteres ("ÉÅ..û..mé" en este caso).
lVer=.F.
SustiExe('INSTALAR.EXE',cp1ml) // Solo se realizar una vez la función
INIT pues cp1ml solo tomar una vez su valor inicial "ÉÅ..û..mé" .. las
veces siguientes que se ejecute el programa la variable cp1ml contendrá
los caracteres del número de serie del disco (cNumSeDisk) ya que el
contenido de cNumSeDisk es grabado con la función INIT en el lugar que
ocupaba el valor de cp1ml.
ELSE // Si cp1ml no contiene el numero de serie del disco termina el
programa.
IF cp1ml#cNumSeDisk
@ 10,10 SAY "COPIA NO AUTORIZADA. LA APLICACION ESTA BLOQUEADA"
@ 12,10 SAY "PULSE UNA TECLA PARA TERMINAR... "; INKEY(0)
RETURN
ENDIF
ENDIF
*
* ====== PROTECCION DE INSTALAR.EXE POR Nº DE INSTALACIONES ======
*
lVer=.T.
* A la función que controla en nº de instalaciones se le pasan los
parámetros Nombre_del_fichero y los 9 primeros caracteres de la variable
cCic para ser buscados en INSTALAR.EXE.
SustiExe('INSTALAR.EXE',LEFT(cCic,9))
IF lSeguir=.F.
@ 4,10 SAY "HA SUPERADO EL NUMERO DE INSTALACIONES AUTORIZADAS ..."
@ 5,10 SAY "PULSE UNA TECLA PARA TERMINAR "; INKEY(0)
RETURN
ENDIF
* ------------------------------------------------------------------
* INSTALACION ...
*-------------------------------------------------------------------
CLS
PRIVATE cDirInst:="C:\TEMP"
RUN COPY APLICATI.EXE c:\TEMP
* Esta rutina de instalación solo es un ejemplo. Hay programas de
instalación freeware para hacer esta tarea mucho más elaborada.
*-------------------------------------------------------------------
* PROTECCION DEL APLICATIVO A SER INSTALADO ...
*-------------------------------------------------------------------
RUN VOL C: > m00zxw
CLS
cNumSeDisk:=SUBST(MEMOREAD("m00zxw"),-11,9)
cNumSeDisk=CODIF(cNumSeDisk)
ERASE m00zxw
lVer=.F.
SustiExe("C:\TEMP\APLICATI.EXE",c1ptk)
RETURN
*-------------------------------------------------------------------
* Aquí acaba el programa de instalación de aplicativos.
*-------------------------------------------------------------------

**** FUNCIONES UTILIZADAS EN EL PROGRAMA DE INSTALACION ************


* SUSTIEXE = Función para cambiar el contenido de una variable en un
fichero ejecutable a proteger.
* -------------------------------------------------------------------
FUNCTION SustiExe(cNomExe,cStr)
* Apertura del fichero .EXE en modo 2 (lectura-escritura):
LOCAL cFicExe:=FOPEN(cNomExe,2)
* nLeoFic = nº de caracteres leidos por Fread():
LOCAL nLeoFic:=0
* nPosStr = Posición de la cadena buscada en la cadena de la variable
cBuffer que recibe los caracteres en Fread():
LOCAL nPosStr:=0
* lLoop = Variable de control del ciclo Do While:
LOCAL lLoop:=.T.
* cBuffer = Variable que recibe cadenas de 4096 caracteres leidos con
Fread()
* en el fichero ejecutable:
LOCAL cBuffer:=SPACE(4096) // Inicializaci¢n de cBuffer.
* Posición de comienzo de lectura en el fichero .EXE:
LOCAL nStart:=FSEEK(cFicExe,0,0)
* Nº de caracteres de la cadena a buscar y reemplazar:
LOCAL nLenStr:=LEN(cStr)+1

DO WHILE lLoop
lLoop = .F. // lLoop ser .F. al comienzo de cada ciclo.
* Lectura del fichero abierto cada 4096 bytes sobre la variable c
Buffer, y asignación sobre nLeoFic del nº de bytes leidos (serán 4096
menos la última lectura que se haga en caso de que se fin de fichero):
nLeoFic=FREAD(cFicExe,@cBuffer,4096)
* Posición de la cadena buscada en cBuffer:
nPosStr=AT(cStr,cBuffer)
DO CASE
CASE nPosStr>0 // Si se cumple es que hemos encontrado la cadena
buscada.
* --------- Rutina control nº instalaciones --------------------
IF lVer // Si lVer=.T. la función verá el nº de instalaciones
efectuadas.
lSeguir=.T.
nInstalacion=VAL(CODIF(SUBSTR(cBuffer,nPosStr+9,3)))
IF nInstalacion=nMaxInst+1 // Si se han superado el nº
instalaciones.
lSeguir=.F. // No se permitir n m s instalaciones ...
RETURN NIL // No sigue el proceso y regresa ...
ELSE
++nInstalacion
cInstalacion=CODIF(STRZERO(nInstalacion,3))
cCic=cStr+cInstalacion
cStrGrab=cCic
ENDIF
ELSE // Si lVer=.F. la función hará protección por nº serie
cStrGrab=cNumSeDisk // La cadena a grabar ser el nº de serie
ENDIF
* ---------- Fin rutina control nº instalaciones -----------------
* Posicionamiento en el byte anterior a la cadena encontrada:
FSEEK(cFicExe,(nStart+nPosStr)-1,0)
* Grabación de la nueva cadena en el lugar de la encontrada, con lo
que cambiará el contenido de la variable cuyo valor es el de la cadena a
sustituir:
FWRITE(cFicExe,cStrGrab)
FCLOSE(cFicExe) // Se cierra el fichero.
* Si se ha llegado a fin de fichero es que no se ha encontrado la
cadena buscada y se cierra el fichero:
CASE nLeoFic < 4096
FCLOSE(cFicExe)
* Si no se ha llegado a fin de fichero ni se ha encotrado la cadena
buscada se actualiza el valor del puntero de lectura nStart, se
inicializa el contenido de cBuffer y se continua la búsqueda (lLoop=.T.):
OTHERWISE
nStart=FSEEK(cFicExe,-nLenStr,1)
cBuffer=SPACE(4096)
lLoop= .T.
ENDCASE
ENDDO
RETURN NIL
*--------------------------------------------------------------------
* CODIF = Función de codificación de literales ...
*--------------------------------------------------------------------
FUNC CODIF(cTexto)
PRIVATE nI:=0, nLenTexto:=LEN(cTexto), cCarTexto:=" "
FOR nI=1 TO nLenTexto
cCarTexto=SUBSTR(cTexto,nI,1)
cTexto=STUFF(cTexto,nI,1,CHR(255-ASC(cCarTexto)))
NEXT
RETURN (cTexto)
*--------------------------------------------------------------------
* Fin de programa ...........
*--------------------------------------------------------------------

COMENTARIOS A LA PROTECCION DE INSTALAR.EXE

La protección del programa INSTALAR.EXE se hace en dos fases:

1.- La primera se hace mediante la creación de una variable (cp1ml) que toma un valor
inicial cualquiera ("ÉÅ..û..mé" en este caso concreto) y mediante funciones de bajo nivel
de Clipper se abre en forma binaria (ASCII) en fichero INSTALAR.EXE y se cambia el
contenido de esta variable por los 9 caracteres correspondientes al número de serie del
disquete donde se encuentra el programa INSTALAR.EXE y el aplicativo que ha de ser
instalado al ser ejecutado INSTALAR una primera vez. El número de serie del volumen
(disquete) se obtiene enviando un eco del comando VOL a un fichero (m00zxw) que recoge
el literal que contiene entre otros datos dicho nº de serie de volumen. Este nº de serie será
comparado con la variable en cuestión, preguntando previmente si el contenido de la
variable es el que le asignamos de entrada ("ÉÅ..û..mé") en cuyo caso seguir la ejecución
del programa por ser la primera vez que lo intentamos, si no es as¡ comparar con la variable
(cp1ml) con el nº de serie de volumen y si no coincide se abortar la ejecución.

La función que realiza el cambio del contenido de la variable es la función INIT que se
ejecuta una sola vez para proteger el programa INSTALAR.EXE, mediante las referidas
funciones de bajo nivel.

Notas:
A) Hay que tener en cuenta que el literal asociado por primera vez a la variable
("ÉÅ..û..mé") no puede aparecer en el programa anteriormente a su declaración como
privada (exceptuando en los comentarios como este) ya que si fuera as¡ la función INIT
cambiaría la primera ocurrencia de éste y no funcionaría la comparación de la variable
(cp1ml) ya que no habría sido cambiado su contenido.

B) También habrá que tener en cuenta que este literal asociado a dicha variable deberá
aparecer en el programa considerado como fichero ASCII antes del byte o carácter nº
65.535, por limitaciones de la búsqueda de las funciones de bajo nivel en la función INIT.
C) También hay que tener en cuenta que el disquete que contiene INSTALAR. EXE y el
aplicativo motivo de la instalación, ha de tener número de serie de volumen, pues de no ser
así podrá ser copiado en otro disquete sin nº de volumen y la protección no servirá de nada
ya que coincidirán las cadenas obtenidas del mensaje producido por el eco de VOL.

D) El hecho de que el disquete donde se intentara copiar el disco de instalación no tenga nº


de serie no importa, ya que tampoco coincidirán en este caso el nº de volumen del disco de
instalación con el literal obtenido con VOL del disco copia.

2.- La segunda fase de protección consiste en controlar el número de instalaciones que se


hacen. Se utiliza para ello un método parecido al anterior en cuanto que se va cambiando el
contenido inicial de una variable en el propio programa INSTALAR.EXE mediante la
función VERNINST. Es el contenido de la variable (cCic) en este caso, que contiene un
literal de 12 caracteres: los 9 primeros sin significado alguno y los 3 últimos son ("000")
codificados con la función CODIF(). El hecho de contener 9 caracteres anteriores a los tres
que harán de contador de instalaciones es debido a que existe una mínima posibilidad de
que existieran esos tres caracteres anteriormente en el programa INSTALAR.EXE, y al
tener 12 caracteres a comparar disminuye la posibilidad de coincidencia. Al contrario de lo
que sucede en la 1ª fase (INIT solo se ejecuta una vez) la función VERNINST() se
ejecutará tantas veces como instalaciones hagamos hasta el nº de instalciones permitido que
está declarado en la variable nMaxInst. Se diferencia esta función de INIT básicamente en
que controla los 3 últimos caracteres del contenido de la variable elegida (cCic) y cambia
su valor cada vez, por lo demás, su funcionamiento es el mismo. También habrá que tener
aquí en cuenta las notas expresadas en la primera fase de protección.

Aclaratoria: El hecho de tomar como literales de entrada en las variables cp1ml y cCic un
grupo de caracteres tan poco significativos como el nombre de las propias variables, es para
evitar su fácil identificación en caso editar el fichero INSTALAR.EXE antes de ejecutarlo
por primera vez (cosa poco probable ya que es condición indispensable el ejecutar una 1ª
vez el programa INSTALAR.EXE antes de su posible "pirateo".), ya que son literales cuyo
contenido es distinto antes y después de ejecutarse el programa. También por este motivo
se codifican mediante la función CODIF() el contenido de las variables (el nº de volumen
del disco) que sería visible al editarse el programa .EXE y ser revisado con cierta dosis de
paciencia.

Notas Finales: Como se ha dicho, es indispensable ejecutar una primera vez el programa de
instalación INSTALAR.EXE para protegerlo copiando el nº del disquete en el propio
INSTALAR.EXE, ya que sino lo hacemos se podrian sacar tantas copias como quisieramos
con un DISKCOPY "vulgaris" antes efectuar la instalación, esta primera instalación sería la
nº cero, y no contaría como instalación de usuario ya que se ha tenido en cuenta a la hora de
inicia lizar el contador...

El aplicativo a ser instalado tendrá que contener las siguientes lineas de programa o
parecidas...:

* RUN VOL > m00zxw


* PRIVATE cNumSeDisk:=SUBST(MEMOREAD("m00zxw"),-11,9)
* cNumSeDisk=CODIF(cNumSeDisk)
* ERASE m00zxw
* PRIVATE cp1ml:="ÉÅ..û..mé"
* IF cp1ml#cNumSeDisk
* @ 5,5 say "Copia no autorizada...
* @ 6,5 say "Pulsa una tecla y... adios!"; inkey(0)
* RETURN
* ENDIF
* y la función CODIF, ya que es utilizada...
No es necesaria aquí la función INIT() ya que el contenido de la variable (cp1ml) es de
principio el que corresponde a los 9 caracteres elegidos del eco del comando VOL, pues
esta tarea ya se hace en el programa de instalaci¢n INSTALAR.EXE ...

En cuanto a las posible formas de "piratear" el aplicativo una vez instalado las desconozco,
ya que no sé de ningún "copión" que copie el nº de serie del disco duro y la aplicación pues
tendría que ser de propósito muy específico para esta protección... y en cuanto a la
posibilidad de encontrar y manipular el contenido de la variable es mínima ya que está
codificada y además hay que saber que la protección es ésta.

Con un buen copión podemos copiar el disco de instalación íntegro, con nº de serie de
volumen incluido, con lo que ya no es efectiva la protección. Claro que esto requiere ya la
disposición de unos medios y una intención "decidida" de copiar lo que sea. Por otra parte,
una vez ejecutada la instalción la 1ª vez para activar la protección, no podemos ejecutar el
aplicativo en el propio disquete (además no tiene sentido y probablemente ni espacio, ya
que todo el aplicativo con sus ficheros de datos posiblemente irán comprimidos), y si
copiamos el aplicativo a otro disquete o disco fijo tampoco funcionará ya que no coincidirá
el valor inicial de la variable con el nº de serie codificado del disco en el que hayamos
copiado (tenga o no dicho nº) salvo coincidencia, casi imposible... por el mismo motivo
tampoco funcionará una copia del aplicativo ya instalado del disco fijo a otro disco.

COMENTARIOS A LA PROTECCION EN EL APLICATIVO


El sistema de protección del aplicativo que se instala en disco fijo es el mismo que el
utilizado para proteger el programa INSTALAR.EXE en su primera fase, con la diferencia
de que el cambio del contenido de la variable elegida a tal efecto (c1pkt) se hace sobre el
aplicativo ya instalado en el disco fijo, quedando el contenido del aplicativo en el disquete
sin modificar en ninguna de las instalaciones efectuadas. No habrá que olvidar tampoco en
este caso las notas expuestas en la 1ª fase de protección del programa de instalación
INSTALAR.EXE.

*--------------------------------------------------------------------
* APLICATI = APLICATIVO A INSTALAR
CLS
* Se envia al fichero m00zxw el mensaje del comando VOL del MS-DOS
RUN VOL > m00zxw // EL FICHERO m00zxw CONTENDRA EL MENSAJE
CLEAR ALL
* cNumSeDisk toma los 9 caracteres correspondientes al num.serie del
disco
PRIVATE cNumSeDisk:=SUBST(MEMOREAD("m00zxw"),-11,9)
cNumSeDisk=CODIF(cNumSeDisk)
* Se borra el fichero Volume.TXT una vez obtenido el num.serie del disco.
ERASE m00zxw
*
PRIVATE cp1ml:="ÉÅ..û..mé" // cp1ml tiene que tener el mismo número de
caracteres que la cadena que mandemos al fichero .EXE, en este caso serán
9 caracteres = caracteres del nº de serie del disco que sustituirá en el
fichero .EXE al valor inicial de cp1ml. La palabra "ÉÅ..û..mé" debe
aparacer por primera vez (o sólo una vez) en el programa asociada a su
variable cp1ml, pues de lo contrario al ser buscada y encontrada en otro
lugar anterior sería ahí cambiada por el num. de serie del disco por lo
que ya la variable seguiria teniendo el contenido "ÉÅ..û..mé".
IF cp1ml#cNumSeDisk
@ 5,5 say "Copia no autorizada... !"
@ 6,5 say "Pulsa una tecla y... adios!"; inkey(0)
RETURN
ENDIF
@ 5,5 SAY "ESTO ESTA FUNCIONANDO....."
@ 6,5 SAY "PULSA UNA TECLA PARA FIN..";INKEY(0)
RETURN
****
FUNC CODIF(cTexto)
PRIVATE nI:=0, nLenTexto:=LEN(cTexto), cCarTexto:=" "
FOR nI=1 TO nLenTexto
cCarTexto=SUBSTR(cTexto,nI,1)
cTexto=STUFF(cTexto,nI,1,CHR(255-ASC(cCarTexto)))
NEXT
RETURN (cTexto)

Pablo Martinez Morillas