以下所有陈述均基于 xp-sp3
WinDbg中也可以用来分析在VadTree RWX页面
复制粘贴以下几行**.txt and run the script $$>a< path to **.txt
脚本内容需要在路径中使用 grep 进行文本解析
aS proc @#Process ;
aS procname @@c++( (char *)(((nt!_EPROCESS *) @#Process ))->ImageFileName ) ;
aS procvad @@c++( (((nt!_EPROCESS *) @#Process ))->VadRoot ) ;
.block { !for_each_process ".printf \"%20ma\t%p\t%p\n\n\",${procname}, ${proc} , ${procvad}; .echo \n;.shell -ci \"!vad ${procvad}\" grep \"EXECUTE_READWRITE\"" } ;
ad *
然后设置进程上下文以适应进程并检查从 StartVpn 到 EndVpn 的内存
iirc Winlogon 和 csrss 总是有几个 RWX 页面
csrss RWX 页面似乎总是包含大量初始化 _UNICODE_STRING
大多数页面将无法查看您可能需要在 Phase1Init 阶段进行实时调试
sxe ibp;.reboot
在重新启动设置bp NtCreateProcessEx
直到 csrss 即将创建
bc * ; gu ;!vad on csrss _EPROCESS
csrss 进程此时不会有 RWX 页面
只有 4 个 vads 将存在于 csrss VadTree
您可能需要从这里开始并捕获分配/写入和执行
csrss.exe 86acebe0 86d62660
86d39250 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READWRITE Pagefile-backed section
此 oneliner 将获取该页面中的大部分字符串
.foreach (place { s -[1]b 7f6f0000 l?7000 0x7f } ) { r $t0 = place ; dS @$t0-7}
上面一行的输出
7f6f2170 "C:\WINDOWS"
7f6f2190 "C:\WINDOWS\system32"
7f6f21c0 "\BaseNamedObjects"
7f6f2208 ".罯...罯"
7f6f22b0 ".罯...罯"
7f6f221c "Autorun.inf"
7f6f2300 ".罯02.罯Software\Microsoft\Clock"
7f6f226c "DoesNotExist"
7f6f2260 ".罯"
7f6f2368 "ヘ罯...罯.罯"
7f6f22c4 "Clock.ini"
7f6f23d8 ".罯68.罯Control Panel\Color Scheme"
7f6f2418 "s"
7f6f230c "Software\Microsoft\Clock"
winlogon RWX 页面将包含 Executble 代码,其中大多数将以push cx push ax
序列开头,
并以对 somehwre 的间接调用结束,jmp eax
一些对不可见/不存在位置的中间调用可能需要实时分析
从未在 clean explorer / iexplore / services.exe 进程中观察到 rwx 页面,它们仅在安装了某些防病毒软件等后才存在
请参阅下面的Avasted RWX
explorer.exe 页面,修补RtlSetCurrentDirectory_U
和加载snxhk.dll using LdrLoadDll()
相同的补丁也可以在 iexplore.exe 中观察到
.shell dir /b scan*vad*
scanvad4rwx.txt
lkd> $$>a< scanvad4rwx.txt
System 86fc6830 86fbfa90
smss.exe 86b0e020 86dfd008
csrss.exe 86acebe0 86f4e4d0
86d39250 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READWRITE Pagefile-backed section
winlogon.exe 86d7b918 86d58930
86ae8ee0 ( 8) 9550 9553 4 Private EXECUTE_READWRITE
86340690 ( 7) 29c90 29c93 4 Private EXECUTE_READWRITE
86f370d0 ( 6) 2a4f0 2a4f3 4 Private EXECUTE_READWRITE
86b13a38 ( 5) 46580 46583 4 Private EXECUTE_READWRITE
86da2a00 ( 6) 497c0 497c3 4 Private EXECUTE_READWRITE
services.exe 86b0a020 86ec15c8
86da7c20 (12) 380 380 1 Private EXECUTE_READWRITE
lsass.exe 86b2a6b8 86b21110
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
explorer.exe 86241260 86b86768
86b13d28 (13) 90 90 1 Private EXECUTE_READWRITE
86545e50 (11) 2b0 2b0 1 Private EXECUTE_READWRITE
86aa6878 (12) 2c0 2ca 11 Private EXECUTE_READWRITE
86b056a0 (10) 2d0 2da 11 Private EXECUTE_READWRITE
86b3b9c8 (12) 2e0 2ea 11 Private EXECUTE_READWRITE
AvastUI.exe 86315a00 860fc008
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
iexplore.exe 86aaf020 861b3f00
862ae9f8 (16) 150 150 1 Private EXECUTE_READWRITE
在重读时,我注意到以下输出来自不同的会话,因此拆分
and examine the memory using lkd> .process /p /r 862543e8 & lkd> uf 150000
00150000 50 push eax
00150001 60 pushad
00150002 bd42001500 mov ebp,150042h
00150007 8b7d10 mov edi,dword ptr [ebp+10h]
0015000a 8b4518 mov eax,dword ptr [ebp+18h]
0015000d 8b5d1c mov ebx,dword ptr [ebp+1Ch]
00150010 8907 mov dword ptr [edi],eax
00150012 895f04 mov dword ptr [edi+4],ebx
00150015 897c2420 mov dword ptr [esp+20h],edi
00150019 8d454c lea eax,[ebp+4Ch]
0015001c 50 push eax
0015001d ff7548 push dword ptr [ebp+48h]
00150020 8d4550 lea eax,[ebp+50h]
00150023 50 push eax
00150024 8d4540 lea eax,[ebp+40h]
00150027 50 push eax
00150028 6aff push 0FFFFFFFFh
0015002a ff5508 call dword ptr [ebp+8]
0015002d 85c0 test eax,eax
0015002f 750f jne 00150040
00150031 33c9 xor ecx,ecx
00150033 8d4538 lea eax,[ebp+38h]
00150036 50 push eax
00150037 8d4528 lea eax,[ebp+28h]
0015003a 50 push eax
0015003b 51 push ecx
0015003c 51 push ecx
0015003d ff5500 call dword ptr [ebp]
00150040 61 popad
00150041 c3 ret
将命令放在一行中
? @$t1+10 ; ? poi(@$t1+10) ; ln poi(@$t1+10); db (@$t1+18) l8; u (@$t1+18) l3;
? poi(@$t1+4c) ; ? poi(@$t1+48) ; ? poi(@$t1+50) ;? poi(@$t1+40) ; lm m ntdll* ;
ln poi(@$t1+8) ; ? poi(@$t1+38); db (@$t1+28) l8; du /c 40 poi(@$t1+2c) ;
? poi(@$t1); ln poi(@$t1);.echo patches RtlSetCurwith pattern and sets return
address [esp+20]to patched instruction calls ntvirtproct for a pagein ntdll
on successloads a dll using LdrLoadDll;
Evaluate expression: 1376338 = 00150052
Evaluate expression: 2089936810 = 7c91e7aa
(7c91e7aa) Exact matches: ntdll!RtlSetCurrentDirectory_U
0015005a 6a 6c 68 78 e9 91 7c e8 jlhx..|.
0015005a 6a6c push 6Ch
0015005c 6878e9917c push offset ntdll!`string'+0x34 (7c91e978)
00150061 e81501ffff call 0014017b
Evaluate expression: 64 = 00000040
Evaluate expression: 32 = 00000020
Evaluate expression: 4096 = 00001000
Evaluate expression: 2089934848 = 7c91e000
start end module name
7c900000 7c9b2000 ntdll (pdb symbols) f:\symbols\ntdll.pdb
(7c90d6ee) Exact matches: ntdll!NtProtectVirtualMemory
Evaluate expression: 1691353088 = 64d00000
0015006a 60 00 60 00 9a 00 15 00 `.`.....
0015009a "C:\Program Files\Alwil Software\Avast5\snxhk.dll"
Evaluate expression: 2089903043 = 7c9163c3
(7c9163c3) Exact matches: ntdll!LdrLoadDll = <no type information>
patches RtlSetCurwith pattern and sets return address
[esp+20] to patched instruction calls ntvirtproct for
a page in ntdll on success loads a dll using LdrLoadDll
更新
CSRSRV 初始化期间正在创建 csrss.exe 中的 rwx 页面似乎是堆
我在 NtAllocateVirtualMemory 上创建 csrss.exe 后设置了一个条件中断,以在每次分配时打印 VadTree
,我看到在 CSRSRV init 时插入了 rwx 页面,并且在调用堆栈中观察到了 CreateSharedSection
sxe ibp;.reboot
在重新启动bp NtCreateprocessEx and hit g;kb
直到 csrss.exe 即将创建时,
您可以通过查看传递给 RtlCreateUserProcess api 的 unicode_string 在打印的
dS 应打印的调用堆栈中收集正在创建的进程..................... ...../csrss.exe
回车gu
以允许创建进程将进程
!process 0 1 csrss.exe
保存到便笺簿
!vad VadRoot
你应该在 csrss vad 树中观察 4 个 vad
现在设置这个条件断点(substitute the saved eprocess inplace of 0x81160020
注意use 0x notation
)
bp
bp nt!NtAllocateVirtualMemory "!vad @@c++(((nt!_EPROCESS *) 0x81160020)->VadRoot);kb;.echo \n;dd poi(@esp+8);"
如果您坚持访问断点,您可以在将 rwx 页面添加到 ProcessHeapList 时捕获
见下文
ntdll!RtlCreateHeap+0x5b9: 001b:7c9253de e8a6000000 调用 ntdll!RtlpAddHeapToProcessList
(7c925489)
kd> !heap
HEAPEXT:无法获取 *ntdll!RtlpGlobalTagHeap 的地址。索引地址名称调试选项已启用
1:00160000
2:00260000
kd>
p step over the call
ntdll!RtlCreateHeap+0x5be: 001b:7c9253e3 8b45e4 mov eax,dword ptr [ebp-1Ch]
kd> !heap
索引地址名称 调试选项已启用
1:00160000
2:00260000
3: 7f6f0000
kd> `!process 0 1 csrss.exe`
PROCESS `81160020` SessionId: 0 Cid: 01c4 Peb: 7ffde000 ParentCid: 014c
DirBase: 06e30000 ObjectTable: e14a7f38 HandleCount: 10.
Image: csrss.exe
VadRoot `812275c0 Vads 13`
转储瓦德特里
kd> `!vad 812275c0`
VAD level start end commit
812201d8 ( 1) 0 ff 0 Private READWRITE
812280e8 ( 2) 100 100 1 Private READWRITE
81229dd0 ( 3) 110 110 1 Private READWRITE
81222a88 ( 4) 120 15f 4 Private READWRITE
811f30b8 ( 5) 160 25f 3 Private READWRITE
81223b80 ( 6) 260 26f 6 Private READWRITE
812275c0 ( 0) 4a680 4a684 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\csrss.exe
811f4fd8 ( 2) 75b40 75b4a 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\csrsrv.dll
811cced0 ( 1) 7c900 7c9b1 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\ntdll.dll
8121f440 ( 3) `7f6f0 7f7ef 0 Mapped EXECUTE_READWRITE` Pagefile-backed section
81167108 ( 2) 7ffb0 7ffd3 0 Mapped READONLY Pagefile-backed section
811e1d30 ( 4) 7ffdd 7ffdd 1 Private READWRITE
811e21b0 ( 3) 7ffde 7ffde 1 Private READWRITE
Total VADs: 13 average level: 3 maximum depth: 6
转储调用堆栈
kd> kb
ChildEBP RetAddr Args to Child
0015fda4 75b437b8 00007008 7f6f0000 00100000 ntdll!RtlCreateHeap+0x5be
0015fe28 75b42f9a 001626dd 00000000 00000000 CSRSRV!CsrSrvCreateSharedSection+0x23f
0015ff74 75b430f3 0000000a 001624f0 7c90dc9e CSRSRV!CsrParseServerCommandLine+0x255
0015ff88 4a68115d 0000000a 001624f0 00000005 CSRSRV!CsrServerInitialization+0x95
0015ffa8 4a6818d7 0000000a 001624f0 0016251c csrss!main+0x4f
0015fff4 00000000 7ffde000 000000c8 00000166 csrss!NtProcessStartup+0x1d2
断点列表
kd> bl
0 e 8058124c 0001 (0001) nt!NtCreateProcessEx
1 e 805691ea 0001 (0001) nt!NtAllocateVirtualMemory "!vad @@c++(((nt!_EPROCESS *) 0x81160020)->VadRoot);kb;.echo \n;dd poi(@esp+8);"
2 e 7f6f0000 w 1 0001 (0001)
您可以在链的下方进一步使用 winlogon 来遵循此方法
更新以回答评论
断点@NtAllocateVirtualMemory 没有捕捉到vad 12 的分配,
这是来自vad11 的RWX 分配,我的断点只有在分配vad 13
并打印vadtree 时才被击中,我发现vad 增加了2,其中一个是7f6f0000 rwx 页面,所以也许另一种方法用于将 vad 添加到 NtAllocateVirtualMemory 的 vad 树中,有可能需要重置 rwx 而未重置需要调查
我只能确认该页面确实是 HEAP 并且似乎在几乎每个进程中都映射了对所有进程 vad 具有 EXECUTE_READ 权限的进程,除了在它是 RWX 的 csrss 中
lkd> .logopen c:\check7f6f0page.txt
Opened log file 'c:\check7f6f0page.txt'
lkd> !for_each_process ".process /p /r @#Process ; !grep -c \"!vad @@c++( ( ( nt!_EPROCESS *) @#Process )->VadRoot)\" -e \"7f6f0\""
lkd> .logclose
Closing open log file c:\check7f6f0page.txt
结果显示此页面已映射到所有进程
lkd> .shell grep "7f6f0 7f7ef 0 Mapped" c:\check7f6f0page.txt
<.shell waiting 1 second(s) for process>
86d39250 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READWRITE Pagefile-backed section
86d39250 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READWRITE Pagefile-backed section
86e87fd8 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86e87fd8 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86b96d10 ( 3) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86b96d10 ( 3) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86abfe80 ( 3) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86abfe80 ( 3) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86eaf3a8 ( 3) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86eaf3a8 ( 3) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86b3fda8 ( 4) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
86e77b20 ( 2) 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile-backed section
并确认构造_HEAP
lkd> dt -r nt!_HEAP 0x7f6f0000
+0x000 Entry : _HEAP_ENTRY
+0x000 Size : 0xc8
+0x002 PreviousSize : 0
+0x000 SubSegmentCode : 0x000000c8 Void
+0x004 SmallTagIndex : 0x1e ''
+0x005 Flags : 0x1 ''
+0x006 UnusedBytes : 0 ''
+0x007 SegmentIndex : 0 ''
+0x008 Signature : 0xeeffeeff
+0x00c Flags : 0x7008
+0x010 ForceFlags : 8
+0x014 VirtualMemoryThreshold : 0xfe00
+0x018 SegmentReserve : 0x100000
7f6f0000 的转储
lkd> dd 7f6f0000 l1c/4
7f6f0000 000000c8 0000011e eeffeeff 00007008
7f6f0010 00000008 0000fe00 00100000
如果您查看 ntdll!RtlCreateHeap,您可以确认此模式确实是堆
lkd> !grep -c "uf ntdll!RtlCreateHeap" -e "ebp-24h"
7c925dcd c745dc88050000 mov dword ptr [ebp-24h],588h
7c925de7 c745dcc0050000 mov dword ptr [ebp-24h],5C0h
7c925e87 8145dc80000000 add dword ptr [ebp-24h],80h
7c925eb1 8b75dc mov esi,dword ptr [ebp-24h]
7c93c079 0145dc add dword ptr [ebp-24h],eax
在使用地址的地方反汇编
lkd> u 7c925eb1
ntdll!RtlCreateHeap+0x421:
7c925eb1 8b75dc mov esi,dword ptr [ebp-24h]
7c925eb4 83c607 add esi,7
7c925eb7 83e6f8 and esi,0FFFFFFF8h
7c925eba 8bc6 mov eax,esi
7c925ebc c1e803 shr eax,3
7c925ebf 8b4de4 mov ecx,dword ptr [ebp-1Ch]
7c925ec2 668901 mov word ptr [ecx],ax
评估表达式
lkd> ? ((588 + 80 >> 3) + 7) & 0x0fffffff8
Evaluate expression: 200 = 000000c8
更新
csrss 中的 RWX 页面是_CsrSrvSharedSectionHeap
==_CsrSrvSharedSectionBase
从注册表查询特定值并映射到 NtMapViewOfSection
或使用 NtCreateSection 创建的部分所有这些都发生在
csrss!main ->csrsrv.dll ->CsrsrvCreateSharedSection
reg query "hklm\system\currentcontrolset\control\session manager\subsystems\csrss"
! REG.EXE VERSION 3.0
HKEY_LOCAL_MACHINE\system\currentcontrolset\control\session manager\subsystems\csrss
CsrSrvSharedSectionBase REG_DWORD 0x7f6f0000