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ť. :)
Ahoj ANTARAN,
OdpovedaťOdstrániť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.
ty si cisty blazen. riesenia sa nemozu uverejnovat!!!
OdpovedaťOdstrániťPre revoltu:
OdpovedaťOdstrániť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
Ahoj Roman
OdpovedaťOdstrániť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
Re revolta:
OdpovedaťOdstrániť...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...
Ahoj Antaran,
OdpovedaťOdstrániť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.
ahoj Roman
OdpovedaťOdstrániť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 :)
2"Anonymný":
OdpovedaťOdstrániť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
Ahoj Antaran,
OdpovedaťOdstrániť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 ------------------------------------------------
...ja som to pochopil presne tak isto ako ty a vysledky, ktore su uverejnene v tej programatorskej ulohe su urcite dobre...
OdpovedaťOdstrániť...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...
Ahoj Antaran,
OdpovedaťOdstrániť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.
nevim jestli vite ale je uz venku i tohle http://3537.sk/virusovy-analytik.html
OdpovedaťOdstrániť