• [Delphi] Creacion de un Server Builder con recursos

 #466146  por Doddy
 09 Mar 2015, 18:53
[Titulo] : Creacion de un Server Builder con recursos
[Lenguaje] : Delphi
[Autor] : Doddy Hackman

[Temario]

-- =================--------

0x01 : Introduccion
0x02 : Creacion del builder
0x03 : Creacion del stub
0x04 : Probando el programa
0x05 : Builder Tools

-- =================--------

0x01 : Introduccion

En este manual les voy a enseñar como hacer un Server Builder en Delphi usando recursos , en el manual anteior les enseñe como hacerlo mediante EOF , algo que no era muy seguro porque los datos estaban en texto plano y se podian leer facilmente , mediante recursos es diferente y para asegurarlo vamos a usar XOR para eso.

Empecemos ...

0x02 : Creacion del builder

Primero vamos hacer el builder , para eso vamos a "File->New->VCL Forms Application" como lo hice en la imagen :



Ahora creamos dos edit y boton con el texto de "Make Server" como en la siguiente imagen :



Despues deben cambiar el titulo del formulario a "Builder" y cambiarle el nombre por defecto que tienen los edits de la siguiente forma :

Edit1 -> ip
Edit2 -> port

Una vez hecho , hacemos doble click en el boton y agregamos el siguiente codigo :
procedure TForm1.Button1Click(Sender: TObject);
var
  archivo: string; // Declaramos la variable "archivo" como string
  datos: string; // Declaramos la variable "datos" como string
  clave: integer; // Declaramos la variable "clave" como integer
begin
  archivo := 'stubnow.exe';
  // Establecemos la variable "archivo" como el nombre del ejecutable
  // que vamos abrir
  datos := '[ip]' + ip.Text + '[ip]' + '[port]' + port.Text + '[port]';
  // Establecemos los datos que contiene la IP y el puerto separados por etiquetas
  // y los guardamos en la variable "datos"
  clave := 123; // Establecemos la variable "clave" como "123"
  escribir_recurso(archivo, datos, clave);
  // Escribimos el recurso usando la funcion
  // "escribir_recurso" usando como argumentos las variables que acabamos de establecer
  ShowMessage('Done'); // Mostramos un mensaje en pantalla
end;
Fuera del codigo de la funcion "click" del boton agregamos el codigo de estas dos funciones :
function xor_now(texto: string; clave: integer): string;
// Funcion xor_now con el argumento
// del texto a crifrar y la clave a usar

var
  numero: integer; // Declaramos la variable "numero" como entero
  contenido: string; // Declaramos la variable "contenido" como string
begin
  contenido := ''; // Vaciamos la variable contenido
  for numero := 1 to Length(texto) do // Realizamos un for del "1"
  // a la longitud de la variable texto
  begin
    contenido := contenido + Char(integer(texto[numero]) xor clave);
    // Realizamos el cifrado xor
  end;
  Result := contenido; // Devolvemos como resultado la variable "contenido"
end;

function escribir_recurso(ruta: string; datos: string; clave: integer): bool;
var
  escribiendo: THandle; // Declaramos la variable "escribiendo" como THandle
begin
  datos := xor_now('-0x646F646479206861636B6D616E-' + datos +
    '-0x646F646479206861636B6D616E-', clave);
  // Ciframos los datos usando la funcion xor_now
  // Los parametros que usamos en la funcion xor_now son la variable "datos" como el texto
  // a cifrar , los "datos" estan entre dos delimitadores para facilitar su busqueda y
  // tambien usamos la variable "clave" como key en el cifrado xor
  escribiendo := BeginUpdateResource(pchar(ruta), False);
  // Empezamos el inicio de de la creacion
  // del recurso usando la variable "ruta"
  UpdateResource(escribiendo, MakeIntResource(10), 'CONFIGURATION', 0,
    pchar(datos), (Length(datos) + 1) * SizeOf(datos[1]));
  // Escribimos el recurso usando
  // la variable "datos" como el contenido del recurso y como nombre del recurso usamos
  // "CONFIGURATION"
  EndUpdateResource(escribiendo, False); // Terminamos de crear el recurso
  Result := True; // Devolvemos True como resultado de la funcion
end;
Les deberia quedar algo asi :



Con eso ya estaria el builder entonces guardamos el proyecto como "builder_now" o como quieran para terminar el builder.

0x03 : Creacion del stub

Ahora vamos a codear el Stub para eso vamos a "File->New->VCL Forms Application" como lo hice en la imagen :



La idea es buscar el recurso en el ejecutable mismo , entonces para eso vamos a crear dos edits y un boton con el texto de "Get Values".

Despues deben poner como titulo del formulario "Stub" y cambiar los names de los edits de la siguiente forma :

Edit1 -> ip
Edit2 -> port

El formulario les deberia quedar algo asi :



Ahora hacemos doble click en el boton y ponemos el siguiente codigo :
procedure TForm1.Button1Click(Sender: TObject);
var
  clave: integer; // Declaramos la variable "clave" como integer
  datos: string; // Declaramos la variable "datos" como string
  ip_found: string; // Declaramos la variable "ip_found" como string
  port_found: string; // Declaramos la variable "port_found" como string
begin
  clave := 123; // Establecemos la variable "clave" como 123
  datos := leer_recurso(clave); // Leemos el recurso usando el key que esta
  // en la variable clave y guardamos los datos en la variable "datos"
  ip_found := regex(datos, '[ip]', '[ip]');
  // Usamos la funcion regex() para buscar
  // la ip y la guardamos en la variable "ip_found"
  port_found := regex(datos, '[port]', '[port]');
  // Usamos la funcion regex() para
  // buscar el puerto y lo guardamos en la variable "port_found"
  ip.text := ip_found; // Mostramos en el edit "ip" la IP
  port.text := port_found; // Mostramos en el edit "port" el puerto
  ShowMessage('Loaded'); // Mostramos en pantalla un mensaje
end;
Despues ponemos las siguientes funciones fuera del codigo del boton :
function regex(text: string; deaca: string; hastaaca: string): string;
begin
  Delete(text, 1, AnsiPos(deaca, text) + Length(deaca) - 1);
  SetLength(text, AnsiPos(hastaaca, text) - 1);
  Result := text;
end;

function xor_now(texto: string; clave: integer): string;
// Funcion xor_now con el argumento
// del texto a crifrar y la clave a usar

var
  numero: integer; // Declaramos la variable "numero" como entero
  contenido: string; // Declaramos la variable "contenido" como string
begin
  contenido := ''; // Vaciamos la variable contenido
  for numero := 1 to Length(texto) do // Realizamos un for del "1"
  // a la longitud de la variable texto
  begin
    contenido := contenido + Char(integer(texto[numero]) xor clave);
    // Realizamos el cifrado xor
  end;
  Result := contenido; // Devolvemos como resultado la variable contenido
end;

function leyendo_recurso: string;
var
  leyendo1: HRSRC; // Establecemos la variable "leyendo1" como HRSRC
  leyendo2: DWORD; // Establecemos la variable "leyendo2" como DWORD
  leyendo3: THandle; // Establecemos la variable "leyendo3" como THandle
  leyendo4: pointer; // Establecemos la variable "leyendo4" como Pointer
begin
  leyendo1 := FindResource(hInstance, 'CONFIGURATION', RT_RCDATA);
  // Buscamos el recurso
  // "CONFIGURATION"
  leyendo2 := SizeofResource(hInstance, leyendo1);
  // Calculamos la tamaño del recurso
  leyendo3 := LoadResource(hInstance, leyendo1); // Cargamos el recurso
  leyendo4 := LockResource(leyendo3);
  // Bloqueamos el recurso para poder leerlo despues
  if leyendo4 <> nil then // Si "leyendo4" no esta null ...
  begin
    SetLength(Result, leyendo2 - 1); // Cambiamos la longitud de Result
    CopyMemory(@Result[1], leyendo4, leyendo2);
    // Copiamos los datos al resultado de la funcion
    FreeResource(leyendo3); // Liberamos el recurso
  end;
end;

function leer_recurso(clave: integer): string;
var
  datos: string; // Declaramos la variable "datos" como string
begin
  datos := xor_now(leyendo_recurso, clave);
  // Realizamos el cifrado xor con los datos que usamos
  // como argumentos de la funcion leer_recurso()
  datos := regex(datos, '-0x646F646479206861636B6D616E-',
    '-0x646F646479206861636B6D616E-');
  // Usamos la funcion regex() para cortar los delimitadores
  // y encontrar asi los datos del recurso para despues guardar el
  // resultado en la variable "datos"
  Result := datos;
  // Devolvemos como resultado lo que contiene la variable "datos"
end;
El codigo les deberia quedar asi :



Guardan el proyecto con el nombre que quieran y con eso ya estaria listo el stub.

0x04 : Probando el programa

Para probarlo cargamos el builder y llenamos los campos de IP y Puerto como quieran , un ejemplo de como los complete yo seria :



Despues presionan el boton "Make Server" y listo.

Ahora cargamos el stub y le damos al boton "Get Values" , deberian ver como resultado algo como esto :



Si no ven algo como en la imagen es porque hicieron algo mal en el codigo.

0x05 : Builder Tools

Como regalo les dejo esta Unit que hice en Delphi sobre como hacer un Builder , contiene funciones para EOF y Recursos , en los dos casos uso XOR para encriptar los datos , tambien viene con ejemplos de uso.

Solo deben agregar "builder_tools" en el parte de "uses" del codigo y listo , podran usar las funciones.

El codigo :
// Unit : Builder Tools
// Version : 0.2
// (C) Doddy Hackman 2015
// Credits : Resources based in http://www.hackforums.net/showthread.php?tid=1422700
// Examples :
// escribir_eof('stub.exe','-delimitador-','-delimitador-','test',123);
// leer_eof('stub.exe','-delimitador-','-delimitador-',123);
// escribir_recurso('stub.exe','test',123);
// leer_recurso(123);

unit builder_tools;

interface

uses SysUtils, Windows;

function leer_eof(ruta, delimitador1, delimitador2: string;
  clave: integer): string;
function escribir_eof(ruta, delimitador1, delimitador2, texto: string;
  clave: integer): bool;
function escribir_recurso(ruta: string; datos: string; clave: integer): bool;
function leyendo_recurso: string;
function leer_recurso(clave: integer): string;
function xor_now(texto: string; clave: integer): string;
function regex(text: string; deaca: string; hastaaca: string): string;

implementation

function xor_now(texto: string; clave: integer): string;
var
  numero: integer;
  contenido: string;
begin
  contenido := '';
  for numero := 1 to Length(texto) do
  begin
    contenido := contenido + Char(integer(texto[numero]) xor clave);
  end;
  Result := contenido;
end;

function regex(text: string; deaca: string; hastaaca: string): string;
begin
  Delete(text, 1, AnsiPos(deaca, text) + Length(deaca) - 1);
  SetLength(text, AnsiPos(hastaaca, text) - 1);
  Result := text;
end;

function leer_eof(ruta, delimitador1, delimitador2: string;
  clave: integer): string;
var
  ob: THandle;
  code: Array [0 .. 9999 + 1] of Char;
  nose: DWORD;
  resultado: string;

begin

  ob := INVALID_HANDLE_VALUE;
  code := '';

  ob := CreateFile(pchar(ruta), GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, 0, 0);
  if (ob <> INVALID_HANDLE_VALUE) then
  begin
    SetFilePointer(ob, -9999, nil, FILE_END);
    ReadFile(ob, code, 9999, nose, nil);
    CloseHandle(ob);
  end;

  resultado := regex(code, delimitador1, delimitador2);
  resultado := xor_now(resultado, clave);
  Result := resultado;

end;

function escribir_eof(ruta, delimitador1, delimitador2, texto: string;
  clave: integer): bool;
var
  linea: string;
  aca: THandle;
  code: Array [0 .. 9999 + 1] of Char;
  nose: DWORD;
  marca_uno: string;
  marca_dos: string;

begin

  aca := INVALID_HANDLE_VALUE;
  nose := 0;

  begin
    linea := delimitador1 + xor_now(texto, clave) + delimitador2;
    StrCopy(code, pchar(linea));
    aca := CreateFile(pchar(ruta), GENERIC_WRITE, FILE_SHARE_READ, nil,
      OPEN_EXISTING, 0, 0);
    if (aca <> INVALID_HANDLE_VALUE) then
    begin
      SetFilePointer(aca, 0, nil, FILE_END);
      WriteFile(aca, code, 9999, nose, nil);
      CloseHandle(aca);
      Result := True;
    end
    else
    begin
      Result := False;
    end;
  end;
end;

function escribir_recurso(ruta: string; datos: string; clave: integer): bool;
var
  escribiendo: THandle;
begin
  datos := xor_now('-0x646F646479206861636B6D616E-' + datos +
    '-0x646F646479206861636B6D616E-', clave);
  escribiendo := BeginUpdateResource(pchar(ruta), False);
  UpdateResource(escribiendo, MakeIntResource(10), 'CONFIGURATION', 0,
    pchar(datos), (Length(datos) + 1) * SizeOf(datos[1]));
  EndUpdateResource(escribiendo, False);
  Result := True;
end;

function leyendo_recurso: string;
var
  leyendo1: HRSRC;
  leyendo2: DWORD;
  leyendo3: THandle;
  leyendo4: pointer;
begin
  leyendo1 := FindResource(hInstance, 'CONFIGURATION', RT_RCDATA);
  leyendo2 := SizeofResource(hInstance, leyendo1);
  leyendo3 := LoadResource(hInstance, leyendo1);
  leyendo4 := LockResource(leyendo3);
  if leyendo4 <> nil then
  begin
    SetLength(Result, leyendo2 - 1);
    CopyMemory(@Result[1], leyendo4, leyendo2);
    FreeResource(leyendo3);
  end;
end;

function leer_recurso(clave: integer): string;
var
  datos: string;
begin
  datos := xor_now(leyendo_recurso, clave);
  datos := regex(datos, '-0x646F646479206861636B6D616E-',
    '-0x646F646479206861636B6D616E-');
  Result := datos;
end;

end.

// The End ?
Eso seria todo.

--========--
The End ?
--========--

[ Debe registrarse para ver este enlace ].

Version en VideoTutorial :

 #466151  por comand
 09 Mar 2015, 20:35
Excelente tutoría Doddy, muy bien explicado y fácil comprensión. Gracias
 #468410  por joselin
 09 Abr 2015, 06:52
mucha dedicacion y bien comentado el codigo
se nota que le pones esfuerzo
gracias por compartir.

pregunta :a parte de los recursos que otro metodo puede usarse para
agregar datos a un exe, me gustaria aprender otro metodo
ya que siempre uso solo este de los recursos .
saludos.
 #478439  por Insidious
 27 Sep 2015, 14:37
this good method but maybe there is a problem. If your values or value be null not work. Because read from resource and in order. Just I'm guessing. maybe working i don't now. thanks for share.
 #478868  por Doddy
 05 Oct 2015, 02:13
Insidious escribió:this good method but maybe there is a problem. If your values or value be null not work. Because read from resource and in order. Just I'm guessing. maybe working i don't now. thanks for share.
Ese problema no sucede en mis nuevos programas , simplemente checkeo que los valores a usar en la clase builder_tools sean siempre correctos y no esten vacios.

Igual gracias por comentar.