关于windows session的一些探索
关于windows session的一些探索
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://debug-sai.blogbus.com/logs/109178332.html
有错误欢迎指针。
很久以前互联网上公开的一份代码
// 功能 : 扫描Session工作链枚举进程
void ScanSessionProcessList(PEPROCESS eprocess)
{
DWORD sessionlistoffset;
PLIST_ENTRY cur;
PLIST_ENTRY pro;
if (*NtBuildNumber == 2600)
sessionlistoffset = 0x0b4;
else if (*NtBuildNumber == 2195)
sessionlistoffset = 0x118;
else if (*NtBuildNumber == 3790)
sessionlistoffset = 0x0b4;
else if(*NtBuildNumber == 6000)
{
sessionlistoffset = 0x0cc;
}
else return ;
if (IS_WINDOWSSRV2003SP1())
{
sessionlistoffset = 0x0C4;
}
pro = (PLIST_ENTRY)(*(PVOID *)((PUCHAR)eprocess + sessionlistoffset + 4));
cur = pro->Flink;
for (;cur != pro;cur = cur->Flink)
{
CollectProcess((PEPROCESS)((ULONG)cur - sessionlistoffset));
}
CollectProcess((PEPROCESS)((ULONG)pro - sessionlistoffset));
return ;
}
=======================================
这里面其实引出了个session的概念.
session---》窗口站---》桌面
1交互式用户登录时,winlogin创建了交互窗口站"WinSta0",交互窗口站至少有三个桌面,对应:登录时,与用户交互时,屏保时。
2当非交互进程(比如服务应用)试图连接到一个窗口站并且该登录会话还没有窗口站存在时,系统将尝试给这个会话创建窗口站。创建的窗口站的名字是根据用户SID Service-0xZ1-Z2$, 其中Z1是登录SID的高位部分而Z2是SID的低位部分。由于SID对登录会话来说是唯一的,两个运行在同一session的服务使用唯一的窗口站。这些窗口站是非交互的。他们都有一个桌面被命名为default
3与交互窗口站(WinSta0)关键的那些桌面能用于显示用户界面并接受用户输入,但是同一时刻,这些桌面中,只能有一个是活动的。活动桌面,也被称作输入桌面,是这些桌面用户当前可见并接收用户输入的那个。应用程序可以使用OpenInputDesktop函数来获得输入桌面的句柄。已经请求访问的应用程序可以使用SwitchDesktop函数来指定一个不同的输入桌面
以下不做特别说明都以xp为例。代码则是wrk也就是2003的。vista,win7开始出现session隔离,变化较大,放在后面说。
首先是2个重要的全局变量:
MiSessionWsList是系统中的一个_LIST_ENTRY,将系统中所有的session链接起来。系统的session结构用MM_SESSION_SPACE结构表示(该结构在2000里貌似没有symbol,windbg无法看,但是MiSessionWsList是有symbol的,参考2000源码发现MM_SESSION_SPACE结构也存在)。session是怎么插入链表的见后面
MmSessionSpace是保存当前上下文的session。
=======================================
每个_eprocess都有两个成员:SessionProcessLinks链表和Session(2000是SessionId)
Session是指向该进程所属的Session,而SessionProcessLinks是个链表,将该session的所有进程链接起来(当然进程很可能断开了SessionProcessLinks链表)。
以xp sp3为例:
_eprocess:
.....
+0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x89e6752c - 0x8a16c26c ]
.....
+0x170 Session : 0xb9e00000
lkd> dt _MM_SESSION_SPACE 0xb9e00000
nt!_MM_SESSION_SPACE
+0x000 ReferenceCount : 0x39--------该session的进程数,当为0后session销毁(MiDereferenceSession---》MiDereferenceSessionFinal(如果是有图形化的session,该函数貌似会卸载该session的win32k.sys))
+0x004 u : __unnamed
+0x008 SessionId : 0-----------session id也得到了,这样就不用去peb里取了
+0x00c SessionPageDirectoryIndex : 0x15c87
+0x010 GlobalVirtualAddress : 0xb9e00000 _MM_SESSION_SPACE ------》指向全局Session链表头
+0x014 ProcessList : _LIST_ENTRY [ 0x8abe1e54 - 0x88f47d74 ]----》这个链表连接的就是每个进程的SessionProcessLinks链表
+0x01c NonPagedPoolBytes : 0
+0x020 PagedPoolBytes : 0
+0x024 NonPagedPoolAllocations : 0
+0x028 PagedPoolAllocations : 0
+0x02c NonPagablePages : 0x2f
+0x030 CommittedPages : 0x839
+0x038 LastProcessSwappedOutTime : _LARGE_INTEGER 0x0
+0x040 PageTables : 0x8ac0a800 _MMPTE----页表
+0x044 PagedPoolMutex : _FAST_MUTEX
+0x064 PagedPoolStart : 0xbb000000
+0x068 PagedPoolEnd : 0xbb3fffff
+0x06c PagedPoolBasePde : 0xc0602ec0 _MMPTE
+0x070 PagedPoolInfo : _MM_PAGED_POOL_INFO
+0x094 Color : 0xab2
+0x098 ProcessOutSwapCount : 0xa
+0x09c ImageList : _LIST_ENTRY [ 0x8ac341a8 - 0x8abda558 ]----这个很有意思,是
通过MmLoadSystemImage-》MiLoadImageSection-》MiSessionWideReserveImageAddress-》MiSessionInsertImage来得到一个IMAGE_ENTRY_IN_SESSION,这个结构没有symbol,windbg没法解析
/*
参考 MiSessionInsertImage
typedef struct _IMAGE_ENTRY_IN_SESSION {
LIST_ENTRY Link; ---》这个链接起来了
PVOID Address; ---》 这个baseaddr有效
PVOID LastAddress;
ULONG ImageCountInThisSession; ---》这个有效
LOGICAL ImageLoading; // Mods to this field protected by system load mutant
PMMPTE PrototypePtes;
PKLDR_DATA_TABLE_ENTRY DataTableEntry; ---》这个无效,所以不能得到sys名字了
PSESSION_GLOBAL_SUBSECTION_INFO GlobalSubs;
} IMAGE_ENTRY_IN_SESSION, *PIMAGE_ENTRY_IN_SESSION;
*/
+0x0a4 GlobalPteEntry : 0xc05cf000 _MMPTE
+0x0a8 CopyOnWriteCount : 0x80
+0x0ac SessionPoolAllocationFailures : [4] 0
+0x0bc AttachCount : 0
+0x0c0 AttachEvent : _KEVENT
+0x0d0 LastProcess : (null)
+0x0d8 Vm : _MMSUPPORT
+0x118 Wsle : 0xbe40003c _MMWSLE
+0x11c WsLock : _ERESOURCE
+0x154 WsListEntry : _LIST_ENTRY [ 0x80562b58 - 0x80562b58 ]----》系统session链表,链接过程见后面,在2000上偏移是0x174
+0x15c Session : _MMSESSION
+0x198 Win32KDriverObject : _DRIVER_OBJECT----》这个是win32k驱动对象的拷贝,在xp之前是一个拷贝,在2003后只有一个Win32KDriverUnload来得到win32k的DriverUnload,有图形化的session在退出时需要DriverUnload win32k驱动的。赋值流程是NtSetSystemInformation(SystemExtendServiceTableInformation)--》MmSessionSetUnloadAddress(&Win32KDevice)得到
+0x240 WorkingSetLockOwner : (null)
+0x244 PagedPool : _POOL_DESCRIPTOR
+0x126c ProcessReferenceToSession : 812
+0x1270 LocaleId : 0x804
前面提到MiSessionWsList是将系统中所有的session链接起来。它链接的是_MM_SESSION_SPACE中的WsListEntry成员。
lkd> dd MiSessionWsList
80562b58 b9e00154 b9e00154 05000000 be400000
0xb9e00154-0x154正好和上面的0xb9e00000印证。
session的创建:
NtSetSystemInformation(SystemSessionCreate)---》MmSessionCreate
MmSessionCreate(....)
{
......
Status = MiSessionCreateInternal (SessionId);
if (!NT_SUCCESS(Status)) {
KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
return Status;
}
//
// Add the session space to the working set list.
//
// NO SESSION POOL CAN BE ALLOCATED UNTIL THIS COMPLETES.
//
Status = MiSessionInitializeWorkingSetList ();
.....
}
在MiSessionInitializeWorkingSetList 中
{
。。。。
InsertTailList (&MiSessionWsList, &SessionGlobal->WsListEntry);
InsertTailList (&MmWorkingSetExpansionHead.ListHead,
&SessionGlobal->Vm.WorkingSetExpansionLinks);
。。。。
}
===========================================
每一个进程创建,就会在session中添加引用计数,进程退回则反之,当session没有一个进程后(比如退出远程桌面),session自动被销毁。
进程自身退出时会用MmCleanProcessAddressSpace---》MiSessionRemoveProcess---》MiDereferenceSession减掉session的引用计数---》减到0就调用MiDereferenceSessionFinal清除session。
还有一种session引用计数的减少是进程发起NtSetSystemInformation(SystemSessionDetach)来脱离session。
===========================================
从2000开始,windows就有了多session的支持(远程桌面),但直到vista才开始有了session隔离
关于session隔离的概念
http://www.cnblogs.com/gnielee/archive/2010/04/07/session0-isolation-part1.html
http://www.cnblogs.com/gnielee/archive/2010/04/08/session0-isolation-part2.html
http://technet.microsoft.com/zh-cn/ee791007.aspx
http://wenku.baidu.com/view/9470b59951e79b8968022603.html
关于vista和win7的一些探索....
win7上出现了session对象(估计vista开始),逆向相关代码如下:
int __cdecl MiSessionObjectCreate()
{
......
status = ObCreateObject(0, MmSessionObjectType, &ObjectAttributes, 0, 0, 20, 0, 0, &Object);
ExFreePoolWithTag(buf_bak3, 0);
if ( status < 0 )
return status;
object_bak = Object;
object_bak2 = Object;
*(Object + 16) = session;//所以session对象的+0x10偏移是_MM_SESSION_SPACE
KeInitializeEvent(object_bak2, 0, 0);
result = ObInsertObjectEx(object_bak, &AccessState, 0, 1u, 0, 0, 0);
if ( result >= 0 )
{
session->u.LongFlags |= 0x40u;
_InterlockedExchangeAdd(&session->ProcessReferenceToSession, 1u);
session->SessionObjectHandle = AccessState;
session->SessionObject = object_bak;
session->IoState = 2;
session->IoStateSequence = 1;
KeInitializeEvent(&session->IoNotificationEvent, SynchronizationEvent, 1u);
result = v11;
}
......
}
kd> !object \\KernelObjects
Object: 86c05ad0 Type: (82dee820) Directory
ObjectHeader: 86c05ab8 (new version)
HandleCount: 0 PointerCount: 20
Directory Object: 86c010f8 Name: KernelObjects
Hash Address Type Name
---- ------- ---- ----
。。。。。。。
840ddda8 Session Session0
24 8490b4f0 Session Session1
两个session
kd> dd 840ddda8
840ddda8 83040000 00000000 840dddb0 840dddb0
840dddb8 86ee2000 00000000 0403000b 36616c41
840dddc8 848ab5b0 00000000 1bfe17dc 0a069f3f
840dddd8 04130003 7473444e 00880086 840ddde8
840ddde8 006e0049 00650074 0028006c 00290052
840dddf8 00500020 004f0052 0031002f 00300030
840dde08 00200030 0054004d 004e0020 00740065
840dde18 006f0077 006b0072 00430020 006e006f
kd> dd 8490b4f0
8490b4f0 00040000 00000000 8490b4f8 8490b4f8
8490b500 86f09000 850ff685 045d000b e5726854
8490b510 00000000 000002b8 00000048 81975c40
8490b520 00000002 00000001 00000000 00080008
8490b530 81975c40 86c05cf6 00000006 00000000
8490b540 8490b540 8490b540 00240b06 00000000
8490b550 00000000 00000000 057a8518 00000000
8490b560 86ebcfd0 86eba000 86ebcb08 00000000
猜测+0x8处是一个链表,具体链接什么暂时不清
由上面得知86ee2000和86f09000就是两个session的_MM_SESSION_SPACE
而这两个_MM_SESSION_SPACE同样是连接在MiSessionWsList里的
kd> dd MiSessionWsList
819883c8 86ee2070 86f09070 00000000 00000000
第一个_MM_SESSION_SPACE
kd> dd 86ee2070
86ee2070 86f09070 819883c8 00000000 00000000
第二个_MM_SESSION_SPACE
kd> dd 86f09070
86f09070 819883c8 86ee2070 00000000 00000000
这个不是,只起一个链接作用
kd> dd 819883c8
819883c8 86ee2070 86f09070 00000000 00000000
所以可以遍历\\KernelObjects目录来得到session对象,进一步得到每个session对象的_MM_SESSION_SPACE,然后利用_MM_SESSION_SPACE结构的ImageList可以得到一系列驱动的基地址,还是有一定参考价值的。另外,那份遍历SessionProcessLis检测进程的代码仍然可以用,只是每个session有独立的SessionProcessList。
关于session隔离的机制还没时间分析,待续。。。。。