▄▄                   ▄
▀▀▀ STEALTH GROUP WW █ Mail:   BOX 15, 125080 MOSCOW   ████████ █████████ █▀▀█
▀██ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ █ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀▀▐▀▀▀   ┌─┐┬ ┬┌─┤┬ ┬ ╥ ┬┐┌ █▄▄█
 ▐█ █▀▄ █▀▀ ▄▀▀ ▄▀▀ ▄█▄ ▄▀▀ █▀█   ▌ █ ▄▀█ █ ▄▀▀ █▄▄    ├┬┘│ │└─┐├─┤   │└┤ ▄  █
  █ █ █ █▀  █▀  █    █  █▀  █ █   █ █ █ █ █ █   █      ┴└─└─┘└─┘┴ ┴   ┴ ┴ ▀▀▀▀
  █ ▐ ▐ ▐   ▐▄▄ ▐▄▄  ▐  ▐▄▄ ▐▄▀    ▀█ ▀▄█ ▐ ▐▄▄ ▐▄▄▄   ████  WINTER ' 96  ████
  ▐ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄   ███████████████████████

  ████████████ НАХОЖДЕНИЕ НАСТОЯЩЕГО АДРЕСА INT 21h ЧЕРЕЗ PSP ████████████████
                ──────────────────────────────────────────────

Автор  : Satan's Little Helper    (Немного Помогающий Сатане)
Перевод: LovinGOD / SGWW          :)
	 Мои добавления и комментарии ограничены метками <LG+> и <LG->.

    ОПИСАНИЕ
    ────────

            Не надо обьяснять, зачем нужен именно НАСТОЯЩИЙ адрес int21h.	
       Описанный здесь метод позволяет найти настоящий адрес DOS int,
       используя PSP:0006.

            PSP:6 содержит doubleWord указатель на диспетчер функций DOS
	(я надеюсь). Он отличается от адреса точки входа в int21h.

	<LG+> PSP:0005 содержит 5-байтный CALL FAR. <LG->

	(R.Brown Interrupt List:
	  PSP:0005  BYTE  запрос на обслуживание CP/M CALL 5 (FAR JMP на
	                  00C0h)
			  Ошибка:(DOS 2+) PSP, созданные с помощью 4Bh int21h,
				 указывают на 00BEh
	  PSP:0006  WORD  совместимость с CP/M - размер первого сегмента для
			  .COM файла
	  PSP:0008  2байта Остаток от FAR JMP по адресу 05h.
	 Конец цитаты.    <LG+>)

	Этот диспетчер начинается с JMP FAR (код=0EAh). Он может указывать на
	a) обработчик диспетчера DOS
	b) конструкция "NOP / NOP / CALL NEAR", используемая некоторыми 
	   версиями DOS. Впоследствии эта конструкция укажет на тот же
           диспетчер (a)

	    Обработчик диспетчера DOS и обработчик int21h в памяти выглядят
	примерно так:

    dos_dispatch_handler:
        0000  1E                   push    ds
        0001  2E: 8E 1E 3DE7       mov     ds,word ptr cs:[3DE7h]
        0006  8F 06 05EC           pop     word ptr ds:[5ECh]
        000A  58                   pop     ax
        000B  58                   pop     ax
        000C  8F 06 0584           pop     word ptr ds:[584h]
        0010  9C                   pushf
        0011  FA                   cli
        0012  50                   push    ax
        0013  FF 36 0584           push    word ptr ds:[584h]
        0017  FF 36 05EC           push    word ptr ds:[5ECh]
        001B  1F                   pop     ds
        001C  80 F9 24             cmp     cl,24h
        001F  77 DC                ja      $-22h
        0021  8A E1                mov     ah,cl
        0023  EB 06                jmp     $+8
    int21_handler:
        0025  FA                   cli
        0026  80 FC 6C             cmp     ah,6Ch
        0029  77 D2                ja      $-2Ch
        002B  80 FC 33             cmp     ah,33h

    Таким образом:

        int21_handler = dos_dispatch_handler + 25h

	    В итоге, если мы только что нашли адрес 'dos_dispatch_hndlr',
	проверим соответствие его начала с кодом (1E2E/FA80) и добавим
	разницу (int21_handler-dos_dispatch_hndlr) к указателю на
	dos_dispatch_hndlr, чтобы получить адрес настоящего обработчика int21h.

        Это просто! (если не дошло - перечитайте)

	В случае (b) необходимо сделать то же самое, принимая во внимание,
	что смещение dispatch_handler отличается от обработчика int 21.

        0000  90                   nop
        0001  90                   nop
        0002  E8 00E0              call    $+0E3h
        0005  2E: FF 2E 1062       jmp     dword ptr cs:[1062h]
        000A  90                   nop
        000B  90                   nop
        000C  E8 00D6              call    $+0D9h
        000F  2E: FF 2E 1066       jmp     dword ptr cs:[1066h]
    int21_handler:
        0014  90                   nop
        0015  90                   nop
        0016  E8 00CC              call    $+0CFh
        0019  2E: FF 2E 106A       jmp     dword ptr cs:[106Ah]
        001E  90                   nop
        001F  90                   nop
        0020  E8 00C2              call    $+0C5h
        0023  2E: FF 2E 106E       jmp     dword ptr cs:[106Eh]
        0028  90                   nop
        0029  90                   nop
        002A  E8 00B8              call    $+0BBh
        002D  2E: FF 2E 1072       jmp     dword ptr cs:[1072h]
        0032  90                   nop
        0033  90                   nop
        0034  E8 00AE              call    $+0B1h
        0037  2E: FF 2E 1076       jmp     dword ptr cs:[1076h]
        003C  90                   nop
        003D  90                   nop
        003E  E8 00A4              call    $+0A7h
        0041  2E: FF 2E 107A       jmp     dword ptr cs:[107Ah]
    dos_dispatch_handler:
        0046  90                   nop
        0047  90                   nop
        0048  E8 009A              call    $+9Dh
        004B  2E: FF 2E 107E       jmp     dword ptr cs:[107Eh]

    таким образом:

        int21_handler = dos_dispatch_handler - 32h

    КОД
    ────

	Этот код не оптимизирован и сделан специально легким для понимания.

        ;name:      psp_trace
        ;на входе:  ds=psp segment
        ;на выходе: ds:bx=int 21 address если CF=0
        ;предназначение:  находит оригинальный обработчик int21h, используя
	;адрес PSP:0006

        psp_trace:
            lds     bx,ds:[0006h]           ;указатель на обработчик диспетчера
        trace_next:
            cmp     byte ptr ds:[bx],0EAh   ;JMP xxxx:xxxx ?
            jnz     check_dispatch
            lds     bx,ds:[bx+1]            ;куда указывает xxxx:xxxx в JMP-е
            cmp     word ptr ds:[bx],9090h  ;проверка на два NOP
            jnz     trace_next
            sub     bx,32h                  ;32h byte offset from dispatch
                                            ;handler
            cmp     word ptr ds:[bx],9090h  ;начало int 21 имеет такую же 
					    ;сигнатуру
            jnz     check_dispatch
        good_search:
            clc
            ret
        check_dispatch:
            cmp     word ptr ds:[bx],2E1Eh  ;проверка на push ds, префикс cs: 
            jnz     bad_exit
            add     bx,25h                  ;смещение 25h байт 
            cmp     word ptr ds:[bx],80FAh  ;проверка "cli" и "push ax"
            jz      good_search
        bad_exit:
            stc
            ret

    ЗАМЕЧАНИЯ
    ─────────

	    INT 30h и INT 31h содержит _код_ (не адрес) перехода
	на обработчик диспетчера, так что для трассировки с исполь-
	зованием INT 30h/31h нужно всего лишь установить ds:bx на
	0:c0 и вызвать trace_next в процедуре psp_trace.

	Дамп INT 30/31 в таблице векторов:

                  Непосредственный far JMP
                    ____________
        -d 0:c0    |            |
        0000:00C0  EA 28 00 02 01 FF 00 F0-0F 00 02 01 DF 0D 39 01
                   |_________| |_________|
                      INT 30     INT 31
                       addr       addr

        EA 28 00 02 01 = JMP 0102:0028

        ;name:      int30_trace
        ;out cond:  ds:bx=int 21 address if carry clear
        ;           ds:bx=nothing if carry set.
        ;purpose:   finds int 21 address using an INT 30/31 trace.

        int30_trace:
            xor     bx,bx
            mov     ds,bx
            mov     bl,0c0h                 ;point to 0:0c0
            jmp     short trace_next


    ДРУГИЕ ЗАМЕЧАНИЯ
    ────────────────

	После написания этого я услышал о вирусе "MG", который испо-
	льзует аналогичные технологии. Так вот, образчик этого вируса
	у меня есть и никаких подобных технологий он не использует.


    TESTING
    ───────

	   Был проверен на MSDOS 6.x, Novell Netware и софте IBM network. 

	   Машины с DR DOS, Novell DOS, 4DOS, OS/2 and NT не могли быть 
	найдены. Допускается, что это не будет работать на ВСЕХ DOS
	платформах, поэтому я включил проверку на ошибки (возврат Carry Flag).

    ЗАКЛЮЧЕНИЕ
    ──────────
	
            На практике INT 30h/31h немного более надежно, чем PSP:6, поэтому
	в случае неудачи вызовите int30_trace. Причина, по которой вы должны
	использовать вначале PSP trace, - антивирусникам будет больше работы ;)

    CREDITS
    ───────

        TaLoN - помог в исследовании адресов и рассказал о существовании
                int 30h/31h.
        Lookout Man - tester
        Aardvark - network tester

    DEMO PROGRAM
    ────────────


    ;-------8<--------абрэзать сюды---------8<-------

    comment |

        TASM ASSEMBLY:
            tasm psptest.asm
            tlink /t psptest.obj

        A86 ASSEMBLY:
            a86 psptest.asm
    |

    .model tiny
    .code

    org     100h

start:
    mov     dx,offset psp_status
    call    print_str                       ;print "PSP trace: "
    call    psp_trace                       ;do the trace
    jc      bad_psp
print_status:
    mov     dx,offset ok_str                ;print "Ok!"
    call    print_str
    mov     dx,offset psp_addr              ;print "interrupt trace to: "
    call    print_str
    push    bx
    mov     bx,ds                           ;print segment
    call    bin_to_hex
    call    print_colon                     ;print ":"
    pop     bx
    call    bin_to_hex                      ;print offset
    jmp     do_int30
bad_psp:
    mov     dx,offset bad_str
    call    print_str
do_int30:
    nop
    nop
    mov     word ptr cs:do_int30,20CDh      
    mov     dx,offset i30_status
    call    print_str                       ;print "PSP trace: "
    call    int30_trace
    jnc     print_status
    jmp     short do_int30

print_str:
    mov     ah,9
    push    ds
    push    cs
    pop     ds
    int     21h
    pop     ds
    ret

psp_addr    db  13,10,'Interrupt traced to: $'
psp_status  db  13,10,'PSP trace      : $'
i30_status  db  13,10,'INT 30/31 trace: $'
ok_str      db  'Ok!$'
bad_str     db  'Failure$'

;name:      psp_trace
;in cond:   ds=psp segment
;out cond:  ds:bx=int 21 address if carry clear
;           ds:bx=nothing if carry set.
;purpose:   finds int 21 address using a PSP trace.

psp_trace:
    lds     bx,ds:[0006h]           ;указатель на dispatch handler
trace_next:
    cmp     byte ptr ds:[bx],0EAh   ;это JMP xxxx:xxxx ?
    jnz     check_dispatch
    lds     bx,ds:[bx+1]            ;указатель на xxxx:xxxx  JMP'а
    cmp     word ptr ds:[bx],9090h  ;проверка сигнатуры дубль-NOP
    jnz     trace_next
    sub     bx,32h                  ;32h - смещение от dispatch handler
    cmp     word ptr ds:[bx],9090h  ;сигнатура int 21 
    jnz     check_dispatch
good_search:
    clc
    ret
check_dispatch:
    cmp     word ptr ds:[bx],2E1Eh  ;проверка на push ds, префикс cs: 
    jnz     bad_exit
    add     bx,25h                  ;25h - смещение от dispatch
    cmp     word ptr ds:[bx],80FAh  ;проверка на cli, push ax
    jz      good_search
bad_exit:
    stc
    ret

;name:      int30_trace
;на выходе:  ds:bx=адрес int 21, если CF=0
;            ds:bx=ничего, если CF=1
;purpose:   находит адрес int 21, используя INT 30/31.

int30_trace:
    xor     bx,bx
    mov     ds,bx
    mov     bl,0c0h                 ;point to 0:0c0
    jmp     short trace_next

bin_to_hex:                         ;напечатает hex число в BX
    push    cx                      ;код "позаимствован" из KRTT demo
    push    dx
    push    ax
    mov     ch,4
rotate:
    mov     cl,4
    rol     bx,cl
    mov     al,bl
    and     al,0Fh
    add     al,30h
    cmp     al,'9'+1
    jl      print_it
    add     al,07h
print_it:
    mov     dl,al
    mov     ah,2
    int     21h
    dec     ch
    jnz     rotate
    pop     ax
    pop     dx
    pop     cx
    ret

print_colon:
    mov     ah,2
    mov     dl,':'
    int     21h
    ret

    end     start

    ;-------8<--------cut here---------8<-------

; ─────────────────────────────────────────────────────────────────────────
; ──────────────── Remember Where You Saw This Phile First ────────────────
; ───────[=] ARRESTED DEVELOPMENT +31.77.3547477 The Netherlands [=]───────
; ─────────────────────────────────────────────────────────────────────────
