Hacking Sztuka penetracji Wydanie II

background image

Wydawnictwo Helion

ul. Koœciuszki 1c

44-100 Gliwice

tel. 032 230 98 63

e-mail: helion@helion.pl

Hacking. Sztuka

penetracji. Wydanie II

Autor: Jon Erickson

T³umaczenie: Marcin Rogó¿

ISBN: 978-83-246-1802-6

Tytu³ orygina³u:

Hacking:

The Art of Exploitation, 2nd Edition

Format: 170x230, stron: 520

Zdob¹dŸ wiedzê godn¹ hakera!

Co trzeba wiedzieæ, aby byæ hakerem?

Jak ³amaæ has³a?

Jak uzyskaæ dostêp do zabezpieczonej sieci bezprzewodowej?

S³owo haker kojarzy nam siê z komputerowym mistrzem manipulacji Kevinem

Mitnickiem. Pojêcie to jednak ewoluowa³o od czasu jego spektakularnych akcji. Zatem

kim jest dziœ haker? Wbrew obiegowej opinii, wiêkszoœæ hakerów nie wykorzystuje swej

wiedzy do niecnych celów. Dziêki swej wiedzy i dociekliwoœci przyczyniaj¹ siê do

rozwoju bezpieczeñstwa sieci i programów. Nikt bowiem nie potrafi tak jak oni zg³êbiaæ

sposoby dzia³ania zaawansowanego oprogramowania i sprzêtu i tropiæ luki pozwalaj¹ce

na atak lub wyciek danych oraz przewidywaæ mo¿liwe problemy w ich dzia³aniu.
Jon Erickson w ksi¹¿ce Hacking. Sztuka penetracji. Wydanie II omawia te zagadnienia

ze œwiata informatyki, które nie mog¹ byæ obce hakerowi. Dziêki tej ksi¹¿ce poznasz

m.in. podstawy jêzyka C oraz dowiesz siê, jak wykorzystaæ jego s³aboœci

oraz potkniêcia programistów pisz¹cych w tym jêzyku. Zapoznasz siê z podstawami

funkcjonowania sieci i zdobêdziesz wiedzê o modelu OSI, a tak¿e nauczysz siê

pods³uchiwaæ transmitowane w sieci dane, skanowaæ porty i ³amaæ has³a.

Programowanie w jêzyku C

Model OSI

Pods³uchiwanie sieci

Skanowanie portów

Sposoby ³amania hase³

Szyfrowanie danych i po³¹czeñ

Sposoby atakowania sieci bezprzewodowych

Oto elementarz prawdziwego hakera!

background image

S P I S T R E C I

PRZEDMOWA 11

PODZIKOWANIA 12

0X100 WPROWADZENIE

13

0X200 PROGRAMOWANIE

19

0x210 Istota

programowania .....................................................................................20

0x220 Pseudokod ......................................................................................................22
0x230 Struktury sterujce ...........................................................................................22

0x231 If-Then-Else ........................................................................................22
0x232 Ptle

While/Until ................................................................................24

0x233 Ptle for .............................................................................................25

0x240 Podstawowe pojcia programistyczne .............................................................26

0x241 Zmienne .............................................................................................26
0x242 Operatory arytmetyczne .....................................................................27
0x243 Operatory

porównania .......................................................................28

0x244 Funkcje

...............................................................................................30

0x250 Zaczynamy brudzi sobie rce ..........................................................................34

0x251 Wikszy

obraz ....................................................................................35

0x252 Procesor

x86 ......................................................................................38

0x253 Jzyk

asembler ...................................................................................40

0x260 Wracamy do podstaw .....................................................................................53

0x261 acuchy ............................................................................................53
0x262 Ze znakiem, bez znaku, duga i krótka ................................................57
0x263 Wskaniki

...........................................................................................59

0x264 acuchy

formatujce

.........................................................................63

background image

6

Hacking. Sztuka penetracji

0x265 Rzutowanie

typów .............................................................................67

0x266 Argumenty wiersza polece ...............................................................74
0x267 Zasig

zmiennych

...............................................................................78

0x270 Segmentacja

pamici

.......................................................................................85

0x271 Segmenty pamici w jzyku C ............................................................92
0x272 Korzystanie ze sterty ...........................................................................94
0x273 Funkcja malloc() ze sprawdzaniem bdów .........................................96

0x280 Budujemy na podstawach ...............................................................................98

0x281 Dostp do plików ...............................................................................98
0x282 Prawa dostpu do plików .................................................................104
0x283 Identyfikatory

uytkowników

............................................................105

0x284 Struktury ..........................................................................................114
0x285 Wskaniki do funkcji .........................................................................117
0x286 Liczby

pseudolosowe

........................................................................118

0x287 Gry

hazardowe

.................................................................................120

0X300 NADUYCIA

133

0x310 Uogólnione techniki naduy .........................................................................136
0x320 Przepenienia

bufora

......................................................................................137

0x321 Luki zwizane z przepenieniem stosowym .......................................140

0x330 Eksperymenty z BASH ....................................................................................152

0x331 Wykorzystanie

rodowiska ...............................................................161

0x340 Przepenienia w innych segmentach ..............................................................170

0x341 Podstawowe przepenienie na stercie ...............................................170
0x342 Przepenienia wskaników funkcyjnych .............................................176

0x350 acuchy

formatujce

....................................................................................187

0x351 Parametry

formatujce .....................................................................188

0x352 Podatno cigów formatujcych na ataki ........................................190
0x353 Odczyt spod dowolnych adresów pamici ........................................192
0x354 Zapis pod dowolnymi adresami pamici ...........................................193
0x355 Bezporedni dostp do parametrów .................................................201
0x356 Uycie zapisu krótkich liczb cakowitych ...........................................203
0x357 Obejcia z uyciem sekcji dtors .........................................................205
0x358 Kolejny saby punkt programu notesearch ........................................210
0x359 Nadpisywanie globalnej tabeli przesuni ........................................212

0X400 SIECI

217

0x410 Model

OSI .....................................................................................................217

0x420 Gniazda

.........................................................................................................220

0x421 Funkcje

obsugujce

gniazda ............................................................221

0x422 Adresy

gniazd ..................................................................................223

0x423 Sieciowa

kolejno

bajtów

................................................................224

0x424 Konwersja adresu internetowego .....................................................225

background image

Spis treci

7

0x425 Prosty przykad serwera ....................................................................226
0x426 Przykad klienta WWW .....................................................................230
0x427 Maleki serwer WWW ......................................................................235

0x430 Zagldamy do niszych warstw .....................................................................240

0x431 Warstwa

cza

danych

......................................................................240

0x432 Warstwa

sieci

...................................................................................242

0x433 Warstwa

transportowa

.....................................................................244

0x440 Podsuchiwanie

w

sieci

..................................................................................247

0X441 Sniffer surowych pakietów ...............................................................249
0x442 Sniffer

libpcap ..................................................................................251

0x443 Dekodowanie

warstw ......................................................................253

0x444 Aktywne

podsuchiwanie .................................................................263

0x450 Odmowa

usugi

.............................................................................................276

0x451 Zalew pakietów SYN (SYN Flooding) .................................................276
0x452 Atak Ping of Death ...........................................................................281
0x453 Atak

Teardrop ..................................................................................281

0x454 Zalew pakietów ping (Ping Flooding) ................................................281
0x455 Atak ze wzmocnieniem (Amplification) .............................................282
0x456 Rozproszony atak DoS ......................................................................283

0x460 Przejcie

TCP/IP .............................................................................................283

0x461 Rozczanie za pomoc RST ..............................................................283
0x462 Przejcie z kontynuacj .....................................................................289

0x470 Skanowanie

portów ......................................................................................289

0x471 Ukryte skanowanie SYN ....................................................................289
0x472 Skanowanie FIN, X-mas i Null ...........................................................290
0x473 Skanowanie z ukrycia .......................................................................290
0x474 Skanowanie z uyciem bezczynnego komputera ...............................291
0x475 Zabezpieczenie wyprzedzajce (Shroud) ...........................................293

0x480 Id i wam si gdzie .....................................................................................298

0x481 Analiza z uyciem GDB .....................................................................299
0x482 Prawie ma znaczenie ........................................................................301
0x483 Shellcode wicy port .....................................................................304

0X500 SHELLCODE

309

0x510 Asembler a C .................................................................................................309

0x511 Linuksowe wywoania systemowe w asemblerze .............................312

0x520 cieka do shellcode ......................................................................................315

0x521 Instrukcje asemblera wykorzystujce stos .........................................315
0x522 Badanie za pomoc GDB ..................................................................317
0x523 Usuwanie

bajtów

zerowych

..............................................................319

0x530 Kod

wywoujcy

powok

..............................................................................324

0x531 Kwestia

uprawnie

...........................................................................328

0x532 Skracamy

jeszcze

bardziej

.................................................................331

background image

8

Hacking. Sztuka penetracji

0x540 Kod powoki wicy port .............................................................................332

0x541 Duplikowanie standardowych deskryptorów plików .........................336
0x542 Rozgaziajce struktury sterujce ....................................................338

0x550 Shellcode nawizujcy poczenie powrotne .................................................343

0X600 RODKI

ZAPOBIEGAWCZE

349

0x610 rodki zapobiegawcze, które wykrywaj .......................................................350
0x620 Demony

systemowe ......................................................................................351

0x621 Byskawiczne wprowadzenie do sygnaów .......................................352
0x622 Demon

tinyweb

................................................................................354

0x630 Narzdzia

pracy

.............................................................................................358

0x631 Narzdzie naduywajce tinywebd ...................................................359

0x640 Pliki

dziennika ...............................................................................................364

0x641 Wmieszaj si w tum ........................................................................365

0x650 Przeoczywszy

oczywiste ................................................................................366

0x651 Krok po kroku ...................................................................................367
0x652 Ponowne skadanie wszystkiego ......................................................371
0x653 Robocze procesy potomne ................................................................377

0x660 Zaawansowana sztuka kamuflau .................................................................378

0x661 Faszowanie rejestrowanego adresu IP .............................................379
0x662 Nierejestrowane

naduycie

...............................................................383

0x670 Caa

infrastruktura

.........................................................................................386

0x671 Ponowne

wykorzystanie

gniazda

......................................................386

0x680 Przemyt

adunku

............................................................................................390

0x681 Kodowanie

acuchów .....................................................................391

0x682 Jak ukry puapk? ...........................................................................394

0x690 Ograniczenia

bufora ......................................................................................395

0x691 Polimorficzny kod powoki z drukowalnymi znakami ASCII ...............397

0x6a0 Zabezpieczenia

wzmacniajce .......................................................................408

0x6b0 Niewykonywalny

stos

....................................................................................408

0x6b1 Powracanie do funkcji biblioteki libc .................................................409
0x6b2 Powrót do funkcji system() ...............................................................409

0x6c0 Randomizacja przestrzeni stosu .....................................................................411

0x6c1 Badanie za pomoc BASH i GDB .......................................................413
0x6c2 Odbijanie od linux-gate ....................................................................417
0x6c3 Wiedza

stosowana

...........................................................................420

0x6c4 Pierwsza

próba

.................................................................................421

0x6c5 Gramy w koci ..................................................................................422

0X700 KRYPTOLOGIA

425

0x710 Teoria informacji ............................................................................................426

0x711 Bezwarunkowe

bezpieczestwo .......................................................426

0x712 Szyfr z kluczem jednorazowym .........................................................426

background image

Spis treci

9

0x713 Kwantowa dystrybucja kluczy ...........................................................427
0x714 Bezpieczestwo

obliczeniowe

...........................................................428

0x720 Rozlego

algorytmów .................................................................................429

0x721 Notacja asymptotyczna .....................................................................430

0x730 Szyfrowanie

symetryczne

...............................................................................430

0x731 Kwantowy algorytm przeszukiwania autorstwa Lova Grovera ...........432

0x740 Szyfrowanie

asymetryczne

.............................................................................432

0x741 RSA ..................................................................................................433
0x742 Kwantowy algorytm rozkadu na czynniki autorstwa Petera Shora ....437

0x750 Szyfry

hybrydowe ..........................................................................................438

0x751 Ataki z ukrytym porednikiem ...........................................................439
0x752 „Odciski palców” komputerów w protokole SSH ...............................443
0x753 Rozmyte „odciski palców” ................................................................447

0x760 amanie

hase ...............................................................................................451

0x761 Ataki

sownikowe

.............................................................................453

0x762 Ataki na zasadzie penego przegldu ................................................455
0x763 Tablica wyszukiwania skrótów .........................................................457
0x764 Macierz

prawdopodobiestwa

hase ................................................457

0x770 Szyfrowanie w sieci bezprzewodowej 802.11b ..............................................467

0x771 Protokó Wired Equivalent Privacy (WEP) ..........................................468
0x772 Szyfr

strumieniowy

RC4

....................................................................469

0x780 Ataki na WEP ................................................................................................470

0x781 Ataki na zasadzie penego przegldu w trybie offline .......................470
0x782 Ponowne uycie strumienia klucza ....................................................471
0x783 Tablice sownikowe z wektorami IV ..................................................472
0x784 Przekierowanie

IP

.............................................................................473

0x785 Atak Fluhrera, Mantina i Shamira (FMS) ............................................474

0X800 PODSUMOWANIE

485

0x810 Bibliografia i dodatkowe informacje ..............................................................486
0x820 Kody

ródowe ..............................................................................................487

O PYCIE CD

489

SKOROWIDZ 491

background image

0x200

P R O G R A M O W A N I E

Haker to termin uywany do okrelenia zarówno piszcych kod, jak
i tych, którzy wykorzystuj znajdujce si w nim bdy. Cho obie
grupy hakerów maj róne cele, to i jedni, i drudzy stosuj podobne
techniki rozwizywania problemów. A ze wzgldu na fakt, e umiejt-
no programowania pomaga tym, którzy wykorzystuj bdy w kodzie,
za zrozumienie metod zastosowania pomaga tym, którzy programuj,

wielu hakerów robi obie rzeczy jednoczenie. Interesujce rozwizania istniej
i w zakresie technik pisania eleganckiego kodu, i technik sucych do wykorzysty-
wania saboci programów. Hakerstwo to w rzeczywistoci akt znajdowania pomy-
sowych i nieintuicyjnych rozwiza problemów.

Metody stosowane w narzdziach wykorzystujcych saboci programów zwy-

kle s zwizane z zastosowaniem regu funkcjonowania komputera w sposób, któ-
rego nigdy nie brano pod uwag — pozornie magiczne rezultaty osiga si zwykle
po skupieniu si na omijaniu zaimplementowanych zabezpiecze. Metody uywa-
ne podczas pisania programów s podobne, bo równie wykorzystuj reguy funk-
cjonowania komputera w nowy i pomysowy sposób, jednak w tym przypadku koco-
wym celem jest osignicie najbardziej wydajnego lub najkrótszego kodu ródowego.
Istnieje nieskoczenie wiele programów, które mona napisa w celu wykonania do-
wolnego zadania, jednak wikszo z istniejcych rozwiza jest niepotrzebnie
obszerna, zoona i niedopracowana. Pozostaa niewielka ich liczba to programy
niedue, wydajne i estetyczne. Ta waciwo programów nosi nazw elegancji, za
przemylane i pomysowe rozwizania prowadzce do takiej wydajnoci nazywane
s sztuczkami (ang. hacks). Hakerzy stojcy po obu stronach metodyki programowania
doceniaj zarówno pikno eleganckiego kodu, jak i geniusz pomysowych sztuczek.

background image

20

0x200

W wiecie biznesu mniejsz wag przykada si do przemylanych metod pro-

gramowania i eleganckiego kodu, a wiksz do tworzenia funkcjonalnego kodu w
jak najkrótszym czasie i jak najtaniej. Ze wzgldu na gwatowny wzrost mocy obli-
czeniowej oraz dostpnoci pamici powicenie dodatkowych piciu godzin na
opracowanie nieco szybszego i mniej wymagajcego pod wzgldem pamici frag-
mentu kodu po prostu nie opaca si, gdy mamy do czynienia z nowoczesnymi kom-
puterami dysponujcymi gigahercowymi cyklami procesora i gigabajtami pamici.
Podczas gdy optymalizacje czasu i wykorzystania pamici pozostaj niezauwaone
przez wikszo (z wyjtkiem wyrafinowanych) uytkowników, nowa funkcjonal-
no ma potencja marketingowy. Kiedy najwaniejszym kryterium s pienidze,
powicanie czasu na opracowywanie przemylanych sztuczek optymalizacyjnych
nie ma po prostu sensu.

Elegancj programowania pozostawiono hakerom, hobbistom komputerowym,

których celem nie jest zarabianie, lecz wycinicie wszystkiego, co si da, z ich sta-
rych maszyn Commodore 64, autorom programów wykorzystujcych bdy, pisz-
cym niewielkie i niesamowite fragmenty kodu, dziki którym potrafi przedostawa
si przez wskie szczeliny systemów zabezpiecze, oraz wszystkim innym doceniaj-
cym warto szukania i znajdowania najlepszych moliwych rozwiza. S to osoby
zachwycajce si moliwociami oferowanymi przez programowanie i dostrzegajce
pikno eleganckich fragmentów kodu oraz geniusz przemylanych sztuczek. Poznanie
istoty programowania jest niezbdne do zrozumienia, w jaki sposób mona wykorzy-
stywa saboci programów, dlatego te programowanie to naturalny punkt wyjcia
dla naszych rozwaa.

0x210 Istota programowania

Programowanie to pojcie niezmiernie naturalne i intuicyjne. Program jest tylko
seri instrukcji zapisanych w okrelonym jzyku. Programy wystpuj wszdzie
i nawet technofoby codziennie korzystaj z programów. Opisywanie drogi dojazdu
w jakie miejsce, przepisy kulinarne, rozgrywki pikarskie i spirale DNA to s ró-
nego typu programy. Typowy „program” opisu dojazdu samochodem w konkretne
miejsce moe wyglda tak:

Najpierw zjed w dó Alej Kociuszki, prowadzc na wschód. Jed ni
do momentu, kiedy zobaczysz po prawej stronie koció. Jeeli ulica bdzie
zablokowana ze wzgldu na prowadzone roboty, skr w prawo w ul. Moniuszki,
potem skr w lewo w ul. Prusa i w kocu skr w prawo w ul. Orzeszkowej.
W przeciwnym razie moesz po prostu kontynuowa jazd Alej Kociuszki
i skrci w ul. Orzeszkowej. Jed ni i skr w ul. Docelow. Jed ni
jakie 8 kilometrów — nasz dom bdzie si znajdowa po prawej stronie.
Dokadny adres to ul. Docelowa 743.

Kady, kto zna jzyk polski, pojmie podane instrukcje i bdzie móg kierowa

si nimi podczas jazdy. Bez wtpienia nie zapisano ich zbyt byskotliwie, ale s jed-
noznaczne i zrozumiae.

background image

Programowanie

21

Jednak komputer nie zna jzyka polskiego — rozumie jedynie jzyk maszynowy

(ang. machine language). W celu poinstruowania go, aby wykona pewn czynno,
instrukcj t naley zapisa w zrozumiaym dla niego jzyku. Jednake jzyk ma-
szynowy jest bardzo ezoteryczny i trudny do opanowania. Skada si z serii bitów
oraz bajtów i róni si, w zalenoci od danej architektury komputerowej. Tak wic
w celu napisania programu w jzyku maszynowym dla procesora z rodziny Intel x86
naley okreli warto zwizan z kad instrukcj, sposób interakcji poszczególnych
instrukcji oraz mnóstwo innych niskopoziomowych szczegóów. Tego rodzaju pro-
gramowanie jest bardzo niewdzicznym oraz kopotliwym zadaniem i z pewnoci
nie jest intuicyjne.

Do pokonania komplikacji zwizanych z pisaniem programów w jzyku maszy-

nowym potrzebny jest translator. Jedn z form translatora jzyka maszynowego jest
asembler. To program, który tumaczy jzyk asemblera na kod zapisany w jzyku
maszynowym. Jzyk asemblera jest bardziej przystpny od kodu maszynowego,
poniewa dla rónych instrukcji i zmiennych wykorzystuje nazwy (mnemoniki), a nie
same wartoci liczbowe. Jednak jzyk asemblera wci jest daleki od intuicyjnego.
Nazwy instrukcji s ezoteryczne, a sam jzyk wci jest zaleny od architektury.
Oznacza to, e tak samo, jak jzyk maszynowy dla procesorów Intel x86 róni si
od jzyka maszynowego dla procesorów Sparc, jzyk asemblera x86 jest róny od
jzyka asemblera Sparc. aden program napisany przy uyciu jzyka asemblera dla
architektury jednego procesora nie bdzie dziaa w architekturze innego procesora.
Jeeli program zosta napisany w jzyku asemblera x86, musi zosta przepisany, aby
mona byo uruchomi go w architekturze Sparc. Ponadto w celu napisania wydaj-
nego programu w jzyku asemblera naley zna wiele niskopoziomowych szczegó-
ów, dotyczcych architektury danego procesora.

Problemów tych mona unikn przy uyciu kolejnej formy translatora, nosz-

cego nazw kompilatora (ang. compiler). Kompilator konwertuje kod zapisany w jzy-
ku wysokopoziomowym do postaci kodu maszynowego. Jzyki wysokopoziomowe s
o wiele bardziej intuicyjne od jzyka asemblera i mog by konwertowane do wielu
rónych typów jzyka maszynowego dla odmiennych architektur procesorów. Ozna-
cza to, e jeli zapisze si program w jzyku wysokiego poziomu, ten sam kod moe
zosta skompilowany przez kompilator do postaci kodu maszynowego dla rónych
architektur. C, C++ lub FORTRAN to przykady jzyków wysokopoziomowych.
Program napisany w takim jzyku jest o wiele bardziej czytelny

1

od jzyka asem-

blera lub maszynowego, cho wci musi by zgodny z bardzo surowymi reguami
dotyczcymi sposobu wyraania instrukcji, poniewa w przeciwnym razie kompila-
tor nie bdzie w stanie ich zrozumie.

1

Oczywicie pod warunkiem, e przez czytelny rozumiemy taki, który przypomina jzyk angielski
przyp. tum.

background image

22

0x200

0x220 Pseudokod

Programici dysponuj jeszcze jednym rodzajem jzyka programowania, noszcym
nazw pseudokodu. Pseudokod (ang. pseudo-code) to po prostu wyraenia zapisane
w jzyku naturalnym, ustawione w struktur ogólnie przypominajc jzyk wyso-
kopoziomowy. Nie jest on rozumiany przez kompilatory, asemblery ani kompute-
ry, ale stanowi przydatny sposób skadania instrukcji. Pseudokod nie jest dobrze
zdefiniowany. W rzeczywistoci wiele osób zapisuje pseudokod odmiennie. Jest to
rodzaj nieokrelonego, brakujcego ogniwa midzy jzykami naturalnymi, takimi
jak angielski lub polski, a wysokopoziomowymi jzykami programowania, takimi
jak C lub Pascal. Pseudokod stanowi wietne wprowadzenie do uniwersalnych
zaoe programistycznych.

0x230 Struktury sterujce

Bez struktur sterujcych program byby jedynie seri kolejno wykonywanych instruk-
cji. Jest to wystarczajce w przypadku bardzo prostych programów, ale wikszo
programów, takich jak np. opis dojazdu, taka nie jest. Prezentowany opis dojazdu
zawiera instrukcje: Jed ni do momentu, kiedy zobaczysz po prawej stronie koció.
Jeeli ulica bdzie zablokowana ze wzgldu na prowadzone roboty…
Instrukcje te
nazywamy strukturami sterujcymi, poniewa zmieniaj przebieg wykonywania
programu z prostego, sekwencyjnego, na bardziej zoony i uyteczny.

0x231 If-Then-Else

W naszym opisie dojazdu Aleja Kociuszki moe by w remoncie. Do rozwizania
problemu wynikajcego z tej sytuacji potrzebujemy specjalnego zestawu instrukcji.
Jeeli zdefiniowane okolicznoci nie wystpi (remont), bd wykonywane standardo-
we instrukcje. Tego rodzaju specjalne przypadki mona wzi pod uwag w progra-
mie, korzystajc z jednej z najbardziej naturalnych struktur sterujcych:

if

-

then

-

else

(jeeli-wówczas-w przeciwnym przypadku). Ogólnie wyglda to mniej wicej tak:

If (warunek) then
{
Zestaw instrukcji do wykonania, gdy warunek jest speniony;
}
Else
{
Zestaw instrukcji do wykonania, gdy warunek nie jest speniony;
}

W tej ksice bdziemy posugiwali si pseudokodem przypominajcym jzyk C,

wic kada instrukcja bdzie zakoczona rednikiem, a ich zbiory bd grupowane
za pomoc nawiasów klamrowych i wyróniane wciciem. Pseudokod struktury

if-then-else

dla wskazówek dojazdu mógby przedstawia si nastpujco:

background image

Programowanie

23

Jed w dó Alej Kociuszki;
Jeeli (ulica zablokowana)
{
Skr w prawo w ul. Moniuszki;
Skr w lewo w ul. Prusa;
Skr w prawo w ul. Orzeszkowej;
}
else
{
Skr w prawo w ul. Orzeszkowej;
}

Kada instrukcja znajduje si w osobnym wierszu, a róne zestawy instrukcji

warunkowych s zgrupowane wewntrz nawiasów klamrowych i dla zwikszenia
czytelnoci zastosowano dla nich wcicie. W C i wielu innych jzykach programo-
wania sowo kluczowe

then

jest domniemane i tym samym pomijane, wic pomi-

nlimy je równie w pseudokodzie.

Oczywicie, istniej jzyki, których skadnia wymaga zastosowania sowa klu-

czowego

then

— przykadami mog tu by BASIC, Fortran, a nawet Pascal. Tego

typu rónice syntaktyczne midzy jzykami programowania s niemal nieistotne,
jako e podstawowa struktura jest taka sama. Gdy programista zrozumie zaoenia
tych jzyków, nauczenie si rónych odmian syntaktycznych jest stosunkowo atwe.
Poniewa w dalszych rozdziaach bdziemy programowali w jzyku C, prezento-
wany pseudokod bdzie przypomina ten jzyk. Naley jednak pamita, e moe
on przyjmowa róne postaci.

Inn powszechn regu skadni podobnej do C jest sytuacja, w której zestaw

instrukcji umieszczonych w nawiasach klamrowych zawiera tylko jedn instrukcj.
Dla zwikszenia czytelnoci wci warto dla takiej instrukcji zastosowa wcicie,
ale nie jest ono wymagane. Zgodnie z t regu mona wic napisa wczeniej przed-
stawiony opis dojazdu tak, aby uzyska równowany fragment pseudokodu:

Jed w dó Alej Kociuszki;
Jeeli (ulica zablokowana)
{
Skr w prawo w ul. Moniuszki;
Skr w lewo w ul. Prusa;
Skr w prawo w ul. Orzeszkowej;
}
else
Skr w prawo w ul. Orzeszkowej;

Regua mówica o zestawach instrukcji dotyczy wszystkich struktur sterujcych

opisywanych w niniejszej ksice, a sam regu równie mona zapisa w pseu-
dokodzie.

background image

24

0x200

If (w zestawie instrukcji znajduje si tylko jedna instrukcja)
Uycie nawiasów klamrowych do zgrupowania instrukcji jest opcjonalne;
Else
{
Uycie nawiasów klamrowych jest niezbdne;
Poniewa musi istnie logiczny sposób zgrupowania tych instrukcji;
}

Nawet opis skadni mona potraktowa jak program. Istnieje wiele odmian struk-

tury

if-then-else

, np. instrukcje

select

i

case

, ale logika pozostaje taka sama: jeeli

stanie si tak, zrób to i to, w przeciwnym przypadku wykonaj, co poniej (a poniej
mog si znajdowa kolejne instrukcje

if-then

).

0x232

Ptle While/Until

Innym podstawowym pojciem programistycznym jest struktura sterujca

while

,

bdca rodzajem ptli. Programista czsto chce wykona zestaw instrukcji kilka razy.
Program moe wykona to zadanie, stosujc ptl, ale wymaga to okrelenia warun-
ków jej zakoczenia, aby nie trwaa w nieskoczono. Ptla

while

wykonuje podany

zestaw instrukcji, dopóki warunek jest prawdziwy. Prosty program dla godnej
myszy mógby wyglda nastpujco:

While (jeste godna)
{
Znajd jakie jedzenie;
Zjedz jedzenie;
}

Te dwa zestawy instrukcji za instrukcj

while

bd powtarzane, dopóki mysz

bdzie godna. Ilo poywienia odnalezionego przez mysz przy kadej próbie moe
waha si od maego okruszka po cay bochen chleba. Podobnie liczba wykona
zestawu instrukcji w ptli

while

zaley od iloci poywienia znalezionego przez mysz.

Odmian ptli

while

jest ptla

until

, wykorzystywana w Perlu (w C skadnia

ta nie jest uywana). Ptla

until

jest po prostu ptl

while

z odwróconym warunkiem.

Ten sam program dla myszy zapisany z uyciem ptli

until

wygldaby nastpujco:

Until (nie jeste godna)
{
Znajd jakie jedzenie;
Zjedz jedzenie;
}

Logicznie kada instrukcja podobna do

until

moe by przeksztacona w ptl

while

. Opis dojazdu zawiera zdanie: „Jed ni do momentu, kiedy zobaczysz po

prawej stronie koció”. Moemy to w prosty sposób przeksztaci w standardow
ptl

while

— wystarczy, e odwrócimy warunek:

background image

Programowanie

25

While (nie ma kocioa po prawej stronie)
Jed Alej Kociuszki;

0x233 Ptle

for

Kolejn struktur sterujc jest ptla

for

, wykorzystywana wtedy, gdy programista

chce, aby ptla wykonaa okrelon liczb iteracji. Instrukcja dojazdu: „Jed ni
jakie 8 kilometrów” przeksztacona do ptli

for

mogaby wyglda nastpujco:

For (8 iteracji)

Jed prosto 1 kilometr;

W rzeczywistoci ptla

for

jest po prostu ptl

while

z licznikiem. Powysz

instrukcj mona równie dobrze zapisa tak:

Ustaw licznik na 0
While (licznik jest mniejszy od 8)
{
Jed prosto 1 kilometr;
Dodaj 1 do licznika;
}

Skadnia pseudokodu dla ptli

for

sprawia, e jest to jeszcze bardziej widoczne:

For (i=0; i<8; i++)
Jed prosto 1 kilometr;

W tym przypadku licznik nosi nazw

i

, a instrukcja

for

jest podzielona na trzy

sekcje oddzielone rednikami. Pierwsza sekcja deklaruje licznik i ustawia jego po-
cztkow warto — w tym przypadku 0. Druga sekcja przypomina instrukcj

while

z licznikiem — dopóki licznik spenia podany warunek, kontynuuj ptl. Trzecia
i ostatnia sekcja opisuje, co ma si dzia z licznikiem przy kadej iteracji. W tym
przypadku

i++

jest skróconym sposobem na powiedzenie: „Dodaj 1 do licznika

o nazwie i”.

Zastosowanie wszystkich omówionych struktur sterujcych umoliwia przekszta-

cenie opisu dojazdu ze strony 6 w poniszy pseudokod przypominajcy jzyk C:

Rozpocznij jazd na wschód Alej Kociuszki;
While (po prawej stronie nie ma kocioa)
Jed Alej Kociuszki;
If (ulica zablokowana)
{
Skr w prawo w ul. Moniuszki);
Skr w lewo w ul. Prusa);
Skr w prawo w ul. Orzeszkowej);
}

background image

26

0x200

Else
Skr(prawo, ul. Orzeszkowej);
Skr(lewo, ul. Docelowa);
For (i=0; i<8; i++)
{
Jed prosto 1 kilometr;
}
Zatrzymaj si przy ul. Docelowej 743;

0x240 Podstawowe pojcia programistyczne

W kolejnych punktach zostan przedstawione podstawowe pojcia programistyczne.
S one wykorzystywane w wielu jzykach programowania, róni si jedynie pod
wzgldem syntaktycznym. Podczas prezentacji bd integrowane z przykadami
w pseudokodzie przypominajcym skadni jzyka C. Na kocu pseudokod bdzie
bardzo przypomina kod napisany w jzyku C.

0x241

Zmienne

Licznik wykorzystywany w ptli

for

jest rodzajem zmiennej. O zmiennej moemy

myle jak o obiekcie przechowujcym dane, które mog by zmieniane — std
nazwa. Istniej równie zmienne, których wartoci nie s zmieniane, i trafnie nazywa
si je staymi. W przykadzie motoryzacyjnym jako zmienn moemy potraktowa
prdko samochodu, natomiast kolor lakieru samochodu byby sta. W pseudo-
kodzie zmienne s po prostu pojciami abstrakcyjnymi, natomiast w C (i wielu in-
nych jzykach) zmienne przed wykorzystaniem musz by zadeklarowane i naley
okreli ich typ. Jest tak dlatego, e program napisany w C bdzie kompilowany
do postaci programu wykonywalnego. Podobnie jak przepis kucharski, w którym
przed faktycznymi instrukcjami wymieniane s wszystkie potrzebne skadniki, de-
klaracje zmiennych pozwalaj dokona przygotowa przed przejciem do faktycznej
treci programu. Ostatecznie wszystkie zmienne s przechowywane gdzie w pamici,
a ich deklaracje pozwalaj kompilatorowi wydajniej uporzdkowa pami. Jednak
na koniec, mimo wszystkich deklaracji typów zmiennych, wszystko odbywa si
w pamici.

W jzyku C dla kadej zmiennej okrelany jest typ, opisujcy informacje, które

bd przechowywane w tej zmiennej. Do najczciej stosowanych typów zalicza-
my

int

(liczby cakowite),

float

(liczby zmiennoprzecinkowe) i

char

(pojedyncze

znaki). Zmienne s deklarowane poprzez uycie tych sów kluczowych przed nazw
zmiennej, co zobrazowano na poniszym przykadzie.

int a, b;
float k;
char z;

Zmienne

a

i

b

s zadeklarowane jako liczby cakowite,

k

moe przyjmowa warto-

ci zmiennoprzecinkowe (np. 3,14), a

z

powinna przechowywa warto znakow,

background image

Programowanie

27

tak jak

A

lub

w

. Wartoci mona przypisywa zmiennym podczas deklaracji lub

w dowolnym póniejszym momencie. Suy do tego operator

=

.

int a = 13, b;
float k;
char z = 'A';

k = 3.14;
z = 'w';
b = a + 5;

Po wykonaniu powyszych instrukcji zmienna

a

bdzie posiadaa warto 13,

zmienna

k

bdzie zawieraa liczb 3,14, a zmienna

b

bdzie miaa warto 18, po-

niewa 13 plus 5 równa si 18. Zmienne s po prostu sposobem pamitania wartoci,
jednak w jzyku C naley najpierw zadeklarowa typ kadej zmiennej.

0x242 Operatory

arytmetyczne

Instrukcja

b = a + 7

jest przykadem bardzo prostego operatora arytmetycznego.

W jzyku C dla rónych operacji matematycznych wykorzystywane s ponisze
symbole.

Pierwsze cztery operatory powinny wyglda znajomo. Redukcja modulo moe

stanowi nowe pojcie, ale jest to po prostu reszta z dzielenia. Jeeli

a

ma warto

13, to 13 podzielone przez 5 równa si 2, a reszta wynosi 3, co oznacza, e

a % 5 = 3

.

Ponadto skoro zmienne

a

i

b

s liczbami cakowitymi, po wykonaniu instrukcji

b = a / 5

, zmienna

b

bdzie miaa warto 2, poniewa jest to cz wyniku bdca

liczb cakowit. Do przechowania bardziej poprawnego wyniku, czyli 2,6, musi
zosta uyta zmienna typu

float

(zmiennoprzecinkowa).

Operacja

Symbol

Przykad

Dodawanie

+

b = a + 5

Odejmowanie

-

b = a - 5

Mnoenie

*

b = a * 5

Dzielenie

/

b = a / 5

Redukcja modulo

%

b = a % 5

Aby program korzysta z tych zaoe, musimy mówi w jego jzyku. Jzyk C

dostarcza kilku skróconych form zapisu tych operacji arytmetycznych. Jedna z nich
zostaa przedstawiona wczeniej i jest czsto wykorzystywana w ptlach

for

.

Pene wyraenie

Skrót

Wyjanienie

i = i + 1

i++ lub ++i

Dodaje 1 do wartoci zmiennej.

i = i - 1

i-- lub i--

Odejmuje 1 od wartoci zmiennej.

background image

28

0x200

Te skrócone wyraenia mog by czone z innymi operacjami arytmetycznymi

w celu utworzenia bardziej zoonych wyrae. Wówczas staje si widoczna rónica
midzy

i++

i

++i

. Pierwsze wyraenie oznacza: „Zwiksz warto

i

o 1 po przepro-

wadzeniu operacji arytmetycznej”, natomiast drugie: „Zwiksz warto

i

o 1 przed

przeprowadzeniem operacji arytmetycznej”. Poniszy przykad pozwoli to lepiej
zrozumie.

int a, b;
a = 5
b = a++ * 6;

Po wykonaniu tego zestawu instrukcji zmienna

b

bdzie miaa warto 30, nato-

miast zmienna

a

bdzie miaa warto 6, poniewa skrócony zapis

b = a++ * 6

jest

równowany poniszym instrukcjom.

b = a * 6;
a = a + 1;

Jeeli jednak zostanie uyta instrukcja

b = ++a * 6

, kolejno dodawania zostanie

zmieniona i otrzymamy odpowiednik poniszych instrukcji.

a = a + 1;
b = a * 6;

Poniewa kolejno wykonywania dziaa zmienia si, w powyszym przypad-

ku zmienna

b

bdzie miaa warto 36, natomiast warto zmiennej

a

wci bdzie

wynosia 6.

Czsto w programach musimy zmodyfikowa zmienn w danym miejscu. Przy-

kadowo moemy doda dowoln warto, tak jak 12, i przechowa wynik w tej
samej zmiennej (np.

i = i + 12

) Zdarza si to tak czsto, e równie utworzono

skrócon form tej instrukcji.

Pene wyraenie

Skrót

Wyjanienie

i = i + 12

i+=12

Dodaje okrelon warto do wartoci zmiennej.

i = i - 12

i-=12

Odejmuje okrelon warto od wartoci zmiennej.

i = i * 12

i*=12

Mnoy okrelon warto przez warto zmiennej.

i = i / 12

i/=12

Dzieli warto zmiennej przez okrelon warto.

0x243

Operatory porównania

Zmienne s czsto wykorzystywane w instrukcjach warunkowych wczeniej opisanych
struktur sterujcych, a te instrukcje warunkowe opieraj si na jakiego rodzaju
porównaniu. W jzyku C operatory porównania wykorzystuj skrócon skadni,
która jest stosunkowo powszechna w innych jzykach programowania.

background image

Programowanie

29

Warunek

Symbol

Przykad

Mniejsze ni

<

(a < b)

Wiksze ni

>

(a < b)

Mniejsze lub równe

<=

(a <= b)

Wiksze lub równe

>=

(a >= b)

Równe

==

(a == b)

Nie równa si

!=

(a != b)

Wikszo z tych operatorów jest zrozumiaa, jednake naley zauway, e

w skrócie porównania równoci wykorzystywane s dwa znaki równoci. Jest to wane
rozrónienie, poniewa podwójny znak równoci jest stosowany do sprawdzenia
równoci, natomiast jeden znak równoci jest uywany do przypisania wartoci
zmiennej. Instrukcja

a = 7

oznacza: „Umie w zmiennej

a

warto 7”, natomiast

a == 7

oznacza: „Sprawd, czy warto zmiennej

a

wynosi 7”. (Niektóre jzyki pro-

gramowania, takie jak Pascal, wykorzystuj do przypisywania wartoci zmiennym
nastpujcy znak —

:=

— aby wyeliminowa ryzyko bdnego zrozumienia kodu).

Naley te zwróci uwag, e wykrzyknik zwykle oznacza nie. Ten symbol moe by
wykorzystany do odwrócenia dowolnego wyraenia.

!(a < b) jest równowane (a >= b)

Operatory porównania mog by czone ze sob za pomoc skrótów dla ope-

ratorów logicznych

OR

i

AND

.

Operator logiczny

Symbol

Przykad

OR

||

((a < b) || (a < c))

AND

&&

((a < b) && !(a < c))

Przykadowa instrukcja zawierajca dwa mniejsze warunki poczone operato-

rem

OR

zostanie oszacowana jako prawdziwa, jeeli warto zmiennej

a

bdzie mniej-

sza od wartoci zmiennej

b

LUB warto zmiennej

a

bdzie mniejsza od wartoci

zmiennej

c

. Podobnie przykadowa instrukcja zawierajca dwa mniejsze warunki

poczone operatorem

AND

zostanie oszacowana jako prawdziwa, jeeli warto

zmiennej

a

bdzie mniejsza od wartoci zmiennej

b

I warto zmiennej

a

nie bdzie

mniejsza od wartoci zmiennej

c

. Takie instrukcje powinny by grupowane za pomoc

nawiasów i mog zawiera wiele rónych odmian.

Wiele rzeczy moemy sprowadzi do zmiennych, operatorów porównania i struk-

tur sterujcych. W przykadzie myszy poszukujcej poywienia gód moemy przed-
stawi jako zmienn boolowsk o wartoci

true

lub

false

(prawda lub fasz). Oczy-

wicie,

1

oznacza

true

, a

0

false

.

background image

30

0x200

While (gód == 1)
{
Szukaj poywienia;
Zjedz poywienie;
}

Oto kolejny skrót czsto wykorzystywany przez programistów i hakerów. Jzyk

C nie zawiera adnych operatorów boolowskich, wic kada warto niezerowa jest
uznawana za

true

, a instrukcja jest szacowana jako

false

, gdy zawiera 0. W rzeczy-

wistoci operatory porównania faktycznie zwracaj 1, jeeli porównanie jest spe-
nione, a w przeciwnym przypadku zwracaj 0. Sprawdzenie, czy zmienna

gód

ma

warto 1, zwróci 1, jeeli

gód

ma warto 1, lub zwróci 0, jeeli gód ma warto 0.

Poniewa program wykorzystuje tylko te dwa przypadki, mona w ogóle pomin
operator porównania.

While (gód)
{
Szukaj poywienia;
Zjedz poywienie;
}

Sprytniejszy program sterujcy zachowaniem myszy z uyciem wikszej liczby

danych wejciowych to przykad, jak mona czy operatory porównania ze zmien-
nymi.

While ((gód) && !(kot_obecny))
{
Szukaj poywienia;
If (!(poywienie_znajduje_si_w_puapce_na_myszy;
Zjedz poywienie;
}

W tym przykadzie zaoono, e dostpne s równie zmienne opisujce obec-

no kota oraz pooenie poywienia z wartociami 1 dla spenienia warunku i 0 dla
przypadku przeciwnego. Wystarczy pamita, e warto niezerowa oznacza prawd,
a warto 0 jest szacowana jako fasz.

0x244

Funkcje

Czasami zdarzaj si zestawy instrukcji, których programista bdzie potrzebowa
kilka razy. Takie instrukcje mona zgrupowa w mniejszym podprogramie, zwanym
funkcj. W innych jzykach funkcje nazywane s take procedurami i podprocedu-
rami. Przykadowo wykonanie skrtu samochodem skada si z kilku mniejszych
instrukcji: wcz odpowiedni kierunkowskaz, zwolnij, sprawd, czy nie nadjedaj
inne samochody, skr kierownic w odpowiednim kierunku itd. Opis trasy z poczt-
ku tego rozdziau zawiera cakiem sporo skrtów, jednake wymienianie wszystkich

background image

Programowanie

31

drobnych instrukcji przy kadym skrcie byoby mudne (i zmniejszaoby czytel-
no kodu). W celu zmodyfikowania sposobu dziaania funkcji moemy przesya do
niej zmienne jako argumenty. W tym przypadku do funkcji jest przesyany kierunek
skrtu.

Function Skrt(zmienna_kierunku)
{
Wcz zmienna_kierunku kierunkowskaz;
Zwolnij;
Sprawd, czy nie nadjedaj inne samochody;
while (nadjedaj inne samochody)
{
Zatrzymaj si;
Obserwuj nadjedajce samochody;
}
Obró kierownic w zmienna_kierunku;
while (skrt nie jest ukoczony)
{
if (prdko < 8 km/h)
Przyspiesz;
}
Obró kierownic do pierwotnego pooenia;
Wycz zmienna_kierunku kierunkowskaz;
}

Funkcja ta zawiera wszystkie instrukcje konieczne do wykonania skrtu. Gdy

program, w którym funkcja taka si znajduje, musi wykona skrt, moe po prostu
wywoa t funkcj. Gdy zostaje wywoana, znajdujce si w niej instrukcje s wy-
konywane z przesanymi argumentami. Nastpnie wykonywanie programu powraca
do momentu za wywoaniem funkcji. Do tej funkcji mona przesa warto lewo
albo prawo, co spowoduje wykonanie skrtu w tym kierunku.

Domylnie w jzyku C funkcje mog zwraca wartoci do elementu wywouj-

cego. Dla osób znajcych matematyk jest to zupenie zrozumiae. Wyobramy sobie
funkcj obliczajc silni — jest oczywiste, e zwraca wynik.

W jzyku C funkcje nie s oznaczane sowem kluczowym

function

. Zamiast tego

s deklarowane przez typ danych zwracanej zmiennej. Taki format bardzo przy-
pomina deklaracj zmiennej. Jeeli funkcja w zamierzeniu ma zwraca liczb ca-
kowit (moe to by np. funkcja obliczajca silni jakiej liczby

x

), jej kod mógby

wyglda nastpujco:

int factorial(int x)
{
int i;
for(i=1; i < x; i++)
x *= i;
return x;
}

background image

32

0x200

Funkcja ta jest deklarowana liczb cakowit, poniewa mnoy kad warto

od 1 do

x

i zwraca wynik, który jest liczb cakowit. Instrukcja

return

na kocu

funkcji przesya zawarto zmiennej

x

i koczy wykonywanie funkcji. Funkcj obli-

czajc silni mona wówczas wykorzysta jak kad zmienn typu

integer

w gównej

czci kadego programu, który „wie” o tej funkcji:

int a=5, b;
b = factorial(a);

Po ukoczeniu wykonywania tego krótkiego programu zmienna

b

bdzie miaa

warto 120, poniewa funkcja

factorial()

zostanie wywoana z argumentem 5

i zwróci 120.

Ponadto w jzyku C kompilator musi „wiedzie” o funkcji, zanim jej uyje. W tym

celu mona po prostu napisa ca funkcj przed póniejszym wykorzystaniem jej
w programie lub skorzysta z prototypu funkcji. Prototyp funkcji jest prostym spo-
sobem poinformowania kompilatora, i powinien spodziewa si funkcji o podanej
nazwie, zwracajcej okrelony typ danych i przyjmujcej argumenty o okrelonym
typie danych. Faktyczny kod funkcji mona umieci pod koniec programu, ale mona
j wykorzysta w dowolnym miejscu, poniewa kompilator bdzie ju wiedzia o jej
istnieniu. Przykadowy prototyp funkcji

factorial()

mógby wyglda nastpujco:

int factorial(int);

Zwykle prototypy funkcji s umieszczane blisko pocztku programu. W proto-

typie nie ma potrzeby definiowania nazw zmiennych, poniewa dzieje si to w sa-
mej funkcji. Kompilator musi jedynie zna nazw funkcji, typ zwracanych danych
i typy danych argumentów funkcjonalnych.

Jeeli funkcja nie posiada wartoci, któr moe zwróci (np. wczeniej opisana

funkcja

skr()

), powinna by zadeklarowana jako typ

void

. Jednake funkcja

skr()

nie posiada jeszcze caej funkcjonalnoci wymaganej przez nasz opis dojazdu. Kady
skrt w opisie dojazdu zawiera zarówno kierunek, jak i nazw ulicy. To oznacza, e
funkcja skrcajca powinna przyjmowa dwie zmienne: kierunek skrtu oraz nazw
ulicy, w któr naley skrci. To komplikuje funkcj skrcajc, poniewa przed
wykonaniem skrtu naley zlokalizowa ulic. Bardziej kompletna funkcja skrcajca,
w której wykorzystano skadni podobn do jzyka C, jest zamieszczona w pseu-
dokodzie poniszego listingu.

void skr(zmienna_kierunku, nazwa_docelowej_ulicy)
{
Szukaj tabliczki z nazw ulicy;
nazwa_biecego_skrzyowania = odczytaj tabliczk z nazw ulicy;
while (nazwa_biecego_skrzyowania != nazwa_docelowej_ulicy)
{
Szukaj innej tabliczki z nazw ulicy;
nazwa_biecego_skrzyowania = odczytaj tabliczk z nazw ulicy;
}

background image

Programowanie

33

Wcz zmienna_kierunku kierunkowskaz;
Zwolnij;
Sprawd, czy nie nadjedaj inne samochody;
while (nadjedaj inne samochody)
{
Zatrzymaj si;
Obserwuj nadjedajce samochody;
}
Obró kierownic w zmienna_kierunku;
while (skrt nie jest ukoczony)
{
if (prdko < 8 km/h)
Przyspiesz;
}
Obró kierownic do pierwotnego pooenia;
Wycz zmienna_kierunku kierunkowskaz;
}

Funkcja ta zawiera sekcj, która wyszukuje odpowiednie skrzyowanie poprzez

odnajdywanie tabliczki z nazw ulicy, odczytywanie z niej nazwy i przechowywanie
jej w zmiennej o nazwie

nazwa_biecego_skrzyowania

. Wyszukiwanie i odczyty-

wanie tabliczek z nazwami odbywa si do momentu odnalezienia docelowej ulicy.
Wówczas wykonywane s pozostae instrukcje skrtu. Moemy teraz zmieni pseu-
dokod z instrukcjami dojazdu, aby wykorzystywa funkcj skrtu.

Rozpocznij jazd na wschód Alej Kociuszki;
while (po prawej stronie nie ma kocioa)
{
Jed Alej Kociuszki;
}
If (ulica zablokowana)
{
Skr(prawo, ul. Moniuszki);
Skr(lewo, ul. Prusa);
Skr(prawo, ul. Orzeszkowej);
}
else
{
Skr(prawo, ul. Orzeszkowej);
}
Skr(lewo, ul. Docelowa);
For (i=0; i<5; i++)
{
Jed prosto 1 kilometr;
}
Zatrzymaj si przy ul. Docelowej 743;

Funkcje nie s czsto wykorzystywane w pseudokodzie, bo zwykle jest on sto-

sowany przez programistów do zarysowania zaoe programu przed napisaniem
kompilowalnego kodu. Poniewa pseudokod nie musi dziaa, nie trzeba wypisywa
penych funkcji — wystarczy jedynie krótki zapisek: Tu zrób co zoonego. Jednak

background image

34

0x200

w jzyku programowania, takim jak C, funkcje s czsto wykorzystywane. Wikszo
prawdziwej uytecznoci C pochodzi ze zbiorów istniejcych funkcji, zwanych
bibliotekami.

0x250 Zaczynamy brudzi sobie rce

Gdy zaznajomilimy si ju troch ze skadni jzyka C i wyjanilimy kilka pod-
stawowych poj programistycznych, przejcie do faktycznego programowania w C
nie jest niczym nadzwyczajnym. Kompilatory jzyka C istniej dla niemal kadego
systemu operacyjnego i architektury procesora, jednak w niniejszej ksice bdziemy
wykorzystywali wycznie system Linux i procesor z rodziny x86. Linux jest dar-
mowym systemem operacyjnym, do którego kady ma dostp, a procesory x86 s
najpopularniejszymi procesorami konsumenckimi na wiecie. Poniewa hacking
wie si gównie z eksperymentowaniem, najlepiej bdzie, jeeli w trakcie lektury
bdziesz dysponowa kompilatorem jzyka C.

Dziki dyskowi LiveCD doczonemu do niniejszej ksiki moesz praktycznie

stosowa przekazywane informacje, jeeli tylko dysponujesz procesorem z rodziny
x86. Wystarczy woy dysk CD do napdu i ponownie uruchomi komputer. Uru-
chomione zostanie rodowisko linuksowe, które nie narusza istniejcego systemu ope-
racyjnego. W tym rodowisku moesz wypróbowywa przykady z ksiki, a take
przeprowadza wasne eksperymenty.

Przejdmy do rzeczy. Program firstprog.c jest prostym fragmentem kodu w C,

wypisujcym 10 razy „Hello world!”.

Listing 2.1. firstprog.c

#include <stdio.h>

int main()
{
int i;
for(i=0; i < 10; i++) // Wykonaj ptl 10 razy.
{
puts("Hello, world!\n"); // Przeka acuch do wyjcia.
}
return 0; // Poinformuj OS, e program zakoczy si bez bdów.
}

Gówne wykonywanie programu napisanego w C rozpoczyna si w funkcji

main()

.

Tekst znajdujcy si za dwoma ukonikami jest komentarzem ignorowanym przez
kompilator.

Pierwszy wiersz moe wprawia w zakopotanie, ale jest to jedynie skadnia

informujca kompilator, aby doczy nagówki dla standardowej biblioteki wej-
cia-wyjcia o nazwie stdio. Ten plik nagówkowy jest dodawany do programu
podczas kompilacji. Znajduje si on w /usr/include/stdio.h i definiuje kilka staych
i prototypów funkcji dla odpowiednich funkcji w standardowej bibliotece we-wy.
Poniewa funkcja

main()

wykorzystuje funkcj

printf()

ze standardowej biblioteki

background image

Programowanie

35

we-wy, wymagany jest prototyp funkcji

printf()

przed jej zastosowaniem. Ten

prototyp funkcji (a take wiele innych) znajduje si w pliku nagówkowym stdio.h.
Sporo moliwoci jzyka C to pochodne jego zdolnoci do rozbudowy oraz wyko-
rzystania bibliotek. Reszta kodu powinna by zrozumiaa i przypomina wczeniej
prezentowany pseudokod. S nawet nawiasy klamrowe, które mona byo pomin.
To, co bdzie si dziao po uruchomieniu tego programu, powinno by oczywiste,
ale skompilujmy go za pomoc GCC, aby si upewni.

GNU Compiler Collection jest darmowym kompilatorem jzyka C, tumaczcym

jzyk C na jzyk maszynowy, zrozumiay dla komputera. W wyniku tumaczenia
powstaje wykonywalny plik binarny, któremu domylnie nadawana jest nazwa a.out.
Czy skompilowany program wykonuje to, co chcielimy?

reader@hacking:~/booksrc $ gcc firstprog.c
reader@hacking:~/booksrc $ ls -l a.out
-rwxr-xr-x 1 reader reader 6621 2007-09-06 22:16 a.out
reader@hacking:~/booksrc $ ./a.out
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
reader@hacking:~/booksrc $

0x251

Wikszy obraz

Dobrze, tego wszystkiego mona si nauczy na podstawowym kursie programo-
wania — s to podstawy, ale niezbdne. Wikszo pocztkowych kursów progra-
mowania uczy jedynie, jak czyta i pisa w jzyku C. Prosz mnie le nie zrozumie
— pynna znajomo C jest bardzo przydatna i wystarczy do stania si dobrym
programist, ale jest to tylko cz wikszej caoci. Wikszo programistów uczy
si jzyka z góry do dou i nigdy nie ma szerszego obrazu. Hakerzy s tak dobrzy,
poniewa wiedz, jak wszystkie czci tego wikszego obrazu wchodz ze sob
w interakcje. Aby w programowaniu patrze szerzej, wystarczy sobie zda spraw, e
kod w jzyku C bdzie kompilowany. Kod nie moe nic zrobi, dopóki nie zostanie
skompilowany do wykonywalnego pliku binarnego. Mylenie o kodzie ródowym
w C jak o programie jest czstym bdem wykorzystywanym codziennie przez ha-
kerów. Instrukcje w pliku a.out s zapisane w jzyku maszynowym — podstawowym
jzyku zrozumiaym dla procesora. Kompilatory tumacz jzyk kodu C na jzyk
maszynowy rónych architektur procesorów. W tym przypadku procesor pocho-
dzi z rodziny wykorzystujcej architektur x86. Istniej równie architektury pro-
cesorów Sparc (uywane w stacjach roboczych Sun) oraz architektura PowerPC

background image

36

0x200

(wykorzystywana w macintoshach przed zastosowaniem procesorów Intela). Kada
architektura wymaga innego jzyka maszynowego, wic kompilator jest poredni-
kiem — tumaczy kod w jzyku C na jzyk maszynowy docelowej architektury.

Dopóki skompilowany program dziaa, przecitny programista skupia si wy-

cznie na kodzie ródowym. Jednak haker zdaje sobie spraw, e w rzeczywistoci
wykonywany jest program skompilowany. Majc dogbn wiedz na temat dziaania
procesora, haker moe manipulowa dziaajcymi programami. Widzielimy kod
ródowy naszego pierwszego programu i skompilowalimy go do pliku wykony-
walnego dla architektury x86. Ale jak wyglda ten wykonywalny plik binarny? Na-
rzdzia programistyczne GNU zawieraj program o nazwie objdump, który moe by
uyty do badania skompilowanych plików binarnych. Rozpocznijmy od poznania
kodu maszynowego, na który zostaa przetumaczona funkcja

main()

.

reader@hacking:~/booksrc $ objdump -D a.out | grep -A20 main.:
08048374 <main>:
8048374: 55 push %ebp
8048375: 89 e5 mov %esp,%ebp
8048377: 83 ec 08 sub $0x8,%esp
804837a: 83 e4 f0 and $0xfffffff0,%esp
804837d: b8 00 00 00 00 mov $0x0,%eax
8048382: 29 c4 sub %eax,%esp
8048384: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
804838b: 83 7d fc 09 cmpl $0x9,0xfffffffc(%ebp)
804838f: 7e 02 jle 8048393 <main+0x1f>
8048391: eb 13 jmp 80483a6 <main+0x32>
8048393: c7 04 24 84 84 04 08 movl $0x8048484,(%esp)
804839a: e8 01 ff ff ff call 80482a0 <printf@plt>
804839f: 8d 45 fc lea 0xfffffffc(%ebp),%eax
80483a2: ff 00 incl (%eax)
80483a4: eb e5 jmp 804838b <main+0x17>
80483a6: c9 leave
80483a7: c3 ret
80483a8: 90 nop
80483a9: 90 nop
80483aa: 90 nop
reader@hacking:~/booksrc $

Program objdump zwróci zbyt wiele wierszy wynikowych, aby rozsdnie si im

przyjrze, wic przekazalimy wyjcie do

grep

z opcj powodujc wywietlenie

tylko 20 wierszy za wyraeniem regularnym

main.:

. Kady bajt jest reprezentowany

w notacji szesnastkowej, systemie liczbowym o podstawie 16. System liczbowy, do
którego jestemy najbardziej przyzwyczajeni, wykorzystuje podstaw 10, a przy
liczbie 10 naley umieci dodatkowy symbol. W systemie szesnastkowym stoso-
wane s cyfry od 0 do 9 reprezentujce 0 do 9, ale take litery A do F, które repre-
zentuj w nim liczby od 10 do 15. Jest to wygodny zapis, poniewa bajt zawiera 8 bi-
tów, z których kady moe mie warto prawda lub fasz. To oznacza, e bajt ma
256 (2

8

) moliwych wartoci, wic kady bajt moe by opisany za pomoc dwóch

cyfr w systemie szesnastkowym.

background image

Programowanie

37

Liczby szesnastkowe — rozpoczynajc od 0x8048374 po lewej stronie — s ad-

resami pamici. Bity jzyka maszynowego musz by gdzie przechowywane, a tym
„gdzie” jest pami. Pami jest po prostu zbiorem bajtów z tymczasowej przestrzeni
magazynowej, którym przypisano adresy liczbowe.

Podobnie jak rzd domów przy lokalnej ulicy, z których kady posiada wasny

adres, pami moemy traktowa jako rzd bajtów, z których kady ma wasny adres.
Do kadego bajta pamici mona uzyska dostp za pomoc jego adresu, a w tym
przypadku procesor siga do tej czci pamici, aby pobra instrukcje jzyka ma-
szynowego skadajce si na skompilowany program. Starsze procesory Intela z rodzi-
ny x86 wykorzystuj 32-bitowy schemat adresacji, natomiast nowsze — 64-bitowy.
Procesory 32-bitowe posiadaj 2

32

(lub te 4 294 967 296) moliwych adresów, na-

tomiast procesory 64-bitowe dysponuj iloci adresów równ 2

64

(1,84467441 × 10

19

).

Procesory 64-bitowe mog pracowa w trybie kompatybilnoci 32-bitowej, co umo-
liwia im szybkie wykonywanie kodu 32-bitowego.

Bajty szesnastkowe znajdujce si porodku powyszego listingu s instrukcjami

w jzyku maszynowym procesora x86. Oczywicie, te wartoci szesnastkowe s
jedynie reprezentacjami binarnych jedynek i zer, które rozumie procesor. Ale po-
niewa 0101010110001001111001011000001111101100111100001

przydaje si

tylko procesorowi, kod maszynowy jest wywietlany jako bajty szesnastkowe, a kada
instrukcja jest umieszczana w osobnym wierszu, co przypomina podzia akapitu
na zdania.

Gdy si zastanowimy, okae si, e bajty szesnastkowe same w sobie te nie s

przydatne — tutaj dochodzi do gosu jzyk asembler. Instrukcje po prawej stronie
s zapisane w asemblerze. Asembler jest po prostu zbiorem mnemoników dla od-
powiednich instrukcji jzyka maszynowego. Instrukcja

ret

jest znacznie atwiejsza

do zapamitania i zrozumienia ni 0xc3 czy te 11000011. W przeciwiestwie do C
i innych jzyków kompilowanych, instrukcje asemblera wystpuj w relacji jeden-
do-jednego z instrukcjami odpowiednimi jzyka maszynowego. Oznacza to, e skoro
kada architektura procesora posiada wasny zestaw instrukcji jzyka maszynowego,
kada z nich ma równie wasn odmian asemblera. Jzyk asemblera jest dla pro-
gramistów tylko sposobem reprezentacji instrukcji jzyka maszynowego podawa-
nych procesorowi. Dokadny sposób reprezentacji tych instrukcji maszynowych jest
tylko kwesti konwencji i preferencji. Cho teoretycznie mona stworzy wasn
skadni asemblera dla architektury x86, wikszo osób wykorzystuje jeden z gów-
nych typów — skadni AT&T lub Intel. Kod asemblera przedstawiony na stronie 21
jest zgodny ze skadni AT&T, poniewa niemal wszystkie dezasemblery w Linuksie
domylnie wykorzystuj t skadni. Skadni AT&T mona atwo rozpozna dzi-
ki kakofonii symboli % i $ umieszczanych przed wszystkimi elementami (prosz
ponownie spojrze na stron 21). Ten sam kod mona wywietli w skadni Intela,
dodajc do polecenia

objdump

dodatkow opcj

-M

:

reader@hacking:~/booksrc $ objdump -M intel -D a.out | grep -A20 main.:
08048374 <main>:
8048374: 55 push ebp
8048375: 89 e5 mov ebp,esp

background image

38

0x200

8048377: 83 ec 08 sub esp,0x8
804837a: 83 e4 f0 and esp,0xfffffff0
804837d: b8 00 00 00 00 mov eax,0x0
8048382: 29 c4 sub esp,eax
8048384: c7 45 fc 00 00 00 00 mov DWORD PTR [ebp-4],0x0
804838b: 83 7d fc 09 cmp DWORD PTR [ebp-4],0x9
804838f: 7e 02 jle 8048393 <main+0x1f>
8048391: eb 13 jmp 80483a6 <main+0x32>
8048393: c7 04 24 84 84 04 08 mov DWORD PTR [esp],0x8048484
804839a: e8 01 ff ff ff call 80482a0 <printf@plt>
804839f: 8d 45 fc lea eax,[ebp-4]
80483a2: ff 00 inc DWORD PTR [eax]
80483a4: eb e5 jmp 804838b <main+0x17>
80483a6: c9 leave
80483a7: c3 ret
80483a8: 90 nop
80483a9: 90 nop
80483aa: 90 nop
reader@hacking:~/booksrc $

Uwaam, e skadnia Intela jest znacznie bardziej czytelna i atwiejsza do zro-

zumienia, wic bdzie ona stosowana w niniejszej ksice. Niezalenie od repre-
zentacji jzyka asemblera, polecenia rozumiane przez procesor s cakiem proste.
Instrukcje te skadaj si z operacji i czasem dodatkowych operacji opisujcych cel
i (lub) ródo operacji. Operacje te przenosz dane w pamici, aby wykona jakie-
go rodzaju podstawowe dziaania matematyczne, lub przerywaj dziaanie proce-
sora, by wykona co innego. To jest wszystko, co procesor potrafi wykona. Jednak,
podobnie jak za pomoc stosunkowo niewielkiego alfabetu napisano miliony ksiek,
tak samo, korzystajc z niewielkiego zbioru instrukcji maszynowych, mona utworzy
nieskoczenie wiele programów.

Procesory posiadaj równie wasny zestaw specjalnych zmiennych zwanych

rejestrami. Wikszo instrukcji wykorzystuje rejestry do odczytywania lub zapi-
sywania danych, wic ich poznanie jest niezbdne do zrozumienia instrukcji. Duy
obraz wci si powiksza…

0x252

Procesor x86

Procesor 8086 by pierwszym procesorem w architekturze x86. Zosta opracowany
i wyprodukowany przez firm Intel, która póniej wprowadzaa na rynek bardziej
zaawansowane procesory z tej rodziny: 80186, 80286m 80386 i 80486. Jeeli pami-
tasz, e w latach 80. i 90. ubiegego wieku mówiono o procesorach 386 i 486, chodzio
wówczas o te wanie ukady.

Procesor x86 posiada kilka rejestrów, które s dla niego czym w rodzaju we-

wntrznych zmiennych. Mógbym teraz przeprowadzi abstrakcyjny wykad na temat
rejestrów, ale uwaam, e lepiej zobaczy co na wasne oczy. Narzdzia progra-
mistyczne GNU zawieraj równie debuger o nazwie GDB. Debugery s uywane
przez programistów do wykonywania skompilowanych programów krok po kroku,
badania pamici programu i przegldania rejestrów procesora. Programista, który

background image

Programowanie

39

nigdy nie korzysta z debugera do przyjrzenia si wewntrznym mechanizmom
pracy programu, jest jak siedemnastowieczny badacz, który nigdy nie uywa mi-
kroskopu. Debuger, tak jak mikroskop, pozwala hakerowi na precyzyjne przyjrze-
nie si kodowi maszynowemu, ale moliwoci debugera wykraczaj daleko poza t
metafor. W przeciwiestwie do mikroskopu, debuger umoliwia obejrzenie wy-
konywania programu ze wszystkich stron, wstrzymanie go oraz zmian wszelkich
parametrów.

Poniej GDB zosta uyty do wywietlenia stanu rejestrów procesora tu przed

rozpoczciem programu:

reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) break main

Breakpoint 1 at 0x804837a
(gdb) run
Starting program: /home/reader/booksrc/a.out

Breakpoint 1, 0x0804837a in main ()
(gdb) info registers
eax 0xbffff894 -1073743724
ecx 0x48e0fe81 1222704769
edx 0x1 1
ebx 0xb7fd6ff4 -1208127500
esp 0xbffff800 0xbffff800
ebp 0xbffff808 0xbffff808
esi 0xb8000ce0 -1207956256
edi 0x0 0
eip 0x804837a 0x804837a <main+6>
eflags 0x286 [ PF SF IF ]
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
reader@hacking:~/booksrc $

Punkt wstrzymania zosta ustawiony przy funkcji

main()

, wic wykonywanie

programu zostanie zatrzymane tu przed uruchomieniem naszego kodu. Nastpnie
GDB uruchamia program, zatrzymuje si w punkcie wstrzymania i wywietla wszyst-
kie rejestry procesora i ich biecy stan.

Pierwsze cztery rejestry (EAX, ECX, EDX i EBX) s rejestrami ogólnego prze-

znaczenia. S to odpowiednio rejestry: akumulatorowy, licznika, danych i bazowy.
S one wykorzystywane do rónych celów, ale su gównie jako zmienne tymcza-
sowe dla procesora, gdy wykonuje instrukcje kodu maszynowego.

background image

40

0x200

Kolejne cztery rejestry (ESP, EBP, ESI i EDI) s równie rejestrami ogólnego

przeznaczenia, ale czasem nazywa si je wskanikami i indeksami. S to odpowiednio:
wskanik, wskanik bazowy, ródo i przeznaczenie. Pierwsze dwa rejestry s nazy-
wane wskanikami, poniewa przechowuj 32-bitowe adresy, wskazujce do miejsc
w pamici. Te rejestry s istotne dla wykonywania programu i zarzdzania pamici.
Póniej omówi je dokadniej. Kolejne dwa rejestry, z technicznego punktu widzenia
równie wskanikowe, czsto wykorzystywane s do wskazywania róda i celu, gdy
dane musz by odczytane lub zapisane. Istniej instrukcje odczytujce i zapisujce,
które uywaj tych rejestrów, ale przewanie mona je traktowa jak zwyke rejestry
ogólnego przeznaczenia.

Rejestr EIP jest rejestrem wskanika instrukcji, wskazujcym aktualnie wykony-

wan instrukcj. Tak jak dziecko podczas czytania pokazuje sobie palcem poszczegól-
ne sowa, tak procesor odczytuje konkretne instrukcje, korzystajc z EIP jak z palca.
Oczywicie, rejestr ten jest bardzo istotny i bdzie czsto wykorzystywany podczas
debugowania. Aktualnie wskazuje adres pamici 0x804838a.

Pozostay rejestr, EFLAGS, zawiera kilka flag bitowych wykorzystywanych do

porówna oraz segmentacji pamici. Pami jest dzielona na kilka rónych seg-
mentów, co opisz póniej, a rejestr ten pozwala je ledzi. Przewanie moemy je
zignorowa, poniewa rzadko konieczny jest bezporedni dostp do nich.

0x253

Jzyk asembler

Poniewa w niniejszej ksice wykorzystujemy skadni Intela w jzyku asembler,
musimy odpowiednio skonfigurowa narzdzia. W GDB skadni dezasemblera
mona ustawi na intelowsk, wpisujc po prostu

set disassembly intel

lub w skrócie

set dis intel

. Moemy skonfigurowa GDB tak, aby to ustawienie byo aktywne

przy kadym uruchomieniu, umieszczajc to polecenie w pliku .gdbinit w katalogu
domowym.

reader@hacking:~/booksrc $ gdb -q
(gdb) set dis intel
(gdb) quit
reader@hacking:~/booksrc $ echo "set dis intel" > ~/.gdbinit
reader@hacking:~/booksrc $ cat ~/.gdbinit
set dis intel
reader@hacking:~/booksrc $

Po skonfigurowaniu GDB tak, eby wykorzystywa skadni Intela, zapoznajmy

si z ni. W skadni Intela instrukcje asemblera maj zwykle ponisz posta:

operacja <cel>, <ródo>

Wartociami docelowymi i ródowymi s rejestr, adres pamici lub warto.

Operacje s zwykle intuicyjnie rozumianymi mnemonikami. Operacja

mov

przenosi

warto ze róda do celu,

sub

odejmuje,

inc

inkrementuje itd. Przykadowo ponisze

instrukcje przenosz warto z ESP do EBP, a nastpnie odejmuj 8 od ESP (zapisu-
jc wynik w ESP).

background image

Programowanie

41

8048375: 89 e5 mov ebp,esp
8048377: 83 ec 08 sub esp,0x8

Dostpne s równie operacje wykorzystywane do sterowanie przebiegiem

wykonywania. Operacja

cmp

suy do porównywania wartoci, a niemal wszystkie

operacje, których nazwa rozpoczyna si liter

j

, su do przeskakiwania do innej

czci kodu (w zalenoci od wyniku porównania). W poniszym przykadzie najpierw
4-bajtowa warto znajdujca w ERB minus 4 jest porównywana z liczb 9. Nastpna
instrukcja jest skrótem od przeskocz, jeeli mniejsze lub równe ni (ang. jump if less
than or equal to
), odnoszcym si do wyniku wczeniejszego porównania. Jeeli
warto ta jest mniejsza lub równa 9, wykonywanie przeskoczy do instrukcji znaj-
dujcej si pod adresem 0x8048393. W przeciwnym przypadku wykonywana bdzie
kolejna instrukcja z bezwarunkowym przeskokiem. Jeeli warto nie bdzie mniejsza
ani równa 9, procesor przeskoczy do 0x80483a6.

804838b: 83 7d fc 09 cmp DWORD PTR [ebp-4],0x9
804838f: 7e 02 jle 8048393 <main+0x1f>
8048391: eb 13 jmp 80483a6 <main+0x32>

Przykady te pochodz z naszej poprzedniej dezasemblacji. Skonfigurowalimy

debuger do wykorzystywania skadni Intela, wic wykorzystajmy go do kroczenia
przez nasz pierwszy program na poziomie instrukcji asemblera.

W kompilatorze GCC mona poda opcj

–g

, dziki czemu zostan doczone

dodatkowe informacje debugowania, co da GDB dostp do kodu ródowego.

reader@hacking:~/booksrc $ gcc -g firstprog.c
reader@hacking:~/booksrc $ ls -l a.out
-rwxr-xr-x 1 matrix users 11977 Jul 4 17:29 a.out
reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) list
1 #include <stdio.h>
2
3 int main()
4 {
5 int i;
6 for(i=0; i < 10; i++)
7 {
8 printf("Hello, world!\n");
9 }
10 }
(gdb) disassemble main
Dump of assembler code for function main():
0x08048384 <main+0>: push ebp
0x08048385 <main+1>: mov ebp,esp
0x08048387 <main+3>: sub esp,0x8
0x0804838a <main+6>: and esp,0xfffffff0
0x0804838d <main+9>: mov eax,0x0
0x08048392 <main+14>: sub esp,eax

background image

42

0x200

0x08048394 <main+16>: mov DWORD PTR [ebp-4],0x0
0x0804839b <main+23>: cmp DWORD PTR [ebp-4],0x9
0x0804839f <main+27>: jle 0x80483a3 <main+31>
0x080483a1 <main+29>: jmp 0x80483b6 <main+50>
0x080483a3 <main+31>: mov DWORD PTR [esp],0x80484d4
0x080483aa <main+38>: call 0x80482a8 <_init+56>
0x080483af <main+43>: lea eax,[ebp-4]
0x080483b2 <main+46>: inc DWORD PTR [eax]
0x080483b4 <main+48>: jmp 0x804839b <main+23>
0x080483b6 <main+50>: leave
0x080483b7 <main+51>: ret
End of assembler dump.
(gdb) break main
Breakpoint 1 at 0x8048394: file firstprog.c, line 6.
(gdb) run
Starting program: /hacking/a.out

Breakpoint 1, main() at firstprog.c:6
6 for(i=0; i < 10; i++)
(gdb) info register eip
eip 0x8048394 0x8048394
(gdb)

Najpierw wypisywany jest kod ródowy oraz dezasemblacja funkcji

main()

.

Nastpnie na pocztku

main()

ustawiany jest punkt wstrzymania i program jest

uruchamiany. Ten punkt wstrzymania po prostu informuje debuger, aby wstrzyma
wykonywanie programu, gdy dojdzie do tego punktu. Poniewa punkt wstrzymania
zosta ustawiony na pocztku funkcji

main()

, program dociera do punktu wstrzy-

mania i zatrzymuje si przed wykonaniem jakichkolwiek instrukcji z funkcji

main()

.

Nastpnie wywietlana jest warto EIP (wskanika instrukcji).

Naley zwróci uwag, e EIP zawiera adres pamici, wskazujcy instrukcj

w dezasemblacji funkcji

main()

(pogrubionej na listingu). Wczeniejsze instrukcje

(zapisane kursyw), razem nazywane prologiem funkcji, s generowane przez kom-
pilator w celu ustawienia pamici dla reszty zmiennych lokalnych funkcji

main()

.

Jednym z powodów koniecznoci deklaracji zmiennych w jzyku C jest pomoc
w konstrukcji tej czci kodu. Debuger „wie”, e ta cz kodu jest generowana
automatycznie i potrafi j pomin. Prologiem funkcji zajmiemy si póniej, a na
razie, wzorujc si na GDB, pominiemy go.

Debuger GDB zawiera bezporedni metod badania pamici za pomoc pole-

cenia

x

, które jest skrótem od examine. Badanie pamici jest bardzo wan umiejtno-

ci kadego hakera. Wikszo technik hakerskich przypomina sztuczki magiczne
— wydaj si niesamowite i magiczne, dopóki nie poznasz oszustwa. Zarówno
w magii, jak i hakerstwie, jeeli popatrzymy w odpowiednie miejsce, sztuczka stanie
si oczywista. Jest to jeden z powodów, dla których dobry magik nigdy nie wykonuje
dwa razy tego samego triku w czasie jednego wystpu. Jednak za pomoc debugera,
takiego jak GDB, moemy dokadnie zbada kady aspekt wykonywania programu,
wstrzyma go, przej krok dalej i powtórzy tyle razy, ile potrzeba. Poniewa
dziaajcy program to w wikszoci procesor i segmenty pamici, zbadanie pamici
jest pierwsz z metod przekonania si, co naprawd si dzieje.

background image

Programowanie

43

Polecenie

examine

w GDB moe zosta uyte do przyjrzenia si okrelonym adre-

som pamici na róne sposoby. To polecenie oczekuje dwóch argumentów: miejsca
w pamici, które ma by zbadane, oraz okrelenia sposobu wywietlania zawartoci.

Do okrelania formatu wywietlania równie uywany jest jednoliterowy skrót,

który mona poprzedzi liczb elementów do zbadania. Najczciej wykorzystywane
s ponisze skróty formatujce:

o — wywietla w formacie ósemkowym,

x — wywietla w formacie szesnastkowym,

u — wywietla w standardowym systemie dziesitnym, bez znaków,

t — wywietla w formacie binarnym.

Liter tych mona uy z poleceniem

examine

do zbadania okrelonego adresu

pamici. W poniszym przykadzie wykorzystano biecy adres z rejestru EIP.
Skrócone polecenia s czsto wykorzystywane w GDB i nawet

info register eip

mona skróci do

i r eip

.

(gdb) i r eip
eip 0x8048384 0x8048384 <main+16>
(gdb) x/o 0x8048384
0x8048384 <main+16>: 077042707
(gdb) x/x $eip
0x8048384 <main+16>: 0x00fc45c7
(gdb) x/u $eip
0x8048384 <main+16>: 16532935
(gdb) x/t $eip
0x8048384 <main+16>: 00000000111111000100010111000111
(gdb)

Pami, któr wskazuje rejestr EIP, moe by zbadana za pomoc adresu prze-

chowywanego w EIP. Debuger umoliwia bezporednie odwoywanie si do reje-
strów, wic

$eip

jest równowane wartoci przechowywanej aktualnie w EIP. Warto

077042707 w systemie ósemkowym jest tym samym, co 0x00fc45c7 w systemie szes-
nastkowym, co jest tym samym, co 16532935 w systemie dziesitnym, co z kolei jest
tym samym, co 00000000111111000100010111000111 w systemie dwójkowym.
Format polecenia

examine

mona równie poprzedzi cyfr, okrelajc liczb

badanych jednostek w docelowym adresie.

(gdb) x/2x $eip
0x8048384 <main+16>: 0x00fc45c7 0x83000000
(gdb) x/12x $eip
0x8048384 <main+16>: 0x00fc45c7 0x83000000 0x7e09fc7d 0xc713eb02
0x8048394 <main+32>: 0x84842404 0x01e80804 0x8dffffff 0x00fffc45
0x80483a4 <main+48>: 0xc3c9e5eb 0x90909090 0x90909090 0x5de58955
(gdb)

background image

44

0x200

Domylnym rozmiarem jednej jednostki jest 4-bajtowa jednostka zwana sowem.

Rozmiar jednostek wywietlania dla polecenia

examine

moe by zmieniany poprzez

dodanie odpowiedniej litery za liter formatujc. Poprawnymi literami rozmiaru s:

b — pojedynczy bajt,

h — pósowo o rozmiarze dwóch bajtów,

w — sowo o rozmiarze czterech bajtów,

g — sowo podwójne o rozmiarze omiu bajtów.

Wprowadza to pewien zamt, poniewa czasami termin sowo okrela równie

wartoci 2-bajtowe. W takim przypadku podwójne sowo lub DWORD oznacza war-
to 4-bajtow. W ksice tej terminy „sowo” i DWORD bd okrelay wartoci
4-bajtowe. Do okrelania wartoci 2-bajtowych bdzie uywany termin „pósowo”.
Ponisze wyjcie z GDB obrazuje pami wywietlan w rónych rozmiarach.

(gdb) x/8xb $eip
0x8048384 <main+16>: 0xc7 0x45 0xfc 0x00 0x00 0x00 0x00 0x83
(gdb) x/8xh $eip
0x8048384 <main+16>: 0x45c7 0x00fc 0x0000 0x8300 0xfc7d 0x7e09 0xeb02 0xc713
(gdb) x/8xw $eip
0x8048384 <main+16>: 0x00fc45c7 0x83000000 0x7e09fc7d 0xc713eb02
0x8048394 <main+32>: 0x84842404 0x01e80804 0x8dffffff 0x00fffc45
(gdb)

Jeeli dobrze si przyjrzysz, zauwaysz w powyszych danych co dziwnego.

Pierwsze polecenie

examine

pokazuje pierwsze osiem bajtów i, oczywicie, polece-

nia

examine

wykorzystujce wiksze jednostki wywietlaj wicej danych. Jednake

wynik pierwszego polecenia pokazuje, e pierwszymi dwoma bajtami s 0xc7 i 0x45,
ale gdy badane jest pósowo w dokadnie tym samym adresie pamici, pokazywana
jest warto 0x45c7, czyli bajty s odwrócone. Ten sam efekt moemy zauway
w przypadku penego 4-bajtowego sowa wywietlanego jako 0x00fc45c7. Jeeli
jednak pierwsze cztery bajty s wywietlane bajt po bajcie maj one kolejno 0xc7,
0x45m 0xfc i 0x00.

Jest tak, poniewa w procesorze x86 wartoci s przechowywane w kolejnoci

little endian, co oznacza, e najmniej istotny bajt jest przechowywany jako pierwszy.
Jeeli np. cztery bajty maj by interpretowane jako jedna warto, bajty musz by
uyte w odwrotnej kolejnoci. Debuger GDB jest na tyle mdry, e wie, jak prze-
chowywane s wartoci, wic gdy badane jest sowo lub pósowo, bajty musz by
odwrócone w celu wywietlenia poprawnych wartoci w ukadzie szesnastkowym.
Przejrzenie tych wywietlanych wartoci w systemie szesnastkowym i jako liczb
dziesitnych bez znaku moe uatwi zrozumienie tej kwestii.

(gdb) x/4xb $eip
0x8048384 <main+16>: 0xc7 0x45 0xfc 0x00
(gdb) x/4ub $eip
0x8048384 <main+16>: 199 69 252 0
(gdb) x/1xw $eip

background image

Programowanie

45

0x8048384 <main+16>: 0x00fc45c7
(gdb) x/1uw $eip
0x8048384 <main+16>: 16532935
(gdb) quit
The program is running. Exit anyway? (y or n) y
reader@hacking:~/booksrc $ bc -ql
199*(256^3) + 69*(256^2) + 252*(256^1) + 0*(256^0)
3343252480
0*(256^3) + 252*(256^2) + 69*(256^1) + 199*(256^0)
16532935
quit
reader@hacking:~/booksrc $

Pierwsze cztery bajty s pokazane zarówno w notacji szesnastkowej, jak i standar-

dowej, dziesitnej. Kalkulator dziaajcy w wierszu polece

bc

posuy do wyka-

zania, e jeeli bajty zostan zinterpretowane w nieprawidowej kolejnoci, otrzy-
mamy w wyniku zupenie nieprawidow warto 3343252480. Kolejno bajtów
w danej architekturze jest istotnym czynnikiem, którego naley by wiadomym.
Cho wikszo narzdzi debugujcych i kompilatorów zajmuje si automatycznie
szczegóami zwizanymi z kolejnoci bajtów, czasem bdziesz musia samodzielnie
manipulowa pamici.

Oprócz konwersji kolejnoci bajtów, GDB moe za pomoc polecenia

examine

wykonywa inne konwersje. Widzielimy ju, e GDB moe dezasemblowa instruk-
cje jzyka maszynowego na zrozumiae dla czowieka instrukcje asemblera. Pole-
cenie

examine

przyjmuje równie liter formatujc

i

(skrót od instruction), co po-

woduje wywietlenie pamici jako dezasemblowanych instrukcji jzyka asembler.

reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) break main
Breakpoint 1 at 0x8048384: file firstprog.c, line 6.
(gdb) run
Starting program: /home/reader/booksrc/a.out

Breakpoint 1, main () at firstprog.c:6
6 for(i=0; i < 10; i++)
(gdb) i r $eip
eip 0x8048384 0x8048384 <main+16>
(gdb) x/i $eip
0x8048384 <main+16>: mov DWORD PTR [ebp-4],0x0
(gdb) x/3i $eip
0x8048384 <main+16>: mov DWORD PTR [ebp-4],0x0
0x804838b <main+23>: cmp DWORD PTR [ebp-4],0x9
0x804838f <main+27>: jle 0x8048393 <main+31>
(gdb) x/7xb $eip
0x8048384 <main+16>: 0xc7 0x45 0xfc 0x00 0x00 0x00 0x00
(gdb) x/i $eip
0x8048384 <main+16>: mov DWORD PTR [ebp-4],0x0
(gdb)

background image

46

0x200

W powyszym przykadzie program a.out zosta uruchomiony w GDB z punktem

wstrzymania ustawionym w

main()

. Poniewa rejestr EIP wskazuje na pami, która

faktycznie zawiera instrukcje w jzyku maszynowym, adnie poddaj si one proce-
sowi dezasemblacji.

Wczeniejsza dezasemblacja za pomoc

objectdump

potwierdza, e siedem bajtów,

które wskazuje EIP, to faktycznie jzyk maszynowy dla odpowiedniej instrukcji
asemblera.

8048384: c7 45 fc 00 00 00 00 mov DWORD PTR [ebp-4],0x0

Ta instrukcja asemblera przenosi warto 0 do pamici znajdujcej si pod ad-

resem przechowywanym w rejestrze EBP minus 4. To wanie w tym miejscu pa-
mici przechowywana jest zmienna

i

z jzyka C. Zmienna ta zostaa zadeklarowana

jako liczba cakowita (

int

), wykorzystujca 4 bajty pamici w przypadku procesora

x86. To polecenie po prostu zeruje zmienn

i

dla ptli

for

. Gdybymy teraz zbadali

t pami, zawieraaby ona tylko przypadkowe mieci. Pami w tej lokacji mona
zbada na róne sposoby:

(gdb) i r ebp
ebp 0xbffff808 0xbffff808
(gdb) x/4xb $ebp - 4
0xbffff804: 0xc0 0x83 0x04 0x08
(gdb) x/4xb 0xbffff804
0xbffff804: 0xc0

0x83 0x04 0x08

(gdb) print $ebp - 4
$1 = (void *) 0xbffff804
(gdb) x/4xb $1
0xbffff804: 0xc0 0x83 0x04 0x08
(gdb) x/xw $1
0xbffff804: 0x080483c0
(gdb)

Rejestr EBP zawiera adres 0xbffff808, a instrukcja asemblera bdzie zapisywaa

do adresu o tej wartoci pomniejszonej o 4 — 0xbfffff804. Polecenie

examine

moe

zbada bezporednio ten adres pamici lub wykona odpowiednie obliczenia w locie.
Za pomoc polecenia

print

równie mona wykona proste dziaania arytmetyczne,

a wynik zostanie zapisany w tymczasowej zmiennej w debugerze. Zmienna ta nosi
nazw

$1

i moe póniej zosta uyta do szybkiego uzyskania dostpu do okrelonego

miejsca w pamici. Kada z przedstawionych wyej metod pozwala uzyska ten
sam rezultat: wywietlenie znalezionych w pamici 4 bajtów mieci, które zostan
wyzerowane po wykonaniu biecej instrukcji.

Uruchommy biec instrukcj, korzystajc z polecenia

nexti

, bdcego skrótem

dla next instruction (nastpna instrukcja). Procesor odczyta instrukcj z EIP, wykona
j i przestawi EIP na kolejn instrukcj.

background image

Programowanie

47

(gdb) nexti
0x0804838b 6 for(i=0; i < 10; i++)
(gdb) x/4xb $1
0xbffff804: 0x00 0x00 0x00 0x00
(gdb) x/dw $1
0xbffff804: 0
(gdb) i r eip
eip 0x804838b 0x804838b <main+23>
(gdb) x/i $eip
0x804838b <main+23>: cmp DWORD PTR [ebp-4],0x9
(gdb)

Zgodnie z oczekiwaniami, poprzednia instrukcja zeruje 4 bajty odnalezione

w adresie EBP minus 4, czyli pamici przydzielonej zmiennej

i

z kodu C. EIP

przechodzi do kolejnej instrukcji. Omówienie kolejnych instrukcji warto przepro-
wadzi cznie.

(gdb) x/10i $eip
0x804838b <main+23>: cmp DWORD PTR [ebp-4],0x9
0x804838f <main+27>: jle 0x8048393 <main+31>
0x8048391 <main+29>: jmp 0x80483a6 <main+50>
0x8048393 <main+31>: mov DWORD PTR [esp],0x8048484
0x804839a <main+38>: call 0x80482a0 <printf@plt>
0x804839f <main+43>: lea eax,[ebp-4]
0x80483a2 <main+46>: inc DWORD PTR [eax]
0x80483a4 <main+48>: jmp 0x804838b <main+23>
0x80483a6 <main+50>: leave
0x80483a7 <main+51>: ret
(gdb)

Pierwsza instrukcja,

cmp

, jest instrukcj porównania, która porównuje zawarto

pamici wykorzystywanej przez zmienn i z kodu C z wartoci 9. Kolejna instrukcja,

jle

, oznacza przeskocz, jeeli mniejsze lub równe (ang. jump if less than equal to).

Wykorzystuje ona wynik poprzedniego porównania (który jest przechowywany
w rejestrze EFLAGS) do przestawienia EIP tak, aby wskazywa inn cz kodu,
jeeli cel poprzedniej operacji porównania jest mniejszy lub równy ródu. W tym
przypadku instrukcja powoduje przeskok do adresu 0x8048393, jeeli warto
przechowywana w pamici dla zmiennej

i

jest mniejsza lub równa wartoci 9. W prze-

ciwnym przypadku EIP przejdzie do kolejnej instrukcji, która jest instrukcj prze-
skoku bezwarunkowego. Powoduje ona przeskok EIP do adresu 0x80483a6. Te trzy
instrukcje cznie tworz struktur sterujc

if-then-else

: jeeli

i

jest mniejsze lub

równe 9, przejd do instrukcji pod adresem 0x8048393; w przeciwnym przypadku
przejd do instrukcji pod adresem 0x80483a6
. Pierwszy adres, 0x804893 (pogrubiony),
jest po prostu sta instrukcj przeskoku, a drugi adres — 0x80483a6 (zapisany
kursyw) — znajduje si na kocu funkcji.

Poniewa wiemy, e w lokacji pamici porównywanej z 9 przechowywane jest 0

i wiemy, e 0 jest mniejsze lub równe 9, po wykonaniu kolejnych dwóch instrukcji
EIP powinien wskazywa na 0x8048393.

background image

48

0x200

(gdb) nexti
0x0804838f 6 for(i=0; i < 10; i++)
(gdb) x/i $eip
0x804838f <main+27>: jle 0x8048393 <main+31>
(gdb) nexti
8 printf("Hello world!\n");
(gdb) i r eip
eip 0x8048393 0x8048393 <main+31>
(gdb) x/2i $eip
0x8048393 <main+31>: mov DWORD PTR [esp],0x8048484
0x804839a <main+38>: call 0x80482a0 <printf@plt>
(gdb)

Zgodnie z oczekiwaniami, wczeniejsze dwie instrukcje przeniosy wykonywanie

programu do 0x8048393, co doprowadza do kolejnych dwóch instrukcji. Pierwsza
z nich jest kolejn instrukcj

mov

, która zapisze adres 0x8048484 do adresu pamici

znajdujcego si w rejestrze ESP. Ale co wskazuje ESP?

(gdb) i r esp
esp 0xbffff800 0xbffff800
(gdb)

W tej chwili ESP wskazuje adres pamici 0xbffff800, wic po wykonaniu instrukcji

mov

zostanie tutaj zapisany adres 0x8048484. Ale dlaczego? Co takiego specjalnego

jest w adresie pamici 0x8048484? Jest tylko jeden sposób, aby si o tym przekona.

(gdb) x/2xw 0x8048484
0x8048484: 0x6c6c6548 0x6f57206f
(gdb) x/6xb 0x8048484
0x8048484: 0x48 0x65 0x6c 0x6c 0x6f 0x20
(gdb) x/6ub 0x8048484
0x8048484: 72 101 108 108 111 32
(gdb)

Dowiadczony czytelnik moe zauway w tej pamici co szczególnego, zwasz-

cza w zakresie bajtów. Po nabraniu dowiadczenia w badaniu pamici tego typu
wzorce stan si bardziej oczywiste. Bajty te zawieraj si w zakresie znaków ASCII.
ASCII jest uzgodnionym standardem, który odwzorowuje wszystkie znaki z klawia-
tury (a take kilka innych) na stae liczby. Bajty 0x48, 0x65 i 0x6f odpowiadaj literom
alfabetu przedstawionym w tabeli znaków ASCII (tabela 2.1). Tabel mona znale
na stronach podrcznika ASCII dostpnego w wikszoci systemów Unix po wpi-
saniu

man

ascii

.

Na szczcie, polecenie

examine

w GDB posiada równie moliwo przyjrzenia

si tego typu pamici. Litera formatujca

c

umoliwia automatyczne sprawdzenie

bajta w tablicy ASCII, a litera formatujca

s

powoduje wywietlenie caego acucha

danych znakowych.

background image

Programowanie

49

Tabela 2.1. Tablica znaków ASCII

Oct

Dec

Hex

Char

Oct

Dec

Hex

Char

000

0

00

NUL '\0'

100

64

40

@

001

1

01

SOH

101

65

41

A

002

2

02

STX

102

66

42

B

003

3

03

ETX

103

67

43

C

004

4

04

EOT

104

68

44

D

005

5

05

ENQ

105

69

45

E

006

6

06

ACK

106

70

46

F

007

7

07

BEL '\a'

107

71

47

G

010

8

08

BS '\b'

110

72

48

H

011

9

09

HT '\t'

111

73

49

I

012

10

0A

LF '\n'

112

74

4A

J

013

11

0B

VT '\v'

113

75

4B

K

014

12

0C

FF '\f'

114

76

4C

L

015

13

0D

CR '\r'

115

77

4D

M

016

14

0E

SO

116

78

4E

N

017

15

0F

SI

117

79

4F

O

020

16

10

DLE

120

80

50

P

021

17

11

DC1

121

81

51

Q

022

18

12

DC2

122

82

52

R

023

19

13

DC3

123

83

53

S

024

20

14

DC4

124

84

54

T

025

21

15

NAK

125

85

55

U

026

22

16

SYN

126

86

56

V

027

23

17

ETB

127

87

57

W

030

24

18

CAN

130

88

58

X

031

25

19

EM

131

89

59

Y

032

26

1A

SUB

132

90

5A

Z

033

27

1B

ESC

133

91

5B

[

034

28

1C

FS

134

92

5C

\ '\\'

035

29

1D

GS

135

93

5D

]

036

30

1E

RS

136

94

5E

^

037

31

1F

US

137

95

5F

_

040

32

20

SPACE

140

96

60

041

33

21

!

141

97

61

a

042

34

22

"

142

98

62

b

043

35

23

#

143

99

63

c

background image

50

0x200

Tabela 2.1. Tablica znaków ASCII — cig dalszy

Oct

Dec

Hex

Char

Oct

Dec

Hex

Char

044

36

24

$

144

100

64

d

045

37

25

%

145

101

65

e

046

38

26

&

146

102

66

f

047

39

27

'

147

103

67

g

050

40

28

(

150

104

68

h

051

41

29

)

151

105

69

i

052

42

2A

*

152

106

6A

j

053

43

2B

+

153

107

6B

k

054

44

2C

,

154

108

6C

l

055

45

2D

-

155

109

6D

m

056

46

2E

.

156

110

6E

n

057

47

2F

/

157

111

6F

o

060

48

30

0

160

112

70

p

061

49

31

1

161

113

71

q

062

50

32

2

162

114

72

r

063

51

33

3

163

115

73

s

064

52

34

4

164

116

74

t

065

53

35

5

165

117

75

u

066

54

36

6

166

118

76

v

067

55

37

7

167

119

77

w

070

56

38

8

170

120

78

x

071

57

39

9

171

121

79

y

072

58

3A

:

172

122

7A

z

073

59

3B

;

173

123

7B

{

074

60

3C

<

174

124

7C

|

075

61

3D

=

175

125

7D

}

076

62

3E

>

176

126

7E

~

077

63

3F

?

177

127

7F

DEL

(gdb) x/6cb 0x8048484
0x8048484: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' '
(gdb) x/s 0x8048484
0x8048484: "Hello, world!\n"
(gdb)

Polecenia te pokazuj, e pod adresem 0x8048484 przechowywany jest acuch

danych

"Hello, world!\n"

. Ten acuch jest argumentem funkcji

printf()

, co wska-

zuje, e przeniesienie adresu tego acucha do adresu przechowywanego w ESP

background image

Programowanie

51

(0x8048484) ma co wspólnego z t funkcj. Poniszy wynik z

gdb

pokazuje adres

acucha danych przenoszony do adresu, który wskazuje ESP.

(gdb) x/2i $eip
0x8048393 <main+31>: mov DWORD PTR [esp],0x8048484
0x804839a <main+38>: call 0x80482a0 <printf@plt>
(gdb) x/xw $esp
0xbffff800: 0xb8000ce0
(gdb) nexti
0x0804839a 8 printf("Hello, world!\n");
(gdb) x/xw $esp
0xbffff800: 0x08048484
(gdb)

Kolejna instrukcja wywouje funkcj

printf()

. Wypisuje ona acuch danych.

Wczeniej instrukcje stanowiy przygotowania do wywoania tej funkcji, a wynik
tego wywoania zosta pogrubiony poniej.

(gdb) x/i $eip
0x804839a <main+38>: call 0x80482a0 <printf@plt>
(gdb) nexti
Hello, world!
6 for(i=0; i < 10; i++)
(gdb)

Korzystajc dalej z debugera, przyjrzyjmy si kolejnym dwóm instrukcjom.

Ponownie wikszy sens ma opisanie ich razem.

(gdb) x/2i $eip
0x804839f <main+43>: lea eax,[ebp-4]
0x80483a2 <main+46>: inc DWORD PTR [eax]
(gdb)

Te dwie instrukcje po prostu zwikszaj warto zmiennej

i

o 1. Instrukcja

lea

,

akronim od Load Effective Address (wczytaj efektywny adres), wczytuje znany ju
adres EBP minus 4 do rejestru EAX. Wykonanie tej instrukcji przedstawiono poniej.

(gdb) x/ i $eip
0x804839f <main+43>: lea eax,[ebp-4]
(gdb) print $ebp - 4
$2 = (void *) 0xbffff804
(gdb) x/x $2
0xbffff804: 0x00000000
(gdb) i r eax
eax 0xd 13
(gdb) nexti
0x080483a2 6 for(i=0; i < 10; i++)
(gdb) i r eax
eax 0xbffff804 -1073743868
(gdb) x/xw $eax

background image

52

0x200

0xbffff804: 0x00000000
(gdb) x/dw $eax
0xbffff804: 0
(gdb)

Kolejna instrukcja,

inc

, zwikszy warto znalezion pod tym adresem (przecho-

wywan teraz w rejestrze EAX) o 1. Wykonanie tej instrukcji równie przedstawiono
poniej.

(gdb) x/i $eip
0x80483a2 <main+46>: inc DWORD PTR [eax]
(gdb) x/dw $eax
0xbffff804: 0
(gdb) nexti
0x080483a4 6 for(i=0; i < 10; i++)
(gdb) x/dw $eax
0xbffff804: 1
(gdb)

W wyniku warto przechowywana pod adresem pamici EBP minus 4 (0xbfffff804)

jest powikszana o 1. To zachowanie odpowiada fragmentowi kodu C, w którym
warto zmiennej

i

jest powikszana w ptli

for

.

Kolejn instrukcj jest bezwarunkowy przeskok.

(gdb) x/i $eip
0x80483a4 <main+48>: jmp 0x804838b <main+23>
(gdb)

Instrukcja po wykonaniu przekieruje program z powrotem do instrukcji spod

adresu 0x804838b. Dokonuje tego poprzez proste ustawienie EIP na t warto.

Spogldajc ponownie na pen dezasemblacj, powiniene stwierdzi, które

czci kodu C zostay skompilowane do których instrukcji jzyka maszynowego.

(gdb) disass main
Dump of assembler code for function main:
0x08048374 <main+0>: push ebp
0x08048375 <main+1>: mov ebp,esp
0x08048377 <main+3>: sub esp,0x8
0x0804837a <main+6>: and esp,0xfffffff0
0x0804837d <main+9>: mov eax,0x0
0x08048382 <main+14>: sub esp,eax
0x08048384 <main+16>: mov DWORD PTR [ebp-4],0x0
0x0804838b <main+23>: cmp DWORD PTR [ebp-4],0x9
0x0804838f <main+27>: jle 0x8048393 <main+31>
0x08048391 <main+29>: jmp 0x80483a6 <main+50>
0x08048393 <main+31>: mov DWORD PTR [esp],0x8048484
0x0804839a <main+38>: call 0x80482a0 <printf@plt>
0x0804839f <main+43>: lea eax,[ebp-4]
0x080483a2 <main+46>: inc DWORD PTR [eax]
0x080483a4 <main+48>: jmp 0x804838b <main+23>


Wyszukiwarka

Podobne podstrony:
Asembler Sztuka programowania Wydanie II asesz2
hacking sztuka+penetracji reklam%f3wka+ksi%b9%bfki PY5Q567BORKJTPXQMPE75HYCNH47C3KJWDLAPTI
Hacking Sztuka penetracji
Hacking Sztuka penetracji hacpen
Sztuka Wojny Wydanie II artwa2
Sztuka Wojny Wydanie II superekskluzywne exawa2
Hacking Sztuka penetracji 2
Asembler Sztuka programowania Wydanie II 2
[demo] Hacking Sztuka penetracji
Asembler Sztuka programowania Wydanie II
Hacking Sztuka penetracji
Sztuka Wojny Wydanie II

więcej podobnych podstron