winlogon.exe 进程中具有 RWX 权限的 VAD

逆向工程 视窗 记忆 数字取证
2021-06-27 13:40:51

在 VirtualBox VM 内运行的干净的 Windows XP SP2 安装上,当使用 vboxmangage debugvm --dumpguestcore 制作快照并在 Volatility 中分析它时,我总是在 winlogon.exe 进程中找到 9 个具有 PAGE_EXECUTE_READWRITE 权限的 VAD。

我已经在这里问过这个问题,但是对于 winlogon 和 csrss 进程: 在 winlogon 和 csrss 进程中具有 RWX 权限的 VAD

我能够发现 csrss.exe 进程中的 RWX VAD 是堆。不幸的是,我无法为 winlogon.exe 中的 VAD 确认这一点。

但是我在 Digital Investigations 杂志上读过一篇文章“用户空间代码的完整性验证”,其中有一些关于这些 RWX VAD 的信息。该文章可以在这里找到:http : //www.dfrws.org/2013/proceedings/DFRWS2013-12.pdf

在这篇文章中,安德鲁怀特和他的同事们发表了以下声明:

除了默认的可执行部分,Windows XP 还在两个系统进程中展示了一些默认行为,这些进程创建了不可验证的分配。第一个进程是 winlogon.exe,其中创建了 9 个看似仅包含数据的可执行和可写分配。这些分配中的每一个都有 4 页长,并且人烟稀少。这些分配的位置可以在 winlogon.exe 的 .data 部分中的数组中找到,通常从 winlogon.exe + 0x72b0c 开始。

不幸的是,我无法确认这一点。我认为这是由于我使用 Windows XP SP2 而他们使用 XP SP3。这可能会导致此地址发生更改。

他们为他们的方法编写的代码是开源的(它基于波动率插件),你可以在这里找到它:https : //github.com/a-white/Hashtest他们编写的用于提取数组的函数在数据部分是:

def get_winlogon_allocations(self, task, ps_ad):
    """Get the EXECUTE_READWRITE pages used by winlogon"""
    if str(task.ImageFileName) == "winlogon.exe":
        base = task.SectionBaseAddress
        addrs = []
        # TODO - determine better method of finding offset
        start = 0x72b0c  # will change for other versions of winlogon
        current = start
        while True:
            value = ps_ad.zread(base + current, 4)
            value = struct.unpack("<L", value)[0]
            if value > 0 and value % 0x1000 == 0:
                addrs.append(value)
                current += 0x8
            else:
                break
        return addrs
    else:
        return []

你知道他们是如何找到这个地址的吗?或者任何可以指向正确地址的提示?

提前致谢并致以最诚挚的问候!

2个回答

winlogon iirc 分配more than 9 RWX页面,但在9 pages创建转储之前不会仅释放这些页面

你在转储中观察这些页面,因为转储是过早的死亡

如果您在关闭/注销路径中等待足够长,您可能会捕获 VirtualFree() 的

我已经在您链接的上一篇文章中发布了几乎所有这些页面都包含使用 pushf pushad 序列保存标志和寄存器并通过 jmp eax 跳转到某个地址的代码

下面是一个实时堆栈,其中从 RWX 页面执行代码(当您创建转储时,此页面将被释放将不可用)

在您的设置中找出地址的一种方法可能是搜索转储中显示的特定内容DWORD!vad 在 winlogon 内存中输出一个 RWX 页面,其示例也粘贴在下面

kd> kb
ChildEBP RetAddr  Args to Child              
01e8f8b8 01010cf0 00000000 000080fd 00004000 winlogon!RmvpOpenNtDeviceFromWin32Path+0x23b
01e8f904 01010bd8 000002a4 000002a4 00000000 winlogon!RmvpOpenNtDeviceFromWin32Path+0x1ea
01e8f91c 0100e477 000002a4 000002a4 00000000 winlogon!RmvpOpenNtDeviceFromWin32Path+0xd2
01e8fc04 01058b0a 00000001 01058c00 01e8fc4c winlogon!CheckForUserObjectUpdates+0xb3
01e8fc70 02f7179d 000002a4 01049efc 00000000 winlogon!AutoPtrBase<_SECURITY_DESCRIPTOR>::AutoPtrBase<_SECURITY_DESCRIPTOR>+0x20
WARNING: Frame IP not in any known module. Following frames may be wrong.
01e8fef8 7c92796d 000002a4 7c97e460 000cfb20 0x2f7179d
01e8ff40 7c9279ab 01049efc 000002a4 00000000 ntdll!RtlpWorkerCallout+0x70
01e8ff60 7c927a6d 00000000 000002a4 000cfb20 ntdll!RtlpExecuteWorkerRequest+0x1a
01e8ff74 7c927a44 7c927991 00000000 000002a4 ntdll!RtlpApcCallout+0x11
01e8ffb4 7c80b713 00000000 00000000 00000000 ntdll!RtlpWorkerThread+0x87
01e8ffec 00000000 7c910250 00000000 00000000 kernel32!BaseThreadStart+0x37

调用堆栈中的一页不在任何已知模块中,反汇编并查看

kd> ub 02f7179d
02f71789 0000            add     byte ptr [eax],al
02f7178b 0000            add     byte ptr [eax],al
02f7178d 0000            add     byte ptr [eax],al
02f7178f 0000            add     byte ptr [eax],al
02f71791 53              push    ebx
02f71792 52              push    edx
02f71793 e8f8ca09fe      call    winlogon!DeleteRasConnections+0x3c (0100e290)
02f71798 e8d78a0efe      call    winlogon!CreateAndHoldWPAGlobalMutex (0105a274)
kd> u 02f7179d
02f7179d 9c              pushfd
02f7179e 60              pushad
02f7179f 56              push    esi
02f717a0 57              push    edi
02f717a1 6a08            push    8
02f717a3 e854cb09fe      call    winlogon!DeleteRasConnections+0xa8 (0100e2fc)
02f717a8 ffe0            jmp     eax
02f717aa 90              nop

所以 winlogon!CreateAndHoldWPAGlobalMutex (0105a274) 正在我们的访问断点中断时从未知页面执行

kd> r
eax=968dab54 ebx=00010000 ecx=000080fd edx=0000ffff esi=00000000 edi=00010000
eip=01010d41 esp=01e8f8b0 ebp=01e8f8b8 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000282
winlogon!RmvpOpenNtDeviceFromWin32Path+0x23b:
001b:01010d41 c1f810          sar     eax,10h  <--- eip is +1 when hardware bp is hit

kd> ub @eip
winlogon!RmvpOpenNtDeviceFromWin32Path+0x21f:
01010d25 03c6            add     eax,esi
01010d27 5e              pop     esi
01010d28 5d              pop     ebp
01010d29 c20800          ret     8
01010d2c a1042b0701      mov     eax,dword ptr [winlogon!MMX_available+0x39c (01072b04)]  < read access not hit 
01010d31 69c0fd430300    imul    eax,eax,343FDh
01010d37 05c39e2600      add     eax,269EC3h
01010d3c a3042b0701      mov     dword ptr [winlogon!MMX_available+0x39c (01072b04)],eax  < we hit write access here match eax with data 

并且 72b0c 还保存执行发生的页面地址 try !vad on winlogon 并确认它是否是 RWX 并搜索 winlogon 内存

kd> dd 01072b04 l4
01072b04  968dab54 00000002 02f70000 00000000


kd> !process 0 0 winlogon.exe
PROCESS 81167cf8  SessionId: 0  Cid: 0218    Peb: 7ffdf000  ParentCid: 0168
    DirBase: 088f5000  ObjectTable: e14a0600  HandleCount: 185.
    Image: winlogon.exe



kd> !grep -i -c "!vad @@c++(((nt!_EPROCESS *) 0x81167cf8)->VadRoot)" -e "execute_readwrite"

812287d8 ( 9)       2f70     2f73         4 Private      EXECUTE_READWRITE 


kd> dd 01072b04 
01072b04  968dab54 00000002 02f70000 00000000
01072b14  00000000 00000000 00000000 00000000
01072b24  00000000 00000000 00000000 00000000
01072b34  00000000 00000000 00000000 00000000
01072b44  00000000 00000000 00000000 00000000
01072b54  00000000 00000000 00000000 00000000
01072b64  00000000 00000000 00000000 00000000
01072b74  00000000 00000000 00000000 00000000


kd> lm m winlo*
start    end        module name
01000000 01081000   winlogon   (pdb symbols)    


kd> s -d winlogon l?81000 02f70000
01072b0c  02f70000 00000000 00000000 00000000  ................

您可以在转储中搜索 rwx 页面地址而不是 72b0c,如果它显示为 68900,您将能够在 winlogon 地址空间中找到该地址的交叉引用

(windbg 命令#(搜索程序集模式)

kd> # 72b0c 1008000 l?11000
winlogon!CheckForUserObjectUpdates+0x49:
0100e40d 8b04c50c2b0701  mov     eax,dword ptr winlogon!MMX_available+0x3a4 (01072b0c)[eax*8]
winlogon!MprLogonNotify+0xda:
01010812 8b04f50c2b0701  mov     eax,dword ptr winlogon!MMX_available+0x3a4 (01072b0c)[esi*8]
winlogon!RmvpOpenNtDeviceFromWin32Path+0x157:
01010c5d 8934fd0c2b0701  mov     dword ptr winlogon!MMX_available+0x3a4 (01072b0c)[edi*8],esi

最后一个是写位置,edi 包含计数

这是 xp sp3 中的 RWX VirtualAlloc 您应该也可以在 sp2 中找到类似的模式

01010CDC  PUSH    40               ; /Protect = PAGE_EXECUTE_READWRITE
01010CDE  PUSH    3000             ; |AllocationType = MEM_COMMIT|MEM_RESERVE
01010CE3  PUSH    4000             ; |Size = 4000 (16384.)
01010CE8  PUSH    ESI              ; |/Arg2 = FFFFFFFF
01010CE9  PUSH    0                ; ||Arg1 = 00000000
01010CEB  CALL    winlogon.01010D05; |\winlogon.01010D05
01010CF0  IMUL    EAX, EBX         ; |
01010CF3  ADD     EAX, EDI         ; |ntdll.7C910228
01010CF5  PUSH    EAX              ; |Address = NULL
01010CF6  CALL    K32.VirtualAlloc]; \VirtualAlloc

我能够在 Windows XP SP2 的 winlogon.exe 进程中找到正确的地址。它是 0x71ac4。

我使用易失性从内存中转储了 winlogon.exe 进程。然后使用十六进制编辑器,我能够在该过程中找到 RWX VAD 的地址,地址数组从 0x71ac4 开始。为什么我一开始找不到这些地址的问题很简单:这是字节序。我搜索了地址的 little-endian 出现,但它们是 big-endian。

感谢我的一位同事为我指出这一点。:-)