;***********************************************************************
;*                                                                     *
;*                 Nigr0 Compression Engine                            *
;*                                                                     *
;***********************************************************************
;
;   Engine Size (Compression and Descompression) = 01C0h Bytes  
;
; Estadisticias:
;
;     File WINWORD.EXE:
;   Section    size         New size    NCE Ratio
;   -------    ------       --------    ---------    
;   Header       0400h        024Ah      57,2%   
;   Code      0357000h     03319E9h      97,4%   
;   Data        04000h       028BFh      63,6%     
;   Rsrc        0E000h       08B07h      62,0%
;   Reloc      027000h      0192CFh      64,5%
;
;     File NETSCAPE.EXE:
;   Section    size         New size    NCE Ratio       (JQEnc) New Size
;   -------    ------       --------    ---------       ----------------
;   Header       0400h         0229h     54,0%                0184h
;   Code      030E000h      02FC3C4h     97,7%             0245002h
;   Data       056200h       043F18h     78,8%              031C0Ah
;   Rsrc        03E00h        02E78h     74,9%               027F6h
;
;
;   This engine is very usufull when the data to compress has 
;   a lot of repetitions or when the data variate only a little.
;   0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 4 4 4 4 1 1 1 1 1 1 1 1
;   This secuence will have a good ratio because it has a lot of
;   words repeated.
;   10 11 10 10 12 11 10 11 12 10 12 10 11
;   This secuence will olso have a good ratio because the
;   differences between 10, 11 and 12 is very low.
;
;   The engine will get 2 bytes from input buffer and compress
;   it in the output buffer, the output format will be;

;  (Seg) 1 bit-> Segurity bit (if 1 not compression posible and 16 bits
;                follow it there are the data without any compression)
;  (C)  1 bit -> Complement  (0 no complement /1 complement)
;  (O)  1 bit -> SUB or not SUB ( 0 Sub/ 1 not Sub)
;  (S)  3 bits -> The size of the new encoding data
;  (N)  last bits -> The data compressed
;
;      ÉÍÍÍÍÍÍËÍÍÍÍÍÍËÍÍÍÍÍÍËÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍ»
;      º (Seg)º (C)  º (O)  º  (S)  º   (N)       º
;      º 1bit º 1bit º 1bit º 3bits º   Nbits     º
;      ÈÍÍÍÍÍÍÊÍÍÍÍÍÍÊÍÍÍÍÍÍÊÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
;
;   In this way, if there are repeatition of words in the text to compress
;   the second word will need only 6bits ,because N will be 0.
;   With operation of SUB and Complement will be able to optain N=0, and
;   will only need to code the compression data bits (Seg,C,O and S bits).


.386p
locals
jumps
.model flat,STDCALL

extrn      ExitProcess:PROC
extrn      CreateFileA:PROC
extrn      ReadFile:PROC
extrn      CloseHandle:PROC
extrn      WriteFile:PROC
extrn      SetFilePointer:PROC


GENERIC_READ    EQU     80000000H  ;abre archivo para lectura
GENERIC_WRITE   EQU     40000000H  ;abre el archivo para escritura
OPEN_EXISTING   EQU     3          ;usado por CreateFile para abrir archivo existente

size            EQU     03E00h
dir             equ     03C2E00h

.data

dumm7y    db    0                         ;de esta secci¢n paso
text     db    'Ejemplo de Compression Ejecutado',0

.code

start:
       
        xor     ebp,ebp

        lea     esi,ebp+host           ;Abro el archivo
        xor     eax,eax 
        push    eax     
        push    eax
        push    large OPEN_EXISTING
        push    eax
        push    eax
        push    large GENERIC_READ or GENERIC_WRITE
        mov     eax,esi     
        push    eax                            
        call    CreateFileA               ;abro el archivo a comprimir

        mov    dword ptr [ebp+ahand],eax

        push    LARGE 0                   ;en edx: el offset del archivo
        push    LARGE 0
        push    LARGE dir
        push    dword ptr [ebp + ahand]
        call    SetFilePointer          ;me voy al principio
         
        mov     ecx,size  
        lea     edx,[ebp+end]
        push    large 0                 ;En ecx: Numero de bytes a leer
        lea     eax,[ebp +IOBYTES]      ;En edx: el offset del buffer        
        push    eax
        push    ecx
        push    edx
        push    dword ptr [ebp + ahand]
        call    ReadFile

        push    dword ptr [ebp + ahand]
        call    CloseHandle                       ;cierro el archivo

       

       int   03h

       mov   ebp,end_c_engine-start_c_engine
       xor   ebp,ebp
       lea   esi,[ebp+end]
       lea   edi,[ebp+end]
       add   edi,size
       mov   ecx,size
       call  nce_comp

       int   03h

       lea   edi,[ebp+end]
       mov   esi,edi
       add   esi,size
       mov   ecx,size
       call  nce_decomp

salir:
       Push  LARGE -1
       call  ExitProcess

IOBYTES:
       dd     0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h
       dd     0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h
       dd     0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h
       dd     0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h
       dd     0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h,0h

ahand dd    0h   ;el handle abierto

host  db   'prueba.exe',0
compr db   'prueba.cmp',0

;************************************************************************
;***************** Comienzo de la rutina de compresion ******************
;************************************************************************

start_c_engine:

nce_comp:
       pushad
       inc   ecx
       shr   ecx,1    ;divido entre 2
       xor  ebx,ebx   ;ebx sera el contador de bits
       xor  ebp,ebp   ;en ebp se almacena la palabra anterior

otrapalabra:
       push ecx

       xor  eax,eax
       lodsw       ;leo 2 bytes

       push eax

       push esi
       push eax
@otravez:
       call pone0       ;bit de seguridad

       xor  esi,esi
       push eax
       push eax
       pop  edx
       pop  ecx

       sub   dx,bp
       xor   cx,0ffffh
       mov   si,cx
       sub   si,bp

       shl   eax,2
       shl   edx,2
       shl   ecx,2
       shl   esi,2

       add   edx,0002h
       add   ecx,0001h
       add   esi,0003h
reord:
       cmp   eax,edx
       jle   @a
       xchg  eax,edx
       jmp   reord
@a:    cmp   edx,ecx
       jle   @b
       xchg  edx,ecx
       jmp   reord
@b:    cmp   ecx,esi
       jle   @c
       xchg  ecx,esi
       jmp   reord
@c:

       push   eax
       xchg   eax,edx
       mov    ecx,02h       ;meto 2 bits con la codificacion de complemento
       call   mbit          ;y operacion
       pop    eax
       shr    eax,2

       xor  edx,edx
       dec  edx

       db  066h,0fh,0bdh,0d0h  ;bsr  dx,ax      ;calculo el tama¤o que tendr 

       inc   edx
       cmp   dx,7
       jle   @fuera
       sub   ebx,3
       call  pone1
       pop   edx
       pop   esi
       mov   ecx,16       ;mete la palabra sin comprimir
       call  mbit
       jmp  @4
@fuera:
       add  esp,4
       pop  esi
       and  edx,0ffffh
       push edx
       mov  ecx,03h         ;codifico la longitud en 3 bits
       call mbit
       pop  ecx

       jecxz   @4

       dec  ecx        ;El bit mas significativo ser  1 no hace falta
                       ;codificarlo
       jecxz  @4

       xchg eax,edx
       call mbit       ;y ahora mete la nueva codificacion
@4:
       pop  ebp        ;en ebp la palabra anterior
       pop  ecx
       dec  ecx
       jne  otrapalabra

       shr  ebx,03h
       inc  ebx
                        ;en ebx los bytes que ocupara encriptado
       mov  ebp,esp
       mov  dword ptr [ebp+24],ebx
       popad
       ret

;****** Rutina que se encarga de poner un 1 o un 0 en el bit ebx *******
;****** a partir de la direccion edi ***********************************

pone1:
       bts [edi],ebx   ;pone un 1
       jmp @s
pone0:
       btr [edi],ebx   ;pone un 0
@s:    inc ebx
       ret

;***** Rutina que copia tantos bit como indique ecx *****
;***** desde el registro dx al buffer **********************

mbit:                           
       rcr  dx,1
       jc   meteun1
       call pone0
       jmp  sale
meteun1:
       call pone1
sale:
       loop mbit
       ret


;************************************************************************
;************* Comienzo de la rutina de decompresion ********************
;************************************************************************

nce_decomp:
       pushad
       inc  ecx
       shr ecx,01h   ;lo paso a (16 bits)
       xor ebx,ebx
       xor ebp,ebp

descomprimeotro:
       push ecx
       push edi
       xor  edi,edi

       call leobit
       jnc  estacomprimido

       mov  ecx,016d
formoword:
       bt   [esi],ebx
       rcr  ax,1         ;voy formando el bit
       inc  ebx
       loop formoword
       jmp  @p3
       
estacomprimido:
       call leobit
       jc   cmpl
       push  LARGE 0
       jmp  nocmpl
cmpl:  push LARGE -1

nocmpl: call leobit
        jnc  @prosigue
        inc  edi

@prosigue:
       
       mov  ecx,3              
       xor  edx,edx
otroc:
       bt   [esi],ebx
       rcr  dl,1        ;leo los 4 bits siguientes en dl
       inc  ebx
       loop otroc
       shr  dl,5


       xchg ecx,edx     ;en ecx el tama¤o
       xor  eax,eax 

       jecxz   @5
       dec  ecx
       jecxz   @6
       push ecx
      
metebit:
       bt [esi],ebx
       rcr  ax,1         ;voy formando el bit
       inc  ebx
       loop metebit
       pop  ecx
@6:
       inc  ecx
       stc
       rcr  ax,1

       mov  edx,16
       sub  edx,ecx
       xchg ecx,edx
       shr  ax,cl       ;desplazo lo que queda
                        ;en ax tengo la palabra leida
@5:
       pop   ecx
       or    ecx,ecx
       jz    nocmp
       xor   ax,0ffffh 
nocmp:
       or   edi,edi
       jz   @p3
       add  ax,bp
@p3:

       mov  ebp,eax     ;en bp el nuevo valor para obtener las relocations
       pop  edi
       stosw

       pop  ecx
       dec  ecx
       jnz  descomprimeotro
       popad
       ret

leobit:
       bt   [esi],ebx
       inc  ebx
       ret




end_c_engine:
end:


buffer   db 030f000h*2   dup(0)
memoria   db 010h   dup(0)  ;buffer para el algoritmo de jackqy
tempbuf   db 066000h dup(0) ;buffe temporal para el algo de jackqery
        end   start



 
 
