Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00318 008409 10493344 na godz. na dobę w sumie
Hacking. Sztuka penetracji. Wydanie II - książka
Hacking. Sztuka penetracji. Wydanie II - książka
Autor: Liczba stron: 512
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-1802-6 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> hacking >> klasyka hakera
Porównaj ceny (książka, ebook, audiobook).

Zdobądź wiedzę godną hakera!

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.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Hacking. Sztuka penetracji. Wydanie II Autor: Jon Erickson T‡umaczenie: Marcin Rog(cid:243)¿ ISBN: 978-83-246-1802-6 Tytu‡ orygina‡u: Hacking: The Art of Exploitation, 2nd Edition Format: 170x230, stron: 520 Zdob„d(cid:159) wiedzŒ godn„ hakera! (cid:149) Co trzeba wiedzie(cid:230), aby by(cid:230) hakerem? (cid:149) Jak ‡ama(cid:230) has‡a? (cid:149) Jak uzyska(cid:230) 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(cid:156) haker? Wbrew obiegowej opinii, wiŒkszo(cid:156)(cid:230) haker(cid:243)w nie wykorzystuje swej wiedzy do niecnych cel(cid:243)w. DziŒki swej wiedzy i dociekliwo(cid:156)ci przyczyniaj„ siŒ do rozwoju bezpieczeæstwa sieci i program(cid:243)w. Nikt bowiem nie potrafi tak jak oni zg‡Œbia(cid:230) sposoby dzia‡ania zaawansowanego oprogramowania i sprzŒtu i tropi(cid:230) luki pozwalaj„ce na atak lub wyciek danych oraz przewidywa(cid:230) mo¿liwe problemy w ich dzia‡aniu. Jon Erickson w ksi„¿ce Hacking. Sztuka penetracji. Wydanie II omawia te zagadnienia ze (cid:156)wiata informatyki, kt(cid:243)re nie mog„ by(cid:230) obce hakerowi. DziŒki tej ksi„¿ce poznasz m.in. podstawy jŒzyka C oraz dowiesz siŒ, jak wykorzysta(cid:230) jego s‡abo(cid:156)ci oraz potkniŒcia programist(cid:243)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(cid:230) transmitowane w sieci dane, skanowa(cid:230) porty i ‡ama(cid:230) has‡a. (cid:149) Programowanie w jŒzyku C (cid:149) Model OSI (cid:149) Pods‡uchiwanie sieci (cid:149) Skanowanie port(cid:243)w (cid:149) Sposoby ‡amania hase‡ (cid:149) Szyfrowanie danych i po‡„czeæ (cid:149) Sposoby atakowania sieci bezprzewodowych Oto elementarz prawdziwego hakera! Wydawnictwo Helion ul. Ko(cid:156)ciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl S P I S T R E ¥ C I PRZEDMOWA PODZI}KOWANIA 0X100 WPROWADZENIE 11 12 13 PROGRAMOWANIE 19 0X200 Istota programowania .....................................................................................20 0x210 0x220 Pseudokod ......................................................................................................22 0x230 Struktury sterujÈce ...........................................................................................22 0x231 If-Then-Else ........................................................................................22 0x232 PÚtle While/Until ................................................................................24 0x233 PÚtle for .............................................................................................25 0x240 Podstawowe pojÚcia programistyczne .............................................................26 0x241 Zmienne .............................................................................................26 0x242 Operatory arytmetyczne .....................................................................27 0x243 Operatory porównania .......................................................................28 0x244 Funkcje ...............................................................................................30 0x250 Zaczynamy brudziÊ sobie rÚce ..........................................................................34 0x251 WiÚkszy obraz ....................................................................................35 0x252 Procesor x86 ......................................................................................38 0x253 JÚzyk asembler ...................................................................................40 0x260 Wracamy do podstaw .....................................................................................53 0x261 ’añcuchy ............................................................................................53 0x262 Ze znakiem, bez znaku, dïuga i krótka ................................................57 0x263 Wskaěniki ...........................................................................................59 0x264 ’añcuchy formatujÈce .........................................................................63 0x265 Rzutowanie typów .............................................................................67 0x266 Argumenty wiersza poleceñ ...............................................................74 0x267 ZasiÚg zmiennych ...............................................................................78 0x270 Segmentacja pamiÚci .......................................................................................85 0x271 Segmenty pamiÚci w jÚzyku C ............................................................92 0x272 Korzystanie ze sterty ...........................................................................94 0x273 Funkcja malloc() ze sprawdzaniem bïÚdów .........................................96 0x280 Budujemy na podstawach ...............................................................................98 0x281 DostÚp do plików ...............................................................................98 0x282 Prawa dostÚpu do plików .................................................................104 0x283 Identyfikatory uĝytkowników ............................................................105 0x284 Struktury ..........................................................................................114 0x285 Wskaěniki do funkcji .........................................................................117 0x286 Liczby pseudolosowe ........................................................................118 0x287 Gry hazardowe .................................................................................120 133 0X300 NADU¿YCIA 0x310 Uogólnione techniki naduĝyÊ .........................................................................136 0x320 Przepeïnienia bufora ......................................................................................137 0x321 Luki zwiÈzane z przepeïnieniem stosowym .......................................140 0x330 Eksperymenty z BASH ....................................................................................152 0x331 Wykorzystanie Ărodowiska ...............................................................161 0x340 Przepeïnienia w innych segmentach ..............................................................170 0x341 Podstawowe przepeïnienie na stercie ...............................................170 0x342 Przepeïnienia wskaěników funkcyjnych .............................................176 0x350 ’añcuchy formatujÈce ....................................................................................187 0x351 Parametry formatujÈce .....................................................................188 0x352 PodatnoĂÊ ciÈgów formatujÈcych na ataki ........................................190 0x353 Odczyt spod dowolnych adresów pamiÚci ........................................192 0x354 Zapis pod dowolnymi adresami pamiÚci ...........................................193 0x355 BezpoĂredni dostÚp do parametrów .................................................201 0x356 Uĝycie zapisu krótkich liczb caïkowitych ...........................................203 0x357 ObejĂcia z uĝyciem sekcji dtors .........................................................205 0x358 Kolejny sïaby punkt programu notesearch ........................................210 0x359 Nadpisywanie globalnej tabeli przesuniÚÊ ........................................212 SIECI 217 0X400 0x410 Model OSI .....................................................................................................217 0x420 Gniazda .........................................................................................................220 0x421 Funkcje obsïugujÈce gniazda ............................................................221 0x422 Adresy gniazd ..................................................................................223 0x423 Sieciowa kolejnoĂÊ bajtów ................................................................224 0x424 Konwersja adresu internetowego .....................................................225 6 Hacking. Sztuka penetracji 0x425 Prosty przykïad serwera ....................................................................226 0x426 Przykïad klienta WWW .....................................................................230 0x427 Maleñki serwer WWW ......................................................................235 0x430 ZaglÈdamy do niĝszych warstw .....................................................................240 0x431 Warstwa ïÈcza danych ......................................................................240 0x432 Warstwa sieci ...................................................................................242 0x433 Warstwa transportowa .....................................................................244 0x440 Podsïuchiwanie w sieci ..................................................................................247 0X441 Sniffer surowych pakietów ...............................................................249 0x442 Sniffer libpcap ..................................................................................251 0x443 Dekodowanie warstw ......................................................................253 0x444 Aktywne podsïuchiwanie .................................................................263 0x450 Odmowa usïugi .............................................................................................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 PrzejÚcie TCP/IP .............................................................................................283 0x461 RozïÈczanie za pomocÈ RST ..............................................................283 0x462 PrzejÚcie 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 uĝyciem bezczynnego komputera ...............................291 0x475 Zabezpieczenie wyprzedzajÈce (Shroud) ...........................................293 Idě i wïam siÚ gdzieĂ .....................................................................................298 0x481 Analiza z uĝyciem GDB .....................................................................299 0x482 Prawie ma znaczenie ........................................................................301 0x483 Shellcode wiÈĝÈcy port .....................................................................304 0x480 SHELLCODE 309 0X500 0x510 Asembler a C .................................................................................................309 0x511 Linuksowe wywoïania systemowe w asemblerze .............................312 0x520 ¥cieĝka do shellcode ......................................................................................315 0x521 Instrukcje asemblera wykorzystujÈce stos .........................................315 0x522 Badanie za pomocÈ GDB ..................................................................317 0x523 Usuwanie bajtów zerowych ..............................................................319 0x530 Kod wywoïujÈcy powïokÚ ..............................................................................324 0x531 Kwestia uprawnieñ ...........................................................................328 0x532 Skracamy jeszcze bardziej .................................................................331 Spis treĂci 7 0x540 Kod powïoki wiÈĝÈcy port .............................................................................332 0x541 Duplikowanie standardowych deskryptorów plików .........................336 0x542 RozgaïÚziajÈce struktury sterujÈce ....................................................338 0x550 Shellcode nawiÈzujÈcy poïÈczenie powrotne .................................................343 ¥RODKI ZAPOBIEGAWCZE 349 0X600 0x610 ¥rodki zapobiegawcze, które wykrywajÈ .......................................................350 0x620 Demony systemowe ......................................................................................351 0x621 Bïyskawiczne wprowadzenie do sygnaïów .......................................352 0x622 Demon tinyweb ................................................................................354 0x630 NarzÚdzia pracy .............................................................................................358 0x631 NarzÚdzie naduĝywajÈce tinywebd ...................................................359 0x640 Pliki dziennika ...............................................................................................364 0x641 Wmieszaj siÚ w tïum ........................................................................365 0x650 Przeoczywszy oczywiste ................................................................................366 0x651 Krok po kroku ...................................................................................367 0x652 Ponowne skïadanie wszystkiego ......................................................371 0x653 Robocze procesy potomne ................................................................377 0x660 Zaawansowana sztuka kamuflaĝu .................................................................378 0x661 Faïszowanie rejestrowanego adresu IP .............................................379 0x662 Nierejestrowane naduĝycie ...............................................................383 0x670 Caïa infrastruktura .........................................................................................386 0x671 Ponowne wykorzystanie gniazda ......................................................386 0x680 Przemyt ïadunku ............................................................................................390 0x681 Kodowanie ïañcuchów .....................................................................391 0x682 Jak ukryÊ puïapkÚ? ...........................................................................394 0x690 Ograniczenia bufora ......................................................................................395 0x691 Polimorficzny kod powïoki z drukowalnymi znakami ASCII ...............397 0x6a0 Zabezpieczenia wzmacniajÈce .......................................................................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 koĂci ..................................................................................422 425 0X700 KRYPTOLOGIA 0x710 Teoria informacji ............................................................................................426 0x711 Bezwarunkowe bezpieczeñstwo .......................................................426 0x712 Szyfr z kluczem jednorazowym .........................................................426 8 Hacking. Sztuka penetracji 0x713 Kwantowa dystrybucja kluczy ...........................................................427 0x714 Bezpieczeñstwo obliczeniowe ...........................................................428 0x720 RozlegïoĂÊ 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 rozkïadu na czynniki autorstwa Petera Shora ....437 0x750 Szyfry hybrydowe ..........................................................................................438 0x751 Ataki z ukrytym poĂrednikiem ...........................................................439 0x752 „Odciski palców” komputerów w protokole SSH ...............................443 0x753 Rozmyte „odciski palców” ................................................................447 0x760 ’amanie haseï ...............................................................................................451 0x761 Ataki sïownikowe .............................................................................453 0x762 Ataki na zasadzie peïnego przeglÈdu ................................................455 0x763 Tablica wyszukiwania skrótów .........................................................457 0x764 Macierz prawdopodobieñstwa 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 peïnego przeglÈdu w trybie offline .......................470 0x782 Ponowne uĝycie strumienia klucza ....................................................471 0x783 Tablice sïownikowe z wektorami IV ..................................................472 0x784 Przekierowanie IP .............................................................................473 0x785 Atak Fluhrera, Mantina i Shamira (FMS) ............................................474 PODSUMOWANIE 485 0X800 0x810 Bibliografia i dodatkowe informacje ..............................................................486 0x820 Kody ěródïowe ..............................................................................................487 O P’YCIE CD SKOROWIDZ 489 491 Spis treĂci 9 0x200 P R O G R A M O W A N I E Haker to termin uĝywany do okreĂlenia zarówno piszÈcych kod, jak i tych, którzy wykorzystujÈ znajdujÈce siÚ w nim bïÚdy. ChoÊ obie grupy hakerów majÈ róĝne cele, to i jedni, i drudzy stosujÈ podobne techniki rozwiÈzywania problemów. A ze wzglÚdu na fakt, ĝe umiejÚt- noĂÊ programowania pomaga tym, którzy wykorzystujÈ bïÚdy w kodzie, zaĂ zrozumienie metod zastosowania pomaga tym, którzy programujÈ, wielu hakerów robi obie rzeczy jednoczeĂnie. InteresujÈce rozwiÈzania istniejÈ i w zakresie technik pisania eleganckiego kodu, i technik sïuĝÈcych do wykorzysty- wania sïaboĂci programów. Hakerstwo to w rzeczywistoĂci akt znajdowania pomy- sïowych i nieintuicyjnych rozwiÈzañ problemów. Metody stosowane w narzÚdziach wykorzystujÈcych sïaboĂci programów zwy- kle sÈ zwiÈzane z zastosowaniem reguï funkcjonowania komputera w sposób, któ- rego nigdy nie brano pod uwagÚ — pozornie magiczne rezultaty osiÈga siÚ zwykle po skupieniu siÚ na omijaniu zaimplementowanych zabezpieczeñ. Metody uĝywa- ne podczas pisania programów sÈ podobne, bo równieĝ wykorzystujÈ reguïy funk- cjonowania komputera w nowy i pomysïowy sposób, jednak w tym przypadku koñco- wym celem jest osiÈgniÚcie najbardziej wydajnego lub najkrótszego kodu ěródïowego. Istnieje nieskoñczenie wiele programów, które moĝna napisaÊ w celu wykonania do- wolnego zadania, jednak wiÚkszoĂÊ z istniejÈcych rozwiÈzañ jest niepotrzebnie obszerna, zïoĝona i niedopracowana. Pozostaïa niewielka ich liczba to programy nieduĝe, wydajne i estetyczne. Ta wïaĂciwoĂÊ programów nosi nazwÚ elegancji, zaĂ przemyĂlane i pomysïowe rozwiÈzania prowadzÈce do takiej wydajnoĂci nazywane sÈ sztuczkami (ang. hacks). Hakerzy stojÈcy po obu stronach metodyki programowania doceniajÈ zarówno piÚkno eleganckiego kodu, jak i geniusz pomysïowych sztuczek. W Ăwiecie biznesu mniejszÈ wagÚ przykïada siÚ do przemyĂlanych metod pro- gramowania i eleganckiego kodu, a wiÚkszÈ do tworzenia funkcjonalnego kodu w jak najkrótszym czasie i jak najtaniej. Ze wzglÚdu na gwaïtowny wzrost mocy obli- czeniowej oraz dostÚpnoĂci pamiÚci poĂwiÚcenie dodatkowych piÚciu godzin na opracowanie nieco szybszego i mniej wymagajÈcego pod wzglÚdem pamiÚci frag- mentu kodu po prostu nie opïaca siÚ, gdy mamy do czynienia z nowoczesnymi kom- puterami dysponujÈcymi gigahercowymi cyklami procesora i gigabajtami pamiÚci. Podczas gdy optymalizacje czasu i wykorzystania pamiÚci pozostajÈ niezauwaĝone przez wiÚkszoĂÊ (z wyjÈtkiem wyrafinowanych) uĝytkowników, nowa funkcjonal- noĂÊ ma potencjaï marketingowy. Kiedy najwaĝniejszym kryterium sÈ pieniÈdze, poĂwiÚcanie czasu na opracowywanie przemyĂlanych sztuczek optymalizacyjnych nie ma po prostu sensu. ElegancjÚ programowania pozostawiono hakerom, hobbistom komputerowym, których celem nie jest zarabianie, lecz wyciĂniÚcie wszystkiego, co siÚ da, z ich sta- rych maszyn Commodore 64, autorom programów wykorzystujÈcych bïÚdy, piszÈ- cym niewielkie i niesamowite fragmenty kodu, dziÚki którym potrafiÈ przedostawaÊ siÚ przez wÈskie szczeliny systemów zabezpieczeñ, oraz wszystkim innym doceniajÈ- cym wartoĂÊ szukania i znajdowania najlepszych moĝliwych rozwiÈzañ. SÈ to osoby zachwycajÈce siÚ moĝliwoĂciami oferowanymi przez programowanie i dostrzegajÈce piÚkno eleganckich fragmentów kodu oraz geniusz przemyĂlanych sztuczek. Poznanie istoty programowania jest niezbÚdne do zrozumienia, w jaki sposób moĝna wykorzy- stywaÊ sïaboĂci programów, dlatego teĝ programowanie to naturalny punkt wyjĂcia dla naszych rozwaĝañ. 0x210 Istota programowania Programowanie to pojÚcie niezmiernie naturalne i intuicyjne. Program jest tylko seriÈ instrukcji zapisanych w okreĂlonym jÚzyku. Programy wystÚpujÈ wszÚdzie i nawet technofoby codziennie korzystajÈ z programów. Opisywanie drogi dojazdu w jakieĂ miejsce, przepisy kulinarne, rozgrywki piïkarskie i spirale DNA to sÈ róĝ- nego typu programy. Typowy „program” opisu dojazdu samochodem w konkretne miejsce moĝe wyglÈdaÊ tak: Najpierw zjedļ w dóđ Alejæ Koħciuszki, prowadzæcæ na wschód. Jedļ niæ do momentu, kiedy zobaczysz po prawej stronie koħcióđ. Jeľeli ulica búdzie zablokowana ze wzglúdu na prowadzone roboty, skrúè w prawo w ul. Moniuszki, potem skrúè w lewo w ul. Prusa i w koēcu skrúè w prawo w ul. Orzeszkowej. W przeciwnym razie moľesz po prostu kontynuowaè jazdú Alejæ Koħciuszki i skrúciè w ul. Orzeszkowej. Jedļ niæ i skrúè w ul. Docelowæ. Jedļ niæ jakieħ 8 kilometrów — nasz dom búdzie siú znajdowađ po prawej stronie. Dokđadny adres to ul. Docelowa 743. Kaĝdy, kto zna jÚzyk polski, pojmie podane instrukcje i bÚdzie mógï kierowaÊ siÚ nimi podczas jazdy. Bez wÈtpienia nie zapisano ich zbyt bïyskotliwie, ale sÈ jed- noznaczne i zrozumiaïe. 20 0x200 Jednak komputer nie zna jÚzyka polskiego — rozumie jedynie jÚzyk maszynowy (ang. machine language). W celu poinstruowania go, aby wykonaï pewnÈ czynnoĂÊ, instrukcjÚ tÚ naleĝy zapisaÊ w zrozumiaïym dla niego jÚzyku. Jednakĝe jÚzyk ma- szynowy jest bardzo ezoteryczny i trudny do opanowania. Skïada siÚ z serii bitów oraz bajtów i róĝni siÚ, w zaleĝnoĂci od danej architektury komputerowej. Tak wiÚc w celu napisania programu w jÚzyku maszynowym dla procesora z rodziny Intel x86 naleĝy okreĂliÊ wartoĂÊ zwiÈzanÈ z kaĝdÈ instrukcjÈ, sposób interakcji poszczególnych instrukcji oraz mnóstwo innych niskopoziomowych szczegóïów. Tego rodzaju pro- gramowanie jest bardzo niewdziÚcznym oraz kïopotliwym zadaniem i z pewnoĂciÈ nie jest intuicyjne. Do pokonania komplikacji zwiÈzanych z pisaniem programów w jÚzyku maszy- nowym potrzebny jest translator. JednÈ z form translatora jÚzyka maszynowego jest asembler. To program, który tïumaczy jÚzyk asemblera na kod zapisany w jÚzyku maszynowym. JÚzyk asemblera jest bardziej przystÚpny od kodu maszynowego, poniewaĝ dla róĝnych instrukcji i zmiennych wykorzystuje nazwy (mnemoniki), a nie same wartoĂci liczbowe. Jednak jÚzyk asemblera wciÈĝ jest daleki od intuicyjnego. Nazwy instrukcji sÈ ezoteryczne, a sam jÚzyk wciÈĝ jest zaleĝny od architektury. Oznacza to, ĝe tak samo, jak jÚzyk maszynowy dla procesorów Intel x86 róĝni siÚ od jÚzyka maszynowego dla procesorów Sparc, jÚzyk asemblera x86 jest róĝny od jÚzyka asemblera Sparc. ¿aden program napisany przy uĝyciu jÚzyka asemblera dla architektury jednego procesora nie bÚdzie dziaïaï w architekturze innego procesora. Jeĝeli program zostaï napisany w jÚzyku asemblera x86, musi zostaÊ przepisany, aby moĝna byïo uruchomiÊ go w architekturze Sparc. Ponadto w celu napisania wydaj- nego programu w jÚzyku asemblera naleĝy znaÊ wiele niskopoziomowych szczegó- ïów, dotyczÈcych architektury danego procesora. Problemów tych moĝna uniknÈÊ przy uĝyciu kolejnej formy translatora, noszÈ- cego nazwÚ kompilatora (ang. compiler). Kompilator konwertuje kod zapisany w jÚzy- ku wysokopoziomowym do postaci kodu maszynowego. JÚzyki wysokopoziomowe sÈ o wiele bardziej intuicyjne od jÚzyka asemblera i mogÈ byÊ konwertowane do wielu róĝnych typów jÚzyka maszynowego dla odmiennych architektur procesorów. Ozna- cza to, ĝe jeĂli zapisze siÚ program w jÚzyku wysokiego poziomu, ten sam kod moĝe zostaÊ skompilowany przez kompilator do postaci kodu maszynowego dla róĝnych architektur. C, C++ lub FORTRAN to przykïady jÚzyków wysokopoziomowych. Program napisany w takim jÚzyku jest o wiele bardziej czytelny1 od jÚzyka asem- blera lub maszynowego, choÊ wciÈĝ musi byÊ zgodny z bardzo surowymi reguïami dotyczÈcymi sposobu wyraĝania instrukcji, poniewaĝ w przeciwnym razie kompila- tor nie bÚdzie w stanie ich zrozumieÊ. 1 OczywiĂcie pod warunkiem, ĝe przez czytelny rozumiemy taki, który przypomina jÚzyk angielski — przyp. tïum. Programowanie 21 0x220 Pseudokod ProgramiĂci dysponujÈ jeszcze jednym rodzajem jÚzyka programowania, noszÈcym nazwÚ pseudokodu. Pseudokod (ang. pseudo-code) to po prostu wyraĝenia zapisane w jÚzyku naturalnym, ustawione w strukturÚ ogólnie przypominajÈcÈ jÚzyk wyso- kopoziomowy. Nie jest on rozumiany przez kompilatory, asemblery ani kompute- ry, ale stanowi przydatny sposób skïadania instrukcji. Pseudokod nie jest dobrze zdefiniowany. W rzeczywistoĂci wiele osób zapisuje pseudokod odmiennie. Jest to rodzaj nieokreĂlonego, brakujÈcego ogniwa miÚdzy jÚzykami naturalnymi, takimi jak angielski lub polski, a wysokopoziomowymi jÚzykami programowania, takimi jak C lub Pascal. Pseudokod stanowi Ăwietne wprowadzenie do uniwersalnych zaïoĝeñ programistycznych. 0x230 Struktury sterujÈce Bez struktur sterujÈcych program byïby jedynie seriÈ kolejno wykonywanych instruk- cji. Jest to wystarczajÈce w przypadku bardzo prostych programów, ale wiÚkszoĂÊ programów, takich jak np. opis dojazdu, taka nie jest. Prezentowany opis dojazdu zawieraï instrukcje: Jedě niÈ do momentu, kiedy zobaczysz po prawej stronie koĂcióï. Jeĝeli ulica bÚdzie zablokowana ze wzglÚdu na prowadzone roboty… Instrukcje te nazywamy strukturami sterujÈcymi, poniewaĝ zmieniajÈ przebieg wykonywania programu z prostego, sekwencyjnego, na bardziej zïoĝony i uĝyteczny. If-Then-Else 0x231 W naszym opisie dojazdu Aleja KoĂciuszki moĝe byÊ w remoncie. Do rozwiÈzania problemu wynikajÈcego z tej sytuacji potrzebujemy specjalnego zestawu instrukcji. Jeĝeli zdefiniowane okolicznoĂci nie wystÈpiÈ (remont), bÚdÈ wykonywane standardo- we instrukcje. Tego rodzaju specjalne przypadki moĝna wziÈÊ pod uwagÚ w progra- mie, korzystajÈc z jednej z najbardziej naturalnych struktur sterujÈcych: if-then-else (jeĝeli-wówczas-w przeciwnym przypadku). Ogólnie wyglÈda to mniej wiÚcej tak: If (warunek) then { Zestaw instrukcji do wykonania, gdy warunek jest speđniony; } Else { Zestaw instrukcji do wykonania, gdy warunek nie jest speđniony; } W tej ksiÈĝce bÚdziemy posïugiwali siÚ pseudokodem przypominajÈcym jÚzyk C, wiÚc kaĝda instrukcja bÚdzie zakoñczona Ărednikiem, a ich zbiory bÚdÈ grupowane za pomocÈ nawiasów klamrowych i wyróĝniane wciÚciem. Pseudokod struktury if-then-else dla wskazówek dojazdu mógïby przedstawiaÊ siÚ nastÚpujÈco: 22 0x200 Jedļ w dóđ Alejæ Koħciuszki; Jeľeli (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; } Kaĝda instrukcja znajduje siÚ w osobnym wierszu, a róĝne zestawy instrukcji warunkowych sÈ zgrupowane wewnÈtrz nawiasów klamrowych i dla zwiÚkszenia czytelnoĂci zastosowano dla nich wciÚcie. W C i wielu innych jÚzykach programo- wania sïowo kluczowe then jest domniemane i tym samym pomijane, wiÚc pomi- nÚliĂmy je równieĝ w pseudokodzie. OczywiĂcie, istniejÈ jÚzyki, których skïadnia wymaga zastosowania sïowa klu- czowego then — przykïadami mogÈ tu byÊ BASIC, Fortran, a nawet Pascal. Tego typu róĝnice syntaktyczne miÚdzy jÚzykami programowania sÈ niemal nieistotne, jako ĝe podstawowa struktura jest taka sama. Gdy programista zrozumie zaïoĝenia tych jÚzyków, nauczenie siÚ róĝnych odmian syntaktycznych jest stosunkowo ïatwe. Poniewaĝ w dalszych rozdziaïach bÚdziemy programowali w jÚzyku C, prezento- wany pseudokod bÚdzie przypominaï ten jÚzyk. Naleĝy jednak pamiÚtaÊ, ĝe moĝe on przyjmowaÊ róĝne postaci. InnÈ powszechnÈ reguïÈ skïadni podobnej do C jest sytuacja, w której zestaw instrukcji umieszczonych w nawiasach klamrowych zawiera tylko jednÈ instrukcjÚ. Dla zwiÚkszenia czytelnoĂci wciÈĝ warto dla takiej instrukcji zastosowaÊ wciÚcie, ale nie jest ono wymagane. Zgodnie z tÈ reguïÈ moĝna wiÚc napisaÊ wczeĂniej przed- stawiony opis dojazdu tak, aby uzyskaÊ równowaĝny fragment pseudokodu: Jedļ w dóđ Alejæ Koħciuszki; Jeľeli (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; Reguïa mówiÈca o zestawach instrukcji dotyczy wszystkich struktur sterujÈcych opisywanych w niniejszej ksiÈĝce, a samÈ reguïÚ równieĝ moĝna zapisaÊ w pseu- dokodzie. Programowanie 23 If (w zestawie instrukcji znajduje siú tylko jedna instrukcja) Uľycie nawiasów klamrowych do zgrupowania instrukcji jest opcjonalne; Else { Uľycie nawiasów klamrowych jest niezbúdne; Poniewaľ musi istnieè logiczny sposób zgrupowania tych instrukcji; } Nawet opis skïadni moĝna potraktowaÊ jak program. Istnieje wiele odmian struk- tury if-then-else, np. instrukcje select i case, ale logika pozostaje taka sama: jeĝeli stanie siÚ tak, zrób to i to, w przeciwnym przypadku wykonaj, co poniĝej (a poniĝej mogÈ siÚ znajdowaÊ kolejne instrukcje if-then). 0x232 PÚtle While/Until Innym podstawowym pojÚciem programistycznym jest struktura sterujÈca while, bÚdÈca rodzajem pÚtli. Programista czÚsto chce wykonaÊ zestaw instrukcji kilka razy. Program moĝe wykonaÊ to zadanie, stosujÈc pÚtlÚ, ale wymaga to okreĂlenia warun- ków jej zakoñczenia, aby nie trwaïa w nieskoñczonoĂÊ. PÚtla while wykonuje podany zestaw instrukcji, dopóki warunek jest prawdziwy. Prosty program dla gïodnej myszy mógïby wyglÈdaÊ nastÚpujÈco: While (jesteħ gđodna) { Znajdļ jakieħ jedzenie; Zjedz jedzenie; } Te dwa zestawy instrukcji za instrukcjÈ while bÚdÈ powtarzane, dopóki mysz bÚdzie gïodna. IloĂÊ poĝywienia odnalezionego przez mysz przy kaĝdej próbie moĝe wahaÊ siÚ od maïego okruszka po caïy bochen chleba. Podobnie liczba wykonañ zestawu instrukcji w pÚtli while zaleĝy od iloĂci poĝywienia znalezionego przez mysz. OdmianÈ pÚtli while jest pÚtla until, wykorzystywana w Perlu (w C skïadnia ta nie jest uĝywana). PÚtla until jest po prostu pÚtlÈ while z odwróconym warunkiem. Ten sam program dla myszy zapisany z uĝyciem pÚtli until wyglÈdaïby nastÚpujÈco: Until (nie jesteħ gđodna) { Znajdļ jakieħ jedzenie; Zjedz jedzenie; } Logicznie kaĝda instrukcja podobna do until moĝe byÊ przeksztaïcona w pÚtlÚ while. Opis dojazdu zawieraï zdanie: „Jedě niÈ do momentu, kiedy zobaczysz po prawej stronie koĂcióï”. Moĝemy to w prosty sposób przeksztaïciÊ w standardowÈ pÚtlÚ while — wystarczy, ĝe odwrócimy warunek: 24 0x200 While (nie ma koħciođa po prawej stronie) Jedļ Alejæ Koħciuszki; 0x233 PÚtle for KolejnÈ strukturÈ sterujÈcÈ jest pÚtla for, wykorzystywana wtedy, gdy programista chce, aby pÚtla wykonaïa okreĂlonÈ liczbÚ iteracji. Instrukcja dojazdu: „Jedě niÈ jakieĂ 8 kilometrów” przeksztaïcona do pÚtli for mogïaby wyglÈdaÊ nastÚpujÈco: For (8 iteracji) Jedļ prosto 1 kilometr; W rzeczywistoĂci pÚtla for jest po prostu pÚtlÈ while z licznikiem. PowyĝszÈ instrukcjÚ moĝna równie dobrze zapisaÊ tak: Ustaw licznik na 0 While (licznik jest mniejszy od 8) { Jedļ prosto 1 kilometr; Dodaj 1 do licznika; } Skïadnia pseudokodu dla pÚtli 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- czÈtkowÈ wartoĂÊ — w tym przypadku 0. Druga sekcja przypomina instrukcjÚ while z licznikiem — dopóki licznik speïnia podany warunek, kontynuuj pÚtlÚ. Trzecia i ostatnia sekcja opisuje, co ma siÚ dziaÊ z licznikiem przy kaĝdej iteracji. W tym przypadku i++ jest skróconym sposobem na powiedzenie: „Dodaj 1 do licznika o nazwie i”. Zastosowanie wszystkich omówionych struktur sterujÈcych umoĝliwia przeksztaï- cenie opisu dojazdu ze strony 6 w poniĝszy pseudokod przypominajÈcy jÚzyk C: Rozpocznij jazdú na wschód Alejæ Koħciuszki; While (po prawej stronie nie ma koħciođa) Jedļ Alejæ Koħciuszki; If (ulica zablokowana) { Skrúè w prawo w ul. Moniuszki); Skrúè w lewo w ul. Prusa); Skrúè w prawo w ul. Orzeszkowej); } Programowanie 25 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 pojÚcia programistyczne W kolejnych punktach zostanÈ przedstawione podstawowe pojÚcia programistyczne. SÈ one wykorzystywane w wielu jÚzykach programowania, róĝniÈ siÚ jedynie pod wzglÚdem syntaktycznym. Podczas prezentacji bÚdÈ integrowane z przykïadami w pseudokodzie przypominajÈcym skïadniÚ jÚzyka C. Na koñcu pseudokod bÚdzie bardzo przypominaï kod napisany w jÚzyku C. 0x241 Zmienne Licznik wykorzystywany w pÚtli for jest rodzajem zmiennej. O zmiennej moĝemy myĂleÊ jak o obiekcie przechowujÈcym dane, które mogÈ byÊ zmieniane — stÈd nazwa. IstniejÈ równieĝ zmienne, których wartoĂci nie sÈ zmieniane, i trafnie nazywa siÚ je staïymi. W przykïadzie motoryzacyjnym jako zmiennÈ moĝemy potraktowaÊ prÚdkoĂÊ samochodu, natomiast kolor lakieru samochodu byïby staïÈ. W pseudo- kodzie zmienne sÈ po prostu pojÚciami abstrakcyjnymi, natomiast w C (i wielu in- nych jÚzykach) zmienne przed wykorzystaniem muszÈ byÊ zadeklarowane i naleĝy okreĂliÊ ich typ. Jest tak dlatego, ĝe program napisany w C bÚdzie kompilowany do postaci programu wykonywalnego. Podobnie jak przepis kucharski, w którym przed faktycznymi instrukcjami wymieniane sÈ wszystkie potrzebne skïadniki, de- klaracje zmiennych pozwalajÈ dokonaÊ przygotowañ przed przejĂciem do faktycznej treĂci programu. Ostatecznie wszystkie zmienne sÈ przechowywane gdzieĂ w pamiÚci, a ich deklaracje pozwalajÈ kompilatorowi wydajniej uporzÈdkowaÊ pamiÚÊ. Jednak na koniec, mimo wszystkich deklaracji typów zmiennych, wszystko odbywa siÚ w pamiÚci. W jÚzyku C dla kaĝdej zmiennej okreĂlany jest typ, opisujÈcy informacje, które bÚdÈ przechowywane w tej zmiennej. Do najczÚĂciej stosowanych typów zalicza- my int (liczby caïkowite), float (liczby zmiennoprzecinkowe) i char (pojedyncze znaki). Zmienne sÈ deklarowane poprzez uĝycie tych sïów kluczowych przed nazwÈ zmiennej, co zobrazowano na poniĝszym przykïadzie. int a, b; float k; char z; Zmienne a i b sÈ zadeklarowane jako liczby caïkowite, k moĝe przyjmowaÊ warto- Ăci zmiennoprzecinkowe (np. 3,14), a z powinna przechowywaÊ wartoĂÊ znakowÈ, 26 0x200 takÈ jak A lub w. WartoĂci moĝna przypisywaÊ zmiennym podczas deklaracji lub w dowolnym póěniejszym momencie. Sïuĝy do tego operator =. int a = 13, b; float k; char z = A ; k = 3.14; z = w ; b = a + 5; Po wykonaniu powyĝszych instrukcji zmienna a bÚdzie posiadaïa wartoĂÊ 13, zmienna k bÚdzie zawieraïa liczbÚ 3,14, a zmienna b bÚdzie miaïa wartoĂÊ 18, po- niewaĝ 13 plus 5 równa siÚ 18. Zmienne sÈ po prostu sposobem pamiÚtania wartoĂci, jednak w jÚzyku C naleĝy najpierw zadeklarowaÊ typ kaĝdej zmiennej. 0x242 Operatory arytmetyczne Instrukcja b = a + 7 jest przykïadem bardzo prostego operatora arytmetycznego. W jÚzyku C dla róĝnych operacji matematycznych wykorzystywane sÈ poniĝsze symbole. Pierwsze cztery operatory powinny wyglÈdaÊ znajomo. Redukcja modulo moĝe stanowiÊ nowe pojÚcie, ale jest to po prostu reszta z dzielenia. Jeĝeli 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 caïkowitymi, po wykonaniu instrukcji b = a / 5, zmienna b bÚdzie miaïa wartoĂÊ 2, poniewaĝ jest to czÚĂÊ wyniku bÚdÈca liczbÈ caïkowitÈ. Do przechowania bardziej poprawnego wyniku, czyli 2,6, musi zostaÊ uĝyta zmienna typu float (zmiennoprzecinkowa). Operacja Dodawanie Odejmowanie Mnoĝenie Dzielenie Redukcja modulo Symbol + - * / Przykïad b = a + 5 b = a - 5 b = a * 5 b = a / 5 b = a 5 Aby program korzystaï z tych zaïoĝeñ, musimy mówiÊ w jego jÚzyku. JÚzyk C dostarcza kilku skróconych form zapisu tych operacji arytmetycznych. Jedna z nich zostaïa przedstawiona wczeĂniej i jest czÚsto wykorzystywana w pÚtlach for. Peïne wyraĝenie i = i + 1 i = i - 1 Skrót i++ lub ++i i-- lub i-- WyjaĂnienie Dodaje 1 do wartoĂci zmiennej. Odejmuje 1 od wartoĂci zmiennej. Programowanie 27 Te skrócone wyraĝenia mogÈ byÊ ïÈczone z innymi operacjami arytmetycznymi w celu utworzenia bardziej zïoĝonych wyraĝeñ. Wówczas staje siÚ widoczna róĝnica miÚdzy i++ i ++i. Pierwsze wyraĝenie oznacza: „ZwiÚksz wartoĂÊ i o 1 po przepro- wadzeniu operacji arytmetycznej”, natomiast drugie: „ZwiÚksz wartoĂÊ i o 1 przed przeprowadzeniem operacji arytmetycznej”. Poniĝszy przykïad pozwoli to lepiej zrozumieÊ. int a, b; a = 5 b = a++ * 6; Po wykonaniu tego zestawu instrukcji zmienna b bÚdzie miaïa wartoĂÊ 30, nato- miast zmienna a bÚdzie miaïa wartoĂÊ 6, poniewaĝ skrócony zapis b = a++ * 6 jest równowaĝny poniĝszym instrukcjom. b = a * 6; a = a + 1; Jeĝeli jednak zostanie uĝyta instrukcja b = ++a * 6, kolejnoĂÊ dodawania zostanie zmieniona i otrzymamy odpowiednik poniĝszych instrukcji. a = a + 1; b = a * 6; Poniewaĝ kolejnoĂÊ wykonywania dziaïañ zmieniïa siÚ, w powyĝszym przypad- ku zmienna b bÚdzie miaïa wartoĂÊ 36, natomiast wartoĂÊ zmiennej a wciÈĝ bÚdzie wynosiïa 6. CzÚsto w programach musimy zmodyfikowaÊ zmiennÈ w danym miejscu. Przy- kïadowo moĝemy dodaÊ dowolnÈ wartoĂÊ, takÈ jak 12, i przechowaÊ wynik w tej samej zmiennej (np. i = i + 12) Zdarza siÚ to tak czÚsto, ĝe równieĝ utworzono skróconÈ formÚ tej instrukcji. Peïne wyraĝenie i = i + 12 i = i - 12 i = i * 12 i = i / 12 Skrót i+=12 i-=12 i*=12 i/=12 WyjaĂnienie Dodaje okreĂlonÈ wartoĂÊ do wartoĂci zmiennej. Odejmuje okreĂlonÈ wartoĂÊ od wartoĂci zmiennej. Mnoĝy okreĂlonÈ wartoĂÊ przez wartoĂÊ zmiennej. Dzieli wartoĂÊ zmiennej przez okreĂlonÈ wartoĂÊ. 0x243 Operatory porównania Zmienne sÈ czÚsto wykorzystywane w instrukcjach warunkowych wczeĂniej opisanych struktur sterujÈcych, a te instrukcje warunkowe opierajÈ siÚ na jakiegoĂ rodzaju porównaniu. W jÚzyku C operatory porównania wykorzystujÈ skróconÈ skïadniÚ, która jest stosunkowo powszechna w innych jÚzykach programowania. 28 0x200 Warunek Mniejsze niĝ WiÚksze niĝ Mniejsze lub równe WiÚksze lub równe Równe Nie równa siÚ Symbol = = == != Przykïad (a b) (a b) (a = b) (a = b) (a == b) (a != b) WiÚkszoĂÊ z tych operatorów jest zrozumiaïa, jednakĝe naleĝy zauwaĝyÊ, ĝe w skrócie porównania równoĂci wykorzystywane sÈ dwa znaki równoĂci. Jest to waĝne rozróĝnienie, poniewaĝ podwójny znak równoĂci jest stosowany do sprawdzenia równoĂci, natomiast jeden znak równoĂci jest uĝywany do przypisania wartoĂci zmiennej. Instrukcja a = 7 oznacza: „UmieĂÊ w zmiennej a wartoĂÊ 7”, natomiast a == 7 oznacza: „Sprawdě, czy wartoĂÊ zmiennej a wynosi 7”. (Niektóre jÚzyki pro- gramowania, takie jak Pascal, wykorzystujÈ do przypisywania wartoĂci zmiennym nastÚpujÈcy znak — := — aby wyeliminowaÊ ryzyko bïÚdnego zrozumienia kodu). Naleĝy teĝ zwróciÊ uwagÚ, ĝe wykrzyknik zwykle oznacza nie. Ten symbol moĝe byÊ wykorzystany do odwrócenia dowolnego wyraĝenia. !(a b) jest równowaľne (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 OR AND Symbol || Przykïad ((a b) || (a c)) ((a b) !(a c)) Przykïadowa instrukcja zawierajÈca dwa mniejsze warunki poïÈczone operato- rem OR zostanie oszacowana jako prawdziwa, jeĝeli wartoĂÊ zmiennej a bÚdzie mniej- sza od wartoĂci zmiennej b LUB wartoĂÊ zmiennej a bÚdzie mniejsza od wartoĂci zmiennej c. Podobnie przykïadowa instrukcja zawierajÈca dwa mniejsze warunki poïÈczone operatorem AND zostanie oszacowana jako prawdziwa, jeĝeli wartoĂÊ zmiennej a bÚdzie mniejsza od wartoĂci zmiennej b I wartoĂÊ zmiennej a nie bÚdzie mniejsza od wartoĂci zmiennej c. Takie instrukcje powinny byÊ grupowane za pomocÈ nawiasów i mogÈ zawieraÊ wiele róĝnych odmian. Wiele rzeczy moĝemy sprowadziÊ do zmiennych, operatorów porównania i struk- tur sterujÈcych. W przykïadzie myszy poszukujÈcej poĝywienia gïód moĝemy przed- stawiÊ jako zmiennÈ boolowskÈ o wartoĂci true lub false (prawda lub faïsz). Oczy- wiĂcie, 1 oznacza true, a 0 — false. Programowanie 29 While (gđód == 1) { Szukaj poľywienia; Zjedz poľywienie; } Oto kolejny skrót czÚsto wykorzystywany przez programistów i hakerów. JÚzyk C nie zawiera ĝadnych operatorów boolowskich, wiÚc kaĝda wartoĂÊ niezerowa jest uznawana za true, a instrukcja jest szacowana jako false, gdy zawiera 0. W rzeczy- wistoĂci operatory porównania faktycznie zwracajÈ 1, jeĝeli porównanie jest speï- nione, a w przeciwnym przypadku zwracajÈ 0. Sprawdzenie, czy zmienna gđód ma wartoĂÊ 1, zwróci 1, jeĝeli gđód ma wartoĂÊ 1, lub zwróci 0, jeĝeli gïód ma wartoĂÊ 0. Poniewaĝ program wykorzystuje tylko te dwa przypadki, moĝna w ogóle pominÈÊ operator porównania. While (gđód) { Szukaj poľywienia; Zjedz poľywienie; } Sprytniejszy program sterujÈcy zachowaniem myszy z uĝyciem wiÚkszej liczby danych wejĂciowych to przykïad, jak moĝna ïÈczyÊ operatory porównania ze zmien- nymi. While ((gđód) !(kot_obecny)) { Szukaj poľywienia; If (!(poľywienie_znajduje_siú_w_puđapce_na_myszy; Zjedz poľywienie; } W tym przykïadzie zaïoĝono, ĝe dostÚpne sÈ równieĝ zmienne opisujÈce obec- noĂÊ kota oraz poïoĝenie poĝywienia z wartoĂciami 1 dla speïnienia warunku i 0 dla przypadku przeciwnego. Wystarczy pamiÚtaÊ, ĝe wartoĂÊ niezerowa oznacza prawdÚ, a wartoĂÊ 0 jest szacowana jako faïsz. 0x244 Funkcje Czasami zdarzajÈ siÚ zestawy instrukcji, których programista bÚdzie potrzebowaï kilka razy. Takie instrukcje moĝna zgrupowaÊ w mniejszym podprogramie, zwanym funkcjÈ. W innych jÚzykach funkcje nazywane sÈ takĝe procedurami i podprocedu- rami. Przykïadowo wykonanie skrÚtu samochodem skïada siÚ z kilku mniejszych instrukcji: wïÈcz odpowiedni kierunkowskaz, zwolnij, sprawdě, czy nie nadjeĝdĝajÈ inne samochody, skrÚÊ kierownicÚ w odpowiednim kierunku itd. Opis trasy z poczÈt- ku tego rozdziaïu zawieraï caïkiem sporo skrÚtów, jednakĝe wymienianie wszystkich 30 0x200 drobnych instrukcji przy kaĝdym skrÚcie byïoby ĝmudne (i zmniejszaïoby czytel- noĂÊ kodu). W celu zmodyfikowania sposobu dziaïania funkcji moĝemy przesyïaÊ do niej zmienne jako argumenty. W tym przypadku do funkcji jest przesyïany kierunek skrÚtu. Function Skrút(zmienna_kierunku) { Wđæcz zmienna_kierunku kierunkowskaz; Zwolnij; Sprawdļ, czy nie nadjeľdľajæ inne samochody; while (nadjeľdľajæ inne samochody) { Zatrzymaj siú; Obserwuj nadjeľdľajæce samochody; } Obróè kierownicú w zmienna_kierunku; while (skrút nie jest ukoēczony) { if (prúdkoħè 8 km/h) Przyspiesz; } Obróè kierownicú do pierwotnego pođoľenia; Wyđæcz zmienna_kierunku kierunkowskaz; } Funkcja ta zawiera wszystkie instrukcje konieczne do wykonania skrÚtu. Gdy program, w którym funkcja taka siÚ znajduje, musi wykonaÊ skrÚt, moĝe po prostu wywoïaÊ tÚ funkcjÚ. Gdy zostaje wywoïana, znajdujÈce siÚ w niej instrukcje sÈ wy- konywane z przesïanymi argumentami. NastÚpnie wykonywanie programu powraca do momentu za wywoïaniem funkcji. Do tej funkcji moĝna przesïaÊ wartoĂÊ lewo albo prawo, co spowoduje wykonanie skrÚtu w tym kierunku. DomyĂlnie w jÚzyku C funkcje mogÈ zwracaÊ wartoĂci do elementu wywoïujÈ- cego. Dla osób znajÈcych matematykÚ jest to zupeïnie zrozumiaïe. Wyobraěmy sobie funkcjÚ obliczajÈcÈ silniÚ — jest oczywiste, ĝe zwraca wynik. W jÚzyku C funkcje nie sÈ oznaczane sïowem kluczowym function. Zamiast tego sÈ deklarowane przez typ danych zwracanej zmiennej. Taki format bardzo przy- pomina deklaracjÚ zmiennej. Jeĝeli funkcja w zamierzeniu ma zwracaÊ liczbÚ caï- kowitÈ (moĝe to byÊ np. funkcja obliczajÈca silniÚ jakiejĂ liczby x), jej kod mógïby wyglÈdaÊ nastÚpujÈco: int factorial(int x) { int i; for(i=1; i x; i++) x *= i; return x; } Programowanie 31 Funkcja ta jest deklarowana liczbÈ caïkowitÈ, poniewaĝ mnoĝy kaĝdÈ wartoĂÊ od 1 do x i zwraca wynik, który jest liczbÈ caïkowitÈ. Instrukcja return na koñcu funkcji przesyïa zawartoĂÊ zmiennej x i koñczy wykonywanie funkcji. FunkcjÚ obli- czajÈcÈ silniÚ moĝna wówczas wykorzystaÊ jak kaĝdÈ zmiennÈ typu integer w gïównej czÚĂci kaĝdego programu, który „wie” o tej funkcji: int a=5, b; b = factorial(a); Po ukoñczeniu wykonywania tego krótkiego programu zmienna b bÚdzie miaïa wartoĂÊ 120, poniewaĝ funkcja factorial() zostanie wywoïana z argumentem 5 i zwróci 120. Ponadto w jÚzyku C kompilator musi „wiedzieÊ” o funkcji, zanim jej uĝyje. W tym celu moĝna 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, zwracajÈcej okreĂlony typ danych i przyjmujÈcej argumenty o okreĂlonym typie danych. Faktyczny kod funkcji moĝna umieĂciÊ pod koniec programu, ale moĝna jÈ wykorzystaÊ w dowolnym miejscu, poniewaĝ kompilator bÚdzie juĝ wiedziaï o jej istnieniu. Przykïadowy prototyp funkcji factorial() mógïby wyglÈdaÊ nastÚpujÈco: int factorial(int); Zwykle prototypy funkcji sÈ umieszczane blisko poczÈtku 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. Jeĝeli funkcja nie posiada wartoĂci, którÈ moĝe zwróciÊ (np. wczeĂniej opisana funkcja skrúè()), powinna byÊ zadeklarowana jako typ void. Jednakĝe funkcja skrúè() nie posiada jeszcze caïej funkcjonalnoĂci wymaganej przez nasz opis dojazdu. Kaĝdy skrÚt w opisie dojazdu zawiera zarówno kierunek, jak i nazwÚ ulicy. To oznacza, ĝe funkcja skrÚcajÈca powinna przyjmowaÊ dwie zmienne: kierunek skrÚtu oraz nazwÚ ulicy, w którÈ naleĝy skrÚciÊ. To komplikuje funkcjÚ skrÚcajÈcÈ, poniewaĝ przed wykonaniem skrÚtu naleĝy zlokalizowaÊ ulicÚ. Bardziej kompletna funkcja skrÚcajÈca, w której wykorzystano skïadniÚ podobnÈ do jÚzyka C, jest zamieszczona w pseu- dokodzie poniĝszego listingu. void skrúè(zmienna_kierunku, nazwa_docelowej_ulicy) { Szukaj tabliczki z nazwæ ulicy; nazwa_bieľæcego_skrzyľowania = odczytaj tabliczkú z nazwæ ulicy; while (nazwa_bieľæcego_skrzyľowania != nazwa_docelowej_ulicy) { Szukaj innej tabliczki z nazwæ ulicy; nazwa_bieľæcego_skrzyľowania = odczytaj tabliczkú z nazwæ ulicy; } 32 0x200 Wđæcz zmienna_kierunku kierunkowskaz; Zwolnij; Sprawdļ, czy nie nadjeľdľajæ inne samochody; while (nadjeľdľajæ inne samochody) { Zatrzymaj siú; Obserwuj nadjeľdľajæce samochody; } Obróè kierownicú w zmienna_kierunku; while (skrút nie jest ukoēczony) { if (prúdkoħè 8 km/h) Przyspiesz; } Obróè kierownicú do pierwotnego pođoľenia; Wyđæcz zmienna_kierunku kierunkowskaz; } Funkcja ta zawiera sekcjÚ, która wyszukuje odpowiednie skrzyĝowanie poprzez odnajdywanie tabliczki z nazwÈ ulicy, odczytywanie z niej nazwy i przechowywanie jej w zmiennej o nazwie nazwa_bieľæcego_skrzyľowania. Wyszukiwanie i odczyty- wanie tabliczek z nazwami odbywa siÚ do momentu odnalezienia docelowej ulicy. Wówczas wykonywane sÈ pozostaïe instrukcje skrÚtu. Moĝemy teraz zmieniÊ pseu- dokod z instrukcjami dojazdu, aby wykorzystywaï funkcjÚ skrÚtu. Rozpocznij jazdú na wschód Alejæ Koħciuszki; while (po prawej stronie nie ma koħciođa) { Jedļ Alejæ Koħciuszki; } 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È czÚsto wykorzystywane w pseudokodzie, bo zwykle jest on sto- sowany przez programistów do zarysowania zaïoĝeñ programu przed napisaniem kompilowalnego kodu. Poniewaĝ pseudokod nie musi dziaïaÊ, nie trzeba wypisywaÊ peïnych funkcji — wystarczy jedynie krótki zapisek: Tu zrób coĂ zïoĝonego. Jednak Programowanie 33 w jÚzyku programowania, takim jak C, funkcje sÈ czÚsto wykorzystywane. WiÚkszoĂÊ prawdziwej uĝytecznoĂci C pochodzi ze zbiorów istniejÈcych funkcji, zwanych bibliotekami. 0x250 Zaczynamy brudziÊ sobie rÚce Gdy zaznajomiliĂmy siÚ juĝ trochÚ ze skïadniÈ jÚzyka C i wyjaĂniliĂmy kilka pod- stawowych pojÚÊ programistycznych, przejĂcie do faktycznego programowania w C nie jest niczym nadzwyczajnym. Kompilatory jÚzyka C istniejÈ dla niemal kaĝdego systemu operacyjnego i architektury procesora, jednak w niniejszej ksiÈĝce bÚdziemy wykorzystywali wyïÈcznie system Linux i procesor z rodziny x86. Linux jest dar- mowym systemem operacyjnym, do którego kaĝdy ma dostÚp, a procesory x86 sÈ najpopularniejszymi procesorami konsumenckimi na Ăwiecie. Poniewaĝ hacking wiÈĝe siÚ gïównie z eksperymentowaniem, najlepiej bÚdzie, jeĝeli w trakcie lektury bÚdziesz dysponowaï kompilatorem jÚzyka C. DziÚki dyskowi LiveCD doïÈczonemu do niniejszej ksiÈĝki moĝesz praktycznie stosowaÊ przekazywane informacje, jeĝeli tylko dysponujesz procesorem z rodziny x86. Wystarczy wïoĝyÊ dysk CD do napÚdu i ponownie uruchomiÊ komputer. Uru- chomione zostanie Ărodowisko linuksowe, które nie narusza istniejÈcego systemu ope- racyjnego. W tym Ărodowisku moĝesz wypróbowywaÊ przykïady z ksiÈĝki, a takĝe przeprowadzaÊ wïasne eksperymenty. Przejděmy do rzeczy. Program firstprog.c jest prostym fragmentem kodu w C, wypisujÈcym 10 razy „Hello world!”. Listing 2.1. firstprog.c #include stdio.h int main() { int i; for(i=0; i 10; i++) // Wykonaj pútlú 10 razy. { puts( Hello, world! ); // Przekaľ đaēcuch do wyjħcia. } return 0; // Poinformuj OS, ľe program zakoēczyđ siú bez bđúdów. } Gïówne wykonywanie programu napisanego w C rozpoczyna siÚ w funkcji main(). Tekst znajdujÈcy siÚ za dwoma ukoĂnikami jest komentarzem ignorowanym przez kompilator. Pierwszy wiersz moĝe wprawiaÊ w zakïopotanie, ale jest to jedynie skïadnia informujÈca kompilator, aby doïÈczyï nagïówki dla standardowej biblioteki wej- Ăcia-wyjĂcia o nazwie stdio. Ten plik nagïówkowy jest dodawany do programu podczas kompilacji. Znajduje siÚ on w /usr/include/stdio.h i definiuje kilka staïych i prototypów funkcji dla odpowiednich funkcji w standardowej bibliotece we-wy. Poniewaĝ funkcja main() wykorzystuje funkcjÚ printf() ze standardowej biblioteki 34 0x200 we-wy, wymagany jest prototyp funkcji printf() przed jej zastosowaniem. Ten prototyp funkcji (a takĝe wiele innych) znajduje siÚ w pliku nagïówkowym stdio.h. Sporo moĝliwoĂci jÚzyka C to pochodne jego zdolnoĂci do rozbudowy oraz wyko- rzystania bibliotek. Reszta kodu powinna byÊ zrozumiaïa i przypomina wczeĂniej prezentowany pseudokod. SÈ nawet nawiasy klamrowe, które moĝna byïo pominÈÊ. To, co bÚdzie siÚ dziaïo po uruchomieniu tego programu, powinno byÊ oczywiste, ale skompilujmy go za pomocÈ GCC, aby siÚ upewniÊ. GNU Compiler Collection jest darmowym kompilatorem jÚzyka C, tïumaczÈcym jÚzyk C na jÚzyk maszynowy, zrozumiaïy dla komputera. W wyniku tïumaczenia powstaje wykonywalny plik binarny, któremu domyĂlnie nadawana jest nazwa a.out. Czy skompilowany program wykonuje to, co chcieliĂmy? 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 WiÚkszy obraz Dobrze, tego wszystkiego moĝna siÚ nauczyÊ na podstawowym kursie programo- wania — sÈ to podstawy, ale niezbÚdne. WiÚkszoĂÊ poczÈtkowych kursów progra- mowania uczy jedynie, jak czytaÊ i pisaÊ w jÚzyku C. ProszÚ mnie ěle nie zrozumieÊ — pïynna znajomoĂÊ C jest bardzo przydatna i wystarczy do stania siÚ dobrym programistÈ, ale jest to tylko czÚĂÊ wiÚkszej caïoĂci. WiÚkszoĂÊ programistów uczy siÚ jÚzyka z góry do doïu i nigdy nie ma szerszego obrazu. Hakerzy sÈ tak dobrzy, poniewaĝ wiedzÈ, jak wszystkie czÚĂci tego wiÚkszego obrazu wchodzÈ ze sobÈ w interakcje. Aby w programowaniu patrzeÊ szerzej, wystarczy sobie zdaÊ sprawÚ, ĝe kod w jÚzyku C bÚdzie kompilowany. Kod nie moĝe nic zrobiÊ, dopóki nie zostanie skompilowany do wykonywalnego pliku binarnego. MyĂlenie o kodzie ěródïowym w C jak o programie jest czÚstym bïÚdem wykorzystywanym codziennie przez ha- kerów. Instrukcje w pliku a.out sÈ zapisane w jÚzyku maszynowym — podstawowym jÚzyku zrozumiaïym dla procesora. Kompilatory tïumaczÈ jÚzyk kodu C na jÚzyk maszynowy róĝnych architektur procesorów. W tym przypadku procesor pocho- dzi z rodziny wykorzystujÈcej architekturÚ x86. IstniejÈ równieĝ architektury pro- cesorów Sparc (uĝywane w stacjach roboczych Sun) oraz architektura PowerPC Programowanie 35 (wykorzystywana w macintoshach przed zastosowaniem procesorów Intela). Kaĝda architektura wymaga innego jÚzyka maszynowego, wiÚc kompilator jest poĂredni- kiem — tïumaczy kod w jÚzyku C na jÚzyk maszynowy docelowej architektury. Dopóki skompilowany program dziaïa, przeciÚtny programista skupia siÚ wy- ïÈcznie na kodzie ěródïowym. Jednak haker zdaje sobie sprawÚ, ĝe w rzeczywistoĂci wykonywany jest program skompilowany. MajÈc dogïÚbnÈ wiedzÚ na temat dziaïania procesora, haker moĝe manipulowaÊ dziaïajÈcymi programami. WidzieliĂmy kod ěródïowy naszego pierwszego programu i skompilowaliĂmy go do pliku wykony- walnego dla architektury x86. Ale jak wyglÈda ten wykonywalny plik binarny? Na- rzÚdzia programistyczne GNU zawierajÈ program o nazwie objdump, który moĝe byÊ uĝyty do badania skompilowanych plików binarnych. Rozpocznijmy od poznania kodu maszynowego, na który zostaïa przetïumaczona 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 rozsÈdnie siÚ im przyjrzeÊ, wiÚc przekazaliĂmy wyjĂcie do grep z opcjÈ powodujÈcÈ wyĂwietlenie tylko 20 wierszy za wyraĝeniem regularnym main.:. Kaĝdy bajt jest reprezentowany w notacji szesnastkowej, systemie liczbowym o podstawie 16. System liczbowy, do którego jesteĂmy najbardziej przyzwyczajeni, wykorzystuje podstawÚ 10, a przy liczbie 10 naleĝy umieĂciÊ dodatkowy symbol. W systemie szesnastkowym stoso- wane sÈ cyfry od 0 do 9 reprezentujÈce 0 do 9, ale takĝe 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 kaĝdy moĝe mieÊ wartoĂÊ prawda lub faïsz. To oznacza, ĝe bajt ma 256 (28) moĝliwych wartoĂci, wiÚc kaĝdy bajt moĝe byÊ opisany za pomocÈ dwóch cyfr w systemie szesnastkowym. 36 0x200 Liczby szesnastkowe — rozpoczynajÈc od 0x8048374 po lewej stronie — sÈ ad- resami pamiÚci. Bity jÚzyka 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 rzÈd domów przy lokalnej ulicy, z których kaĝdy posiada wïasny adres, pamiÚÊ moĝemy traktowaÊ jako rzÈd bajtów, z których kaĝdy ma wïasny adres. Do kaĝdego bajta pamiÚci moĝna uzyskaÊ dostÚp za pomocÈ jego adresu, a w tym przypadku procesor siÚga do tej czÚĂci pamiÚci, aby pobraÊ instrukcje jÚzyka ma- szynowego skïadajÈce siÚ na skompilowany program. Starsze procesory Intela z rodzi- ny x86 wykorzystujÈ 32-bitowy schemat adresacji, natomiast nowsze — 64-bitowy. Procesory 32-bitowe posiadajÈ 232 (lub teĝ 4 294 967 296) moĝliwych adresów, na- tomiast procesory 64-bitowe dysponujÈ iloĂciÈ adresów równÈ 264 (1,84467441 × 1019). Procesory 64-bitowe mogÈ pracowaÊ w trybie kompatybilnoĂci 32-bitowej, co umoĝ- liwia im szybkie wykonywanie kodu 32-bitowego. Bajty szesnastkowe znajdujÈce siÚ poĂrodku powyĝszego listingu sÈ instrukcjami w jÚzyku maszynowym procesora x86. OczywiĂcie, te wartoĂci szesnastkowe sÈ jedynie reprezentacjami binarnych jedynek i zer, które rozumie procesor. Ale po- niewaĝ 0101010110001001111001011000001111101100111100001… przydaje siÚ tylko procesorowi, kod maszynowy jest wyĂwietlany jako bajty szesnastkowe, a kaĝda instrukcja jest umieszczana w osobnym wierszu, co przypomina podziaï akapitu na zdania. Gdy siÚ zastanowimy, okaĝe siÚ, ĝe bajty szesnastkowe same w sobie teĝ nie sÈ przydatne — tutaj dochodzi do gïosu jÚzyk asembler. Instrukcje po prawej stronie sÈ zapisane w asemblerze. Asembler jest po prostu zbiorem mnemoników dla od- powiednich instrukcji jÚzyka maszynowego. Instrukcja ret jest znacznie ïatwiejsza do zapamiÚtania i zrozumienia niĝ 0xc3 czy teĝ 11000011. W przeciwieñstwie do C i innych jÚzyków kompilowanych, instrukcje asemblera wystÚpujÈ w relacji jeden- do-jednego z instrukcjami odpowiednimi jÚzyka maszynowego. Oznacza to, ĝe skoro kaĝda architektura procesora posiada wïasny zestaw instrukcji jÚzyka maszynowego, kaĝda z nich ma równieĝ wïasnÈ odmianÚ asemblera. JÚzyk asemblera jest dla pro- gramistów tylko sposobem reprezentacji instrukcji jÚzyka maszynowego podawa- nych procesorowi. Dokïadny sposób reprezentacji tych instrukcji maszynowych jest tylko kwestiÈ konwencji i preferencji. ChoÊ teoretycznie moĝna stworzyÊ wïasnÈ skïadniÚ asemblera dla architektury x86, wiÚkszoĂÊ osób wykorzystuje jeden z gïów- nych typów — skïadniÚ AT T lub Intel. Kod asemblera przedstawiony na stronie 21 jest zgodny ze skïadniÈ AT T, poniewaĝ niemal wszystkie dezasemblery w Linuksie domyĂlnie wykorzystujÈ tÚ skïadniÚ. SkïadniÚ AT T moĝna ïatwo rozpoznaÊ dziÚ- ki kakofonii symboli i $ umieszczanych przed wszystkimi elementami (proszÚ ponownie spojrzeÊ na stronÚ 21). Ten sam kod moĝna wyĂwietliÊ w skïadni Intela, dodajÈc 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 Programowanie 37 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 $ Uwaĝam, ĝe skïadnia Intela jest znacznie bardziej czytelna i ïatwiejsza do zro- zumienia, wiÚc bÚdzie ona stosowana w niniejszej ksiÈĝce. Niezaleĝnie od repre- zentacji jÚzyka asemblera, polecenia rozumiane przez procesor sÈ caïkiem proste. Instrukcje te skïadajÈ siÚ z operacji i czasem d
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Hacking. Sztuka penetracji. Wydanie II
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: