Formy zraniteľností v programoch a ich možné zneužitie - 1.časť

Formy zraniteľností v programoch a ich možné zneužitie - 1.časť
02.06.2009 01:40 | Články | 123_

Nezávisle na zvolenom programovacom jazyku, výsledné programy sú komplexným súborom pravidiel, ktoré jednoznačne určujú počítaču čo má "robiť". Exploitovanie programov je spôsob, ako povedať počítaču čo má robiť, aj napriek tomu, že bol práve bežiaci program vytvorený, aby zabránil danému spôsobu. Nakoľko program dokáže robiť len to, k čomu bol vytvorený, bezpečnostné diery sú výsledkom chýb alebo nepozorností vziknutých vo fáze písana zdrojového kódu programu.

Väčšina exploitov využíva pre útok tzv. memory corruption. Sem môžeme zaradiť exploitovacie techniky ako pretečenie zásobníka (buffer overflow) alebo zneužitie formátovacích reťazcov (format strings exploit). V ďaľších častiach si oba spôsoby názorne predvedieme. Využitím týchto techník sleduje útočník jediný cieľ, a to získať kontrolu nad vykonávacím tokom cieľového programu tým, že ho prinúti vykonať prepašovaný kód v pamäti počítača.

Samozrejme, aby sme mohli začať skúmať programy a hľadat ich zraniteľnosti, musíme disponovať určitými vedomosťami a zručnosťami. V prvom rade je potrebná znalosť vyššieho programovacieho jazyka ( v našom seriály sa zameriame na jazyk C ) a tiež istá znalosť nižšieho programovacieho jazyka, assemblera ( zameráme sa na inštrukčné sady procesorov x86 ). Pracovať budeme v prostredi operačného systému založenom na GNU/Linux, ku práci budeme potrebovať kompilátor (gcc), debugger (gdb), použijeme aj nástroj objdump. V neposlednom rade budeme potrebovať aj prostredie perlu, ktorý využijeme na zjednodušenie vstupných parametrov pre naše zraneniteľné programy. Samozrejmosťou je editor, odporúčam Vim s konfigurákom Cream, ktorý je vhodný aj pre úplných začiatočníkov.

Najprv si napíšeme veľmi jednoduchý program, ktorý následne prejdeme objdumpom a debuggerom.

#include <stdio.h>

int main() {
    int i;
    for(i=0;i<10;i++)
        puts("Hello World!");
    return 0;
}

Program 10 krát vypíše reťazec Hello World! a oznámi (return 0;), že prebehol bez chýb. Uložme si ho ako hello.c Program teraz skompilujeme.

$ gcc -o hello hello.c

Prostredníctvom prepínača -o určíme výstupný súbor kompilácie. Po spustení programu dostaneme nasledujúci výstup.

 

$ ./hello
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

 

Pozrime sa na strojový kód, do ktorého bola funkcia main() preložená. Použijeme príkaz objdump, ktorého výstup cez pipe bude vstupom príkazu grep. Nakoľko sa budeme venovať procesorom x86, objdumpu prepínačom -M oznámime, aby pre výstup použil Intel syntax. Defaultne je použitá AT&T syntax.

 

$ objdump -M intel -D hello | grep -A20 main.:

 

080483a4 <main>:
 80483a4:       8d 4c 24 04             lea    ecx,[esp+0x4]
 80483a8:       83 e4 f0                and    esp,0xfffffff0
 80483ab:       ff 71 fc                push   DWORD PTR [ecx-0x4]
 80483ae:       55                      push   ebp
 80483af:       89 e5                   mov    ebp,esp
 80483b1:       51                      push   ecx
 80483b2:       83 ec 14                sub    esp,0x14
 80483b5:       c7 45 f8 00 00 00 00    mov    DWORD PTR [ebp-0x8],0x0
 80483bc:       eb 10                   jmp    80483ce <main+0x2a>
 80483be:       c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483c5:       e8 0a ff ff ff          call   80482d4 <puts@plt>
 80483ca:       83 45 f8 01             add    DWORD PTR [ebp-0x8],0x1
 80483ce:       83 7d f8 09             cmp    DWORD PTR [ebp-0x8],0x9
 80483d2:       7e ea                   jle    80483be <main+0x1a>
 80483d4:       b8 00 00 00 00          mov    eax,0x0
 80483d9:       83 c4 14                add    esp,0x14
 80483dc:       59                      pop    ecx
 80483dd:       5d                      pop    ebp
 80483de:       8d 61 fc                lea    esp,[ecx-0x4]
 80483e1:       c3                      ret    

Čísla v šestnástkovej sústave na ľavej strane výpisu predstavujú pamäťové adresy. Pamäť je súborom bajtov, pričom každý z nich ma svoju vlastnú adresu. Ku každému z týchto bajtov sa pristupuje na základe jeho adresy a v tomto prípade CPU pristupuje k tejto časti pamäti, aby získal inštrukcie, ktoré tvoria skompilovaný program. Čisla v ďalšom stĺpci sú inštrukcie v strojovom kóde pre x86 procesor. Samozrejme sú len reprezentáciou binárnych čísiel, ktorým CPU skutočne rozumie. Inštrukcie na pravej strane sú v assemblery pre x86 procesory. Inštrukcie assemblera majú priamy vzťah jedna ku jednej k príslušej inštrukcii strojového kódu. Procesory majú aj sadu špeciálnych premenných, ktoré nazývame registre. Ukážeme si ich pomocou debuggera. Debuggery sa využívajú na prechádzanie skompilovanými programami, na preskúmanie pamäte a prehľad registrov procesora. Príkazom echo "set dis intel" > ~/.gdbinit nastavíme, že GDB bude pri svojom behu používať Intel syntax. Alternatívnym riešením je po každom spustení vykonať (gdb) set dis intel

 

$ gdb -q hello

 

(gdb) break main 
Breakpoint 1 at 0x80483b2
(gdb) run
Starting program: /1/hello 

Breakpoint 1, 0x080483b2 in main ()
Current language:  auto; currently asm
(gdb) info registers 
eax            0xbfd5d564       -1076505244
ecx            0xbfd5d4e0       -1076505376
edx            0x1      1
ebx            0xb7f20ff4       -1208872972
esp            0xbfd5d4c4       0xbfd5d4c4
ebp            0xbfd5d4c8       0xbfd5d4c8
esi            0x8048400        134513664
edi            0x80482f0        134513392
eip            0x80483b2        0x80483b2 <main+14>
eflags         0x200282 [ SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) quit
The program is running.  Exit anyway? (y or n) y

Nastavili sme si breakpoint na funkciu main(). Následne GDB spustí program, zastaví sa pri breakpointe a vypíše informácie o registroch.Prvé štyri registre EAX(accumulator), ECX(counter), EDX(data) a EBX(base) sú nazývané General Purpose Registers(všeobecné registre). Používajú sa na viaceré účely, ale hlavne ako dočasné premenné pre CPU vo fáze vykonávania strojových inštrukcií. Nasledujúce štyri registre ESP(stack pointer), EBP(base pointer), ESI(source index) a EDI(destination index) sú tiež General Purpose Registers. Sú známe aj ako smerníky a indexy. Prvé dva sa nazývajú smerníky, pretože sú v nich uložené 32bit adresy, ktoré ukazujú na umiestnenie v pamäti. Zvyšné dva registre ukazujú odkiaľ sa má čítať a kam sa má zapisovať, čiže technicky sú to tiež smerníky. EIP(instruction pointer) register ukazuje na momentálnu inštrukciu, ktorú procesor číta. EFLAGS register sa skladá z niekoľkých bit-flagov, ktoré sa používajú na porovnávanie a segmentáciu pamäte. Teraz sa trochu zameriame na samotný assembler. Nie som s ním velký kamarát, ale pokúsim sa ho trošku ozrejmiť, nakoľko porozumenie inštrukcií je dôležité pri odhaľovaní zraniteľností. Intel syntax sa riadi štýlom inštrukcia <cieľ>, <zdroj>. Cieľ a zdroj sú buď register, adresa pamäte alebo hodnota. Napríklad inštrukcia mov presunie hodnotu zo zdroja do cieľa, sub bude odčítavať atď. Uvediem si zopár príkladov.

80483af:        89 e5                   mov    ebp,esp   // inštrukcia mov presunie ESP do EBP
80483b1:        51                      push   ecx       // push uloží ECX do stacku(utriedený zoznam prvkov na princípe LIFO)
80483b2:        83 ec 14                sub    esp,0x14  // a následne sub odčíta 14 z ESP a výsledok uloží do ESP


80483ce:        83 7d f8 09             cmp    DWORD PTR [ebp-0x8],0x9  // cmp porovná DWORD hodnotu z EBP mínus 8 s číslom 9
80483d2:        7e ea                   jle    80483be <main+0x1a>      // ak je hodnota menšia alebo rovná 9 (jump less then equal),vykonávanie skočí na inštrukciu v 0x80483be 
80483d4:        b8 00 00 00 00          mov    eax,0x0                  // ak hodnota nie je <=9, presunie sa hodnota 0 do EAX

Použijeme debugger, aby sme si predchádzajúce vedomosti vyskúšali v praxi. Prepínač -g použitý s GCC umožní pridať extra informácie pre debugger, ktoré umožnia debuggeru prístup k zdrojovému kódu, ktorý príkazom (gdb) list môžeme dať vypísať. Tento príkaz nebudem demonštrovať, vyskúšajte si ho sami.

$ gcc -g -o hello hello.c
$ gdb -q hello
(gdb) disassemble main
Dump of assembler code for function main:
0x080483a4 <main+0>:	lea    ecx,[esp+0x4]
0x080483a8 <main+4>:	and    esp,0xfffffff0
0x080483ab <main+7>:	push   DWORD PTR [ecx-0x4]
0x080483ae <main+10>:	push   ebp
0x080483af <main+11>:	mov    ebp,esp
0x080483b1 <main+13>:	push   ecx
0x080483b2 <main+14>:	sub    esp,0x14
0x080483b5 <main+17>:	mov    DWORD PTR [ebp-0x8],0x0
0x080483bc <main+24>:	jmp    0x80483ce <main+42>
0x080483be <main+26>:	mov    DWORD PTR [esp],0x80484b0
0x080483c5 <main+33>:	call   0x80482d4 <puts@plt>
0x080483ca <main+38>:	add    DWORD PTR [ebp-0x8],0x1
0x080483ce <main+42>:	cmp    DWORD PTR [ebp-0x8],0x9
0x080483d2 <main+46>:	jle    0x80483be <main+26>
0x080483d4 <main+48>:	mov    eax,0x0
0x080483d9 <main+53>:	add    esp,0x14
0x080483dc <main+56>:	pop    ecx
0x080483dd <main+57>:	pop    ebp
0x080483de <main+58>:	lea    esp,[ecx-0x4]
0x080483e1 <main+61>:	ret     
End of assembler dump.
(gdb) break main
Breakpoint 1 at 0x80483b5: file hello.c, line 4.
(gdb) run
Starting program: /1/hello 

Breakpoint 1, main () at hello.c:4
4               for(i=0;i<10;i++)
(gdb) info register eip
eip            0x80483b5	0x80483b5 <main+17>
(gdb) 

Breakpoint sme nastavili na funkciu main() a následne vypíšeme hodnotu EIP, ktorá obsahuje adresu, ktorá ukazuje na zvýraznenú inštrukciu. Inštrukcie nachádzajúce sa pred týmto miestom, sú známe ako prológ a sú generované kompilátorom na vymedzenie pamäťového miesta pre zvyšné lokálne premenné funkcie. Debugger poskytuje priamy spôsob preskúmania pamäte prostredníctvom príkazu x. Tento príkaz umožňuje pozrieť sa na určitú adresu v pamäti. Potrebuje dva argumenty - akým spôsobom má zobraziť informácie a miesto v pamäti na preskúmanie. Formáty sú nasledovné: o (zobraziť v osmičkovej sústave), x (zobraziť v 16kovej sústave), u (zobraziť v unsigned 10kovej sústave), t (zobraziť v binárnej sústave). Vyzerá to nasledovne:

(gdb) x/o $eip
0x80483b5 :     076042707
(gdb) x/x $eip
0x80483b5 :     0x00f845c7
(gdb) x/u $eip
0x80483b5 :     16270791
(gdb) x/t $eip
0x80483b5 :     00000000111110000100010111000111
(gdb) 

Pred formátom výpisu možeme použiť číslo na preskúmanie jednotiek na danej adrese. Defaultná veľkosť jednotky je 4bajtová jednotka nazývaná word. Veľkosť zobrazených jednotiek môžeme zmeniť pridaním písmena na koniec formátu: b (bajt), h (halfword, 2bajty), w (word, 4bajty), g (tzv. giant, 8bajtov). Termín word sa používa aj na označenie 2bajtových hodnôt a termín DWORD sa používa na označenie 4bajtových hodnôt. Ukážka na príklade:

(gdb) x/8xb $eip
0x80483b5 <main+17>:	0xc7	0x45	0xf8	0x00	0x00	0x00	0x00	0xeb
(gdb) x/8xh $eip
0x80483b5 <main+17>:	0x45c7	0x00f8	0x0000	0xeb00	0xc710	0x2404	0x84b0	0x0804
(gdb) x/8xw $eip
0x80483b5 <main+17>:	0x00f845c7	0xeb000000	0x2404c710	0x080484b0
0x80483c5 <main+33>:	0xffff0ae8	0xf84583ff	0xf87d8301	0xb8ea7e09

Teraz si výpis pozorne prejdite predtým, ako začnete čítať ďalej. Všimli ste si niečo zaujímavé? Prvý príkaz zobrazí prvých osem bajtov, čím väčšie jednotky zobrazujeme, tým je logicky viac údajov. Prvý výpis obsahuje prvé dva bajty 0xc7 a 0x45. Ale keď si pozrieme halfword na tej iste adrese, dostaneme hodnotu 0x45c7, čiže s prehodenými bajtmi. Podobne si túto reverziu môžeme všimnút pri 4bajtovej hodnote 0x00f845c7. Je to spôsobené tým, že hodnoty na x86 procesoroch sú uložené v tzv. little endian bajtovom usporiadaní, čo znamená, že najmenej významný bajt, alebo least significant byte, je uložený na najnižšej adrese. Na záver prvého dielu sa ešte trošku pohráme s debuggerom. Ten nám umožňuje použitím formátovacieho znaku i vypísať obsah pamäte ako inštrukciu assemblera:

(gdb) x/i $eip
0x80483b5 <main+17>:     mov    DWORD PTR [ebp-0x8],0x0

Ak si pozriete znova výstup objdumpu, zistíte, že 7bajtov, na ktoré EIP ukazuje, je príslušná inštrukcia assemblera v strojovom kóde. Inštrukcia presunie hodnotu 0 do pamäte, ktorá sa nachádza na adrese uloženej v EBP mínus 8. Presne tu je uložená naša premenná i z funkcie main(). Táto inštrukcia v podstate vynuluje premennú i pre cyklus.

(gdb) info register ebp
ebp            0xbf9758e8       0xbf9758e8
(gdb) print $ebp-8
$1 = (void *) 0xbf9758e0
(gdb) x/xw $1
0xbf9758e0:     0xb7f6b250

EBP obsahuje adresu 0xbf9758e8 a inštrukcia zapíše do hodnoty o 8 nižšej 0xbf9758e0. Príkaz print uloží výsledok operácie do dočasnej premennej $1, ku ktorej môžeme neskôr pristupovať. Posuňme sa ďalej v našom programe. Príkaz nexti vypíše ďalšiu inštrukciu. CPU prečíta inštrukciu v EIP, vykoná ju a posunie EIP na ďalšiu inštrukciu.

(gdb) nexti
0x080483bc      4               for(i=0;i<10;i++)
(gdb) x/dw $1
0xbf9758e0:     0   // dôkaz o vynulovaní miesta v pamäti ebp-8

Prejdime si ďalšie inštrukcie, z ktorých nám pomaly bude jasnejšia postupnosť a logika inštrukcií.

(gdb) x/12i $eip
0x80483bc <main+24>:	jmp    0x80483ce <main+42>
0x80483be <main+26>:	mov    DWORD PTR [esp],0x80484b0
0x80483c5 <main+33>:	call   0x80482d4 <puts@plt>
0x80483ca <main+38>:	add    DWORD PTR [ebp-0x8],0x1
0x80483ce <main+42>:	cmp    DWORD PTR [ebp-0x8],0x9
0x80483d2 <main+46>:	jle    0x80483be <main+26>
0x80483d4 <main+48>:	mov    eax,0x0
0x80483d9 <main+53>:	add    esp,0x14
0x80483dc <main+56>:	pop    ecx
0x80483dd <main+57>:	pop    ebp
0x80483de <main+58>:	lea    esp,[ecx-0x4]
0x80483e1 <main+61>:	ret  

Nasledujúca inštrukcia jmp je tzv. unconditional jump na adresu 0x80483ce. Na danej adrese máme inštrukciu cmp, ktorá porovnáva našu premennú i s číslom 9. Nasleduje podmienka "jump if less or equal". Ak je podmienka i<=9 splnená, skočí na adresu 0x80483be, ktorá sa nachádza za fixným jumpom. Inštrukcia call zavolá puts() funkciu, add pripočíta k adrese uloženej v ebp-8 hodnotu 1 a následne sa ide opäť porovnávať. Ak podmienka nebude splnená, vykoná sa inštrukcia mov eax,0x0, ktorá presunie hodnotu 0 do EAX na ukončenie programu. Zvyšné inštrukcie sú tzv. epilóg, ktorý zruší kroky, ktoré vykonal prológ (sub esp,0x14/add esp,0x14 ; push ecx/pop ecx atď).
Nakoľko vieme,že na adrese, ktorá sa porovnáva s 9 je uložená 0, EIP by mala ukazovať na 0x80483be po vykonaní ďalšich dvoch inštrukcií.

(gdb) nexti
0x080483d2      4               for(i=0;i<10;i++)
(gdb) nexti
5                       puts("Hello World!");
(gdb) info register eip
eip            0x80483be        0x80483be <main+26>
(gdb) x/i $eip
0x80483be :     mov    DWORD PTR [esp],0x80484b0

Inštrukcia mov zapíše adresu 0x80484b0 do pamäťovej adresy v ESP, ale kam ESP ukazuje, zistíme nasledovne:


(gdb) info register esp
esp            0xbf9758d0       0xbf9758d0

ESP momentálne ukazuje na adresu 0xbf9758d0, takže po vykonaní inštrukcie mov sa tam zapíše adresa 0x80484b0. Je len na nás, aby sme zistili, prečo je táto adresa zaujímavá.


(gdb) x/8xb 0x80484b0
0x80484b0:      0x48    0x65    0x6c    0x6c    0x6f    0x20    0x57    0x6f
(gdb) x/8ub 0x80484b0
0x80484b0:      72      101     108     108     111     32      87      111

Ak sa pozrieme do ASCII tabuľky, zistíme, že naše bajty korešpondujú s konkrétnymi znakmi. Použijeme ďalšie formátovacie znaky c, ktorý vyhľadá bajt v ASCII tabuľke a s, ktorý nám zobrazí celý reťazec:


(gdb) x/8cb 0x80484b0
0x80484b0:      72 'H'  101 'e' 108 'l' 108 'l' 111 'o' 32 ' '  87 'W'  111 'o'
(gdb) x/s 0x80484b0
0x80484b0:       "Hello World!"

Výstup príkazu nám ukazuje, že na adrese 0x80484b0 sa nachádza reťazec Hello World!.

V druhej časti seriálu, ktorý bude menej nezáživný, sa budeme zaoberať segmentáciou pamäte a pripravíme sa na techniky exploitovania, ktoré si predstavíme v tretej časti seriálu.

    • Re: 02.06.2009 | 13:58
      mucha   Návštevník
      Vyborne, cakame dalsiu cast.
      Nie prilis jednoduche veci, podane dost zrozumitelnym jazykom ...

      Vdaka !
    • Dopohody clanok ale.. 03.06.2009 | 00:03
      luzr   Návštevník
      ..navrhujem tu pridat anketu s dvoma moznostami: "pochopil som" a "nepochopil som" :) Neverim, ze prva moznost ziska viac ako 10 hlasov lebo clovek bez predchadzajucej skusenosti s assemblerom sa proste nechyti.
      • Re: Dopohody clanok ale.. 03.06.2009 | 10:37
        Avatar Lapajko Arch Linux  Používateľ
        Nie každý článok musí písať o základoch danej témy.
        Základy assembleru získať veľmi ľahko, návody sú všade. Ak ťa zaujíma napr. reverzné inžinierstvo, tak si snáď ochotný obetovať trochu času assembleru bez toho, aby bol ten tutorial na linuxos
        • Re: Dopohody clanok ale.. 03.06.2009 | 10:37
          Avatar Lapajko Arch Linux  Používateľ
          Základy assembleru získať veľmi ľahko, návody sú všade ==> Základy assembleru môžeš získať veľmi ľahko, návody sú všade.
      • Re: Dopohody clanok ale.. 05.06.2009 | 16:28
        Avatar srigi   Používateľ
        Ak vykladu nerozumies, doporucujem ti tuto knihu a ak si pokrocilejsi uzivatel, prejdi rovno na stranu 55. Je tam velmi pekny vyklad C programu v ASM.

        Dobrym introm do GNU debugeru je zase tato kniha.

        Inak musim napisat, ze mnou uvedene linky su omnoho zrozumitelnejsie ako tento clanok.
        • Re: Dopohody clanok ale.. 05.06.2009 | 17:47
          123   Návštevník
          podstata tohto clanku nespociva vysvetlit alebo naucit niekoho programovat v assemblery, ja sam v tom nie som bohvieco....dolezite je vediet citat kod, aby bolo mozne identifikovat miesta v pamati, ktore obsahuju napadnutelne udaje...takze ak je to az moc nezrozumitelne, tak sori:) ked sa dostanem k pokracovaniam, tak to uz bude ako som spominal snad zazivnejsie :)
      • Re: Dopohody clanok ale.. 20.07.2009 | 18:05
        fsadgasdfgad   Návštevník
        pripocitaj si 1 k "pochopil som" bez znalosti ASM.
    • Re: 03.06.2009 | 13:33
      Avatar pejta Archlinux  Používateľ
      vdaka za pekný článok, dufam že sa dočkám pokračovania :-)
    • The Art of exploitation 11.06.2009 | 13:30
      Avatar HurriHawk   Používateľ
      Ak cakate na dalsiu cast precitajte si do Johna Ericcsona Hacking - The Art of exploitation a mate to rovno cely serial prejdeny }:-) uvítal by som aspon oznamenie ze ide preklad alebo zostrucnenie dotycnej knihy.
      • Re: The Art of exploitation 11.06.2009 | 14:46
        123   Návštevník
        predtym nez nieco napises ty blbecek tak si to radsej premysli....knihu samozrejme poznam a poznam aj mnohe ine.....nakolko si sa nejakou wannabie nahodou dostal prave k tejto knizke, tak vobec nemas ponatia o tom, ze skoro v kazdej podobnej knizke sa rozobera Hello World.....zistis, ze je to skoro navlas rovnake...ja by som z tvojej strany uvital, aby si tu nepisal picoviny
        • Re: The Art of exploitation 11.06.2009 | 22:36
          Avatar HurriHawk   Používateľ
          sry ak som Ta urazil
          • Re: The Art of exploitation 11.06.2009 | 23:46
            123   Návštevník
            nie neurazil...len mam teraz strasne vela toho a som strasne podrazdeny....ospravedlnujem sa ti za reakciu, naozaj nemam za potreby obhajovat svoje vedomosti, ale ono toto bol let letmy uvod do problematiky, ked si zoberies hociaku inu oblast, zoberies k tomu knizky, uvody sa velmi podobaju, lebo su o tom istom....a naozaj debugovat hello world + pokec o registroch sa tazko napise roznymi sposobmi...su to postupy a pojmy, ktorych sa treba drzat....
            • Re: The Art of exploitation 12.06.2009 | 01:03
              HurriHawk   Návštevník
              oks v pohode ja som tiez nereagoval najprivetivejsie. Budem rad ak budes pokracovat v seriali. Predsalen, pre niekoho je pohodlnejsie si to citat na internete nez z knihy.
    • hmm 17.06.2009 | 00:41
      Jarda   Návštevník
      >> EIP(instruction pointer) register ukazuje na momentálnu inštrukciu, ktorú procesor číta

      Jenom bych doplnil, že se nejedná o ukazatel na aktuálně prováděnou instrukci, ale na tu následující po aktuálně prováděné!

      PS: sedem * štyri, takový těžký počty v ochraně proti spamu ... co třeba jedna + jedna?
    • mov 27.02.2010 | 23:16
      Avatar Fridolín Pokorný Fedora 21  Používateľ
      "...Napríklad inštrukcia mov presunie hodnotu zo zdroja do cieľa..."
      Nie, instrikcia mov kopiruje.