PDA

Ver la Versión Completa : Cómo ocultar información para que no se vea en un ejecutable


carlos gonzalez
05-01-2016, 17:20:49
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


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=CA400Data base=168.1.1.50User_Name=usersisPassword=Ori147HServerCharSet=ErrorResourceFile=LocaleCode=0000BlobS ize=-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
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/13145112/secure-way-to-store-password-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
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
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:


// 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
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
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
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
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
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.

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?

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:

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

Reasen
11-01-2016, 04:49:41
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.

Actualmente existe un plugin de ollydbg que oculta cualquier tecnica de anti-debugging en Ring0-3 que te puedas imaginar, lo unico que te queda es hacer la tecnica ParentProcess, te lo digo por experiencia.

escafandra
11-01-2016, 14:27:58
Actualmente existe un plugin de ollydbg que oculta cualquier tecnica de anti-debugging en Ring0-3 que te puedas imaginar, lo unico que te queda es hacer la tecnica ParentProcess, te lo digo por experiencia.

Te refieres a la técnica de Self-Debugging, o simplemente a averiguar el proceso padre. En este segundo caso te diré que desde Vista ers posible que una aplicación lanzadera engañe sobre el padre del proceso, aquí (http://clubdelphi.com/foros/showthread.php?t=88594) se discutió el tema.

Saludos.

Reasen
11-01-2016, 17:28:11
Te refieres a la técnica de Self-Debugging, o simplemente a averiguar el proceso padre. En este segundo caso te diré que desde Vista ers posible que una aplicación lanzadera engañe sobre el padre del proceso, aquí (http://clubdelphi.com/foros/showthread.php?t=88594) se discutió el tema.

Saludos.
Ya me lo imaginaba, igualmente otra manera para evitar cracking es leer la memoria de una función para ver si es cambiada comprobándola por MD5, también se puede usar para la desencriptación de strings por lo que dañaría el programa si alguien parcheara algo.

Reasen
13-01-2016, 10:07:25
Ya me lo imaginaba, igualmente otra manera para evitar cracking es leer la memoria de una función para ver si es cambiada comprobándola por MD5, también se puede usar para la desencriptación de strings por lo que dañaría el programa si alguien parcheara algo.
Por si alguien le interesa de que va deje un ejemplo en otro foro: https://forum.tuts4you.com/topic/37894-crackme-2016-delphi-itself-checks/