%TITLE  "Shadow v1.0 Beta - COM encryptor by Tailgunner"

        IDEAL           ; ideal mode r0x ;)

        JUMPS           ; allow jumps bigger then 128 bytes
        MODEL   tiny

CR      EQU     0Dh     ; ASCII for carriage return
LF      EQU     0Ah     ; ASCII for line feed

        DATASEG

Intro           DB      'ÄÄÄÍ[ Shadow COM encryptor version 1.0 beta ]ÍÄÄÄ',LF,CR
                DB      '           Coded in 1998 by Tailgunner',LF,CR,'$'
NoCTail         DB      LF,CR,'  þ Directions : shadow <filename.com>',LF,CR,'$'
Opening         DB      LF,CR,'  þ Opening file ...$'
Allocate        DB      LF,CR,'  þ Allocating memory ...$'
Reading         DB      LF,CR,'  þ Reading from input file ...$'
Crypting        DB      LF,CR,'  þ Mutating code ...$'
Writing         DB      LF,CR,'  þ Writing to output file : $'
Done            DB      LF,CR,'  þ Job complete!',LF,CR,'$'
ErrOpen         DB      LF,CR,'  þ Error : File not found!',LF,CR,'$'
ErrRead         DB      LF,CR,'  þ Error reading from file!',LF,CR,'$'
ErrWrite        DB      LF,CR,'  þ Error writing to output file!',LF,CR,'$'
ErrCreate       DB      LF,CR,'  þ Error creating output file!',LF,CR,'$'
ErrAlloc        DB      LF,CR,'  þ Error allocating memory!',LF,CR,'$'
; ---------------------------------------------------------------------------
Handle          DW      0               ; storage for file handle
Jump            DB      0E9h            ; code for a JMP
FSize           DW      0               ; file size holder
CrpSize         DW      0               ; filesize / 2 + 1 (for loop)
CTailStor       DW      0               ; points to beginning of command tail
CTailSize       DW      0               ; size of command tail
MemAddr         DW      0               ; New DS address
Key             DB      0               ; encryption key from clock
XORKey          DW      0               ; stores final key value
NewFile         DB      0Dh DUP (0),LF,CR,'$'   ; output file name

        CODESEG

        ORG     100h
        P386
        
Start:
        lea     dx,[Intro]              ; load 'Intro' message
        call    Print                   ; print the message   
        mov     cl,[ds:80h]             ; get command tail length
        or      cl,cl                   ; anything there?
        jnz     FoundCmd                ; if so move on ...
        lea     dx,[NoCTail]            ; print 'NoCTail' message
        call    Print
        jmp     Exit                    

FoundCmd:
        call    GetCmdTail              ; procedure to get params on cmdtail
        lea     dx,[Opening]            ; load 'Opening' message
        call    Print                   ; print the message
        call    OpenFile                ; open file from command tail
        jnc     FileOpen                ; jump if there is no errors
        lea     dx,[ErrOpen]            ; load 'ErrOpen' message
        call    Print                   ; print the message
        jmp     Exit

FileOpen:
        mov     [Handle],ax             ; move file handle into 'Handle'        
        lea     dx,[Allocate]           ; load 'Allocate' message
        call    Print                   ; print the message
        call    MemAllocate             ; procedure to allocate memory
        jnc     StartRead               ; if everything is ok, jump on...
        lea     dx,[ErrAlloc]           ; print 'ErrAlloc' message
        call    Print                   ; print the message
        jmp     Exit

StartRead:
        mov     [MemAddr],ax            ; MemAddr <-- address of new memory
        lea     dx,[Reading]            ; load 'Reading' message
        call    Print                   ; print the message
        call    ReadFile                ; read input file into memory
        jnc     Encryp                  ; if everything is ok, move on
        lea     dx,[ErrRead]            ; load 'ErrRead' message
        call    Print                   ; print the message
        jmp     Exit

Encryp:
        call    CloseFile               ; close input file
        mov     ah,2Ch                  ; get time from clock
        int     21h
        xor     dl,dh                   ; dh = Seconds, dl = Hundredths
        mov     [Key],dl                ; move random key into 'Key'
        mov     bx,[FSize]              ; bx = filesize (key for encryption)
        mov     cx,bx                   ; also need filesize in cx for loop
        movzx   dx,dl                   ; move dl to dx
        xor     bx,dx                   ; bx = filesize dx = random Value
        mov     [XORKey],bx             ; save XORKey for Decrypt procedure
        lea     dx,[Crypting]           ; load 'Crypting' message
        call    Print                   ; print the message

        shr     cx,1                    ; divide filesize by 2
        inc     cx                      ; add one in case of remainder
        mov     [CrpSize],cx            ; save for adding to Decrypt proc
        mov     ax,[MemAddr]            ; move 'MemAddr' into ax
        push    ds es                   ; save ds and es to the stack
        mov     ds,ax                   ; ds points to the allocated mem
        mov     es,ax                   ; ... and so does es
        xor     dx,dx                   ; ds:dx points to start of filebuf
        xor     si,si                   ; ds:si
        xor     di,di                   ; es:di
Loop1:
        lodsw                           ; load word to ax
        xor     ax,bx                   ; crypt it with bx
        stosw                           ; store it back on di
        xchg    bl,bh                   ; switch bl with bh
        not     bx                      ; get ones complement of bx
        loop    Loop1                   ; loop back for the next word

        pop     es ds                   ; restore old ds and es
        call    NewFName                ; comfile.com --> comfile.sdw

FNameStr:
        mov     si,[CTailStor]          ; si points to start of command tail
        lea     di,[NewFile]            ; di points to 'NewFile' variable
        mov     cx,[CTailSize]          ; command tail length in cx
        dec     cx                      ; we don't need the null 0 at the end

Loop2:
        lodsb
        stosb                           ; put new filename into NewFile
        loop    Loop2

OK:
        lea     dx,[Writing]            ; load 'Writing' message
        call    Print                   ; print the message
        lea     dx,[NewFile]            ; load 'NewFile' (new file name)
        call    Print                   ; print the filename
        call    CreateFile              ; create output file
        jnc     Continue                ; if everything is ok jump on
        lea     dx,[ErrCreate]          ; load 'ErrCreate' message
        call    Print                   ; print the message
        jmp     Exit

Continue:
        mov     [Handle],ax             ; put file handle into 'Handle'
        mov     cx,03h                  ; cx = number of bytes to write
        lea     dx,[Jump]               ; dx points to start of bytes
        mov     bx,[Handle]             ; put file handle into bx
        call    WriteFile               ; write the bytes to file
        jnc     WriteOK                 ; if everything is good, jump
        lea     dx,[ErrWrite]           ; load 'ErrWrite' message

WriteOK:
        mov     cx,[CrpSize]            
        mov     [word ptr PtchSize+1],cx
        mov     cx,[XORKey]
        mov     [word ptr PtchCrp+1],cx

; The above routine may be a bit confusing so i'll explain ;)
; CrpSize = Half the filesize, we need this in the Decrypt procedure because
; we are crypting word values. XORKey = the encryption key that was
; created when the input file buffer was crypted farther up in the source.
; mov [word ptr PatchSize+1],cx patches the Decrypt procedure before it
; is written to the output file. The same thing goes for the XORKey.


        push    ds                      ; save ds to the stack
        mov     cx,[FSize]              ; load filesize into cx
        mov     bx,[Handle]             ; bx contains file handle
        mov     ax,[MemAddr]            ; load address of allocated mem in ax
        mov     ds,ax                   ; ds now points to allocated memory
        xor     dx,dx                   ; ds:dx points to file buffer
        call    WriteFile               ; write the buffer to output file
        pop     ds                      ; restore old ds

        lea     dx,[Decrypt]            ; dx points to start of Decrypt proc
        mov     cx,(Marker-Decrypt)     ; number of bytes to write 
        mov     bx,[Handle]             ; move file handle into bx
        call    WriteFile               ; write the decrypt procedure to file
        call    CloseFile               ; close the output file
        lea     dx,[Done]               ; load 'Done' message
        call    Print                   ; print the message

Exit:
        mov     ah,4Ch                  ; function 4Ch = terminate process
        int     21h

PROC    Print
        mov     ah,09h                  ; function 4Ch = print string
        int     21h
        ret
ENDP    Print

PROC    GetCmdTail
        inc     cx                      ; cx = length to scan
        mov     [CTailSize],cx          ; save command tail size to CTailSize
        mov     di,81h                  ; 81h = start of command tail
        mov     al,' '
        repe    scasb                   ; scan bytes while al = ' '
        lea     dx,[di-01h]             ; dx points to beginning of tail
        mov     [CTailStor],dx          ; also put in CTailStor
        repne   scasb                   ; scan while al <> ' '
        dec     di
        xor     al,al                   ; null terminate the parameter
        stosb                           ;
        ret
ENDP    GetCmdTail

PROC    OpenFile
        mov     dx,[CTailStor]          ; dx points to filename from CTailStor
        mov     ax,3D02h                ; open file for read/write
        int     21h
        ret
ENDP    OpenFile

PROC    MemAllocate
        mov     ah,4Ah                  ; modify allocated memory blocks
        mov     bx,1000h                ; make 1000h byte paragraphs
        int     21h
        mov     ah,48h                  ; allocate memory blocks
        mov     bx,1000h                ; allocate 1000h blocks
        int     21h
        ret
ENDP    MemAllocate

PROC    ReadFile
        mov     bx,[Handle]             ; move file handle into bx
        mov     cx,0FFFFh               ; maximum number of bytes to read
        mov     ax,[MemAddr]            ; ax has address of allocated mem
        push    ds                      ; save old ds
        mov     ds,ax                   ; we are reading file into new mem
        xor     ax,ax                   ; clear ax
        xor     dx,dx                   ; ds:dx points to allocated mem
        mov     ah,3Fh                  ; function 3Fh = read from file
        int     21h
        pop     ds                      ; restore old ds
        mov     [FSize],ax              ; save filesize to FSize
        ret
ENDP    ReadFile

PROC    NewFName
        mov     cx,[CTailSize]          ; load command tail size into cx
        xor     di,di                   ; clear di
        mov     di,[CTailStor]          ; di points to first char on cmdtail
        mov     al,'.'
        repne   scasb                   ; scan bytes while al <> '.'
        mov     al,'s'                  ;
        stosb                           ;
        mov     al,'d'                  ; create new filename extention
        stosb                           ;
        mov     al,'w'                  ;
        stosb                           ;
        ret
ENDP    NewFName

PROC    CloseFile
        mov     bx,[Handle]             ; move handle into bx
        mov     ah,3Eh                  ; function 3Eh = close file
        int     21h
        ret
ENDP    CloseFile

PROC    CreateFile
        mov     dx,[CTailStor]          ; dx points to filename from CTailStor
        xor     cx,cx                   ; clear cx
        mov     ah,3Ch                  ; function 3Ch = create file
        int     21h
        ret
ENDP    CreateFile

PROC    WriteFile
        mov     ah,40h                  ; function 40h = write bytes to file
        int     21h
        ret
ENDP    WriteFile

PROC    Decrypt
PtchSize:
        mov     cx,0                    ; byte ptr from above patches the 0
PtchCrp:
        mov     bx,0                    ; byte ptr from above patches the 0
        mov     si,103h                 ; start of crypted code
        mov     di,100h                 ; decrypt to cs:0100h
Lp:
        lodsw                           ; load word to decrypt into ax
        xor     ax,bx                   ; crypt it!
        stosw                           ; overwrite encrypted code
        xchg    bl,bh                   ; exchange bl with bh
        not     bx                      ; get ones complement of bx 
        loop    Lp
Return:
        push    100h                    ; ret to cs:100h
        ret
ENDP    Decrypt
 Marker  DB      0                      ; marker for the end of procedure

        END     Start




