标题: 关于x64/Win10中Shim机制的一次调试分析过程 创建: 2018-04-26 14:32 更新: 2018-04-28 16:05 链接: https://scz.617.cn/windows/201804261432.txt 有阵子给windbg写jscript插件,无意中在x64/Win10上发现一件事,执行notepad不 从nt!PspProcessOpen()过,mspaint则过。跟bluerust说起这事,他瞎猜了一个说法, 是不是因为mspaint有Shim机制介入,进而导致这种区别。为什么有这种区别,到了 也没去深究,不是刚需。但他说的Shim机制,对于一向孤陋寡闻的我,有点意思。 Alex Ionescu早年写过一个未完的系列,我觉得就那么回事吧。 -------------------------------------------------------------------------- Secrets of the Application Compatilibity Database (SDB) Part 1 - Alex Ionescu [2007-05-20] http://www.alex-ionescu.com/?p=39 Secrets of the Application Compatilibity Database (SDB) Part 2 - Alex Ionescu [2007-05-21] http://www.alex-ionescu.com/?p=40 Secrets of the Application Compatilibity Database (SDB) Part 3 - Alex Ionescu [2007-05-26] http://www.alex-ionescu.com/?p=41 Secrets of the Application Compatilibity Database (SDB) Part 4 - Alex Ionescu [2007-06-17] http://www.alex-ionescu.com/?p=43 -------------------------------------------------------------------------- 有个中国同胞就Shim机制做过逆向分析: -------------------------------------------------------------------------- shimeng - wedday [2008-08-26] http://wedday.blogspot.jp/2008/08/shimeng.html (讲了32位的Shim机制,没讲64位的) shimeng注入 - wedday [2008-08-27] http://wedday.blogspot.jp/2008/08/include-ntifs.html -------------------------------------------------------------------------- 看得出来,是个高手,年代久远,无从联系,不知此君还有新的个人主页否?后来搜 了一下,上文可能最早发表在bbs.zndev.com,至少是2006.5.3之前。 在这个领域遍历了一圈,比较精彩的几篇是: -------------------------------------------------------------------------- Leveraging the Application Compatibility Cache in Forensic Investigations - Andrew Davis, Associate Consultant, Mandiant [2012-04-17] https://www.fireeye.com/content/dam/fireeye-www/services/freeware/shimcache-whitepaper.pdf https://github.com/mandiant/ShimCacheParser Shim Shady: Live Investigations of the Application Compatibility Cache - Fred House, Claudiu Teodorescu, Andrew Davis [2015-10-27] https://www.fireeye.com/blog/threat-research/2015/10/shim_shady_live_inv.html https://www.fireeye.com/blog/threat-research/2015/10/shim_shady_live_inv/shim-shady-part-2.html Malicious Application Compatibility Shims - Sean Pierce [2015-11-03] https://www.blackhat.com/docs/eu-15/materials/eu-15-Pierce-Defending-Against-Malicious-Application-Compatibility-Shims-wp.pdf -------------------------------------------------------------------------- 既然声称遍历了一圈,看过的肯定远比这些多,不过没必要在此一一列举,有兴趣、 有毅力者自己放狗。顺便说一句,Sysinternals的autoruns至今没有检查Shim机制相 关的东西。 下面是一些关于x64/Win10中Shim机制的调试分析过程。 无意中发现mspaint.exe会加载AcGenral.dll。 cdb.exe -noinh -snul -hd -o -xe ld:ntdll mspaint.exe 拦截对AcGenral.dll的加载: sxe ld:AcGenral 命中时调用栈回溯如下: ntdll!NtMapViewOfSection+0x14 ntdll!LdrpMinimalMapModule+0xde ntdll!LdrpMapDllWithSectionHandle+0x14 ntdll!LdrpMapDllNtFileName+0x18a ntdll!LdrpMapDllSearchPath+0x1de ntdll!LdrpProcessWork+0x66 ntdll!LdrpLoadDllInternal+0x13e ntdll!LdrpLoadDll+0x107 ntdll!LdrpLoadShimEngine+0x194 ntdll!LdrpInitShimEngine+0x157 ntdll!LdrpInitializeProcess+0x1cda ntdll!_LdrpInitialize+0x4e393 ntdll!LdrpInitialize+0x3b ntdll!LdrInitializeThunk+0xe 在其中注意到: LdrpLoadShimEngine LdrpInitShimEngine 顾名思义,初始化、加载Shim引擎。逆向分析其主调函数: -------------------------------------------------------------------------- LdrpInitializeProcess ( PCONTEXT Context, ... ) { ... /* * 保存5个关键函数的前16字节 */ LdrpCaptureCriticalThunks(); ... /* * 检查EXE的IFEO */ LdrpInitializeExecutionOptions(); ... /* * FLG_SHOW_LDR_SNAPS(2) */ if ( 0 != ( Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS ) ) { LdrpDebugFlags |= 1; } ... if ( !UseWOW64 ) { /* * > dt ntdll!_PEB pShimData * +0x2d8 pShimData : Ptr64 Void */ ShimData = PEB->pShimData; } ... if ( 0 != ( Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS ) ) { LdrpDebugFlags |= 1; } ... if ( ShimData != NULL && ... ) { PEB->AppCompatInfo = NULL; /* * 初始化SHIM引擎 */ LdrpInitShimEngine( ShimData ); } ... AppCompatFlags = PEB->AppCompatFlags.LowPart; /* * 可以通过AppCompatFlags间接将LoaderThreads置1 */ if ( AppCompatFlags & 0x10000000 ) { PEB->ProcessParameters->LoaderThreads = 1; } LdrpEnableParallelLoading( PEB->ProcessParameters->LoaderThreads ); ... LdrInitState = 2; if ( PEB->BeingDebugged ) { /* * "初始化断点"所在 */ LdrpDoDebuggerBreak(); } ... LdrpProcessInitContextRecord = Context; LdrpDrainWorkQueue( 0 ); /* * 加锁,用到了ntdll!LdrpLoaderLock */ LdrpAcquireLoaderLock(); LdrpInitializeGraphRecurse( LdrpImageEntry->DdagNode, x, x ); /* * 释放锁 */ LdrpReleaseLoaderLock(...); LdrpFreeLoadContextOfNode( LdrpImageEntry->DdagNode, x ); LdrpDropLastInProgressCount(...); LdrpProcessInitContextRecord = NULL; ... if ( LdrpImageEntry->TlsIndex ) { ... RtlActivateActivationContextUnsafeFast( x, LdrpImageEntry->EntryPointActivationContext ); /* * EXE的TLS在此得到处理 */ LdrpCallTlsInitializers( DLL_PROCESS_ATTACH, LdrpImageEntry ); RtlDeactivateActivationContextUnsafeFast( x ); } /* * 布尔变量 * * db ntdll!g_ShimsEnabled l 1 */ if ( g_ShimsEnabled && ... ) { g_ShimsEnabled = FALSE; /* * lmfc a @@masm(poi(ntdll!g_pShimEngineModule)) * * 比如apphelp.dll的基址 */ LdrUnloadDll( g_pShimEngineModule ); /* * 一旦从ibp离开,该变量很快被清成NULL */ g_pShimEngineModule = NULL; } if ( PEB->PostProcessInitRoutine != NULL ) { PEB->PostProcessInitRoutine(); } ... } -------------------------------------------------------------------------- 如果只是关心Shim机制,没必要看这一大堆,只要知道为了加载Shim引擎, PEB->pShimData不得为NULL。起初以为是ntdll.dll初始化该值,后来确认 ntdll.dll被映射到进程空间时,该值已经就绪。 dq @$peb+@@(#FIELD_OFFSET(nt!_PEB,pShimData)) l 1 dt ntdll!_PEB pShimData @$peb dx @$peb->pShimData 进一步调试发现,"sxe cpr"命中时,PEB已经存在,跟ntdll是否映射无关,只是不 能以符号形式访问PEB,只能用数字偏移。PEB->pShimData已经有值,由于缺少 ntdll.pdb,只能使用: dq @$peb+0x2d8 l 1 为了知道PEB->pShimData何时被赋值、被赋何值,可能需要调试父进程的代码。当时 有点犯傻,第一反应是用kd进行内核态调试,拦截nt!PspAllocateProcess(),从 EPROCESS中找PEB,对PEB->pShimData设数据断点。 -------------------------------------------------------------------------- NTSTATUS PspAllocateProcess ( /* * 对应父进程 */ PEPROCESS ParentProcess, // rcx KPROCESSOR_MODE AccessMode, // rdx POBJECT_ATTRIBUTES ObjectAttributes, // r8 unsigned char Protection, // r9 unsigned char SignatureLevel, // rsp+0x28 unsigned char SectionSignatureLevel, // rsp+0x30 PSECTION Section, // rsp+0x38 PTOKEN Token, // rsp+0x40 ULONG Flags, // rsp+0x48 a10, // rsp+0x50 a11, // rsp+0x58 /* * JobMemberLevel != 0 */ BOOLEAN a12, // rsp+0x60 a13, // rsp+0x68 PVOID *a14, // rsp+0x70 /* * 由此输出新分配、创建的EPROCESS */ PEPROCESS *Process // rsp+0x78 out ); -------------------------------------------------------------------------- 该函数第1形参ParentProcess对应父进程,可以从中获取父进程的名字,可以针对父 进程名设置条件断点,比如当父进程是cdb时断在nt!PspAllocateProcess()。 Hit:[cdb.exe] ... nt!PspAllocateProcess: fffff801`6ef25a7c 4c8bdc mov r11,rsp kd> r $t0=poi(@rsp+0x78) kd> dp @$t0 l 1 fffff50f`80994f10 00000000`00000000 kd> g poi(@rsp) ... nt!NtCreateUserProcess+0x723: fffff801`6ef1f657 8bf0 mov esi,eax "g poi(@rsp)"之后,子进程的EPROCESS已经生成,检查确认子进程是mspaint: kd> dp @$t0 l 1 fffff50f`80994f10 ffffdf00`660d4400 kd> r $t1=poi(@$t0) kd> !process @$t1 0 PROCESS ffffdf00660d4400 SessionId: 1 Cid: 2754 Peb: d6286a7000 ParentCid: 23d0 DirBase: 7b7aa000 ObjectTable: ffffa40019946980 HandleCount: 0. Image: mspaint.exe 检查确认父进程(当前进程)是cdb: kd> !process -1 0 PROCESS ffffdf00697ed5c0 SessionId: 1 Cid: 23d0 Peb: 951eb82000 ParentCid: 2e90 DirBase: 4766d000 ObjectTable: ffffa400176c6540 HandleCount: 100. Image: cdb.exe 刷新用户态符号,查看调用栈回溯: kd> .reload /user kd> kpn # Child-SP RetAddr Call Site 00 fffff50f`80994e50 fffff801`6ebf8d53 nt!NtCreateUserProcess+0x723 01 fffff50f`80995a90 00007ffd`66631654 nt!KiSystemServiceCopyEnd+0x13 02 00000095`1e92e968 00007ffd`638006df ntdll!NtCreateUserProcess+0x14 03 00000095`1e92e970 00007ffd`637fd7a6 KERNELBASE!CreateProcessInternalW+0x1b3f 04 00000095`1e92f5d0 00007ffd`6623e4e3 KERNELBASE!CreateProcessW+0x66 05 00000095`1e92f640 00007ffd`4157caa2 KERNEL32!CreateProcessWStub+0x53 06 00000095`1e92f6a0 00007ffd`4139e43a dbgeng!LiveUserDebugServices::CreateProcessW+0x262 07 00000095`1e92f810 00007ffd`4135e054 dbgeng!LiveUserTargetInfo::StartCreateProcess+0x10a 08 00000095`1e92f870 00007ffd`4135df27 dbgeng!DebugClient::CreateProcessAndAttach2Wide+0x114 09 00000095`1e92f930 00007ff7`fdd653b9 dbgeng!DebugClient::CreateProcessAndAttachWide+0x77 0a 00000095`1e92f9b0 00007ff7`fdd6a3c3 cdb!InitializeSession+0x5d5 0b 00000095`1e92fa70 00007ff7`fdd6e359 cdb!wmain+0x3ef 0c 00000095`1e92fd10 00007ffd`66241fe4 cdb!std::_Winerror_map+0x299 0d 00000095`1e92fd50 00007ffd`665fef91 KERNEL32!BaseThreadInitThunk+0x14 0e 00000095`1e92fd80 00000000`00000000 ntdll!RtlUserThreadStart+0x21 检查子进程的PEB: dq @$t1+@@(#FIELD_OFFSET(nt!_EPROCESS,Peb)) l 1 dt nt!_EPROCESS Peb @$t1 dx -r0 ((nt!_EPROCESS *)@$t1)->Peb ? @@c++(((nt!_EPROCESS *)@$t1)->Peb) kd> r $t2=@@c++(((nt!_EPROCESS *)@$t1)->Peb) kd> ? @$t2 Evaluate expression: 919801065472 = 000000d6`286a7000 现在$t1、$t2依次对应mspaint的EPROCESS、PEB。 kd> .process /p /r @$t1 kd> r $t3=@$t2+@@(#FIELD_OFFSET(nt!_PEB,pShimData)) kd> dq @$t3 l 1 000000d6`286a72d8 00000000`00000000 此时mspaint的PEB->pShimData尚未初始化,对之设数据断点: kd> ba w1 @$t3 kd> g 数据断点命中: nt!memcpy+0x2f: fffff801`6ebf9f6f 75ef jne nt!memcpy+0x20 (fffff801`6ebf9f60) [br=0] kd> kpn # Child-SP RetAddr Call Site 00 fffff50f`809954f8 fffff801`6ef9abff nt!memcpy+0x2f 01 fffff50f`80995500 fffff801`6ef9a630 nt!MmCopyVirtualMemory+0x53f 02 fffff50f`809959d0 fffff801`6effa1d7 nt!MiReadWriteVirtualMemory+0x160 03 fffff50f`80995a50 fffff801`6ebf8d53 nt!NtWriteVirtualMemory+0x1b 04 fffff50f`80995a90 00007ffd`66630584 nt!KiSystemServiceCopyEnd+0x13 05 00000095`1e92e968 00000000`00000000 0x00007ffd`66630584 kd> !process -1 0 PROCESS ffffdf00660d4400 SessionId: 1 Cid: 2754 Peb: d6286a7000 ParentCid: 23d0 DirBase: 7b7aa000 ObjectTable: ffffa40019946980 HandleCount: 0. Image: mspaint.exe kd> dq @$t3 l 1 000000d6`286a72d8 0000024f`ea7f0000 此时mspaint的PEB->pShimData已被初始化。 kd> .reload /user Loading User Symbols PEB is paged out (Peb.Ldr = 000000d6`286a7018). Type ".hh dbgerr001" for details 在mspaint进程空间,但".reload /user"失败,可以用"!vad"解决之: kd> !vad 7ffd`66630584 1 VAD @ ffffdf0069588960 Start VPN 7ffd66590 End VPN 7ffd6676f Control Area ffffdf006701a980 FirstProtoPte ffffa40014e23010 LastPte ffffa40014e23f08 Commit Charge c (0n12) Secured.Flink 0 Blink 0 Banked/Extend 0 File Offset 0 ImageMap ViewShare EXECUTE_WRITECOPY ControlArea @ ffffdf006701a980 Segment ffffa40014d2ab40 Flink ffffdf00695889c0 Blink ffffdf0066ff7830 Section Ref 2 Pfn Ref 167 Mapped Views 51 User Ref 53 WaitForDel 0 Flush Count ac30 File Object ffffdf0067000900 ModWriteCount 0 System Views 9987 WritableRefs c0001e Flags (a0) Image File \Windows\System32\ntdll.dll Segment @ ffffa40014d2ab40 ControlArea ffffdf006701a980 BasedAddress 00007ffd66590000 Total Ptes 1e0 Segment Size 1e0000 Committed 0 Image Commit c Image Info ffffa40014d2ab88 ProtoPtes ffffa40014e23010 Flags (c2822000) DebugSymbolsLoaded ProtectionMask Reload command: .reload ntdll.dll=00007ffd`66590000,1e0000 kd> .reload ntdll.dll=00007ffd`66590000,1e0000 kd> lmu start end module name 00007ffd`66590000 00007ffd`66770000 ntdll (pdb symbols) 再次查看调用栈回溯: kd> kpn # Child-SP RetAddr Call Site 00 fffff50f`809954f8 fffff801`6ef9abff nt!memcpy+0x2f 01 fffff50f`80995500 fffff801`6ef9a630 nt!MmCopyVirtualMemory+0x53f 02 fffff50f`809959d0 fffff801`6effa1d7 nt!MiReadWriteVirtualMemory+0x160 03 fffff50f`80995a50 fffff801`6ebf8d53 nt!NtWriteVirtualMemory+0x1b 04 fffff50f`80995a90 00007ffd`66630584 nt!KiSystemServiceCopyEnd+0x13 05 00000095`1e92e968 00000000`00000000 ntdll!NtWriteVirtualMemory+0x14 像这种到了5号栈帧就突然结束的调用栈回溯,一般涉及Attach操作: kd> x nt!K*AttachProcess fffff801`6eb7d880 nt!KeStackAttachProcess (void) fffff801`6eb7d7d0 nt!KeAttachProcess (void) fffff801`6eb7d950 nt!KiAttachProcess (void) fffff801`6eb39540 nt!KiStackAttachProcess (void) 此时应该换种方式查看调用栈回溯: kd> !thread -p -1 0xf PROCESS ffffdf00660d4400 SessionId: 1 Cid: 2754 Peb: d6286a7000 ParentCid: 23d0 DirBase: 7b7aa000 ObjectTable: ffffa40019946980 HandleCount: 0. Image: mspaint.exe THREAD ffffdf0068d85700 Cid 23d0.11d8 Teb: 000000951eb83000 Win32Thread: ffffdf0068a1dbc0 RUNNING on processor 0 Not impersonating Owning Process ffffdf00697ed5c0 Image: cdb.exe Attached Process ffffdf00660d4400 Image: mspaint.exe Wait Start TickCount 61160402 Ticks: 0 Context Switch Count 61 IdealProcessor: 0 UserTime 00:00:00.015 KernelTime 00:00:00.015 Win32 Start Address 0x00007ff7fdd6e3d0 Stack Init fffff50f80995c90 Current fffff50f809954e0 Base fffff50f80996000 Limit fffff50f80990000 Call 0000000000000000 Priority 14 BasePriority 13 PriorityDecrement 0 IoPriority 2 PagePriority 5 Child-SP RetAddr Call Site fffff50f`809954f8 fffff801`6ef9abff nt!memcpy+0x2f fffff50f`80995500 fffff801`6ef9a630 nt!MmCopyVirtualMemory+0x53f fffff50f`809959d0 fffff801`6effa1d7 nt!MiReadWriteVirtualMemory+0x160 fffff50f`80995a50 fffff801`6ebf8d53 nt!NtWriteVirtualMemory+0x1b fffff50f`80995a90 00007ffd`66630584 nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff50f`80995b00) 00000095`1e92e968 00000000`00000000 ntdll!NtWriteVirtualMemory+0x14 上述显示表明,父进程是cdb,然后Attach到子进程mspaint。 kd> bp nt!NtWriteVirtualMemory+0x1b kd> g 断点命中时果然已切回cdb: kd> !thread -p -1 0x1f PROCESS ffffdf00697ed5c0 SessionId: 1 Cid: 23d0 Peb: 951eb82000 ParentCid: 2e90 DirBase: 4766d000 ObjectTable: ffffa400176c6540 HandleCount: 109. Image: cdb.exe THREAD ffffdf0068d85700 Cid 23d0.11d8 Teb: 000000951eb83000 Win32Thread: ffffdf0068a1dbc0 RUNNING on processor 0 Not impersonating DeviceMap ffffa400160f9e40 Owning Process ffffdf00697ed5c0 Image: cdb.exe Attached Process N/A Image: N/A Wait Start TickCount 61160402 Ticks: 0 Context Switch Count 61 IdealProcessor: 0 UserTime 00:00:00.015 KernelTime 00:00:00.015 Win32 Start Address cdb!wmainCRTStartup (0x00007ff7fdd6e3d0) Stack Init fffff50f80995c90 Current fffff50f809954e0 Base fffff50f80996000 Limit fffff50f80990000 Call 0000000000000000 Priority 14 BasePriority 13 PriorityDecrement 0 IoPriority 2 PagePriority 5 Child-SP RetAddr Call Site fffff50f`80995a50 fffff801`6ebf8d53 nt!NtWriteVirtualMemory+0x1b fffff50f`80995a90 00007ffd`66630584 nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff50f`80995b00) 00000095`1e92e968 00007ffd`6380196f ntdll!NtWriteVirtualMemory+0x14 00000095`1e92e970 00007ffd`637fd7a6 KERNELBASE!CreateProcessInternalW+0x2dcf 00000095`1e92f5d0 00007ffd`6623e4e3 KERNELBASE!CreateProcessW+0x66 00000095`1e92f640 00007ffd`4157caa2 KERNEL32!CreateProcessWStub+0x53 00000095`1e92f6a0 00007ffd`4139e43a dbgeng!LiveUserDebugServices::CreateProcessW+0x262 00000095`1e92f810 00007ffd`4135e054 dbgeng!LiveUserTargetInfo::StartCreateProcess+0x10a 00000095`1e92f870 00007ffd`4135df27 dbgeng!DebugClient::CreateProcessAndAttach2Wide+0x114 00000095`1e92f930 00007ff7`fdd653b9 dbgeng!DebugClient::CreateProcessAndAttachWide+0x77 00000095`1e92f9b0 00007ff7`fdd6a3c3 cdb!InitializeSession+0x5d5 00000095`1e92fa70 00007ff7`fdd6e359 cdb!wmain+0x3ef 00000095`1e92fd10 00007ffd`66241fe4 cdb!std::_Winerror_map+0x299 00000095`1e92fd50 00007ffd`665fef91 KERNEL32!BaseThreadInitThunk+0x14 00000095`1e92fd80 00000000`00000000 ntdll!RtlUserThreadStart+0x21 至此知道: KERNELBASE!CreateProcessW+0x61 KERNELBASE!CreateProcessInternalW+0x1b39 ntdll!NtCreateUserProcess nt!NtCreateUserProcess // cdb创建mspaint KERNELBASE!CreateProcessInternalW+0x2dc9 ntdll!NtWriteVirtualMemory nt!NtWriteVirtualMemory // cdb更新mspaint的PEB->pShimData 为了搞清楚SHIM初始化,必须逆向分析KERNELBASE!CreateProcessInternalW()。这 里一定要记住,子进程的PEB->pShimData是由父进程填充的,假设用cdb调试mspaint, "sxe cpr"断下来时mspaint的PEB->pShimData已被填充,无法调试这个填充过程。可 以用kd调试cmd,也可以用cdb附加到cmd,然后在cmd里启动mspaint。 前面拦截nt!PspAllocateProcess(),根本目的是拦截子进程PEB的创建,进一步逆向 找到: -------------------------------------------------------------------------- NTSTATUS MmCreatePeb ( PEPROCESS TargetProcess, // rcx PINITIAL_PEB InitialPeb, // rdx PPEB *Base // r8 out PVOID a4 // r9 out ); -------------------------------------------------------------------------- 可以直接拦截nt!MmCreatePeb(),对之设置条件断点,当目标进程是mspaint时断在 nt!MmCreatePeb(): Hit:[mspaint.exe] ... nt!MmCreatePeb: fffff801`6ef5e1d0 4c8bdc mov r11,rsp kd> !thread -p -1 0x1f PROCESS ffffdf0068f73080 SessionId: 1 Cid: 14a8 Peb: 8e7f1f4000 ParentCid: 0f38 DirBase: 473cd000 ObjectTable: ffffa400191eb6c0 HandleCount: 236. Image: cmd.exe THREAD ffffdf006873c080 Cid 14a8.3108 Teb: 0000008e7f1f5000 Win32Thread: ffffdf0067c90b00 RUNNING on processor 0 Not impersonating DeviceMap ffffa400160f9e40 Owning Process ffffdf0068f73080 Image: cmd.exe Attached Process N/A Image: N/A Wait Start TickCount 61303344 Ticks: 1 (0:00:00:00.015) Context Switch Count 392 IdealProcessor: 0 UserTime 00:00:00.031 KernelTime 00:00:00.109 Win32 Start Address cmd!mainCRTStartup (0x00007ff689ec6b00) Stack Init fffff50f7febcc90 Current fffff50f7febc480 Base fffff50f7febd000 Limit fffff50f7feb7000 Call 0000000000000000 Priority 10 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5 Child-SP RetAddr Call Site fffff50f`7febb9b8 fffff801`6ef2698c nt!MmCreatePeb fffff50f`7febb9c0 fffff801`6ef1f657 nt!PspAllocateProcess+0xf10 fffff50f`7febbe50 fffff801`6ebf8d53 nt!NtCreateUserProcess+0x723 fffff50f`7febca90 00007ffd`66631654 nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff50f`7febcb00) 0000008e`7efae438 00007ffd`638006df ntdll!NtCreateUserProcess+0x14 0000008e`7efae440 00007ffd`637fd7a6 KERNELBASE!CreateProcessInternalW+0x1b3f 0000008e`7efaf0a0 00007ffd`6623e4e3 KERNELBASE!CreateProcessW+0x66 0000008e`7efaf110 00007ff6`89ebaec8 KERNEL32!CreateProcessWStub+0x53 0000008e`7efaf170 00007ff6`89ec39e3 cmd!ExecPgm+0x244 0000008e`7efaf3b0 00007ff6`89ebfb9e cmd!ECWork+0xa3 0000008e`7efaf620 00007ff6`89ebff35 cmd!FindFixAndRun+0x3de 0000008e`7efafac0 00007ff6`89ecd0d1 cmd!Dispatch+0xa5 0000008e`7efafb50 00007ff6`89ec6a89 cmd!_chkstk+0x5241 0000008e`7efafbf0 00007ffd`66241fe4 cmd!wil::details_abi::ProcessLocalStorage::~ProcessLocalStorage+0x289 0000008e`7efafc30 00007ffd`665fef91 KERNEL32!BaseThreadInitThunk+0x14 0000008e`7efafc60 00000000`00000000 ntdll!RtlUserThreadStart+0x21 kd调试经常需要".reload /user",还是用cdb附加到cmd调试比较方便。 在KERNELBASE!CreateProcessInternalW()中看到若干与SHIM相关的导入函数,来自 kernel32.dll。"x KERNEL32!*AppCompat*"可以看到更多相关符号,比如: KERNEL32!BasepQueryAppCompat KERNEL32!BasepGetAppCompatData KERNEL32!BasepInitAppCompatData KERNEL32!IsTSAppCompatEnabled KERNEL32!IsRegTSAppCompatEnabled KERNEL32!BasepCheckAppCompat KERNEL32!BaseGenerateAppCompatData 设断: bp KERNEL32!BasepQueryAppCompat bp KERNEL32!BasepGetAppCompatData bp KERNEL32!BasepInitAppCompatData bp KERNEL32!IsTSAppCompatEnabled bp KERNEL32!IsRegTSAppCompatEnabled bp KERNEL32!BasepCheckAppCompat bp KERNEL32!BaseGenerateAppCompatData mspaint启动过程中依次看到如下几种调用栈回溯: KERNEL32!BasepQueryAppCompat KERNELBASE!CreateProcessInternalW+0x27b3 KERNELBASE!CreateProcessW+0x66 KERNEL32!CreateProcessWStub+0x53 cmd!ExecPgm+0x244 KERNEL32!BasepGetAppCompatData KERNELBASE!CreateProcessInternalW+0x2d03 KERNELBASE!CreateProcessW+0x66 KERNEL32!CreateProcessWStub+0x53 cmd!ExecPgm+0x244 KERNEL32!BaseGenerateAppCompatData KERNEL32!BasepGetAppCompatData+0x391 KERNELBASE!CreateProcessInternalW+0x2d03 KERNELBASE!CreateProcessW+0x66 KERNEL32!CreateProcessWStub+0x53 cmd!ExecPgm+0x244 mspaint、notepad、calc都会触发BasepQueryAppCompat、BasepGetAppCompatData, 但notepad、calc不会触发BaseGenerateAppCompatData,这与mspaint不同。 前面已知父进程的KERNELBASE!CreateProcessInternalW()会调用 ntdll!NtWriteVirtualMemory()去写子进程的PEB->pShimData,检查父进程附近代码 得知: KERNELBASE!CreateProcessW+0x61 KERNELBASE!CreateProcessInternalW+0x1b39 ntdll!NtCreateUserProcess // cmd创建mspaint KERNELBASE!CreateProcessInternalW+0x2d53 ntdll!NtAllocateVirtualMemory // cmd在mspaint进程空间分配内存,将来用于存放SHIM数据 KERNELBASE!CreateProcessInternalW+0x2d8d ntdll!NtWriteVirtualMemory // cmd向mspaint进程空间写入SHIM数据 KERNELBASE!CreateProcessInternalW+0x2dc9 ntdll!NtWriteVirtualMemory // cmd更新mspaint的PEB->pShimData 实测mspaint、notepad、calc都有上述流程。对比mspaint、notepad、calc的SHIM数 据,发现它们都是0xfb8字节,可以解码其中一部分: -------------------------------------------------------------------------- b8 0f 00 00 // +0x0 长度域,包含自身 ab ed 0d ac // +0x4 固定值,猜是magic 01 00 00 00 // +0x8 mspaint有值,notepad、calc是0 64 86 // +0xc 固定值 00 00 // +0xe c4 19 13 00 // +0x10 mspaint有值,notepad、calc是0 ... 00 00 01 00 // +0x50 mspaint有值,notepad、calc是0 ... 01 00 00 00 // +0xb8 mspaint有值,notepad、calc是0 ... 01 08 00 00 // +0xd0 mspaint有值,notepad、calc是0 01 00 00 00 // +0xd4 mspaint有值,notepad、calc是0 // // 11111111-1111-1111-1111-111111111111 // 11 11 11 11 11 11 11 11 // +0xd8 DBID,参mspaint.xml 11 11 11 11 11 11 11 11 ... 41 70 70 68 65 6c 70 44 // +0x1d8 初始值为0,ibp时填成"ApphelpDebug" 65 62 75 67 00 ... 00 04 00 00 // +0x224 00 10 00 00 // +0x228 00 00 00 00 // +0x22c 02 00 00 00 // +0x230 73 68 69 6d 65 6e 67 73 // +0x234 初始值为0,ibp时填成"shimengstate" 74 61 74 65 00 ... // // .writemem mspaint.xml 0x029421db8320 l 0x554 // 20 83 db 21 94 02 00 00 // +0x274 buf=0x029421db8320,一个指针 54 05 00 00 // +0x27c buflen=0x554,上面这个指针指向的内存的字节数 ... 02 00 00 00 // +0x28c 53 68 69 6d 44 65 62 75 // +0x290 初始值为0,ibp时填成"ShimDebugLog" 67 4c 6f 67 00 ... // // 50 52 49 4e 54 2c 4e 6f-74 69 66 79 46 6e 2c 33 PRINT,NotifyFn,3 // 37 32 2c 47 65 6e 65 72-61 6c 20 50 75 72 70 6f 72,General Purpo // 73 65 20 53 68 69 6d 73-20 69 6e 69 74 69 61 6c se Shims initial // 69 7a 65 64 2e 0d 0a ized... // // "PRINT,NotifyFn,372,General Purpose Shims initialized.\r\n" // 00 3e dc 21 94 02 00 00 // +0x2d0 buf=0x029421dc3e00,一个指针 37 00 00 00 // +0x2d8 buflen=0x37,上面这个指针指向的内存的字节数 00 10 00 00 // +0x2dc 00 10 00 00 // +0x2e0 00 00 00 00 // +0x2e4 02 00 00 00 // +0x2e8 ... 03 00 00 00 00 00 00 00 // +0x5d8 初始值为1,ibp时为3 01 00 00 00 00 00 00 00 // +0x5e0 固定值 ... 00 00 0a 00 // +0x5f4 固定值 03 00 00 00 // +0x5f8 固定值 ... // // !pde.guid // 8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a Win10 // e2011457-1546-43c5-a5fe-008deee3d3f0 Vista // 12 7a 0f 8e b3 bf e8 4f // +0x608 MaxSupportedOS GUID b9 a5 48 fd 50 a1 5a 9a 57 14 01 e2 46 15 c5 43 // +0x618 MinSupportedOS GUID a5 fe 00 8d ee e3 d3 f0 // MinSupportedOS初始值同MaxSupportedOS,ibp时发生变化 01 00 00 00 // +0x628 固定值 ... a8 14 00 00 // +0x930 父进程PID,0x14a8(5288) 43 00 3a 00 5c 00 57 00 // +0x934 父进程路径,C:\Windows\System32\cmd.exe 69 00 6e 00 64 00 6f 00 77 00 73 00 5c 00 53 00 79 00 73 00 74 00 65 00 6d 00 33 00 32 00 5c 00 63 00 6d 00 64 00 2e 00 65 00 78 00 65 00 00 00 ... 00 94 66 00 // +0xf3c 文件大小(dir查看),0x669400(6722560) 70 31 67 00 // +0xf40 PE校验和,0x673170 ... 01 00 00 00 // +0xf50 固定值 00 00 00 00 // +0xf54 01 00 00 00 // +0xf58 00 00 00 00 // +0xf5c ... 00 00 ff ff // +0xf98 mspaint有值,notepad、calc是0 ... 03 00 00 00 // +0xfa0 mspaint有值,notepad、calc是0 -------------------------------------------------------------------------- mspaint.xml如下: -------------------------------------------------------------------------- -------------------------------------------------------------------------- 用Process Explorer搜索apphelp.dll,发现如下进程也加载了它: dwm.exe winlogon.exe svchost.exe (要进一步检查对应的服务) RuntimeBroker.exe explorer.exe cmd.exe cdb.exe 检查cmd的SHIM数据,对比mspaint、cmd: +0x1d8 "ApphelpDebug" +0x234 "shimengstate"->"PcaCliTrace" +0x274 0x029421db8320->0x01efc4007c50,一个指针,指向"TRACE..." +0x27c 0x554->0x4e,buflen +0x290 "ShimDebugLog"->"PcaCliDebug" +0x930 父进程PID,0x14a8(5288)->0xf38(3896) +0x934 "C:\Windows\System32\cmd.exe"->"C:\WINDOWS\Explorer.EXE" +0xf3c 文件大小(dir查看) +0xf40 PE校验和 > da /c 64 0x01efc4007c50 000001ef`c4007c50 "TRACE,0000,2600,PcaClient,Excluded,C:\WINDOWS\system32\mmc.exe,SFC protected.." > db 0x01efc4007c50 l 0x4e 000001ef`c4007c50 54 52 41 43 45 2c 30 30-30 30 2c 32 36 30 30 2c TRACE,0000,2600, 000001ef`c4007c60 50 63 61 43 6c 69 65 6e-74 2c 45 78 63 6c 75 64 PcaClient,Exclud 000001ef`c4007c70 65 64 2c 43 3a 5c 57 49-4e 44 4f 57 53 5c 73 79 ed,C:\WINDOWS\sy 000001ef`c4007c80 73 74 65 6d 33 32 5c 6d-6d 63 2e 65 78 65 2c 53 stem32\mmc.exe,S 000001ef`c4007c90 46 43 20 70 72 6f 74 65-63 74 65 64 0d 0a FC protected.. 至此可以自定义几个用于IDA逆向分析的结构: -------------------------------------------------------------------------- #pragma pack(push,1) struct SomeStruct_0 { unsigned int unknown_0; // +0x0 unsigned int unknown_4; // +0x4 unsigned int unknown_8; // +0x8 unsigned int unknown_c; // +0xc unsigned int unknown_10; // +0x10 unsigned int unknown_14; // +0x14 unsigned int unknown_18; // +0x18 unsigned int unknown_1c; // +0x1c unsigned int unknown_20; // +0x20 unsigned int unknown_24; // +0x24 unsigned int unknown_28; // +0x28 unsigned int unknown_2c; // +0x2c unsigned int unknown_30; // +0x30 unsigned int unknown_34; // +0x34 unsigned int unknown_38; // +0x38 unsigned int unknown_3c; // +0x3c unsigned int unknown_40; // +0x40 unsigned int unknown_44; // +0x44 /* * 11111111-1111-1111-1111-111111111111 */ GUID DBID; // +0x48 参mspaint.xml unsigned int unknown_58; // +0x58 unsigned int unknown_5c; // +0x5c unsigned int unknown_60; // +0x60 unsigned int unknown_64; // +0x64 unsigned int unknown_68; // +0x68 unsigned int unknown_6c; // +0x6c unsigned int unknown_70; // +0x70 unsigned int unknown_74; // +0x74 unsigned int unknown_78; // +0x78 unsigned int unknown_7c; // +0x7c // +0x80 }; struct SomeStruct_1 { SomeStruct_0 struct_0; // +0x0 SomeStruct_0 struct_80; // +0x80 SomeStruct_0 struct_100; // +0x100 unsigned char unknown_180[0x48]; // +0x180 // +0x1c8 }; struct ShimData { unsigned int ShimDataLen; // +0x0 长度域,包含自身,固定值,0xFB8 unsigned int magic; // +0x4 固定值,0xAC0DEDAB unsigned int unknown_8; // +0x8 /* * ? wo(@@c++(@$peb->ImageBaseAddress)+dwo(@@c++(@$peb->ImageBaseAddress)+0x3c)+0x4) * dt ntdll!_IMAGE_DOS_HEADER e_lfanew * dt ntdll!_IMAGE_NT_HEADERS64 FileHeader.Machine */ unsigned short int Machine; // +0xc 0x8664(34404)表示x64 unsigned short int unknown_e; // +0xe SomeStruct_1 struct_10; // +0x10 unsigned char str_1d8[0x40]; // +0x1d8 ibp时填成"ApphelpDebug" unsigned int unknown_218; // +0x218 unsigned int unknown_21c; // +0x21c unsigned int unknown_220; // +0x220 unsigned int unknown_224; // +0x224 unsigned int unknown_228; // +0x228 unsigned int unknown_22c; // +0x22c unsigned int unknown_230; // +0x230 unsigned char str_234[0x40]; // +0x234 ibp时填成"shimengstate" unsigned char *buf_274; // +0x274 unsigned int buflen_27c; // +0x27c unsigned char unknown_280[0xc]; // +0x280 unsigned int unknown_28c; // +0x28c unsigned char str_290[0x40]; // +0x290 ibp时填成"ShimDebugLog" unsigned char *buf_2d0; // +0x2d0 unsigned int buflen_2d8; // +0x2d8 unsigned int unknown_2dc; // +0x2dc unsigned int unknown_2e0; // +0x2e0 unsigned int unknown_2e4; // +0x2e4 unsigned int unknown_2e8; // +0x2e8 unsigned char unknown_2ec[0x2ec]; // +0x2ec unsigned int unknown_5d8; // +0x5d8 unsigned int unknown_5dc; // +0x5dc unsigned int unknown_5e0; // +0x5e0 unsigned char unknown_5e4[0x10]; // +0x5e4 unsigned int unknown_5f4; // +0x5f4 unsigned int unknown_5f8; // +0x5f8 unsigned char unknown_5fc[0xc]; // +0x5fc /* * !pde.guid * 8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a Win10 * e2011457-1546-43c5-a5fe-008deee3d3f0 Vista */ GUID MaxSupportedOS; // +0x608 GUID MinSupportedOS; // +0x618 unsigned int unknown_628; // +0x628 unsigned char unknown_62c[0x304]; // +0x62c unsigned int ParentPid; // +0x930 父进程PID wchar_t ParentPath[0x104]; // +0x934 父进程路径 unsigned char unknown_b3c[0x400]; // +0xb3c unsigned int FileSize; // +0xf3c 文件大小(dir查看) unsigned int PESum; // +0xf40 PE校验和 unsigned int boolean_f44; // +0xf44 unsigned int unknown_f48; // +0xf48 unsigned int unknown_f4c; // +0xf4c unsigned int unknown_f50; // +0xf50 unsigned int boolean_f54; // +0xf54 unsigned int unknown_f58; // +0xf58 unsigned int unknown_f5c; // +0xf5c unsigned char unknown_f60[0x38]; // +0xf60 unsigned int unknown_f98; // +0xf98 unsigned int unknown_f9c; // +0xf9c unsigned int unknown_fa0; // +0xfa0 unsigned char unknown_fa4[0x14]; // +0xfa4 // +0xfb8 }; #pragma pack(pop) -------------------------------------------------------------------------- 写入子进程的SHIM数据由父进程调用KERNEL32!BasepGetAppCompatData()产生: -------------------------------------------------------------------------- void BasepGetAppCompatData ( a1, // rcx a2, // rdx a3, // r8 a4, // r9 a5, // rsp+0x28 a6, // rsp+0x30 /* * ? wo(@@c++(@$peb->ImageBaseAddress)+dwo(@@c++(@$peb->ImageBaseAddress)+0x3c)+0x4) * dt ntdll!_IMAGE_DOS_HEADER e_lfanew * dt ntdll!_IMAGE_NT_HEADERS64 FileHeader.Machine */ unsigned short int Machine, // rsp+0x38 a8, // rsp+0x40 a9, // rsp+0x48 /* * ? poi(poi(@rsp+0x50)) * ? dwo(poi(@rsp+0x58)) */ SomeStruct_1 **a10, // rsp+0x50 in /* * *all==sizeof(SomeStruct_1) */ unsigned int *a11, // rsp+0x58 in unsigned char **out, // rsp+0x60 out unsigned int *outlen // rsp+0x68 out ); -------------------------------------------------------------------------- BasepGetAppCompatData()对如下三个EXE做了特别对待: wwahost.exe microsoftedge.exe microsoftedgecp.exe 用wt命令对比分析mspaint、notepad在KERNEL32!BasepGetAppCompatData()中的流程, 确认mspaint的*a10、*a11有值,notepad则无,这些数据将来会复制到ShimData中。 BasepGetAppCompatData()的*a10等于NULL时,导致notepad不会调用 BaseGenerateAppCompatData()。需要进一步分析CreateProcessInternalW(),以了 解BasepGetAppCompatData()的*a10何时不为NULL。*a10是由BasepQueryAppCompat() 填充的: -------------------------------------------------------------------------- void BasepQueryAppCompat ( a1, // rcx a2, // rdx a3, // r8 a4, // r9 HANDLE ProcessHandle, // rsp+0x28 a6, // rsp+0x30 a7, // rsp+0x38 a8, // rsp+0x40 /* * 对应BasepGetAppCompatData()的a10 */ SomeStruct_1 **x9, // rsp+0x48 /* * 对应BasepGetAppCompatData()的a11 * * sizeof(SomeStruct_1)==0x1c8 */ unsigned int *x10, // rsp+0x50 a11, // rsp+0x58 a12, // rsp+0x60 a13, // rsp+0x68 a14, // rsp+0x70 a15, // rsp+0x78 a16, // rsp+0x80 a17, // rsp+0x88 a18 // rsp+0x90 ); -------------------------------------------------------------------------- 顺着BasepQueryAppCompat()找到CompatCacheLookupAndWriteToProcess(),mspaint 和notepad在后者的流程会分叉。 分析CompatCacheLookupAndWriteToProcess(),越来越混乱。至此仍然无法解释为什 么mspaint有Shim机制介入,而notepad没有,这个配置到底在哪里? 观察到mspaint会加载apphelp.dll、映射sysmain.sdb,猜测cmd在创建mspaint时也 会映射sysmain.sdb,也就是说mspaint实际涉及2次sysmain.sdb。猜测x64/Win10不 分32、64位,只有一份sysmain.sdb,AppPatch64子目录是个摆设。 监控cmd对sysmain.sdb的映射,看到调用栈回溯: Hit:[C:\Windows\apppatch\sysmain.sdb] rax=0000000000000000 rbx=0000000000000000 rcx=00007ffd66630344 rdx=0000000000000000 rsi=000001f959c82f00 rdi=000001f959c82f68 rip=00007ffd60e77f17 rsp=000000c933b7e0f0 rbp=000000c933b7e169 r8=000000c933b7e0e8 r9=000000c933b7e169 r10=0000000000000000 r11=0000000000000246 r12=0000000000000001 r13=0000000000000001 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 apphelp!RtlFileMapMapView+0x137: 00007ffd`60e77f17 8bd8 mov ebx,eax > kpn # Child-SP RetAddr Call Site 00 000000c9`33b7e0f0 00007ffd`60e77ca9 apphelp!RtlFileMapMapView+0x137 01 000000c9`33b7e1d0 00007ffd`60e77c04 apphelp!AslFileMappingEnsureMappedAs+0x35 02 000000c9`33b7e210 00007ffd`60e77ac8 apphelp!SdbOpenDatabaseEx+0x8c 03 000000c9`33b7e260 00007ffd`60e763f8 apphelp!SdbInitDatabaseEx+0xa8 04 000000c9`33b7e500 00007ffd`66237e6f apphelp!ApphelpCreateAppcompatData+0xa8 05 000000c9`33b7e550 00007ffd`66237891 KERNEL32!BaseGenerateAppCompatData+0x5f 06 000000c9`33b7e5a0 00007ffd`638018a3 KERNEL32!BasepGetAppCompatData+0x391 07 000000c9`33b7e670 00007ffd`637fd7a6 KERNELBASE!CreateProcessInternalW+0x2d03 08 000000c9`33b7f2d0 00007ffd`6623e4e3 KERNELBASE!CreateProcessW+0x66 09 000000c9`33b7f340 00007ff6`89ebaec8 KERNEL32!CreateProcessWStub+0x53 0a 000000c9`33b7f3a0 00007ff6`89ec39e3 cmd!ExecPgm+0x244 > u 7ffd`60e77f17-6 l 1 apphelp!RtlFileMapMapView+0x131: 00007ffd`60e77f11 ff15811e0400 call qword ptr [apphelp!_imp_ZwMapViewOfSection (00007ffd`60eb9d98)] > dps apphelp!_imp_ZwMapViewOfSection l 1 00007ffd`60eb9d98 00007ffd`66630330 ntdll!NtMapViewOfSection cmd创建mspaint时果然先映射了一次sysmain.sdb。 至此知道: KERNELBASE!CreateProcessW+0x61 KERNELBASE!CreateProcessInternalW+0x1b39 ntdll!NtCreateUserProcess // cmd创建mspaint KERNELBASE!CreateProcessInternalW+0x2cfd KERNEL32!BasepGetAppCompatData+0x38c KERNEL32!BaseGenerateAppCompatData+0x59 // notepad不会过此 apphelp!ApphelpCreateAppcompatData+0xa3 apphelp!SdbInitDatabaseEx+0xa3 apphelp!SdbOpenDatabaseEx+0x87 // cmd打开sysmain.sdb KERNELBASE!CreateProcessInternalW+0x2d53 ntdll!NtAllocateVirtualMemory // cmd在mspaint进程空间分配内存,将来用于存放SHIM数据 KERNELBASE!CreateProcessInternalW+0x2d8d ntdll!NtWriteVirtualMemory // cmd向mspaint进程空间写入SHIM数据 KERNELBASE!CreateProcessInternalW+0x2dc9 ntdll!NtWriteVirtualMemory // cmd更新mspaint的PEB->pShimData 尽管确认cmd创建mspaint时,自己会映射一次sysmain.sdb,但这不是最早的分叉点。 CompatCacheLookupAndWriteToProcess()所暗示的"Compatibility Cache"是什么东 西,从哪里来的? 放狗搜"Windows Compatibility Cache",找到这些内容: -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache] "AppCompatCache"=hex:... "CacheMainSdb"=hex:... "SdbTime"=hex:... -------------------------------------------------------------------------- 这3个键值都是REG_BINARY类型。 C:\Windows\appcompat\Programs\Amcache.hve C:\Windows\AppCompat\Programs\RecentFileCache.bcf $ sc qc ahcache SERVICE_NAME: ahcache TYPE : 1 KERNEL_DRIVER START_TYPE : 1 SYSTEM_START ERROR_CONTROL : 1 NORMAL BINARY_PATH_NAME : system32\DRIVERS\ahcache.sys LOAD_ORDER_GROUP : TAG : 0 DISPLAY_NAME : Application Compatibility Cache DEPENDENCIES : SERVICE_START_NAME : $ sc qc PcaSvc SERVICE_NAME: PcaSvc TYPE : 20 WIN32_SHARE_PROCESS START_TYPE : 3 DEMAND_START ERROR_CONTROL : 1 NORMAL BINARY_PATH_NAME : C:\WINDOWS\system32\svchost.exe -k LocalSystemNetworkRestricted -p LOAD_ORDER_GROUP : TAG : 0 DISPLAY_NAME : Program Compatibility Assistant Service DEPENDENCIES : RpcSs SERVICE_START_NAME : LocalSystem kd> x ahcache!AhcCacheHandle 看了一圈,估计是这个意思。一个程序是否需要Shim机制介入,归根结底还是 sysmain.sdb在起作用。如果某程序第一次执行时被判定需要Shim机制介入,会在 "Compatibility Cache"里缓存相应信息。当系统重启、关闭时, "Compatibility Cache"里缓存的信息被序列化后存入AppCompatCache子键下。程序 执行时,先在"Compatibility Cache"里找,找不到了再去sysmain.sdb里找,以此判 定是否需要Shim机制介入。 我用下面这个工具看sysmain.sdb: Windows Shim Database (SDB) Parser (shims) - David Tomczak https://tzworks.net/prototype_page.php?proto_id=33 在其中找到: -------------------------------------------------------------------------- -------------------------------------------------------------------------- 与之前从内存中转储得来的mspaint.xml做个对比,关键内容相符合。 最初没有特别明确的目标,只是想用调试器看看,如果能找到一些关键点,即使当下 不深究,将来需要时也可以提纲挈领式地继续。后来工作安排有变动,不打算看Shim 机制了,但已经有过一些调试分析,不忍舍弃,留于此间。本文未做Shim机制科普, 最后也无明确的指导性结论,但个人觉得有一些通用逆向分析思路藏于其中。这些思 考过程不是最优的,但这种基于当下知识储备展开的逐步迭代、推进,显得格外真实, 供读者借鉴。 2018-04-28 16:05 scz "Shim Cache"即"Compatibility Cache"。外面能找到的工具有几种用法,一种是读 注册表,这个时效性受限,看不到当前生效中的"Shim Cache";第二种是转储内存后 离线检查;第三种是离线检查硬盘。 假设victim有kd接入,且正在运转中,如何只用windbg自带功能查看x64/Win10当前 生效中的"Shim Cache"?有解。 由于livekd的存在,其解对于取证有实际意义,非YY。 这个问题,留给那些永远充满好奇心的人们。