SlideShare a Scribd company logo
1 of 68
Download to read offline
Akademia Górniczo­Hutnicza
im. Stanisława Staszica w Krakowie
Wydział Elektrotechniki, Automatyki, Informatyki i Elektroniki
KATEDRA AUTOMATYKI
 
PRACA DYPLOMOWA INŻYNIERSKA
Dariusz Jania
Implementacja wybranych elementów rozproszonego
systemu operacyjnego – moduł zarządzania procesami 
w architekturze WebSerwis
PROMOTOR :
dr inż. Grzegorz Rogus
Kraków 2012
2
OŚWIADCZENIE AUTORA PRACY
OŚWIADCZAM ,  ŚWIADOMY ODPOWIEDZIALNOŚCI KARNEJ ZA POŚWIAD ­
CZENIE NIEPRAWDY, ŻE NINIEJSZĄ PRACĘ DYPLOMOWĄ WYKONAŁEM
OSOBIŚCIE I SAMODZIELNIE, I NIE KORZYSTAŁEM ZE ZRÓDEŁ INNYCH
NIŻ WYMIENIONE W PRACY.
…...............................................    
                   PODPIS                     
AGH
University of Science and Technology in Krakow
Faculty of Electrical Engineering, Automatics, Computer Science and Electronics
DEPARTMENT OF AUTOMATICS
 
DIPLOM THESIS
Dariusz Jania
Implementation of selected elements of a distributed 
operating system – process managment module in the 
architecture WebSerwis
SUPERVISOR :
Grzegorz Rogus Ph. D
Kraków 2012
4
5
Spis Tre ciś
1 Wprowadzenie.................................................................................................................................................7
1.1 O systemie...................................................................................................................................................7
1.2 Moduł wykonawczy....................................................................................................................................8
1.3 Zalety i wady rozproszonego modułu wykonawczego.................................................................................9
2. Zagadnienia teorytyczne..............................................................................................................................10
2.1 Wsteczna inżynieria oprogramowania.......................................................................................................10
2.1.1 Analiza behawioralna......................................................................................................................10
2.1.2 Deasemblacja....................................................................................................................................19
2.1.3 Dekompilacja...................................................................................................................................21
2.2 Procesy w systemie operacyjnym...............................................................................................................21
2.2.1 Procesy i biblioteki..........................................................................................................................22
2.2.2 Plik wykonywalny..........................................................................................................................23
2.2.3 Wywołania systemowe...................................................................................................................26
2.3 Kontrolowanie wywołań systemowych......................................................................................................28
2.3.1 Proxy DLL........................................................................................................................................28
2.3.2 Nadpisanie tablicy importów lub miejscowe nadpisanie funkcji.............................................29
2.3.3 Wstrzyknięcie DLL przy pomocy systemowego hookowania...................................................29
2.3.4 Wstrzyknięcie DLL przy pomocy rejestru...................................................................................30
2.3.5 Wstrzyknięcie DLL przy pomocy zdalnego wątku....................................................................30
2.4 Javascript i HTML5..................................................................................................................................31
2.4.1 JavaScript..........................................................................................................................................31
2.4.2 XML..................................................................................................................................................31
2.4.3 Ajax...................................................................................................................................................32
2.4.4 XSLT i XPath....................................................................................................................................36
2.4.5 Comet...............................................................................................................................................37
2.4.6 Websocket........................................................................................................................................38
2.5 Usługi sieciowe..........................................................................................................................................39
2.5.1 HTTP................................................................................................................................................39
2.5.2 Uwierzytelnianie w protokole HTTP............................................................................................41
2.5.3 SOAP................................................................................................................................................42
3 Architektura modułu.....................................................................................................................................43
3.1 Jednostka zarządzająca..............................................................................................................................44
3.2 Jednostka wykonawcza..............................................................................................................................44
4 Moduł wykonawczy z perspektywy użytkownika..................................................................................45
4.1 Konsola użytkownika na lokalnym komputerze.........................................................................................47
4.2 Konsola użytkownika w przeglądarce internetowej...................................................................................47
5 Implementacja jednostki wykonawczej.....................................................................................................48
5.1 Implementacja w systemach UNIX­like.....................................................................................................48
5.2 Implementacja w systemach Windows.......................................................................................................50
5.3 Biblioteka systemowa.................................................................................................................................50
5.4 Proces Zarządcy........................................................................................................................................51
6. Prototypowa implementacja modułu, realizującego przykładowy scenariusz użycia.....................53
6
6.1 Zaimplementowany scenariusz użycia i przykładowe rezultaty działania.................................................53
6.2 Techniczne szczegóły implementacji..........................................................................................................54
6.3 API jednostek............................................................................................................................................55
6.4 Dalszy rozwój implementacji....................................................................................................................56
7 Możliwości dalszego rozwoju modułu......................................................................................................56
7.1 Skalowalność..............................................................................................................................................57
7.2 Graficzny interfejs użytkownika................................................................................................................57
7.3 Rozproszenie wykonywania procesów, moduły jądra.................................................................................57
7.4 Sieci wirtualne...........................................................................................................................................57
7.5 Maszyny wirtualne...................................................................................................................................57
7.6 Rozproszone algorytmy zarządzające.........................................................................................................57
7.7 Poufność danych oraz bezpieczeństwo........................................................................................................57
7.8 Kontrola zasobów sprzętowych oraz monitorowanie sprawności...............................................................58
7.9 Zależności w systemach ze współdzielonymi bilbiotekami.........................................................................58
8 Podsumowanie...............................................................................................................................................58
9 Literatura.........................................................................................................................................................58
Załączniki...........................................................................................................................................................61
A Zawartość płyty dołączonej do pracy...........................................................................................................62
B Kod programu testującego funkcje śledzące w systemie Linux.....................................................................62
C Kod programu zapisującego dane do pliku...................................................................................................63
D Kod programu pośredniczącego w zapisie danych do pliku..........................................................................64
E Kod programu wykorzystującego bibliotekę do zapisu danych do pliku.......................................................66
F Kod programu obsługującego wywołania biblioteki......................................................................................67
7
1 Wprowadzenie
Moduł zarządzania procesami, opisany w niniejszej pracy, jest częścią eksperymentalnego 
rozproszonego systemu operacyjnego projektowanego i realizowanego przez pracowników Akademii 
Górniczo­Hutniczej   w   Krakowie.   System   ten   składa   się   z   kilku   modułów   realizowanych   jako 
samodzielne usługi  sieciowe. Usługi te działają wewnątrz istniejącego systemu operacyjnego  jak 
Linux, Windows czy FreeBSD, przy czym, mogą się one znajdować w jednym systemie operacyjnym 
bądź być rozproszone na kilka komputerów.  Robocza nazwa tego modułu na potrzeby tej pracy to 
„moduł wykonawczy”.
Realizacja tej pracy składa się z kilku etapów:
1. Zdefiniowanie   wymagań   funkcjonalnych   modułu   wykonawczego.   Poświęcone   są   temu 
rozdziały 1.1 do 1.3.
2. Analiza technologii przydatnych do realizacji modułu wykonawczego. Poświęcony jest temu 
rozdział 2.
3. Podział   realizacji   funkcji   systemu   na   poszczególne   komponenty   modułu   wykonawczego, 
opracowanie   architektury   tych   komponentów   oraz   sposobów   komunikacji   między   nimi. 
Poświęcone jest temu rozdział 3. oraz rozdział 4.
4. Opracowanie sposobów implementacji modułów, zbadanie realizowalności tych sposobów 
oraz   ich   wpływu   na   wydajność   procesów   użytkownika   wykonywanych   przez   system. 
Poświęcony jest temu rozdział 5. zaś programy testujące zostały umieszczone w załącznikach.
5. Implementacja prototypu modułu wykonawczego z perspektywy przykładowego scenariusza 
użycia. Poświęcony jest temu rozdział 6.
6. Dyskusja zagadnień, które nie zostały uwzględnione podczas opracowywania architektury 
modułu, a które mogą posłużyć do jego dalszego rozwoju. Poświęcony jest temu rozdział 7.
7. Podsumowanie i wnioski z realizacji tej pracy. Poświęcony jest temu rozdział 8.
1.1 O systemie
Podstawowym zadaniem modułu zarządznia procesami jest uruchamianie oraz nadzorowanie 
procesów uruchamianych przez użytkowników w systemie. 
Rys. 1 Uruchamianie programów z połączonymi potokami.
Rozproszony System Konsola sterująca
Użytkownik
Program1 | program
Zainicjuj program1 i program2,
Przekieruj standardowe wej/wyj,
Uruchom programy
8
Dba on także, żeby użytkownik mógł wprowadzić dane dla procesu oraz odczytać dane zwracane 
przez działający proces, innymi słowy, dysponuje standardowym wejściem oraz wyjściem procesów. 
Dostęp do systemu oraz sterowanie odbywa się przez sprawdzony mechanizm, znany z sys­
temów UNIX­like, czyli tekstową konsolę. Aby obsługa systemu była intuicyjna dla użytkowników, 
konsola powinna pozwalać na konstrukcje znane z jej odpowiedników z tradycyjnych systemów czyli 
łączenie potoków:
Program1 | program2
czy przekierowanie standardowego wejścia/wyjścia programu do pliku:
program1 > plik.txt
Dodatkowo, lokalne pliki i polecenia mogą być zaznaczane przez specjalny znak np. wykrzyknik 
znany   z   konsolowego   klienta   FTP,   co   pozwalałoby   na   współpracę   programów   znajdujących   się 
lokalnie na komputerze użytkownika z tymi znajdującymi się w systemie rozproszonym. Przykładowe 
wykonanie dwóch programów w systemie rozproszonym i przekierowanie wyniku ich działania na 
standardowe wejście programu trzeciego działającego na lokalnym komputerze użytkownika:
Program1 | Program2 | !Program_lokalny
Inny przykład, w którym treść zdalnego pliku jest wczytywana na standardowe wejście programu, zaś 
standardowe wyjście jest przekierowane do pliku w lokalnym komputerze użytkownika:
Program < plik.txt > !plik_lokalny.txt
Choć z punktu widzenia użytkownika, system rozproszony może mieć powłokę użytkownika 
bardzo podobną do znanych mu powłok, to wewnętrzna implementacja takiej powłoki ukrywa wiele 
szczegółów. Więcej informacji na temat implementacji powłoki oraz zadań przed nią stawianych 
zostanie omówione w dalszych rozdziałach.
1.2 Modu wykonawczył
Jest on zrealizowany jako niezależna usługa sieciowa działająca wewnątrz istniejącego systemu 
operacyjnego, wobec czego może on korzystać z istniejącego API systemowego. Dzięki temu, że jego 
elementy składowe są realizowane jako procesy w systemie operacyjnym, to nie musi się on zajmować 
niskopoziomową funkcjonalnością zarządzania procesami. Zamiast planować sprawiedliwy przydział 
procesorów  dla procesów, zajmuje się on możliwie transparentnym rozproszeniem uruchamianych 
procesów na kilka systemów operacyjnych znajdujących się na komputerach umiejscowionych w do­
wolnym  miejscu na  świecie.  Realizuje on dodatkową warstwę abstrakcji rozciągając zarządzanie 
procesami do wyboru komputera i systemu, w którym procesy mają być uruchamiane.
Rys. 2 Dodatkowa warstwa abstrakcji zapewniona przez moduł zarządzania procesami.
Proces użytkownika
Warstwa zarządzająca
System operacyjny
Proces użytkownika
9
Moduł ten komunikuje się z innymi częściami systemu wykorzystując sieć internetową, przy 
czym, kilka modułów może znajdować się w tym samym systemie operacyjnym, w sieci lokalnej LAN 
a   także   w   WAN   jednocześnie.   Jego   architektura   została   opracowana   z   naciskiem   na   prostotę 
implementacji   oraz   minimalną   ilością   czynności   potrzebnych   do   uruchomienia   pojedynczych 
komponentów. Implementacja została przedstawiona z punktu widzenia systemów Windows oraz 
UNIX­like.
1.3 Zalety i wady rozproszonego modu u wykonawczegoł
Dodatkowa   warstwa   zarządzająca   wprowadza   dodatkowe   opóźnienia   w   wywołaniach 
systemowych,   co   w   przypadku   programów,   które   często   je   wywołują,   spowoduje   znaczne 
spowolnienie działania. Dodatkowo pojedyncze składniki systemu mogą się znajdować w różnych 
miejscach na świecie co powoduje wprowadzenie opóźnień sieciowych, które mogą się wahać od 
pojedynczych milisekund do kilkuset milisekund, które dodatkowo spowalniają komunikację między 
procesami oraz modułem dyskowym. Jaki jest więc zysk z tej rozproszonej architektury? Po pierwsze 
zwiększa się niezawodność. Awaria jednego systemu powoduje przerwanie wykonania procesów w 
nim znajdujących się, lecz procesy znajdujące się w innych systemach nadal są wykonywane bez 
przeszkód. 
Następną zaletą jest transparentne bilansowanie obciążenia na kilka jednostek – programista 
może napisać program, który przy wykonaniu korzysta z wielu procesów potomnych np. do obliczeń, 
gdzie   każdy   z   nich   może   być   wykonywany   na   innym   komputerze.   Pozwala   to   osiągnąć   moc 
obliczeniową niedostępną dla pojedynczej jednostki. Przy czym taki rozproszony program nie różni 
się   wiele   od   wieloprocesowego   programu   napisanego   dla   pojedynczego   systemu   operacyjnego. 
Ułatwia to debugowanie programu, gdyż pozwala korzystać z technik i narzędzi dla standardowej 
komunikacji międzyprocesowej.
Warto   także   wspomnieć,   że   rozproszona   architektura   pozwala   na   współpracę   procesów 
wykonywanych na różnych systemach operacyjnych. Z punktu widzenia programisty komunikacja z 
innymi procesami wygląda tak samo, niezależnie od tego czy wykonują się one w tym samym 
systemie operacyjnym, w tych samych rodzajach systemu operacyjnego, lecz znajdujących się w 
różnych miejscach na świecie, czy wręcz w różnych typach systemu operacyjnego. Stosując potoki, 
znane chociażby z systemów UNIX­like, użytkownik może na przykład napisać w swojej konsoli 
sterującej komendę:
program1 | program2 | program3
Gdzie: 
• program1 – program java wykonywany w 32­bitowym systemie Macintosh
• program2 – binarny program wykonywany w 64­bitowym systemie Linux
• program3 – program platformy .NET wykonywany w 64­bitowym systemie Windows
Efekt   wykonania   tego   polecenia   użytkownik   może   zobaczyć   w   konsoli   w   swoim   systemie 
operacyjnym,   bądź   w   przeglądarce,   gdyż   opracowywana   konsola   sterująca   może   być   także 
zaimplementowana przy użyciu języka JavaScript.
10
2. Zagadnienia teorytyczne
Projekt ten jest bardzo wymagający pod względem znajomości rozwiązań technicznych oraz 
technik   programistycznych,   stosowanych   we   współczesnych   systemach   operacyjnych.   Dodatkowo 
wykorzystane   zostały   techniki   wstecznej   analizy   oprogramowania   oraz   zaawansowane   techniki 
programistyczne języka JavaScript, wśród których znajdują się takie, które są obsługiwane przez 
przeglądarki   internetowe   dopiero   od   kilku   lat.   Z   tego   powodu   w   rozdziale   tym   opracowano 
najważniejsze   technologie,   użyte   bezpośrednio   do   implementacji   modułu   zarządzającego   lub 
pomocne do zrozumienia jego działania. 
2.1 Wsteczna in ynieria oprogramowaniaż
W   pracy  tej  kilkukrotnie  korzystano  z   możliwości   i  narzędzi   jakimi  dysponuje   wsteczna 
inżynieria oprogramowania (reverse engineering). Nie jest to popularna dziedzina informatyki, dlatego 
w   tym   rozdziale   krótko   opiszę   czym   się   zajmuje   wsteczna   inżynieria   oprogramowania   oraz 
przedstawię kilka narzędzi pomocnych przy analizowaniu programów.
Ze wsteczną inżynierią oprogramowania mamy do czynienia za każdym razem, gdy analizie 
poddawany zostaje program. Może mieć to miejsce, gdy programista powraca do rozwoju programu, 
którym się nie zajmował już od dłuższego czasu, bądź gdy analizowane jest działanie złośliwego 
programu, wysyłającego spam do użytkowników i replikującego się w ich systemach. Wsteczna 
inżynieria przydaje się w wielu sytuacjach, w których nie ma dostępu do kodu źródłowego programu, 
a istnieje potrzeba zmiany jego zachowania. Jest ona intensywnie wykorzystywana przez twórców 
wirusów do znajdywania błędów w systemach operacyjnych, a także przez autorów oprogramowania 
antywirusowego. 
Niejednokrotnie analiza wsteczna oprogramowania jest zabroniona prawnie, innym razem 
programistą   może   zależeć   na   utrudnieniu   analizy   oprogramowania.   Sytuacja   ta   ma   miejsce   w 
przypadku, przywołanego już przykładu, twórców wirusów oraz oprogramowania antywirusowego, 
gdzie jedna grupa chce ukryć szczegóły działania ich programów przed drugą. Dlatego, w myśl 
anegdoty o ulepszaniu miecza i tarczy, powstało wiele sposobów zapobiegania wstecznej inżynierii 
oraz   omijania   tych   zabezpieczeń.   Pełne   omówienie   sposobów   analizy   oprogramowania   oraz   ich 
zabezpieczania przed analizą oraz omijanie tych zabezpieczeń nie jest istotne w tej pracy, więc 
zostanie pominięte.
2.1.1 Analiza behawioralna
Do analizy behawioralnej, czyli analizy zachowania programu, kwalifikują się wszystkie te 
narzędzia i sposoby, które monitorują akcje podejmowane przez działające programy [Eil00][Kas00]. 
W zależności od tego, jakie zachowanie programu jest istotne, takie zostają użyte narzędzia do jego 
monitorowania. 
Gdy w grę wchodzi krokowe wykonanie programu, analiza pamięci procesu oraz argumentów 
wywoływanych   funkcji,   wówczas   użyty   zostaje   debugger.   Debugger   jest   programem,   który   jest 
głównie wykorzystywany przez programistów języków wysokiego poziomu do odnalezienia błędów 
w ich programach. Może być on jednak z powodzeniem stosowany do analizy binarnego programu, 
zwłaszcza   gdy   zawiera   wbudowany   deasembler   jak   ollydbg.   Ollydbg   jest   debuggerem   systemu 
Windows z wbudowanym deasembler oraz graficznym interfejsem użytkownika. Pozwala on na 
11
edycję asemblerowego kodu programu w locie i dlatego jest często wykorzystywany przez   osoby 
łamiące zabezpieczenia autorskie w programach – popularnie określane jako cracki.
#include "stdio.h"
void sayHello(int times, const char * string)
{
int i;
for(i = 0; i < times; ++i)
printf("%sn", string);
}
int main(int argc, char **argv)
{
sayHello(5, "Hello!");
return 0;
}
Przykład 1 Program języka C, wypisujący pięciokrotnie „Hello!”, użyty do dalszych demonstracji.
Rys. 3 Okno programu ollydbg.
Na rys. 3 zaprezentowano zrzut ekranu okna ollydbg 1.10, który został uruchomiony z pro­
gramem pokazanym w przykładzie 1.  W lewym, górnym fragmencie okna znajduje się zdeasemblo­
wany kod programu. Break point został ustawiony na początku funkcji main i jest zaznaczony czerwo­
nym kolorem na offsecie 0x004013D7. Program został wykonany krokowo od tego momentu i został 
12
zatrzymany tuż przed wywołaniem funkcji  sayHello(), czyli na offsecie 0x004013F4. Program został 
skompilowany   bez   symboli   debugujących,   więc   nazwa   funkcji  sayHello()  została   bezpowrotnie 
utracona i zastąpiona nazwą roboczą  hello.004013B0, gdzie   0x004013B0 jest adresem w pamięci 
procesu, w którym znajduje się owa funkcja. W prawym, górnym fragmencie okna znajduje się 
zawartość rejestrów procesora. W prawym, dolnym rogu znajduje się zawartość stosu programu. 
Szczyt stosu ma adres 0x22FF60 i jest zaznaczony czarnym kolorem. Można tam dostrzec argumenty 
funkcji  sayHello()  umieszczone zgodnie z calling conventions języka C, czyli liczbę 5 oraz łańcuch 
znakowy, znajdujący się pod adresem 0x00403064. Zawartość tego kawałka pamięci można zobaczyć 
w lewej, dolnej części ekranu, gdzie można się przekonać, że ten łańcuch znakowy to „Hello!”.
Rys. 4 Właściwości uruchomionego programu Opera.
Inną metodą monitorowania działania programu jest analizowanie aktywności sieciowej oraz 
operacji dyskowych. Rys. 4 zawiera informacje wyświetlane przez program Process Explorer, dostępny 
na licencji freeware,  w systemie Windows na temat uruchomionej przeglądarki internetowej Opera. 
Po lewej znajdują się otwarte połączenia internetowe, zaś po prawej czas spędzony w trybie kernel 
oraz user, a także informacje o używanej pamięci i operacjach dyskowych. W chwili pisania tej pracy 
adresy 74.125.230.90 i  74.125.230.92 były adresami serwerów www google, zaś 149.156.96.2 adresem 
www, na której znajduje się oficjalna strona AGH. Process Explorer potrafi znacznie więcej np. potrafi 
wyświetlić listę załadowanych bibliotek dll czy łańcuchy znakowe znajdujące się w pamięci procesu.
Oprócz   ogólnych   informacji   o   procesie,   można   monitorować   także   konkretne   wywołania 
systemowe czy funkcje z określonych bibliotek. Na rys. 6 można zobaczyć jak dużo operacji wykonuje 
tak prosty program, jak pokazany w przykładzie 1, który wypisuje na konsolę systemową pięciokro­
tnie łańcuch znakowy w systemie Windows. Do monitorowania wywołań funkcji i ich argumentów z 
określonych   bibliotek   w   systemie   Windows   można   użyć   programu  WinAPIOverride32  [Wio32], 
13
dostępnego na licencji open source. Na rys. 5 został on użyty do przechwycenia wywołania funkcji 
WriteFile()  i jej argumentów. Innym programem do monitorowania wywołań funkcji w systemach 
Windows jest program API Monitor dostępny na licencji freeware.
Do podglądu ogólnych informacji zapisanych w pliku wykonywalnym w systemach Windows 
istnieje szereg programów. Jednym z nich jest Peview, którego okno z otwartym, przykładowym 
plikiem hello.exe można zobaczyć na rys. 8.
Użytkownicy   systemów   UNIX­like   także   mają   do   dyspozycji   narzędzia   pomocne   przy 
wstecznej analizie programów. Debuggerem, który jest najczęściej używany w tych systemach, jest 
GDB, który jest częścią narzędzi GNU. Choć  GDB  jest interaktywnym programem konsolowym to 
istnieje duża  ilość graficznych  frontendów  do  niego.  Oprócz  programu  Nemiver,  bazującego  na 
bibliotekach GNOME, oraz kgdb, opartego na bibliotekach KDE, bardzo popularnym frontendem do 
GDB  jest  ddd,   którego   okno   zostało   zaprezentowane   na   rys.   7.   Podobnie   jak   w   przykładzie   z 
debuggerem OllyDbg, zaprezentowano wykonanie programu z przykładu 1. Wykonywanie programu 
zostało zatrzymane przez wywołaniem funkcji sayHello(). W ramce „X”, z czerwonym tle znajduje się 
zrzut pamięci wskazującej przez rejestr esp procesora, czyli szczyt ramki stosu. Zauważyć można na 
nim argumenty funkcji sayHello(), czyli liczbę pięć oraz adres łańcucha znakowego. Adres łańcucha 
znakowego zawiera napis „Hello!”, co zostało pokazane w ramce „Print” z zielonym tłem.
Rys. 5 Przechwycone wywołania funkcji WriteFile() przez program WinAPIOverride32.
14
Rys. 6 Efekt działania programu Process Monitor monitorującego wykonanie hello.exe.
Rys. 7 Okno programu ddd – graficznego frontendu debuggera GDB.
15
Rys. 8 Okno programu PEview.
Do analizy wywołań systemowych programów w systemach UNIX­like można zastosować 
konsolowy program strace. Potrafi on zarówno wyświetlić podsumowanie zawierające listę wywołań 
systemowych oraz czas ich wykonywania jak i dokładną listę wywoływanych funkcji systemowych. 
Podsumowanie wyświetlane przez  strace  w systemie kubuntu x86 dla programu z przykładu 1:
user@user:~$ strace -c ./hello
Hello!
Hello!
Hello!
Hello!
Hello!
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
-nan 0.000000 0 1 read
-nan 0.000000 0 5 write
-nan 0.000000 0 2 open
-nan 0.000000 0 2 close
-nan 0.000000 0 1 execve
-nan 0.000000 0 3 3 access
-nan 0.000000 0 1 brk
-nan 0.000000 0 1 munmap
-nan 0.000000 0 3 mprotect
-nan 0.000000 0 7 mmap2
-nan 0.000000 0 3 fstat64
-nan 0.000000 0 1 set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 30 3 total
Dokładna lista wywołań systemowych, ich argumentów oraz wartości zwracanych:
user@user:~$ strace ./hello
execve("./hello", ["./hello"], [/* 42 vars */]) = 0
brk(0) = 0x9fea000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78f0000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=78669, ...}) = 0
mmap2(NULL, 78669, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78dc000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/libc.so.6", O_RDONLY) = 3
16
read(3, "177ELF11100000000030301000@n10004000"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1421892, ...}) = 0
mmap2(NULL, 1427880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xdcb000
mmap2(0xf22000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x157) =
0xf22000
mmap2(0xf25000, 10664, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) =
0xf25000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78db000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb78db6c0, limit:1048575, seg_32bit:1,
contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xf22000, 8192, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0x3d6000, 4096, PROT_READ) = 0
munmap(0xb78dc000, 78669) = 0
fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78ef000
write(1, "Hello!n", 7Hello!
) = 7
write(1, "Hello!n", 7Hello!
) = 7
write(1, "Hello!n", 7Hello!
) = 7
write(1, "Hello!n", 7Hello!
) = 7
write(1, "Hello!n", 7Hello!
) = 7
exit_group(0) = ?
Podobnie jak i w systemie Windows, także i tym razem lista czynności wykonywanych przez 
program, aby wyświetlić pięciokrotnie napis „Hello!”, choć zdecydowanie krótsza, to nadal zawiera 
sporo elementów.
Do monitorowania wywołań funkcji można w systemach UNIX­like można użyć programu 
etrace  opracowanego   przez   grupę   „The   ERESI   Reverse   Engineering   Software   Interface”.   Więcej 
informacji o tym, oraz o innych narzędziach stworzonych przez tą grupę można znaleźć na ich stronie 
internetowej [ERESI]. Innym narzędziem mogącym posłużyć do tego celu jest ltrace:
user@user:~$ ltrace ./hello
__libc_start_main(0x80483dc, 1, 0xbf94e2b4, 0x8048410, 0x8048400 <unfinished ...>
puts("Hello!"Hello!
)
= 7
puts("Hello!"Hello!
)
= 7
puts("Hello!"Hello!
)
= 7
puts("Hello!"Hello!
)
= 7
puts("Hello!"Hello!
)
= 7
+++ exited (status 0) +++
Do sprawdzenia zależności od dynamicznie ładowanych bibliotek można użyć polecenia ldd:
user@user:~$ ldd hello
linux-gate.so.1 => (0x00ac7000)
libc.so.6 => /lib/libc.so.6 (0x00c2a000)
/lib/ld-linux.so.2 (0x00e02000)
17
Ogólną strukturę plików wykonywalnych ELF można podglądnąć przy pomocy readelf:
user@user:~$ readelf -a hello
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048300
Start of program headers: 52 (bytes into file)
Start of section headers: 4400 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 29
Section header string table index: 26
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048168 000168 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0804818c 00018c 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481ac 0001ac 000050 10 A 6 1 4
(...)
Przy pomocy polecenia lsof można wyświetlić listę otwartych plików:
(...)
bash 6347 user cwd DIR 8,5 4096 12 /home/daroo
bash 6347 user rtd DIR 8,2 4096 2 /
bash 6347 user txt REG 8,2 801808 260616 /bin/bash
bash 6347 user mem REG 8,2 79676 1499 /lib/libnsl-2.12.1.so
bash 6347 user mem REG 8,2 42572 1538 /lib/libnss_files-2.12.1.so
bash 6347 user mem REG 8,2 227864 115 /lib/libncurses.so.5.7
bash 6347 user mem REG 8,2 38504 1554 /lib/libnss_nis-2.12.1.so
bash 6347 user mem REG 8,2 118084 709 /lib/ld-2.12.1.so
bash 6347 user mem REG 8,2 1421892 1200 /lib/libc-2.12.1.so
bash 6347 user mem REG 8,2 9736 1239 /lib/libdl-2.12.1.so
bash 6347 user mem REG 8,2 30496 1500 /lib/libnss_compat-2.12.1.so
bash 6347 user mem REG 8,2 26048 133629 /usr/lib/gconv/gconv-
modules.cache
bash 6347 user mem REG 8,2 5396736 140426 /usr/lib/locale/locale-archive
bash 6347 user 0u CHR 136,1 0t0 4 /dev/pts/1
bash 6347 user 1u CHR 136,1 0t0 4 /dev/pts/1
bash 6347 user 2u CHR 136,1 0t0 4 /dev/pts/1
bash 6347 user 255u CHR 136,1 0t0 4 /dev/pts/1
(...)
Program lsof może także posłużyć do wyświetlenia otwartych połączeń internetowych:
user@user:/usr/include/i386-linux-gnu$ ps ax | grep opera
2843 ? Sl 0:41 /usr/lib/opera/opera
3077 pts/1 S+ 0:00 grep opera
user@user:/usr/include/i386-linux-gnu$ lsof -i -p 2843 | egrep 'IPv4|IPv6'
opera 2843 user 14u IPv4 47387 0t0 TCP user.local:38494->10.0.0.182:2869 (ESTABLISHED)
opera 2843 user 19u IPv4 49501 0t0 TCP user.local:51520->web2.uci.agh.edu.pl:www (ESTABLISHED)
opera 2843 user 20u IPv4 47020 0t0 TCP user.local:51521->web2.uci.agh.edu.pl:www (ESTABLISHED)
opera 2843 user 21u IPv4 47021 0t0 TCP user.local:51522->web2.uci.agh.edu.pl:www (ESTABLISHED)
opera 2843 user 66u IPv4 47023 0t0 TCP user.local:51524->web2.uci.agh.edu.pl:www (ESTABLISHED)
opera 2843 user 71u IPv4 47024 0t0 TCP user.local:51525->web2.uci.agh.edu.pl:www (ESTABLISHED)
opera 2843 user 78u IPv4 33507 0t0 UDP 239.255.255.250:1900
opera 2843 user 79u IPv4 33508 0t0 UDP user.local:41547
opera 2843 user 83u IPv4 47025 0t0 TCP user.local:37819->fra07s07-in-f138.1e100.net:www
(ESTABLISHED)
18
Systemy UNIX­like implementują system pseudo plików procf, w którym można znaleźć 
mnóstwo informacji o uruchomionym procesie m. in. otwarte pliki, statystyki pamięci, szczegółowe in­
formacje o ruchu sieciowym, polecenie uruchamiania, a także informacje o systemie. Między innymi 
program ps korzysta z tych informacji. Przykładowe informacje zawarte w procf dla konsoli KDE w 
systemie kubuntu x86:
user@user:~$ ps | grep 3394
3394 pts/3 00:00:00 bash
user@user:~$ cat /proc/3394/net/arp
IP address HW type Flags HW address Mask Device
10.0.0.182 0x1 0x2 70:f1:a1:80:aa:d2 * wlan0
10.0.0.1 0x1 0x2 00:1c:f0:87:a9:e0 * wlan0
user@user:~$ cat /proc/3394/status
Name: bash
State: S (sleeping)
Tgid: 3394
Pid: 3394
PPid: 2218
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 256
Groups: 4 20 24 46 112 119 120 1000
VmPeak: 7320 kB
VmSize: 7256 kB
VmLck: 0 kB
VmHWM: 3740 kB
VmRSS: 3740 kB
VmData: 2040 kB
VmStk: 136 kB
VmExe: 764 kB
VmLib: 1884 kB
VmPTE: 32 kB
VmSwap: 0 kB
Threads: 1
(…)
user@user:~$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 Duo CPU T5450 @ 1.66GHz
stepping : 13
cpu MHz : 1000.000
cache size : 2048 KB
(…)
Dla procesu konsoli, o numerze pid równym 3394, wyświetlono tablicę ARP, używaną do tłumaczenia 
adresów IP na fizyczne adresy sieciowe oraz ogólne informacje o procesie jak status, ilość wątków, czy 
ilość i typ zajętej pamięci. Pokazano także informacje o procesorze w komputerze.
Do dokładnej analizy ruchu sieciowego programu służą sniffery sieciowe, wśród których 
bardzo popularny jest WireShark, który  jest dostępny na licencji open source. Na rys. 9 zapre­
zentowano listę pakietów przechwyconych przez sniffera. Pakiety te zostały wygenerowane podczas 
pobierania   strony   AGH   przez   przeglądarkę   www.   WireShark   oferuje   szeroki   zakres   filtrowania 
przechwyconych pakietów, a także zawiera wbudowaną analizę popularnych protokołów interne­
towych.
19
Rys. 9 Okno programu WireShark.
2.1.2 Deasemblacja
Deasemblacja to proces zamiany kodu binarnego z powrotem na kod asemblerowy. Statyczna 
deasemblacja, w przeciwieństwie do  dynamicznej, zaprezentowanej we wcześniejszym  rozdziale, 
wymaga od deasemblera analizy całego pliku wykonywalnego. Obecnie wiele pracy jest wykony­
wanych jest automatycznie przez nowoczesne, interaktywne deasemblery. Potrafią one wykrywać 
argumenty znanych funkcji systemowych, rysować drzewa wywołań i nie tylko [Eil00][Kas00]. 
Najbardziej funkcjonalnym deasemblerem jest bez wątpienia komercyjny program IDA Pro, 
który   oprócz   deasemblera   zawiera   także   wbudowany   debugger.   Jest   on   dostępny   zarówno   dla 
systemów Windows jak i UNIX­like. Potrafi deasemblować 32 oraz 64 bitowe pliki binarne w wielu 
formatach, a także bytecod używany przez wirtualne maszyny java oraz .NET. Zrzut ekranu programu 
IDA Pro 5.0 jest pokazany na rys. 10. IDA Pro została wykorzystana do deasemblacji funkcji sayHello() 
z przykładu 1, a efekt jego pracy jest wyświetlany w postaci grafów wywołań.
W systemach Windows oraz UNIX­like zwykle dostępny jest prosty, konsolowy deasembler 
objdump. W niektórych systemach można spotkać także graficzne frontendy dla tych narzędzi, jak na 
przykład program dissy. 
20
Rys. 10 Okno programu IDA Pro 5.0 ze zdeasemblowaną funkcją sayHello().
Funkcja main() oraz sayHello(), po potraktowaniu ich deasemblerem objdump:
080483b4 <sayHello>:
80483b4: 55 push ebp
80483b5: 89 e5 mov ebp,esp
80483b7: 83 ec 28 sub esp,0x28
80483ba: c7 45 f4 00 00 00 00 mov DWORD PTR [ebp-0xc],0x0
80483c1: eb 0f jmp 80483d2 <sayHello+0x1e>
80483c3: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]
80483c6: 89 04 24 mov DWORD PTR [esp],eax
80483c9: e8 22 ff ff ff call 80482f0 <puts@plt>
80483ce: 83 45 f4 01 add DWORD PTR [ebp-0xc],0x1
80483d2: 8b 45 f4 mov eax,DWORD PTR [ebp-0xc]
80483d5: 3b 45 08 cmp eax,DWORD PTR [ebp+0x8]
80483d8: 7c e9 jl 80483c3 <sayHello+0xf>
80483da: c9 leave
80483db: c3 ret
080483dc <main>:
80483dc: 55 push ebp
80483dd: 89 e5 mov ebp,esp
80483df: 83 e4 f0 and esp,0xfffffff0
80483e2: 83 ec 10 sub esp,0x10
80483e5: c7 44 24 04 c0 84 04 mov DWORD PTR [esp+0x4],0x80484c0
80483ec: 08
80483ed: c7 04 24 05 00 00 00 mov DWORD PTR [esp],0x5
80483f4: e8 bb ff ff ff call 80483b4 <sayHello>
80483f9: b8 00 00 00 00 mov eax,0x0
80483fe: c9 leave
80483ff: c3 ret
21
Analiza asemblerowych fragmentów programów nie jest prostym zadaniem. Spowodowane 
jest to dużą ilością kodu maszynowego, jaki jest potrzebny do wykonania prostych czynności przez 
programy. Dodatkowo zadanie to jest utrudniane przez nowoczesne kompilatory, które mogą zostać 
użyte z agresywnymi opcjami kompilacji. 
2.1.3 Dekompilacja
Dekompilacja to krok naprzód w stosunku do deasemblacji. Dekompilatory próbują odtworzyć 
struktury sterującego znane z języków wyższego poziomu jak pętle, czy instrukcje if/else. Dekom­
pilacja jest ciągle słabo zbadanym procesem i dlatego dekompilatory zwykle nie radzą sobie z bardziej 
skomplikowanymi funkcjami [Eil00][Kas00]. Spowodowane jest to tym, że w procesie kompilacji kod 
programu jest mocno optymalizowany przez nowoczesne kompilatory i utracona zostaje informacja o 
pierwotnych instrukcjach sterujących wyższego poziomu. Dlatego ich użycie wśród ludzi zajmujących 
się wsteczną inżynierią jest mocno ograniczone, a efekty pracy dekompilatorów służą bardziej jako 
wskazówka, niż jako efekt finalny. 
Najlepszym   obecnie   dostępnym   i   aktywnie   rozwijanym   dekompilatorem   jest   komercyjny 
plugin do programu IDA Pro. Na rys. 11 zaprezentowano zdekompilowaną funkcję  sayHello()  z 
przykładu   1.   Jak   widać   dekompilator   poprawnie   wykrył   parametry   funkcji   oraz   wygenerował 
poprawny kod języka C z kodu asemblerowego. Mimo wszystko odtworzony kod nie jest identyczny z 
tym w przykładzie 1.
Rys. 11 Oknoprogramu IDA Pro z pluginem dekompilatora.
2.2 Procesy w systemie operacyjnym
Aby w pełni zrozumieć architekturę omawianego systemu trzeba zdawać sobie sprawę w jaki 
sposób odbywa się interakcja między procesami oraz jądrem we współczesnych  systemach operacyj­
nych. Rozdział ten krótko przybliży informacje o systemach UNIX­like oraz Windows, istotne dla 
omawianego systemu rozproszonego.
Przed  systemem  operacyjnym  stawiane   jest   szereg  zadań.  Jednym   z  nich   jest   zwolnienie 
programistów   aplikacji   z   obowiązku   dostosowywania   programów   do   różnych   konfiguracji 
sprzętowych, na jakich ich programy będą uruchamiane. Pośredniczy on między sprzętem (ang. 
22
hardware), a programami (ang. software) nań uruchamianymi, dzięki czemu programy muszą jedynie 
wiedzieć w jaki sposób się „porozumieć” z systemem. Komunikacja między procesami, a systemem 
odbywa się poprzez z góry ustalone API i z góry ustalony sposób, najczęściej inny dla różnych 
systemów operacyjnych [Sil05][Tan08].
Rys. 12 Relacja między sprzętem, systemem operacyjnym oraz procesami.
Jak można zauważyć na rys. 12, procesy w systemach operacyjnych można traktować jako dość 
niezależne jednostki. Systemy operacyjne starają się je odseparować od siebie na tyle, na ile jest to 
możliwe, minimalizując tym samym wpływ błędnego działania jednego procesu na drugi. Procesy nie 
mogą   być   jednak   w   pełni   niezależne,   gdyż   czasami   programistą   zależy   na   czymś   zupełnie 
przeciwnym   –  chcą  tworzyć  programy  wieloprocesowe,  których  wynik  działania  jest  rezultatem 
współpracy   wielu   procesów.   Dlatego   systemy   UNIX­like   oraz   Windows   udostępniają   szereg 
mechanizmów wzajemnej interakcji między procesami (Inter­process Communication) [Fus09][Ker10]. 
przykładem  wieloprocesowych  aplikacji  używanych  na  co  dzień  są  przeglądarki  internetowe, w 
których pluginy są najczęściej implementowane jako osobne procesy, dzięki  czemu błędy  w ich 
implementacji nie mają wpływu na działanie całej przeglądarki.
System   operacyjny   dysponuje   sprzętem   i   przydziela   każdemu   procesowi   określony   czas 
procesora,   pamięć   RAM.   Pośredniczy   on   także   przy   operacjach   dyskowych   oraz   połączeniach 
internetowych. Dla tych zadań opracowane zostały wydajne algorytmy, które zapobiegają fragmentacji 
pamięci czy przywłaszczeniu czasu procesora. Każdy proces ma przydzieloną oddzielną, wirtualną 
przestrzeń adresową w pamięci, która jest mapowana na rzeczywistą pamięć operacyjną i która 
zapobiega przypadkowej oraz intencjonalnej ingerencji innych procesów w dane procesu. Zapis i od­
czyt w pamięci wirtualnej drugiego procesu jest oczywiście możliwy, lecz nie wprost, tylko wymaga 
pośredniczenia systemu operacyjnego [Tan08].
Przed systemami operacyjnymi stawianych jest oczywiście szereg innych wymagań, między 
innymi zarządzanie zasobami sprzętowymi, w tym przydzielanie czasu procesora dla procesów oraz 
zarządzanie pamięcią RAM i nieulotną, czy pośredniczenie w połączeniach internetowych. Kompletne 
omówienie zadań i sposobu ich realizacji przez systemy operacyjne jest poza zakresem niniejszej 
pracy. Zainteresowanych tymi tematami czytelników odsyłam do bogatej literatury traktujących o tych 
zagadnieniach [Tan08][Sil05][Tan05][Tan95].
2.2.1 Procesy i biblioteki
Proces jest jednym z podstawowych pojęć stosowanych w systemach operacyjnych [Sil05]. 
Tworzenie nowego procesu w systemie operacyjnym jest wieloetapowe i dość złożone [Sil05][Bov00]
sprzęt
System operacyjny
Proces Proces
Proces
23
[Tan08].   Wpływ   ma   na   to   elastyczność   formatów   plików   wykonywalnych,   a   także   zależność 
programów od bibliotek. Biblioteki te mogą być dołączone do pliku wykonywalnego – biblioteki 
kompilowane statycznie, bądź być ładowane do pamięci w chwili, gdy nowy proces od nich zależny 
jest   uruchamiany,  bądź  wywołuje  funkcje  w  nich   się   znajdujące   –  biblioteki   dynamiczne[Fus09]
[Ker10]. Biblioteki dynamicznie ładowane mają zwykle rozszerzenie .dll w systemach Windows oraz 
.so w systemach UNIX­like.
Na proces w systemach operacyjnych składa się szereg składników [Sil05][Tan08] w tym: 
1. Prywatna przestrzeń adresowa pamięci.
2. Otwarte pliki oraz połączenia sieciowe.
3. Wątki.
4. Katalog roboczy.
5. Dane pomocne do wykonywania procesu – stos, stan rejestrów procesora.
6. Załadowany do pamięci kod programu oraz biblioteki. 
Procesy zwykle mają otwarte na początku swojego działania trzy uchwyty plikowe – standardowego 
wejścia, standardowego wyjścia oraz błędów.
2.2.2 Plik wykonywalny
Plik wykonywalny programu jest charakterystyczny dla danego systemu operacyjnego, a jego 
budowa ma ścisły związek z historią systemu oraz tworzeniem nowego procesu [Pie94][mpe10]. 
Formaty plików wykonywalnych zostały opracowane w taki sposób, by możliwie wydajnie można je 
było uruchamiać, dlatego ich budowa często jest podobna do struktur pamięci już uruchomionego 
procesu.   Innymi   kryteriami,   które   były   rozpatrywane   podczas   opracowywania   formatu   plików 
wykonywalnych były m. in. elastyczność czy przenośność między platformami sprzętowymi. System 
Linux domyślnie korzysta z plików ELF, zaś systemy Windows używają plików PE [Pie94][mpe10]
[elfsp][elf64]. 
Plik wykonywalny posiada tzw. entry point, w którym zaczyna się wykonywanie procesu. 
Dynamicznie ładowane biblioteki mają także entry point, którego kod jest wykonywany w chwili 
załadowania biblioteki do pamięci lub usuwania biblioteki z pamięci procesu. Nie należy mylić entry 
point z funkcją  main()  w programach języka C, ponieważ przed rozpoczęciem wykonywania kodu 
funkcji  main(), wcześniej pracę wykonują funkcje umieszczone w kodzie przez kompilator, które 
przygotowują środowisko i m. in. przygotowują argumenty funkcji main() [26][elfsp].
Rys.   13   obrazuje   budowę   typowego   wykonywalnego   pliku   PE   systemu   Windows   [Pie94]
[mpe10]. Kolejne wycinki oznaczają:
• MS­DOS Header i DOS Stub – nagłówek pliku wykonywalnego systemu DOS oraz program 
DOS, dzięki któremu program uruchomiony w systemie DOS zwykle wyświetla wiadomość 
„This program cannot be run in DOS mode” i kończy działanie.
• Signature – sygnatura pliku PE, wskazuje wersję pliku PE.
• IMAGE_FILE_HEADER – struktura zawierająca informacje takie jak typ procesora, liczba 
sekcji czy typ pliku: program, dynamiczna biblioteka, plik OBJ i inne.
24
• IMAGE_OPTIONAL_HEADER – struktura zawierająca m. in. wersję linkera, rozmiar kodu, 
adres entry point, wersję systemu operacyjnego,  informacje przyspieszające ładowanie pliku 
do pamięci i inne.
• IMAGE_SECTION_HEADERS – struktury opisujące sekcje znajdujące się w pliku, ich nazwy, 
rozmiary i inne.
• .text – sekcja zwykle zawierająca kod programu.
• .data – sekcja zwykle zawierająca dane programu.
• .rsrc – sekcja zwykle zawierająca osadzone pliki i grafikę.
• .idata – tablica importów, czyli lista funkcji importowanych (używanych) przez program oraz 
nazwy bibliotek dll, je zawierających.
• .edata   –   tablica   eksportów,   czyli   lista   funkcji,   które   mogą   być   wywołane   z   tego   pliku 
wykonywalnego.
Opisane powyżej sekcje i ich nazwy mają jedynie charakter informacyjny, ponieważ mogą się niemal 
dowolnie zmieniać [Pie94][mpe10].
Rys. 13  Budowa typowego pliku PE systemu Windows.
Rys. 14 Budowa pliku wykonywalnego ELF.
Rys. 14 obrazuje budowę  wykonywalnego pliku ELF [elfsp][elf64]. Kolejne fragmenty oznaczają:
• ELF header – opisuje organizację pliku, typ procesora, entry point, wersję ABI i inne.
• Program header table – zawiera informacje niezbędne do utworzenia procesu.
• Sekcje – zawierają kod programu, dane.
• Section header table – opisuje sekcje w pliku, nazwy, rozmiary i inne.
MS­DOS Header
DOS Stub
Signature
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER
IMAGE_SECTION_HEADERs
.text
.data
.rscr
.idata
.edata
ELF header
Program header table
Sekcje
Section header table
25
Wśród sekcji pliku pojawiają się specjalne sekcje, które opisują np. importowane funkcje. 
Podobnie jak w przypadku plików PE, nazwy sekcji mogą się zmieniać (poza sekcjami specjalnymi) 
tak, jak ich pozycja w pliku [elfsp][elf64].
Uruchomione   programy   stają   się   procesami   i   są   zarządzane   przez   system   operacyjny. 
Uruchomienie nowego procesu nie jest jednak takie proste jak brzmi – system operacyjny musi 
wykonać szereg zabiegów zanim zostanie powołany do życia nowy, w pełni sprawny proces. 
Warto w tym momencie wspomnieć o ABI dla plików wykonywalnych. ABI jest zbiorem zasad, 
które formalizuje typy i rozmiar argumentów, sposób nazywania oraz wywoływania funkcji (ang. 
calling   conventions)   z   binarnych   plików   wykonywalnych   [sys10][wca64].   Dzięki   standardowemu 
interfejsowi binarnemu dla bibliotek języka C możliwe jest dynamiczne ładowanie tych bibliotek oraz 
wywoływanie funkcji w nich się znajdujących. 
W środowisku x86 istnieją trzy szeroko stosowane konwencje wywoływania funkcji [Eil00], są 
to cdecl, stdcall oraz fastcall. Pierwsza z nich jest standardową konwencją wykorzystywaną domyślnie w 
językach C oraz C++. Argumenty funkcji są przekazywane przez stos, na którym są umieszczane w 
odwrotnej kolejności. Uprzątnięcie stosu z argumentów funkcji leży w gestii kodu wywołującego 
funkcję. Konwencja stdcall jest bardzo popularna w systemach Windows, gdyż jest wykorzystywana w 
bibliotekach systemowych. Podobnie jak w konwencji cdecl argumenty są przekazywane przez stos, 
jednak w tym przypadku są one umieszczane w normalnej kolejności, oraz to wywoływana funkcja 
jest odpowiedzialna za usunięcie argumentów ze stosu po jej wykonaniu. Konwencja  fastcall,  jak 
nazwa wskazuje, jest zoptymalizowana do szybkiego wywoływania. Pierwsze dwa argumenty funkcji 
są przekazywane przez rejestry ECX oraz EDX, kolejne zaś przez stos.
W   środowisku   x64   obowiązują   zupełnie   inne   konwencje   wywoływania   funkcji   niż   w 
środowisku x86 . W systemach Linux parametry funkcji są przekazywane w normalnej kolejności przy 
czym:
• Argumenty całkowitoliczbowe (także wskaźniki) przez rejestry RDI, RSI, RDX, RCX, R8, R9, a 
kolejne przez stos.
• Argumenty zmiennoprzecinkowe przez rejestry zmiennoprzecinkowe XMM0  do  XMM7, a 
kolejne przez stos.
Z innych, ciekawych informacji na temat funkcji w systemie Linux w  środowisku x64, to 
wywoływana funkcja posiada zarezerwowany dla niej obszar 128 bajtów powyżej wskaźnika ramki 
stosu, przechowywanego w RSP, zwany "red zone", gdzie można przechowywać zmienne tymczasowe 
funkcji, zamiast je wrzucać na stos za pomocą pushq. Dodatkowo wskaźnik ramki stosu jest ustawiony 
"na sztywno" i nie zmienia swojego położenia po wywołaniu pushq/popq. Pozwala to na operacje na 
stosie bez używania rejestru EBP do przechowywania wskaźnika podstawy stosu (początku ramki). 
Przypomnę  jeszcze tylko,  że ramka stosu jest tworzona przy każdorazowym  wywołaniu funkcji 
[Bry05][sys10].
W przypadku systemów Windows w środowisku x64 sytuacja wygląda podobnie [wca64]. Parametry 
funkcji są przekazywane w normalnej kolejności, przy czym:
• Argumenty całkowitoliczbowe (także wskaźniki) przez rejestry RCX, RDX, R8, R9, a kolejne 
przez stos.
• Argumenty zmiennoprzecinkowe przez rejestry zmiennoprzecinkowe XMM0 do XMM3,  a 
26
kolejne przez stos.
2.2.3 Wywo ania systemoweł
Każdy proces ma określoną pulę możliwych instrukcji, które może wykonać. Jeśli chce zrobić 
coś   ponadto,   musi   poprosić   system   operacyjny,   aby   wykonał   dane   zadanie   w   jego   imieniu.   Ta 
komunikacja pomiędzy procesem, a systemem ma miejsce przy pomocy przerwań systemowych, co 
ilustruje rys. 15 [Sil05].
Rys. 15 Przerwanie systemowe powoduje wywołanie usług systemowych.
Przerwanie to pojedyncza instrukcja maszynowa:
int 0x80 ;Linux
int 0x2e ;Windows
sysenter
Numer przerwania jest charakterystyczny dla systemu operacyjnego i wynosi 0x80 dla systemu 
Linux oraz 0x2e dla systemów Windows z rodziny NT. Dodatkowo, nowoczesne systemy operacyjne 
wykorzystują   instrukcję  sysenter,   zamiast   przerwania,   która   jest   zoptymalizowana   dla   wywołań 
systemowych [Ker10][Bov00][Sch01]. 
Systemy UNIX­like mają dobrze udokumentowane przerwania systemowe. Ich listę wraz z 
numerami można znaleźć w pliku nagłówkowym unistd.h, lub włączanych przez niego plikach:
#ifndef _ASM_X86_UNISTD_32_H
#define _ASM_X86_UNISTD_32_H
/*
* This file contains the system call numbers.
*/
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
(…)
Nazwy wywołań oraz ich argumenty  często się pokrywają z funkcjami systemowymi o takich 
samych nazwach. De facto funkcje te są bardzo cienkimi nakładkami na te przerwania. Argumenty dla 
wywołań systemowych w systemie Linux są przekazywane kolejno przez rejestry EBX, ECX, EDX, 
ESX, EDI, zaś numer przerwania jest umieszczany w rejestrze EAX. Rezultat wywołania systemowego 
jest dostępny w rejestrze EAX [Bov00]. Przykład programu asemblerowego, który zwraca 2 jako 
Proces
User Land Kernel Land
systemPrzerwanie
27
numer wyjścia:
.text
.global _start
_start:
movl $1,%eax
movl $2,%ebx
int $0x80
Asemblacja, konsolidacja oraz wykonanie:
user@user:~$ as exit.s
user@user:~$ ld a.out -o exit
user@user:~$ ./exit
user@user:~$ echo $?
2
W systemach Windows wskaźnik do argumentów przerwania jest umieszczany w rejestrze EDX, zaś 
numer przerwania w rejestrze EAX. Rezultat przerwania jest dostępny w rejestrze EAX [Sch01]. 
Rys. 16 Pośredniczenie bibliotek systemowych podczas wywołań systemowych.
W   systemach   Windows   nie   ma   tak   cienkiej   nakładki   na   wywołania   systemowe   jak   w 
przypadku systemu Linux. Użytkownicy nie wywołują przerwań systemowych bezpośrednio,   a 
zamiast tego korzystają z dynamicznie linkowanych bibliotek, jak zostało to zilustrowane na rys. 16 
[Sil05].   Przykładowo,   podstawowe   funkcje   obsługujące   pliki   i   wątki   znajdują   się   w   bibliotece 
kernel32.dll, podczas gdy funkcje odpowiedzialne za interfejs użytkownika rezydują w  user32.dll. 
Obie   te   biblioteki   intensywnie   korzystają   z   natywnego   interfejsu   Windowsa   znajdującego   się   w 
ntdll.dll. Biblioteka  ntdll.dll  realizuje niektóre funkcje w trybie user, inne zaś realizuje wykonując 
przerwanie do trybu jądra.
.text
.global _start
_start:
movl $0x101,%eax # zakończ proces
push $13 # kod wyjścia
push $-1
movl %esp,%edx
int $0x2e # przerwanie systemowe
Przykład 2  Program, który kończy działanie zwracając 13 jako kod wyjścia do systemu.
Jest oczywiście możliwe bezpośrednie wywoływanie przerwań systemowych, jest to jednak 
bardzo utrudnione, gdyż o ile API Windowsa jest dobrze udokumentowane, o tyle jest już problem z 
dokumentacją natywnego API w ntdll.dll, nie wspominając o bezpośrednich przerwaniach. W przy­
kładzie 2 zaprezentowano program, który omija natywne API Windowsa. Asemblacja, konsolidacja 
Proces
User Land Kernel Land
systemPrzerwanieNtdll.dll
Kernel32.dll
28
oraz wykonanie programu:
C:>as test_calls.s
C:>ld -o test.exe a.out
C:>test.exe
C:>echo %errorlevel%
13
Warto zwrócić uwagę, że program ten został przygotowany dla systemu Windows XP SP3. 
Kody wywołań systemowych mogą być inne dla różnych wersji systemu Windows. 
2.3 Kontrolowanie wywo a systemowychł ń
Rozdział ten skupia się na kontrolowaniu wywołań systemowych w systemach Windows. Jak 
wspomniano w poprzednim rozdziale, Windows korzysta z szeregu bibliotek systemowych. Zatem, 
aby  kontrolować  wywoływanie  usług   systemowych  należy  przejąć  kontrolę  nad  wywoływanymi 
funkcjami. Technika nadpisywania wywołań funkcji nosi nazwę spoofing lub hooking. Nadpisywanie 
to może mieć miejsce w trybie user albo kernel. Hooking w trybie kernel, co w tym wypadku 
nazywane jest często syscall proxy, jest zdecydowanie bardziej zaawansowanym problemem [Hog05]
[Blun09][dpw10][wsp09] i zostanie pominięty w tej pracy.
2.3.1 Proxy DLL
Technika proxy dll [Hog05][mll08] korzysta z faktu, że podczas uruchamiania procesu loader 
najpierw poszukuje bibliotek do załadowania w katalogu aplikacji, a dopiero potem, gdy nie znajdzie 
potrzebnych bibliotek w katalogu programu, wówczas sprawdza inne miejsca. Jest to prawdą dla 
większości bibliotek, poza kluczowymi  bibliotekami systemowymi, które są poszukiwane w katalogu 
systemu Windows przed pozostałymi miejscami. Aby móc zastosować technikę proxy dll dla tych 
bibliotek   trzeba   najpierw   zmodyfikować   plik   wykonywalny   programu,   zmieniając   nazwy   tych 
bibliotek.
Na potrzeby tego rozdziału załóżmy, że chcemy nałożyć proxy na bibliotekę o nazwie lib.dll.
Pierwszym krokiem, który wykonujemy jest zmiana nazwy biblioteli lib.dll na, powiedzmy, origLib.dll. 
Teraz tworzymy bibliotekę – proxy w katalogu programu, o takiej samej nazwie, jaką miała oryginalna 
biblioteka, czyli lib.dll. Nasza biblioteka proxy powinna zawierać wszystkie te funkcje, które zawiera 
lib.dll. Dodatkowo we wnętrzu wszystkich funkcji z lib.dll wywołujemy odpowiadające im funkcje z 
origLib.dll.   W   tym   momencie   program   działa   bez   zmian,   ponieważ   wszystkie   funkcje   są 
przekierowane na ich oryginalne wersje. Jeśli chcemy zmodyfikować, działanie programu musimy 
zmienić implementację tych funkcji z lib.dll, na któych nam zależy.
Aby   zastosować   tą   technikę   dla   biblioteki   systemowej,   jak  ntdll.dll,   to   musimy   wykonać 
dodatkowe kroki. Na początku modyfikowany jest plik wykonywalny programu – zmieniana jest 
nazwa biblioteki systemowej ntdll.dll na przykład na prepn.dll. Następnie kopiowana jest biblioteka 
systemowa ntdll.dll do katalogu programu i zmieniana jest jej nazwa np. na ntdll_orig.dll. Następnie 
kopiowana   jest   specjalnie   przygotowana   biblioteka   prepn.dll,   która   definiuje   aliasy   dla   funkcji 
systemowych   tj.   dla   przykładowej   funkcji  ZwTerminateProcess  definiowany   jest   alias 
ntdll_orig.ZwTerminateProcess. W tym momencie wywołanie funkcji  ZwTerminateProcess powoduje 
wywołanie   funkcji    ntdll_orig.ZwTerminateProcess  znajdującej   się   w     ntdll_orig.dll   i   która   jest 
oryginalną   systemową   funkcją   Windowsa.   Nasza,   przygotowana   wcześniej,   biblioteka   prepn.dll 
oprócz aliasów dla funkcji posiada także własne definicje tych funkcji, które chcemy nadpisać.
29
Rys. 17 biblioteka proxy prepn.dll z aliasem dla funkcji exit() oraz własną implementacją funkcji write().
Opisana powyżej technika proxy dll, posiada kilka ważnych zalety – działa w trybie user, nie 
powoduje znaczącego spadku szybkości działania programów oraz nie ingeruje w działanie innych 
procesów. Jej poważną wadą jest natomiast to, że zdeterminowany użytkownik jest w stanie używać 
bezpośrednio przerwań systemowych bez odwoływania się do funkcji z ntdll.dll, tak jak zostało to 
zademonstrowane w przykładzie 2, w rozdziale 3.3 wywołania systemowe. Kłopotliwe może być także 
nadpisywanie natywnego API Windowsa, gdyż Microsoft nie udostępnia dokumentacji tego API, 
racjonalizując ten fakt tym, że API to może się zmieniać między kolejnymi wydaniami i aktualizacjami 
systemu [Sch01][Hog05][Blun09]. Dostępne opisy funkcji natywnego API Windowsa opierają się na 
technikach wstecznej inżynierii oprogramowania i są tworzone przez miłośników wstecznej inżynierii 
z całego świata [Neb00].
2.3.2 Nadpisanie tablicy importów lub miejscowe nadpisanie funkcji
Po pierwsze można nadpisywać tablicę importów w binarnym pliku wykonywalnym [Hog05]
[Blun09]. Podobnie zresztą, przy ewentualnej drobnej pomocy deasemeblera, można wprost edytować 
początek funkcji tj. wykonać skok do wcześniej wygenerowanego kodu, który dodany został do pliku 
binarnego, a następnie wykonać skok z powrotem do ciała funkcji. Technika nadpisywania preambuły 
funkcji i skoków do kodu, a następnie powrotu przy użyciu trampoliny została po raz pierwszy 
opracowana przez oddział badawczy firmy Microsoft w 1994 roku i po dziś dzień jest nazywana 
Detours [Hun99].
Opisaną   powyżej   metodę   nadpisywania   preambuły   funkcji,   można   także   wykonać   na 
działającym procesie, trzeba mieć tylko dostęp do przestrzeni adresowej procesu. Opisane poniżej 
techniki   używają   wstrzykiwania   bibliotek   dll,   do   wykonywania   kodu   w   przestrzeni   adresowej 
wybranego procesu, umiejscawiając wykonywany kod wewnątrz funkcji DllMain().
2.3.3 Wstrzykni cie DLL przy pomocy systemowego hookowaniaę
Microsoft   w   swoich   systemach   Windows   udostępnia   API   do   hookowania   wiadomości 
systemowych   w   innym   procesie[Hog05][Blun09].   Wiąże   się   to   z   dynamicznym   załadowaniem 
biblioteki, pobraniem adresu funkcji, a następnie użyciem funkcji nadpisującej wywołanie funkcji. 
Przykładowy kod:
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;
hinstDLL = LoadLibrary(TEXT("c:myappmydll.dll"));
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "myFunction");
hhookSysMsg = SetWindowsHookEx(WH_KEYBOARD, hkprcSysMsg, hinstDLL, 0);
Po   wykonaniu   tego   kodu,   za   każdym   razem,   gdy   jakiś   proces   wygeneruje   zdarzenie 
klawiatury, wówczas do jego pamięci zostanie załadowana biblioteka mydll.dll i wywołana funkcja 
myFunction(). Istnieje też możliwość hookowania pojedynczego procesu. Ładowanie biblioteki może 
posłużyć  do  wykonania   dowolnego  kodu   w  przestrzeni  procesu,  w  tym  może   nadpisać   tablicę 
proces prepn.dll ntdll_orig.dll
exit() exit()
write(stdout) write(socket)
30
importów czy lokalnie nadpisać funkcję. Wystarczy tylko ten kod umieścić w załadowanej bibliotece:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
// kod wykonywany w przestrzeni użytkownika podczas ładowania biblioteki
}
return true;
}
__declspec (dllexport) LRESULT myFunction (int code, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(g_hhook, code, wParam, lParam);
}
Funkcja  DllMain() jest odpowiednikiem funkcji main() z programów języka C. W jej wnętrzu należy 
umieścić kod odpowiednio nadpisze wywołania funkcji [Hog05][Blun09].
2.3.4 Wstrzykni cie DLL przy pomocy rejestruę
W systemach Windows od wersji Windowsa 2000 istnieje gałąź rejestru [Hog05][Blun09]:
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWindows]
"AppInit_DLLs"=""
"DeviceNotSelectedTimeout"="15"
"GDIProcessHandleQuota"=dword:00002710
"Spooler"="yes"
"swapdisk"=""
"TransmissionRetryTimeout"="90"
"USERProcessHandleQuota"=dword:00002710
Zawiera ona klucz  AppInit_DLLs. Dodanie biblioteki dll (pełnej ścieżki) do tego klucza spowoduje, że 
za każdym razem, gdy uruchomiony zostaje proces, który korzysta z user32.dll, to wczytana zostaje 
również   wskazana   biblioteka   do   przestrzeni   adresowej   tego   procesu.   Wystarczy   tylko   dodać 
odpowiedni kod do funkcji DllMain() w tej bibliotece, która nadpisze wywołania funkcji. Można także 
dodać więcej bibliotek do tego klucza oddzielając je znakiem spacji [Blun09].
2.3.5 Wstrzykni cie DLL przy pomocy zdalnego w tkuę ą
Jest   to   popularna   technika,   wykorzystana   na   przykład   w   programie   WinAPIOverride32, 
przedstawionym w rozdziale 2 wsteczna inżynieria oprogramowania. Składa się z następujących 
etapów wykonywanych przez zewnętrzny proces [Hog05][Blun09]:
1. Pobierany jest uchwyt procesu, do którego ma być wstrzyknięta biblioteka dll, przy pomocy 
funkcji  OpenProcess().
2. Dynamicznie pobierany jest adres funkcji  LoadLibrary()  z biblioteki  kernel32.dll  przy pomocy 
funkcji GetProcAddress() oraz GetModuleHandle().
3. Alokowana jest zdalnie pamięć przy pomocy virtualAllocEx().
4. W   miejsce   zaalokowanej   pamięci   kopiowana   jest   pełna   nazwa   biblioteki   przy   pomocy 
WriteProcessMemory().
5. Tworzony jest zdalny wątek przy użyciu funkcji  CreateRemoteThread(), który używa funkcji 
LoadLibrary() do wstrzyknięcia biblioteki dll.
31
2.4 Javascript i HTML5
Technologie internetowe stają się coraz bardziej funkcjonalne, co zostało zauważone zarówno 
przez użytkowników jak i twórców coraz, to bardziej poważniejszego oprogramowania z interfejsem 
użytkownika dla przeglądarek internetowych. Interfejs www staje się także bardziej naturalny dla 
użytkowników. W ostatnich latach można było zauważyć wzrost zainteresowania tym medium wśród 
twórców oprogramowania, w szczególności wzrosła liczba usług internetowych. Opracowanie to 
także nie jest obojętne dla tych technologii i przewiduje interfejs użytkownika między innymi w fo­
rmie   przystosowanej   dla   przeglądarek   internetowych.   Technologie   internetowe   stały   się   również 
zdecydowanie bardziej złożone, dlatego ten rozdział przybliża kilka z nich, pokazując możliwości 
zwłaszcza tych, które zostały użyte dalej w opracowaniu. Opis HTML oraz CSS zostały pominięte w 
tym rozdziale, choć zawiera on kilka informacji na temat wybranych elementów szkicu standardu 
HTML 5 [39, 40].
2.4.1 JavaScript
Javascript jest skryptowym językiem programowania, którego implementacja jest obecna we 
wszystkich popularnych przeglądarkach internetowych. Umożliwia on programowanie funkcyjne, 
obiektowe oraz imperatywne. Jego składnia jest implementacją języka   ECMAScript, zaś wersją, na 
której bazuje większość implementacji w popularnych przeglądarkach internetowych, jest trzecia 
edycja ECMA­262. Standard ten opisuje takie elementy języka jak typy danych czy struktury sterujące 
[ECM99].
Interakcja  z elementami dokumentu  HTML  w przeglądarkach  jest  standaryzowana przez 
World Wide Web Consortium w rekomendacjach wydawanych przez tą grupę. W3C stworzyło model 
DOM oraz ustandaryzowało API dla manipulacji elementami dokumentów HTML. Obecnie wszystkie 
popularne przeglądarki implementują DOM w wersji 1 oraz dużą część DOM w wersji 2 [DOM]. 
JavaScript umożliwia manipulację dokumentami HTML, arkuszami stylów CSS, oraz w ogra­
niczonym stopniu oknami. Umożliwia wykonywanie kodu w zależności od akcji użytkownika, w tym 
umożliwia   obsługę   myszy   i   klawiatury.   W   najbardziej   zaawansowanych   zastosowaniach   może 
posłużyć   do   zbudowania   dynamicznego   interfejsu   użytkownika,   podobnego   do   tradycyjnych 
programów z graficznym interfejsem użytkownika, bądź dynamicznej grafiki, nawet trójwymiarowej 
[Zak06][Zak07][HTML5][HTM11].
Pomimo rekomendacji wydawanych przez W3C, nadal nie istnieje pełna zgodność między 
funkcjami języka JavaScript w różnych przeglądarkach [Zak06][Zak07], dlatego wśród programistów 
tego języka popularne jest użycie frameworków, które ukrywają różnice w implementacjach. Jednym z 
takich  frameworków  jest  Mootools,  choć  istnieje  oczywiście  bardzo  dużo  innych,  popularnych  i 
dojrzałych frameworków języka JavaScript, rozwijanych przez społeczności programistów, jak jQuery 
czy Prototype. Dystrybuowane są one zwykle jako niezależne moduły, przez co użytkownicy mogą 
dołączać te moduły fameworka do swoich programów, które w danym momencie potrzebują. Różne 
frameworki   nie   zawsze   są   one   ze   sobą   zgodne,   przez   co   nie   koniecznie   można   ich   używać 
jednocześnie. 
2.4.2 XML
XML jest uniwersalnym, tekstowym formatem, standaryzowanym przez grupę W3C [XML08]
[Nam09].   Jest   on   członkiem   szerszej   rodziny   formatów   zgodnych   z   SGML,   a   częstym   jego 
32
zastosowaniem jest przechowywanie danych w sposób niezależny od platformy sprzętowej oraz ze 
wsparciem wielu systemów kodowania znaków. Powstało wiele formatów danych, bazujących na 
dokumentach XML w tym MathML, RSS oraz SVG, które zdobyły dużą popularność w aplikacjach 
webowych   oraz   przeglądarkach   www.   Dokumenty   XML   nie   muszą   być   związane   tylko   z 
przechowywaniem   informacji,   dowodem   na   to   jest   szereg   języków   programowania,   które   są 
dokumentami   XML.   Jednym   z   takich   języków   jest   język   transformacji   XSLT,   którego   kod   jest 
pełnoprawnym   dokumentem   XML.   Świadczy   to   o   dużej   elastyczności   oraz   uniwersalności   tego 
formatu. 
Pewną niedogodnością formatu XML jest brak wsparcia dla danych binarnych, które muszą 
być odpowiednio przekonwertowane na znaki, zanim można je osadzić w dokumencie. Istnieje wiele 
algorytmów, które mogą zostać wykorzystane w tym celu, między innymi Base64 stosowany w 
wiadomościach mailowych [bbb06]. Format ten ma jeszcze jedną wadę,   a mianowicie jest bardzo 
ekspresywny,   co   skutkuje   dużą   nadmiarowością   formy   na   treścią.   Można   sobie   z   tym   radzić 
kompresując dokumenty bezstratnymi algorytmami kompresji.
Obsługa dokumentów XML jest obecna we wszystkich popularnych przeglądarkach www. Do 
manipulacji tymi dokumentami może zostać użyty język JavaScript. XML zdobył dużą popularność, 
dzięki czemu dostępnych jest wiele bibliotek w różnych językach programowania wspierających tą 
technologię. Obsługa tego formatu jest nawet częścią standardowej biblioteki niektórych języków 
programowania jak Python czy Ruby.
2.4.3 Ajax
Ajax jest techniką programistyczną, na którą się składa szereg technologii zarówno po stronie 
przeglądarki jak i serwera [Zak06][Zak07]. Główną jej ideą i zastosowaniem jest asynchroniczne 
ładowanie zewnętrznych dokumentów z serwera. Dzięki temu, aplikacje JavaScript mogą być bardziej 
interaktywne i w większym stopniu przypominać tradycyjne programy.
Rys. 18 Najczęściej spotykana struktura technologii stojących za Ajax.
Programiści JavaScript opracowali kilka sposobów realizacji asynchronicznych żądań HTTP. 
Każdy   z  tych  sposobów  ma  wady  oraz  zalety  i  dlatego  w  realnych  zastosowaniach,  najczęściej 
korzysta się z kilku technik równocześnie. 
Pierwszym sposobem jest technika ukrytej ramki [Zak07]. Wymaga ona, żeby strona www była 
oparta   na   dwóch   ramkach   –   pierwszej,   zajmującej   cały   widoczny   ekran,   w   której   znajduje   się 
wyświetlana   strona   oraz   drugiej,   niewidocznej   dla   użytkownika.   Adres   niewidocznej   ramki   jest 
zmieniany w kodzie programu JavaScript, co powoduje ładowanie nowych treści do ramki. Treści te, 
po załadowaniu, są następnie interpretowane przez kod programu. Aby wykonać żądanie POST 
należy utworzyć nowy formularz, wypełnić jego pola oraz wysłać go, używając metody  submit(). 
Oczywistą wadą tej techniki jest wymagana obecność ramek, na których musi się opierać kod strony.
JavaScript
Serwer
Baza
Danych
Przeglądarka
www
XML/XSLT,
HTML,
Tekst,
JSON,
PHP
33
Drugi sposób jest analogiczny do poprzedniego z tą różnicą, że ramka użyta do komunikacji 
nie jest na stałe umiejscowiona w kodzie strony, lecz jest tworzona dynamicznie [Zak07]. Program 
tworzy ramkę iframe, oraz używa jej do komunikacji, co zostało pokazane w przykładzie 4.
var oFrame = null;
window.onload = function(){
// utwórz ukrytą ramkę i dodaj ją do strony
var oEl = document.createElement("iframe");
oEl.style.display = "none";
oEl.name = "dynFrame";
oEl.id = "dynFrame";
document.body.appendChild(oEl);
oFrame = frames["dynFrame"];
// odczekaj 10 ms
setTimeout(makeRequest, 10);
};
function makeRequest(){
oFrame.location = "hello.html"; // wyślij żądanie
}
Przykład 4 Kod JavaScript, umieszczany na głównej do komunikacji z serwer przy użyciu ukrytej ramki.
Plik hello.html zawiera kod, który ma być wykonany po wczytaniu ramki:
<html>
<head>
<script type="text/javascript">
alert("Hello!");
</script>
</head>
<body>
</body>
</html>
Także i w tym przypadku, aby wysłać żądanie POST należy wczytać formularz do ukrytej 
ramki, wypełnić jego pola, a następnie go wysłać. Dostęp do okna klienta w kodzie Javascript serwera 
jest możliwy poprzez obiekt parent.
Zupełnie   oddzielnym   sposobem   wykonywania   asynchronicznych   żądań   HTTP  jest   użycie 
obiektu XMLHttpRequest [Zak06][Zak07], obecnego we wszystkich popularnych przeglądarkach www. 
Obiekt ten pozwala zdefiniować funkcję, która ma być wywołana w momencie ukończenia żądania, 
bądź  błędu   połączenia.   Technika  ta  jest  zdecydowanie   najbardziej  wygodna   z  punktu  widzenia 
programisty JavaScript oraz pozwala na dostęp do nagłówków HTTP oraz kodów zwrotnych serwera. 
Niestety także i ona nie jest ona pozbawiona wad. W odróżnieniu od metod opartych na ramkach, 
użycie obiektu   XMLHttpRequest  nie powoduje zmian historii przeglądarki, przez co nie pozwala 
symulować nawigacji za pomocą standardowych opcji cofnij/ponów z przeglądarek.
Do demonstracji tej techniki utworzone zostały dwa pliki – hello.txt, zawierający napis „Hello!” 
oraz hello.php, którego zawartość jest następująca:
<?php
header("Content-Type: text/plain");
echo $_POST['msg'].' user!';
?>
34
Kod Javascript, który wysyła żądania GET oraz POST:
// utwórz obiekt
function createXHR(){
if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Safari, and Opera
var oXHR = new XMLHttpRequest();
} else { // IE5, IE6
var aVersions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0"];
for (var i = 0; i < aVersions.length; i++) {
try {
var oXHR = new ActiveXObject(aVersions[i]);
return oXHR;
}
catch (oError) {
// ignoruj
}
}
}
return oXHR;
}
window.onload = function(){
var oXHR = createXHR();
// wyślij żądanie GET
oXHR.open("get", "hello.txt", true);
oXHR.onreadystatechange = function(){
if (oXHR.readyState == 4) {
alert("Response: " + oXHR.responseText);
}
};
oXHR.send(null);
// wyślij żądanie POST
var oXHRp = createXHR();
var sMsg = "Hello";
oXHRp.open("post", "hello.php", true);
oXHRp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
oXHRp.onreadystatechange = function(){
if (oXHRp.readyState == 4) {
alert("Response: " + oXHRp.responseText);
}
};
oXHRp.send("msg=" + encodeURIComponent(sMsg));
}
Odpowiednik powyższego kodu, napisany przy użyciu frameworku Mootools:
window.onload = function(){
new Request({
url: "hello.txt",
method: "get",
onSuccess: function(responseText, responseXML){
alert("Response: " + responseText);
}
}).send();
var sMsg = "Hello";
new Request({
url: "hello.php",
method: "post",
data: "msg=" + encodeURIComponent(sMsg),
onSuccess: function(responseText, responseXML){
alert("Response: " + responseText);
}
}).send();
}
Istnieją jeszcze dwie techniki asynchronicznych żądań HTTP – jedna oparta na atrybucie src 
obrazków oraz druga, bazująca na dynamicznym wczytywaniu skryptów JavaScript (JSONP) [Zak07]. 
35
Pierwsza,   wspomniana   technika   nie   jest   wykorzystywana   w   tym   opracowaniu   więc   zostanie 
pominięta. Dynamiczne wczytywanie skryptów bazuje na fakcie, że zewnętrzny dokument JavaScript 
zostaje pobrany przez przeglądarkę w momencie dodania elementów <script> go zawierających do 
strony. Kod po stronie przeglądarki może wyglądać następująco:
window.onload = function() {
var oScript = document.createElement("script");
oScript.type = "text/javascript";
oScript.src = "dynamicScript.php?functionToCall=dynScriptLoaded";
document.body.appendChild(oScript);
};
function dynScriptLoaded(sMessage){
alert("Dynamic script loaded with message: " + sMessage);
}
Zawiera on funkcję dynScriptLoaded(), która zostanie wykonana po załadowaniu kodu dynamicznego 
skryptu.   Zaś   po   stronie   serwera,   plik  dynamicScript.php,   jest   dynamicznie   generowanym   kodem 
programu Javascript, który może wyglądać następująco:
<?php header("Content-type: text/javascript"); ?>
var sMessage = "Hello!";
<?php echo $_GET["functionToCall"] ?>(sMessage);
Po załadowaniu skryptu   dynamicScript.php wyświetlony zostanie alert zawierający przesłaną 
wiadomość. Podstawową zaletą techniki dynamicznego skryptu JavaScript jest to, że pozwala ona 
obejść politykę bezpieczeństwa wspólnego pochodzenia, która nie pozwala wysyłać żądań HTTP do 
dokumentów nie znajdujących się w tej samej domenie, co strona na której jest wykonywany kod. 
Wadą   tego   sposobu   jest   to,   że   nie   pozwala   na   wysyłanie   żądań   POST.   Kłopotliwe   jest   także 
obsługiwanie   błędów,   ze   względu   na   brak   możliwości   ich   detekcji,   poza   odczekiwaniem   przez 
określony czas na odpowiedź.
Jakie typy danych są pobierane przez asynchroniczne żądania HTTP, opisane powyżej? Jednym 
słowem różne, choć najczęściej są to dokumenty tekstowe, XML, XSLT, HTML bądź kod Javascript 
[Zak06][Zak07].   Czasem   wykorzystywane   są   alternatywne   formaty   np.   JSON,   który   jest 
pełnoprawnym kodem Javascript i który dzięki temu, upraszcza parsowanie danych. 
Co jest potrzebne po stronie serwera? Dowolny serwer www, który będzie udostępniał żądane 
dokumenty. Najczęściej jest to apache z modułem PHP5, do dynamicznego generowania dokumentów 
i dostępu do bazy danych. [Zak07]
CORS   jest   standardem,   który   umożliwia   ominięcie   polityki   wspólnego   pochodzenia   w 
przeglądarce internetowej. W przeciwieństwie do JSONP, który umożliwia wysyłanie tylko żądań GET 
między różnymi domenami, CORS wspiera także żądania POST. Jest to stosunkowo nowy standard, 
dostępny przeglądarkach dopiero od kilku lat. Jest on obsługiwany przez firefoxa od wersji 3.5 
(wydanej w czerwcu 2009 roku), chrome od bardzo wczesnych wersji tej przeglądarki oraz Internet 
Explorer od wersji 8. Planowana jest jego implementacja w przeglądarce opera w wersji 12. Z punktu 
widzenia programisty użycie CORS to używanie obiektu XMLHttpRequest w standardowy sposób, 
bez żadnych zmian uwzględniających pochodzenie zasobów z innych domen. Obsługa standardu 
odbywa się przez przeglądarkę w transparentny dla programisty sposób. Jedynie po stronie serwera 
jest wymagany dodatkowy nagłówek http w odpowiedzi, który służy zdeterminowaniu adresów 
36
domen, spod których dany zasób jest dostępny.
W przeglądarce Internet Explorer funkcjonalność asynchronicznego i międzydomenowego 
żądania http jest zaimplementowana przypomocy obietku XDomainRequest. Tak samo jak w innych 
przeglądarkach wymagany jest dodatkowy nagłówek "Access­Control­Allow­Origin" w odpowiedzi 
serwer przy żądaniu o zasób.
2.4.4 XSLT i XPath
XSLT jest językiem, którego kod  źródłowy jest dokumentem XML. Służy on głównie do 
transformacji jednych dokumentów XML w inne dokumenty XML bądź inne dokumenty tekstowe. 
Powszechne jest jego użycie do przekształcania treści stron internetowych w dokumenty pdf, bądź 
transformowania dokumentów XML w strony HTML. Kod programu języka XSLT jest interpretowany 
przez procesor XSLT. Procesor ten na podstawie poleceń kodu programu przekształca dokumenty 
XML dostarczone do transformacji [Zak07][XSL99]. Obrazowo schemat ten został pokazany na rys. 19. 
Procesor XSLT 1.0 jest zaimplementowany we wszystkich popularnych przeglądarkach internetowych 
i   dlatego   chętnie   jest   on   wykorzystywany   przez   programistów   JavaScript   do   transformacji 
dokumentów XML, uzyskiwanych przy użyciu technologii Ajax, opisanej w następnym rozdziale.
Programy XSLT intensywnie korzystają z technologii XPath, do selekcjonowania interesujących 
fragmentów dokumentów XML [XPa99]. Dzięki XPath wybieranie węzłów w dokumentach jest dużo 
łatwiejsze. Technologia ta przypomina w pewnym sensie wyrażenia regularne, gdyż wyrażenia XPath 
mogą być równie zawiłe i niezrozumiałe. XPath jest częścią języka XSLT, lecz dostępne są także 
implementacje niezwiązane z XSLT. Przeglądarki internetowe udostępniają interfejs dla programistów 
języka JavaScript, który może posłużyć do używania XPath do wyboru węzłów dokumentów XML.
Składnia wyrażenia XPath składa się z dwóch części – węzła lub zbioru węzłów, którego 
elementów zapytanie ma dotyczyć oraz samego wyrażenia wyszukującego. Kilka przykładów zapytań 
XPath:
//X | //Y – wybierz wszystkie elementy X oraz Y z dokumentu.
X[1] – wybierz pierwsze dziecko X.
X[Z eq '10'] – wybierz dzieci X, które mają dziecko o nazwie Z i wartości '10'.
X[@a ne '10'] - wybierz dzieci X, które mają atrybut o nazwie a, który nie ma wartości '10'.
X[number(@a) < 10] – wybierz dzieci X, które zawierają atrybut a o wartości mniejszej od 10.
X/na:Y – wybierz wszystkie dzieci X o nazwie Y w dokumencie, które należą do przestrzeni nazw
„na”.
/X/Y[last() - 1] – wybierz przedostatnie dziecko X o nazwie Y, X jest głównym elementem
dokumentu (korzeniem).
X[sum(@a*) < 7] – wybierz dzieci X, których atrybuty sumują się do wartości mniejszej niż 7.
//*[count(X) = 2] – wybierz elementy, które mają dwójkę dzieci
//X[position() mod 2 = 0 ] - wybierz elementy X, które mają parzystą pozycje jako dzieci –
wybiera, co drugie dziecko.0
Poniższy kod JavaScript ilustruje użycie XPath do wyboru wartości 23.6 z dokumentu:
var sXmlSample = '<Root><ProcOut id="34"><Data>23.6</Data></ProcOut><ProcOut
id="14"><Data>27.4</Data></ProcOut></Root>';
var sXPath = "//Data[number(.) < 25]"; // wyrażenie XPath
if (window.ActiveXObject) { // IE
var oXmlDom = new ActiveXObject("Microsoft.XmlDom");
oXmlDom.loadXML(sXmlSample); // załaduj z ciągu znakowego
oXmlDom.setProperty("SelectionLanguage", "XPath");
var aNodes = oXmlDom.documentElement.selectNodes(sXPath);
} else { // DOM
var oParser = new DOMParser();
var oXmlDom = oParser.parseFromString(sXmlSample, "text/xml"); // załaduj z ciągu znakowego
var oResult = oXmlDom.evaluate(sXPath, oXmlDom, null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
37
var aNodes = new Array;
if (oResult != null) {
var oElement;
while (oElement = oResult.iterateNext()) {
aNodes.push(oElement);
}
}
}
for(var i = 0; i < aNodes.length; ++i){
alert("Numb = " + aNodes[i].firstChild.nodeValue); // wyświetla „Numb = 23.6”
}
2.4.5 Comet
Bolączką programistów systemów bazujących na Ajax, są programy które oprócz interakcji 
typu żądanie – odpowiedź, muszą także obsługiwać dane wysyłane przez serwer bez ich żądania 
przez   klienta.   Jest   to   o   tyle   kłopotliwe,   że   technika   Ajax   bazuje   na   żądaniach   HTTP,   przez   co 
dziedziczy  charakter typu żądanie – odpowiedź tego protokołu.  Programiści Javascript opracowali 
kilka technik umożliwiających emulowanie wysyłania danych przez serwer, które zostaną krótko 
omówione w tym rozdziale. Technika wysyłania danych od serwera ma różne nazwy, m. in. Comet i 
HTTP Streaming [Zak07].
Najbardziej   oczywistym   sposobem   emulowania   wysyłania   danych   przez   serwer   jest 
nadmiarowe (pooling) wysyłanie   żądań  HTTP [Zak07].  Klient  wysyła  więcej  żądań, przy użyciu 
obiektów  XMLHttpRequest, bądź dynamicznych skryptów Javascript, niż jest to mu potrzebne. Dzięki 
temu serwer zawsze dysponuje żądanie HTTP, które może użyć do wysłania danych. Wadą tego 
sposobu jest nadmiarowość, która powoduje zwiększone użycie zasobów, co może mieć znaczenie 
przy dużym ruchu sieciowym. Rozwiązanie to może być także zbyt wolne przy dużych opóźnieniach 
sieciowych.
Innym sposobem jest użycie techniki ukrytej ramki [Zak07]. Do zilustrowania tej techniki, 
użyjmy kodu po stronie klienta z przykładu 4, z ukrytą ramką, z rozdziału Ajax, tego opracowania. 
Zmienimy   adres   żądane   dokumenty   z  hello.html,   na   dynamicznie   generowany  hello.php,   którego 
zawartość jest następująca:
<html><head></head><body>
<script type="text/javascript">
alert("Hello!");
</script>
<?php
// wyślij dane
ob_flush();
flush();
sleep(10); // odczekaj 10 sek
?>
<script type="text/javascript">
alert("Hello again!");
</script>
</body></html>
Kod ten spowoduje wyświetlenie okna z napisem „Hello!”, a po 10 sekundach następnego, z 
napisem   „Hello   again!”.  Podczas   używania  tej,   oraz   innych   technik   Comet   należy  pamiętać,   że 
serwery www mają ograniczony czas połączenia, oraz że połączenie może zostać zerwane. Aby 
wykryć takie sytuacje kod JavaScript po stronie serwera powinien od czasu do czasu sygnalizować, że 
połączenie jest otwarte np. wysyłając ustaloną wiadomość lub wywołując ustaloną funkcję. Kod po 
stronie klienta powinien natomiast sprawdzać, czy otrzymywane są potwierdzenia od serwera. W 
przypadku wykrycia braku potwierdzeń połączenie powinno zostać wznowione. Wadą techniki jest 
38
to, że przeglądarki w czasie połączenia zachowują się jakby ładowana była strona tj. zmieniają kursor 
na zajęty oraz zmieniają powiadomienia na pasku statusu na ładowanie.
Pozostałe techniki Comet są charakterystyczne dla konkretnych przeglądarek i są używane, by 
wyeliminować niekorzystne zachowanie interfejsu użytkownika przeglądarek podczas korzystania z 
techniki   ukrytej   ramki   [Zak07].   W   przeglądarce   Internet   Explorer   używany   jest   obiekt   ActiveX 
HTMLFile. Obiekt ten symuluje okno przeglądarki, przez co można dodać do niego ramkę, która 
będzie   służyć   do   realizacji   techniki   Comet.   W   przeglądarce   Opera   można   wykorzystać 
zaimplementowaną w tej przeglądarce technologię  Server­Sent DOM Events. Sprowadza się to do 
dodania elementu HTML, który jest zdarzeniem i którego źródło wskazuje na dokument na serwerze. 
Następnie do tego elementu przypisuje się funkcję nasłuchującą, która jest wykonywana w momencie 
wysłania zdarzeń przez serwer.
W przeglądarkach bazujących na silniku Gecko, jak Mozilla FireFox, oraz tych bazujących na 
silniku   WebKit,   jak   Chrome,   można   zrealizować   to   w   przyjemny   dla   programisty   sposób.   Do 
komunikacji   używa   się   obiektu    XMLHttpRequest,  któremu   przypisuje   się   funkcję   wywoływaną 
podczas  zdarzenia  ReadyStateChange.  Zdarzenie  to  jest  generowane  podczas  każdego   otrzymania 
danych od serwera w tych przęglądarkach.
2.4.6 Websocket
Rozdziały Ajax oraz Comet w tym opracowaniu powinny uświadomić każdego, jak wiele 
pracy musieli włożyć programiści Javascript, aby osiągnąć interaktywność programów na poziomie, 
który spotykamy współcześnie.  Niemniej, opisane techniki są tylko sztuczkami omijającymi sztuczne 
ograniczenia języka JavaScript w przeglądarkach. Kreatywność programistów została zauważona 
przez twórców samych przeglądarek i dlatego opracowywany standard HTML 5 zawiera obsługę 
technologii websocket. Sam standard HTML 5 ciągle jeszcze ewoluuje, lecz duża jego część jest już 
zaimplementowana w przeglądarkach, w tym websockety.
Websocket jest tym, co brakowało w JavaScript, a jest dostępne dla tradycyjnych programów od 
samego   początku   internetu.   Websocket   jest   protokołem   sieciowym,   służącym   do   emulowania 
tradycyjnych   gniazd   sieciowych   na   potrzeby   serwisów   sieciowych   i   programów   JavaScript.   Sam 
protokół jest standaryzowany przez IETF [Web11], zaś jego obsługa i interfejs programistyczny w 
przeglądarkach jest standaryzowane przez W3C [WPI11]. Jego użycie pozwala uniknąć narzutu kodu i 
komplikacji, jakie są częścią Ajax oraz Comet.
Z punktu widzenia programisty JavaScript użycie websocket jest intuicyjne:
var socket = new WebSocket('ws://distos.net:7636/app');
socket.onopen = function(){
// kod wykonywany po otwarciu połączenia
socket.send("message", "userProtocol"); // wyślij wiadomość
};
socket.onclose = function(){
// kod wykonywany przy zamknięciu połączenia
};
socket.onmessage = function(oMsg){
var sMsg = oMsg.data; // odczytanie przesłanych danych
};
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec
Dariusz_Jania_exec

More Related Content

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Dariusz_Jania_exec