Vrstvený mlžení: taxonomie software mlžení techniky pro vrstvené bezpečnostní

Tento oddíl zkoumá mlžení techniky pro konkrétní kód prvky. Tato vrstva pokrývá většinu publikací v oblasti mlžení softwaru. Jak je znázorněno na obr. 4, podle toho, co prvky, jako mlžení techniky cíle, můžeme rozdělit tuto kategorii do pěti sub-kategorií: zamlžování rozvržení, zamlžování kontroly, zamlžování dataobfuscating funkce, a zamlžování tříd.

obr. 4
figure4

Na mlžení techniky kód-prvek vrstva

Zamlžování uspořádání

Rozvržení mlžení pere rozložení kódy nebo instrukce při zachování původní syntaxe neporušené. Tato část pojednává o čtyřech strategiích zamlžování rozvržení: nesmyslné klasifikátory, odizolování redundantních symbolů, oddělení souvisejících kódů a nevyžádané kódy.

Bezvýznamných identifikátorů

Tento přístup je také známý jako lexikální mlžení, které transformuje smysluplné identifikátory nesmyslné ty. Pro většinu programovacích jazyků je jako správná programovací praxe vyžadováno přijetí smysluplných a jednotných pravidel pojmenování (např. maďarský zápis (Simonyi 1999)). Ačkoli jsou tyto názvy specifikovány ve zdrojových kódech, některé by ve výchozím nastavení zůstaly ve vydaném softwaru. Například názvy globálních proměnných a funkcí v C / C++ jsou uloženy v binárních souborech a všechna jména Java jsou vyhrazena v bytekodech. Protože taková smysluplná jména mohou usnadnit kontradiktorní programovou analýzu, měli bychom je vyškrábat. Aby byly zmatené identifikátory matoucí, Chan a Yang (2004) navrhli úmyslně použít stejné názvy pro objekty různých typů nebo v různých doménách. Tyto přístupy byly přijaty ProGuard (2016) jako výchozí schéma obfuskace pro Java programy.

Odstraňování nadbytečné symboly

Tato strategie proužky redundantní symbolické informace z vydané software, jako je například informace o ladění pro většinu propgrams (Nízká 1998). Kromě toho existují další redundantní symboly pro konkrétní formáty programů. Soubory ELF například obsahují tabulky symbolů, které zaznamenávají dvojice identifikátorů a adres. Při přijímání výchozích možností kompilace pro kompilaci programů C / C++, například pomocí LLVM (Lattner a Adve 2004), generované binární soubory obsahují takové tabulky symbolů. K odstranění těchto redundantních informací mohou vývojáři použít nástroj strip systému Linux. Dalším příkladem s redundantními informacemi jsou kódy Android smali. Ve výchozím nastavení generované kódy smali obsahují informace začínající .linka a .zdroj, který lze odstranit pro účely obfuskace (Dalla Preda and Maggi 2017).

oddělování souvisejících kódů

program je snadněji čitelný, pokud jsou jeho logicky související kódy také fyzicky blízké (Collberg et al . 1997). Oddělení souvisejících kódů nebo pokynů proto může zvýšit potíže při čtení. Je použitelný jak pro zdrojové kódy (např. přeskupování proměnných (Low 1998)), tak pro montážní kódy (např. pokyny pro přeskupování (Wroblewski 2002)). V praxi je použití bezpodmínečných skoků k přepsání programu populárním přístupem k dosažení tohoto cíle. Například vývojáři mohou zamíchat montážní kódy a pak zaměstnat goto rekonstruovat původní řídicí tok (vy a Yim 2010). Tento přístup je populární pro montážní kódy a Java bytecodes s dostupností instrukcí goto (Dalla Preda a Maggi 2017).

nevyžádané kódy

tato strategie přidává nevyžádané pokyny, které nejsou funkční. Pro binární soubory můžeme přidat instrukce bez provozu (NOP nebo 0x00) (Dalla Preda a Maggi 2017; Marcelli et al. 2018). Kromě toho můžeme také přidat nevyžádané metody, jako je přidání zaniklých metod do kódů Android smali (Dalla Preda a Maggi 2017). Nevyžádané kódy mohou obvykle měnit podpisy kódů, a proto unikají statickému rozpoznávání vzorů.

protože zmatenost rozvržení neovlivňuje původní syntaxi kódu, je méně náchylná k problémům s kompatibilitou nebo chybám. Proto jsou tyto techniky v praxi nejoblíbenější. Navíc techniky nesmyslných identifikátorů a odizolování redundantních symbolů mohou snížit velikost programů, což je dále činí atraktivními (ProGuard 2016). Účinnost rozvržení je však omezená. Má slibnou odolnost vůči útokům deobfuskace, protože některé transformace jsou jednosměrné,které nelze zvrátit. Některé informace o rozvržení však lze jen stěží změnit, například identifikátory metody z Java SDK. Takové zbytkové informace jsou nezbytné pro protivníky, aby obnovili zamlžené informace. Například Bichsel et al. (2016) se pokusil deobfuscated ProGuard-zmatené aplikace, a úspěšně obnovit kolem 80% jmen.

Obfuscating controls

tento typ obfuscation technik transformuje ovládací prvky kódů pro zvýšení složitosti programu. Toho lze dosáhnout pomocí falešných řídicích toků, pravděpodobnostních řídicích toků, dispečerských kontrol a implicitních kontrol.

falešné řídicí toky

falešné řídicí toky se vztahují k řídicím tokům, které jsou záměrně přidány do programu, ale nikdy nebudou provedeny. Může zvýšit složitost programu, např., in McCabe complexity (McCabe 1976) nebo Harrison metrics (Harrison and Magel 1981). Například, McCabe složitost (McCabe 1976) se vypočítá jako počet hran na grafu řízení toku minus počet uzlů, a pak plus dvakrát připojených komponent. Chcete-li zvýšit složitost McCabe, můžeme buď zavést nové hrany nebo přidat nové hrany a uzly k připojené komponentě.

aby byla zaručena nedosažitelnost falešných kontrolních toků, Collberg et al. (1997) navrhl použití neprůhledných predikátů. Definovali neprůhledný predikát jako predikát, jehož výsledek je znám během zmatku, ale je obtížné odvodit statickou programovou analýzou. Obecně platí, že neprůhledný predikát může být neustále pravdivý (PT), neustále nepravdivý (PF) nebo kontextově závislý (P?). Existují tři metody pro vytvoření neprůhledných predikátů: numerická schémata, programovací schémata a kontextová schémata.

Numerická schémata

Numerická schémata tvoří neprůhledné predikáty s matematickými výrazy. Například 7×2-1≠y2 platí neustále pro všechna celá čísla x a y. Můžeme přímo použít takové neprůhledné predikáty k zavedení falešných kontrolních toků. Obrázek 5a ukazuje příklad, ve kterém neprůhledný predikát zaručuje, že falešný řídicí tok (tj. Útočníci by však měli větší šanci je odhalit, pokud v zamlženém programu často používáme stejné neprůhledné predikáty. Arboit (2002) proto navrhl automaticky vygenerovat rodinu takových neprůhledných predikátů, takže obfuscator si může pokaždé vybrat jedinečný neprůhledný predikát.

obr. 5
figure5

Control-flow mlžení s neprůhledným predikáty

Další matematický přístup s vyšší bezpečnosti, je použití šifrovací funkce, jako je hash funkce \(\mathcal {H}\) (Sharif et al. 2008) a homomorfní šifrování (Zhu and Thomborson 2005). Například, my můžeme nahradit predikát x==c \(\mathcal {H}(x)==c_{hash}\) skrýt řešení x pro tuto rovnici. Všimněte si, že takový přístup je obecně používán malwarem, aby se vyhnul dynamické analýze programů. Můžeme také použít kryptografické funkce k šifrování rovnic, které nelze uspokojit. Takové neprůhledné predikáty však způsobují velkou režii.

pro vytvoření neprůhledných konstant odolných vůči statické analýze, Moser et al. (2007) navrhl zaměstnávat 3-SAT problémy, které jsou NP-hard. To je možné, protože člověk může mít efektivní algoritmy pro vytváření takových těžkých problémů (Selman et al . 1996). Například Tiella a Ceccato (2017) předvedli, jak sestavit takové neprůhledné predikáty s problémy k-clique.

pro vytvoření neprůhledných konstant odolných vůči dynamické analýze, Wang et al. (2011) navrhl sestavit neprůhledné predikáty s formou nevyřešených dohadů, které se mnohokrát opakují. Protože smyčky jsou náročné pro dynamickou analýzu, přístup v přírodě by měl být odolný vůči dynamické analýze. Příklady takových domněnek zahrnují Collatzovu domněnku, 5x+1 domněnku, Matthewsovu domněnku. Obrázek 5b ukazuje, jak využít Collatz domněnky zavést falešné kontrolní toky. Bez ohledu na to, jak inicializujeme x, program končí s x=1 a originalCodes() lze vždy spustit.

Programování Systémů

Protože kontradiktorní program analýzy je velkou hrozbou pro neprůhledné predikáty, můžeme využít náročný program analýzy problémů skládat neprůhledné predikáty. Collberg et al. navrhl dva klasické problémy, analýzu ukazatelů a souběžné programy.

obecně se analýza ukazatelů týká určení, zda dva ukazatele mohou nebo mohou ukazovat na stejnou adresu. Některé problémy s analýzou ukazatelů mohou být NP-těžké pro statickou analýzu nebo dokonce nerozhodnutelné (Landi and Ryder 1991). Další výhodou je, že operace ukazatele jsou během provádění velmi efektivní. Proto se vývojáři mohou vytvářet pružný a efektivní neprůhledné předpovídá s dobře navržené ukazatele analýzy problémů, jako je udržování ukazatele na některé objekty s dynamickými datovými strukturami (Collberg et al. 1998a).

souběžné programy nebo paralelní programy jsou dalším náročným problémem. Obecně platí, že paralelní oblast n výroků má n! různé způsoby provedení. Provedení není určeno pouze programem, ale také stavem běhu hostitelského počítače. Collberg et al. (1998a) navrhl použít souběžné programy pro zlepšení přístupu založeného na ukazatelích souběžnou aktualizací ukazatelů. Majumdar a Thomborson (2006) navrhli použít distribuované paralelní programy k vytváření neprůhledných predikátů.

kromě toho některé přístupy skládají neprůhledné predikáty s programovacími triky, jako je využití mechanismů zpracování výjimek. Například Dolz a Parra (2008) navrhli použít mechanismus try-catch k vytvoření neprůhledných predikátů pro. NET a Java. Události výjimek zahrnují dělení nulou, nulovým ukazatelem, indexem mimo rozsah nebo dokonce zvláštními výjimkami hardwaru (Chen et al. 2009). Původní sémantiku programu lze dosáhnout pomocí přizpůsobených schémat zpracování výjimek. Takové neprůhledné predikáty však nemají žádný bezpečnostní základ a jsou náchylné k pokročilým ručním útokům.

kontextová schémata

kontextová schémata mohou být použita k vytvoření variantních neprůhledných predikátů (tj. {P?}). Predikáty by měly mít některé deterministické vlastnosti, aby mohly být použity k zamlžení programů. Například rouška a kol. (2009) navrhl sestavit takové neprůhledné predikáty, které jsou invariantní pod kontextovým omezením, např. neprůhledný predikát x mod3= = 1 je neustále pravdivý, pokud x mod3:1?x++: x=x+3. Palsberg et al. (2000) navrhované dynamické neprůhledné predikáty, které zahrnují sekvenci korelovaných predikátů. Výsledek hodnocení každého predikátu se může v každém běhu lišit. Pokud jsou však predikáty korelovány, chování programu je deterministické. Obrázek 5c ukazuje příklad dynamických neprůhledných predikátů. Bez ohledu na to, jak inicializujeme *p a * q, program je ekvivalentní y=x+3, x=y+3.

odpor falešných řídicích toků většinou závisí na bezpečnosti neprůhledných predikátů. Ideální bezpečnostní vlastnost pro neprůhledné predikáty je, že vyžadují zlomení exponenciálního času v nejhorším případě, ale pouze polynomiální čas. Všimněte si, že některé neprůhledné predikáty jsou navrženy s takovými bezpečnostními obavami, ale mohou být implementovány s vadami. Například problémy 3-SAT navržené Ogiso et al. (2003) jsou založeny na triviální nastavení problému, které lze snadno zjednodušit. Pokud jsou takové neprůhledné predikáty implementovány správně, slibovaly by, že budou odolné.

pravděpodobnostní řídicí toky

falešné řídicí toky mohou způsobit potíže statické analýze programu. Jsou však náchylné k dynamické analýze programu, protože falešné řídicí toky jsou neaktivní. Myšlenka pravděpodobnostních kontrolních toků přijímá jinou strategii k řešení hrozby (Pawlowski et al . 2016). Zavádí replikace řídicích toků se stejnou sémantikou, ale odlišnou syntaxí. Při příjmu stejného vstupu několikrát se program může chovat odlišně pro různé doby provádění. Tato technika je také užitečná pro boj proti útokům na bočních kanálech (Crane et al. 2015).

Všimněte si, že strategie pravděpodobnostních řídicích toků je podobná falešným řídicím tokům s kontextovými neprůhlednými predikáty. Jsou však odlišné povahy, protože kontextové neprůhledné predikáty zavádějí mrtvé cesty, i když nezavádějí nevyžádané kódy.

dispečerské řízení

dispečerské řízení určuje další bloky kódů, které mají být provedeny za běhu. Takové kontroly jsou nezbytné pro zmatení řídicího toku, protože mohou skrýt původní řídicí toky proti statické analýze programu.

jedním z hlavních dispečerských obfuskačních přístupů je zploštění řídicího toku, které transformuje kódy hloubky na mělké s větší složitostí. Wang et al. (2000) nejprve navrhl tento přístup. Figura 6 ukazuje příklad z jejich papíru, který transformuje while smyčku do jiné formy se spínacím pouzdrem. Pro realizaci takové transformace je prvním krokem transformace kódu na ekvivalentní reprezentaci s příkazy if-then-goto, jak je znázorněno na obr. 6; poté upraví příkazy goto pomocí příkazů přepínačů, jak je znázorněno na obr. 6. Tímto způsobem je původní programová sémantika realizována implicitně řízením toku dat proměnné přepínače. Protože pořadí provádění bloků kódu je dynamicky určeno proměnnou, nelze znát řídicí toky bez spuštění programu. Cappaert a Preneel (2010) formální kontrola-flow zploštění zaměstnává dispečer uzlu (např. switch), který řídí další blok kódu, které mají být provedeny; po provedení blok, ovládání je převedena zpět na odesílatele uzlu. Kromě toho existuje několik vylepšení zploštění toku kódu. Například pro zvýšení odolnosti vůči statické analýze programu na proměnné spínače, Wang et al. (2001) navrhl zavést problémy s analýzou ukazatelů. Dále komplikovat program, Chow et al. (2001) navrhl přidat falešné bloky kódu.

obr. 6
číslo6

řízení toku zploštění přístup navržený Wang et al. (2000)

László a Kiss (2009) navrhli mechanismus zploštění řízení a toku pro zpracování specifické syntaxe C++, jako je try-catch, while-do, continue. Mechanismus je založen na abstraktním syntaxovém stromu a používá pevný vzor rozvržení. Pro každý blok kódu k zamlžení, konstruuje while prohlášení ve vnější smyčce a switch-case sloučeniny uvnitř smyčky. Sloučenina switch-case implementuje původní programovou sémantiku a proměnná switch se také používá k ukončení vnější smyčky. Cappaert a Preneel (2010) zjistili, že mechanismy by mohly být ohroženy místní analýzy, tj., spínače, proměnné, je ihned přiřazena taková, že protivníci lze odvodit další blok spustit pouze při pohledu do aktuálního bloku. Navrhli posílený přístup s několika triky, jako je zaměstnávání referenční úkol (např. swVar=swVar+1) namísto přímého přiřazení (např. swVar=3), nahrazení přiřazení pomocí if-else s jednotným přiřazení výraz a zaměstnává jednosměrný funkce při výpočtu nástupce základního bloku.

kromě zploštění řídicího toku existuje několik dalších dispečerských obfuskačních vyšetřování (např. (Linn and Debray 2003; Ge et al. 2005; Zhang et al. 2010; Schrittwieser a Katzenbeisser 2011)). Linn a Debray (2003) navrhli zamlžovat binární soubory s pobočkovými funkcemi, které řídí provádění na základě informací o zásobníku. Podobně, Zhang et al. (2010) navrhuje zaměstnat větev funkce obfuscate objektově orientované programy, které definují jednotný způsob vyvolání styl s objektem, bazén. Pro zvýšení bezpečnosti těchto mechanismů, Ge et al. (2005) navrhl skrýt kontrolní informace v jiném samostatném procesu a využívat meziprocesní komunikaci. Schrittwieser a Katzenbeisser (2011) navrhli použít diverzifikované bloky kódu, které implementují stejnou sémantiku.

dispečerská obfuskace je odolná proti statické analýze, protože skrývá graf řídicího toku softwarového programu. Je však zranitelný dynamickou programovou analýzou nebo hybridními přístupy. Například Udupa et al. (2005) navrhl hybridní přístup k odhalení skrytých řídicích toků jak statickou analýzou, tak dynamickou analýzou.

implicitní ovládací prvky

tato strategie převádí explicitní řídicí pokyny na implicitní. Může bránit zpětným technikům v řešení správných řídicích toků. JMP a jne) kombinací mov a dalších pokynů, které implementují stejnou řídicí sémantiku (Balachandran and Emmanuel 2011).

Všimněte si, že všechny existující přístupy k obfuskaci řídicího toku se zaměřují na syntaktickou transformaci, zatímco ochrana sémantické úrovně byla zřídka diskutována. I když mohou prokázat určitou odolnost vůči útokům, jejich obfuskační účinnost týkající se sémantické ochrany zůstává nejasná.

Obfuscating data

současné techniky obfuscation dat se zaměřují na běžné datové typy, jako jsou celá čísla, řetězce a pole. Můžeme transformovat data pomocí rozdělení, sloučení, procedurizace, kódování atd.

rozdělení/sloučení dat

rozdělení dat rozděluje informace jedné proměnné do několika nových proměnných. Například booleovská proměnná může být rozdělena na dvě booleovské proměnné a provádění logických operací na nich může získat původní hodnotu.

sloučení dat naproti tomu agreguje několik proměnných do jedné proměnné. Collberg et al. (1998b) demonstroval příklad, který sloučí dvě 32bitová celá čísla do jednoho 64bitového celého čísla. Ertaul a Venkatesh (2005) navrhli další metodu, která zabalí několik proměnných do jednoho prostoru s diskrétními logaritmy.

procedurizace dat

procedurizace dat nahrazuje statická data voláním procedur. Collberg et al. (1998b) navrhl nahradit řetězce funkcí, která může produkovat všechny řetězce zadáním hodnot patikulárních parametrů. Rouška a et al. (2004) navrhl kódování číselných dat dvěma inverzními funkcemi f A g. Chcete-li přiřadit hodnotu v proměnné i, přiřadíme ji injektované proměnné j jako j=f(v). Chcete-li použít i, místo toho vyvoláme g(j).

kódování dat

kódování dat kóduje data matematickými funkcemi nebo šifry. Ertaul a Venkatesh (2005) navrhli kódovat řetězce pomocí afinních šifer (např. Caserova šifra) a používat diskrétní logaritmy k balení slov. Fukušima a kol. (2008) navrhl zakódovat jasná čísla s exkluzivními nebo operacemi a poté dešifrovat výsledek výpočtu před výstupem. Kovacheva (2013) navrhl šifrovat řetězce pomocí šifry RC4 a poté je dešifrovat během běhu.

transformace pole

pole je jednou z nejčastěji používaných datových struktur. Chcete-li zamlžit pole, Collberg et al. (1998b), diskutovala o několika transformací, jako je rozdělení jednoho pole do několika subarrays, slučování více polí do jednoho pole, skládací pole pro zvýšení jeho rozměr, nebo zploštění pole pro snížení dimenze. Ertaul a Venkatesh (2005) navrhli transformaci indexů pole pomocí kompozitních funkcí. Zhu et al. (2006); Zhu (2007) navrhl použít homomorfní šifrování pro transformaci pole, včetně změny indexu, skládání a lichotení. Například, můžeme zamíchat prvky matice s∗m mod n, kde i je původní index, n je velikost původního pole, a m a n jsou nesoudělné.

Zamlžování metody

Metoda inline/outline

metoda je nezávislá postup, který může být volán další instrukce programu. Metoda inline nahrazuje původní procedurální volání samotným tělem funkce. Metoda outline pracuje opačným způsobem, který extrahuje posloupnost instrukcí a abstraktuje metodu. Jsou to dobré společnosti, které mohou zamlžit původní abstrakci postupů (Collberg et al. 1997).

metoda clone

pokud je metoda silně vyvolána, můžeme vytvořit replikace metody a náhodně zavolat jednu z nich. Zmást sporné interpretace, každá verze replikace by měl být jedinečný nějak, jako například přijetím odlišné obfuscation transformací (Collberg et al. 1997) nebo různé podpisy (Ertaul a Venkatesh 2004).

metoda agregace / rozptyl

myšlenka je podobná zmatení dat. Můžeme agregovat irelevantní metody do jedné metody nebo rozptylovat metodu do několika metod (Collberg et al. 1997; nízký 1998).

metoda proxy

tento přístup vytváří metody proxy, které zaměňují reverzní inženýrství. Můžeme například vytvořit proxy jako veřejné statické metody s randomizovanými identifikátory. Pro stejnou metodu může existovat několik odlišných proxy (Dalla Preda a Maggi 2017). Tento přístup je velmi užitečný, když podpisy metody nelze změnit (Protsenko and Muller 2013).

Zamlžování třídy

Zamlžování tříd sdílí některé podobné nápady s zamlžování metody, jako je štěpení a klonování (Collberg et al. 1998b). Protože však třída existuje pouze v objektově orientovaných programovacích jazycích, jako je JAVA a. net, diskutujeme o nich jako o jedinečné kategorii. Níže uvádíme hlavní strategie pro zamlžení tříd.

Dropovací modifikátory

objektově orientované programy obsahují modifikátory (např., veřejné, soukromé) omezit přístup k třídám a členům tříd. Dropping modifikátory odstraní taková omezení a zveřejní všechny členy (Protsenko and Muller 2013). Tento přístup může usnadnit implementaci dalších metod mlžení třídy.

Rozdělení/Spojování třídy

myšlenka spojit/rozdělit je obfuscate záměr vývojáři při návrhu tříd (Sosonkin et al. 2003). Při splynutí tříd můžeme přenést místní proměnné nebo místní instrukční skupiny do jiné třídy (Fukushima et al. 2003).

zploštění hierarchie tříd

rozhraní je výkonný nástroj pro objektově orientované programy. Podobně jako metoda proxy, můžeme vytvořit proxy pro třídy s rozhraními (Sosonkin et al. 2003). Účinnějším způsobem je však přerušit původní dědičný vztah mezi třídami s rozhraními. Tím, že necháme každý uzel podstromu v hierarchii tříd implementovat stejné rozhraní, můžeme hierarchii vyrovnat (Foket et al. 2012).

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.