štvrtok 30. apríla 2009

CR4CK ME (časť 1.)

Tento blog voľne nadväzuje na predchádzajúcu programátorskú úlohu, tentokrát sa pozriem na úlohu pre analytikov počítačových infiltrácií. Ako Java programátor som našťastie v bežnom živote vzdialený milióny riadkov kódu od assembleru, ale kto by odolal výzve. :)

! VAROVANIE: tento článok obsahuje riešenie, alebo jeho časti, ktoré môžu, ale nemusia byť správne, každopádne ak ste úlohu ešte neriešili a chcete si ju urobiť samostatne, tak ďalej nečítajte a vráťte sa k tomuto textu až keď si budete chcieť porovnať svoje zistenia !

Zadanie úlohy je možné nájsť na http://www.3537.sk/virusovy-analytik.html a skrátene znie takto:

Predložená úloha - program s názvom ESET_crackme.exe bol navrhnutý za účelom otestovania vašich schopností v oblasti reverzného inžinierstva programov. Vašou úlohou je vykonať analýzu tohto programu (jeho programového kódu). Analýza programu (programového kódu) podáva komplexné informácie o činnosti programu, podmienkach potrebných pre vykonanie určitých akcií v programe a podobne. Programový kód môže obsahovať skryté texty, podmienené úlohy, ochranu pred ladiacimi programami a pod.

Prvá vec, ktorú vyskúšam je proste EXE súbor iba spustiť, aby som vedel ako sa správa keď ho neladím a aby som vedel ako sa javí bežnému užívateľovi.
  • prvý pokus...rezidentná ochrana môjho antivíru mi zablokovala prístup k súboru s tým že je to možno vírus, :) mno nič vypnem antivír
  • druhý pokus...rezidentná ochrana môjho anti-adware programu mi zablokovala prístup k súboru, taktiež som ju vypol
  • tretí pokus...program vypíše chybové hlásenie, v zmysle, že mu chýba knižnica rtl70.bpl, nevadí stiahnem požadovanú knižnicu a nakopírujem ju do systémového adresára
  • štvrtý pokus...hurá :) program vypíše informačný text do konzoly, počká si na stlačenie klávesy a skončí
Pamätám si, že kedysi strašne dávno som si naprogramoval niečo v C++ Builderi 3 a keď som sa s tým chcel pochváliť kamarátovi, tak ma čakalo podobné nemilé prekvapenie, u mňa samozrejme program bežal, ale u každého kto nemal nainštalovaný C++ Builder alebo Delphi bol problém. Každopádne môj prvý dojem z programu je taký, že bol asi napísaný ako konzolová aplikácia v Pascale konkrétne v Delphi 7 a ak v ňom bol použitý assembler, tak asi len inline priamo v Pascalovských zdrojákoch.

Predtým ako má vôbec zmysel začať ladiť tento program je potrebné zistiť či je skomprimovaný a keď áno tak čím. Na tento účel existuje určite množstvo nástrojov, ja som si zvolil PEiD.



Ako je zrejmé z obrázkov, tak po miernej zmene nastavenia z Normal Scan na Hardcore Scan, PEiD identifikuje, že súbor je skomprimovaný programom UPX. Čo je dobrá správa, pretože UPX je open source, to znamená, že je ho možné voľne stiahnuť, existuje k nemu verejná dokumentácia a sú verejné aj jeho zdrojové kódy. Najjednoduchší spôsob ako teda súbor rozpakovať je stiahnuť si UPX a skúsiť to automaticky.



Hmmm, až také ľahké to nebude, zrejme bola PE hlavička nejakým spôsobom modifikovaná, ale "vygooglit" si podrobný návod ako rozpakovať UPX manuálne dokonca aj s odkazmi na zdrojový kód UPX a vysvetlivkami je len otázkou chvíľky. V návode pre riešiteľov sa odporúča ako veľmi dobrý ladiaci program OllyDbg, tak v ňom teda otvorím ESET_crackme.exe a privíta ma hlásením, ktoré ma upozorňuje, že analýza kódu bude zrejme chybná, lebo telo programu je skomprimované.



Návod na manuálne rozbalenie UPX archívu hovorí, že je potrebné hľadať inštrukciu POPAD (inštrukcia obnoví registre pre všeobecné použitie zo zásobníka, je to prakticky opak inštrukcie PUSHAD, na ktorej sa práve nachádzame), ktorú nasleduje inštrukcia JMP (inštrukcia urobí nepodmienený skok). Tak si vyhľadáme [Ctrl-S], [] Entire block, POPAD.



Na ďalšom obrázku je vidieť, že sme úspešne našli inštrukciu POPAD, za ktorou sa nachádza nepodmienený skok JMP a práve naň si dáme breakpoint [F2].



Spustíme program [F9] až po breakpoint a posunieme sa ešte o jednu inštrukciu [F7] cez náš JMP a mali by sme mať rozpakovaný program a zároveň by sme mali byť nastavení na originálnom vstupnom bode aplikácie.



Keďže by bolo zbytočné tento postup opakovať zakaždým keď budeme ladiť program, tak použijeme plugin na dumpovanie procesov a vytvoríme si týmto spôsobom nový EXE súbor, ale už rozpakovaný a s novým entry pointom ako je to na nasledujúcich dvoch obrázkoch.



Keď už máme rozpakovaný program, urobíme si na ňom takú predbežnú analýzu, aby sme zistili aký má potenciál. Napríklad, pracuje zo súbormi? Zapisuje alebo číta niečo z registrov windows? Komunikuje s inými počítačmi? Na to aby sme zistili či má program potenciál robiť nasledovné veci si ho otvoríme v programe IDA Pro Free. A budeme skúmať aké knižnice používa, aké funkcie windows volá a aké textové reťazce obsahuje, ale to až v budúcej časti, ak si nájdem čas a ak sa mi bude chcieť. :)

12 komentárov:

  1. Ahoj ANTARAN,
    v C++ programujem len 2 tyzdne a skusam urobit program s Tvojimi algoritmami. Ale nerozumiem preco mi to vyhadzuje chybu (ako je na obrazku),
    robim to v Borland C++ Builder 6
    Najskor som skusal algoritmus s nacitanim podpisu ako celeho retazca a prehladavanie zotriedeneho pola zaznamov, pri malom subore to preslo za 1 sec., pri velkom to bolo veeelmi dlho, ale vysledky boli spravne.
    Popis mojeho vytvoru aj s obrazkom chyby som dal na:
    http://www.upnito.sk/download.php?dwToken=309d86c26137a22e8418d8e58fb3944e
    Vopred dakujem za odpoved,
    Roman.

    OdpovedaťOdstrániť
  2. ty si cisty blazen. riesenia sa nemozu uverejnovat!!!

    OdpovedaťOdstrániť
  3. Pre revoltu:
    Moj prispevok sa tyka programatorskej ulohy,
    ktora uz bola uzavreta a rovnako uzavrete je asi aj forum, ktore mal ANTARAN na tu temu. A kedze nemam na neho mail, tak som to dal do tohoto fora, ospravedlnujem sa. Ak by mi s tym vedel niekto poradit,
    prosim napiste na rkysucky@gmail.com

    OdpovedaťOdstrániť
  4. Ahoj Roman

    Ja uz nerobim v C-cku roky, ten algoritmus bola len taka recesia/nostalgia, ale pozrel som si tu chybu aj ten TXT subor.

    Ta chyba je na tom obrazku bohuzial odseknuta, ale povedal by som po prezreti toho TXT suboru, ze nemas spravny typ premennnej \"fileDescriptions\".

    Ty sa mu snazis podhodit list<FileDescription> a ja tam mam list<FileDescription*>, tj. ja mam list ukazovatelov na FileDescription a ty mas list FileDescription. (hviezdicka navyse :))

    Ja som to prepisoval z Javy a tam sa pouzivaju iba referencie, takze mi pripadalo prirodzene dat tam ukazovatele.

    ant

    OdpovedaťOdstrániť
  5. Re revolta:

    ...to je len rozpakovanie toho EXE suboru, na to by prisiel kazdy po hodine "googlenia", ale ak budu vyhrady zo strany zadavatelov ulohy, tak ten clanok samozrejme ihned zmazem...

    OdpovedaťOdstrániť
  6. Ahoj Antaran,
    dakujem za pomoc. Myslel som si totiz, ze Tebe
    ten C++ algoritmus bezal, kedze si pod nim mal
    komentar, ze vykon je porovnatelny s Java 2 riesenim :) Tiez sa mi zdalo, ze je to tam divne -
    raz je tam pointer, raz struktura, ale kedze v C
    len zacinam, tak som si myslel, ze to je nejaka finta. Skusim to teda nejako upravit, bude to dobre cvicenie. Ked som tam skusil dat fileDescriptions*, tak to vypisalo chybu Expression syntax, asi musim zadefinovat list poinerov a prekopat to hlbsie.
    Vela stastia pri CRACK ME ulohe,
    Roman.

    OdpovedaťOdstrániť
  7. ahoj Roman

    asi som sa zle vyjadril...ten algoritmus normalne bezal, tj. je odskusany, ziadne struktury v nom pouzite niesu, iba jeden class...

    moja definicia vyzera takto:

    list<FileDescription*> fileDescriptions;

    a plnim ju v skratke takto:

    FileDescription* fileDescription = new FileDescription();
    fileDescriptions.push_back(fileDescription);

    ...dovod preco pouzivam listy pointrov na FileDescription a nie priamo listy s FileDescription je taky, ze povodne som mal tych listov viac, list na vsetky, list pre unikatne, list pre duplikaty, tak ako v jave a vsetky tie listy ukazovali na tie iste objekty...

    ...v zasade mas dve moznosti, bud prerobis tvoju metodu, ktora nacitava data do pamate tak aby pouzivala list<FileDescription*>, to mi pripada jednoduchsie, alebo prerobis moju metodu aby pouzivala list<FileDescription>, to budes mat tazsie, lebo budes musiet menit moj kod :)

    ...ak si nebudes vediet poradit, kludne mi napis poslem ti cele zdrojaky...ale najprv sa posnaz sam :)

    OdpovedaťOdstrániť
  8. 2"Anonymný":
    sorry, to nebolo na teba to bolo na toho mantaka co tu zverejnil postup ako unpacknut target, na toho "antaran"-a.

    2"antaran":
    to si tu nemal davat vobec, a nie ze ty to vymazes ak bude mat eset pripomienky. eset nema ani sajn, ze tu nieco je.

    revolta

    OdpovedaťOdstrániť
  9. Ahoj Antaran,
    takze dakujem za cenne rady, upravil som nacitavanie a Tvoj algoritmus slape bez problemov, ALE:
    ... podla zadania ESETu je podpis suboru postupnost celych, nezapornych 32 bitovych cisiel
    ... to znamena, ze maximalne cislo v hexa tvare bude FFFFFFFF, nacitavat teda budem vzdy 8 znakov, prelozim ich do Long
    a ulozim do pola podpisu
    ... a z toho mi vyplyva, ze ak mam subor s riadkami o suboroch:
    "f1" 3a798531 21ee03f5
    "f2" 3a79853
    tak obidva subory su jedinecne, ale ked bude mat f2 podpis 3a798531, tak je prefixom pre f1, ak bude mat 3a798531 21,
    tak znovu nebude prefixom, musia sa zhodovat 8 bytove sekvencie !
    ... mam niekde chybu v uvahe ?
    Lebo potom mi vychadza napr. pre set_small.dat
    pocet jedinecnych 886 a prefixovych 56
    Este prikladam moj algoritmus nacitania:
    //--- nacitanie a parsovanie riadkov suboru ------------------------------------
    ifstream Subor;
    long RiadPoc = 0;
    long poz;
    string strM,strP;
    list/FileDescription*/ fileDescriptions;
    Subor.open(cboSubor->Text.c_str());
    string StrHex = "";
    string::iterator iterHex;
    int ValDec = 0;
    while ( !Subor.eof() ) {
    getline(Subor,Riadok);
    if (Riadok.empty() == false){
    FileDescription* Zaznam = new FileDescription();
    poz = Riadok.find_first_of(" ");
    strM = Riadok.substr(0,poz);
    Zaznam->setName(strM);
    strP = Riadok.substr(poz+1,Riadok.length()-poz+1);
    Zaznam->clrSignature();
    StrHex = "";
    ValDec = 0;
    for (iterHex = strP.begin();iterHex < strP.end();iterHex++){
    if (StrHex.length() < 8){ // max.8 bytove hexa cislo
    if ((*iterHex >= 47 && *iterHex <=57) ||
    (*iterHex >= 97 && *iterHex <=102) ||
    (*iterHex >= 65 && *iterHex <=70))
    StrHex = StrHex + *iterHex;
    }
    else
    {
    sscanf(StrHex.c_str(), "%x", &ValDec);
    Zaznam->addSignature(ValDec);
    StrHex = "";
    ValDec = 0;
    if ((*iterHex >= 47 && *iterHex <=57) ||
    (*iterHex >= 97 && *iterHex <=102) ||
    (*iterHex >= 65 && *iterHex <=70))
    StrHex = StrHex + *iterHex;
    }
    }
    if (StrHex.length() > 0){
    sscanf(StrHex.c_str(), "%x", &ValDec);
    Zaznam->addSignature(ValDec);
    }
    fileDescriptions.push_back(Zaznam);
    RiadPoc++;
    }
    }
    Subor.close();
    //--- koniec nacitavania suboru ------------------------------------------------

    OdpovedaťOdstrániť
  10. ...ja som to pochopil presne tak isto ako ty a vysledky, ktore su uverejnene v tej programatorskej ulohe su urcite dobre...

    ...zrejme je v chyba nacitavani tych zaznamov, ak ti mozem poradit, tak si urob vlastny malicky testovaci subor, v obycajnom notepade, copy-pastni tam napriklad toto:

    "f0" f1484042 fecdc5fb b0fdae86
    "f1" f1484042 fecdc5fb
    "f2" 285ec121

    ...a podrobne si odlad ako sa ti to nacitalo, pripadne si aj preloz na kalkulacke, ci mas tie cisla dobre skonvertovane, tu mas unikatne dve "f0" a "f2". A jeden duplikat "f1"...

    ...ja som ten subor nejak extra neskumal, ale myslim, ze tie cisla su HASHe, takze vzdy maju dlzku 32 bitov...

    OdpovedaťOdstrániť
  11. Ahoj Antaran,
    takze odskusal som si prehladavanie na Tvojom aj na inych kratkych testovacich suboroch. Vsjo OK.
    Ked to spustim na set_small.dat, tak nedostanem tie 851 vysledky. Pozrel som si len tak namatkovo data v tom smalle, tak napriklad na konci riadka pre "f0" je 7-miestny zapis ed7430d a tiez v podpise pre "f1" a "f94" je retazec 5822a2f
    Dalsie som nehladal a pockam si, kym ESET konecne zverejni vysledky, teda ked ich vobec zverejni (alebo to este nemaju spocitane ? :))
    Zatial som si urobil beta verziu programu, chcem do neho dorobit este moznost porovnavania znak po znaku a potom budem spokojny ;) Mozes si to stiahnut odtialto:
    http://www.upnito.sk/download.php?dwToken=b35d729c3481e58ef7a68daebeb69d6b
    Vo vyslednom subore je ulozeny podpis v decimalnom tvare, takze si mozes overit, ze preklad hex2dec funguje ok...

    "f1": f1484042 fecdc5fb = 40480440984274898427

    Zatial ahoj, este raz diky za pomoc,
    Roman.

    OdpovedaťOdstrániť
  12. nevim jestli vite ale je uz venku i tohle http://3537.sk/virusovy-analytik.html

    OdpovedaťOdstrániť