Prihlásenie

SecIT na Facebooku

SecIT.sk na Facebooku

Odpovedať na komentár

4.42857
Priemerné hodnotenie: 4.4 (7 votes)
Vaše hodnotenie: Žiadne

V několika minulých dnech jsem se intenzivně zabýval zjišťováním, jakže to funguje ochrana jednoho nejmenovaného bezpečnostního produktu. Tato činnost často obnáší použití disassembleru a debuggeru a tento případ nebyl výjimkou. Během práce jsem si všiml přítomnosti zvláštní instrukce REP RET. Kdybych ji neviděl na vlastní oči, pokládal bych ji za neplatnou. Ale protože ji zřejmě procesor "sežere", udělal jsem malé pátrání, abych se dozvěděl, co tato instrukce provádí.

Rozklad

Záhadná instrukce se skládá ze dvou částí. Pokud se na ně podíváme odděleně, nic nás nepřekvapí. Jak REP, tak RET dávají smysl. Pravda, prefix REP musí být následován nějakou instrukcí, ale jak uvidíme v následujícím odstavci, RET by mezi takové patřit rozhodně neměla.

Příznak REP říká procesoru, aby následující instrukci prováděl pořád dokola a při každé obrátce snížil hodnotu v registru ECX (CX na 16-bitové platformě, RCX na 64-bitové) o jedničku. Cyklus skončí, jakmile hodnota registru dosáhne nuly. Proto se tento příznak využívá například při kopírování bloku paměti, práci s řetězci či jiných cyklických operacích.

Instrukci RET se také jinak říká návrat z podprogramu. Procesor vybere z vrcholu zásobníku slovo (v bajtech odpovídá velikosti adresy) a zapíše jej do registru EIP (IP na 16-bitové platformě, RIP na 64-bitové). Protože tento registr vždy obsahuje adresu instrukce, která se má začít vykonávat, dojde ke skoku na adresu, jež se nacházela na vrcholu zásobníku. Existuje též varianta, která po načtení hodnoty do xIP odstraní z vrcholu zásobníku dalších n bajtů. Nazývá se RET n.

Sémantika

Už tedy víme, k čemu slouží příznak REP a instrukce RET, použijeme-li je zvlášť. Ale jakou má sémantiku instrukce, která vznikne jejich spojením (REP RET)? Má vybírat slova ze zásobníku, dokud nebude xCX obsahovat nulu a na adresu v posledním odebraném skočit? Nebo snížit registr o jedničku, vybrat slovo ze zásobníku, použít jej jako adresu pro skok a dál v opakování nepokračovat, protože skok změnil adresu aktuální instrukce? Ani jedna odpověď není správná.

Dnešní procesory jsou velmi složité a pro zvýšení rychlosti využívají vyrovnávacích pamětí (L1, L2, L3 cache a další) či techniky zpracovávání více instrukcí najednou zvané pipelining či superskalární pipelining. Procesor nenačítá instrukce přesně tak, jak mu velí změny hodnoty v registru xIP, ale snaží se předem odhadnout, kudy program poběží a tyto instrukce si načíst (a případně předzpracovat) dříve, než ve skutečnosti potřebuje (prefetching). Moderní procesory též zpracovávají více instrukcí najednou - zatímco se jedna dekóduje, druhá může zapisovat do registru a třetí číst z paměti.

Aby mohl úspěšně načítat instrukce "dopředu", procesor musí nějakým způsobem uhodnout, kudy se tok programu bude ubírat. Problém zde mohou způsobovat například podmíněné skoky - v době jejich "přednačtení" nemusí být známo, jestli je podmínka skoku splněna, nebo ne. V takovém případě se některé procesory pokusí další tok programu odhadnout a načíst a předzpracovat instrukce z příslušné adresy. Pokud se odhad ukáže jako nesprávný, předzpracované instrukce jsou zahozeny a pocesor se vrátí do stavu před provedením podmíněného skoku (či jinou instrukcí, která vyžaduje hádání).

Jak se podle mého zdroje píše v manuálech AMD, implementace dopředného načítání instrukcí se dostane do potíží, nachází-li se těsně po instrukci podmíněného skoku instrukce návratu z procedury. Procesor přestane přednačítávat další instrukce, dokud se nevykoná RET, nebo se tok programu nepřesměruje do jiných míst. Má-li však taková instrukce před sebou prefix REP, k "záseku" nedochází, a tedy výkon procesoru není ztracen.

Na závěr ještě uvedu zdrojovou URL a příslušnou citaci:


Here's the principle. The processor tries to fetch the next few
instructions to be executed, so that it can start the process of decoding
and executing them. It even does this with jump and return instructions,
guessing where the program will head next.


What AMD says here is that, if a ret instruction immediately follows a
conditional jump instruction, their predictor cannot figure out where the
ret instruction is going. The pre-fetching has to stop until the ret
actually executes, and only then will it be able to start looking ahead
again.


The "rep ret" trick apparently works around the problem, and lets the
predictor do its job. The "rep" has no effect on the instruction.

http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm.x86/2006-03/msg00041.html

Sledujte aktuality zo sveta IT bezpečnosti!

Odpovedať

Obsah tohto poľa je súkromný a nebude verejne zobrazený.
  • Riadky a odstavce sa zalomia automaticky.

Viac informácií o možnostiach formátovania

CAPTCHA
Opíšte prosím znaky z obrázka, potvrdíte tak, že sa nejedná o spam. Nula sa medzi znakmi nevyskytuje.
Image CAPTCHA
Napíšte znaky zobrazené na obrázku. Ignorujte medzery, ale dbajte na správne napísanie malých a veľkých písmen, či iných znakov.

Fórum | IRC

SecIT.sk fórum

IRC kanál: #secit
IRC server: irc.secit.sk
Porty (SSL): 6696, 9998
Porty (bez SSL): 6667, 6670

Freeweb by WebSupport.sk

© SecIT.sk - info(at)secit.sk - Všetky práva vyhradené. Žiaden obsah umiestnený na našom portáli a fóre sa nesmie kopírovať!