Univerza v Ljubljani
Fakulteta za raˇ cunalniˇ stvo in informatiko
Klemen Jesenovec
Statiˇ cna forenziˇ cna analiza slabogramja
MAGISTRSKO DELO
MAGISTRSKI PROGRAM DRUGE STOPNJE RA ˇCUNALNIˇSTVO IN INFORMATIKA
Mentor : doc. dr. Boˇstjan Slivnik
Ljubljana, 2021
Avtorske pravice. Rezultati magistrskega dela so intelektualna lastnina avtorja in Fakultete za raˇcunalniˇstvo in informatiko Univerze v Ljubljani. Za objavljanje ali izkoriˇsˇcanje rezultatov magistrskega dela je potrebno pisno soglasje avtorja, Fakultete za raˇcunalniˇstvo in informatiko ter mentorja.
©2021 Klemen Jesenovec
Kazalo
Povzetek Abstract
1 Uvod 1
2 Sorodna dela 5
3 Statiˇcna analiza 9
3.1 Orodja . . . 10
4 Obratno inˇzenirstvo na arhitekturi x86 17 4.1 Zgradba izvrˇsljivih datotek . . . 17
4.2 Pogojni stavki . . . 19
4.3 Zanke . . . 21
4.4 Tabele in strukture . . . 22
4.5 Funkcije . . . 23
4.6 Posebnosti objektno usmerjenih programskih jezikov . . . 26
5 Zmaliˇcenje programske kode 29 5.1 Desinhronizacija razbirnika . . . 30
5.2 Dinamiˇcno izraˇcunan naslov . . . 31
5.3 Zmaliˇcenje kontrolnega toka . . . 31
5.4 Skrivanje uvoˇzenih funkcij . . . 33
5.5 Polimorfiranje in metamorfiranje . . . 33
KAZALO
5.6 Pakiranje . . . 34
6 Program Ghidra 37
6.1 Potek dela . . . 38 6.2 Orodja . . . 41 7 Primer statiˇcne analize slabogramja 55 7.1 Priprava delovnega okolja . . . 55 7.2 Analiza slabogramjaECCENTRICBANDWAGON . . . 56 7.3 Analiza slabogramjaSLOTHFULMEDIA . . . 68
8 Zakljuˇcek 91
Seznam uporabljenih kratic
kratica angleˇsko slovensko
DDOS distributed denial-of-service porazdeljena zavrnitev storitve DLL dynamic-link library dinamiˇcna knjiˇznjica
IDA Interactive Disassembler Interaktivni razbirnik LIFO last in first out zadnji noter prvi ven
NSA National Security Agency Nacionalna varnostna agencija PE portable executable prenosna izvrˇsljiva datoteka RTTI run-time type information informacije o tipih med
tekom programa
SRE software reverse engineering obratno inˇzenirstvo programske opreme
WSL Windows subsystem for Linux podsistem za Linux na
operacijskem sistemu Windows
Povzetek
Naslov: Statiˇcna forenziˇcna analiza slabogramja
Slabogramje dandanes predstavlja veliko nevarnost raˇcunalniˇskim siste- mom po celem svetu. Da se lahko pred slabogramjem uˇcinkovito zavarujemo, je potrebno razumeti njegovo delovanje, kar doseˇzemo z analizo slabogramja.
V magistrski nalogi se osredotoˇcimo na statiˇcne pristope analize slabogramja napisanega za arhitekturo x86. Predstavimo lastnosti programov napisanih za arhitekturo x86 in tehnike zmaliˇcenja tovrstnih programov. Predstavimo nov program za obratno inˇzenirstvo Ghidra in opiˇsemo njegova glavna orodja.
S programom Ghidra na dveh primerih slabogramja pokaˇzemo praktiˇcno ana- lizo slabogramja in povzamemo njuno delovanje.
Kljuˇ cne besede
obratno inˇzenirstvo, obratno prevajanje, slabogramje
Abstract
Title: Static forensic analysis of malware
Today malware represents a large threat to computer systems worldwide.
To effectively defend against malware, we first need to understand its oper- ation, which we accomplish with malware analysis. In this master’s thesis, we focus on static analysis approaches of malware written for the x86 archi- tecture. We present properties of programs written for the x86 architecture and their obfuscation techniques. We present a new program for reverse en- gineering called Ghidra and describe its main tools. We show the practical analysis of two malware samples with Ghidra and summarize their behavior.
Keywords
reverse engineering, decompilation, malware
Poglavje 1 Uvod
Slabogramje (angl. malware) je kakrˇsnakoli programska oprema, ki deluje z namenom povzroˇcanja ˇskode raˇcunalniˇskim sistemom ali njihovim uporabni- kom. Obstaja ˇze, odkar obstajajo raˇcunalniˇski sistemi. O njem je pisal ˇze oˇce raˇcunalniˇstva John von Neumann [1]. Razvrstimo ga lahko na veˇc vrst glede na naˇcine ˇsirjenja in obnaˇsanja. Spodaj je navedenih nekaj najbolj pogostih vrst z opisi delovanja [2]:
Virusi so slabogramje, ki se ˇsiri tako, da svojo zlonamerno programsko kodo vstavi v druge neˇskodljive programe. Primer tega je injekcija v DLL.
Crvi so slabogramje, ki delujejo samostojno in se aktivno ˇsirijo s pomo-ˇ ˇcjo varnostnih ranljivosti preko omreˇzja, naprav USB, ipd.
Izsiljevalno slabogramje navadno kriptografsko zaˇsifrira podatke upo- rabnika raˇcunalniˇskega sistema in nato za deˇsifrirni kljuˇc zahteva od- kupnino.
Slabogramje, ki napadalcu omogoˇca nadzor nad okuˇzenim raˇcunalni- ˇskim sistemom in svoje delovanje prikrije uporabniku tega raˇcunalni- ˇskega sistema (angl. rootkit).
1
2 1. UVOD
Vohunsko slabogramje spremlja dogajanje na okuˇzenem raˇcunalniˇskem sistemu in o tem poroˇca napadalcu.
Oglaˇsevalno slabogramje uporabniku okuˇzenega raˇcunalniˇskega sistema prikazuje nezaˇzelene oglase. V zadnjih letih je na porastu tudi podvrsta takˇsnega slabogramja, ki ponudniku oglaˇsevalnih storitev poˇsilja laˇzne podatke o ogledu oglasov.
Mreˇza botov je slabogramje, ki okuˇzi skupino raˇcunalniˇskih sistemov, ki jih lahko napadalec uporablja za izvajanje ˇskodljivih dejanj, kot je naprimer napad DDOS (Distributed Denial of Service).
Slabogramje se lahko med seboj moˇcno razlikuje v namenu, po stopnji zlo- namernosti in po kompleksnosti programa. Prvi ˇcrv z imenom Creeper, ki ga je ustvaril Bob Thomas leta 1971 in se je ˇsiril preko ARPANETa, je bil zelo preprost. Edina ˇskoda, ki jo je povroˇcil, je bil izpis niza: ”I’M THE CREEPER; CATCH ME IF YOU CAN”.
Eno najkompleksnejˇsih slabogramij, ki naj bi ga razvila ameriˇska Naci- onalna varnostna agencija (NSA) nekje med 2005 in 2010, je Stuxnet [3].
Slabogramje je ciljalo Iranski jedrski program, kjer je okuˇzilo raˇcunalniˇske sisteme in krmilnike PLC (slika 1.1), ki so bili zadolˇzeni za nadzor centrifug za oplemenitev jedrskega goriva. Slabogramje je nadzorni ploˇsˇci prikazovalo normalne vrednosti, medtem pa je sˇcasoma uniˇcevalo centrifuge.
Slika 1.1: Siemensov krmilnik PLC Simatic S7-300, na katerega je ciljal Stuxnet.
3 Slabogramje je ˇse dandanes velik problem v raˇcunalniˇski varnosti. Zato se razvijajo orodja, ki ga poskuˇsajo prepoznati in odpraviti. Da lahko slabo- gramje pravilno prepoznamo, je potrebna analiza slabogramja, ki jo delimo na dve vrsti [4]:
Statiˇcna analiza poskuˇsa iz binarnih datotek, ki sestavljajo slabogra- mje, izluˇsˇciti njegovo delovanje brez dejanskega poganjanja slabogra- mja. Ker za slabogramje navadno nimamo dostopa do izvorne kode, so glavna orodja za tovrstno analizo razbirniki, ki so zmoˇzni iz binarne datoteke rekonstruirati izvorno kodo zbirnika.
Dinamiˇcna analiza poskuˇsa razumeti delovanje slabogramja z dejan- skim poganjanjem slabogramja. Da se izognemo nezaˇzelenemu ˇsirjenju slabogramja, ga navadno poganjamo v nadzorovanem okolju, ki ga ime- nujemo peskovnik (angl. sandbox).
Za analizo primera slabogramja se navadno uporabljata obe metodi, saj imata vsaka svoje prednosti in slabosti. Statiˇcna analiza je ˇcasovno zelo potratna in zahteva veliko izkuˇsenj. Poleg tega je lahko slabogramje zmaliˇceno (angl.
obfuscated), da ˇse dodatno oteˇzi statiˇcno analizo (npr. uporabljanje ukazov, ki zmedejo razbirnik, a se na pravem sistemu ˇse vedno izvedejo).
Dinamiˇcna analiza je enostavnejˇsa. Slabogramje je lahko napisano na naˇcin, da oteˇzuje dinamiˇcno analizo (npr. slabogramje zazna, da je pognano v peskovniku in se ne poˇzene). Poleg tega lahko slabogramje izvede svojo kodo z zamikom in te kode med dinamiˇcno analizo ne bomo mogli opaziti.
To magistrsko delo se osredotoˇca na statiˇcno analizo slabogramja, pred- vsem na obratno inˇzenirstvo binarnih datotek. Osredotoˇcili se bomo na ope- racijski sistem Windows in binarne datoteke za arhitekturo x86. Velik deleˇz predstavljenega znanja se lahko prenese tudi na ostale arhitekture in ope- racijske sisteme. V magisterskem delu bomo uporabili in predstavili dokaj nov program za obratno inˇzenirstvo Ghidra [5], ki ga je razvila ameriˇska Nacionalna varnostna agencija in ga kot odprtokodni program objavila leta 2019.
4 1. UVOD
Poglavje 2 Sorodna dela
Slabogramje in analiza programov se v literaturi pojavljata ˇze odkar obsta- jajo prvi programi in raˇcunalniˇski sistemi [1]. Sprva so programerji pro- grame pisali v zbirniku na naˇcin, ki je bil programerju ˇcim bolj razumljiv.
Poslediˇcno je bila statiˇcna analiza enako zahtevna kot samo programiranje.
Z razvojem prevajalnikov se je strojna koda zaˇcela bistveno razlikovati od izvorne kode, kar je oteˇzilo statiˇcno analizo programov. Ko gre za analizo slabogramja, je strojna koda navadno ˇse dodatno zmaliˇcena prav z namenom oteˇzitve statiˇcne analize, saj se tako ˇzelijo pisci slabogramja izogniti njego- vemu odkritju. Podroˇcje analize slabogramja je zelo aktivno, saj se tehnike zmaliˇcenja nenehno razvijajo. Uveljavljajo se tudi novi programi in tehnike analize.
V literaturi zasledimo sploˇsna dela o obratnem inˇzenirstvu programske opreme in njegovega razumevanja. O obratnem inˇzenirstvu, predvsem pa o njegovi uporabi pri razumevanju zastarelih programskih sistemov, govori ˇclanek ”Reverse engineering: A roadmap” [6]. Celostno je obratno inˇzenirstvo programske opreme predstavljeno v knjigi ”Reversing: secrets of reverse en- gineering” [7]. V njej so obravnavane teme o osnovah obratnega inˇzenirstva, nizkonivojski programski opremi, posebnostih operacijskega sistema Win- dows, orodjih za obratno inˇzenirstvo, dekodiranju podatkovnih formatov, obratnem inˇzenirstvu slabogramja, piratstvu in zaˇsˇciti kopiranja program-
5
6 2. SORODNA DELA ske opreme, tehnikah zmaliˇcenja programske opreme in obratnem prevajanju programske opreme.
Antivirusni programi, ki za odkrivanje slabogramja uporabljajo algori- tem ujemanja vzorcev, obiˇcajno pregledujejo le strukturo programa in ne upoˇstevajo semantike ukazov. Razvoj algoritma za klasifikacijo slabogra- mja s pomoˇcjo metode obˇcutljive na semantiko ukazov je opisan v ˇclanku
”Semantics-aware malware detection” [8]. Razvit je algoritem, ki je odporen na pogoste tehnike zmaliˇcenja slabogramja.
V literaturi lahko najdemo ˇclanke o odkrivanju zmaliˇcene kode. Pogo- ste oblike slabogramja so pregledane v ˇclanku ”Survey on malware detec- tion methods” [9]. Opisane so tehnike zmaliˇcenja kode in teoretiˇcni al- goritem za zaznavo slabogramja. Predstavljena je tudi struktura in funk- cionalnost zmaliˇcenega slabogramja. Tehnike zmaliˇcenja slabogramja, ki vkljuˇcujejo ˇsifriranje, polimorfiˇcno in metamorfiˇcno slabogramje so predsta- vljene v ˇclanku ”Malware obfuscation techniques: A brief survey” [10]. Pred- stavljeni so tudi trendi, ki naj bi se v slabogramju pojavljali v prihodnosti.
Novejˇsi pristopi poskuˇsajo slabogramje statiˇcno analizirati tudi s pomoˇcjo umetne inteligence. Primerjava raznih pristopov statiˇcne analize slabogra- mja, ki uporabljajo strojno uˇcenje, je opisano v delu ”Static malware analysis using mechine learning methods” [11]. Razliˇcni pristopi statiˇcne analize sla- bogramja, ki uporabljajo strojno uˇcenje, so praktiˇcno ovrednoteni v ˇclanku
”Machine learning aided static malware analysis: A survey and tutorial” [12].
Izdelan je vodiˇc o rabi razliˇcnih tehnik strojnega uˇcenja, ki jih lahko upora- bimo za statiˇcno doloˇcanje lastnosti datotek PE (Portable Executable).
Pojavljajo pa se tudi ˇclanki o slabogramju, ki cilja mobilne operacijske sisteme. Najnovejˇse metode odkrivanja in analize slabogramja, ki je name- njeno operacijskemu sistemu Android so raziskane v ˇclanku ”The evolution of Android malware and Android analysis techniques” [13]. Predstavljena je tudi uˇcinkovitost teh metod.
V tem delu se osredotoˇcimo predvsem na statiˇcno analizo programov v programu Ghidra. Zaradi novosti programa zanj ˇse ni napisano veliko
7 literature. Veˇcino literature za tovrstne programe je napisane za program IDA [14], ki je bil na tem podroˇcju dominanten do objave programa Ghidra.
Na spletu lahko najdemo vodiˇce o uporabi programa Ghidra. Nedavno pa je bila napisana tudi knjiga o uporabi programa [15].
8 2. SORODNA DELA
Poglavje 3
Statiˇ cna analiza
Statiˇcna analiza programov je preuˇcevanje izvrˇsljive datoteke brez samega poganjanja programa v njej. Razdelimo jo lahko na osnovno statiˇcno analizo in napredno statiˇcno analizo [16]:
Osnovna statiˇcna analiza iz datotek izluˇsˇci podatke, ki so lahko upo- rabni za razumevanje programa brez vpogleda v strojno kodo.
Napredna statiˇcna analiza se osredotoˇca na preuˇcevanje strojne kode s pomoˇcjo razbirnikov (angl. disassembler).
Programe, za katere obstaja sum, da bi lahko bili slabogramje (npr. da- toteke, ki jih prejmemo v sumljivem e-poˇstnem sporoˇcilu), navadno najprej pregledamo s pomoˇcjo osnovne statiˇcne analize. Ta nam razkrije osnovne po- datke o programu. ˇCe izvemo, da gre za sumljivo datoteko, je naslednji korak dinamiˇcna analiza, kjer sumljiv program poˇzenemo v nadzorovanem okolju in opazujemo njegovo delovanje. Napredno statiˇcno analizo uporabljamo, ko so poskusi dinamiˇcne analize neuspeˇsni, ker je slabogramje napisano na naˇcin, da se skrije pred tovrstnimi poskusi. Uporabljamo jo tudi, ko ˇzelimo kar se da natanˇcno razumeti delovanje primera slabogramja (npr. ˇce uporablja nove tehnike zmaliˇcenja, izkoriˇsˇca nove ranljivosti, ipd.).
9
10 3. STATI ˇCNA ANALIZA
Slika 3.1: ˇSestnajstiˇski urejevalnik HxD.
3.1 Orodja
Spodaj predstavimo nekaj najbolj pogostih orodij za statiˇcno analizo in nji- hov namen.
3.1.1 Sestnajstiˇ ˇ ski urejevalniki
ˇSestnajstiˇski urejevalniki so orodja, ki nam omogoˇcajo vpogled in urejanje binarne datoteke. Nekateri so zmoˇzni razbrati podatkovne tipe in zbirniˇske ukaze. Primer ˇsestnajstiˇskega urejevalnika HxD je na sliki 3.1.
3.1.2 file
Ukaz file je nameˇsˇcen na veˇcini operacijskih sistemov Linux. Na opera- cijskem sistemu Windows lahko do njega dostopamo z WSL (Windows Sub- system for Linux). Ukaz file poskuˇsa iz vsebine datoteke prepoznati njen tip. Zmoˇzen je pogledati zaglavje datotek, kot so datoteke HTML, XML, ipd. Binarne datoteke lahko prepoznamo po magiˇcnem ˇstevilu (angl. magic number). To je navadno nekaj bajtov na zaˇcetku datoteke. Vse datotekePNG se na primer zaˇcnejo z nizom bajtov 89 50 4E 47 0D 0A 1A 0A.
Pri statiˇcni analizi slabogramja nas zanimajo predvsem izvrˇsljive dato- teke. Te se na operacijskem sistemu Windows navadno zaˇcnejo z bajtoma4D
3.1. ORODJA 11
Slika 3.2: Primer izpisa orodja za pregledovanje nizov strings.
5A (ASCII: M Z), na Linuxu pa z bajti 7F 45 4C 46 (ASCII: DEL E L F).
Zanimajo nas tudi stisnjene datoteke (npr. datoteke zip, zaˇcenˇsi z bajti 50 4B 03 04), ker bi lahko vsebovale izvrˇsljive datoteke.
3.1.3 Pregledovanje nizov
V veˇcini programov lahko najdemo nize, ki nam do neke mere razkrijejo na- men programa. ˇCe ima program zelo malo razumljivih nizov, je to lahko znak zmaliˇcenega programa. Na veˇcini operacijskih sistemov Linux je nameˇsˇcen ukaz strings, ki iz datotek izluˇsˇci nize znakov. Primer izpisa dobljenega z ukazomstringspognanim nad preprostim programom prevedenim s preva- jalnikomgcc je prikazan na sliki 3.2.
12 3. STATI ˇCNA ANALIZA
Slika 3.3: Orodje za pregledovanje izvrˇsljivih datotek PEiD.
3.1.4 Pregledovanje izvrˇ sljivih datotek
Orodja za pregledovanje izvrˇsljivih datotek nam lahko pokaˇzejo osnovne in- formacije iz zaglavja datoteke izvrˇsljivega formata. Te vkljuˇcujejo podatke o vstopni toˇcki programa, informacije o povezovalniku, velikosti datoteke, ipd.
Na sliki 3.3 je prikazan program PEiD.
3.1.5 Pregledovanje simbolov
Ob prevajanju programa mora prevajalnik v objektnih datotekah pustiti imena simbolov, da jih lahko nato povezovalnik poveˇze v izvrˇsljivo datoteko.
Ti simboli ostanejo v izvrˇsljivi datoteki, ˇce jih namenoma ne odstranimo.
Orodja, kot so nm za Linux ali PEStudio za operacijski sistem Windows, lahko te simbole izluˇsˇcijo iz objektnih ali izvrˇsljivih datotek. Primer izpisa dobljenega z ukazomnm pognanim nad preprostim programom prevedenim s prevajalnikom gcc je prikazan na sliki 3.4.
3.1. ORODJA 13
Slika 3.4: Primer izpisa orodja za pregledovanje simbolov nm.
14 3. STATI ˇCNA ANALIZA
Slika 3.5: Orodje za pregledovanje uvozov in izvozov DependencyWalker.
3.1.6 Pregledovanje uvozov in izvozov
Programi skoraj vedno uporabljajo kodo iz knjiˇznic. Ta jim omogoˇca dostop do standardnih funkcij operacijskega sistema. Koda iz knjiˇznice je lahko programu dodana statiˇcno, dinamiˇcno ali na oba naˇcina. Statiˇcno dodano knjiˇznico v program poveˇze povezovalnik ob prevajanju programa, dinamiˇcno dodano knjiˇznico pa v spomin naloˇzi nalagalnik ob poganjanju programa ali pa med samim tekom programa. Da lahko nalagalnik pravilno naloˇzi po- trebne knjiˇznice, mora prevajalnik v izvrˇsljivi datoteki pustiti ustrezne infor- macije. Prav tako morajo biti v knjiˇznici ustrezne informacije o funkcijah, ki jih knjiˇznica ponuja. Te informacije lahko z orodji za pregledovanje uvozov in izvozov izluˇsˇcimo iz izvrˇsljive datoteke. Primera takih orodij sta ldd na Linuxu in Dependency Walker na operacijskem sistemu Windows. Slednji je prikazan na sliki 3.5.
3.1. ORODJA 15
3.1.7 Razbirniki
Izvrˇsljive datoteke so na disku shranjene v obliki strojne kode. S pomoˇcjo ra- zbirnikov lahko strojno kodo v izvrˇsljivi datoteki pretvorimo v ukaze zbirnika, ki so laˇzje razumljivi. Za razbiranje se uporabljata dva glavna pristopa [15]:
Linearen razbirnik omogoˇca enostavnejˇsi pristop. Deluje tako, da ukaze razbira enega za drugim. Razbiranje je nekoliko laˇzje na arhitekturah, ki imajo enako dolge ukaze. Ta pristop ima dve teˇzavi. Prva nastane, ko razbiramo bajte, ki se v kodi uporabljajo kot podatki (npr. tabela za konstruktswitch). Druga teˇzava je, da pogosto ne vemo, kje zaˇceti postopek razbiranja.
Rekurzivni razbirnik pri razbiranju upoˇsteva tok ukazov (angl. control flow). Algoritem zaˇcne pri vstopni toˇcki programa in sledi ukazom.
Veˇcina ukazov je zaporednih, kar pomeni, da se izvajanje nadaljuje z naslednjim ukazom, zato v takem primeru algoritem deluje kot pri linearnem pristopu. Do odstopanja pride pri skoˇcnih ukazih, kot sta jz in jmp. Ker je statiˇcno nemogoˇce doloˇciti, kateri veji bo sledil tok ukazov pri pogojnih skokih, rekurzivni pristop sledi obema vejama. Pri skokih naletimo na teˇzavo, kadar je naslov skoka doloˇcen dinamiˇcno (npr. jmp rax).
Funkcijske klice obravnavamo kot nepogojne skoke. Ker priˇcakujemo, da se funkcija sˇcasoma vrne, dodamo na seznam naslovov, ki jim mo- ramo slediti, ˇse povratni naslov funkcije (ukaz takoj za klicem funkcije).
Tukaj lahko nastane teˇzava, ker lahko funkcija namenoma spreminja povratni naslov in se vrne na drugo mesto.
Ko naletimo na ukaz, ki mu ne moremo veˇc slediti (npr. ret), vzamemo s seznama naslovov, ki smo jih shranili, naslednji naslov in sledimo temu, dokler nam naslovov ne zmanjka. Glavna prednost tega pristopa je, da zelo dobro razlikuje med strojno kodo in podatki.
16 3. STATI ˇCNA ANALIZA Nekateri razbirniki so zmoˇzni nad kodo izvesti ˇse dodatne analize, ki izluˇsˇcijo ˇse dodatne uporabne informacije. V poglavju 6 predstavimo orodje Ghidra, ki je poleg razbiranja zmoˇzen izvesti ˇse ogromno dodatnih analiz, ki nam pomagajo pri razumevanju razbranega programa.
Poglavje 4
Obratno inˇ zenirstvo na arhitekturi x86
Navadno za slabogramje nimamo dostopa do izvorne kode. Zato je obra- tno inˇzenirstvo programske opreme glavni del analize slabogramja, ko ˇzelimo njegovo obnaˇsanje razumeti zelo podrobno. To obiˇcajno poˇcnemo s pregle- dovanjem razbranega programa. Pri prevajanju iz viˇsjenivojskega jezika v strojno kodo se izgubi veliko informacij o strukturi programa. Da bi lahko razumeli delovanje programa, je potrebno razumeti zgradbo programa in kako se pogosti koncepti iz viˇsjenivojskih jezikov prevedejo v strojno kodo. Spodaj razloˇzimo pomembnejˇse koncepte viˇsjenivojskih jezikov in jih primerjamo z nekaterimi tipiˇcnimi prevedenimi oblikami v zbirniku x86.
4.1 Zgradba izvrˇ sljivih datotek
Pri prevajanju programa navadno prevajalnik ustvari veˇc objektnih dato- tek, ki jih nato povezovalnik poveˇze v izvrˇsljivo datoteko. Ta vsebuje vse potrebne informacije, da jo lahko nalagalnik naloˇzi v pomnilnik in poˇzene.
Na operacijskem sistemu Linux se uporablja izvrˇsljiva datoteka tipa ELF, na operacijskem sistemu Windows pa izvrˇsljiva datoteka tipa PE. Slednja je sestavljena iz naslednjih delov [17]:
17
18 4. OBRATNO IN ˇZENIRSTVO NA ARHITEKTURI X86
Zaˇcne se s programom, ki je zdruˇzljiv z operacijskim sistemom MS- DOS (Microsoft Disk Operating System). Ta vsebuje svoje zaglavje in program, ki ga med prevajanjem vstavi povezovalnik. Za programe, prevedene za operacijski sistem Windows, ki jih poˇzenemo na opera- cijskem sistemu MS-DOS, ta obiˇcajno samo izpiˇse niz: ”This program cannot be run in DOS mode”. Na naslovu 0x3C tega dela datoteke PE se nahaja odmik do naslednjega dela.
Sledi zaglavje datoteke PE, ki se zaˇcne z magiˇcnim ˇstevilom ”P E NULL NULL”. Vsebuje podatke o arhitekturi sistema, ˇstevilu sekcij v datoteki PE, velikosti opcijskega zaglavja in ˇse nekaj dodatnih podatkov. Veˇcino pomembnih podatkov za izvrˇsljive datoteke se nahaja v opcijskem za- glavju.
Za zaglavjem datoteke PE se v izvrˇsljivih datotekah nahaja opcijsko za- glavje. Ta v objektnih datotekah navadno ne obstaja. Vsebuje podatke, ki so pomembni za nalaganje in izvajanje programa. Pomembnejˇsi po- datki so:
magiˇcno ˇstevilo, ki nam pove ali gre za 32 ali 64-bitno datoteko;
naslov vstopne toˇcke, kjer se po koncu nalaganja program zaˇcne;
poravnava sekcij, ki doloˇca, na katerih naslovih so lahko sekcije, ko so naloˇzene v pomnilnik;
razliˇcica podsistema, ki doloˇca, za kateri operacijski sistem je dato- teka namenjena;
informacije o podatkovnih direktorijih, ki jih je 16 in kaˇzejo na naslove svojih podatkov, ki vkljuˇcujejo uvozno tabelo, izvozno ta- belo, tabelo izjem, idr.
Opcijskemu zaglavju sledi ˇse tabela sekcij. Vsak vnos v tabeli je velik 40 bajtov in vsebuje ime sekcije, velikost sekcije, kazalec na zaˇcetek sekcije v datoteki in ˇse nekaj dodatnih informacij.
4.2. POGOJNI STAVKI 19
Za tabelo sekcij se nahajajo same sekcije. Pomembnejˇse sekcije so:
sekcija .text vsebuje izvedljivo kodo programa,
sekcija .bss je namenjena neinicializiranim podatkom programa, sekcija .rdata vsebuje podatke namenjene samo za branje,
sekcija .edata vsebuje imena in naslove funkcij namenjenih za izvoz, sekcija .idata vsebuje informacije o uvoˇzenih funkcijah.
Ko nalagalnik program naloˇzi v pomnilnik, se izvajanje zaˇcne na vstopni toˇcki programa. To je navadno koda, ki jo generira prevajalnik, da pripravi vse za izvajanje programa. To vkljuˇcuje inicializiranje statiˇcnih vrednosti, priprava sklada, inicializacijo knjiˇznic, ipd. Nato ta koda kliˇce glavno funkcijo programa.
4.2 Pogojni stavki
Pogojni stavki, kot staifinswitch, se v strojno kodo prevedejo v primerjave vrednosti in skoke. Za stavekif se obiˇcajno generirata 2 skoka. En za skok na vejo in en za skok na konec if stavka. Primera viˇsjenivojske kode v Cju in pripadajoˇce razbrane kode v zbirniku stavka if sta prikazana s spodnjo kodo.
if ( sum < 10) { v a r 1 = 1;
} e l s e { v a r 1 = 2;
}
0 0 4 0 1 1 3 f 89 45 dc MOV d w o r d ptr [ EBP + sum ] , EAX 0 0 4 0 1 1 4 2 83 7 d dc 0 a CMP d w o r d ptr [ EBP + sum ] ,0 xa 0 0 4 0 1 1 4 6 7 d 09 JGE I F _ F A L S E
0 0 4 0 1 1 4 8 c7 45 d8 MOV d w o r d ptr [ EBP + v a r 1 ] ,0 x1 01 00 00 00
0 0 4 0 1 1 4 f eb 07 JMP I F _ E N D
I F _ F A L S E
20 4. OBRATNO IN ˇZENIRSTVO NA ARHITEKTURI X86
0 0 4 0 1 1 5 1 c7 45 d8 MOV d w o r d ptr [ EBP + v a r 1 ] ,0 x2 02 00 00 00
I F _ E N D
Stavki switch so zelo podobni stavkomif. Razlikujejo se po ˇstevilu vej in primerjav. Primera viˇsjenivojske kode v Cju in pripadajoˇce razbrane kode v zbirniku stavka switch sta prikazana s spodnjo kodo.
s w i t c h ( sum ) { c a s e 0:
x = 0;
b r e a k ; c a s e 1:
x = 1;
b r e a k ; c a s e 2:
x = 2;
b r e a k ; d e f a u l t :
x = 3;
}
0 0 4 0 1 1 5 8 8 b 4 d dc MOV ECX , d w o r d ptr [ EBP + sum ] 0 0 4 0 1 1 5 b 89 4 d e0 MOV d w o r d ptr [ EBP + t e m p ] , ECX 0 0 4 0 1 1 5 e 83 7 d e0 00 CMP d w o r d ptr [ EBP + t e m p ] ,0 x0 0 0 4 0 1 1 6 2 74 0 e JZ B R A N C H 1
0 0 4 0 1 1 6 4 83 7 d e0 01 CMP d w o r d ptr [ EBP + t e m p ] ,0 x1
0 0 4 0 1 1 6 8 74 11 JZ B R A N C H 2
0 0 4 0 1 1 6 a 83 7 d e0 02 CMP d w o r d ptr [ EBP + t e m p ] ,0 x2
0 0 4 0 1 1 6 e 74 14 JZ B R A N C H 3
0 0 4 0 1 1 7 0 eb 1 b JMP B R A N C H 4 B R A N C H 1
0 0 4 0 1 1 7 2 c7 45 ec MOV d w o r d ptr [ EBP + x ] ,0 x0 00 00 00 00
0 0 4 0 1 1 7 9 eb 19 JMP S W I T C H _ E N D B R A N C H 2
0 0 4 0 1 1 7 b c7 45 ec MOV d w o r d ptr [ EBP + x ] ,0 x1 01 00 00 00
0 0 4 0 1 1 8 2 eb 10 JMP S W I T C H _ E N D B R A N C H 3
4.3. ZANKE 21
0 0 4 0 1 1 8 4 c7 45 ec MOV d w o r d ptr [ EBP + x ] ,0 x2 02 00 00 00
0 0 4 0 1 1 8 b eb 07 JMP S W I T C H _ E N D B R A N C H 4
0 0 4 0 1 1 8 d c7 45 ec MOV d w o r d ptr [ EBP + x ] ,0 x3 03 00 00 00
S W I T C H _ E N D
4.3 Zanke
Zanke so pogosti koncepti v programih. Prepoznamo jih lahko po skokih nazaj v kodi. Primera viˇsjenivojske kode v Cju in razbrane kode v zbirniku stavka forsta prikazana s spodnjo kodo.
for ( int i = 0; i < s ; i + + ) { p r i n t f (" i = \% d " , i );
}
0 0 4 0 1 1 a8 c7 45 e4 MOV d w o r d ptr [ EBP + i ] ,0 x0 00 00 00 00
0 0 4 0 1 1 af eb 09 JMP F O R _ B O D Y F O R _ I N C
0 0 4 0 1 1 b1 8 b 45 e4 MOV EAX , d w o r d ptr [ EBP + i ]
0 0 4 0 1 1 b4 83 c0 01 ADD EAX ,0 x1
0 0 4 0 1 1 b7 89 45 e4 MOV d w o r d ptr [ EBP + i ] , EAX F O R _ B O D Y
0 0 4 0 1 1 ba 8 b 4 d e4 MOV ECX , d w o r d ptr [ EBP + i ] 0 0 4 0 1 1 bd 3 b 4 d dc CMP ECX , d w o r d ptr [ EBP + sum ] 0 0 4 0 1 1 c0 7 d 13 JGE F O R _ E N D
0 0 4 0 1 1 c2 8 b 55 e4 MOV EDX , d w o r d ptr [ EBP + i ]
0 0 4 0 1 1 c5 52 P U S H EDX
0 0 4 0 1 1 c6 68 28 21 P U S H s _ i _ = _ \% d _ 0 0 4 0 2 1 2 8 40 00
0 0 4 0 1 1 cb e8 80 fe C A L L p r i n t f ff ff
0 0 4 0 1 1 d0 83 c4 08 ADD ESP ,0 x8
0 0 4 0 1 1 d3 eb dc JMP F O R _ I N C
F O R _ E N D
22 4. OBRATNO IN ˇZENIRSTVO NA ARHITEKTURI X86
4.4 Tabele in strukture
Tabele so pomemben koncept, ki jih ni vedno lahko zaznati s statiˇcno analizo.
Globalno dodeljene tabele imajo statiˇcen naslov, zato lahko prevajalnik pri uporabi konstantnih odmikov izraˇcuna naslove vseh dostopanih elementov.
Pri tabelah, ki so na skladu, to ni moˇzno, ampak lahko prevajalnik ˇse vedno izraˇcuna toˇcne odmike elementov in nam tako skrije prisotnost tabele. Da lahko tabelo prepoznamo, je navadno potrebno, da se indeks dostopa do tabele spreminja dinamiˇcno. Primera viˇsjenivojske kode v Cju in razbrane kode v zbirniku dostopa do tabele sta prikazana s spodnjo kodo.
int i n t a r r a y [ 1 0 ] ;
for ( int c n t r = 0; c n t r < 10; c n t r ++) { i n t a r r a y [ c n t r ] = c n t r ;
}
0 0 4 0 1 2 2 e c7 45 e8 MOV d w o r d ptr [ EBP + c n t r ] ,0 x0 00 00 00 00
0 0 4 0 1 2 3 5 eb 09 JMP F O R _ B O D Y F O R _ I N C
0 0 4 0 1 2 3 7 8 b 4 d e8 MOV ECX , d w o r d ptr [ EBP + c n t r ]
0 0 4 0 1 2 3 a 83 c1 01 ADD ECX ,0 x1
0 0 4 0 1 2 3 d 89 4 d e8 MOV d w o r d ptr [ EBP + c n t r ] , ECX F O R _ B O D Y
0 0 4 0 1 2 4 0 83 7 d e8 0 a CMP d w o r d ptr [ EBP + c n t r ] ,0 xa 0 0 4 0 1 2 4 4 7 d 0 c JGE F O R _ E N D
0 0 4 0 1 2 4 6 8 b 55 e8 MOV EDX , d w o r d ptr [ EBP + c n t r ] 0 0 4 0 1 2 4 9 8 b 45 e8 MOV EAX , d w o r d ptr [ EBP + c n t r ]
0 0 4 0 1 2 4 c 89 44 95 ac MOV d w o r d ptr [ EBP + EDX *0 x4 + -0 x54 ] , EAX 0 0 4 0 1 2 5 0 eb e5 JMP F O R _ I N C
F O R _ E N D
Velikost tabele, ki je dodeljena globalno ali na sklad, je ˇse ena lastnost, ki se izgubi pri prevajanju programa in jo moramo navadno poiskati roˇcno z analizo kode. Velikost dinamiˇcno dodeljene tabele (npr. s klicem funkcije malloc) pa lahko razberemo iz argumentov funkcije, ki rezervira prostor v pomnilniku. Primer dinamiˇcno dodeljene tabele kode v zbirniku je prikazan
4.5. FUNKCIJE 23
s spodnjo kodo.
0 0 4 0 1 1 d5 6 a 0 a P U S H 0 xa
0 0 4 0 1 1 d7 ff 15 4 c C A L L d w o r d ptr [ - > m a l l o c 20 40 00
0 0 4 0 1 1 dd 83 c4 04 ADD ESP ,0 x4
0 0 4 0 1 1 e0 89 45 d4 MOV d w o r d ptr [ EBP + a r r a y ] , EAX
Dostopanje do elementov strukture je v strojni kodi zelo podobno kot dostopanje do elementov tabel. Razlikuje se v tem, da odmiki do posame- znih elementov v strukturi niso enakomerno porazdeljeni, kot to velja pri tabelah. Poleg tega se lahko prevajalnik odloˇci, da med elemente strukture doda dodaten prostor, s katerim zagotovi pravilno poravnavo podatkov, kar predstavlja ˇse dodatno teˇzavnost pri odkrivanju strukture tablele.
4.5 Funkcije
Analiza funkcij in potek programa je glavni del statiˇcne analize. V programu poskuˇsamo odkriti glavno funkcijo, kako ta kliˇce ostale in kaj je njihov smi- sel. Slabogramje se obiˇcajno, kot veˇcina programov, zanaˇsa na knjiˇznice operacijskega sistema, da lahko uporablja njegove funkcije. To nam lahko pri analizi funkcij pove, kaj toˇcno ˇzeli program doseˇci. Spodaj predstavimo glavne koncepte, na katere moramo biti pozorni pri analizi funkcij.
4.5.1 Uporaba sklada
Pri klicu funkcije mora program argumente funkcije shraniti v pomnilnik.
Prav tako mora klicana funkcija imeti prostor za svoje lokalne spremenljivke in mesto, kamor vrne svoj rezultat. Funkcija mora shraniti tudi povratni naslov, kjer se bo izvajanje funkcije nadaljevalo, ko se klicana funkcija konˇca.
Ce je takih podatkov malo, jih lahko shranimo v registre. Ker je registrovˇ na arhitekturi x86 sorazmerno malo, je obiˇcajno potrebno te podatke shraniti v glavni pomnilnik. Za to se uporablja skladovna podatkovna struktura, ki deluje po principu LIFO. Klicoˇca koda za klicano funkcijo na skladu ustvari
24 4. OBRATNO IN ˇZENIRSTVO NA ARHITEKTURI X86 klicni zapis, kamor shrani potrebne podatke.
Veˇcino arhitektur podpira sklad v strojni opremi. Na arhitekturi x86 sta za to zadolˇzena registra ESP in EBP. Podatke na sklad nalagamo z ukazom PUSH, z njega pa jemljemo z ukazomPOP. Register ESPvedno kaˇze na zadnji vstavljen element. Sklad raste proti niˇzjim naslovom.
4.5.2 Klic funkcije
Potek funkcije lahko razdelimo na naslednje korake [7, 15]:
1. Klicoˇca koda shrani argumente klicane funkcije. Te lahko postavi na sklad ali jih shrani v registre glede na klicno konvencijo.
2. Klicoˇca koda preda nadzor klicani funkciji. Na arhitekturi x86 se za to uporablja ukaz CALL. Povratni naslov se shrani na sklad oziroma v register.
3. Po potrebi klicana funkcija shrani registre, za katere klicoˇca koda priˇcaku- je, da bodo ostali nespremenjeni.
4. Klicana funkcija pripravi prostor za lokalne spremenljivke. Navadno to stori s poveˇcanjem sklada.
5. Klicana funkcija izvede svoje ukaze in rezultat shrani v registrih ali na skladu.
6. Klicana funkcija nato sprosti pomnilnik, ki ga je rezervirala za lokalne spremenljivke.
7. ˇCe je klicana funkcija shranila registre, jih v tem koraku nastavi nazaj.
8. Klicana funkcija preda nadzor nazaj klicoˇci kodi. Na arhitekturi x86 se za to uporablja ukaz RET.
9. Po potrebi klicoˇca koda iz sklada odstrani argumente klicane funkcije.
4.5. FUNKCIJE 25 Korake, ki se izvedejo pred zaˇcetkom ukazov funkcije, imenujemo pro- log funkcije. Korake, ki se izvedejo za koncem funkcije, imenujemo epilog funkcije.
4.5.3 Klicne konvencije
Klicne konvencije doloˇcajo, kako se argumenti prenesejo iz klicoˇce kode v klicano funkcijo, kdo je odgovoren za sprostitev sklada, katere registre shrani klicoˇca koda in katere klicana funkcija, itn. Spodaj predstavimo najbolj pogoste klicne konvencije [7, 15]:
cdecl Ta je najbolj uporabljena klicna konvencija veˇcine prevajalnikov za programski jezik C. Vsi argumenti se prenaˇsajo na skladu v vrstnem redu od desne proti levi, kar omogoˇca enostavno klicanje funkcij, ki prejmejo razliˇcno ˇstevilo argumentov. Za ˇciˇsˇcenje sklada po koncu funkcije je zadolˇzena klicoˇca koda.
Uporablja se tudi za 64-bitne datoteke, kjer se nekaj argumentov pre- nese tudi v registrih odvisno od prevajalnika, ki je prevedel program.
C++ programi lahko uporabijo to klicno konvencijo in nestatiˇcnim ra- zrednim funkcijam kot prvi argument nastavijo kazalec this.
stdcall Ta klicna konvencija je podobna klicni konvencijicdecl. Argumente prav tako prenaˇsa na skladu v vrstnem redu od desne proti levi. Za ˇciˇsˇcenje sklada je tu zadolˇzena klicana funkcija, kar onemogoˇca klicanje funkcij z razliˇcnim ˇstevilom argumentov.
To klicno konvencijo uporabljajo vse funkcije knjiˇznic za operacijski sistem Windows, ki prejmejo fiksno ˇstevilo argumentov.
fastcall Je razliˇcica klicne konvencije stdcall. Prva dva argumenta se pri tej klicni konvenciji preneseta v registrihECX inEDX.
thiscall Je klicna konvencija, ki jo na operacijskem sistemu Windows upo- rabljajo C++ programi. Podobna je klicni konvenciji stdcall, le da za nestatiˇcne razredne funkcije kazalec thisprenaˇsa v registru ECX.
26 4. OBRATNO IN ˇZENIRSTVO NA ARHITEKTURI X86
4.6 Posebnosti objektno usmerjenih program- skih jezikov
Prevajalniki objektno usmerjenih jezikov v kodi generirajo nekaj dodatnih konstruktov. Razumevanje teh nam lahko pomaga pri obratnem inˇzenirstvu takih programov. Spodaj predstavimo nekatere pomembnejˇse posebnosti objektno usmerjenih programskih jezikov [15]:
kazalec this Vse nestatiˇcne razredne funkcije ob klicu prejmejo tudi argu- ment s kazalcem this, ki kaˇze na naslov objekta, do katerega funkcija dostopa. Kazalec this se lahko nahaja kot prvi argument na skladu ali pa v registru ECX, odvisno od klicne konvencije. Uporaba takega argumenta kot kazalec lahko nakazuje, da gre za nestatiˇcno razredno funkcijo.
navidezne funkcije Prevajalnik generira tabelo navideznih funkcij za vsak razred, ki jih uporablja. Tabela vsebuje kazalce na funkcije razreda, kar omogoˇca, da koda kliˇce pravilno funkcijo ob izvajanju programa, odvisno od tipa razreda. Kazalec na tabelo navideznih funkcij generira prevajalnik in ga usmeri na zaˇcetek objekta. Ob teku programa kaza- lec na tabelo navideznih funkcij nastavi konstruktor, ko ustvari objekt danega razreda.
Pri obratnem inˇzenirstvu lahko pogledamo v konstruktor razreda in najdemo nastavitev kazalca tabele navideznih funkcij, kar nam omogoˇca, da v tabeli navideznih funkcij najdemo vse navidezne funkcije razreda.
ˇzivljenska doba objektov Razumevanje, kdaj se objekti ustvarijo in spro- stijo iz pomnilnika, nam pomaga pri obratnem inˇzenirstvu. Objekti se ustvarijo, ko pridejo v obmoˇcje vidnosti in izbriˇsejo, ko gredo iz njega.
Za statiˇcno ustvarjene objekte je to pred zaˇcetkom programa. Te se sprostijo, ko se program konˇca. Objekti na skaldu se ustvarijo, preden se funkcija zaˇcne in sprostijo, ko se funkcija konˇca. Dinamiˇcno ustvar-
4.6. POSEBNOSTI OBJEKTNO USMERJENIH PROGRAMSKIH
JEZIKOV 27
jeni objekti najprej ustvarijo prostor v pomnilniku z operatorjemnewin nato kliˇcejo konstruktor. Take objekte mora programer sprostiti roˇcno z operatorjem delete.
Ob ustvarjanju objekta se kliˇce njegov konstruktor. ˇCe je razred de- dovan, se najprej pokliˇce konstruktor njegovega nadrazreda. Za tem po potrebi konstruktor nastavi kazalec na tabelo navideznih funkcij.
Nato se kliˇcejo konstruktorji vseh razredov, ki jih ta razred vsebuje.
Nazadnje se izvede ˇse koda, ki jo konstruktor vsebuje.
Ko se objekt sproˇsˇca, se kliˇce njegov destruktor. Najprej ponastavi kazalec na virtualno tabelo navideznih funkcij, ˇce je bil ta spremenjen.
Potem se izvede koda v telesu destruktorja. Nato se kliˇcejo destruktorji vseh razredov, ki jih ta razred vsebuje. Na koncu se kliˇce ˇse destruktor nadrazreda, ˇce ga ta razred ima.
dedovanje Dedovanje razredov lahko razpoznamo pri statiˇcni analizi pro- grama z analizo klicev konstruktorjev. Podedovan razred bo v svojem konstruktorju klical konstruktor starˇsevskega razreda. Tako analizo nam lahko oteˇzi uporaba vrinjenih konstruktorjev, kjer prevajalnik na mesto, kjer bi bil klic funkcije, namesto klica konstruktorja, vrine kodo konstruktorja. V tem primeru ni veˇc oˇcitno, da gre za klic funkcije, saj prevajalnik funkcijsko telo vstavi na mesto, kjer bi obiˇcajno stal klic funkcije.
Dedovanje razredov lahko razpoznamo tudi s primerjavo naslovov v tabelah navideznih funkcij razredov. ˇCe imata dve tabeli navideznih funkcij enako ˇstevilo naslovov, je moˇzno, da sta razreda med seboj po- vezana z dedovanjem. ˇCe imata dve tabeli navideznih funkcij razliˇcno ˇstevilo naslovov, je moˇzno, da je razred, ki ima v virtualni tabeli manj naslovov, nadrazred drugega razreda. ˇCe v dveh tabelah navideznih funkcij najdemo nekaj enakih naslovov, sta ta razreda povezana z de- dovanjem.
28 4. OBRATNO IN ˇZENIRSTVO NA ARHITEKTURI X86
Poglavje 5
Zmaliˇ cenje programske kode
Ze s prevajanjem programa, napisanega v viˇsjenivojskem jeziku, v strojnoˇ kodo se izgubi veliko informacij, ki bi programerju veliko povedale o poteku in sestavi programa. Izgubijo se informacije o podatkovnih strukturah kot so tabele, razredi, ipd. Izloˇcijo se tudi simbolne informacije, ki niso nujno potrebne ob teku programa. Orodja za obratno inˇzenirstvo nam pomagajo, da te informacije pridobimo nazaj oz. jih rekonstruiramo s pomoˇcjo analize programa. Pisci slabogramja se ˇzelijo izogniti razumevanju programske kode slabograma, zato poskuˇsajo prepreˇciti analizo kode s pomoˇcjo zmaliˇcenja programske kode. Zmaliˇcenje spremeni programsko kodo, da oteˇzi njeno razumevanje. Pri tem programska koda ostane funkcionalno enaka.
Tehnike zmaliˇcenja lahko delimo na statiˇcne in dinamiˇcne. Statiˇcne teh- nike zmaliˇcenja oteˇzujejo statiˇcno analizo s spreminjanjem programske kode, skrivanjem nizov, itd. Njihov namen je oteˇzevanje berljivosti programske kode in prelisiˇcevanje orodij za obratno inˇzenirstvo. Dinamiˇcne tehnike zmaliˇcenja se osredotoˇcajo na prepreˇcevanje dinamiˇcne analize. To poˇcnejo z detekcijo peskovnikov, razhroˇsˇcevalnikov (angl. debugger), ipd.
Tehnike zmaliˇcenja se med seboj razlikujejo po svojem namenu in stopnji oteˇzevanja analize. Spodaj predstavimo nekaj statiˇcnih tehnik zmaliˇcenja [7, 10, 16, 15, 18].
29
30 5. ZMALI ˇCENJE PROGRAMSKE KODE
5.1 Desinhronizacija razbirnika
Desinhronizacija razbirnika (angl. disassembly desynchronization) je tehnika, ki poskuˇsa zmesti razbirnik. To naredi s skokom na naslov, ki bi se obiˇcajno nahajal med ukazom. S to tehniko zmaliˇcenja doseˇzemo napaˇcen izpis raz- birnika.
Skok je lahko obiˇcajen JMP ukaz, ki ga je lahko odkriti. Rekurzivni raz- birnik ga odkrije kar sam, saj sledi toku programa. Bolj napredne metode uporabljajo pogojne skoke, ki se bodo vedno izvedli, ali pa ukazeRET, zatem ko na sklad postavijo ciljni naslov.
V primeru iz literature [15] je v spodnji kodi uporabljen ukazJZ, ki skoˇci na naslov, ki je en bajt odmaknjen od ukaza CALL. Razbirnik je sledil toku, ko se skok ukaza JZ ne izvede.
0 0 4 0 1 0 0 0 XOR EAX , EAX
0 0 4 0 1 0 0 2 JZ L A B _ 0 0 4 0 1 0 0 9 +1
0 0 4 0 1 0 0 4 MOV EBX , d w o r d ptr [ EAX ]
0 0 4 0 1 0 0 6 MOV d w o r d ptr [ p a r a m _ 1 + -0 x4 ] , EBX L A B _ 0 0 4 0 1 0 0 9 +1
0 0 4 0 1 0 0 9 C A L L S U B _ a d f e f f c 6
0 0 4 0 1 0 0 e F I C O M w o r d ptr [ EAX + 0 x59 ]
Z analizo kodo lahko vidimo, da se bo skok vedno izvedel, saj ukazXOR, ki se nahaja pred skokom, vedno postavi niˇcelno zastavico. Pravilno razbrana koda zbirnika je prikazana s spodnjo kodo.
0 0 4 0 1 0 0 0 XOR EAX , EAX 0 0 4 0 1 0 0 2 JZ L A B _ 0 0 4 0 1 0 0 a
0 0 4 0 1 0 0 4 MOV EBX , d w o r d ptr [ EAX ]
0 0 4 0 1 0 0 6 MOV d w o r d ptr [ p a r a m _ 1 + -0 x4 ] , EBX 0 0 4 0 1 0 0 9 ?? E8h
L A B _ 0 0 4 0 1 0 0 a
0 0 4 0 1 0 0 a MOV EAX ,0 x d e a d b e e f 0 0 4 0 1 0 0 f P U S H EAX
0 0 4 0 1 0 1 0 POP p a r a m _ 1
5.2. DINAMI ˇCNO IZRA ˇCUNAN NASLOV 31
5.2 Dinamiˇ cno izraˇ cunan naslov
Dinamiˇcno izraˇcunan naslov se izraˇcuna med tekom programa. S skokom na dinamiˇcno izraˇcunan naslov lahko skrijemo kodo, ki se na naslovu nahaja, saj jo rekurzivni razbirnik ne doseˇze. V primeru iz literature [15] je s spodnjo kodo prikazano raˇcunanje in skok na dinamiˇcno izraˇcunan naslov.
0 a 0 4 b 3 b e MOV ECX ,0 x 7 f 1 3 1 7 6 0 ; ECX = 7 F 1 3 1 7 6 0 0 a 0 4 b 3 c 3 XOR EDI , EDI ; EDI = 0 0 0 0 0 0 0 0 0 a 0 4 b 3 c 5 MOV DI ,0 x 1 1 5 6 ; EDI = 0 0 0 0 1 1 5 6 0 a 0 4 b 3 c 9 ADD EDI ,0 x 1 3 3 a c 0 0 0 ; EDI = 133 A D 1 5 6 0 a 0 4 b 3 c f XOR ECX , EDI ; ECX = 6 C 2 9 C 6 3 6 0 a 0 4 b 3 d 1 SUB ECX ,0 x 6 2 2 5 4 5 c e ; ECX = 0 A 0 4 8 0 6 8 0 a 0 4 b 3 d 7 MOV EDI , ECX ; EDI = 0 A 0 4 8 0 6 8 0 a 0 4 b 3 d 9 POP EAX
0 a 0 4 b 3 d a POP ESI 0 a 0 4 b 3 d b POP EBX 0 a 0 4 b 3 d c POP EDX 0 a 0 4 b 3 d d POP ECX
0 a 0 4 b 3 d e X C H G d w o r d ptr [ ESP ] , EDI ; na v r h u s k a d a je 0 A 0 4 8 0 6 8 0 a 0 4 b 3 e 1 RET ; v r n e m o se na 0 A 0 4 8 0 6 8
5.3 Zmaliˇ cenje kontrolnega toka
Ta vrsta zmaliˇcenja kodo programa spremeni z namenom skrivanja kontrol- nega toka. To lahko doseˇzemo z odstranjevanjem informacij o kontrolnem toku ali z dodajanjem novih ukazov, ki spremenijo kontrolni tok. S tem lahko moˇcno oteˇzimo analizo programa, saj nam je skritih veliko informacij, na katere se opiramo pri obratnem inˇzenirstvu. Pogosti naˇcini zmaliˇcenja kontrolnega toka vkljuˇcujejo:
Neprosojni predikati (angl. opaque predicate) so v osnovi logiˇcne iz- jave z vnaprej znano vrednostjo, ki se izraˇcunajo dinamiˇcno. Enostavni primer uporabe je predstavljen s kodo v razdelku 5.2, kjer drugi ukaz JZ uporablja neprosojen predikat (angl. opaque predicate). V tem pri-
32 5. ZMALI ˇCENJE PROGRAMSKE KODE meru se neprosojni predikat (angl. opaque predicate) zanaˇsa samo na rezultat prejˇsnjega ukaza in ga je lahko odkriti. Bolj napredni nepro- sojni predikati (angl. opaque predicate) se lahko nanaˇsajo na vrednosti, ki jih program konstantno spreminja, kar bistveno oteˇzi razumevanje kontrolnega toka programa.
Interpretacija s tabelami je naˇcin zmaliˇcenja kontrolnega toka, ki popol- noma skrije kontrolni tok programa. Kodo zmaliˇcimo tako, da najprej kodo programa razbijemo na manjˇse dele in jih med seboj pomeˇsamo.
Nato pred deli kode ustvarimo zanko, ki vsebuje zaporedje pogojnih izrazov, ki skoˇcijo na del kode, ki ga je potrebno izvesti. ˇCe je ta zanka dobro zasnovana, je iz kode zelo teˇzko razvozlati, kateri del kode se bo izvedel.
Vrinjene in izrinjene funkcije oteˇzujejo berljivost kode z odstranjevanjem ali dodajanjem funkcij. Vrinjena funkcija je rezultat optimizacije, ki jo naredi prevajalnik, kjer prevajalnik zamenja klic funkcije s telesom funkcije, da se znebi cene klica funkcije. Tako transformacijo kode lahko uporabimo kot zmaliˇcenje, saj skrije klice funkcij, kar lahko oteˇzi razu- mevaje kode. Kodo lahko zmaliˇcimo tudi z uporabo izrinjenih funkcij, ki so nasprotje vrinjenim funkcijam. V tem primeru obstojeˇco kodo spremenimo v funkcijo. S tem dodamo v program dodatno funkcijo, ki se kliˇce samo enkrat, kar lahko zmede analizerja kode.
Prepletena koda je naˇcin zmaliˇcenja kontrolnega toka, kjer veˇc funkcij med seboj prepletemo. To naredimo tako, da med ukaze ene funk- cije vstavimo ukaze druge funkcije. Seveda moramo poskrbeti, da se koda ˇse vedno izvede v pravilnem zaporedju. Zato na dele, kjer se konˇca koda iz ene funkcije, vstavimo skok z neprosojnim predikatom (angl. opaque predicate), ki skoˇci na pravo mesto iste funkcije.
Medprocesno zmaliˇcenje se zanaˇsa na neprosojne predikate (angl. opaque predicate) v razliˇcnih procesih ali nitih. Tako vrsto zmaliˇcenja je teˇzko
5.4. SKRIVANJE UVO ˇZENIH FUNKCIJ 33 razvozlati, saj moramo roˇcno analizirati vse procese in njihove naˇcine sinhronizacije, da lahko razvozlamo pravilen kontrolni tok programa.
Uporaba izjem je naˇcin zmaliˇcenja kontrolnega toka, kjer stanje programa spremenimo med servisiranjem izjeme. Program namenoma ustvari izjemo, nato pa v kodi za obravnavo izjeme spremeni stanje programa z namenom vplivanja na kontrolni tok programa, ko se ta vrne iz izjeme.
5.4 Skrivanje uvoˇ zenih funkcij
Iz seznama uvoˇzenih funkcij lahko izluˇsˇcimo osnovne namene programa. Te- mu se pisci slabogramja poskuˇsajo izogniti, zato pogosto zunanje funkcije naloˇzijo dinamiˇcno med tekom programa in jih tako skrijejo pred orodji, ki analizirajo uvoˇzene funkcije. Na operacijskem sistemu Windows se za to uporablja funkcijaLoadLibraryza nalaganje knjiˇznic inGetProcAddressza iskanje naslova posamezne funkcije v knjiˇznici. Slabogramje mora obiˇcajno te funkcije vkljuˇciti v seznam uvoˇzenih funkcij. Obstajajo pa tudi napredne metode, kjer program dinamiˇcno poiˇsˇce funkcijo LoadLibrary iz knjiˇznjice kernel32.dll, ki se privzeto naloˇzi v vse programe, ki teˇcejo na operacijskem sistemu Windows. V tem primeru mora program roˇcno poiskati tudi vse funkcije, ki jih ˇzeli uporabljati v doloˇceni knjiˇznici, oz. najprej roˇcno poiskati ˇse funkcijo GetProcAddress.
5.5 Polimorfiranje in metamorfiranje
Polimorfiranje in metamorfiranje sta tehniki, ki ju uporablja slabogramje za izogib detekciji enostavni statiˇcni analizi (npr. detekcija z vpogledom v zgoˇsˇceno tabelo). Bistvo te tehnike je spreminjanje kode z namenom spremi- njanja zgoˇsˇcene vrednosti slabogramja. Na te tehnike moramo biti pozorni tudi pri napredni statiˇcni analizi. Spodaj predstavimo nekaj takih tehnik [10]:
Vstavljanje mrtve kode v program vstavi dodatne ukaze, ki ne spremi-
34 5. ZMALI ˇCENJE PROGRAMSKE KODE njajo dejanskega poteka programa. Najpreprostejˇse to doseˇzemo z do- dajanjem ukazov nop. Lahko dodamo tudi ukaze, ki se med seboj izniˇcijo (npr. zaporedje PUSH ECX, INC EDX, DEC EDX, POP ECX).
Zamenjava registrov je tehnika, pri kateri zamenjamo vloge registrov. Po- slediˇcno se spremeni zgoˇsˇcena vrednost programa, saj program upora- blja razliˇcne ukaze, ne pa tudi pomen programa.
Premeˇsˇcanje podprogramov zamenja vrstni red podprogramov in tako spremeni zgoˇsˇceno vrednost programa.
Zamenjava ukazov je tehnika, pri kateri zamenjamo doloˇcene ukaze z nji- hovimi enakovrednimi ukazi. Namesto da register resetiramo s pomoˇcjo ukaza MOV, lahko to storimo na primer z ukazom XOR.
Transpozicija kode zamenja vrstni red skupin ukazov brez vpliva na po- men programa. To lahko storimo z zamenjavo skupin ukazov, za katere ni pomembno, v kakˇsnem vrstnem redu jih izvedemo. Moˇzna je tudi nakljuˇcna zamenjava skupin ukazov, ki jih nato poveˇzemo s skoˇcnimi ukazi, da se koda izvede v pravilnem zaporedju.
5.6 Pakiranje
Pakiranje je tehnika, ki ga slabogramje zelo pogosto uporablja. Za to se uporabljajo programi, ki jih imenujemo pakirniki. Pakirniki kot vhod vza- mejo izvrˇsljivo datoteko in kot izhod ustvarijo zapakirano izvrˇsljivo datoteko.
Zapakirana datoteka je sestavljena iz dveh delov:
majhnega programa, ki ob zagonu pakiranega programa odpakira za- pakiran program,
zapakiranega programa.
Pakiran program lahko prepoznamo po naslednjih znakih:
Program ima zelo malo uvoˇzenih funkcij ali pa jih sploh nima.
5.6. PAKIRANJE 35
Program vsebuje zelo malo berljivih nizov.
Ko program analiziramo z orodjem (npr. Ghidra), ta razpozna soraz- merno malo kode.
Program vsebuje imena sekcij, ki so znaˇcilne za pakirane programe.
Program ima neobiˇcajne velikosti sekcij (npr. sekcija .text, ki ima niˇcelno velikost na disku in neniˇcelno virtualno velikost).
Zapakiran program je pogosto zaˇsifriran in stisnjen. S tem je skrita dejan- ska koda programa, kar nam oteˇzi napredno statiˇcno analizo, saj je potrebno program pred analizo najprej odpakirati. Pri pakiranju programa lahko pa- kirnik izvede ˇse dodatne tehnike zmaliˇcenja, ki so opisane zgoraj. Poleg tega stisnjen program zavzame manj prostora na disku in se lahko hireje prenaˇsa.
Ko pakiran program poˇzenemo, se izvedejo naslednji koraki:
1. Nalagalnik rezervira prostor za odpakiran program, kot je zapisano v zaglavju izvrˇsljive datoteke.
2. Program odpakira zapakiran program in ga naloˇzi v pomnilnik.
3. ˇCe je potrebno, program dinamiˇcno naloˇzi knjiˇznice, ki jih potrebuje.
4. Program skoˇci na originalno vstopno toˇcko odpakiranega programa.
Obstajajo orodja, ki lahko pakirane programe odpakirajo samodejno, ˇce od- krijejo, da so bili pakirani z znanim orodjem (npr. UPX, PECompact, idr.).
Pogosto se zgodi, da moramo pakiranje programe odpakirati roˇcno. Za to obstaja statiˇcni in dinamiˇcni pristop:
Pri statiˇcnem pristopu datoteko analiziramo in poiˇsˇcemo del programa, ki je odgovoren za odpakiranje. Na osnovi te kode sestavimo svoj pro- gram, ki bo kodo odpakiral.
Pri dinamiˇcnem pristopu program dejansko poˇzenemo. Ko je program v pomnilniku odpakiran, ga iz pomnilnika preberemo in shranimo na disk.
36 5. ZMALI ˇCENJE PROGRAMSKE KODE Pri statiˇcni analizi slabogramja se izogibamo poganjanju programa, zato upo- rabimo statiˇcni pristop. Ko je program odpakiran, je potrebno ˇse poiskati uporabljene knjiˇznice, ˇce so bile te skrite. Poiskati je treba tudi originalno vstopno toˇcko odpakiranega programa. Pri preprostejˇsem pakiranju se skok nanjo obiˇcajno nahaja na koncu dela programa, ki je odgovoren za odpa- kiranje. Napredni pakirniki lahko ta del programa zmaliˇcijo in za predajo nadzora originalni vstopni toˇcki uporabljajo drugaˇcne ukaze (npr. CALL ali RET).
Poglavje 6
Program Ghidra
Ghidra je programska oprema za obratno inˇzenirstvo (angl. software reverse engineering), ki ga je razvila ameriˇska Nacionalna varnostna agencija (NSA).
Za njen obstoj se je izvedelo leta 2017, ko sam program ˇse ni bil na voljo ˇsirˇsi javnosti. Nacionalna varnostna agencija je Ghidro za ˇsirˇso javnost izdala leta 2019 kot odprtokodni program in izvorno kodo objavila na GitHubu. Ghidra podpira veliko orodji, ki jih lahko uporabimo za statiˇcno ali dinamiˇcno analizo programske opreme. Te vkljuˇcujejo razbirnik, zbirnik, prikaz kode v Cju, grafiˇcni prikaz diagrama poteka funkcije, pisanje skript, razhroˇsˇcevanje, idr.
Program predstavlja konkurenco do sedaj uveljavljenem programu IDA [14].
Ghidra je prosto dostopen program, ki ga prenesemo iz uradne spletne strani [5]. Ker je program zgrajen v programskem jeziku Java, moremo imeti zanj nameˇsˇceno ustrezno okolje Java. V ˇcasu pisanja tega dela deluje zadnja razliˇcica programa z verzijo Jave 11. Poslediˇcno lahko Ghidro poˇzenemo na kateremkoli sistemu, ki podpira okolje Java.
V tem poglavju predstavimo osnovni potek dela v programu Ghidra in glavna orodja, ki jih uporabljamo pri statiˇcni analizi slabogramja.
37
38 6. PROGRAM GHIDRA
6.1 Potek dela
Ko odpremo Ghidro, se nam odpre zaˇcetno okno in avtomatsko prikaˇze zadnji odprti projekt, kot je prikazano na sliki 6.1. ˇCe projekta ˇse nimamo, ga je potrebno ustvariti, pri ˇcemer moramo izbrati vrsto projekta, ime in pot, kjer se bo projekt nahajal. Projekt je lahko dveh vrst:
projekt za skupno uporabo, kjer bomo na projektu delali v skupini,
samostojni projekt, kjer bomo na projektu delali sami.
V projekt lahko nato uvozimo izvrˇsljive datoteke, ki jih ˇzelimo analizirati. To storimo tako, da izvrˇsljivo datoteko povleˇcemo v zaˇcetno okno programa. Pri uvozu datoteka Ghidra sama nastavi nastavitve uvoza, kot so tip izvrˇsljive datoteke, arhitektura sistema, informacije o knjiˇznicah, ipd. Te nastavitve lahko roˇcno popravimo, ˇce imamo sami boljˇse informacije o sestavi izvrˇsljive datoteke.
Ko je datoteka uvoˇzena, nam Ghidra predstavi povzetek izvrˇsljive dato- teke, kot je prikazano na sliki 6.2. Tu lahko vidimo osnovne informacije o izvrˇsljivi datoteki, ki vkljuˇcujejo:
ime datoteke,
ˇcas ustvarjanja datoteke,
arhitekturo sistema, ki ji je datoteka namenjena,
bitnost izvrˇsljive datoteke,
podatke o ˇstevilu bajtov, podatkovnih tipov, funkcij in simbolov v da- toteki,
podatke o prevajalniku,
podatke o informacijah za razhroˇsˇcevanje.
6.1. POTEK DELA 39
Slika 6.1: Zaˇceno okno programa Ghidra.
40 6. PROGRAM GHIDRA
Slika 6.2: Prikaz uvoza izvrˇsljive datoteke.
6.2. ORODJA 41 Ko je datoteka uspeˇsno uvoˇzena, jo lahko odpremo z orodjem za ana- liziranje, tako da uvoˇzeno datoteko povleˇcemo na ikono z zmajem. S tem odpremo glavno okno programa, ki je prikazano na sliki 6.4, kjer poteka veˇcina dela med analizo datoteke. Glavno okno je privzeto sestavljeno iz razbirnega okna na sredini, kjer vidimo razbrano strojno kodo. Desno od razbirnega okna se nahaja okno, kjer Ghidra avtomatsko prikaˇze kodo pro- gramskega jezika C trenutne funkcije. Na levi strani imamo po vrsti okno programskih sekcij, okno simbolnega drevesa in okno podatkovnih tipov. Na spodnjem delu glavnega okna se nahaja konzola, kjer se izpisujejo rezultati skript.
Ce smo datoteko z orodjem za analizo odprli prviˇˇ c, datoteka ˇse ni bila analizirana. Ghidra nam v tem primeru odpre okno z moˇznostmi za avto- matsko statiˇcno analizo, kot je prikazano na sliki 6.3. Navadno datoteko analiziramo s privzetimi moˇznostmi. To za velike datoteke (veˇcje od 100 MB) ni vedno moˇzno, saj je analiza ˇcasovno potratna operacija. Pri statiˇcni analizi slabogramja nam to ne predstavlja teˇzave, saj so velikosti izvrˇsljivih datotek slabogramja obiˇcajno zelo majhne.
Ko je avtomatiˇcna statiˇcna analiza konˇcana, zaˇcnemo roˇcno analizira- nje strojne kode. Obiˇcajno najprej najdemo glavno funkcijo programa in nato s sledenjem kontrolnega toka programa izvemo kaj program poˇcne. Pri analizi strojne kode si pomagamo z dodatnimi orodji, ki nam jih Ghidra po- nuja. Pomembnejˇsa orodja, ki jih pogosto uporabljamo pri statiˇcni analizi, so predstavljena v posameznih podpoglavjih.
6.2 Orodja
V tem podpoglavju predstavimo glavna orodja v programu Ghidra, ki jih pri statiˇcni analizi slabogramja najpogosteje uporabljamo.
6.2.1 Razbirno okno
Veˇcino analize poteka v razbirnem oknu. Sestavljeno je iz veˇcih stolpcev:
42 6. PROGRAM GHIDRA
Slika 6.3: Okno z moˇznostmi analize datoteke.
6.2. ORODJA 43
Slika 6.4: Glavno okno programa Ghidra.
44 6. PROGRAM GHIDRA
naslov, ki nam pove, na katerem naslovu se nahaja koda,
vsebina, ki je lahko en ali veˇc bajtov (odvisno od vrste podatka, ki se na naslovu nahaja),
ukaz zbirnika, ki je prikazan, ˇce gre za programsko kodo, komentar,
kriˇzna referenca, ki je prikazana, ˇce je ta del programa uporabljen na dru- gem mestu v kodi.
Med vrsticami se lahko nahajajo ˇse drugi podatki, kot so oznake, podpisi funkcij, komentarji, ipd.
Razbirno okno ni statiˇcno in ga lahko spreminjamo z dodajanjem oznak, spreminjanjem imen, dodajanjem komentarjev, ipd. Na veˇcino naslovov, ki se pojavijo v razbirnem oknu, lahko skoˇcimo z uporabo dvoklika, kar moˇcno olajˇsa navigacijo po kodi. Razbirno okno je povezano z veˇcino ostalih orodji v Ghidri. ˇCe v nekem orodju odpremo funkcijo na doloˇcenem naslovu, se nam razbirno okno avtomatsko postavi na to funkcijo. To delovanje je moˇzno izklopiti za posamezna orodja, ˇce takega delovanja ne ˇzelimo. Omogoˇceno nam je tudi skakanje na poljubne naslove z ukazom goto.
Z navigiranjem po kodi analiziramo potek programa. Enota analize je navadno ena funkcija. Iz strojnih ukazov razberemo delovanje funkcije. Med analizo funkcije si pomagamo z ostalimi orodji, ki nam jih Ghidra ponuja.
Z analizo povezanosti funkcij razberemo celotno delovanje analiziranega pro- grama. Na sliki 6.5 je prikazan primer ene funkcije odprte v razbirnem oknu.
Ghidra nad funkcijo vstavi velik komentar, da vemo, da gre za zaˇcetek funkcije. Temu sledi podpis funkcije, ki ga je Ghidra doloˇcila z avtomatsko analizo. Pod podpisom funkcije je na kratko opisana sestava klicnega zapisa.
Iz kriˇznih referenc lahko vidimo, do katerih naslovov v klicnem zapisu funkcija dostopa, kje do njih dostopa in na kakˇsen naˇcin (branje, pisanje ali klic).
Temu sledi ˇse telo funkcije.
6.2. ORODJA 45
Slika 6.5: Primer preproste funkcije v razbirnem oknu.
46 6. PROGRAM GHIDRA Za primer analize funkcije vzemimo analizo funkcije na sliki 6.5. Funkcija na sliki 6.5 najprej izvede svoj prolog, kjer si sharni vrednost registra EBP, nastavi trenutniEBP in z ukazom SUB na skladu rezervira prostor za lokalne spremenljivke. Iz naslednjih treh ukazov lahko razberemo, da gre za zapiso- vanje vrednosti v tabelo. Funkcija v register EAX zapiˇse velikost podatka v tabeli. Z ukazom MOV zapiˇse vrednost 0 na drugo mesto v tabeli. Naslednji ukaz MOVv register ECX shrani vrednost prvega parametra. Potem ukaz ADD registru ECXpriˇsteje vrednost drugega parametra. Naslednji trije ukazi spet sestavljajo dostop do tabele. Ukaz ADD registru ECX priˇsteje 2. element iz prejˇsnje tabele. Ta bo vedno vrednosti 0, saj ga funkcija vedno nastavi na to vrednost. Funkcija nato vrednost v registru ECXshrani na sklad v lokalno spremenljivko, ki jo nato shrani v registerEAX. Funkcija nato izvede svoj epi- log, kjer v registerESPzapiˇse vrednost registraEBPin tako za seboj pospravi sklad. Iz sklada poenostavi ˇse register EBP in se nato vrne. Ker funkcija uporablja klicno konvencijo cdecl, se njena vrednost nahaja v registru EAX.
Iz te analize lahko razberemo, da funkcija seˇsteva prvi in drugi parameter.
6.2.2 Okno za obratno prevajanje
Ghidra nam vsako funkcijo avtomatsko obratno prevede v programski jezik C. Ta obratni prevod ni vedno natanˇcen in ga je pogosto treba popraviti.
Ghidri lahko pomagamo pri obratnem prevajanju z doloˇcanjem podatkovnih tipov spremenljivk na skladu in urejanjem podpisa funkcije. ˇCeprav obratno prevajanje ni popolno, nam lahko pomaga pri razumevanju razbrane kode, saj iz viˇsjenivojske kode hitreje razberemo strukturo programa.
Na sliki 6.6 je prikazana obratno prevedena funkcija iz slike 6.5. Na sliki lahko vidimo, da Ghidra pogosto ne prikaˇze vseh ukazov, ampak samo tiste za katere doloˇci, da vplivajo na potek programa. V tem primeru je Ghidra pravilno izloˇcila dostope do lokalne tabele. Lahko se zgodi, da Ghidra ne prikaˇze ukazov, ki bi lahko bili za program pomembni.
6.2. ORODJA 47
Slika 6.6: Primer obratnega prevoda funkcije.
6.2.3 Komentarji
Ghidra nam omogoˇca dodajanje komentarjev. Komentojev je veˇc vrst:
komentar, ki se pojavi na koncu vrstice,
komentar, ki se pojavi pred ali po vrstici,
velik komentar obdan z zvezdicami,
ponavljajoˇci se komentar.
Okno za dodajanje komentarja je prikazano na sliki 6.7.
6.2.4 Urejanje imen
Ghidra za pomembne naslove generira oznake oziroma imena. Ghidra ge- nerira imena za naslove funkcij, lokalne spremenljivke funkcij, parametre funkcij, naslove podatkov, idr. Avtomatsko generirana imena lahko zaradi laˇzjega razumevanja programa spreminjamo. Moˇzno je tudi dodajanje novih oznak, da si olajˇsamo razumevanje programa. Okni za dodajanje oznak in preimenovanje obstojeˇcih imen sta si zelo podobni. Okno za preimenovanje obstojeˇcih imen je prikazano na sliki 6.8.
48 6. PROGRAM GHIDRA
Slika 6.7: Primer okna za dodajanje komentarja.
Slika 6.8: Primer okna za preimenovanje imena funkcije.
6.2. ORODJA 49
Slika 6.9: Primer okna za urejanje podpisa funkcije.
6.2.5 Urejanje podatkov o funkciji
Ghidra nam omogoˇca urejanje podpisa funkcije, ker lahko doloˇcimo ime funk- cije, ˇstevilo in tip parametrov, klicno konvencijo in dodatne posebnosti funk- cije. Primer okna za urejanje podpisa funkcije je prikazan na sliki 6.9.
Poleg sploˇsnega pregleda sklada v razbirnem oknu, nam Ghidra ponuja tudi posebno orodje za urejanje klicnega zapisa, kjer lahko podrobno spre- menimo vse funkcijske parametre in lokalne spremenljivke. Primer okna za urejanje klicnega zapisa je prikazan na sliki 6.10.
6.2.6 Urejanje podatkovnih tipov
Za doloˇcanje in spreminjanje enostavnih podatkovnih tipov zadoˇsˇca desni klik na podatek, kjer lahko izberemo ustrezni podatkovni tip. Enostavni podat- kovni tipi vkljuˇcujejo tipe kot soint,double,charin njihove tabele. ˇCe gre
50 6. PROGRAM GHIDRA
Slika 6.10: Primer okna za urejanje klicnega zapisa.
za strukturo, nam Ghidra omogoˇca ustvarjanje svojega kompleksnejˇsega po- datkovnega tipa, kot je prikazano na sliki 6.11. Kot je opisano v 4. poglavju, se informacije o sestavi tabel in struktur izgubijo pri prevajanju programa.
Poslediˇcno jih je teˇzko zaznati z avtomatsko analizo in jih je treba definirati roˇcno.
6.2.7 Grafiˇ cni prikaz diagrama poteka funkcije
Za laˇzjo predstavo kontrolnega toka funkcije nam Ghidra ponuja orodje za grafiˇcni prikaz diagrama poteka funkcije. Orodje za grafiˇcni prikaz diagrama poteka funkcije funkcijo razdeli na skupine ukazov, ki se vedno izvedejo za- poredno, nato pa jih prikaˇze povezane glede na kontrolni tok. Primer okna za grafiˇcni prikaz diagrama poteka funkcije funkcije je prikazan na sliki 6.12.
Na sliki je prikazan del funkcije, kjer vidimo osnove bloke kode in njihove povezave oznaˇcene s puˇsˇcicami, ki so pobarvane glede na vrsto skoka. V spodnjem desnem kotu se nahaja majhno okno, ki nam prikazuje celotno funkcijo in nahajanje trenutnega pogleda.
Za laˇzje razumevanje klicev funkcij nam je v Ghidri dostopen tudi graf klicev funkcij. Graf klicev funkcij nam pokaˇze, kako se funkcije kliˇcejo med
6.2. ORODJA 51
Slika 6.11: Primer okna za urejanje podatkovnega tipa.
seboj. Funkcije organizira v drevesni prikaz. Primer grafa klicev funkcij je prikazan na sliki 6.13.
52 6. PROGRAM GHIDRA
Slika 6.12: Primer okna za grafiˇcni prikaz diagrama poteka funkcije.
6.2. ORODJA 53
Slika 6.13: Primer grafa klicev funkcij.
54 6. PROGRAM GHIDRA
Poglavje 7
Primer statiˇ cne analize slabogramja
Na spletni strani, ki zbira primere slabogramja, smo izbrali dve zlonamerni datoteki [19]. Prvo slabogramje se imenujeECCENTRICBANDWAGON, drugo sla- bogramje pa SLOTHFULMEDIA. S statiˇcno analizo smo poskusili razvozlati de- lovanje obeh slabogramij. Projekt programa Ghidra in datoteke celotne ana- lize so dostopne na GitHubu [20]. V nadaljevanju kronoloˇsko opiˇsemo korake analize in na koncu povzamemo izluˇsˇceno delovanje.
7.1 Priprava delovnega okolja
Pred samo analizo slabogramja smo si postavili delovno okolje. Analizo sla- bogramja je priporoˇcljivo izvajati v kontroliranem okolju, saj tako omejimo moˇznost okuˇzbe delovnega sistema in ˇsirjenja slabogramja po mreˇzi. Za naˇse kontrolirano okolje smo si izbrali navidezni raˇcunalnik v programu Oracle VM VirtualBox. Ker so datoteke, ki smo jo analizirali, namenjene opera- cijskemu sistemu Windows, smo jih v programu VirtualBox analizirali na operacijskem sistemu Linux, da prepreˇcimo morebitno okuˇzbo. S spleta smo prenesli 64-bitno sliko distribucije Ubuntu in ustvarili navidezni raˇcunalnik.
Na navidezni raˇcunalnik smo namestili orodja, ki smo jih pri analizi upora- 55