background image

Wydawnictwo Helion

ul. Chopina 6

44-100 Gliwice

tel. (32)230-98-63

e-mail: helion@helion.pl

PRZYK£ADOWY ROZDZIA£

PRZYK£ADOWY ROZDZIA£

IDZ DO

IDZ DO

ZAMÓW DRUKOWANY KATALOG

ZAMÓW DRUKOWANY KATALOG

KATALOG KSI¥¯EK

KATALOG KSI¥¯EK

TWÓJ KOSZYK

TWÓJ KOSZYK

CENNIK I INFORMACJE

CENNIK I INFORMACJE

ZAMÓW INFORMACJE

O NOWOŒCIACH

ZAMÓW INFORMACJE

O NOWOŒCIACH

ZAMÓW CENNIK

ZAMÓW CENNIK

CZYTELNIA

CZYTELNIA

FRAGMENTY KSI¥¯EK ONLINE

FRAGMENTY KSI¥¯EK ONLINE

SPIS TREŒCI

SPIS TREŒCI

DODAJ DO KOSZYKA

DODAJ DO KOSZYKA

KATALOG ONLINE

KATALOG ONLINE

Hack Wars. Tom 1.

Na tropie hakerów

Autor: John Chirillo

T³umaczenie: Pawe³ Koronkiewicz, Leonard Milcin

ISBN: 83-7197-599-6

Tytu³ orygina³u:

Format: B5, stron: 736

Zawiera CD-ROM

Hack Attacks Revealed: A Complete

Reference with Custom Security Hacking Toolkit

Ekspert w dziedzinie zabezpieczeñ, John Chirillo, zachêca Czytelnika do poznania

mrocznego i tajemniczego œwiata hakerów. Czerpi¹c z bogatego doœwiadczenia we

wspó³pracy z firmami Fortune 1000, Chirillo przedstawia ró¿ne sposoby wykorzystania

przez hakerów luk w zabezpieczeniach sieci oraz metody rozpoznawania tego rodzaju

zagro¿eñ. Uzupe³nieniem jest szczegó³owy opis pakietu TigerBox, umo¿liwiaj¹cego

hakerom przeprowadzanie skutecznych w³amañ, a administratorowi sieci — zyskanie

pewnoœci, ¿e jest w³aœciwie chroniona.
W tej prowokacyjnej ksi¹¿ce znajdziemy:

"
"
"
"

Opis protoko³ów sieciowych i technologii komunikacyjnych z punktu widzenia

hakera
Pe³ny opis stosowanych metod w³amañ, wyjaœniaj¹cy, jak dzia³aj¹ hakerzy,

crackerzy, "phreaks" i cyberpunki
Narzêdzia do gromadzenia informacji i skanowania sieci, umo¿liwiaj¹ce wykrycie

i przeanalizowanie przypadków naruszenia bezpieczeñstwa systemu
Dok³adne instrukcje, jak pos³ugiwaæ siê pakietem typu TigerBox

i wykorzystywaæ go do wykrywania ataków.

ZNAJDZ KSI¥¯KÊ

ZNAJDZ KSI¥¯KÊ

LISTA BESTSELLERÓW

LISTA BESTSELLERÓW

INFORMACJE

O WYDAWNICTWIE HELION

INFORMACJE

O WYDAWNICTWIE HELION

background image

O Autorze .............................................................................................................9

Wstęp ................................................................................................................11

Rozdział 1.  Protokoły komunikacyjne .................................................................15

Krótka historia Internetu ...................................................................................................15

IP — Internet Protocol ................................................................................................16
Datagramy IP — transportowanie, rozmiar i fragmentacja ........................................18
Adresy IP, klasy i maski podsieci ...............................................................................21
VLSM — krótka instrukcja tworzenia podsieci i odczytywania adresu IP ................22

ARP/RARP — rozpoznawanie adresu sprzętowego.........................................................31

ARP — transportowanie, budowa nagłówka pakietu .................................................31
RARP — transportowanie, dokonywanie transakcji ..................................................33
Usługa RARP..............................................................................................................33

TCP — Transmission Control Protocol ............................................................................33

Sekwencje oraz okna...................................................................................................34
Budowa nagłówka pakietu TCP..................................................................................35
Porty, końcówki, nawiązywanie połączenia ...............................................................37

UDP — User Datagram Protocol ......................................................................................37

Budowa i transportowanie datagramów UDP.............................................................38
Multiplexing, demultiplexing oraz porty UDP ...........................................................39

ICMP — Internet Control Message Protocol....................................................................39

Budowa i transportowanie pakietów ICMP ................................................................39
Komunikaty ICMP, wyszukiwanie maski podsieci ....................................................40
Przykłady datagramów ICMP.....................................................................................42

Rozdział 2.  NetWare oraz NetBIOS .....................................................................43

NetWare — wprowadzenie ...............................................................................................43

IPX — Internetwork Packet Exchange .......................................................................44
SPX — Sequenced Packet Exchange .........................................................................48
Budowa i przykłady nagłówków SPX ........................................................................49
Zarządzanie połączeniami, przerywanie .....................................................................49
Algorytm Watchdog....................................................................................................50
Korekcja błędów, ochrona przed zatorami .................................................................51

NetBIOS — wprowadzenie...............................................................................................51

Konwencje nazywania, przykładowe nagłówki..........................................................51
Usługi NetBIOS ..........................................................................................................52

background image

4

Hack Wars. Na tropie hakerów

NetBEUI — wprowadzenie ..............................................................................................53

Związki z NetBIOS.....................................................................................................54
Okna i liczniki.............................................................................................................54

Rozdział 3.  Porty standardowe oraz związane z nimi usługi..................................55

Przegląd portów.................................................................................................................55

Porty TCP oraz UDP...................................................................................................56
Luki w bezpieczeństwie związane z portami standardowymi ....................................57

Niezidentyfikowane usługi................................................................................................69

Rozdział 4.  Techniki rozpoznania i skanowania ...................................................99

Rozpoznanie ......................................................................................................................99

Katalog Whois ..........................................................................................................100
PING .........................................................................................................................102
Serwisy wyszukiwawcze ..........................................................................................105
Social Engineering ....................................................................................................106

Skanowanie portów .........................................................................................................107

Techniki skanowania portów ....................................................................................107
Popularne skanery portów.........................................................................................108

Przykładowy skan ...........................................................................................................120

Rozdział 5.  Niezbędnik hakera..........................................................................127

Pojęcia związane z siecią ................................................................................................127

Model warstwowy — Open Systems Interconnection Model ..................................127
Rodzaje okablowania — przepustowość oraz maksymalna długość........................129
Konwersje pomiędzy postaciami dwójkowymi, dziesiątkowymi

i szesnastkowymi liczb .......................................................................................129

Funkcje wydajnościowe protokołów ........................................................................140

Technologie sieciowe ......................................................................................................141

Adresowanie MAC i kody producentów ..................................................................141
Ethernet .....................................................................................................................141
Token Ring................................................................................................................148
Sieci Token Ring i mostkowanie trasy nadawcy ......................................................149
Sieci Token Ring i translacyjne mostkowanie trasy nadawcy..................................153
Sieci FDDI ................................................................................................................155

Protokoły wybierania tras................................................................................................157

Protokoły wektorowo-odległościowe i protokoły stanów przyłączy........................157
Protokół RIP..............................................................................................................159
Protokół IGRP...........................................................................................................160
Protokół RTMP sieci Appletalk................................................................................161
Protokół OSPF ..........................................................................................................161

Ważne polecenia .............................................................................................................162

append .......................................................................................................................162
assign.........................................................................................................................164
attrib ..........................................................................................................................164
backup .......................................................................................................................165
break..........................................................................................................................166
chcp ...........................................................................................................................166
chdir (cd) ...................................................................................................................167
chkdsk .......................................................................................................................168
cls ..............................................................................................................................168
command...................................................................................................................168
comp..........................................................................................................................169
copy...........................................................................................................................170
ctty.............................................................................................................................171

background image

Spis treści

5

date ............................................................................................................................171
del (erase)..................................................................................................................172
dir ..............................................................................................................................172
diskcomp ...................................................................................................................173
diskcopy ....................................................................................................................174
exe2bin ......................................................................................................................174
exit.............................................................................................................................175
fastopen .....................................................................................................................175
fc ...............................................................................................................................175
fdisk...........................................................................................................................177
find ............................................................................................................................177
format ........................................................................................................................178
graftabl ......................................................................................................................179
Graphics ....................................................................................................................179
join ............................................................................................................................180
keyb...........................................................................................................................181
label...........................................................................................................................182
mkdir (md) ................................................................................................................182
mode..........................................................................................................................183
more ..........................................................................................................................186
nlsfunc.......................................................................................................................186
path............................................................................................................................187
print ...........................................................................................................................187
prompt .......................................................................................................................188
recover.......................................................................................................................189
rename (ren) ..............................................................................................................190
replace .......................................................................................................................190
restore........................................................................................................................191
rmdir (rd)...................................................................................................................192
select .........................................................................................................................192
set ..............................................................................................................................193
share ..........................................................................................................................194
sort.............................................................................................................................194
subst ..........................................................................................................................195
sys .............................................................................................................................196
time ...........................................................................................................................196
tree.............................................................................................................................197
type............................................................................................................................197
ver .............................................................................................................................197
verify .........................................................................................................................198
vol .............................................................................................................................198
xcopy.........................................................................................................................198

Rozdział 6.  Podstawy programowania dla hakerów ...........................................201

Język C ............................................................................................................................201

Wersje języka C ........................................................................................................202
Klasyfikowanie języka C ..........................................................................................203

Struktura języka C ...........................................................................................................203

Komentarze ...............................................................................................................205
Biblioteki...................................................................................................................205

Tworzenie programów ....................................................................................................205

Kompilacja ................................................................................................................205
Typy danych..............................................................................................................206
Operatory ..................................................................................................................210

background image

6

Hack Wars. Na tropie hakerów

Funkcje......................................................................................................................212
Polecenia preprocesora C..........................................................................................216
Instrukcje sterujące ...................................................................................................219
Wejście-wyjście ........................................................................................................223
Wskaźniki .................................................................................................................226
Struktury ...................................................................................................................229
Operacje na plikach...................................................................................................234
Ciągi ..........................................................................................................................244
Obsługa tekstu...........................................................................................................250
Data i godzina ...........................................................................................................253
Pliki nagłówkowe......................................................................................................259
Debugowanie programu............................................................................................259
Błędy wartości zmiennoprzecinkowych ...................................................................260
Obsługa błędów ........................................................................................................260
Konwersja typów zmiennych....................................................................................263
Prototypy...................................................................................................................265
Wskaźniki do funkcji ................................................................................................266
Sizeof........................................................................................................................267
Przerwania.................................................................................................................267
Funkcja signal() ........................................................................................................270
Dynamiczne alokowanie pamięci .............................................................................271
Funkcja atexit() .........................................................................................................273
Wydajność.................................................................................................................274
Przeszukiwanie katalogów........................................................................................275
Dostęp do pamięci rozbudowanej .............................................................................278
Dostęp do pamięci rozszerzonej ...............................................................................282
Tworzenie programów TSR......................................................................................290

Rozdział 7.  Metody przeprowadzania ataków ....................................................319

Streszczenie przypadku ...................................................................................................319
„Tylne wejścia” (backdoors) ...........................................................................................320

Zakładanie „tylnego wejścia” ...................................................................................322

Typowe techniki „tylnego wejścia” ................................................................................323

Filtry pakietów ..........................................................................................................323
Filtry stanowe............................................................................................................328
Bramy proxy i poziomu aplikacji .............................................................................333

Przeciążanie (flooding) ...................................................................................................333
Zacieranie śladów (log bashing) .....................................................................................342

Zacieranie śladów aktywności online .......................................................................343
Unikanie rejestrowania wciśnięć klawiszy ...............................................................344

Bomby pocztowe, spam i podrabianie korespondencji ...................................................355
Łamanie haseł (password cracking) ................................................................................357

Deszyfrowanie i krakowanie.....................................................................................357

Zdalne przejęcie kontroli.................................................................................................362

Krok 1. Rozpoznanie ................................................................................................363
Krok 2. Przyjazna wiadomość email ........................................................................363
Krok 3. Kolejna ofiara ..............................................................................................364

Monitorowanie komunikacji (sniffing) ...........................................................................366
Podrabianie IP i DNS (spoofing) ....................................................................................374

Studium przypadku ...................................................................................................375

Konie trojańskie ..............................................................................................................382
Infekcje wirusowe ...........................................................................................................388
Wardialing .......................................................................................................................391
„Złamanie” strony WWW (Web page hack)...................................................................392

background image

Spis treści

7

Krok 1. Rozpoznanie ................................................................................................394
Krok 2. Uszczegółowienie danych ...........................................................................394
Krok 3. Rozpoczęcie właściwego ataku ...................................................................397
Krok 4. Poszerzenie wyłomu ....................................................................................397
Krok 5. „Hakowanie” strony.....................................................................................397

Rozdział 8.  Bramy, routery oraz demony usług internetowych ............................401

Bramy i routery ...............................................................................................................401

3Com.........................................................................................................................402
Ascend/Lucent ..........................................................................................................409
Cabletron/Enterasys ..................................................................................................416
Cisco .........................................................................................................................423
Intel ...........................................................................................................................431
Nortel/Bay.................................................................................................................438

Demony serwerów internetowych...................................................................................442

Apache HTTP ...........................................................................................................443
Lotus Domino ...........................................................................................................445
Microsoft Internet Information Server......................................................................446
Netscape Enterprise Server .......................................................................................448
Novell Web Server....................................................................................................451
O’Reilly Web Site Professional ................................................................................454

Rozdział 9.  Systemy operacyjne .......................................................................459

UNIX.........................................................................................................................460
AIX ...........................................................................................................................462
BSD...........................................................................................................................470
HP-UX ......................................................................................................................484
IRIX ..........................................................................................................................494
Linux .........................................................................................................................497
Macintosh..................................................................................................................522
Microsoft Windows ..................................................................................................527
Novell NetWare ........................................................................................................543
OS/2 ..........................................................................................................................552
SCO...........................................................................................................................566
Solaris .......................................................................................................................568

Rozdział 10. Serwery proxy i zapory firewall........................................................573

Bramy międzysieciowe ...................................................................................................573

BorderWare...............................................................................................................573
FireWall-1 .................................................................................................................577
Gauntlet.....................................................................................................................581
NetScreen ..................................................................................................................585
PIX ............................................................................................................................589
Raptor........................................................................................................................596
WinGate ....................................................................................................................599

Rozdział 11. TigerSuite — kompletny pakiet narzędzi do badania i ochrony sieci ...605

Terminologia ...................................................................................................................605
Wprowadzenie.................................................................................................................607

Instalacja ...................................................................................................................610

Moduły ............................................................................................................................613

Moduły grupy System Status ....................................................................................614

TigerBox Tookit..............................................................................................................619

TigerBox Tools .........................................................................................................619
TigerBox Scanners....................................................................................................624

background image

8

Hack Wars. Na tropie hakerów

TigerBox Penetrators ................................................................................................626
TigerBox Simulators .................................................................................................627

Przykładowy scenariusz włamania..................................................................................628

Krok 1. Badanie celu.................................................................................................629
Krok 2. Rozpoznanie ................................................................................................631
Krok 3. Socjotechnika...............................................................................................633
Krok 4. Atak..............................................................................................................635

Podsumowanie ................................................................................................................635

Dodatek A  Klasy adresów IP oraz podział na podsieci.......................................637

Dodatek B  Porty standardowe .........................................................................641

Dodatek C  Pełna lista portów specjalnych .......................................................645

Dodatek D  Porty usług niepożądanych .............................................................685

Dodatek E  Zawartość płyty CD .......................................................................691

Skorowidz .........................................................................................................701

background image

Rozdział 6.

Język C

Dla  każdego  hakera,  młodego  czy  starego,  mniej  lub  bardziej  doświadczonego,  zna-
jomość  języka  C  jest  jednym  z  fundamentów  wiedzy.  Niemal  wszystkie  narzędzia
i programy, stosowane w trakcie analiz sieci i włamań, powstają właśnie w tym języ-
ku.  Również  w  niniejszej  książce  większość  przedstawianego  kodu  to  właśnie  kod
źródłowy w języku C. Programy te można modyfikować, dostosowywać do własnych
potrzeb i odpowiednio kompilować.

W  pracy  nad  niniejszym  rozdziałem  wykorzystano  obszerne  fragmenty  pracy  guru
programowania Matthew Proberta. Mają one pełnić funkcję wprowadzenia do pro-
gramowania w języku C i umożliwić stosowanie przedstawianych w książce (i załą-
czonych  na  CD-ROM-ie)  listingów  programów.  Pełny  kurs  języka  znajdziesz  w  nie-
jednej książce wydawnictwa Helion.

Język C wyróżniają następujące cechy, które omawiamy niżej.

J

J

J

Blokowe konstrukcje sterowania wykonywaniem programu (typowe dla
większości języków wysokiego poziomu).

J

J

J

Swobodne operowanie podstawowymi obiektami „maszynowymi” (takimi jak
bajty) i możliwość odwoływania się do nich przy użyciu dowolnej, wymaganej
w danej sytuacji, perspektywy obiektowej (typowe dla języków asemblerowych).

J

J

J

Możliwość wykonywania operacji zarówno wysokiego poziomu (na przykład
arytmetyka zmiennoprzecinkowa), jak i niskiego poziomu (zbliżonych
do instrukcji języka maszynowego), co umożliwia tworzenie kodu wysoce
zoptymalizowanego bez utraty jego przenośności.

background image

202

Hack Wars. Na tropie hakerów

Przedstawiony  w  niniejszym  rozdziale  opis  języka  C  bazować  będzie  na  funkcjach
oferowanych  przez  większość  kompilatorów  dla  komputerów  PC.  Powinien  dzięki
temu  umożliwić  rozpoczęcie  tworzenia  prostych  programów  osobom  nieposiadają-
cym szerokiej wiedzy o języku (uwzględnimy między innymi funkcje zapisane w pa-
mięci ROM i funkcje DOS-u).

Przyjmujemy  założenie,  że  masz,  drogi  Czytelniku,  dostęp  do  kompilatora  C  i  od-
powiedniej  dokumentacji  funkcji  bibliotecznych.  Programy  przykładowe  powstały
w Turbo C firmy Borland; większość elementów niestandardowych tego narzędzia
uwzględniono również w późniejszych edycjach Microsoft C.

Wersje języka C

W  pierwotnej  edycji  języka  C  (jeszcze  przed  publikacją  Kernighana  i  Ritchie’ego,
The C Programming Language, Prentice-Hall 1988 (polskie wydanie: Język ANSI C,
Wydawnictwa  Naukowo-Techniczne  1994))  zintegrowane  operatory  przypisania  (+=,
*= itd.) definiowane były odwrotnie (tj. =+, =* itd.). Znakomicie utrudniało to inter-
pretację wyrażeń takich jak:



co mogłoby znaczyć



lub



Ritchie szybko zauważył dwuznaczność takiego zapisu i zmodyfikował go do postaci
znanej dzisiaj (+=, *= itd.). Mimo to wciąż stosowanych jest wiele odmian będących
rodzajem wypośrodkowania między pierwotną wersją języka C Kernighana i Ritchie’ego
a językiem ANSI C. Różnice między nimi dotyczą przede wszystkim:

J

J

J

wprowadzenia prototypów funkcji i zmiany preambuły definicji funkcji,
aby dostosować ją do stylu prototypów,

J

J

J

wprowadzenia znaku wielokropka (...) do oznaczenia list argumentów o zmiennej
długości,

J

J

J

wprowadzenia słowa kluczowego 



 (dla funkcji, które nie zwracają wartości)

i typu 



 dla ogólnych zmiennych wskaźnikowych,

J

J

J

wprowadzenie w preprocesorze mechanizmów scalania ciągów, wklejania
elementu (token-pasting) i zamiany na ciąg (string-izing),

J

J

J

dodanie w preprocesorze translacji „trygrafów” (trigraph) — trójznakowych
sekwencji reprezentujących znaki specjalne,

J

J

J

dodanie w preprocesorze dyrektywy 



 i formalizacja pseudofunkcji

  

,

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

203

J

J

J

wprowadzenie ciągów i znaków wielobajtowych, zapewniających obsługę
języków narodowych,

J

J

J

wprowadzenie słowa kluczowego 

  

 (jako uzupełnienie słowa 

  

,

stosowane w deklaracjach liczb całkowitych) i jednoargumentowego
operatora plus (



).

Klasyfikowanie języka C

Szerokie możliwości języka C, dopuszczenie bezpośredniego operowania na adresach
i danych w pamięci oraz strukturalne podejście do programowania sprawiają, że język
ten klasyfikuje się jako „język programowania średniego poziomu”. Znajduje to wyraz
w mniejszej liczbie gotowych rozwiązań niż w językach wysokiego poziomu, takich
jak BASIC, ale wyższym poziomie strukturalnym niż niskopoziomowy Assembler.

Słowa kluczowe

Pierwotna  edycja  języka  C  definiuje  27  słów  kluczowych.  Komitet  ANSI  dodał  do
nich 5 nowych. Wynikiem są dwa standardy języka, choć norma ANSI przejęła więk-
szość elementów od Kerninghana i Ritchie’ego. Oto lista:







  





 

 



 

 

 



 

 

 

 

 

 



   

 



 

 



 

  



  



Warto zwrócić uwagę, że niektóre kompilatory C wprowadzają dodatkowe słowa klu-
czowe, specyficzne dla środowiska sprzętowego. Warto zapoznać się z nimi.

Struktura języka C

Język  C  wymaga  programowania  strukturalnego.  Oznacza  to,  że  na  program  składa
się pewna grupa nawzajem wywołujących się bloków kodu. Dostępne są różnorodne
polecenia służące do konstruowania pętli i sprawdzania warunków:

 

Blok  programu  w  języku  C  ujmowany  jest  w  nawiasy  klamrowe  (



).  Może  on  być

kompletną  procedurą,  nazywaną  funkcją  lub  częścią  kodu  funkcji.  Przyjrzyjmy  się
przykładowi:

background image

204

Hack Wars. Na tropie hakerów

 !

"

 #

 !#

$

Instrukcje  wewnątrz  nawiasów  klamrowych  wykonane  zostaną  tylko  wtedy,  gdy  speł-
niony zostanie warunek 



.

Jako kolejny przykład przedstawimy pełny blok kodu funkcji, zawierający wewnątrz
blok pętli:

 %&'()

"

 #



"

 *+,     !  !*#

*- *.#

$

!//0 !#

 #

$

Zwróćmy uwagę, że każdy wiersz instrukcji zakończony jest średnikiem, o ile nie jest
sygnałem  początku  bloku  kodu  (w  takim  przypadku  kolejnym  znakiem  jest  nawias
klamrowy). Język C rozpoznaje wielkość liter, ale nie bierze pod uwagę białych zna-
ków.  Odstępy  między  poleceniami  są  pomijane,  stąd  konieczność  użycia  średnika,
aby oznaczyć koniec wiersza. Tego rodzaju podejście powoduje, że następujące pole-
cenia interpretowane są jako identyczne:

!#

!#

!#

Ogólna postać programu w języku C jest następująca:

J

J

J

instrukcje preprocesora kompilacji,

J

J

J

globalne deklaracje danych.

J

J

J

deklaracje i definicje funkcji (włączając w to zawartość programu):

   

"

  

$

    

"

  

$

  1 

"

  

$

2

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

205

    

"

  

$

Komentarze

Podobnie jak większość języków, C pozwala umieszczać w kodzie programu komen-
tarze. Ich ogranicznikami są symbole 



 i 



:

34' 5   56 743

(Równie  często  korzysta  się  z  komentarzy  jednoliniowych,  otrzymywanych  poprzez
sekwencję //, np.:

33'  85   92:2

Biblioteki

Programy  w  języku  C  kompiluje  się  i  łączy  z  funkcjami  bibliotecznymi,  dostarcza-
nymi  wraz  z  kompilatorem.  Na  biblioteki  składają  się  funkcje  standardowe,  których
działanie  zdefiniowane  zostało  w  normie  ANSI.  Ich  powiązanie  z  konkretnym  kom-
pilatorem zapewnia dostosowanie do platformy sprzętowej. Wynika stąd, że standardowa
funkcja  biblioteczna 

 

  działa  tak  samo  w  systemach  DEC  VAX  i  IBM  PC,

choć różni się jej, zapisany w bibliotece, kod maszynowy. Programista C nie musi za-
głębiać się w zawartość bibliotek, wymagana jest jedynie umiejętność ich stosowania
i znajomość działania funkcji, które pozostają niezmienne na każdym komputerze.

Tworzenie programów

Kompilacja

Zanim zajmiemy się funkcjami, poleceniami, sekwencjami i innymi zaawansowanymi
zagadnieniami, przyjrzyjmy się praktycznemu przykładowi, w którym doprowadzimy
do  skompilowania  kodu.  Kompilowanie  programów  C  jest  stosunkowo  prostą  czyn-
nością, jednak różni się zależnie od stosowanego kompilatora. Kompilatory wyposażone
w  menu  umożliwią  skompilowanie,  skonsolidowanie  i  uruchomienie  programu  jed-
nym  wciśnięciem  klawisza.  Podchodząc  jednak  do  zagadnienia  możliwie  uniwersal-
nie i tradycyjnie, przeprowadzimy poniżej całą procedurę w oparciu o wiersz poleceń.

W dowolnym edytorze wprowadzamy poniższy fragment kodu i zapisujemy plik jako
przyklad.c:

34

;      

43

background image

206

Hack Wars. Na tropie hakerów

<   20

  

"

 *= >+*#

$

Kolejnym  krokiem  jest  skompilowanie  kodu  do  postaci  pliku  programu  —  dopiero
wtedy można będzie go uruchomić (czy też wykonać). W wierszu poleceń w tym sa-
mym katalogu, w którym zapisaliśmy plik przyklad.c, wprowadzamy następujące po-
lecenie kompilacji:

 2

Nie wolno zapominać, że składnia polecenia kompilacji zależy od kompilatora. Nasz
przykład opiera się na standardzie języka C. Współcześnie jednak popularne jest sto-
sowanie składni wywodzącej się z kompilatora GNU C:

 2

Po  wykonaniu  takiego  polecenia  nasz  kod  jest  już  skompilowany  i  ma  postać  pliku
programu,  który  możemy  uruchomić.  Wynik  jego  działania  łatwo  wydedukować
z prostego kodu:

= >

9    

To wszystko! Kompilowanie małych programów w C nie jest trudne, należy jedynie
mieć  świadomość  szkodliwych  niekiedy  efektów  ich  działania.  Programy  przedsta-
wiane na stronach tej książki i załączone na CD-ROM-ie są oczywiście znacznie bar-
dziej skomplikowane, jednak zasady pozostają te same.

Typy danych

W  języku  C  wyróżnia  się  cztery  podstawowe  typy  danych:  znakowy,  całkowity,
zmiennoprzecinkowy  i  nieokreślony.  Odpowiadają  im  słowa  kluczowe: 





,

 

 i 



. Dalsze typy danych tworzy się na tej podstawie, dodając modyfikatory:

  

 (ze znakiem), 

  

 (bez znaku), 



 (długa) i 

 

 (krótka). Modyfika-

tor 

  

  jest  elementem  domyślnym,  co  sprawia,  że  jego  użycie  może  się  okazać

konieczne  jedynie  w  wypadku  gdy  zastosowano  przełącznik  kompilacji  nakazujący
domyślne korzystanie ze zmiennych bez znaku. Rozmiar każdego typu danych zależy
od  platformy  sprzętowej,  jednak  norma  ANSI  wyznacza  pewne  zakresy  minimalne,
zestawione w tabeli 6.1.

W praktyce tak określone konwencje oznaczają, że typ danych 



 nadaje się najle-

piej  do  przechowywania  zmiennych  typu  znacznikowego,  takich  jako  kody  stanu,
o ograniczonym zakresie wartości. Można również korzystać z typu 



. Gdy jednak

zakres wartości nie przekracza 127 (lub 255 dla 

  

), każda deklarowana

w ten sposób zmienna przyczynia się do niepotrzebnego obciążania pamięci.

Natomiast trudniejsze jest pytanie o to, z którego typu liczb rzeczywistych korzystać
— 

 

 

  czy 

   

.  Gdy  wymagana  jest  dokładność,  na  przykład

w aplikacji stosowanej w księgowości, instynktownie powinniśmy użyć typu 

  

,

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

207

Tabela 6.1.

 Rozmiary i zakresy typów danych języka C

Typ

Rozmiar

Zakres



8

–128 do 127

 

8

0 do 255



16

–32 768 do 32 767

 

16

0 do 65 535

 

32

–2 147 483 648 do 2 147 483 647

  

32

0 do 4 294 967 295

 

32

precyzja 6-cyfrowa



64

precyzja 10-cyfrowa

  

80

precyzja 10-cyfrowa

wiąże się to jednak z wykorzystaniem przez każdą zmienną 10 bajtów. Obliczenia na
liczbach  rzeczywistych  nie  są  tak  dokładne  jak  na  liczbach  całkowitych,  warto  więc
zawsze  rozważyć  użycie  typu 



  i  „obejście”  problemu.  Typ  danych 

 

  nie  jest

zbyt dobry, gdyż jego 6-cyfrowa precyzja nie zapewnia dokładności, na której zawsze
będziemy  mogli  polegać.  Ogólną  zasadą  jest  korzystanie  z  typów  całkowitych  tak
szeroko,  jak  tylko  jest  to  możliwe,  a  gdy  pojawia  się  konieczność  użycia  liczb  rze-
czywistych, wprowadzenie typu 

 

.

Deklarowanie zmiennej

Każda zmienna musi zostać zadeklarowana przed użyciem. Ogólną postacią deklara-
cji zmiennej jest:

 #

Aby więc przykładowo zadeklarować zmienną 



 typu 



, przeznaczoną do przecho-

wywania wartości z zakresu od –32 768 do 32 767, użyjemy instrukcji:

 #

Ciągi znakowe deklarować można jako tabele znaków:

 ?   @#

Deklaracja ciągu o nazwie 

 !"#

 i długości 30 znaków, wyglądać będzie następująco:

 ?A!@#

Tablice  danych  innych  typów  mogą  mieć  więcej  niż  jeden  wymiar.  Oto  deklaracja
dwuwymiarowej tablicy liczb całkowitych:

 ? !@? !@#

Elementy tablicy wywołujemy jako:

?!@?!@

?!@? @

?@?@

background image

208

Hack Wars. Na tropie hakerów

Wyróżnia  się  trzy  poziomy  dostępu  do  zmiennych:  lokalny,  na  poziomie  modułu
i globalny.  Zmienna  deklarowana  wewnątrz  bloku  kodu  będzie  dostępna  wyłącznie
dla instrukcji wewnątrz tego bloku. Zmienna deklarowana poza blokami kodu funkcji,
ale poprzedzona modyfikatorem 

 

, będzie dostępna wyłącznie instrukcjom we-

wnątrz  modułu  kodu  źródłowego.  Zmienna  deklarowana  poza  blokami  kodu  funkcji
i niepoprzedzona modyfikatorem będzie dostępna dla dowolnych instrukcji w dowol-
nym module programu. Na przykład:

   #

   #

  7   5 ;  5 B5

5    B 6  8    B

5 55C5    5 2D    CE8  6

;   56  92:2

"

 #

 #

$

 5

"

34F 5 G!43

!

"

  #

  !# 1!# HH

 *+= ,  *#

$

$

W  powyższym  przykładzie  zmienna 

  

  jest  dostępna  dla  wszystkich,  kompilowa-

nych  jako  jeden  program,  modułów  kodu  źródłowego.  Zmienna 

  jest  osiągalna  dla

wszystkich  instrukcji  w  funkcjach 



  i 

#$ 

,  ale  pozostaje  niewidoczna

z poziomu  innych  modułów.  Zmienne 



  i 

%

  są  dostępne  wyłącznie  instrukcjom  we-

wnątrz funkcji 



. Z kolei zmienna 

 

 może być użyta wyłącznie przez instrukcje

wewnątrz bloku kodu po instrukcji 



.

Jeżeli drugi blok kodu faktycznie ma skorzystać ze zmiennej 

  

, wymagane będzie

umieszczenie w nim deklaracji zmiennej globalnej 

 

:

    #

 5 

"

$

Język C nie stawia szczególnych przeszkód w przypisywaniu do siebie różnych typów
danych. Przykładowo możemy zadeklarować zmienną typu 



, co spowoduje przy-

pisanie  do  przechowywania  jej  wartości  jednego  bajtu  danych.  Można  podjąć  próbę
przypisania do niej wartości spoza tego zakresu:

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

209

  

"

I!!!#

$

Zmienna 



 może przechowywać wartości z zakresu od –127 do 128, a więc wartość 5000

nie zostanie przypisana. 



 przyjmie jednak wartość 136.

Potrzeba  przypisania  różnych  typów  danych  nie  jest  niczym  oryginalnym.  Aby  po-
wstrzymać kompilator od generowania ostrzeżeń o takich operacjach, można skorzy-
stać z instrukcji konwersji (cast statement), informując kompilator o tym, że operacja
wykonywana jest świadomie. Instrukcję taką budujemy, umieszczając przed zmienną
lub wyrażeniem nazwę typu danych ujętą w nawiasy:

  

"

  #

 #

 !!31I#

 #

$

Operacja  rzutowania 



  informuje  kompilator  o  konieczności  konwersji  wartości

zmiennej zmiennoprzecinkowej 



 do liczby całkowitej, zanim ta zostanie przypisana

do zmiennej 

%

.

Parametry formalne

Funkcja  w  języku  C  może  przyjmować  parametry  przekazywane  przez  funkcję  wy-
wołującą.  Parametry  te  deklaruje  się  podobnie  jak  zmienne,  podając  ich  nazwy  we-
wnątrz towarzyszących nazwie funkcji nawiasów:

 JKLM  

"

34MGE   8  43

 4#

$

  

"

 #

  #

 #

I#

 N#

JKLM #

 *- - G6- +* #

$

background image

210

Hack Wars. Na tropie hakerów

Modyfikatory dostpu

Stosuje się dwa modyfikatory dostępu: 



 i 

 

. Wartość zmiennej zadekla-

rowanej jako 



 nie może zostać zmieniona przez program, wartość zmiennej za-

deklarowanej  jako 

 

  może  zostać  zmieniona  przez  program.  Dodatkowo,  za-

deklarowanie zmiennej jako 

 

 uniemożliwia kompilatorowi zaalokowanie  jej

do rejestru i ogranicza przeprowadzaną na niej optymalizację.

Typy klas przechowywania zmiennych

Język C przewiduje cztery rodzaje przechowywania zmiennych: 

 

 





.  Typ 

 

  umożliwia  modułowi  kodu  źródłowego  dostęp  do  zmiennej

zadeklarowanej w innym module. Zmienne 

 

 dostępne są wyłącznie z poziomu

bloku kodu, w którym zostały zadeklarowane. Dodatkowo, jeżeli zmienna ma zasięg
lokalny, zachowuje swoją wartość między kolejnymi wywołaniami bloku kodu.

Zmienne rejestrowe (



) są, gdy tylko jest to możliwe, przechowywane w reje-

strach procesora. Zapewnia to najszybszy dostęp do ich wartości. Typ 



 stosuje się

wyłącznie w odniesieniu do zmiennych lokalnych.  Nakazuje  on  zachowywanie  war-
tości zmiennej lokalnej. Ponieważ jest to modyfikator domyślny, rzadko można spo-
tkać go w programach.

Operatory

Operatory to elementy kodu, które nakazują wykonanie obliczeń na zmiennych. W ję-
zyku C dostępne są następujące:

.

adres,

4

pośredniość,

H

plus jednoargumentowy,



minus jednoargumentowy,

O

dopełnienie bitowe,

>

negacja logiczna,

HH

jako prefiks — preinkrementacja, jako sufiks — postinkrementacja,

PP

jako prefiks — predekrementacja, jako sufiks — postdekrementacja,

H

dodawanie,



odejmowanie,

4

mnożenie,

3

dzielenie,

-

reszta z dzielenia (modulo),



przesunięcie w lewo,

00

przesunięcie w prawo,

.

bitowa operacja AND,

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

211

/

bitowa operacja OR,

Q

bitowa operacja XOR,

..

logiczna operacja AND,

//

logiczna operacja OR,



przypisanie,

4

przypisanie iloczynu,

3

przypisanie ilorazu,

-

przypisanie reszty (modułu),

H

przypisanie sumy,



przypisanie różnicy,



przypisanie przesunięcia w lewo,

00

przypisanie przesunięcia w prawo,

.

przypisanie wyniku bitowej operacji AND,

/

przypisanie wyniku bitowej operacji OR,

Q

przypisanie wyniku bitowej operacji XOR,



mniejsze niż,

0

większe niż,



mniejsze lub równe,

0

większe lub równe,



równe,

>

różne od,

2

bezpośredni selektor składnika,

0

pośredni selektor składnika,

RS

jeżeli 

 to prawda, to , w przeciwnym razie %&

?@

definiowanie tablic,



nawiasy oddzielają warunki i wyrażenia,

222

wielokropek wykorzystuje się w listach parametrów formalnych prototypów
funkcji do deklarowania zmiennej liczby parametrów lub parametrów
zmiennych typów.

Aby  zilustrować  sposób  korzystania  z  podstawowych  operatorów,  przyjrzyjmy  się
krótkiemu programowi:

  

"

 #

  #

 #

I#3495 BI43

 31#3495  B  5143

 41#3495 B   8 5143

34F  CC BE543

background image

212

Hack Wars. Na tropie hakerów

 *M5  *#



 *M5  *#

$

Typowym sposobem zwiększenia wartości zmiennej o 1 jest wiersz:

H 

Język C dostarcza operatora inkrementacji, wystarczy więc napisać:

HH

W podobny sposób korzystamy z operatora dekrementacji, czyli zmniejszania war-
tości o 1:



Pozostałe  operatory  matematyczne  wykorzystujemy  podobnie.  Warto  jednak  pamię-
tać o wprowadzanych przez język C możliwościach zapisu skróconego:

Zapis typowy

Zapis w j+zyku C

H HH
 
41

41

3

3

-I

-I

Funkcje

Funkcje to procedury kodu źródłowego tworzące program w języku C. Ich ogólną po-
stacią jest:

       

"

  

$

 

  to  typ  zwracanej  przez  funkcję  wartości: 





 



  itp.

Kod wewnątrz funkcji C pozostaje niewidoczny dla innych funkcji C. Nie można wy-
konywać  skoków  z  jednej  funkcji  do  wnętrza  innej.  Funkcje  mogą  jedynie  wywoły-
wać  inne  funkcje.  Nie  wolno  również  definiować  funkcji  wewnątrz  innych  funkcji.
Definicja musi zostać umieszczona bezpośrednio na poziomie modułu kodu.

Parametry przekazywane są do funkcji jako wartości lub jako odwołania (wskaźniki).
Gdy parametr jest przekazywany jako wartość, funkcja otrzymuje kopię tej wartości.
Parametr przekazywany jako odwołanie jest jedynie wskaźnikiem do właściwego pa-
rametru. Pozwala to na zmianę jego wartości z poziomu wywołanej funkcji. W poniż-
szym przykładzie przekazujemy dwa parametry jako wartość  do  funkcji 

#$ 

,

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

213

która następnie podejmuje próbę zmiany wartości przekazanych zmiennych. Drugim
krokiem jest przekazanie tych samych parametrów do funkcji 

#$ 

, która rów-

nież podejmuje próbę zmiany wartości zmiennych:

<   20

  5  

"

34T 55 5  5  B43

41#

41#

 *+, BE 5- 2, BE 5- *#

 #

$

  5  4 4

"

34T 55 5  5   ;43

4441#

4441#

 *+, BE 5 - 2, BE 5 - *44#

 4#

$

  

"

 #

 #

 #

I#

N#

 5#

 5 ..#

 *+, BE-  BE-  BE- *#

$

#$ 

  nie  zmienia  wartości  otrzymanych  parametrów.  Modyfikowana  jest  za-

wartość  wskazywanych  parametrami  adresów  pamięci.  O  ile 

#$ 

  otrzymuje

z funkcji 



 wartości zmiennych 



 i 

%

#$ 

 otrzymuje z funkcji 



 ich

adresy w pamięci.

Przekazywanie tablicy do funkcji

Następujący  program  przekazuje  do  funkcji  tablicę,  a  funkcja  nadaje  wartości  ele-
mentom tablicy:

background image

214

Hack Wars. Na tropie hakerów

<   20

   5 ?@

"

 #

 !# !!#HH

?@#

$

  

"

   ? !!@#

 #

 5  #

 !# !!#HH

 *+, BE -  - *  ?@#

$

Parametr funkcji, 

'(

, jest tablicą dowolnej długości. Deklaracja taka jest możli-

wa, ponieważ kompilator przekazuje jedynie adres początkowy tablicy, a nie wartości
poszczególnych  jej  elementów.  Konsekwencją  tego  jest  fakt,  że  funkcja  może  zmie-
niać wartości elementów tablicy. Aby uniemożliwić funkcji wprowadzanie modyfika-
cji, konieczne jest użycie typu 



:

 5   ?@

"

$

Przy takiej deklaracji wiersz zmieniający zawartość tablicy wywołałby błąd kompila-
cji. Określenie parametru jako wartości stałej nie likwiduje jednak pośredniości jego
przekazania. Ilustruje to poniższy program:

<   20

   5   ?@

"

 4 #

 #

34' 5  8U      U43

34  5V43

345 V   43

 #

 !# !!#HH

"

4 #

 HH#

$

$

  

"

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

215

   ? !!@#

 #

 5  #

 !# !!#HH

 *+, BE -  - *  ?@#

$

Przekazywanie parametrów funkcji main()

Język C umożliwia przekazanie parametrów do uruchamianego programu z poziomu
systemu operacyjnego. Do ich odczytania wykorzystuje się zmienne 



 i 

'(

:

<   20

   4?@

"

 #

 !##HH

 *+,   -  -*?@#

$

Parametr 



 przechowuje liczbę przekazanych programowi parametrów. W tablicy

'(

 zapisane są ich adresy; 

'(

 jest zawsze nazwą uruchamianego programu.

Mechanizm ten ma szczególne znaczenie dla aplikacji wymagających dostępu do pli-
ków systemowych i danych. Rozważmy następującą sytuację: mała aplikacja obsługi
baz danych przechowuje swoje dane w pojedynczym pliku dane.dat; aplikacja ta musi
zostać tak zaprojektowana, aby można było uruchomić ją z dowolnego katalogu, czy
to na dysku twardym, czy dyskietce; musi również zapewnić uruchamianie za pośred-
nictwem ścieżki wyszukiwania DOS-u (

 

). Do poprawnej pracy aplikacji jest więc

wymagane,  aby  zawsze  mogła  odnaleźć  plik  dane.dat.  Rozwiązanie  takie  zapewni
przyjęcie założenia, że plik danych jest zawsze w identycznym katalogu co sam pro-
gram. Poniższy fragment ilustruje wykorzystanie parametrów 



 i 



 w celu utwo-

rzenia ścieżki do pliku danych aplikacji:

<  20

( ? W!@#

   4?@

"

4( *XD'D2XD'*#

4#

 ( ?!@#

  ( *2*#      ;

å  92:2

KYZZ

"

349    5 27LJ43

background image

216

Hack Wars. Na tropie hakerów

  ( *2 *#

$

34,  5     B43

4 >U++U

#

 ( #

$

Przedstawiony program tworzy i zapisuje w zmiennej 

 !" )#

 ciąg postaci ścież-

ka\dane.dat. Jeżeli więc przykładową nazwą pliku uruchomieniowego będzie test.exe
i  zostanie  on  umieszczony  w  katalogu  \borlandc,  zmiennej 

 !" )#

  przypisany

zostanie ciąg 

*   *  + 

.

Wyj#cie z funkcji

Polecenie 

 

  powoduje  natychmiastowe  wyjście  z  funkcji.  Jeżeli  w  deklaracji

funkcji podano typ zwracanej wartości, w poleceniu 

 

 należy użyć parametru te-

go samego typu.

Prototypy funkcji

Prototypy funkcji umożliwiają kompilatorowi C sprawdzanie poprawności przekazy-
wanych,  do  i  z  funkcji,  danych.  Ma  to  istotne  znaczenie  jako  zabezpieczenie  przed
przekroczeniem zakresu zaalokowanego dla zmiennej obszaru pamięci. Prototyp funkcji
umieszcza się na początku programu po poleceniach preprocesora (takich jak 



)

i przed deklaracjami funkcji.

Polecenia preprocesora C

W języku C w treści kodu źródłowego można umieszczać polecenia dla kompilatora.
Określa się je terminem polecenia preprocesora. Norma ANSI definiuje następujące:

<

< 

< 

<

<

< 

< 

< 

<  

<

< 

<

Wszystkie  polecenia  preprocesora  rozpoczyna  znak  krzyżyka  (hash),  czyli  #.  Każde
wymaga osobnego wiersza kodu (uzupełnionego ewentualnie komentarzem). Poniżej
przedstawiamy krótkie omówienie.

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

217

#define

Polecenie 

 

  tworzy  identyfikator,  który  kompilator  zastąpi  podanym  ciągiem

w danym module kodu źródłowego. Na przykład:

< TDZF&!

< '[Y&>TDZF&

Kompilator zastąpi wszystkie dalsze wystąpienia ciągu 

,-./0

 znakiem 



, a wszystkie

dalsze  wystąpienia  ciągu 

1230

  —  ciągiem 

4

.  Zastępowaniu  nie  podlegają  identyfi-

katory wewnątrz znaków cudzysłowu, a więc wiersz:

 *'[Y&*#

nie zostanie zmieniony, ale

 *- *TDZF&#

podlega modyfikacji.

Polecenie 

 

 może również zostać użyte do definiowania makr, także makr z pa-

rametrami. Do zapewnienia poprawności zastąpień zaleca się ujmowanie parametrów
w nawiasy. W poniższym przykładzie deklarujemy makro o nazwie 

 

, przyj-

mujące dwa parametry i zwracające ten z nich, którego wartość jest większa.

<   20

<  0 RS 

 

"

 *+- 5 6*IN#

$

#error

Polecenie 

 

  powoduje  przerwanie  procesu  kompilacji  i  wyświetlenie  podanego

tekstu, na przykład:

< F\LJ9]ZL,DK&XLJLXYZY:

powoduje zatrzymanie kompilacji i wyświetlenie:

F\LJ9]ZL,DK&XLJLXYZY:

#include

Polecenie 



  nakazuje  kompilatorowi  odczytanie  i  przetworzenie  zawartości

dodatkowego  pliku  źródłowego.  Nazwa  pliku  musi  zostać  ujęta  w  cudzysłów  lub
wstawiona między znaki 

5

, na przykład:

< * 12*

<   20

Jeżeli nazwa pliku została wpisana między znaki 

5

, kompilator wyszukuje go w kata-

logu określonym w konfiguracji. Jest to zasada ogólna.

background image

218

Hack Wars. Na tropie hakerów

#if, #else, #elif, #endif

Grupa  poleceń 



  dostarcza  mechanizmu  kompilacji  warunkowej.  Stosowana  jest

dość typowa składnia:

<   

  

<

  

< 

Polecenie 

 

 to skrócona postać 

  

:

< 

  

< 

  

< 

#ifdef, #ifndef

Rozwinięciem tych poleceń jest 

  

 (jeżeli zdefiniowano) i 

  

(jeżeli nie zdefiniowano). Konstrukcje składniowe są następujące:

<  

  

<

  

< 

<  

  

<

  

< 

   

 to identyfikator utworzony za pomocą deklaracji 

 

.

#undef

Polecenie 

 

  usuwa  definicję  makra  utworzonego  przy  użyciu  wcześniejszej  in-

strukcji 

 

.

#line

Polecenie 



  modyfikuje  zmienne  globalne  kompilatora 

)).670))

  i 

)),6.0))

.

Ogólną postacią instrukcji jest:

< *  *

Wartość 

 

 zostaje umieszczona w zmiennej 

)).670))

, a 

8   8

 — w zmien-

nej 

)),6.0))

.

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

219

#pragma

Umożliwia korzystanie z poleceń specyficznych dla kompilatora.

Instrukcje steruj"ce

Jak  w  każdym  języku  programowania,  również  w  C,  znajdziemy  instrukcje  spraw-
dzające wartość wyrażenia. Wynikiem takiego sprawdzenia jest wartość 

1230

 lub 

,-./0

.

Wartości 

,-./0

 odpowiada liczba 



, a 

1230

 — liczba różna od zera.

Instrukcje wykonania warunkowego

Podstawową instrukcją wykonania warunkowego jest 



 o następującej składni:

 

  



  

gdzie 

  

  może  być  instrukcją  pojedynczą  lub  ujętym  w  nawiasy  klamrowe

blokiem  kodu.  Element 



  jest  opcjonalny.  Jeżeli  wartością 



  jest 

1230

,

wykonywana jest instrukcja podana bezpośrednio po nim. W pozostałych przypadkach
wykonywana jest instrukcja podana po słowie 



 (o ile ta część składni została użyta).

Alternatywą dla konstrukcji 

+++ 

 jest polecenie 

9:

 w postaci:

      

Jeżeli wartością wyrażenia jest 

1230

, wykonywana jest pierwsza instrukcja. W pozo-

stałych przypadkach wykonywana jest instrukcja druga. Ilustruje to przykład:

<   20

  

"

 #

W#

 *+  -*-1!R* *S* *#

$

Język  C  oferuje  również  instrukcję 

"

,  ułatwiającą  porównywanie  wyrażenia

z pewną listą wartości. Wykonywane są instrukcje powiązane z pierwszą dopasowaną
wartością listy. Składnia polecenia 

"

 jest następująca:

  

"

 S  

 #

!S  

 #

2

2

background image

220

Hack Wars. Na tropie hakerów

 S  

 #

   S  

$

Użycie  instrukcji 

  #

  nie  jest  wymagane,  ale  jej  pominięcie  powoduje  dalsze  po-

równywanie wyrażenia z kolejnymi elementami listy wartości.

<   20

  

"

 #

W#

 

"

!S *+G6 *#

 #

 S *+G65 *#

 #

1S *+G6 *#

 #

AS *+G6 *#

 #

   S *+5 6  *#

$

$

Instrukcje 

"

 można zagnieżdżać.

Instrukcje iteracji

W języku C stosuje się trzy instrukcje pętli (iteracji): 



"

 i 

;"

. Składnia

pętli 



 jest następująca:

    # #  

  

Jest ona szczególnie przydatna, gdy korzystamy z licznika, jak w poniższym przykła-
dzie wyświetlającym zestaw znaków ASCII:

<   20

  

"

 #

 A1# 1^#HH

 *- + -+ *#

$

Dopuszczalna jest również nieskończona pętla 



:

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

221

 ##

"

  

$

Język C pozwala używać też pustych instrukcji. Poniższa pętla usuwa z ciągu począt-
kowe znaki odstępu:

 #4 UU# HH

#

Warto zwrócić uwagę na średniki odpowiadające inicjalizacji pętli i pustej instrukcji.

Pętla 

"

 ma konstrukcję nieco prostszą:

 

  

Instrukcja lub blok instrukcji (ujęty w nawiasy klamrowe) będą powtarzane do czasu,
gdy wyrażenie warunku przyjmie wartość 

,-./0

. Jeżeli wyrażenie nie jest prawdziwe

jeszcze  przed  wejściem  do  pętli,  instrukcje  nie  będą  wykonywane  w  ogóle.  Jest  to
istotna różnica w stosunku do pętli 

;"

, która zawsze zostaje wykonana co naj-

mniej raz. Jej składnia to:

"

  

$

 #

Instrukcje skoku

Instrukcja 

 

 pozwala powrócić z funkcji wykonywanej do funkcji, z której ta zo-

stała  wywołana.  W  zależności  od  zadeklarowanego  typu  wartości  zwracanej  przez
funkcję instrukcja 

 

 może wymagać odpowiedniego parametru:

 JYZ'  

"

 4#

$

lub

   5

"

 *+= ,  *#

 #    5  92:2

$

Instrukcja 

  #

 służy do wychodzenia z pętli lub instrukcji 

"

. W przypadku pę-

tli powoduje to jej przedwczesne zakończenie, jak w poniższym przykładzie:

<   20

  

"

 #

background image

222

Hack Wars. Na tropie hakerów

 !#1IW#HH

"

 !!

 #

 *- + *#

$

$

Uzupełnieniem 

  #

 jest polecenie 



, wymuszające przeprowadzenie następ-

nej iteracji pętli. Kolejną wykonywaną instrukcją jest w tym przypadku instrukcja pę-
tli (dalsze instrukcje w iterowanym bloku są pomijane). Dostępna jest również funk-
cja  przedwczesnego  zakończenia  wykonywania  programu  — 



.  Można  za  jej

pomocą przekazać wartość zwracaną do programu wywołującego:

   #

Continue

Słowo kluczowe 



 nakazuje skok do instrukcji kontrolnej pętli. W przypadku

pętli zagnieżdżonych jest to instrukcja pętli wewnętrznej (

"

+++" 

). To spo-

sób  na  łagodne  zakończenie  pętli  jak  w  poniższym  przykładzie,  gdzie  odczytujemy
zapisane w pliku ciągi:

<   20

  

"

T]Z&4#

4#

 ? !!@#

 * 2  ***#

KYZZ

"

  *K 8  E   2  *#

 !#

$



"

   !!#

KYZZ

34, 5B43

   #

 #

$

#

$

W przypadku pętli 



 instrukcja 



 powoduje najpierw wykonanie wyrażenia

inkrementacji, a dopiero po nim następuje sprawdzenie warunku zakończenia.

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

223

Wej#cie-wyj#cie

Pobieranie danych

Program  w  języku  C  może  pobierać  dane  z  konsoli  (która  jest  standardowym  urzą-
dzeniem wejściowym), pliku lub portu. Ogólnym poleceniem odczytu danych ze stan-
dardowego  strumienia  wejściowego 



  jest 

 

.  Skanuje  ono  po  jednym  znaku

kolejne pola wejściowe. Podlegają one formatowaniu zgodnie z pierwszym z przekaza-
nych funkcji 

 

 parametrów. Następnie pole zostaje zapisane pod adresem prze-

kazanym jako kolejny parametr wywołania funkcji. Przykładowy program odczytuje
pojedynczą liczbę całkowitą ze strumienia 



:

  

"

 #

*- *.#

$

Warto zwrócić uwagę na operator użyty jako prefiks zmiennej 



 na liście parametrów

wywołania funkcji 

 

. Funkcja ta zapisuje bowiem wartość pod określonym ad-

resem,  nie  posługując  się  mechanizmem  przypisywania  wartości  zmiennej.  Ciągiem
formatującym jest ciąg znakowy, który może zawierać trzy typy danych: znaki odstępu
(spacja, tabulator, przejście do nowego wiersza), znaki właściwe (wszystkie znaki ASCII
z wyjątkiem znaku %) i specyfikatory formatowania. Specyfikatory te mają następu-
jącą składnię:

-?4@? @?//Z@

Oto przykład:

<   20

  

"

 ?A!@#

 #

 *9 5 *#

*-A!- * .#

 *+-- * #

$

Zwróćmy uwagę na wiersz 

 +5

 — nakazuje on kompilatorowi prze-

twarzanie pliku nagłówkowego stdio.h, w którym zawarte są prototypy funkcji 

 

 

. Po uruchomieniu tego prostego programu łatwo przekonamy się, że użycie

znaku odstępu przerwie wprowadzanie pierwszego pola danych.

Alternatywną funkcją pobierania danych jest 



, odczytująca ciąg znaków ze stru-

mienia 



 do momentu napotkania znaku nowego wiersza. W ciągu docelowym znak

nowego wiersza zastąpiony zostaje znakiem 

73..

. Charakterystyczna dla tej funkcji

jest możliwość odczytywania znaków odstępu. Oto nowa wersja powyższego programu
(korzystająca z 



 w miejsce 

 

):

background image

224

Hack Wars. Na tropie hakerów

<   20

<   20

<  20

  

"

 ?^!@#

4#

 ?A!@#

 #

 *+9 5 *#

34L  C  43

  #

345 V        C 43

. ?   @#

34Y 5 _  6 5C5KYZZ43

4UU"

4!#

#

$

34Z  5   C56C 43

  UU#

34L  5 643

 #

34,  _C    43

4!#

34\  5C  543

   #

34,B  543

 *+K S-S- * #

$

Wyprowadzanie danych

Podstawową funkcją wyprowadzania danych jest 

 

. Jest ona podobna do 

 

z  tą  różnicą,  że  zapisuje  dane  do  standardowego  strumienia  wyjściowego 



.

Funkcja  pobiera  listę  pól  danych  wyjściowych,  odpowiednio  stosuje  specyfikatory
formatowania i wyprowadza wynik. Można stosować takie same przekształcenia for-
matujące jak w przypadku funkcji 

 

, jak również dodatkowe znaczniki:

;

wyrównuje dane wyjściowe do lewej, uzupełniając je z prawej strony
znakami odstępu międzywyrazowego (spacji),



wymusza poprzedzanie liczb znakiem.

Nieco  odmienna  jest  także  postać  specyfikatora  szerokości.  Jest  on  rozbudowany  o  ele-
ment określający precyzję:

2 

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

225

Aby  więc  wyświetlić  liczbę  zmiennoprzecinkową  z  dokładnością  do  trzech  miejsc
dziesiętnych, piszemy:

 *-2A*#

Poniżej przedstawiamy listę specjalnych stałych znakowych, które mogą pojawić się
na liście parametrów funkcji 

 

:

+

nowy wiersz (NL),

+

powrót karetki (CR),

+

tabulator,

+

znak cofania (backspace),

+

znak nowej strony,

+

tabulator pionowy,

++

ukośnik odwrotny (backslash),

+U

apostrof,

+*

cudzysłów,

+R

znak zapytania,

+

ciąg w notacji ósemkowej,

+

ciąg w notacji szesnastkowej.

Kolejny program ilustruje, w jaki sposób wyświetlić liczbę całkowitą w postaci dzie-
siętnej,  szesnastkowej  i  ósemkowej.  Liczba 

<

  po  znaku  procentów  (

=

)  w  instrukcji

 

  nakazuje  kompilatorowi  dopełnienie  wyświetlanej  liczby  do  szerokości  co

najmniej czterech cyfr:

349    5  6 43

34     5G 543

<   20

  

"

 #



"

 *+9 5 6 !  _E*#

*- *.#

 *-!` -!`)-!` *#

$

>!#

$

Do funkcji pokrewnych 

 

 należy 

 

, której prototyp ma postać:

 T]Z&44  ?  222@#

Jej  zadaniem  jest  przesyłanie  sformatowanych  danych  wyjściowych  do  określonego
strumienia plikowego.

background image

226

Hack Wars. Na tropie hakerów

Kolejną tego rodzaju funkcją jest 

 

 o prototypie:

 44  ?  222@#

Alternatywą dla 

 

 jest 



, funkcja przesyłająca prosty ciąg do strumienia



. Przesyłany ciąg zostaje automatycznie uzupełniony znakiem nowego wiersza.

Jest to rozwiązanie szybsze od 

 

, jednak jego możliwości są ograniczone.

Bezpo#rednia wymiana danych z konsol*

Do przesyłania i odczytu danych z konsoli (klawiatury i ekranu) można wykorzysty-
wać również bezpośrednie funkcje we-wy. Wyróżnia je litera „c” na początku — od-
powiednikiem 

 

  jest  więc 

 

,  a  odpowiednikiem 



  —  funkcja



.  Różnice  między  funkcjami  bezpośredniej  wymiany  danych  a  funkcjami

standardowymi są następujące.

J

J

J

Nie są wykorzystywane strumienie predefiniowane, nie można więc przekierować
danych przesyłanych funkcjami komunikacji bezpośredniej.

J

J

J

Funkcji bezpośrednich nie można przenosić między różnymi systemami
operacyjnymi (m.in. nie można z nich korzystać w programach dla Windows).

J

J

J

Funkcje bezpośrednie są szybsze niż standardowe.

J

J

J

Nie zapewniają współpracy ze wszystkimi trybami wyświetlania (zwłaszcza
trybami graficznymi VESA).

Wska%niki

Wskaźnik to zmienna, która przechowuje adres elementu danych w pamięci. Deklara-
cja  wskaźnika  jest  podobna  do  deklaracji  zwykłej  zmiennej,  ale  nazwa  poprzedzana
jest znakiem gwiazdki (



), na przykład:

4#

Powyższy wiersz deklaruje zmienną 



 jako wskaźnik do zmiennej typu 



.

Wykorzystanie  wskaźników  dostarcza  szerokich  możliwości,  wymaga  jednak  szcze-
gólnej  uwagi.  Skutki  przypisania  błędnego  adresu  są  najczęściej  nieprzewidywalne.
Oto przykład prostego programu, w którym wykorzystywany jest wskaźnik:

<   20

  

"

 #

 4#

345 V     43

 !!#

.#

 *+M  5 BE-   -2*#

$

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

227

Wartości wskaźników można zwiększać i zmniejszać, dopuszczalne  są  również  inne
operacje matematyczne. Typowym zastosowaniem wskaźników jest zapewnienie dy-
namicznego przydziału pamięci. W trakcie pracy programu często pojawia się potrze-
ba  przejściowego  (tymczasowego)  zaalokowania  bloku  pamięci.  Korzystamy  wów-
czas z funkcji 



:

 "  #  #

Funkcja 



  zwraca  wskaźnik  typu 



,  co  oznacza,  że  może  on  wskazywać

dane  dowolnego  typu  — 





 

  itd.  W  poniższym  przykładzie  alokujemy

pamięć dla tabeli 1000 liczb całkowitych.

<   20

<   20

  

"

 4#

 #

345 V     43

34'   6 !!! C43

34       5  43

34 5 G5  5   43

  !!!4  #

34F  5  ; 43

KYZZ

"

 *+K 8  E6  !!! 5   B

å  *#

 !#

$

349 5 B G 43

 !# !!!#HH

"

4#

HH#

$

349 BE   C     43

 !!!#

34,B  B  43

 !# !!!#HH"

 *+& -   5 BE- *4#

HH#

$

349  8    5  643

#

$

background image

228

Hack Wars. Na tropie hakerów

Wskaźniki  wykorzystuje  się  również  w  odniesieniu  do  tablic  znaków,  czyli  ciągów
(strings). Ponieważ wszystkie ciągi w programach C kończy bajt o wartości 0, korzy-
stając ze wskaźnika, możemy policzyć znaki w ciągu:

<   20

<  20

  

"

4#

  ? !!@#

    #

34]5 5CU  U43

   *' 5  *#

34Y  BE5 C   43

  #

34]5 5C ;  BE43

   !#

34M5  43

4

"

   HH#

HH#

$

34,B 43

 *+X      S- *   #

$

Wymaganą do zaadresowania 1 MB pamięci 20-bitową liczbę dzieli się na dwie warto-
ści: przesunięcie (offset) i segment (każdy segment to 64 kB). Do przechowywania nu-
merów segmentów pamięci komputer IBM PC wykorzystuje tzw. rejestry segmentowe.
Konsekwencją takiego rozwiązania są w języku C trzy dodatkowe słowa kluczowe:

J

J

J

J  

 — wskaźniki „bliskie” mają rozmiar 16 bitów i umożliwiają dostęp

do danych bieżącego segmentu,

J

J

J

J  

 — wskaźniki „dalekie” obejmują wartości określające przesunięcie

i segment, umożliwiając dostęp do dowolnego adresu w pamięci,

J

J

J

J  

 — wskaźniki „ogromne” to odmiana wskaźników dalekich, zapewniająca

możliwość zwiększania i zmniejszania wartości w całym zakresie 1 MB
(kompilator generuje odpowiedni kod modyfikujący wartość przesunięcia).

Nie  będzie  zapewne  zaskakujące  stwierdzenie,  że  przetwarzanie  programu  korzystają-
cego  ze  wskaźników  typu 



  będzie  szybsze  niż  w  przypadku  programu,  w  którym

zastosowano wskaźniki 



. Wskaźniki 



 są oczywiście największym obciążeniem.

Kompilatory  C  wyposażone  są  w  makro  zwracające  adres  odpowiadający  podanym
wartościom numeru segmentu i przesunięcia:

  4J\(T9       #

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

229

Struktury

Język C oferuje technikę grupowania zmiennych pod jedną nazwą, dostarczając w ten
sposób wygodnego sposobu przechowywania powiązanych ze sobą informacji i struktu-
ralizowania ich. Składnia definicji struktury jest następująca:

   

"

     #

     $

2

2

2

$

 #

Używanie zmiennych strukturalnych jest niezbędne przy korzystaniu z plików, w któ-
rych występuje uporządkowanie oparte na rekordach danych. W poniższym przykła-
dzie operować będziemy na prostym pliku z listą adresów. Rozpoczniemy od deklara-
cji  struktury 

 

,  złożonej  z  sześciu  pól: 

 !"#

 

 

"$ "!"

,

!

 i 

   

:

   

"

 ?A!@#

 ?A!@#

 ?A!@#

 5   ?A!@#

 ?W@#

   ? I@#

$

#

Odwołania do pól zmiennej strukturalnej mają postać:

   2  #

Nie  ma  ograniczenia  liczby  pól  struktury,  nie  jest  również  wymagane,  aby  typy  pól
były takie same lub podobne, na przyklad:

   

"

 ?A!@#

 #

4  #

$

#

Jest to poprawna deklaracja struktury obejmująca: pole tablicy znakowej, pole liczby
całkowitej i pole wskaźnika do zmiennej znakowej. Aby przekazać zmienną struktu-
ralną  jako  parametr,  korzystamy  z  jej  adresu  —  poprzedzamy  nazwę  zmiennej  ope-
ratorem 

>

.  Oto  przykładowy  program  wykorzystujący  struktury  w  celu  wykonania

prostych operacji na pliku listy adresów:

background image

230

Hack Wars. Na tropie hakerów

<   20

<   20

<  20

<  20

<  20

< +  20

34 (   43

<  (1I

   

"

 ?A!@#

 ?A!@#

 ?A!@#

 5   ?A!@#

 ?W@#

   ? I@#

$

#

  #

  #

349  543

  DXX([&7  #

  7ZF  #

  X]F9XD'D  #

  TD'DZ4#

  %&'XD'D  #

  J&KY  #

  L9&KXD'D  #

 F&D[7=  #

  7ZF

"

 #

 !# (#HH

 **#

$

  TD'DZ4  

"

 *+:  S-*  #

 !#

$

  L9&KXD'D

"

34F V 5 2a8 G243

34a8  G     _  243

  * 2  *L([X,[/L(D99&KXF(],[]'&#

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

231

  

"

  * 2  *L([X,[/L(7[&D'F(],[]'&#

  

TD'DZ*K 8  E  *#

$

$

  %&'XD'D

"

349    43

7ZF#

 *K *#

   2 #

 *+D *#

   2 #

 *+J *#

   2 #

 *+, 5G   *#

   2 5   #

 *+\   *#

   2 #

 *+K    *#

   2   #

$

  X]F9XD'D

"

34,B    43

  ?I@#

7ZF#

 *K -*  2 #

 *+D -*  2 #

 *+J -*  2 #

 *+, 5G   -*  2 5   #

 *+\   -*  2 #

 *+K    -++*  2   #

 *,B5&K'&[*#

   #

$

  DXX([&7

"

34X ;C      43

 #

  .    #

 

TD'DZ*M    8*#

$

 F&D[7=

"

background image

232

Hack Wars. Na tropie hakerów

  ? !!@#

 #

 *,  VG *#

   #

4  !

  #

34M  5 C  43

 !F&&\(F&'#



"

34M; 5   643

  .    #

0!

"

349 5  43

    2   >KYZZ

  #

    2   >KYZZ

  #

    2   >KYZZ

  #

    2 5     >KYZZ

  #

    2   >KYZZ

  #

    2     >KYZZ

  #

$

$

0!#

 !#

$

  J&KY

"

  5#

  ? !@#



"

7ZF#

 *++ + + ,  56*#

 *+++ + + X 5   *#

 *+++ + + 19  *#

 *+++ + + A,5B*#

 *+++++*#

   #

 5   #

  5

"

 S%&'XD'D#

349  ;C  5 V  _ 43

 !F&&\(&KX#

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

233

DXX([&7#

 #

1SF&D[7=

X]F9XD'D#



"

 *K]&MKDZ&M]LK&>*#

 *,B5&K'&[*#

   #

$

 #

AS #

$

$

 5>A#

$

  

"

7ZF#

L9&KXD'D#

J&KY#

$

Pola bitowe

Język C przewiduje możliwość korzystania w strukturach ze zmiennych o rozmiarze
mniejszym niż 8 bitów. Określa się je mianem pól bitowych, a ich rozmiar może być
dowolny, od 1 bitu wzwyż. Deklaracja pola bitowego wygląda następująco:

 S  #

Przykładem może być deklaracja kilku jednobitowych znaczników stanu:

   

"

  S #

   S #

  S #

   S #

$

#

#

Zmienna 

! !#

 będzie zajmować w pamięci tylko 4 bity, mimo że składa się z 4 pól,

z których każde dostępne jest jako osobne pole struktury.

Union

Kolejnym  ułatwieniem  języka  C,  pozwalającym  zapewnić  optymalne  wykorzystanie
dostępnej pamięci, jest struktura 



, czyli zbiór zmiennych, współużytkujących je-

den adres pamięci. Oznacza to, oczywiście, że w danym momencie dostępna jest tyl-
ko jedna ze zmiennych składowych. Deklaracja 



 ma następującą postać:

background image

234

Hack Wars. Na tropie hakerów

  

"

   #

   #

2

2

2

   #

$#

Wyliczenia

Wyliczenie  (enumeracja)  to  przypisanie  liście  symboli  rosnących  wartości  całkowi-
tych. Wyliczenie deklarujemy:

  " $    %#

Przykładem może być definicja listy kolorów:

 \LZL[b

"

7MD[Kb

K]&:]&F\]

M]&ZLKb

7M&[,LKb

:[DML,b

aDFKLFMD[b

7]&JKLFMD[b

aDFKLK]&:]&F\]

aDFKLM]&ZLKb

aDFKL7M&[,LKb

MLZ'b

:]DZb

$#

Operacje na plikach

W operacjach dostępu  do  plików  język  C  posługuje  się  buforowanymi  strumieniami
plikowymi. Niektóre z platform języka, jak UNIX i DOS, oferują również niebuforo-
wane uchwyty plików.

Strumienie buforowane

Dostęp do strumieni buforowanych realizowany jest za pośrednictwem wskaźnika do
zmiennej typu 

,6.0

. Ten szczególny typ danych zdefiniowany został w nagłówku st-

dio.h. Aby więc zadeklarować wskaźnik do pliku, wprowadzamy:

<   20

T]Z&4 #

Aby  otworzyć  strumień,  używamy  funkcji 

 

.  Pobiera  ona  dwa  parametry:  na-

zwę otwieranego pliku oraz tryb dostępu. Oto lista trybów dostępu.

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

235

Tryb

Opis



otwórz tylko do odczytu (plik musi istnieć),



utwórz do zapisu; zastąp, jeżeli plik o podanej nazwie istnieje,



otwórz do dołączania danych (dopisywania na końcu pliku); utwórz nowy plik,
jeżeli plik o podanej nazwie nie istnieje,

H

otwórz istniejący plik do odczytu i zapisu (plik musi istnieć),

H

utwórz do odczytu i zapisu; zastąp, jeżeli istnieje,

H

otwórz do czytania i dołączania danych; utwórz nowy plik, jeżeli nie istnieje.

Aby określić tryb tekstowy lub binarny, do opisu trybu można dołączyć 



 lub 

 

. W przy-

padku  pominięcia  tego  znacznika  strumień  zostanie  otwarty  w  trybie  określanym
zmienną globalną 

) 

. Odczyt i zapis danych do strumieni plikowych w trybie tek-

stowym wiąże się z konwersją — podczas zapisu znaki CR i LF zamieniane są na pary
CR LF, a przy odczycie pary CR LF ulegają zamianie na pojedynczy znak LF. Tego
rodzaju operacje nie są wykonywane w trybie binarnym.

Jeżeli funkcja 

 

 nie będzie mogła otworzyć pliku, zwróci w miejsce wskaźnika

wartość 

73..

 (zdefiniowaną w stdio.h). Poniższy program utworzy nowy plik dane.txt

i udostępni go do odczytu i zapisu:

<   20

  

"

T]Z&4#

 * 2  **H*#

$

Aby zamknąć strumień, używamy funkcji 

 

, wymagającej podania wskaźnika

do pliku.

 #

Jeżeli podczas zamykania strumienia wystąpi błąd, funkcja 

 

 zwróci wartość

niezerową  (znacznik  EOF  —  End  Of  File).  Do  przesyłania  i  odbierania  danych  ze
strumieni  służą  cztery  podstawowe  funkcje: 

 



 

  i 



.

Funkcja 

 

  odczytuje  pojedynczy  znak  z  określonego  strumienia  wejściowego

(przekształcany do liczby całkowitej):

  T]Z&4#

Jej odwrotnością jest 



, zapisująca pojedynczy znak do określonego strumienia

wyjściowego:

    T]Z&4#

Funkcja 

 

 odczytuje ze strumienia wejściowego ciąg:

4 4   T]Z&4#

background image

236

Hack Wars. Na tropie hakerów

Odczyt  zostaje  przerwany  po  pobraniu 

  

  znaków  lub  znaku  nowego

wiersza (również wstawianego do tablicy). Do odczytanego ciągu 



 dołączany jest koń-

czący znak

73..! % #?  @A*A

. W przypadku wystąpienia błędów

funkcja zwraca 

73..

.

Funkcja 



 zapisuje do strumienia ciąg zakończony znakiem 

73..

 (inaczej 

A*A

):

    4 T]Z&4#

Wszystkie  opisywane  funkcje  zwracają  w  przypadku  błędów  wartość 

0B,

  (zdefinio-

waną  w  stdio.h)  z  wyjątkiem  funkcji 

 

,  która  w  przypadku  wystąpienia  błędu

zwraca 

73..

. Poniższy program tworzy kopię pliku dane.dat, o nazwie dane.old, ilu-

strując zarazem użycie wszystkich czterech funkcji:

<   20

 

"

T]Z&4#

T]Z&4 #

 *  2  ***#

KYZZ

"

 *+K 8  E     2  *#

 !#

$

  * 2  **H*#

 KYZZ

"

 *+K 8  E  2  *#

 !#

$

349  5   5  5 G43

348  &LT43

> 

   #

34M5   43

 #

  #

 !#

$

W kolejnym przykładowym programie używamy funkcji 



 do kopiowania tekstu

ze strumienia 



 (zazwyczaj oznacza to znaki wprowadzane z klawiatury) do no-

wego pliku dane.txt:

<   20

 

"

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

237

T]Z&4#

  ? !!@#

 * 2  **H*#



"

   #

   #

$

4  #

 #

$

Swobodny dostp do danych strumieni

Dostęp  swobodny  do  danych  dostarczanych  za  pośrednictwem  strumieni  zapewnia
funkcja 

 #

 o prototypie:

 T]Z&4     #

Funkcja  zmienia  pozycję  wskaźnika  pliku  skojarzonego  ze  strumieniem  otwartym
wcześniej  przez 

 

.  Wskaźnik  ustawiany  jest  na 

  

  za  (lub  przed

w przypadku  wartości  ujemnej)  pozycją 

 

.  Tą  ostatnią  może  być  początek

pliku,  bieżące  położenie  wskaźnika  lub  koniec  pliku.  Pozycje  te  symbolizują  stałe

/00C)/01

/00C)D32

 i 

/00C)07E

. Udaną operację 

 #

 sygnalizuje zwrócenie warto-

ści 



. Uzupełnieniem 

 #

 jest funkcja 

 

, zwracająca wartość bieżącej pozy-

cji wskaźnika pliku:

   T]Z&4#

Funkcja  zwraca  pozycję  wskaźnika  pliku,  określoną  jako  ilość  bajtów  od  początku
pliku, lub 

;

 w przypadku błędu.

Uchwyty

Uchwyty plików (handles) otwiera funkcja 

 

 o prototypie:

  4    &?  @#

Udaną operację sygnalizuje zwrócenie numeru uchwytu. W pozostałych przypadkach
zwracane jest 

F

. Na wartość 

 

 składają się połączone bitową operacją OR stałe

symboliczne, odpowiadające deklaracjom w pliku fcntl.h. Różnią się one w zalezności
od kompilatora. Do typowych należą:

L(D99&KX

przed każdym zapisem wskaźnik pliku będzie ustawiany na końcu pliku,

L(7[&D'

jeżeli plik nie istnieje, zostanie utworzony,

L('[YK7

obcina istniejący plik do długości 0 bajtów,

L(&)7Z

używane w połączeniu z 

B)D20-1,

L(:]KD[b

otwiera plik w trybie binarnym,

L('&)'

otwiera plik w trybie tekstowym.

background image

238

Hack Wars. Na tropie hakerów

Po przypisaniu uchwytu pliku za pomocą polecenia 

 

 można korzystać z funkcji



 i 

"  

. Prototyp 



 jest następujący:

   %    4   #

Funkcja podejmuje próbę odczytu podanej liczby bajtów i zwraca liczbę bajtów fak-
tycznie pobranych przez uchwyt pliku. Odczytane dane umieszczane są w bloku pa-
mięci  określonym  parametrem 



.  Funkcja 

 

  działa  podobnie,  nie  różni  się

również jej prototyp i sposób generowania wartości zwracanej. Zapisuje ona podaną
ilość  bajtów  z  określonego  wskaźnikiem  bloku  pamięci.  Pliki  otwierane  funkcją

 

 zamykamy funkcją 

 

:

   %  #

Funkcja 

 

 zwraca 



 w przypadku operacji udanej, a 

F

 w przypadku wystąpie-

nia błędów.

Dostęp swobodny zapewnia funkcja 

 #

, bardzo podobna do 

 #

, ale pobie-

rająca jako parametr numer uchwytu, a nie wskaźnik strumienia 

,6.0

. W poniższym

przykładzie wykorzystujemy uchwyt pliku do zapisu danych z 



 (czyli klawiatu-

ry) do nowego pliku o nazwie dane.txt:

<  20

<  20

< +  20

 

"

  #

  ? !!@#

  * 2  *L([X,[/L(7[&D'/L('[YK7F(],[]'&#



"

   #

  .     #

$

4  #

  #

$

Przegl*d funkcji plikowych

Norma  ANSI  definiuje  związane  z  plikami  operacje  we-wy  przy  użyciu  strumieni,
opisując różnorodne funkcje. Prototyp funkcji 

 

 ma postać:

T]Z&4   4   4#

Funkcja podejmuje próbę otwarcia strumienia łączącego z plikiem o podanej nazwie
w  określonym  trybie.  Udana  operacja  kończy  się  zwróceniem  wskaźnika  typu 

,6.0

.

W przypadku niepowodzenia funkcji zwraca 

73..

. Na wcześniejszych stronach przed-

stawiony został opis parametru 



.

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

239

Funkcja 

 

 służy do zamykania strumienia otwartego wcześniejszym wywoła-

niem 

 

:

  T]Z&4#

Udana operacja 

 

 kończy się opróżnieniem wszystkich buforów pliku i zwró-

ceniem wartości 



. W przypadku błędów zwracana jest wartość 

0B,

.

Wiele komputerów korzysta z buforowanego dostępu do plików. Oznacza to, że dane,
zapisywane do strumienia, wstępnie umieszczane są w pamięci, a faktyczny zapis na-
stępuje  dopiero  po  przekroczeniu  pewnej  granicznej  ilości  bajtów.  Jeżeli  w  czasie,
gdy dane nie zostały jeszcze faktycznie zapisane do strumienia, nastąpi awaria zasila-
nia,  dane  zostaną  utracone.  Zabezpiecza  przed  tym  funkcja 



,  wymuszająca

zapisanie wszystkich danych oczekujących:

  T]Z&4#

Jeżeli wywołanie 



 jest udane, związane ze strumieniem bufory zostają opróż-

nione i zwracana jest wartość 



. W przypadku błędów funkcja zwraca wartość 

0B,

.

Kolejną funkcją jest 

 

 zwracająca lokalizację wskaźnika pliku:

   T]Z&4#

Funkcja zwraca przesunięcie wskaźnika pliku w stosunku do początku pliku lub 

F.

w przypadku błędów. Przesunięcie wskaźnika pliku do nowej pozycji umożliwia 

 #

:

 T]Z&4     #

Funkcja  podejmuje  próbę  przesunięcia  wskaźnika  pliku  o 



  bajtów  od  pozycji

 

, określonej jedną ze stałych:

F&&\(F&'

początek pliku,

F&&\(7Y[

bieżąca pozycja wskaźnika pliku,

F&&\(&KX

koniec pliku.

Przesunięcie (



) może być wartością dodatnią (przesuwanie wskaźnika w stronę

końca  pliku)  lub  ujemną  (przesuwanie  wskaźnika  w  stronę  początku  pliku).  Aby
szybko  przenieść  wskaźnik  do  początku  pliku  i  usunąć  wcześniejsze  odwołania  do
błędów, C dostarcza funkcji 

"

:

   T]Z&4#

Funkcja ta działa podobnie jak 

 #&.&/00C)/01

. Jednak 

 #

 usuwa znacz-

nik 

0B,

, a 

" #"

 wszystkie sygnały błędów. Informacje o błędach funk-

cji plikowych można pobrać przy użyciu funkcji 

  

:

  T]Z&4#

Funkcja zwraca wartość niezerową, jeżeli w określonym strumieniu wystąpił błąd. Po
sprawdzeniu  wartości 

  

  należy  zadbać  o  usunięcie  sygnałów  błędów  za  po-

mocą funkcji 

 

:

  T]Z&4#

background image

240

Hack Wars. Na tropie hakerów

Sprawdzenie,  czy  spełniony  jest  warunek  osiągnięcia  końca  pliku,  realizuje  predefi-
niowane makro 

 

:

  T]Z&4#

Makro zwraca wartość niezerową, gdy dla danego strumienia stwierdzono osiągnięcie
końca pliku. W pozostałych przypadkach zwracaną wartością jest 



.

Dostępnych  jest  kilka  funkcji  realizujących  odczyt  danych  ze  strumienia  plikowego.
Pojedyncze znaki można odczytywać funkcją 

 

:

  T]Z&4#

 

 zwraca wartość ASCII pobranego znaku lub znak 

0B,

 w przypadku wystąpie-

nia błędu. Odczyt ciągu danych umożliwia funkcja 

 

, odczytująca ciąg zakoń-

czony znakiem nowego wiersza:

4 '   T]Z&4#

W  wyniku  udanego  wywołania  funkcji  w  zmiennej 



  umieszczany  jest  ciąg  zakoń-

czony  znakiem  nowego  wiersza  lub  zawierający 



  znaków.  Funkcja  zachowuje

kończący  ciąg  znak  nowego  wiersza,  dołączając  do  ciągu 



  bajt 

73..

.  W  przypadku

nieudanego  wywołania  zwracany  jest  wskaźnik  pusty.  Ciągi  zapisujemy  do  strumie-
nia funkcją 



:

    4 T]Z&4#

Funkcja 



  zapisuje  wszystkie  znaki  ciągu 



,  z  wyjątkiem  końcowego  bajtu

73..

, do strumienia 



. Standardowo funkcja zwraca ostatni zapisany znak, a w przy-

padku wystąpienia błędów — 

0B,

. Dostępna jest również funkcja zapisująca do stru-

mienia pojedynczy znak 



:

    T]Z&4#

Funkcja zwraca zapisany znak lub, w przypadku wystąpienia błędów, znak 

0B,

.

Aby odczytać ze strumienia duży blok danych lub rekord, można posłużyć się funkcją

 

:

(    4(  (  T]Z&4#

Funkcja podejmuje próbę odczytu 



 elementów, z których każdy ma długość 

 

,

ze  strumienia  plikowego 



  do  bloku  pamięci  określonego  wskaźnikiem 



.  Aby

ustalić, czy operacja przebiegła bez zakłóceń, korzystamy z funkcji 

  

.

Siostrzaną funkcją 

 

 jest 

"  

:

(      4(  (  T]Z&4#

Funkcja  zapisuje 



  elementów  o  długości 

 

  z  obszaru  pamięci  określonego

wskaźnikiem 



 do strumienia 



.

Funkcja 

 

 umożliwia odczyt danych formatowanych:

 T]Z&4  4? 222@#

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

241

Funkcja  zwraca  liczbę  faktycznie  odczytanych  pól,  a 

0B,

  w  przypadku  końca  pliku.

Poniższy  przykład  ilustruje  użyteczność  funkcji 

 

  podczas  odczytywania  ze

strumienia liczb:

<   20

  

"

T]Z&4#

 #

  #

 #

  #

 #

  ? !!@#

 * 2  **H*#

>

"

 *K 8  E *#

 !#

$

 * 1A`I+*, +**#

 #

 

"

 *:;C   * #

  #

$

 #

 

"

 *:;C 5   * #

  #

$

*- - - - - -*.. .. .  #

 

"

 *:;C     * #

  #

$

 *+T 5G;- - - - - -*    #

$

Jak  łatwo  zauważyć,  zapis  formatowanych  danych  realizuje  funkcja 

 

.  Gdy

pojawia  się  potrzeba  zapisania  położenia  wskaźnika  pliku  i  późniejszego  jego  przy-
wrócenia, można skorzystać z funkcji 

 

 i 

 

. Pierwsza z nich odczy-

tuje bieżącą pozycję wskaźnika pliku:

   T]Z&4 ( 4 #

background image

242

Hack Wars. Na tropie hakerów

Funkcja 

 

 ustawia wskaźniki pliku na określonej pozycji:

   T]Z&4   ( 4 #

Typ 

)

  zdefiniowany  został  w  nagłówku  stdio.h.  Funkcje  te  są  wygodniejsze

w użyciu niż 

 

 i 

 #

.

Z otwartym już strumieniem można skojarzyć nowy plik. Umożliwia to funkcja 

  

:

T]Z&4   4   4T]Z&4#

Funkcja zamyka strumień istniejący i podejmuje próbę jego ponownego otwarcia przy
użyciu  podanej  nazwy  pliku.  Znajduje  to  zastosowanie  przy  przekierowywaniu  stru-
mieni  predefiniowanych 





  i 



  do  pliku  lub  urządzenia.  Przykłado-

wo, gdy pojawia się potrzeba przekierowania wszystkich danych wyjściowych kiero-
wanych do 



 na drukarkę, można użyć polecenia:

 *Z9' *** #

Predefiniowane strumienie we-wy

Wstępnie  zdefiniowane  zostały  trzy  strumienie  we-wy: 





  i 



.  Do-

myślnie 



 i 



 odpowiadają klawiaturze i monitorowi. Na wielu platformach,

w  tym  systemów  DOS  i  UNIX,  dostępna  jest  możliwość  ich  przekierowania.  Stru-
mień 



 domyślnie powiązany jest z monitorem (wyświetlaczem). Praktyka jego

przekierowywania  nie  jest  raczej  stosowana.  Jego  podstawowym  zadaniem  jest  za-
pewnienie możliwości wyświetlania komunikatów błędów, nawet w sytuacji gdy po-
wiązanie standardowego wyjścia (



) zostało zmienione:

 *\     ;6 * #

Funkcje 

 

 i 



 przekazują dane do strumienia 



. Funkcje 

 



  pobierają  dane  ze  strumienia 



.  Przekierowanie  tych  strumieni  zmienia

sposób działania funkcji.

Jako  przykład  plikowych  operacji  we-wy  na  platformie  PC,  korzystających  z  możli-
wości przekierowania strumieni, przedstawimy  prosty  program  przesyłający  do  stru-
mienia 



 zawartość określonego pliku, przedstawioną jako wartości szesnastko-

we. Polecenie w postaci:

( 20 (5B 2

pozwoli zmienić domyślne powiązanie strumienia 



 z monitorem.

<   20

<  20

<  20

<  20

 4?@

"

  #

   ?1!@#

  #

 #

 #

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

243

>1

"

 *+:cdX29 ;  ;S  +* #

  #

$

  ? @L([XLKZb#

  

"

  *+:cdX2K 8  E-+*? @#

  #

$

  *+MD,D['Lef9Z]\Y-++*  ? @#

!#

 

"

34,;  43

  !1!#

349      43

(  .  W#

34! &LT   ;C 43

 

 #

34,  V   43

  *-!W -!I*#

H W#

34,  V   B 5 G  43

 !# W#HH

  *-!1* ?@#

34,  V BDF7]] 5 G  43

 !# W#HH

"

 ?@0A .. ?@ 1^

  *-* ?@#



 *2* #

$

34M _  43

 *+* #

$

34 _ 43

 !#

$

background image

244

Hack Wars. Na tropie hakerów

Ci"gi

Język C należy do najlepiej wyposażonych w funkcje obsługi ciągów pośród uniwer-
salnych  języków  programowania.  Ciąg  to  jednowymiarowa  tablica  znaków  zakoń-
czona  bajtem  zerowym.  Ciągi  można  inicjować  dwoma  sposobami.  Pierwszym  jest
nadanie im stałej wartości w kodzie programu:

 

"

4*F I*#

?@*9   *#

 !#

$

Drugi to utworzenie ciągu w czasie wykonywania programu za pomocą funkcji 

 %

:

4 4    4"#

Funkcja 

 %

 kopiuje ciąg źródłowy do lokalizacji docelowej, na przykład:

<   20

 

"

?I!@#

 *FF  *#

 *+, BEC UU -*#

 !#

$

Język C umożliwia bezpośredni dostęp do każdego bajtu ciągu:

<   20

 

"

?I!@#

 *FF  *#

 *+, BEC UU -*#

34M C  5  CUU43

?!@UU#

 *+, BEC UU -*#

 !#

$

Niektóre kompilatory C wyposażone zostały w funkcje konwersji ciągów do wielkich
i małych liter, nie obejmuje ich jednak norma ANSI. W specyfikacji pojawiają się za
to funkcje 

 

 i 

" 

, zwracające pojedynczy znak ( w postaci wartości 



)

zamieniony na literę wielką lub małą. Łatwo na tej podstawie utworzyć własne funk-
cje konwersji ciągów:

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

245

<   20

    4  

"

4#

  #

4

"

40gN..4 11

4 4#

HH#

$

$

   4  

"

4#

  #

4

"

40WI..4g!

4  4#

HH#

$

$

 

"

?I!@#

 *FF  *#

 *+, BEC UU -*#

  #

 *+, BEC UU -*#

 #

 *+, BEC UU -*#

 !#

$

'  ; 2T 5     C ;

 5C55   EVG ; 2\ 5 6     

56    B A1  5 G8 6    5C

  ;2aB   5  6 5 8 C

C 5 86  2,   hFi   

hAi2, 5      ; 6 

; 2S

4

"

40gN..4 11

4 4#

HH#

background image

246

Hack Wars. Na tropie hakerów

$



4

"

40WI..4g!

4  4#

HH#

$

X      ; 92:22

W przeciwieństwie do innych języków programowania C nie narzuca ograniczenia dłu-
gości ciągu. Jednak w przypadku niektórych procesorów (CPU) pojawia się ogranicze-
nie wielkości bloku pamięci. Oto prosty program odwracający kolejność znaków w ciągu:

<   20

<  20

4 4

"

34L  5 BEGC    5C5 43

34 _ KYZZ43

4 #

4 #

 #

34Y VU U   C 43

 H  #

34M V  C  C 43

 #

34M43

 0

"

 4 #

4 4#

4 #

 #

HH#

$

  #

$

  

"

  ? !!@#

4#

   *' 5 C*#

   #

 *+-*#

$

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

247

strtok()

Funkcja 

 #

  jest  istotną  funkcją  języka  C,  służącą  do  wyłączania  fragmentów

ciągu. Stosuje się ją, gdy poszczególne podciągi rozdzielone są znanymi ograniczni-
kami, na przykład przecinkami:

<   20

<  20

  

"

 ?I!@#

4#

  *7M&[,LKb9LJD[Dj7ML,bklc'bM]&ZLKbK]&:]&F\]*#

   **#



"

 #

  KYZZ**#

$#

$

Program można oprzeć też na pętli 

 

:

<   20

<  20

  

"

 ?I!@#

4#

  *7M&[,LKb9LJD[Dj7ML,bklc'bM]&ZLKbK]&:]&F\]*#

    **##  KYZZ**

"

 #

$#

$

W  pierwszym  wywołaniu  funkcji 

 #

  podajemy  nazwę  zmiennej  ciągu  oraz

ogranicznik.  Funkcja  zwraca  wówczas  wskaźnik  do  początku  pierwszego  podciągu
i zastępuje pierwszy ogranicznik zerem. Kolejne wywołania 

 #

 wykonywane są

w pętli. Pierwszym parametrem jest wówczas 

73..

, a funkcja zwraca kolejne podcią-

gi. Ponieważ dopuszczalne jest podanie listy ograniczników, funkcja 

 #

 może

posłużyć do utworzenia prostego programu zliczającego słowa:

<   20

<   20

<  20

   4?@

"

T]Z&4#

  ?1IW@#

background image

248

Hack Wars. Na tropie hakerów

4#

 #

>1

"

 *+:cdX29 ;  ;S    +* #

 !#

$

34L G   43

 ? @**#

34F V  ;  43

>

"

 *+:cdX2K 8  E VG ;  +* #

 !#

$

34]5 543

!#



"

34L  5  43

   1II#

34F V C; ;C  &LT43

 // 

   #

34M;   43

34F; G865     43

34+   + #S2>R543

    *+ +#S2>R*#



"

HH#

  KYZZ*+ +#S2>R*#

$

$

> ..> #

34L   _ 2:;C R43

 

"

 *+:;C   VG ;  +* #

 #

 !#

$

34L   _  &LT43

34,   6;G43

 *+9-- ;G; +*? @#

 #

$

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

249

Zamiana liczb na ci*gi i ci*gów na liczby

Wszystkie  kompilatory  C  zapewniają  możliwość  konwertowania  liczb  na  ciągi  przy
użyciu takich funkcji jak 

 

. Funkcja ta ma jednak wiele zastosowań, co po-

woduje,  że  jest  rozbudowana  i  mało  wydajna.  Może  ją  zastępować  funkcja 

61B/

,

korzystająca z dwóch parametrów: liczby całkowitej ze znakiem i wskaźnika do ciągu
znakowego. Funkcja kopiuje liczbę do określonego wskaźnikiem miejsca w pamięci.
Podobnie jak 

 

, funkcja 

61B/

 nie sprawdza, czy ciąg docelowy ma wystar-

czającą do przechowania wyniku konwersji długość. Oto przykładowa funkcja, która
kopiuje liczbę 

  

 do ciągu znakowego.

  ]'LF 4 

"

34M_ 6 C 6;  CCG43

  ?g@" !!!!!!!! !!!!!!! !!!!!! !!!!! !!!! !!! !! ! $#

 #

34F V43

!

"

4 HHUU#

34M_ BE 6 C43

!#

$

 !#g#HH

"

0 ?@

"

4 HHU!UH3 ?@#

- ?@#

$

$

4 U+!U#

 _;_     ;   

å    68     592:2

 #

$

9 8  ; ;   5 5 5C6

å 29 85     C C5692:2S

  ]'LF 4 

"

34M_ 6 C 6;  CCG43

  ?g@" !!!!!!!! !!!!!!! !!!!!! !!!!! !!!! !!! !! ! $#

 #

 !#33    C  C

34F V43

!

"

4 HHUU#

HH#

34M_ BE 6 C43

!#

$

background image

250

Hack Wars. Na tropie hakerów

 !#g#HH

"

HH#

4 HHU!UH3 ?@#

- ?@#

$

4 U+!U#

  #33 G V C C

!#

4 UU33 6  C  5B5 

 HH#

4 U!U"33 5 C  

HH#

 HH#

$

4 >U+!U"

4 4 #33C 5 8  C 

 HH#

$

4 U+!U#

 #

$

Język C oferuje dwie funkcje do zamiany ciągów znakowych na liczby zmiennoprze-
cinkowe: 



 i 

 

. Prototyp funkcji 



 ma postać:

   4 #

a prototyp funkcji 

 

:

    4 44 #

Obie funkcje przeglądają ciąg i przeprowadzają konwersję aż do momentu natrafienia
na niezrozumiały znak. Różnica między nimi polega na tym, że 

 

 pobiera do-

datkowy parametr, wskaźnik 



 ustawiany na pierwszy znak ciągu, który nie został

objęty  konwersją.  Znacznie  zwiększa  to  wygodę  sprawdzania  poprawności  wykona-
nia operacji.

Aby zamienić ciąg na wartość całkowitą, można użyć funkcji 



:

    4 #

Należy pamiętać, że funkcja 



 nie zapewnia żadnej kontroli przepełnienia zmien-

nej.  Nie  jest  zdefiniowana  wartość  zwracana  w  takiej  sytuacji.  W  podobny  sposób
działa  funkcja 



,  zwracająca  wartość 



.  Odpowiedniki  z  dodatkowym  para-

metrem noszą nazwy 

 

 i 

 

.

Obsługa tekstu

Człowiek  zapisuje  informacje  jako  pewien  „tekst”,  złożony  ze  słów,  liczb  i  znaków
przestankowych. Słowa złożone są z liter wielkich i małych, odpowiednio do wyma-
gań  gramatyki.  Wszystko  to  sprawia,  że  komputerowe  przetwarzanie  tekstu  nie  jest

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

251

zadaniem  prostym.  Norma  ANSI  definiuje  wiele  funkcji  przetwarzania  ciągów  zna-
kowych,  które  z  natury  rozpoznają  wielkość  liter.  Oznacza  to,  że  litera  „A”  rozpo-
znawana  jest  jako  różna  od  „a”.  Jest  to  pierwsze  zagadnienie,  którego  rozwiązanie
musi  znaleźć  programista  pracujący  nad  programem  przetwarzającym  tekst.  Na  szczę-
ście, zarówno kompilatory Borlanda, jak i Microsoftu wyposażone zostały w funkcje
obsługi ciągów, które nie rozpoznają wielkości liter.

Taką odmianą funkcji 

  

 jest 

  

, a 

  

 — 

  

. Gdy jed-

nak  pojawia  się  kwestia  przenośności  kodu,  niezbędna  jest  zgodność  z  ANSI  C,  co
pociąga za sobą napisanie własnych funkcji.

Poniżej przedstawiamy prostą implementację nierozróżniającej wielkości liter odmia-
ny funkcji 

  

. Tworzy ona kopie ciągów, zamienia je na wielkie litery i wyko-

nuje standardową operację 

  

. Pozwala to określić poszukiwaną wartość prze-

sunięcia i utworzyć wskaźnik do ciągu źródłowego.

4  4 41

"

 ? !!!@#

1? !!!@#

4#

   #

 11#

   #

  1#

   1#



  H #

 KYZZ#

$

Kolejna  funkcja  przegląda  ciąg 



,  wyszukując  słowo  podane  jako 

G

.  Aby  funkcja

zwróciła wartość 

1230

, znalezione musi zostać odrębne słowo, a nie jedynie sekwen-

cja znaków. Wykorzystujemy przygotowaną wcześniej funkcję 

  

.

   (4 41

"

34 BE C5815 ;   43

4#

4m#

  #

 !#

m #



"

34Z  5 C5G1 43

  m1#



"

background image

252

Hack Wars. Na tropie hakerów

34M 43

  #

0 

"

34F V  C43

4 0UDU..4 UU

 !#

$

34K 5 C 43

H 1#

4

"

34F V C43

40UDU..4UU

 !#

$

$

m#

$

..> #

  #

$

Szerokie zastosowanie znajdzie kilka dalszych prostych funkcji znakowych. 

  

obcina ciąg znakowy:

     4  

"

34L U UGC UU43

  

?  @!#

$

  

 usuwa końcowe znaki spacji (odstępu międzywyrazowego) w ciągu:

   4  

"

34  5 _ 43

4#

.  ?    @#

4A1..0  

4!#

$

  

 zmienia długość ciągu:

   4  

"

34M ;  BEC  ;C5C   5C43

 0!

 H  H #



"

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

253

 ! #

 H  H #

$

$

 

 umieszcza jeden ciąg w innym:

   44m

"

34, Cm C 43

  m#

 m m#

$

  

 zastępuje wszystkie wystąpienia pewnego podciągu innym podciągiem:

   4 4 41

"

34M 6 5  C C143

4#

 #



"

 !#

    #



"

34Y _C 43

 !  #

34, C43

 1#

  #

$

$

 #

$

Data i godzina

Język  C  wyposażony  jest  w  funkcję 

 

,  która  odczytuje  zegar  systemowy  kom-

putera i podaje informację o dacie i godzinie w postaci liczby sekund, która upłynęła
od północy 1 stycznia 1970 roku. Wartość ta może zostać zamieniona na czytelny dla
człowieka ciąg znaków za pomocą funkcji 

 

:

<   20

<  20

 

"

34F         243

 (  #

349   6 6  43

  KYZZ#

 *:8C   S-+* . #

$

background image

254

Hack Wars. Na tropie hakerów

Na ciąg zwracany przez 

 

 składa się siedem pól:

J

J

J

dzień tygodnia,

J

J

J

miesiąc roku,

J

J

J

dzień miesiąca,

J

J

J

godzina,

J

J

J

minuty,

J

J

J

sekundy,

J

J

J

rok.

Uzupełnieniem jest znak nowego wiersza i końcowe 0. Ponieważ pola mają stałą sze-
rokość,  ciąg  zwracany  przez 

 

  idealnie  nadaje  się  do  operacji  wymagających

wyodrębnienia  elementów  daty  lub  godziny.  W  poniższym  programie  definiujemy
strukturę 

!

  oraz  funkcję 

  !) ! 

,  której  zadaniem  jest  wypełnienie

struktury treścią pól ciągu 

 

:

<   20

<  20

<  20

    

"

 (#34J 43

 ( #34% 43

 (#34F  43

$#

   (     4 

"

 (  #

 ?1W@#

4 #

349   6 6  43

  KYZZ#

349    6 6  C 43

   . #

34L  5    43

 ? g@!#

 . ?  @#

349 5C  5     43

 *-1 S-1 S-1 *. 0( . 0(. 0(#

$

 

"

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

255

     #

 ( . #

 *+a  -!1 S-!1 S-!1 *. 2( . 2(. 2(#

$

Norma  ANSI  przewidziała  również  funkcję  konwertującą  wartość  zwracaną  przez
funkcję 

 

 do postaci struktury. Przedstawiony poniżej przykład zawiera deklara-

cję struktury 



 z nagłówka 

 +

:

<   20

<  20

 

"

 (  #

    4 #

349   43

  KYZZ#

34M_ BE    6 43

   . #

 *+a  -!1 S-!1 S-!1 * 0 (  0 ( 0 (#

 !#

$

Struktura 



 (zawarta w pliku 

  

) ma następującą postać:

    

"

  (#

  (#

  ( #

  ( #

  ( #

  (#

  ( #

  ( #

  (  #

$#

'    8 E6BC  5     5 5 8

å    ;G 2, 5 5  B  ;C 2

å J 85C  E 5    G ;G6 

å BE  6I 92:2

Liczniki czasu

Programy często korzystają z możliwości pobrania daty i czasu z nieulotnej pamięci
RAM komputera. Norma ANSI przewiduje kilka różnych funkcji, które mogą zostać
do tego celu wykorzystane. Pierwszą jest funkcja 

 

, zwracająca liczbę sekund od

1 stycznia 1970 roku:

(   ( 4 #

background image

256

Hack Wars. Na tropie hakerów

Funkcja wypełnia przekazaną jej jako parametr zmienną typu 

 )

 



jeśli nie jest to

73..

, zwracając tę samą wartość również jako wartość wyjściową. Można więc wywo-

ływać funkcję 

 

 z parametrem 

73..

 i korzystać z wartości zwracanej:

<  20

  

"

 (  #

  KYZZ#

$

Funkcja 

 

  zamienia  strukturę 



  na  26-znakowy  ciąg  (przedstawiony  przy

opisie funkcji 

 

):

4       4 #

Funkcja 

 

 zamienia wartość czasu (zwracaną przez 

 

) na 26-znakowy ciąg:

<   20

<  20

<  20

  

"

 (  #

  ?A!@#

  KYZZ#

    . #

$

Kolejna  funkcja, 

 

,  zwraca,  liczoną  w  sekundach,  różnicę  między  dwoma

wartościami typu 

 )

. Służy więc do wyznaczania ilości czasu, jaki upłynął mię-

dzy dwoma zdarzeniami, czasu wykonywania funkcji lub generowania przerw w pra-
cy programu, na przykład:

<   20

<  20

  X&ZDb  

"

 (  #

  KYZZ#

 KYZZ H 

#

$

  

"

 *+[   222I  *#

X&ZDbI#

 *+L _ 2*#

$

background image

Rozdział 6. 

¨

¨

¨

¨ Podstawy programowania dla hakerów

257

Funkcja 

 

 zamienia lokalną wartość czasu 

 )

 na wartość GMT o postaci

struktury 



. Działanie tej funkcji zależy od ustawienia globalnej zmiennej strefy cza-

sowej. Struktura 



 została wstępnie zdefiniowana w nagłówku 

 +

. Przedstawili-

śmy ją kilka stron wcześniej.

    

"

  (#

  (#

  ( #

  ( #

  ( #

  (#

  ( #

  ( #

  (  #

$#

Element struktury 

 )  %

 przechowuje dzień miesiąca (od 1 do 31), a 

 )" %

 — dzień

tygodnia  (gdzie  niedzieli  odpowiada  0).  Czas  jest  mierzony  od  1900  roku.  Wartość

 )

 to znacznik, który informuje o tym, czy stosowany jest czas letni. Stosowa-

ne  nazwy  struktury  i  jej  elementów  mogą  różnić  się  w  zależności  od  kompilatora,
jednak sama struktura zasadniczo pozostaje niezmieniona.

Funkcja 

# 

 zamienia strukturę 



 na wartość 

 )

, uzupełniając wartości pól

 )" %

 i 

 )% %

:

(      4#

W kolejnym przykładzie umożliwiamy wprowadzanie daty i używamy funkcji 

# 

do  ustalenia  dnia  tygodnia.  Należy  pamiętać,  że  funkcje  związane  z  czasem  rozpo-
znają wyłącznie daty późniejsze niż 1 stycznia 1970:

<   20

<  20

<  20

  

"

        #

  #

  ? !!@#

4#

4 ?@

"* **  ;** **B ** **C ** **

å   gN!*$#



"

 !#

 *+,  V  6  33*#

   g #

    *3*#

>KYZZ

    2 (  #



   #

background image

258

Hack Wars. Na tropie hakerów

  KYZZ*3*#

>KYZZ

    2 (  #



   #

  KYZZ*3*#

>KYZZ

    2 ( #



   #

  #

$

> #

    2 ( !#

    2 (!#

    2 ( #

    2 (   #

34'   _  43

 .     

    2 ( N#

 *' _ -+* ?    2 ( @#

$

Funkcja 

# 

 zapewnia również wprowadzenie odpowiednich poprawek dla warto-

ści przekraczających swój dopuszczalny zakres. Można to wykorzystać do ustalenia do-
kładnej daty, odległej o 



 dni:

<   20

<  20

<  20

  

"

    4    #

 (  5#

 5 KYZZ#

      . 5#

    0 ( H !#

     #

    0 (0gg



    0 (- !!#

   5CB   ;6       5

å  ;C;    g!!5  ; 8 gg 92:2

 *M 6E  6 -!1 3-!1 3-!1 +*    0 (     0 ( H

å      0 (#

$