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.