<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/tips/8053

            本文將簡要介紹Jscript 9 (Charka)引擎處理數字、對象、函數操作的一些內容。

            0x00 Jscript9 的安全機制


            IE9開始,微軟使用了全新的JavaScript引擎—工程代號Charka版本9的JavaScript引擎。而IE8中它的版本還是5,也就是說5到9之間其實沒有什么其他版本了,既然版本號跳躍如此之大,那Charka(下均稱Jscript 9)到底有什么改進呢?

            首先,與Jscript 5不同的是,JScript9引入了一個新的JIT,由此指令的執行變得更加線性化,不用像之前一樣跳來跳去的執行各個分支,源代碼經過解析器生成AST,然后經過字節碼生成器產生字節碼并由其JIT解釋成機器碼并執行。也達到了之前類似Malzilla Firefox所稱Javascript執行性能已經達到原生C++編譯出的代碼的水平。

            本文中我們將關注:

            大改之后的JScript,由于引入了字節碼執行方式,相對于之前的解釋型執行,必然會為攻擊者提供一些新的思路—ROP。

            字節碼的編譯過程中,如果像編譯普通EXE一樣產生字節碼,必然會遇到如下的問題:

            在微軟的層層保護之下,如果字節碼不設防,那么從字節碼中進行ROP將會是一個十分輕松愉悅的過程。由攻擊者控制的JS代碼(和生成的字節碼)中產生Gadget將會十分簡單,這個可能給UAF類型的漏洞的利用常嚴重的影響,會大幅降低攻擊者攻擊的難度。

            因此,在JScript9的JIT引擎中,引入了大量的安全概念1

            (1)代碼是默認開啟DEP的;

            (2)代碼對齊隨機化,字節碼存放在各個新申請的內存中,“頂格”放可能會被預測地址,因此在對齊方面預留了這樣的一手;

            (3)隨機NOP插入,也是同樣防止攻擊者預測指令地址的,在調試JIT生成的字節碼中,你也許會發現有很多莫名其妙的指令,例如mov ecx,ecx, lea ecx, [ecx],不用理會,這些都是它插入的NOP;

            (4)常量加密存儲,你會發現DWORD值在字節碼中并不是按照原樣存放的,而是xor了一個隨機的值存放,并在使用它的時候再次xor解開;

            (5)以及JIT內存分配的上限,以及頁的隨機化。

            讓我們看一下最為直觀的(4),在閱讀NDSS15的一篇論文時,我關注到了作者所述“Charka中小于2字節的常量都是XOR一個值并存放起來,并在使用時解開”。但是在之后的調試中我發現這個描述是不正確的。看起來也是作者的筆誤。

            經過調試,可知整數的存取整理如下:

            32位IE中,

            (1)2 byte以上32位整數常量全部以(n * 2 + 1) xor (some value)過的形式存在內存中;xor key隨機,需要一段代碼解開才能繼續使用;

            (2)n > 0x7fffffff的值無法* 2 + 1放在EXX寄存器中了,這個時候會轉入SSE寄存器中(xmmX)來處理;

            (3)2 byte以下常量將以n * 2 + 1的方式保存,并在需要使用時將其右移一位再使用。

            以下是具體的例子:

            1、“2Byte” 以下的正整數和負整數。

            2 byte以下常量將以n * 2 + 1的方式保存,并在需要使用時將其右移一位再使用。

            正常來說,32位整數,包括負數在Chakra中均采用有符號數來處理,那-1即0xffffffff,讓我們通過實例來確定是否存在這個情況。

            考慮如下JS代碼: var a = 1; var b = -1; a--; b++;

            掛上調試器,棧中看到這種解釋不出來名字的,跟在Js::JavascriptFunction::CallFunction的,就是編譯出來的字節碼:

            enter image description here

            該地址所在的內存頁的Allocation Base基本就是函數開頭,觀察該函數。

            首先可以看到大量的NOP插入,如箭頭處,感覺沒有什么大作用的語句會讓想從這里拿到ROP的片段的攻擊者大為頭疼。

            enter image description here

            繼續往下,可以看到在Chakra(11.0.9600.17689)中,這兩個數字被解釋為:

            enter image description here

            1被存儲為了3 ,也即 1 * 2 + 1 (左移一位加一)。 -1 被存儲為了0xffffffff, -1 * 2 + 1 = -1 (同上)。

            enter image description here

            而由于編譯執行,所以編譯器自然地做了優化,將a++ 的值2按 * 2 + 1編碼后5 和 b— 的值 -2 ,編碼后-2 * 2 + 1 = -3 (0xfffffffd)提前計算好寫入了字節碼中,如上圖,這個和流行的編譯器的優化邏輯如出一轍,只不過并沒有像是編譯器那樣那么徹底,有點像Release開啟了O1 O2優化之后的感覺。但是明顯效率高于Debug版的。

            讓我們看一下同樣代碼在VS2008 Release開啟O2和Debug 默認以及Chakra的結果:

            enter image description here

            代碼在Debug Vs2008生成如下操作:

            enter image description here

            可以看到就是逐句翻譯,真·機翻的感覺。

            enter image description here

            enter image description here

            Release 開啟O2之后的效果,這里已經把加加減減的值算好了,這個和Chakra的動作一樣。

            enter image description here

            enter image description here

            代碼比較簡單,所以開啟O1也是一個效果,所以用腳趾頭也可以得出結論,Chakra的字節碼編譯過程中確實有優化。

            不過不同于VS,如果你直接寫個變量加加減減最后哪兒也不用他,開啟OX優化的時候,這個變量根本就不會編譯進EXE,而Chakra則稍有不同,即使沒用,還是編譯進來了,只不過做了最大可能的優化處理。

            如果全優化了,F12你怎么調試呢。

            2、“2Byte”~“4Byte”之間的整數存取

            這個區間內的數字比較特殊,采用了異或的方式存儲。異或的隨機密鑰在生成字節碼時由編譯器確定。

            考慮如下JS代碼:

            var a = 0x32132132; var b = -0x12312312;

            a++; b--;

            調試可知,這里的數字被“加密”了:

            enter image description here

            062a003f bad8359075      mov     edx,offset USP10!pScriptProperties+0xd0 (759035d8)
            062a0044 81f2bd77b611    xor     edx,11B677BDh
            

            為例 (a = 0x32132132;)

            0:008> g
            Breakpoint 0 hit
            eax=9ef4b531 ebx=03f2bad0 ecx=03419720 edx=db9db9db esi=03f2b8bc edi=062a0000
            eip=062a003f esp=03f2b8a0 ebp=03f2b8a8 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
            062a003f bad8359075      mov     edx,offset USP10!pScriptProperties+0xd0 (759035d8)
            0:008> p
            eax=9ef4b531 ebx=03f2bad0 ecx=03419720 edx=759035d8 esi=03f2b8bc edi=062a0000
            eip=062a0044 esp=03f2b8a0 ebp=03f2b8a8 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
            062a0044 81f2bd77b611    xor     edx,11B677BDh
            0:008> 
            eax=9ef4b531 ebx=03f2bad0 ecx=03419720 edx=64264265 esi=03f2b8bc edi=062a0000
            eip=062a004a esp=03f2b8a0 ebp=03f2b8a8 iopl=0         nv up ei pl nz na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
            062a004a 899108060000    mov     dword ptr [ecx+608h],edx ds:002b:03419d28=67422664
            

            將edx右移一位,得到0x32132132即a的值。

            負數的處理也是一樣,以第二句為例:

            062a0056 ba170c6687      mov     edx,87660C17h
            062a005b 81f2cab5fb5c    xor     edx,5CFBB5CAh
            
            0:008> 
            eax=9ef4b531 ebx=03f2bad0 ecx=03419720 edx=64264265 esi=03f2b8bc edi=062a0000
            eip=062a0056 esp=03f2b8a0 ebp=03f2b8a8 iopl=0         nv up ei pl nz na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
            062a0056 ba170c6687      mov     edx,87660C17h
            0:008> 
            eax=9ef4b531 ebx=03f2bad0 ecx=03419720 edx=87660c17 esi=03f2b8bc edi=062a0000
            eip=062a005b esp=03f2b8a0 ebp=03f2b8a8 iopl=0         nv up ei pl nz na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
            062a005b 81f2cab5fb5c    xor     edx,5CFBB5CAh
            0:008> 
            eax=9ef4b531 ebx=03f2bad0 ecx=03419720 edx=db9db9dd esi=03f2b8bc edi=062a0000
            eip=062a0061 esp=03f2b8a0 ebp=03f2b8a8 iopl=0         nv up ei ng nz na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
            062a0061 89910c060000    mov     dword ptr [ecx+60Ch],edx ds:002b:03419d2c=dbb99ddb
            

            得到edx后,將其右移一位得到0xEDCEDCEE (記得符號位不要也一起右移了)。正是var b = -0x12312312;。

            下方a++運算結果和2byte的例子一樣,我們就簡單看一個

            062a006d ba30059380      mov     edx,80930530h
            062a0072 81f25747b5e4    xor     edx,0E4B54757h
            

            異或后:64264267 右移一位:32132133 (32132132 + 1)

            3、4byte以上的結果

            作為32位有符號數,大于4byte的就不好弄了,讓我們看看

            var a=0x90909090;
            var b=0x99999999;
            a++;b++;
            

            的結果:

            針對它的加法,JS已經選擇用SSE2的函數了:

            07030080 68b8b31803      push    318B3B8h
            07030085 53              push    ebx
            07030086 e88539e46b      call    jscript9!Js::SSE2::JavascriptMath::Increment_Full (72e73a10)
            0703008b 8bf8            mov     edi,eax
            0703008d e9b8ffffff      jmp     0703004a
            

            它們的值被提前算好存儲起來了:

            063b0067 47              inc     edi
            063b0068 8b1504612c03    mov     edx,dword ptr ds:[32C6104h]
            063b006e 81fa804f2c03    cmp     edx,32C4F80h
            063b0074 0f8562000000    jne     063b00dc
            
            063b007a 8b1508612c03    mov     edx,dword ptr ds:[32C6108h]
            063b0080 8bff            mov     edi,edi
            063b0082 899a08060000    mov     dword ptr [edx+608h],ebx
            063b0088 8b1508612c03    mov     edx,dword ptr ds:[32C6108h]
            063b008e 89b20c060000    mov     dword ptr [edx+60Ch],esi
            063b0094 8b1508612c03    mov     edx,dword ptr ds:[32C6108h]
            063b009a 898208060000    mov     dword ptr [edx+608h],eax
            063b00a0 8b1508612c03    mov     edx,dword ptr ds:[32C6108h]
            063b00a6 898a0c060000    mov     dword ptr [edx+60Ch],ecx
            

            ebx、esi等其實是存儲著mmword 的指針,但這看起來并不直觀,所以我們需要有更直觀的方式:

            var a=0x90909090;
            var b=0x99999999;
            b = a+b;
            
            068f0026 8d6424f4        lea     esp,[esp-0Ch]
            068f002a 57              push    edi
            068f002b 56              push    esi
            068f002c 53              push    ebx
            068f002d bbf0805503      mov     ebx,35580F0h
            068f0032 be00815503      mov     esi,3558100h
            068f0037 33ff            xor     edi,edi
            068f0039 f20f10056c490003 movsd   xmm0,mmword ptr ds:[300496Ch]
            068f0041 f20f100db4f96e00 movsd   xmm1,mmword ptr ds:[6EF9B4h]
            068f0049 f20f58c1        addsd   xmm0,xmm1
            068f004d 8b0538b8fb02    mov     eax,dword ptr ds:[2FBB838h]
            068f0053 8d4810          lea     ecx,[eax+10h]
            068f0056 3b0d34b8fb02    cmp     ecx,dword ptr ds:[2FBB834h]
            068f005c 0f875b000000    ja      068f00bd
            

            這回就看的很清楚了

            enter image description here

            enter image description here

            這正是我們的第一個數,0x90909090;

            enter image description here

            第二個數也不例外,

            enter image description here

            可見,使用xmm的時候,Chakra并沒有給它們做任何的混淆,事實上也沒有什么太大的必要混淆這類數字了,因此做法可以接受。

            VIII.2 對象的操作與結構

            作為一個面向對象的語言,JScript中寬松的定義使得對象操作簡單但是又“復雜” ,考慮如下代碼。

            var a = new Object;  
            a.X = 3; a.Y = 4;
            

            此時a是一個含有X、Y兩個Number成員的Object,它的編譯方式是怎樣呢?

            請一定要記得上一節的內容,3和4在內存里面是7和9。

            enter image description here

            只有這樣,我們才能愉快地找到后兩句的位置,閱讀代碼可知這個對象的內存分布是:

            +0: jscript9!Js::ArrayBufferParent::`vftable' 
            

            enter image description here

            左邊是Object,右邊是成員的兩個Number,在Windbg中可以跟蹤得到:

            0:007> dd [edi+8]
            0b69a030  00000007 00000009 030eb040 030eb040
            0b69a040  00000000 00000000 00000000 00000000
            

            這樣當然是不夠的,讓我們再看看將這個對象(或者更形象的說“Property Bag”)復制后再擴展一個成員(Slot),代碼如下

            #!c
            function xObj(x,y)
            {
            this.X = x; 
            this.Y = y;
            } 
            var a=new xObj(3,4); 
            var b=new xObj(3,4); 
            b.Z = 5;
            

            首先,找到五個賦值語句的位置:

            enter image description here

            第一句的3,4

            enter image description here

            第二句的3,4

            到此為止,這兩個對象都是一樣的,

            enter image description here

            直到這里,可以看出來它給b的第三個元素(應為Z)賦值5,這里a、b的情況我們在控制臺輸入一下。

            a:

            enter image description here

            b:

            enter image description here

            可以看出來a、b除了成員變量之外別無二致,這正是Chakra中為了對象的快速存取而制作的多態特性:

            enter image description here

            VIII.3 函數的調用

            最后,讓我們回到這個問題上,想在一章之內說完Chakra絕對無異于癡人說夢,所以這里挑一個常見的地方來描述:在Chakra中的函數調用是如何的?

            首先是基本的函數,這個和JScript5差不多,一些具體功能的操作符(或者在JS中稱為Token),例如new Object這樣無參數的new操作符,對應的函數是Js::JavascriptOperators::NewJavascriptObjectNoArg

            而有些簡單的內容被編譯器直接計算值后顯示,例如Math.sqrt(5)在這里直接存為了2.23606xxxxx,而不會再現場調用函數來運算:

            enter image description here

            其他的一些無法優化的函數調用還是會照常調用,還是類似JScript5一樣看名字即可知道是做啥的,例如取隨機數的函數即為Js::SSE2::JavascriptMath::Random:

            enter image description here

            通過符號很容易看到各個函數的名稱和參數類型等:

            enter image description here

            而用戶自定義的函數、循環體等通常在字節碼中不會作為內聯函數存在,例如下列偽代碼,它們的調用有點像是:

            enter image description here

            在生成字節碼的時候它的范圍通常是:

            enter image description here

            顏色代表立場,呸,顏色代表不同的函數塊,上述函數在調用時最可能的棧像是:

            enter image description here

            Chakra的內容介紹到此結束,限于個人水平以及篇幅內容,先介紹的就是這么多,其實基本調試方法和調試之前的代碼沒啥兩樣,這里的調試很容易就能夠舉一反三。

            自Chakra開始,IE的腳本執行速度比先前提升了十多倍(微軟自己的SunSpider跑分),原圖我找不著了,但是在微軟的某個文章里面還是看到了小圖……如下,IE9面世不久后的測試得分和當時的Chrome21的腳本跑分不相上下。可惜悲劇的它出來的時候大家在用IE6,IE11出來的時候大家還是在用IE6,就是卡的不行啊怎么辦,趕緊升級吧:)。

            enter image description here

            1 http://files.accuvant.com/web/files/images/webbrowserresearch_v1_0.pdf

            2 http://users.ics.forth.gr/~elathan/papers/ndss15.pdf

            3 https://blog.indutny.com/5.allocating-numbers

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线