#GEDZAC Mitosis eZine Issue 4
#MITOSIS ARTICLE#
#Comprimiendo en ZIP y en RAR
#Autor: Khronos [GEDZAC] <khronos[at]gedzac[dot]com>

#Incluye codigos fuente

Para el siguiente artículo utilizaré la clase TThread de la unidad Classes.pas, el código va a ir en verde y los comentarios en azul... Empezemos planteando la situación: Tenemos un gusano el cual queremos que se extienda por correo electrónico o por el propio Messenger. No podemos enviar el ejecutable porque nos lo catalogan como malware, para comprimirlo utilizaremos el propio WinRar y WinZip, en este artículo aprenderás a detectar si están instalados o como usar sus parámetros.

Es recomendable comprimirlo usando el WinRar porque su algoritmo de compresión es más complejo que el del zip y no todos los antivirus con capaces de explorar archivos rar. Vamos a crear 3 unidades: RunAppModule.pas, RarModule.pas y ZipModule.pas..

Source | Delphi | RunAppModule.pas
unit RunAppModule.pas;
interface
uses Classes, ShellApi, Windows;
type
TRunAppModule = class(TThread)
private
procedure StartApp(FileName, Params: string; Visible: boolean);
public
constructor Create(FileName, Params: string; Visible: boolean);
end;
implementation
constructor TRunAppModule.Create(FileName, Params: string; Visible: boolean);
begin
inherited Create( True);
FreeOnTerminate:= True;
StartApp(FileName, Params, Visible);
end;
procedure TRunAppModule.StartApp(FileName, Params: string; Visible: boolean);
var
Info: TShellExecuteInfo;
pInfo: PShellExecuteInfo;
exitCode: DWORD;
begin
pInfo:= @Info;
with Info do
begin
cbSize:= SizeOf(Info);
fMask:= SEE_MASK_NOCLOSEPROCESS;
lpVerb:= nil;
lpFile:= pchar(FileName);
lpParameters:= Pchar(params);
lpDirectory:= nil;
case Integer(Visible) of
0: nShow:= SW_SHOWNORMAL;
1: nShow:= SW_HIDE;
end;
hInstApp:=0;
end;
ShellExecuteEx(pInfo);
repeat
ExitCode:= WaitForSingleObject(Info.hProcess, 500);
until (ExitCode <> WAIT_TIMEOUT);
end;
end.

Explicación: ¿Para que vamos a usar este thread? Pues es bastante simple, la función clave es WaitForSingleObject. Con esta función conseguimos saber cuando terminó la aplicación que acabamos de ejecutar, esto es de gran utilidad cuando ejecutemos Winzip bajo la línea de comandos ya que solo puede haber una única instancia de este proceso..

Source | Delphi | RunAppModule.pas
RarModule.pas
unit RarModule.pas
interface
Uses Classes, SysUtils, Registry, Windows, RupAppModule;
type
TRarModule = class(TThread)
private
FRarFileName: string;
FRarInstalled: boolean;
procedure CheckWinRarInstalled;
public
constructor Create; reintroduce;
procedure CreateRarFile(RarDest, archivo: string);
procedure UpdateRarFile(Dest, archivo: string);
published
property RarInstalled: boolean read FRarInstalled;
property RarFileName: string read FRarFileName;
end;
 
implementation
 
procedure TRarModule.UpdateRarFile(Dest, archivo: string);
var
cmd: string;
begin
If FRarInstalled = false then Exit;
If FileExists(Archivo) = false then Exit;
cmd:= ' u ' + Dest + ' ' + archivo;
TRunAppModule.Create(FRarFileName, cmd, false);
end;
 
procedure TRarModule.CreateRarFile(RarDest, archivo: string);
var
cmd: string;
begin
If FRarInstalled = false then Exit;
If FileExists(Archivo) = false then Exit;
cmd:= ' a ' + RarDest + ' ' + archivo;
TRunAppModule.Create(FRarFileName, cmd, false);
end;
 
procedure TRarModule.CheckWinRarInstalled;
var
Reg: TRegistry;
begin
FRarFileName:= EmptyStr;
Reg:= TRegistry.Create;
Reg.RootKey:= HKEY_LOCAL_MACHINE;
Reg.OpenKey('\Software\Microsoft\Windows\CurrentVersion\Uninstall\WinRar archiver', false);
FRarFileName:= Reg.ReadString('UninstallString');
FRarFileName:= FRarFileName + 'rar.exe';
If FileExists(FRarFileName) = false then begin
FRarInstalled:= false;
FRarFileName:= EmptyStr;
else
FRarInstalled:= true;
end;
 
constructor TRarModule.Create;
begin
inherited Create(True);
FreeOnTerminate:= true;
CheckWinRarInstalled;
end;
end.

Explicación: Al crear la clase TRarModule comprueba si está instalado winrar. Si está instalado podemos llamar a los procedimiento CreateRarFile para crear un archivo rar con un archivo dentro y al procedimiento UpdateRarFile para añadir un archivo a un fichero rar. No tiene la mayor complicación

Source | Delphi | RunAppModule.pas
unit RunAppModule.pas;
interface
uses Classes, ShellApi, Windows;
type
TRunAppModule = class(TThread)
private
procedure StartApp(FileName, Params: string; Visible: boolean);
public
constructor Create(FileName, Params: string; Visible: boolean);
end;
implementation
constructor TRunAppModule.Create(FileName, Params: string; Visible: boolean);
begin
inherited Create( True);
FreeOnTerminate:= True;
StartApp(FileName, Params, Visible);
end;
procedure TRunAppModule.StartApp(FileName, Params: string; Visible: boolean);
var
Info: TShellExecuteInfo;
pInfo: PShellExecuteInfo;
exitCode: DWORD;
begin
pInfo:= @Info;
with Info do
begin
cbSize:= SizeOf(Info);
fMask:= SEE_MASK_NOCLOSEPROCESS;
lpVerb:= nil;
lpFile:= pchar(FileName);
lpParameters:= Pchar(params);
lpDirectory:= nil;
case Integer(Visible) of
0: nShow:= SW_SHOWNORMAL;
1: nShow:= SW_HIDE;
end;
hInstApp:=0;
end;
ShellExecuteEx(pInfo);
repeat
ExitCode:= WaitForSingleObject(Info.hProcess, 500);
until (ExitCode <> WAIT_TIMEOUT);
end;
end.

Explicación: ¿Para que vamos a usar este thread? Pues es bastante simple, la función clave es WaitForSingleObject. Con esta función conseguimos saber cuando terminó la aplicación que acabamos de ejecutar, esto es de gran utilidad cuando ejecutemos Winzip bajo la línea de comandos ya que solo puede haber una única instancia de este proceso..

Source | Delphi | ZipModule.pas
unit ZipModule.pas
interface
uses Classes, Registry, Windows, SysUtils, RunAppModule;
type
TZipModule = class(TThread)
private
FZipFileName: string;
FZipInstalled: boolean;
procedure CheckWinZipInstalled;
public
constructor Create; reintroduce;
procedure CreateZipFile(ZipDest, archivo: string);
procedure UpdateZipFile(Dest, archivo: string);
published
property ZipInstalled: boolean read FZipInstalled;
property ZipFileName: boolean read FZipFileName;
end;
 
implementation
 
constructor TZipModule.Create;
begin
inherited Create(True);
FreeOnTerminate:= true;
CheckWinZipInstalled;
end;
 
procedure TZipModule.CheckWinZipInstalled;
var
Reg: TRegistry;
begin
FZipFileName: EmptyStr;
Reg:= TRegistry.Create;
Reg.RootKey:= HKEY_LOCAL_MACHINE;
Reg.OpenKey('\Software\Microsoft\Windows\CurrentVersion\Uninstall\Winzip', false);
FZipFileName:= Reg.ReadString('InstallLocation');
FZipFileName:= ExtractFileName(FZipFileName) + 'winzip32.exe';
If FileExists(FZipFileName) = false then
begin
FZipFileName:= EmptyStr;
FZipInstalled:=false;
else
FZipInstalled:= true;
end;
 
procedure TZipModule.CreateZipFile(ZipDest, Archivo: string);
var
cmd: string;
begin
If FZipInstalled = false then Exit;
If FileExists(archivo) = false then Exit;
cmd:= ' -min -a' + Dest + ' ' + arcchivo;
TRunAppModule.Create(FZipFileName, cmd, false);
end;
 
procedure TZipModule.UpdateZipFile(Dest, archivo: string);
var
cmd: string;
begin
If FZipInstalled = false then Exit;
If FileExists(archivo) = false then Exit;
cmd:= ' -min -u ' + Dest + ' ' + Archivo;
TRunAppModule.Create(FZipFileName, cmd, false);
end;
end.

Explicación: Sigue el mismo método que la clase TRarModule, primero comprueba si está instalado WinZip a través del registro, comprueba que existe el ejecutable para llamarlo desde la línea de comandos y si es así podemos utilizar los procedimientos CreateZipFile para crear un archivo zip con un archivo en su interior y UpdateZipFile para añadir un archivo a un archivo zip

Bien, ahora vamos con el "núcleo" de nuestro malware, ahora que tenemos las dos clases creadas haremos los siguiente: Primero comprobamos si está instalado el WinRar y si no lo está pues vamos con el WinZip. Os preguntareis que puede haber pcs sin WinZip y WinRar, pues bien, es cierto pero es muy dificil que haya algún pc sin estos programas. WinRar no todos los pcs lo tienen pero WinZip si. Lo que podiamos hacer es comprobar si estan instalados estos programas y si no es así podriamos crear un archivo zip con el método "enviar a carpeta comprimida en zip" que sale en el menú contextual de cualquier carpeta... pero eso ya no nos interesa en este tutorial...

Source | Delphi | ZipRar.dpr
program ZipRar;
{$APPTYPE CONSOLE}
uses RarModule, ZipModule;
 
var
Rar: TRarModule;
Zip: TZipModule;
begin
Rar:= TRarModule.Create;
If Rar.Installed = false then begin
Zip:= TZipModule.Create;
If Zip.Installed = false then begin
Writeln('No está instalado ni WinZip ni WinRar :(');
Readln;
Exit;
end;
Zip.CreateZipFile('C:\MiZip.zip', 'C:\archivo.txt');
Writeln('Zip creado');
Readln;
Exit;
end;
Rar.CreateRarFile('C:\MiRar.rar', 'C:\arhivo.txt');
Writeln('Rar creado');
Readln;
Exit;
end.

Explicación: Sigue el mismo método que la clase TRarModule, primero comprueba si está instalado WinZip a través del registro, comprueba que existe el ejecutable para llamarlo desde la línea de comandos y si es así podemos utilizar los procedimientos CreateZipFile para crear un archivo zip con un archivo en su interior y UpdateZipFile para añadir un archivo a un archivo zip

Bueno aquí acabamos este artículo de como crear archivos zip y rar con WinZip y WinRar, espero haberme expresado con claridad. Si teneis alguna duda o cualquier pregunta, mandarme un email