
                                        /-----------------------------\
                                        | Xine - issue #1 - Phile 011 |
                                        \-----------------------------/

;
; Methyl [Immortal Riot/Genesis] proudly presents:
;
;
;                 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
;                 ³               Tunneling               ³
;                 ³                 with                  ³
;                 ³            Single step mode           ³
;                 ³                                       ³
;                 ³            EXAMPLE PROGRAM            ³
;                 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;   So you can code a good tunneling routine now, but which one should you 
;choose?  A good method of working out which handler you want to use is to 
;first have a look at how each method performs on YOUR system, and then maybe
;on other systems if you have them available.  So as to save you unknown
;coding time, I have assembled all the methods you have learnt so far into
;this example program, which will simply show you the results of each type
;of tunneling method.
;
;   Please note there are no anti-anti-tunneling routines in here, as they are
;not really needed for an example program such as this.  Also note that this is
;NOT a virus, it is an EXAMPLE PROGRAM!  Almost all of the code in here, at
;least the major portions of the INT 1 handlers, was copied straight from
;my document, cut+paste style, just to prove the routines I provided you are
;ready to run without modification!
;
codesg segment para public 'code'
    assume cs:codesg, ds:codesg, es:codesg, ss:codesg
    org 0100h
start:
    jmp begin
    orig_1         dw 0, 0
    return_address dw 0, 0
    m_startup   db 'Methyl''s example interrupt tunneler$'
    m_segment_o_13 db 0dh, 0ah, 'SEGMENT CHECK, int 13, BIOS method    - $'
    m_segment_n_13 db 0dh, 0ah, 'SEGMENT CHECK, int 13, IO method      - $'
    m_segment_21   db 0dh, 0ah, 'SEGMENT CHECK, int 21                 - $'
    m_hand_o_13    db 0dh, 0ah, 'HAND METHOD, int 13, BIOS method      - $'
    m_hand_n_13    db 0dh, 0ah, 'HAND METHOD, int 13, IO  method       - $'
    m_hand_21      db 0dh, 0ah, 'HAND METHOD, int 21                   - $'
    m_opcode_13    db 0dh, 0ah, 'OPCODE CHECK, int 13                  - $'
    m_opcode_21    db 0dh, 0ah, 'OPCODE CHECK, int 21                  - $'
    m_list_13      db 0dh, 0ah, 'CS:LIST METHOD, int 13                - $'
    m_list_21      db 0dh, 0ah, 'CS:LIST METHOD, int 21                - $'
    m_iret_13      db 0dh, 0ah, 'IRET CHECK, int 13                    - $'
    m_iret_21      db 0dh, 0ah, 'IRET CHECK, int 21                    - $'
    m_desq         db 0dh, 0ah, 'DESQView detected, exitting', 0dh, 0ah, '$'
    m_end       db 0dh, 0ah, 'End of example program', 0dh, 0ah, '$'
begin proc near
    mov ah, 9
    lea dx, [m_startup]
    int 021h                    ; Show startup message

    mov ax, 03501h
    int 021h
    mov [orig_1], bx
    mov [orig_1+2], es          ; Save original INT 1 handler

    mov ax, 02b01h
    mov cx, 'DE'
    mov dx, 'SQ'
    int 021h
    cmp al, -1
    je desqview_not_here        ; Exit if DESQView found

    mov ah, 9
    lea dx, [m_desq]
    int 021h
    mov ax, 04c01h
    int 021h

desqview_not_here:
    mov ah, 9
    lea dx, [m_segment_o_13]
    int 021h
    call segment_o_13
    call show_int_address

    mov ah, 9
    lea dx, [m_segment_n_13]
    int 021h
    call segment_n_13
    call show_int_address

    mov ah, 9
    lea dx, [m_segment_21]
    int 021h
    call segment_21
    call show_int_address

    mov ah, 9
    lea dx, [m_hand_o_13]
    int 021h
    call hand_o_13
    call show_int_address

    mov ah, 9
    lea dx, [m_hand_n_13]
    int 021h
    call hand_n_13
    call show_int_address

    mov ah, 9
    lea dx, [m_hand_21]
    int 021h
    call hand_21
    call show_int_address

    mov ah, 9
    lea dx, [m_opcode_13]
    int 021h
    call opcode_13
    call show_int_address

    mov ah, 9
    lea dx, [m_opcode_21]
    int 021h
    call opcode_21
    call show_int_address

    mov ah, 9
    lea dx, [m_list_13]
    int 021h
    call list_13
    call show_int_address

    mov ah, 9
    lea dx, [m_list_21]
    int 021h
    call list_21
    call show_int_address

    mov ah, 9
    lea dx, [m_iret_13]
    int 021h
    call iret_13
    call show_int_address

    mov ah, 9
    lea dx, [m_iret_21]
    int 021h
    call iret_21
    call show_int_address

    mov ah, 9
    lea dx, [m_end]
    int 021h                    ; Show exit message

    xor ax, ax
    mov es, ax
    cli
    mov ax, [orig_1]
    mov [es:4], ax
    mov ax, [orig_1+2]
    mov [es:6], ax
    sti                         ; Reset original interrupt 1 address

    push cs
    pop ds
    
    mov ax, 04c00h
    int 021h
begin endp
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
segment_o_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset segment_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov byte ptr [segment_status], -1
    mov byte ptr [segment_type], 2
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
segment_o_13 endp
segment_n_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset segment_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov byte ptr [segment_status], -1
    mov byte ptr [segment_type], 1
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
segment_n_13 endp
segment_21 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset segment_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov ah, 030h
    int 021h                    ; DOS version check
    cmp al, 3
    jb alternative_segment
    mov ah, 052h
    int 021h
    mov ax, [es:bx-2]
    mov [first_mcb], ax         ; Setup first MCB address
    jmp segment_done
alternative_segment:
    mov word ptr [first_mcb], 0300h
segment_done:
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov byte ptr [segment_status], -1
    mov byte ptr [segment_type], 0
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 052h
    pushf
    call far ptr [(021h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
segment_21 endp
hand_o_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset hand_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov word ptr [hand_segment], 0
    mov byte ptr [hand_type], 1
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
hand_o_13 endp
hand_n_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset hand_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov word ptr [hand_segment], -1
    mov byte ptr [hand_type], 0
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
hand_n_13 endp
hand_21 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset hand_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov word ptr [hand_segment], -1
    mov byte ptr [hand_type], 0
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 052h
    pushf
    call far ptr [(021h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
hand_21 endp
opcode_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset opcode_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
opcode_13 endp
opcode_21 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset opcode_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 052h
    pushf
    call far ptr [(021h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
opcode_21 endp
list_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset list_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address

    lea bx, [offset list_begin]
zero_loop_13:
    mov word ptr [bx], 0
    add bx, 2
    cmp bx, offset list_end
    jne zero_loop_13            ; Zero out list
    mov word ptr [list_begin], cs        

    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
list_13 endp
list_21 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset list_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address

    lea bx, [offset list_begin]
zero_loop_21:
    mov word ptr [bx], 0
    add bx, 2
    cmp bx, offset list_end
    jne zero_loop_21            ; Zero out list
    mov word ptr [list_begin], cs        

    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 052h
    pushf
    call far ptr [(021h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
list_21 endp
iret_13 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset iret_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov byte ptr [iret_status], -1
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 1
    pushf
    call far ptr [(013h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
iret_13 endp
iret_21 proc near
    push ds
    xor ax, ax
    mov es, ax
    cli
    mov word ptr [es:4], offset iret_handler
    mov [es:6], cs
    sti                         ; redirect INT 1 to our routine
    mov ah, 052h
    int 021h
    mov ax, [es:bx-2]
    mov [first_mcb], ax         ; Setup first MCB address
    mov [return_address], 0
    mov [return_address+2], 0   ; Clear return address
    mov byte ptr [iret_status], -1
                                ; Set us up to start tunneling
    xor ax, ax
    mov ds, ax                  ; Point DS to IVT
    pushf
    pushf
    pop ax
    or ah, 1
    push ax
    popf                        ; Set TF
    mov ah, 052h
    pushf
    call far ptr [(021h*4)]     ; Simulate interrupt call
    
    popf
    pop ds                      ; Restore our DS
    ret
iret_21 endp
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Start of INT 1 handler using SEGMENT CHECK method
    first_mcb      dw 0
    segment_status db -1
    segment_type   db 0             ; 0=DOS KERNEL scan
                                    ; 1=IO KERNEL scan
                                    ; 2=ROM BIOS scan
segment_handler proc far
    push bp
    mov bp, sp
    push ax
    cmp [cs:segment_status], 0
    je segment_exit                 ; exit if we've finished tunneling already    
    mov ax, [bp+4]                  ; get CS:
    cmp [cs:segment_type], 1
    je segment_io_scan
    cmp [cs:segment_type], 2
    je segment_bios_scan
    cmp ax, [cs:first_mcb]
    jb segment_found                ; check CS: is in DOS kernel
    jmp segment_exit
segment_io_scan:
    cmp ax, 070h
    je segment_found
    jmp segment_exit                ; check CS: is in IO kernel
segment_bios_scan:
    cmp ax, 0c800h                  ; check for XT bios
    je segment_found
    cmp ax, 0f000h                  ; check for XT+ bios
    je segment_found
segment_exit:
    pop ax
    pop bp
    iret
segment_found:
    mov ax, [bp+4]
    mov [cs:return_address+2], ax
    mov ax, [bp+2]
    mov [cs:return_address], ax     ; save CS:IP
    mov [cs:segment_status], 0      ; indicate to stop tunneling
    jmp segment_exit
segment_handler endp
; End of INT 1 handler using SEGMENT CHECK method
; Start of INT 1 handler using OPCODE CHECK method
_override dw 0                      ; used to store current override
_cs       dw 0                      ; CS of instruction being executed, needed
                                    ; to simplify override usage
_ds       dw 0                      ; DS before we modified it, needed to 
                                    ; simplify override usage

opcode_handler proc far
    push bp
    mov bp, sp
    push ax
    push si
    push ds                         ; save registers
    mov ax, [bp+4]
    mov [cs:_cs], ax                ; save CS
    mov [cs:_ds], ds                ; save DS
    mov [cs:_override], ds          ; setup override as default
    lds si, [bp+2]                  ; get address of instruction into DS:SI
    cld
read_opcode:
    lodsb
    cmp al, 026h
    je es_override                  ; use ES override
    cmp al, 036h
    je ss_override                  ; use SS override
    cmp al, 02eh
    je cs_override                  ; use CS override
    cmp al, 03eh
    je ds_override                  ; use DS override

    cmp al, 0eah
    je immediate                    ; jmp far off:seg
    dec si
    lodsw
    cmp ax, 02effh
    je variable                     ; jmp far [variable]
    cmp ax, 09ah
    je immediate                    ; call far off:seg
    cmp ax, 01effh
    je variable                     ; call far [variable]

opcode_exit:
    pop ds
    pop si
    pop ax
    pop bp
    iret

immediate:
    lodsw
    mov [cs:return_address], ax
    lodsw
    mov [cs:return_address+2], ax   ; save address of area we're going into
    jmp opcode_exit

variable:
    lodsw
    mov si, ax
    mov ax, [cs:_override]
    mov ds, ax
    jmp immediate                   ; extract off:seg

ds_override:
    mov ax, [cs:_ds]
    mov [cs:_override], ax
    jmp read_opcode
cs_override:
    mov ax, [cs:_cs]
    mov [cs:_override], ax
    jmp read_opcode
es_override:
    mov [cs:_override], es
    jmp read_opcode
ss_override:
    mov [cs:_override], ss
    jmp read_opcode    
opcode_handler endp
; End of INT 1 handler using OPCODE CHECK method
; Start of INT 1 handler using CS:LIST method
list_begin: 
    dw 015h dup(0)
list_end:

list_handler proc far
    push bp
    mov bp, sp
    push ax
    push bx
    mov ax, [bp+4]
    lea bx, [list_begin]
list_traverse:
    cmp bx, offset list_end
    je list_error                   ; this is a check to make sure the 
                                    ; list of CS: values doesn't outgrow
                                    ; the space allocated for them
    cmp [cs:bx], ax
    je list_exit                    ; this is if the CS: is already on the 
                                    ; list
    cmp word ptr [cs:bx], 0
    je list_insert                  ; add us to the list if we've reached the
                                    ; end of defined values
    add bx, 2
    jmp list_traverse               ; this moves down to the next item on 
                                    ; the CS: list
list_insert:
    mov [cs:bx], ax                 ; put us on the list
    mov [cs:return_address+2], ax
    mov ax, [bp+2]
    mov [cs:return_address], ax     ; save CS:IP value
    jmp list_exit

list_error:
    mov [cs:return_address], 0
    mov [cs:return_address+2], 0    ; set error indicator

list_exit:
    pop bx
    pop ax
    pop bp
    iret
list_handler endp
; End of INT 1 handler using CS:LIST method
; Start of INT 1 handler using HAND-over-HAND method
hand_segment dw 0                   ; Where we save our CS: values
hand_type    db 0                   ; 0=Go down
                                    ; 1=Go up
hand_handler proc far
    push bp
    mov bp, sp
    push ax
    mov ax, [bp+4]
    cmp byte ptr [cs:hand_type], 1
    je go_up
go_down:
    cmp ax, [cs:hand_segment]
    jb hand_over_hand
    jmp hand_exit
go_up:
    cmp ax, [cs:hand_segment]
    ja hand_over_hand           
hand_exit:
    pop ax
    pop bp
    iret
hand_over_hand:
    mov [cs:return_address+2], ax
    mov [cs:hand_segment], ax
    mov ax, [bp+2]
    mov [cs:return_address], ax     ; save CS:IP
    jmp hand_exit
hand_handler endp
; End of INT 1 handler using HAND-over-HAND method
; Start of INT 1 handler using IRET method
iret_status db -1
iret_handler proc far
    push bp
    mov bp, sp
    push ax
    push ds
    push si
    cmp [cs:iret_status], 0
    je iret_exit
    mov ax, [cs:return_address+2]
    cmp [bp+4], ax
    jne iret_save
    lds si, [bp+2]
    lodsb
    cmp al, 0cfh
    je iret_exit_detected
iret_exit:
    pop si
    pop ds
    pop ax
    pop bp
    iret
iret_save:
    mov ax, [bp+4]
    mov [cs:return_address+2], ax
    mov ax, [bp+2]
    mov [cs:return_address], ax     ; save CS:IP
    jmp iret_exit
iret_exit_detected:
    mov [cs:iret_status], 0
    jmp iret_exit
iret_handler endp
; End of INT 1 handler using IRET method
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
show_int_address proc near      ; displays return_address
    mov bx, [return_address+2]
    call show_hex
    call show_colon
    mov bx, [return_address]
    call show_hex
    ret    
show_int_address endp
show_colon proc near            ; displays a colon on screen
    mov ah, 2
    mov dl, ':'
    int 021h
    ret
show_colon endp
show_hex proc near              ; displays a HEX number on screen
    mov ch, 4
rotate:
    mov cl, 4
    rol bx, cl
    mov al, bl
    and al, 0fh
    add al, 030h
    cmp al, '9'+1
    jl print_it
    add al, 07h
print_it:
    mov dl, al
    mov ah, 2
    int 021h
    dec ch
    jnz rotate
    ret
show_hex endp
codesg ends
end start

