Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Cómo ocultar información para que no se vea en un ejecutable (https://www.clubdelphi.com/foros/showthread.php?t=89646)

carlos gonzalez 05-01-2016 17:20:49

Cómo ocultar información para que no se vea en un ejecutable
 
Hola amigos tengo una duda ojala alguien de ustedes me pueda ayudar, es algo urgente y delicado para mi trabajo.
Tengo en mi trabajo muchas aplicaciones muy estables desarrolladas en Delphi 7, manejamos dbexpress para las conexiones a la base de datos. No me había dado cuenta que si intentamos abrir el exe desde un block de notas muestra todos los datos de la conexión, servidor, usuario y password. Existe alguna forma de ocultar o encriptar esta información de modo que no sea visible y no ponga en riesgo la seguridad de la empresa.

Ejemplo de una parte de datos que me muestra al abrir el exe con el bloc de notas

Código:

        bvLoweredTabOrder TLabelLabel3Left
TopWidth1Height
Caption        Database:  TLabelDatabaseNameLeft[TopWidthHeight
  TBevelBevelLeftTopWidthþ Height        Shape        bsTopLine  TPanelPanel1LeftTopWidthý HeightAAlignalBottom
BevelOuterbvNoneTabOrder  TLabelLabel1LeftTopWidth8Height
Caption&User Name:FocusControlUserName  TLabelLabel2LeftTop$Width1Height
Caption
&Password:FocusControlPassword  TEditUserNameLeftVTopWidth™ Height        MaxLengthTabOrder  TEditPasswordLeftVTop!Width™ Height        MaxLengthPasswordChar*TabOrder    TPF0TMDataMDataOldCreateOrderOnCreateDataModuleCreateLeftITopfHeight¸Width÷ TSQLConnectionSQLConnection1ConnectionNamePOWER6
DriverNameCA400
GetDriverFuncgetSQLDriverCA400LibraryNamedbexpca400.dllLoginPromptParams.StringsDriverName=CA400Database=168.1.1.50User_Name=usersisPassword=Ori147HServerCharSet=ErrorResourceFile=LocaleCode=0000BlobSize=-1
RowsetSize=-1        RoleName=CA400 TransIsolation=DirtyReadCommitRetain=TrueAutoCommit=TrueCustom String=/trace=0Connection Timeout=-1Trim Char=True        VendorLib        cwbdb.dllLeft Top  TSimpleDataSetSDSCp11pfGrados
Aggregates
ConnectionSQLConnection1DataSet.CommandText

Su amigo Charless

Casimiro Notevi 05-01-2016 17:33:49

Lo más simple y rápido, ahora mismo, es usar algo como UPX o similar.

mamcx 05-01-2016 19:15:48

Ya que usas Sql Server, es mejor que uses "Seguridad Integrada":

http://www.connectionstrings.com/sql-server-2012/

Eso hace que la autenticacion pase por el OS. Es mas seguro. El uso de usuario/clave es desaconsejado para la mayoria de los casos y solo se usa para acceder a BD remotas por fuera del dominio/maquina

AgustinOrtu 05-01-2016 19:55:48

Eso pasa porque esta todo en tiempo de diseño en tu componente connection

Lo mejor que podes hacer es asignar la ConnectionString en runtime, pasando los credenciales como string literales; no los almacenes como constantes o recursos

orodriguezca 05-01-2016 20:20:37

Cita:

Empezado por mamcx (Mensaje 501034)
Ya que usas Sql Server, es mejor que uses "Seguridad Integrada":

Por la librería de conexión "dbexpca400.dll " pensaría que se está conectando a un IBM ISeries (AS400). Si es así en este caso no aplica la "Seguridad Integrada".

carlos gonzalez 05-01-2016 21:50:40

Es correcto la base de datos que manejamos es DBD2 DEL AS/400

look 05-01-2016 22:33:31

No sera mejor indagar en temas de ofuscacion?, o sera algo asi como que exe tambien se va en debug y no release?

Saludos!

mamcx 06-01-2016 00:36:11

En tal caso, la opcion mas recomendada es poner los datos en una ubicacion aparte y leerlo de forma dinamica. Puede ser un archivo que se le aplique los permisos adecuados, o usar mucho mejor el api:

https://msdn.microsoft.com/en-us/library/ms995355.aspx

Y esto en delphi:
https://stackoverflow.com/questions/...ord-in-windows

Esto entonces plantea como alimentar la primera vez esa info. La idea es que puedes por ejemplo pasarlo en un archivo, guardarlo de forma segura en el keylocker y borrar el archivo.

Neftali [Germán.Estévez] 07-01-2016 09:33:29

Yo habitualmente para temas de password, los añado al código (no al DFM) con una encriptación sencilla o en algún fichero de configuración con técnica similar.
Y en tiempo de ejecución se asignan esos parámetros.

pacopenin 07-01-2016 11:10:50

Una posible solución de efectos inmediatos podría ser cargar los valores que se desean ocultar llamando a funciones que devuelvan esos valores.

Hace tiempo nos piratearon un programa mediante un debugger. Generábamos la clave de registro y era almacenaba en una variable, luego la comparaba con la que tenía asignada la instalación del programa. Al asignarla a una variable, dicha clave se veía mediante el debuger. Cambiamos a devolverla mediante una función y ya no aparecía en toda la traza. Es algo sencillo y funciona.

Neftali [Germán.Estévez] 07-01-2016 14:45:51

Cita:

Empezado por pacopenin (Mensaje 501077)
Hace tiempo nos piratearon un programa mediante un debugger. Generábamos la clave de registro y era almacenaba en una variable, luego la comparaba con la que tenía asignada la instalación del programa. Al asignarla a una variable, dicha clave se veía mediante el debuger. Cambiamos a devolverla mediante una función y ya no aparecía en toda la traza. Es algo sencillo y funciona.

Si se entra en temas de debuggers (OllyDbg es el más utilizado) la cosa se complica y hay que entrar "en otro nivel".
Hay que tener en cuenta mensajes de error, mensajes al usuario, nombre que se definen en las funciones, nombres que se definen a las constantes/variables, y bastantes cosas más.
Normalmente lo primero que se hace es atacar al valor de una variable o constante (como comenta pacopenin), pero también al momento de la comparación. Es decir, que por muy complicada que sea la forma de almacenar la clave o de calcularla, al final lo normal es hacer un... "si este valor es igual a este" o "si son diferentes" dejo ejecutar o no (el registro es correcto o no).
Y a ese punto es al que se ataca. Modificando un JZ por un JNZ o JE por JNE, lo que se consigue es "negar" la comparación, por lo tanto, cualquier clave incorrecta pasa a devolver correcta (excepto la buena :o:o).

Es un ejemplo, pero si alguien que sepa utilizar un debugger está pirateando nuestro programa, las técnicas y las estrategias para protegerlo o al menos para ponérselo más difícil son diferentes.

Ñuño Martínez 08-01-2016 11:36:46

Siempre puedes usar una codificación por XOR, de forma que sólo funcionará con la clave correcta y con ninguna otra. Incluso aunque usen depuración les costará.

escafandra 08-01-2016 16:45:14

Cita:

Empezado por Ñuño Martínez (Mensaje 501103)
Siempre puedes usar una codificación por XOR, de forma que sólo funcionará con la clave correcta y con ninguna otra. Incluso aunque usen depuración les costará.

Ese truco he usado en numerosas ocasiones con éxito. Codifico las cadenas en una app externa y luego las pego en el código. Antes de usarlas las descifro. La rutina que he usado es tipo Xor, y por tanto simétrica con la misma clave.

Expongo un ejemplo de esa rutina en delphi, esta función se ejecuta en la app externa y en la aplicación que esconde cadenas u otro tipo de dato:

Código Delphi [-]
// Rutina de encriptación Xor.
// La misma rutina encripta y desencripta.
// Source: un puntero al buffer que contiene la fuente a encriptar.
// Size: Tamaño del buffer a encriptar
// Password: clave en modo texto que se tratará como de 8 caracteres, 64 bits
// _Mod: es el módulo restante para encriptaciones parciales
// Si se encripta un buffer por partes, Mod es Size_encriptado%8
// donde Size_encriptado es el tamaño total de lo encriptado hasta ese momento.
// Mod corrige el punto de comienzo del nuevo bloque a encriptar.

procedure Crypt(Source: Pointer; Size: Cardinal; Password: PCHAR; _Mod: integer);
var
  S: PCHAR;
  len, n: integer;
begin
   S:= Source;
   len:= lstrlen(Password);
   for n:=0 to Size-1 do
   begin
     S[n]:= CHAR(integer(S[n]) xor integer(Password[_Mod mod len]));
     inc(_Mod);
   end;
end;


Saludos.

escafandra 08-01-2016 17:08:57

Cita:

Empezado por Neftali (Mensaje 501082)
Si se entra en temas de debuggers (OllyDbg es el más utilizado) la cosa se complica y hay que entrar "en otro nivel".
Hay que tener en cuenta mensajes de error, mensajes al usuario, nombre que se definen en las funciones, nombres que se definen a las constantes/variables, y bastantes cosas más.
Normalmente lo primero que se hace es atacar al valor de una variable o constante (como comenta pacopenin), pero también al momento de la comparación. Es decir, que por muy complicada que sea la forma de almacenar la clave o de calcularla, al final lo normal es hacer un... "si este valor es igual a este" o "si son diferentes" dejo ejecutar o no (el registro es correcto o no).
Y a ese punto es al que se ataca. Modificando un JZ por un JNZ o JE por JNE, lo que se consigue es "negar" la comparación, por lo tanto, cualquier clave incorrecta pasa a devolver correcta (excepto la buena :o:o).

Es un ejemplo, pero si alguien que sepa utilizar un debugger está pirateando nuestro programa, las técnicas y las estrategias para protegerlo o al menos para ponérselo más difícil son diferentes.

Es más eficaz sustituir el salto condicional relativo por dos instrucciones asm nop. Para evitar tan sencillo crack, la verificación debe estar en varios puntos distintos de código, nunca en una misma subrutina y aislarla de código cercano de mensajes de error. También es conveniente verificaciones por internet y en cada actualización. Pero ninguna protección es infalible, sólo dificultas y con suerte aburres.

Saludos.

Reasen 09-01-2016 00:14:08

Haz que las condiciones vayan por llamadas dinámicas de tal manera que si no coinciden el programa no funcione, (esto es para reemplazar condiciones del mismo)
tambien añade un manejador de excepciones para evitar errores cuando la llamada sea incorrecta,
Luego para ofuscar las strings, si se trata de un password te recomiendo que uses MD5 para conocerlas por colisión.

Delphius 09-01-2016 03:52:50

Cita:

Empezado por escafandra (Mensaje 501110)
Para evitar tan sencillo crack, la verificación debe estar en varios puntos distintos de código, nunca en una misma subrutina y aislarla de código cercano de mensajes de error.
Saludos.

Esto no entendí, ¿Es posible un ejemplo?

Saludos,

Reasen 09-01-2016 03:54:58

Cita:

Empezado por Delphius (Mensaje 501121)
Esto no entendí, ¿Es posible un ejemplo?

Saludos,

hacer copias de la funcion que verifica si esta todo bien y llamarla desde diferentes puntos de codigo es a lo que se refiere
pero es una tecnica poco eficiente pues es tan simple como hacer un script con ollydbg que fixee esos Opcodes.

escafandra 10-01-2016 17:46:54

Cita:

Empezado por Reasen (Mensaje 501122)
hacer copias de la funcion que verifica si esta todo bien y llamarla desde diferentes puntos de codigo es a lo que se refiere
pero es una tecnica poco eficiente pues es tan simple como hacer un script con ollydbg que fixee esos Opcodes.

En realidad no se trata de copiar la función sino de verificar en distintos puntos nuevamente. Para evitar los debugger hay formas de detectarlos y hacer que el código se comporte de forma diferente.

Saludos.

Delphius 10-01-2016 20:41:05

Cita:

Empezado por escafandra (Mensaje 501138)
En realidad no se trata de copiar la función sino de verificar en distintos puntos nuevamente. Para evitar los debugger hay formas de detectarlos y hacer que el código se comporte de forma diferente.

Saludos.

Cita:

Empezado por escafandra (Mensaje 501110)
Para evitar tan sencillo crack, la verificación debe estar en varios puntos distintos de código, nunca en una misma subrutina y aislarla de código cercano de mensajes de error.

Saludos.

A ver si logro entender entonces...

O sea, por ejemplo, En lugar de una función Verify() que regresa un boolean.... ¿Tendría que tener N funciones Verify()? ¿Tampoco debería evitarse hacer algo como esto?

Código Delphi [-]
if Verify(...)
   then ...
   else ShowMessage('Falla de verificación. Además texto en limpio como éste se lo puede leer facilmente en un debugger');

Y quizá algo más seguro sea:

Código Delphi [-]
if Verify(...)
  then ...
  else CryptAdvise(VarText);

procedure CryptAdvise(Text: string);
begin
  Crypt(Text, ThePrivateKey);
end;

Me interesa un poco el tema, pero yo estoy en cero en tema de seguridad anti-copias, anti-cracks, etc. Y por ello me quedé con la duda de a como va la cosa.

Saludos,

AgustinOrtu 10-01-2016 22:23:38

A lo que se refiere es que no hagas esto:

Inicia programa --> validar licencia

Ya que es "facil" de encontrar en donde esta la funcion que verifica

Mas bien, hay que meter la validacion regada por todos lados

Hizo click en guardar como? -> Validar licencia
Apreto combinacion de teclas control+3 para usar x funcion? --> Validar licencia
Pidio imprimir? --> Validar

Y asi


La franja horaria es GMT +2. Ahora son las 07:05:17.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi