e-mail    Debatní kniha    Mapa stránek    Hlavní  
 perličky 
 

Boj proti virům, aneb Jak si chránit vektory

Petr Tůma

Nedávno jsem do Bajtu poslal prográmek, který brání virům v šíření. Princip spočíval v posunutí tabulky přerušovacích vektorů na jiné místo. Velice jednoduchý princip. Avšak záhy poté se mi v hlavě zrodil nový plán, jak zákeřné viry oblafnout.

Nejprve trocha teorie. Princip je opět velice jednoduchý. Spočívá v tom, že procesory i386 a výše mají vestavěný ladící hardware. Jinak řečeno -- umožňují hlídat přístupy do paměti. Jejich počet je samozřejmě omezen -- najednou lze sledovat přístupy pouze na čtyři místa paměti o maximální velikosti 32 bitů. Další omezení je v tom, že tyto breakpointy musejí ležet na adrese beze zbytku dělitelné čtyřmi. K ovládání tohoto hardwaru je procesor vybaven šesti ladícími registry: DR0--DR3, DR6 a DR7. Registry DR0 až DR3 mohou obsahovat lineární adresy čtyř sledovaných míst v paměti. Lineární adresa je to, co se objevuje na vývodech adresové sběrnice procesoru. V reálném módu se spočítá následovně -- segment*16+offset. DR7 je řídící registr a bude popsán dále. DR6 je stavový registr ladícího systému. Na i386 totiž INT může 1 vyvolat pět příčin:

  • Hardwarový beakpoint
  • Neautorizovaný přístup k ladícím registrům
  • Vnější přerušení nebo instrukce INT 1
  • Flag TF
  • Nastavený bit T v TSS při přepnutí procesu; tudíž je nutný registr, který určuje příčinu přerušení. Jednotlivé bity stavového registru DR6, pro nás zajímavé, jsou:

  bit 0:   shoda s adresou 0
      1:   shoda s adresou 1
      2:   shoda s adresou 2
      3:   shoda s adresou 3
     13:   neautorizovaný přístup k ladícím registrům
     14:  krokovací režim (nastaven TF)

Procesor registr DR6 sám nikdy nenuluje, to je starost programátora. Při kontrole čtení či zápisu dat z/do paměti je ještě dobré vědět, že procesor nejprve provede instrukci pracující s inkriminovaným místem v paměti a teprve potom přeruší program. Při kontrole výběru instrukce z dané adresy je to poněkud složitější (v perličce na to není místo). Řídící registr DR7 vypadá takto:

  31              15             0
  --------------------------------
  LLRRLLRRLLRRLLRR  G   GLGLGLGLGL
  NNWWNNWWNNWWNNWW--D---EE33221100
  3333222211110000

Jestliže je bit GD nastaven, každý další pokus o přístup k ladícím registrům vyvolá přerušení 1. V tom okamžiku se bit GD nuluje (aby se dalo zjistit, co se děje).

Bity LN a RW určují typ položky, na kterou ukazuje adresa breakpointu v příslušném ladícím registru.

  00     Výběr instrukce             00    Byte
  01     Zápis dat                   01    Word
  10     nepoužito                   10    nepoužito
  11     Čtení či zápis dat          11    Double word

Význam těchto položek je tedy celkem jasný -- jestliže chci hlídat dvouslovo proti zápisu, bude položka LN=11 a RW=01. Bity LE a GE si jsou v reálném módu rovny a určují, kdy se bude kontrolovat shoda s ladícími registry. Jestliže jsou nastaveny, testuje se shoda až při zpracování instrukce či dat, jinak při výběru z paměti. Jelikož procesor 386 a výše pracuje s proudovou architekturou, je možné, že když jsou tyto bity nenastaveny, procesor nezaregistruje breakpoint umístěný těsně za instrukci, která jej umístila. Zde je však na místě upozornit, že nastavením těchto bitů dochází ke značnému zpomalován procesoru. Bity Lx a Gx jsou si v reálném režimu opět rovny, a povolují či zakazují jednotlivé breakpointy. Je-li bit nastaven, breakpoint je sledován.

Dost však teorie a podívejme se na přiložený program. Ten nejprve otestuje, zda opravdu běží na solidním hardwaru -- když ne, vypíše hlášku a skončí. Jinak převezme interrupt 21h (kvůli nastavovaní přerušovacích vektorů) a záhy spočítá lineární adresu vektoru přerušení (to zas není tak těžké...) a naplní jimi ladící registr. Co se má obsluhovat či hlídat, se nastaví do DR7 a program se "zarezidentní". V paměti po něm zbydou jen dvě obsluhy přerušení. Ta první -- int 21h -- odchytává služby 25h a 35h, a to jen tehdy, když jde o interrupt 21h. V tom okamžiku modifikuje svoje vnitřní proměnné a okamžitě vrátí řízení zpět. V opačném případě předá řízení původní rutině int 21h. Druhá rutinka má ještě jednodušší život. Je-li aktivovaná interruptem 21h, mlčky předpokládá, že systém byl nabořen, nastaví si textový videomód, vypíše hlášku a zastaví systém. Proč je tato rutina tak nepěkně jednoduchá? Protože jinak by byla na perličku příliš veliká.

Závěrem několik možných vylepšení:

Rutina (int 1) by správně měla kontrolovat, jaká že to vůbec nastala událost, chránit si svůj vektor (int 1) a zakázat přístup k ladícím registrům. Přidat tyto věci do perličky je relativně jednoduché, ale to by z ní už byla programátorská veleperla.

(Anti)virům zdar!


comment | Program AntiVir version 1.0 by Petr Tuma (c) 1993 Tento program chrání interrupt 21h proti přepsání Využívá možnosti procesoru i386. Kompilace: TASM antivir.asm TLINK /t antivir.obj | .386p code segment use16 assume cs:code org 100h VECTOR equ 21h ; číslo vektoru LINADR2 equ VECTOR*4 ; lineární adresa hlídaného ; vektoru install: jmp start int21: cmp ah,35h ; rutina na obslouž.požadavku jne short i211 ; změny hlídaných přerušení cmp al,VECTOR jne short i212 mov es,cs:[oldint21s] mov bx,cs:[oldint21o] iret i212: cmp al,1 jne short i21no iret i211: cmp ah,25h jne short i21no cmp al,VECTOR jne short i213 mov cs:[oldint21s],ds mov cs:[oldint21o],dx iret i213: cmp al,1 jne short i21no iret i21no: jmp dword ptr cs:[oldint21o] int1: ; sem se skoci pri chybe! mov ax,3 int 10h ; nastav normální mód mov si,offset fail1mes push cs pop ds ; vypiš zprávu ex1: lodsb cmp al,0 je short x1 mov ah,0eh mov bh,0fh int 10h jmp short ex1 x1: jmp short x1 fail1mes: db 'AntiVirus: Unexpected (Non-DOS) ' db 'access to protected' db ' interrupt or unauthorized',0dh,0ah db 'access to system!!!' db 0dh,0ah,'System halted',0 oldint21o dw 0 oldint21s dw 0 ; tady končí rezidentní část start: call is386 mov ax,2501h push cs pop ds mov dx,offset int1 int 21h ; nová obsluha vektoru 1 mov ax,3521h int 21h mov cs:[oldint21o],bx mov cs:[oldint21s],es push cs pop ds mov dx,offset int21 mov ax,2521h int 21h ; nová obsluha vekt. 21h mov eax,LINADR2 mov dr1,eax xor eax,eax mov dr6,eax mov eax,00000000110100000000000000001100b mov dr7,eax ; sledovací systém zapnut mov ah,9 push cs pop ds mov dx,offset text int 21h ; vypiš text mov ax,3100h mov dx,(start-install)/10h+11h int 21h ; konec, jsem rezidentní is386: ; testuj, zda je přítomen příslušný hardware push sp pop ax cmp ax,sp ; je přítomen 8086? jne short no386 ; ano, konec mov ax,3506h int 21h ; přesměr.vekt.UNKNOWN INSTRUCTION mov cs:[oldint21o],bx mov cs:[oldint21s],es mov ax,2506h push cs pop ds mov dx,offset only286 int 21h xor eax,eax ; je to 386? mov ds,cs:[oldint21s] ; ano, vrať vektor mov dx,cs:[oldint21o] mov ax,2506h int 21h retn only286: mov ds,cs:[oldint21s] ; pouze Intel286, ; vrať vektor mov dx,cs:[oldint21o] mov ax,2506h int 21h no386: mov ah,9 ; není Intel386, vypiš hlášku push cs pop ds mov dx,offset mes1 int 21h mov ax,4c01h int 21h ; zpět do systému, kód chyby->1 text: db 'AntiVirus version 1.0' db ' by Petr Tuma (c) 1993',0dh,0ah db 'INT21h Checking service is instaled' db 0dh,0ah,'$' mes1: db 'No i386 CPU present !',0dh,0ah,'$' code ends end install


Pascal - hlavní
Překladače
Vlastní články
Převzaté články
Věci na stáhnutí
Odkazy k tématu
BP7 buglist
Chyba Run-time 200

BASIC