《附录六:关于Windows Shell远程代码执行漏洞CVE-2010-2568的分析与利用》 -By nEINEI 漏洞描述: Windows Shell 中的漏洞可能允许远程执行代码 (2286198) 漏洞发生模块:shell.dll 之前的版本:6.1.7600.16385; 文件大小: 12,866,560 字节 补丁后的版本:6.1.7600.16644 文件大小:12,867,584 字节 详细信息: https://docs.microsoft.com/zh-cn/security-updates/Securitybulletins/2010/ms10-046 补丁对比可以看到,这次修补的函数包括如下这些,逐一分析可以发现有一个函数中是有特殊的情况, 7385988B CFileOperation::PrepareAndDoOperations(void) 7385982B CFileOperation::PrepareAndDoOperations(void 73896DA8 CRegisteredClient::v_SendNotification(CNotifyEvent const *,int,void (*)(HWND__ *,uint,ulong,long)) 73896D3C CRegisteredClient::v_SendNotification(CNoti 73854871 CFileOperation::StartOperations(ulong,uint,ushort const *,HWND__ *,IOperationsProgressDialog *) 73854831 CFileOperation::StartOperations(ulong,uint, 73904B41 CPLD_Destroy(ControlData *) 73904AE1 CPLD_Destroy(ControlData *) 73A5203A CChangeNotify::~CChangeNotify(void) 73A52012 CChangeNotify::~CChangeNotify(void) 73881967 CDesktopFolder::ParseDisplayName(HWND__ *,IBindCtx *,ushort *,ulong *,_ITEMIDLIST_RELATIVE * *,ulong *) 738818EF CDesktopFolder::ParseDisplayName(HWND__ *,I 738674E3 CControlPanelFolder::~CControlPanelFolder(void) 7386747B CControlPanelFolder::~CControlPanelFolder(v 73903AAD CControlPanelCategoryModuleInner::OnItemsLoaded(bool,IShellFolder2 *,IEnumIDList *) 73903A5D CControlPanelCategoryModuleInner::OnItemsLo 73B78126 RtlGetVersionResource(void *,uint,ulong,_RTL_VERSION_RESOURCE *) 73B77DE3 RtlGetVersionResource(void *,uint,ulong,_RT 73905312 CControlPanelDataWorkItem::~CControlPanelDataWorkItem(void) 739052AA CControlPanelDataWorkItem::~CControlPanelDa 7389D7B3 sub_7389D7B3_21 7389D74B sub_7389D74B_297 739044FB CControlPanelDataWorkItem::_LoadSlowData(void) 739044C1 CControlPanelDataWorkItem::_LoadSlowData(vo 738D17D6 CControlPanelFolder::GetUIObjectOf(HWND__ *,uint,_ITEMID_CHILD const * const *,_GUID const &,uint *,void * *) 738D1786 CControlPanelFolder::GetUIObjectOf(HWND__ * 73A20A15 CCDBurn::_BurnJolietImage(IFileSystemImage *,IDiscFormat2Data *) 73A209CD CCDBurn::_BurnJolietImage(IFileSystemImage 73807D8E CDesktopBrowser::_ActivateView(void) 73808A53 CDesktopBrowser::_ActivateView(void) 73804D8D CChangeNotify::CChangeNotify(HWND__ * *) 73804D8D CChangeNotify::CChangeNotify(HWND__ * *) 7380E8F4 CCollapsingClient::s_DispatchCallback(HWND__ *,uint,ulong,long) 7380E8E1 CCollapsingClient::s_DispatchCallback(HWND_ 73867A9B CControlPanelFolder::CControlPanelFolder(IUnknown *,tagCPCAT) 73867A33 CControlPanelFolder::CControlPanelFolder(IU 7380E9AB CChangeNotify::_WaitForCallbacks(void) 73894DFD CChangeNotify::_WaitForCallbacks(void) 73A03D64 sub_73A03D64_112 73A03C48 sub_73A03C48_384 73857D22 CBaseOperation::_ChangeNotify(long,IShellItem *,IShellItem *) 7385712F CBaseOperation::_ChangeNotify(long,IShellIt 73A03D40 sub_73A03D40_110 73A03C6C sub_73A03C6C_386 73818772 CDefView::_CanDesktopUseSolidBackgroundColor(void) 73818712 CDefView::_CanDesktopUseSolidBackgroundColo 7390E294 CDesktopBrowser::_OnAnimationRequirementsChanged(void) 7390E234 CDesktopBrowser::_OnAnimationRequirementsCh 7380E94A CChangeNotify::PendingCallbacks(HWND__ *,int) 7380E92A CChangeNotify::PendingCallbacks(int) CControlPanelFolder::GetUIObjectOf 函数中新增加了一个补丁函数,CControlPanelFolder::_IsRegisteredCPLApplet // 调试一下可知这个函数是判断当前lnk文件指向的cpl文件是否在已知的一个%program file%, %system32% ,%windows%目录下的文件,因为如果是控制面板的快捷方式,那么它指向的cpl文件一定是系统自己的文件而不是其他路径下的文件 char __thiscall CControlPanelFolder::_IsRegisteredCPLApplet(CControlPanelFolder *this, const unsigned __int16 *a2) { CControlPanelFolder *v2; // edi@1 const struct ControlData *v3; // esi@2 v2 = this; if ( !SHHasTimeoutElapsed(*((_DWORD *)this + 17), 0x7530u) ) { v3 = (CControlPanelFolder *)((char *)v2 + 72); if ( *((_DWORD *)v2 + 18) ) return IsRegisteredCPLApplet(a2, v3); ---- 继续检查 } v3 = (CControlPanelFolder *)((char *)v2 + 72); CPLD_Destroy((CControlPanelFolder *)((char *)v2 + 72)); if ( CPLD_GetModules((CControlPanelFolder *)((char *)v2 + 72)) ) { *((_DWORD *)v2 + 17) = GetTickCount(); return IsRegisteredCPLApplet(a2, v3); -- 继续检查 } return 0; } //IsRegisteredCPLApplet 函数定义如下: char __stdcall IsRegisteredCPLApplet(const unsigned __int16 *a1, const struct ControlData *a2) { char v2; // bl@1 int v3; // esi@1 PVOID v4; // eax@3 v2 = 0; v3 = **((_DWORD **)a2 + 1) - 1; do { if ( v3 < 0 ) break; v4 = DSA_GetItemPtr(*((HDSA *)a2 + 1), v3); // 每次循环取出Itemptr指针,这个指针指向一个系统路径下的cpl文件,通过比较来决定传入的cpl文件是否在此路径下 if ( CompareStringOrdinal(*(_DWORD *)v4, -1, a1, -1, 1) == 2 ) v2 = 1; --v3; } while ( !v2 ); return v2; } // 调试explorer.exe进程,因为加载lnk文件的行为发生在explorer.exe进程空间,explorer加载了shell32.dll模块来解析lnk文件格式 ,然后打开一个包含控制面板快捷方式的lnk文件,或者打开一个stuxnet的lnk漏洞样本也可以, // 可以断在GetUIObjectOf 这里 eax=7c9d3790 ebx=001731b0 ecx=02653968 edx=025fec68 esi=02653968 edi=000e25b0 eip=7cb06d7f esp=025febfc ebp=025fec34 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 SHELL32!CControlPanelFolder::GetUIObjectOf: 7cb06d7f 8bff mov edi,edi 0:015> kv ChildEBP RetAddr Args to Child 025febf8 7ca2d51e 001731b0 00000000 00000001 SHELL32!CControlPanelFolder::GetUIObjectOf (FPO: [Non-Fpo]) 025fec34 7ca081ab 02653968 00000000 00000001 SHELL32!CRegFolder::GetUIObjectOf+0x28c (FPO: [Non-Fpo]) 025fec60 7ca0814b 02651808 00000000 7c9c809c SHELL32!SHGetUIObjectFromFullPIDL+0x40 (FPO: [Non-Fpo]) 025feea0 7ca07ed0 00000000 7c9c809c 000e25b0 SHELL32!CShellLink::_GetUIObject+0xd8 (FPO: [Non-Fpo]) 025ff2d8 7ca07f94 7c9c809c 000e25b0 025ff464 SHELL32!CShellLink::_GetExtractIcon+0x127 (FPO: [Non-Fpo]) 025ff2ec 7ca07f22 000e2560 00000104 00000000 SHELL32!CShellLink::_InitExtractIcon+0x21 (FPO: [0,0,0]) 025ff410 7c9fa8e4 000e2560 00000002 025ff570 SHELL32!CShellLink::GetIconLocation+0x40 (FPO: [Non-Fpo]) 025ff77c 7c9f3478 000e2560 00000000 00132e28 SHELL32!_GetILIndexGivenPXIcon+0x9c (FPO: [Non-Fpo]) 025ff7a4 7ca26222 026501a0 000e2560 00132e28 SHELL32!SHGetIconFromPIDL+0x90 (FPO: [Non-Fpo]) 025ffe20 7c9fa6ea 026501a4 00132e28 00000000 SHELL32!CFSFolder::GetIconOf+0x24e (FPO: [Non-Fpo]) 025ffe40 7c9ff39c 026501a0 026501a4 00132e28 SHELL32!SHGetIconFromPIDL+0x20 (FPO: [Non-Fpo]) 025ffe68 7c9f2a65 02645508 001671a0 00173330 SHELL32!CGetIconTask::RunInitRT+0x47 (FPO: [Non-Fpo]) 025ffe84 75f81b9a 02645508 75f81b18 75f80000 SHELL32!CRunnableTask::Run+0x54 (FPO: [Non-Fpo]) 025ffee0 77f695b8 000bd2b0 00152e48 77f6959b BROWSEUI!CShellTaskScheduler_ThreadProc+0x111 (FPO: [Non-Fpo]) 025ffef8 7c927d2d 00152e48 7c97e460 026459e8 SHLWAPI!ExecuteWorkItem+0x1d (FPO: [Non-Fpo]) 025fff40 7c927d6b 77f6959b 00152e48 00000000 ntdll!RtlpWorkerCallout+0x70 (FPO: [Non-Fpo]) 025fff60 7c927e2d 00000000 00152e48 026459e8 ntdll!RtlpExecuteWorkerRequest+0x1a (FPO: [Non-Fpo]) 025fff74 7c927e04 7c927d51 00000000 00152e48 ntdll!RtlpApcCallout+0x11 (FPO: [Non-Fpo]) 025fffb4 7c80b729 00000000 00000000 00000000 ntdll!RtlpWorkerThread+0x87 (FPO: [Non-Fpo]) 025fffec 00000000 7c910250 00000000 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo]) // 动态调试可以发现,传入_IsRegisteredCPLApplet函数的一个参数是组合成%system%+cpl文件名称的路径 7cb06eac 8d85ecfbffff lea eax,[ebp-414h] 7cb06eb2 50 push eax 7cb06eb3 8d4bf0 lea ecx,[ebx-10h] 7cb06eb6 e882eaffff call SHELL32!CControlPanelFolder::_IsRegisteredCPLApplet (7cb0593d) 0:015> dds esp l10 025fe170 025fe7e4 --- 参数1 025fe174 000e25b0 025fe178 02653968 025fe17c 001731b0 025fe180 00000000 0:015> db 025fe7e4 l50 ---- 查看参数1 025fe7e4 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O. 025fe7f4 57 00 53 00 5c 00 73 00-79 00 73 00 74 00 65 00 W.S.\.s.y.s.t.e. 025fe804 6d 00 33 00 32 00 5c 00-7e 00 57 00 54 00 52 00 m.3.2.\.~.W.T.R. 025fe814 34 00 31 00 34 00 31 00-2e 00 74 00 6d 00 70 00 4.1.4.1...t.m.p. // 这里通过遍历得到列表中的cpl,然后去比较 7cb05380 ff7704 push dword ptr [edi+4] 7cb05383 ff1584a99e7c call dword ptr [SHELL32!_imp__DSA_GetItemPtr (7c9ea984)] 7cb05389 6aff push 0FFFFFFFFh 0:015> db poi(eax) 02640340 43 00 3a 00 5c 00 50 00-72 00 6f 00 67 00 72 00 C.:.\.P.r.o.g.r. 02640350 61 00 6d 00 20 00 46 00-69 00 6c 00 65 00 73 00 a.m. .F.i.l.e.s. 02640360 5c 00 43 00 6f 00 6d 00-6d 00 6f 00 6e 00 20 00 \.C.o.m.m.o.n. . 02640370 46 00 69 00 6c 00 65 00-73 00 5c 00 4d 00 69 00 F.i.l.e.s.\.M.i. 02640380 63 00 72 00 6f 00 73 00-6f 00 66 00 74 00 20 00 c.r.o.s.o.f.t. . 02640390 53 00 68 00 61 00 72 00-65 00 64 00 5c 00 53 00 S.h.a.r.e.d.\.S. 026403a0 70 00 65 00 65 00 63 00-68 00 5c 00 73 00 61 00 p.e.e.c.h.\.s.a. 026403b0 70 00 69 00 2e 00 63 00-70 00 6c 00 00 00 18 00 p.i...c.p.l..... //加载cpl, //如果是未被patch的系统,上面的没有上面的检测,就可以继续运行SHELL32!CShellLink::GetIconLocation,这样可以看到会执行CPL_LoadCPLModule 函数 0:015> kv ChildEBP RetAddr Args to Child 025fec18 7ca71cb8 025fee7c 0010251c 025ff2c4 SHELL32!CPL_LoadCPLModule (FPO: [Non-Fpo]) 025fee50 7ca72787 025fee74 0010251c 00102520 SHELL32!CPL_LoadAndFindApplet+0x4a (FPO: [Non-Fpo]) 025ff294 7cb478b5 00102314 0010251c 00102520 SHELL32!CPL_FindCPLInfo+0x46 (FPO: [Non-Fpo]) 025ff2b8 7c9fac40 00000082 00000000 00000104 SHELL32!CCtrlExtIconBase::_GetIconLocationW+0x7b (FPO: [Non-Fpo]) 025ff2d4 7ca07f4b 0010230c 00000082 025ff570 SHELL32!CExtractIconBase::GetIconLocation+0x1f (FPO: [Non-Fpo]) 025ff410 7c9fa8e4 000e2560 00000082 025ff570 SHELL32!CShellLink::GetIconLocation+0x69 (FPO: [Non-Fpo]) 025ff77c 7c9f3478 000e2560 00000000 00132e28 SHELL32!_GetILIndexGivenPXIcon+0x9c (FPO: [Non-Fpo]) 025ff7a4 7ca26222 026501a0 000e2560 00132e28 SHELL32!SHGetIconFromPIDL+0x90 (FPO: [Non-Fpo]) 025ffe20 7c9fa6ea 026501a4 00132e28 00000000 SHELL32!CFSFolder::GetIconOf+0x24e (FPO: [Non-Fpo]) 025ffe40 7c9ff39c 026501a0 026501a4 00132e28 SHELL32!SHGetIconFromPIDL+0x20 (FPO: [Non-Fpo]) 025ffe68 7c9f2a65 02645508 001671a0 00173330 SHELL32!CGetIconTask::RunInitRT+0x47 (FPO: [Non-Fpo]) 025ffe84 75f81b9a 02645508 75f81b18 75f80000 SHELL32!CRunnableTask::Run+0x54 (FPO: [Non-Fpo]) 025ffee0 77f695b8 000bd2b0 00152e48 77f6959b BROWSEUI!CShellTaskScheduler_ThreadProc+0x111 (FPO: [Non-Fpo]) 025ffef8 7c927d2d 00152e48 7c97e460 026459e8 SHLWAPI!ExecuteWorkItem+0x1d (FPO: [Non-Fpo]) 025fff40 7c927d6b 77f6959b 00152e48 00000000 ntdll!RtlpWorkerCallout+0x70 (FPO: [Non-Fpo]) 025fff60 7c927e2d 00000000 00152e48 026459e8 ntdll!RtlpExecuteWorkerRequest+0x1a (FPO: [Non-Fpo]) 025fff74 7c927e04 7c927d51 00000000 00152e48 ntdll!RtlpApcCallout+0x11 (FPO: [Non-Fpo]) 025fffb4 7c80b729 00000000 00000000 00000000 ntdll!RtlpWorkerThread+0x87 (FPO: [Non-Fpo]) 025fffec 00000000 7c910250 00000000 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo] 0:015> p eax=00000001 ebx=025fee7c ecx=00000002 edx=00000001 esi=00000001 edi=7c80a6e4 eip=7ca68953 esp=025fe9c4 ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0xf7: 7ca68953 56 push esi 0:015> p eax=00000001 ebx=025fee7c ecx=00000002 edx=00000001 esi=00000001 edi=7c80a6e4 eip=7ca68954 esp=025fe9c0 ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0xf8: 7ca68954 56 push esi 0:015> p eax=00000001 ebx=025fee7c ecx=00000002 edx=00000001 esi=00000001 edi=7c80a6e4 eip=7ca68955 esp=025fe9bc ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0xf9: 7ca68955 53 push ebx 0:015> p eax=00000001 ebx=025fee7c ecx=00000002 edx=00000001 esi=00000001 edi=7c80a6e4 eip=7ca68956 esp=025fe9b8 ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0xfa: 7ca68956 ff150000bc7c call dword ptr [SHELL32!_imp__ApphelpCheckExe (7cbc0000)] ds:0023:7cbc0000={SHELL32!_imp_load__ApphelpCheckExe (7cbb7efe)} 0:015> p eax=00000001 ebx=025fee7c ecx=0000c9f5 edx=00180003 esi=00000001 edi=7c80a6e4 eip=7ca6895c esp=025fe9c8 ebp=025fec18 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 SHELL32!_LoadCPLModule+0x100: 7ca6895c 85c0 test eax,eax 0:015> p eax=00000001 ebx=025fee7c ecx=0000c9f5 edx=00180003 esi=00000001 edi=7c80a6e4 eip=7ca6895e esp=025fe9c8 ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0x102: 7ca6895e 7508 jne SHELL32!_LoadCPLModule+0x10c (7ca68968) [br=1] 0:015> p eax=00000001 ebx=025fee7c ecx=0000c9f5 edx=00180003 esi=00000001 edi=7c80a6e4 eip=7ca68968 esp=025fe9c8 ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0x10c: 7ca68968 53 push ebx 0:015> r eax=00000001 ebx=025fee7c ecx=0000c9f5 edx=00180003 esi=00000001 edi=7c80a6e4 eip=7ca68969 esp=025fe9c4 ebp=025fec18 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 SHELL32!_LoadCPLModule+0x10d: 7ca68969 ff15a0159c7c call dword ptr [SHELL32!_imp__LoadLibraryW (7c9c15a0)] ds:0023:7c9c15a0={kernel32!LoadLibraryW (7c80aeeb)} 0:015> db ebx 025fee7c 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O. 025fee8c 57 00 53 00 5c 00 73 00-79 00 73 00 74 00 65 00 W.S.\.s.y.s.t.e. 025fee9c 6d 00 33 00 32 00 5c 00-7e 00 57 00 54 00 52 00 m.3.2.\.~.W.T.R. 025feeac 34 00 31 00 34 00 31 00-2e 00 74 00 6d 00 70 00 4.1.4.1...t.m.p. 025feebc 00 00 a0 7c b0 25 0e 00-c8 f2 5f 02 a0 31 17 00 ...|.%...._..1.. 025feecc a0 31 17 00 00 00 00 00-b8 00 91 7c 40 2e 15 00 .1.........|@... 025feedc a8 ef 5f 02 41 00 91 7c-18 07 09 00 5d 00 91 7c .._.A..|....]..| 025feeec c8 f2 5f 02 00 ef 5f 02-00 00 00 00 b8 00 91 7c .._..._........| // 这里是补丁后的路径,如果是没有补丁的版本,则会加载下面这个绝对路径下的dll文件,这样恶意代码通过构造lnk文件格式就可以让explorer进程来加载 //制定的恶意模块来. 000aa230 53 00 54 00 4f 00 52 00-41 00 47 00 45 00 23 00 S.T.O.R.A.G.E.#. 000aa240 56 00 6f 00 6c 00 75 00-6d 00 65 00 23 00 5f 00 V.o.l.u.m.e.#._. 000aa250 3f 00 3f 00 5f 00 55 00-53 00 42 00 53 00 54 00 ?.?._.U.S.B.S.T. 000aa260 4f 00 52 00 23 00 44 00-69 00 73 00 6b 00 26 00 O.R.#.D.i.s.k.&. 000aa270 56 00 65 00 6e 00 5f 00-4b 00 69 00 6e 00 67 00 V.e.n._.K.i.n.g. 000aa280 73 00 74 00 6f 00 6e 00-26 00 50 00 72 00 6f 00 s.t.o.n.&.P.r.o. 000aa290 64 00 5f 00 44 00 61 00-74 00 61 00 54 00 72 00 d._.D.a.t.a.T.r. 000aa2a0 61 00 76 00 65 00 6c 00-65 00 72 00 5f 00 32 00 a.v.e.l.e.r._.2. 000aa2b0 2e 00 30 00 26 00 52 00-65 00 76 00 5f 00 50 00 ..0.&.R.e.v._.P. 000aa2c0 4d 00 41 00 50 00 23 00-35 00 42 00 36 00 42 00 M.A.P.#.5.B.6.B. 000aa2d0 30 00 39 00 38 00 42 00-39 00 37 00 42 00 45 00 0.9.8.B.9.7.B.E. 000aa2e0 26 00 30 00 23 00 7b 00-35 00 33 00 66 00 35 00 &.0.#.{.5.3.f.5. 000aa2f0 36 00 33 00 30 00 37 00-2d 00 62 00 36 00 62 00 6.3.0.7.-.b.6.b. 000aa300 66 00 2d 00 31 00 31 00-64 00 30 00 2d 00 39 00 f.-.1.1.d.0.-.9. 000aa310 34 00 66 00 32 00 2d 00-30 00 30 00 61 00 30 00 4.f.2.-.0.0.a.0. 000aa320 63 00 39 00 31 00 65 00-66 00 62 00 38 00 62 00 c.9.1.e.f.b.8.b. 000aa330 7d 00 23 00 7b 00 35 00-33 00 66 00 35 00 36 00 }.#.{.5.3.f.5.6. 000aa340 33 00 30 00 64 00 2d 00-62 00 36 00 62 00 66 00 3.0.d.-.b.6.b.f. 000aa350 2d 00 31 00 31 00 64 00-30 00 2d 00 39 00 34 00 -.1.1.d.0.-.9.4. 000aa360 66 00 32 00 2d 00 30 00-30 00 61 00 30 00 63 00 f.2.-.0.0.a.0.c. 000aa370 39 00 31 00 65 00 66 00-62 00 38 00 62 00 7d 00 9.1.e.f.b.8.b.}. 000aa380 5c 00 7e 00 57 00 54 00-52 00 34 00 31 00 34 00 \.~.W.T.R.4.1.4. 000aa390 31 00 2e 00 74 00 6d 00-70 00 00 00 00 00 00 00 1...t.m.p....... //我们可以继续研究一下下面这个函数 SHELL32!CShellLink::GetIconLocation 关于LNK文件格式的较详细介绍请参考,之前在Vxjump上发布的文章,此处不再赘述: http://www.vxjump.net/files/security_research/lnk_inf.txt **********************.lnk 文件格式**************** +---------------------------+ | lnk file header | +---------------------------+ >------. | Shell Item Id List | | +---------------------------+ | | File location info | | +---------------------------+ | | Description string | | +---------------------------+ --- | Relative path string | 这几个节不是每一个都必须存在,如果存在就要按这样的顺序关系排列。 +---------------------------+ --- | Working directory string | | +---------------------------+ | | Command line string | | +---------------------------+ | | Icon filename string | | +---------------------------+ >------. | Extra stuff | +---------------------------+ 我们可以看到,lnk file header 中会有偏移0x38的位置标示icon图标的个数, 在偏移0x14的地方是 linkflags,这里面按bit来表示这个lnk类型有哪些信息, 一个正常lnk快捷方式, 通常会是9b 00 08 00;(表示,具有hasLinkTargetIdlist + hasLinkinfo + hasRelativePath + hasWorkingDir + isUnicode + EnableTargetMetadata ) 一个控制面板的快捷方式, 通常会是81 00 08 00 ;(表示,具有hasLinkTargetIdlist + isUnicode + EnableTargetMetadata) stuxnet构造的快捷方式是81 00 00 00,显然是xp系统下的控制面板的lnk文件,因为win7开始,大多数lnk执行指向具体路径描述是通过ExtraData 节来描述的。 这里的是81 00 00 00 ;(表示,具有hasLinkTargetIdlist + isUnicode) win7开始在ExtraData节的PropertyStoreDataBlock.size 中会指定这个节的大小,节中的IDLIst[0] [1] 会描述具体的执行的目标文件路径。少数情况会继续使用LinkTargetIDlist结构来描述路径。 了解了前面的内容后,我们知道一个lnk文件被explorer 打开会执行一系列的文件格式解析操作,通过解析shell item id list来获得相关lnk节中的信息, 开始需要获得icon的信息,因为快捷方式要显示一个对应lnk执行文件的对应图标icon,而去的图标的前提是先加载对应的cpl文件解析里面资源获得icon。 通过FSFolder::GetIconOf 函数来获得,开始会判断是文件夹还说独立的文件,然后检查icon是否在cache中通过LookupIconIndex,如果传入的是GIL_ASYNC标记表明这是一个特殊的情况,那么会使用Shell_GetCachedImageIndex函数来调用LookupIconIndex来获得icon索引,然后把该icon加入cache中供以后查询,否则则会调用SHGetIconFromPIDL函数来获得icon索引,SHGetIconFromPIDL是一个通用的获得icon是否在system image list中的功能函数。 SHGetIconFromPIDL开始会尝试继续调用Shell_GetCachedImageIndex获得一个从DSA_GetItemCount获得的已知的一个Iconidx索引, 然后通过IShellFolder接口的GetUIObjectOf函数获得IID_IExtractIcon接口指针,再通过_GetILIndexGivenPXIcon获得该索引。 在_GetILIndexGivenPXIcon中需要通过调用IExtractIcon接口的来获得idx索引,这是他需要调用GetIconLocation函数,如果成功返回一个有效的icon,否则shell使用一个默认的icon图标。通常这个idx是-1,如果idx=0,那么需要检查是否是个动态的icon,通过调用CPL_FindCPLInfo来进行查询,如果是true,那么返回当前的idx. CPL_FindCPLInfo通过调用CPL_LoadCPLModule来获得LPCPLMODULE的信息。 0:009> uf 7ca07ee8 SHELL32!CShellLink::GetIconLocation: 7ca07ee8 8bff mov edi,edi 7ca07eea 55 push ebp 7ca07eeb 8bec mov ebp,esp 7ca07eed 81ec10010000 sub esp,110h 7ca07ef3 f6450c80 test byte ptr [ebp+0Ch],80h 7ca07ef7 a14805bd7c mov eax,dword ptr [SHELL32!__security_cookie (7cbd0548)] 7ca07efc 53 push ebx 7ca07efd 8b5d18 mov ebx,dword ptr [ebp+18h] 7ca07f00 56 push esi 7ca07f01 8b7508 mov esi,dword ptr [ebp+8] 7ca07f04 8945fc mov dword ptr [ebp-4],eax 7ca07f07 8b4510 mov eax,dword ptr [ebp+10h] 7ca07f0a 57 push edi 7ca07f0b 8b7d1c mov edi,dword ptr [ebp+1Ch] 7ca07f0e 8985f0feffff mov dword ptr [ebp-110h],eax 7ca07f14 0f85f3d00400 jne SHELL32!CShellLink::GetIconLocation+0x2e (7ca5500d) SHELL32!CShellLink::GetIconLocation+0x38: 7ca07f1a 8d4ed8 lea ecx,[esi-28h] 7ca07f1d e880000000 call SHELL32!CShellLink::_InitExtractIcon (7ca07fa2) // ==============> 这里调用SHELL32!CControlPanelFolder::GetUIObjectOf 7ca07f22 85c0 test eax,eax // 微软补丁修补这里,加入了_IsRegisteredCPLApplet 白名单过滤非系统目录下 7ca07f24 8985f4feffff mov dword ptr [ebp-10Ch],eax // cpl 模块文件 7ca07f2a 7c33 jl SHELL32!CShellLink::GetIconLocation+0xc2 (7ca07f5f) SHELL32!CShellLink::GetIconLocation+0x4a: 7ca07f2c 8b4650 mov eax,dword ptr [esi+50h] 7ca07f2f 804d0c80 or byte ptr [ebp+0Ch],80h 7ca07f33 85c0 test eax,eax 7ca07f35 743d je SHELL32!CShellLink::GetIconLocation+0x71 (7ca07f74) SHELL32!CShellLink::GetIconLocation+0x55: 7ca07f37 8b08 mov ecx,dword ptr [eax] 7ca07f39 57 push edi 7ca07f3a 53 push ebx 7ca07f3b ff7514 push dword ptr [ebp+14h] 7ca07f3e ffb5f0feffff push dword ptr [ebp-110h] 7ca07f44 ff750c push dword ptr [ebp+0Ch] 7ca07f47 50 push eax 7ca07f48 ff510c call dword ptr [ecx+0Ch] // ====================》 没有上面的修补,这里将要调用SHELL32!CExtractIconBase::GetIconLocation,然后 7ca07f4b 8985f4feffff mov dword ptr [ebp-10Ch],eax //*** 然后调用CPL_LoadCPLModule—> LoadLibrary("????.cpl") 加载一个cpl,stuxnet中加载一个绝对路径dll SHELL32!CShellLink::GetIconLocation+0xb4: 7ca07f51 83bdf4feffff00 cmp dword ptr [ebp-10Ch],0 7ca07f58 7c05 jl SHELL32!CShellLink::GetIconLocation+0xc2 (7ca07f5f) SHELL32!CShellLink::GetIconLocation+0xbd: 7ca07f5a 8b07 mov eax,dword ptr [edi] 7ca07f5c 89465c mov dword ptr [esi+5Ch],eax SHELL32!CShellLink::GetIconLocation+0xc2: 7ca07f5f 8b85f4feffff mov eax,dword ptr [ebp-10Ch] SHELL32!CShellLink::GetIconLocation+0xc8: 7ca07f65 8b4dfc mov ecx,dword ptr [ebp-4] 7ca07f68 5f pop edi 7ca07f69 5e pop esi 7ca07f6a 5b pop ebx 7ca07f6b e8c0f4fdff call SHELL32!__security_check_cookie (7c9e7430) 7ca07f70 c9 leave 7ca07f71 c21800 ret 18h SHELL32!CShellLink::GetIconLocation+0x71: 7ca07f74 8b4654 mov eax,dword ptr [esi+54h] 7ca07f77 85c0 test eax,eax 7ca07f79 0f8598d00400 jne SHELL32!CShellLink::GetIconLocation+0x78 (7ca55017) SHELL32!CShellLink::GetIconLocation+0x7c: 7ca07f7f ebd0 jmp SHELL32!CShellLink::GetIconLocation+0xb4 (7ca07f51) SHELL32!CShellLink::GetIconLocation+0x2e: 7ca5500d b857000780 mov eax,80070057h 7ca55012 e94e2ffbff jmp SHELL32!CShellLink::GetIconLocation+0xc8 (7ca07f65) SHELL32!CShellLink::GetIconLocation+0x78: 7ca55017 8b08 mov ecx,dword ptr [eax] 7ca55019 57 push edi 7ca5501a 53 push ebx 7ca5501b 6804010000 push 104h 7ca55020 8d95f8feffff lea edx,[ebp-108h] 7ca55026 52 push edx 7ca55027 ff750c push dword ptr [ebp+0Ch] 7ca5502a 50 push eax 7ca5502b ff510c call dword ptr [ecx+0Ch] 7ca5502e 85c0 test eax,eax 7ca55030 8985f4feffff mov dword ptr [ebp-10Ch],eax 7ca55036 0f8c232ffbff jl SHELL32!CShellLink::GetIconLocation+0xc2 (7ca07f5f) SHELL32!CShellLink::GetIconLocation+0x99: 7ca5503c 83f801 cmp eax,1 7ca5503f 0f840c2ffbff je SHELL32!CShellLink::GetIconLocation+0xb4 (7ca07f51) SHELL32!CShellLink::GetIconLocation+0x9e: 7ca55045 ff7514 push dword ptr [ebp+14h] 7ca55048 8d85f8feffff lea eax,[ebp-108h] 7ca5504e ffb5f0feffff push dword ptr [ebp-110h] 7ca55054 50 push eax 7ca55055 ff15a81c9c7c call dword ptr [SHELL32!_imp__SHAnsiToUnicode (7c9c1ca8)] 7ca5505b e9f12efbff jmp SHELL32!CShellLink::GetIconLocation+0xb4 (7ca07f51) 通过以上分析,可知经过构造的lnk文件可以加载任意指定的路径下的恶意dll文件。