Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Temas relacionados > Seguridad
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Eliminar ciertos datos de la memoria RAM

Hola,

Si uno utiliza un programa como WinHex puede acceder a la memoria RAM que está ocupando un programa determinado. Si haces uso de este programa puedes visualizar la parte de memoria RAM ocupada por un programa, con sus identificadores, variables, valores...

Y aquí está la cuestión, en los valores. Supongamos un programa que puede ser registrado por los usuarios. Para ello el usuario ha de proporcionar al programa su "clave" de usuario y un número de serie. Dentro del programa hay al menos dos funciones "críticas"... o que a mí me lo parecen luego de investigar el asunto un poco.

A ver. Como digo son dos funciones, básicamente. Una de ellas comprueba que el número de serie proporcionado por el usuario resulta válido para la clave de usuario que también se especifique. Esta función no me parece tan crítica como la siguiente: la función que se encarga de obtener un número de serie válido realmente para el usuario, precisamente, para compararlo con el que el usuario proporciona.

Bien. El caso es que el usuario puede ejecutar el programa y simular su registro especificando una clave de usuario y un número de serie al azar. Acto seguido el programa comprueba el número de serie, y, obviamente, no es correcto (sería complicadísimo averiguarlo al azar) así que el programa cierra el cuadro de diálogo correspondiente y aquí paz y después gloria.

Pero no. Si usuario tiene preparado el programa WinEx o lo ejecuta (todavía con nuestro programa en ejecución, o sea en memoria) con WinEx el usuario puede visualizar la memoria RAM ocupada por el programa, y, sorpresa, sorpresa, en la memoria RAM se encuentra el número de serie válido para el usuario... tal como fue generado en la función correspondiente.

He intentado ya unas cuantas cosas. Al final he conseguido (creo) reducir el problema, concretarlo en la función que digo que se encarga de crear un número de serie correcto para el usuario, de tal manera que pueda compararlo con el que proporcione el usuario. Es aquí donde está el problema, y el caso es que la función digamos que es similar a esta:

Código Delphi [-]
function ObtenerNumeroSerie(numeroBase:
 integer; claveUsuario: string): string;
var
  A: Integer;
begin
  result := '';
  if (numeroBase <> 0) and (claveUsuario <> '') then
    Result := numeroBase * Length(claveUsuario) * 77;
end;

Como puede verse (y disculpad que me enrrolle... pero intento dejar claro el asunto lo mejor que sé hacerlo), como puede verse, digo, la función se basa en cierto número base, que a su vez se combina con la "clave del usuario"... pero el caso es que la función tiene que terminar resultando en un número de serie válido para la clave de usuario, el mismo que podríamos nosotros generar en el "generador" que tengamos preparado para cuando alguien registre el programa.

Obviamente tiene que ser así. El usuario proporciona un número de serie y una clave de usuario. El generador de números de serie lo que hace es conformar un número de serie dado en base a un número base y a una clave de usuario. El programa (no el generador) tiene que hacer lo mismo: tiene que poder generar el número de serie que se corresponde con el número base y la clave de usuario que este a su vez proporcione.

Y tiene que hacerlo porque de este modo podremos luego comparar: el número de serie proporcionado por el usuario y el número de serie que tiene realmente habría de ser.

Pues bien. He ahí el problema. Al generarse en nuestro programa el número de serie dentro de la función susomentada... ¡se está dejando en la memoria RAM el número de serie! Es decir que el resultado de la siguiente función:

Código Delphi [-]
function ObtenerNumeroSerie(numeroBase:
 integer; claveUsuario: string): string;
var
  A: Integer;
begin
  result := '';
  result := 'pepe';
  result := result + 'juan';
end;

... puede "verse" con el programa WinEx. Con este programa puede verse "pepe", por un lado, y luego "pepejuan", por otro... es decir, estamos viendo el "result" de la función...

Obviamente no todos los usuarios van a recurrir a un programa como WinEx. Pero a mí me lo ha comentado un usuario del programa que me traigo entre manos; me ha contado cómo lo ha hecho y yo he podido reproducir el sistema muy fácilmente... claro está que lo difícil era saber cómo hacerlo.

Ahora bien. Termino ya, disculpadme, por favor. ¿Qué puedo hacer? El número de serie "correcto" ha de generarse para poder compararlo con el que proporcione el usuario; ¿Cómo puedo evitar que el resultado de la función "ObtenerNumeroSerie" permanezca en memoria únicamente lo preciso? Es decir, sólo cuando se realiza la comprobación. Digamos que se realiza la comprobación y ¡zas!, el número correcto tiene que desaparecer de la memoria RAM...

Bueno. Si necesitáis más información procuraré proporcionarla. Disculpadme el pedazo de rollo que acabo de soltaros y muchas gracias a todos de antemano.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #2  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Bueno. Otra vez yo. Dándome cuenta de que lío las cosas demasiado cuando pueden simplificarse bastante. Olvídense si quieren de números de serie, generadores, registros, claves de usuario...

Simplemente inicien una nueva aplicación en Delphi. Sitúen un botón en el formulario principal. Escriban una función en la implementación del formulario principal:

Código Delphi [-]
function Resultado(): string;
begin
  Result := 'pepe';
end;

Y en el evento "Onclick" del botón añadido al formulario codifiquen lo siguiente:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
  s := Resultado();
  s := '';
end;

Compilen el programa... compílenlo... ¿Ya? Vale, vale.

Salgan de Delphi y ejecuten la aplicación para acto seguido hacer clic en el botón de marras. Ejecuten entonces el WinEx (vale la versión de evaluación) y visualizen la memoria RAM (ALT + F9) de la aplicación que acabamos de compilar y ejecutar.

Para terminar busquen "pepe" en el editor hexadecimal de WinEx. ¿Verdad que está "pepe" ahí? Ahora bien, ¿qué demonios hace "pepe" ahí? ¿Cómo puede quitarse a "pepe" del medio? Y que parezca un accidente, claro.

Gracias de antemano a todos.
__________________
David Esperalta
www.decsoftutils.com

Última edición por dec fecha: 27-03-2007 a las 13:10:39.
Responder Con Cita
  #3  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Una cosa más... no se les ocurra cambiar la función inmediatamente anterior por:

Código Delphi [-]
function Resultado(): string;
begin
  Result := 'pepe' + DateToStr(Time);
end;

Porque entonces si buscan a "pepe" le encontrarán una vez (al ejecutar el programa) y otra vez más cuando pulsen en el botón... y en esta última lo encontrarán en el pasado... "pepe30/12/1899"...

No hagan esto. ¡Porque se pueden volver tan locos como yo!

PD. El que no sabe es como el que no ve. Confucio
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #4  
Antiguo 27-03-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Caray, pues preguntando cómo defenderte de eso, acabas de dar un manual de como hacer eso.

Yo, pues no sé, pero ¿qué no puedes escribir en la misma variable otro valor para borra a pepe?

// Saludos
Responder Con Cita
  #5  
Antiguo 27-03-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Bien, en estos casos lo mejor es tener control sobre la memoria que se esta usando.
Código Delphi [-]
procedure Resultado(Str: PChar; L: Integer);
begin
  // Pues yo si que uso DateToStr ¿que pasa?
  StrLCopy(Str,PChar('Pepe'+DateToStr(Time)),L);
end;

function Comprobar(Str: String): Boolean;
var
  Buffer: PChar;
begin
  GetMem(Buffer,32);
  try
    Resultado(Buffer,31);
    Result:= StrComp(Buffer,PChar(Str)) = 0;
  finally
   //Borramos la memoria
    FillChar(Buffer^,32,#0);
    FreeMem(Buffer);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMEssage(BoolToStr(Comprobar('Hola')));
end;
Responder Con Cita
  #6  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Gracias Román por interesarte por el tema.

Bueno. Antes de nada voy a corregirme a mí mismo:

Código Delphi [-]
DateToStr(Time)

Eso retorna al paso a "pepe" porque no se hacen las cosas bien, como puede verse. En todo caso debe ser así o así:

Código Delphi [-]
DateToStr(Date)
TimeToStr(Time)

Pero, bueno. Es lo de menos... me disculpo porque me pongo quizás demasiado nervioso sin ton ni son y no me paro a mirar las cosas como debe ser...

Vamos al caso. Dices Román que podría dar otro valor a la variable para eliminar el anterior valor... pero el caso es que creo haberlo intentado y no funciona. Es decir.

Código Delphi [-]

const
  NUMERO_BASE = 123;

function Resultado(numeroBase, claveUsuario: string): string;
begin
  result := numeroBase * Length(claveUsuario);
end;

function CompruebaResultado(claveUsuario, numeroSerie: string): boolean;
begin
  result := ( numeroSerie = Resultado(NUMERO_BASE, claveUsuario) );
end;

A esto puede reducirse el caso. Como puede verse en la función "Resultado" se genera el valor que no debería quedarse en la memoria RAM... necesitamos ese valor para compararlo en la función "CompruebaResultado", pero, no debería permanecer en la memoria más tiempo que el preciso.

Y sin embargo aparece... pero he probado y no vale hacer algo así:

Código Delphi [-]
function CompruebaResultado(claveUsuario, numeroSerie: string): boolean;
var
  s: string;
begin
  s := Resultado(NUMERO_BASE, claveUsuario);

  result := ( numeroSerie =  s);

  s := '';
end;

No; El número de serie sigue apareciendo. Y parece ser que es porque donde deja su "huella" en la memoria RAM es en la propia función "Resultado". Pero claro, aquí si que obviamente no podemos hacer algo como esto:

Código Delphi [-]
function Resultado(numeroBase, claveUsuario: string): string;
begin
  result := numeroBase * Length(claveUsuario);
  result := ''; // No puede ser claro está
end;

Se me ocurre al hilo de escribir aquí que tal vez si en lugar de una función fuese un procedimiento que retornara el "número de serie" en un parámetro pasado por referencia... o sea:

Código Delphi [-]
procedure Resultado(numeroBase, claveUsuario: string; var numeroSerie: string);
begin
  numeroSerie := numeroBase * Length(claveUsuario);
end;

... Tal vez sí que podríamos luego hacer algo así:

Código Delphi [-]
function CompruebaResultado(claveUsuario, numeroSerie: string): boolean;
var
  s: string;
begin
  Resultado(NUMERO_BASE, claveUsuario, s);
  result := ( numeroSerie =  s);
  s := '';
end;

Tengo que probar a ver...
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #7  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Muchas gracias Seoane... pero, ¿estás tú seguro de que Pepe no aparece por ahí? ¡A mí no se me va de la memoria!

Edito: Sí que funciona como dices Seoane. Aparece Pepe cuando efectivamente uno quiere comprobar "Pepe", precisamente. Pero si uno trata con "Juan" (es decir, no "valida") entonces "Pepe" no aparece tal cual...

Tengo que tratar ahora de llevar el código al programa que digo, y veremos a ver, porque no termino de comprenderlo... Lo que ya no sé es si probar pasando como parámetro por referencia a Pepe... puesto que la solución que planteas parece más elegante, no sé.
__________________
David Esperalta
www.decsoftutils.com

Última edición por dec fecha: 27-03-2007 a las 13:45:27.
Responder Con Cita
  #8  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Lamento molestar otra vez... Seoane... he intentado implementar el código (y la idea... dentro de mis posibilidades) en el programa de marras y el asunto no ha funcionado: sigue viéndose en la memoria RAM lo que no debía verse.

Y entonces me he preguntado cómo es posible si he probado tu ejemplo y yo mismo he dicho que me había funcionado... pero lo he vuelto a probar y el asunto no funciona Seoane... y ahora no sé si es que no nos ponemos de acuerdo (sin duda por culpa mía) acerca de lo que hay que quitar y lo que no...

En tu ejemplo, en todo caso (se "compruebe" o no se "compruebe") que el usuario escribió "Pepe"... este sigue apareciendo en la memoria RAM... ¿tú cómo lo ves?

Gracias en todo caso.

PD. Es verdad Román que acaso he proporcionado información de cierta relevancia a alguien... pero no era mi intención: no le dí importancia en ese sentido. No sé si porque doy por supuesto que al final lo explicado no va a servir... si al cabo se consigue eliminar de la memoria RAM el valor de que tratamos.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #9  
Antiguo 27-03-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Si aparece no sera por culpa de la función "Comprobar" sino por culpa de la función "Resultado" que al manipular strings nos provoca el problema. Lo ideal es utilizar solo variables que podamos borrar, ya que delphi aunque libera la memoria que ocupan, no se preocupa de borrar lo que contienen.

Aquí el problema es como planteas la protección, comparar lo que entra el usuario con un valor fijo y devolver un boolean no es muy buen sistema de protección. Funciona, y para un usuario "normal" seria suficiente (1), pero si ya nos encontramos con un "listo" la cosa falla. Saltarse una protección de este tipo es tan fácil como parchear el programa para que la función "Comprobar" siempre devuelva TRUE. Así ya podemos llamar a la función mil veces en nuestro código que la protección ha quedado desactivada.

Pero supongamos que el listo no lo es tanto, y no sabe ensamblador, pero conoce el programa WinHex y prueba a "pescar" en la memoria la posible clave. Pues como la incluyamos como constante en nuestro exe ya estamos vendidos, es mas ni siquiera le haría falta leer la RAM, con solo leer el ejecutable la podría encontrar. Por eso la clave debe generarse durante la ejecución, y utilizarse durante todo el proceso (generación y comprobación) variables que luego podamos borrar. Y lo mas importante, que el listo no sepa ensamblador para que no nos desmonte todo usando lo del párrafo anterior

Si de verdad quieres proteger la aplicación (mas tarde o mas temprano caen todas) tendrías que irte a algo mas "profesional". Lo primero un antidebugger, para evitar que usen un debugger. Luego podemos encriptar parte del código del programa y utilizar como clave la clave del producto, de esta manera si la clave no es correcta no hay manera de obtener el código. Y por ultimo un buen rootkit para vacilarlos nosotros antes de que nos intenten vacilar ellos (Parece una broma, pero recordemos a Sony y alguno mas)

Como ves, si empiezas a preocuparte por lo que van a hacer los "listos" puedes terminar paranoico. Así que si verdaderamente es importante, una llave hardware y no se hable mas.

(1) Para mi también seria suficiente, con tantos programas OpenSource como hay, no pienso perder el tiempo buscando claves.
Responder Con Cita
  #10  
Antiguo 27-03-2007
[basti] basti is offline
Miembro Premium
 
Registrado: ago 2004
Posts: 388
Poder: 20
basti Va por buen camino
Hola, he visto este hilo y me parece interesante. Creo que tanto 'Pepe' como la fecha pueden aparecer en el volcado de memoria del programa de Seoane por dos razones, espero no equivocarme.

'Pepe' está escrito de manera estática en la función Resultado, por lo tanto no hay manera de quitarlo de la memoria. Esto no sería un problema para tu aplicación, ya que la clave del cliente no estaría escrita en el código de la aplicación.

El otro problema que veo es la pila del programa, cuando se hace la siguiente llamada:
Código Delphi [-]
  StrLCopy(Str,PChar('Pepe'+DateToStr(Time)),L);

El valor 'Pepe'+DateToStr(Time) se copia en la pila de llamadas de la aplicación, y permanecerá ahi hasta que otras llamadas sobreescriban estos datos en la pila.

Puedes comprobarlo de la manera siguiente:
En el código de Seoane haces una implementación de StrLCopy, algo así
Código Delphi [-]
Procedure StrLcopy(dest, org : PChar; len : Integer);
begin
  while org^ <> #0 do
  begin
    dest^ := org^;
    Inc(dest);
    Inc(org);
  end;
  dest^ := #0;
end;
de manera que uses esta función en vez de la original de delphi. Pones un punto de ruptura dentro de la función, vas a la ventana "Call Stack". Ahí verás el valor tanto de 'Pepe' como la fecha.

La solución, creo que podría ser una llamada a una función recursiva, justo después de la llamada a StrLCopy, para que sobreescriba la pila. La función debe ser llamada las veces que hagan falta para borrar los datos de la pila. Algo así:
Código Delphi [-]
procedure Resultado(Str: PChar; L: Integer);
  procedure VamosAContarAlReves(n : integer);
  begin
    if n > 0 then
      VamosAContalAlReves(n - 1);
  end;
begin
  // Pues yo si que uso DateToStr ¿que pasa?
  StrLCopy(Str,PChar('Pepe'+DateToStr(Time)),L);
  VamosAContarAlReves(100);
end;

Última edición por basti fecha: 27-03-2007 a las 15:02:22.
Responder Con Cita
  #11  
Antiguo 27-03-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Ingenioso método de borrar la pila Basti

Entonces ya tenemos los 3 pasos: no usar constantes, borrar las variables y borrar la pila.
Responder Con Cita
  #12  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Gracias a todos, de verdad. Estaba a punto de escribir esto porque me parecía haber encontrado una posible solución, pero, me quedo corto al lado vuestro.

Como dices Seoane el problema está en manipular variables en la función "Resultado". Si no lo hacemos, es decir, si "calculamos" el resultado ya dentro de la función "StrLCopy" entonces desaparece el problema. Es decir, que puedo decir que el problema está resuelto gracias a vosotros. Acabo de comprobarlo y volverlo a comprobar.

Dices Seoane que dejar el Serial como constante no es buena idea... pero no se hace así. Lo que se tiene como constante es un número "base". Con este número base y la clave del usuario se genera un "Serial", pero esto se hace con cierto algoritmo (luego más sobre esto) que no puede conocerse así como así.

Ahora bien. Parece (y digo parece porque he hecho pruebas pero tengo que hacer alguna más aún) que conseguimos hacer desaparecer el "Serial" correcto de la memoria RAM. Ahora lo que me deja perplejo es el tema de la pila... ¿ya no basta con la memoria RAM? ¿Acaso puede buscarse el "Serial" en la pila incluso cuando digo que ya no aparece en la memoria RAM?

Definitivamente me queda mucho más por aprender de lo que aprenderé nunca.

Para quien esté interesado, estoy utilizando una clase para todo esto que está basada en el componente "JvSerialMaker" de la Jedi Library. Evidentemente ya sabéis que este componente "deja" en la memoria RAM el número de serie que genera y puede comprobar...

En fin voy a asegurarme con más pruebas de que el número de serie no aparece en la memoria RAM y luego acaso me ponga con el tema de la pila que apunta el compañero basti (gracias basti). Pero estoy de acuerdo con Seoane... probablemente estas cosas habría que tomarlas bastante más en serio de lo que estoy dispuesto a hacer para evitar que alguien "piratee" un programa como se empeñe en hacerlo...
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #13  
Antiguo 27-03-2007
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.275
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por dec
Una de ellas comprueba que el número de serie proporcionado por el usuario resulta válido para la clave de usuario que también se especifique. Esta función no me parece tan crítica como la siguiente: la función que se encarga de obtener un número de serie válido realmente para el usuario, precisamente, para compararlo con el que el usuario proporciona.
Bueno, no es mi intención "desmontar" la teoría inicial, pero aquí el fallo está en el planteamiento.
De todas formas el problema de la memoria RAM es interesante también.

Aunque cada uno programa los sistema de registro como desea, normalmente los programas no suelen utilizar el sistema mencionado, porque es muy sencillo detectar el número correcto utilizando un Debugger. No hace falta "rebuscar" en la memoria RAM, basta con ejecutarlas instrucciones del programa y revisando los registros y la pila.

Por ejemplo, "debuggando"(¡qué mal suean esto!) el programa mencionado por dec, con OllyDBG podemos llegar fácilmente (y eso que yo no soy experto en estos temas, pero con un par de minutos me ha bastado...) a este punto:
imagen

En la parte izquierda se ven las instrucciones y en la derecha la pila y los registros.
Normalmente en estos casos (crackendo un programa, cosa que yo nunca he hecho...) se busca un punto de partida (1); Si este es acertado, a partir de ahí se ejecutan las instrucciones hasta llegar a los procedimientos donde se evalua y calcula el número de serie.

(1) Para comenzar se buscan los formularios de Registro, prodecimientos con nombres sospechosos (TestID, Register, RegisterOK,...), Strings "sospechosos" como "El número de registro es incorrecto", "El número de serie no es válido",...
¿Por qué comento esto? Porque sabiéndolo, alguien que diseñe un sistema de protección debe tener en cuenta:
(a) Los procedimientos que tienen que ver con el registro y números de serie nunca deben llamarse: Registro, CalcularSN, TestRegistro,... ni cualquier otro nombre que de pistas sobre olo que están haciendo.
(b) Los mensajes de error relativos al registro deben estar codificados y nunca directamente en el código; La codificación no importa, basta un XOR, o cambiar una letra por otra, lo importante es que si revisas la memoria no aparezcan directamente.
(c) Algunas cosillas más....

Si "cuesta" encontrar en punto de entrada para comenzar a "debuggar" las cosas se hacen un poco más complicadas.

En cuanto al número de registro o números de serie, la premisa es que en ningun momento el número de serie debe estar completo en memoria. En una variable o en una cadena ni debe ser devuelto por una función.

Lo lógico es hacerlo "a partes" y una vez particionado no hacer comparaciones directas.
Un ejemplo sencillo es no hacer esto:

Código Delphi [-]
// 1234 calculado previamente...
if (SN = '1234') then
...

Y en su lugar hacer esto:

Código Delphi [-]
j := Ord('Q') - Ord('N');
// 1234 calculado previamente...
if (SN[1] = '1') and (SN[2] = (4 DIV 2)) and (SN[3] = j) and ... then
...

Comparar las partes desordenadas,....
Hay infinidad de técnicas, que van complicando el tema más... Pero algunas son básicas como las comentadas antes.
Sobre todo ¡Nunca debe estar el SN correcto almacenado de forma contigua en memoria!

Porque si no pasan cosas como esta. LLegado al punto de la comparación te puedes encontrar el nombre del registro, el SN incorrecto y el SN correcto con el que se está comparando...

AÑADO: En esta última imagen tampoco es muy afortunado el nombre del procedimiento ChessRk (contando que el programa se llama Chess); ¿Qué os sugiere ChessRk, sabiendo que el programa está en inglés?
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.

Última edición por Neftali [Germán.Estévez] fecha: 27-03-2007 a las 15:41:24.
Responder Con Cita
  #14  
Antiguo 27-03-2007
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.275
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Veo que habéis avanzado en el tema mientras yo escribía, o mejor dicho, me enrollaba...

Cita:
Empezado por dec
Ahora lo que me deja perplejo es el tema de la pila... ¿ya no basta con la memoria RAM? ¿Acaso puede buscarse el "Serial" en la pila incluso cuando digo que ya no aparece en la memoria RAM?
Como he comentado más arriba, no debería estar ni en la pila ni en los registros; Y eso significa que no se puede asignar a una variable, que no se puede pasar como parámetro y no debe ser devuelto por ninguna función (hablamos del serial correcto completo).
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #15  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Muchas gracias Neftalí. Gracias a todos.

Yo me doy cuenta de lo poco que sé de todo esto... ¡me pierdo enseguida! Y como me pierda no me encuentro. ¡¿Pues no resulta ahora que tras haber comprobado con estos ojos que se han de comer la tierra, me pongo a implementar el asunto en el programa de marras y todo sigue igual?!

Igual. El número de serie correcto aparece en memoria. Pero ahora el número no está en ninguna variable como antes. Yo no sé si estoy comprendiendo lo que hablamos, porque, ahora mismo el número de serie "se calcula" dentro de la propia función "StrLCopy"...

Es decir, que pasa a la variable "destino" de la función "StrLCopy", directamente, variable que luego es destruída tal como Seoane ha explicado...

No sé. ¿Acaso me queda entonces por hacer lo que apunta el compañero basti? ¿No basta entonces con liberar dicha variable (única que llega a contener el número de serie correcto)?

No sé... voy a probar a ver...

Y en todo caso pelear con lo que menciona Neftalí: pero me temo que voy a dar unos cuantos palos de ciego... ¡Ay!
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #16  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Yo de nuevo.

Oyes Neftalí... ¿sabes que lo de comprobar el número de serie por partes puede acaso ser una solución? Pero no se me ocurre cómo... de momento... y puede que nunca.

El caso es que, efectivamente, ni siquiera quitando del medio la función "Resultado", es decir, comparando el número de serie del usuario con la cadena resultante del cálculo del número de serie... es decir, comparando una variable con "un valor" (no una variable) que se conforma en el momento... aun así el número de serie, o sea el "valor" queda en la memoria...

Así que como no sea partiendo el número de serie, de modo que quede... pero irreconocible, pudiera ser una buena opción. Ahora toca averiguar cómo demonios hago esto, porque no se me ocurre... no sé...
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #17  
Antiguo 27-03-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Joroba... ahora me doy cuenta de que no he terminado de probar el asunto del modo que lo planteaba el compañero basti, es decir, lo hize como Seoane explicó, pero, no llegué a "actualizar" a lo que basti comentaba... y ahora no sé si hacerlo, puesto, que, llegando a estar el número de serie correcto en memoria incluso aunque no esté en una variable... ¿no invalida esto el método propuesto por el compañero basti?

Quiero decir, si tras intentar del mejor modo que he sabido lo que propone Seoane llego a la conclusión de que, efectivamente, el número de serie sigue permaneciendo en memoria (si estoy metiendo la pata me corregís por favor), puesto que en algún punto del programa ha de componerse para poderlo comparar con el que propone el usuario...

Parece que de todas formas la posible solución pasa (sin ir más allá...) por lo que dice Neftalí (¿o me equivoco?), es decir, no llegar nunca a formar el número de serie completo, sino hacerlo por partes... para que aunque aparezcan estas partes sea complicado reunirlas a todas y conocer así el número de serie.

Ahora bien, quedaría entonces cómo comparar el serial del usuario (por partes) con el serial correcto que hemos de generar (también por partes...)...

¡jo, jo, jo, jo!
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #18  
Antiguo 27-03-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Y si cambias el planteamiento. Hasta ahora estas comprobando lo que inserta el usuario, tal cual, con un numero "generado". Pues bien yo te propongo lo siguiente: tomar el valor que introduce el usuario y calcular su hash (md5 por ejemplo), entonces comparamos su hash con el que tenemos guardado, en una constante porque no nos importa que lo vean en la RAM. Y no nos importa porque aunque alguien conozca el hash nadie puede saber que numero tiene que introducir para obtener ese hash. Sencillo y efectivo, esta es la magia del Hash
Responder Con Cita
  #19  
Antiguo 27-03-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Y para continuar mi mensaje anterior un poco de código:
Código Delphi [-]
uses Hashes;

function Comprobar(Str: String): Boolean;
begin
  Result:= AnsiSameText(StrCheckSum(Str),'e885d567f57b0f87333c25f7f3a1e381');
end;

// Por ejemplo
ShowMessage(BoolToStr(Comprobar(Edit1.text),TRUE)); // Pepe es la clave
La clave correcta en este caso es "Pepe" pero como ves no aparece por ninguna parte, ni en el código, ni en memoria, ni en ningún sitio. Solo aparece su hash, pero a partir de su hash no podemos obtener la clave.

PD: La unit hashes se puede encontrar aquí
http://www.clubdelphi.com/foros/show...22&postcount=4
Responder Con Cita
  #20  
Antiguo 27-03-2007
Avatar de ArdiIIa
[ArdiIIa] ArdiIIa is offline
Miembro Premium
 
Registrado: nov 2003
Ubicación: Valencia city
Posts: 1.481
Poder: 22
ArdiIIa Va por buen camino
Seoane, como siempre, es brillante la visión de la jugada que aportas....

He estado leyendo el hilo y no me ha dejado hacer la digestión en condiciones.

Estuve pensando sobre el tema en un planteamiento relativamente parecido.

La idea en sí, es tener un valor previo codificado... Por el sistema que fuera. En este caso mis pocas neuronas pensaron en un algoritmo de movimientos o/y complementos de bits hasta hallar una serie mas o menos complicada, y con la clave introducida, realizar el mismo movimiento y posterior comparación. En definitiva, la codificación por el método que sea. Obviamente la serie codificada e885d567f57b0f87333c25f7f3a1e381 tendría que ser previamente tratada antes de ser introducida en el propio código del programa.
Creo que mas o menos el planteamiento tuyo pero obviamente mas sencillo y versátil.

Hace años y basándome en esto mismo que digo, hice un pequeño código en ensamblador, pero realmente esta codificación afectaba al propio código del programa, de tal manera que dejaba dentro de la rutina espacios de memoria a cero (NOP), la rutina se auto-descodificaba y se movía a esa porción de memória para seguidamente dar un salto al nuevo código...
__________________
Un poco de tu generosidad puede salvar la vida a un niño. ASÍ DE SENCILLO
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
eliminar datos con dbgrid UREÑA Conexión con bases de datos 20 30-03-2007 23:41:32
Eliminar Datos eficientemente k_rito Conexión con bases de datos 5 27-11-2006 00:44:45
Cómo obtener ciertos datos de los archivos ejecutables y librerías StartKill Varios 1 14-08-2006 23:10:01
Eliminar del memoria los querys Aura OOP 4 01-04-2004 17:40:40
Eliminar datos de una tabla DBF vicvil Tablas planas 4 16-05-2003 21:17:46


La franja horaria es GMT +2. Ahora son las 22:29:49.


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
Copyright 1996-2007 Club Delphi