首页
社区
课程
招聘
[原创]记为何Attach到其他进程后不能用目标进程的句柄表
发表于: 2014-5-20 13:39 9031

[原创]记为何Attach到其他进程后不能用目标进程的句柄表

2014-5-20 13:39
9031
我在上个文章中提出了个问题:"为何Attach到其他进程后不能用目标进程的句柄表"
然后现在解决了
首先是原因:
"attached是是切换CR3,内存,不切换句柄表"
上面那行的答案来自:"wowocock"大神

然后问题出现了:
那么为什么不切换句柄表呢?
因为:系统获取句柄表,是直接查线程句柄表(ETHREAD.ThreadsProcess.ObjectTable)的,因为我们的线程句柄表是继承自进程的句柄表,所以没有什么问题
ETHREAD.ThreadsProcess是线程所属进程的EPROCESS
但是被attached的进程的句柄表(EPROCESS.ObjectTable)没有被我们的线程继承,所以表现出来是没有切换句柄表

那么为什么attached后进程句柄表没有继承到线程句柄表中呢

这个就要从Attach机制说起了
KeAttachProcess的实现在:
wrk\base\ntos\ke\procobj.c@226

attach的机制是将cr3等进行了切换.但是并不是真正的侵入其他进程.还是在自己的线程.但是进程空间变成别人的了

这时候.注意windows查句柄表时查的是是原本进程的句柄表(因为ETHREAD中的ThreadsProcess没有被修改)
所以虽然你用的是别人的进程领域.但是系统查的不是EPROCESS.ObjectTable.所以你attach了也不能直接用人家的句柄

说白了就是:attached时候没有修改ETHREAD.ThreadsProcess

不过我想了下..既然都拿到EPROCESS了.可以直接从ObjectTable里面查对应的对象,然后再通过obXX函数获取句柄

后记:
"attached的时候虽然没有修改ETHREAD.ThreadsProcess 但是修改了ETHREAD.ApcState.Process,而ObReferenceObjectByHandle使用的PsGetCurrentProcessByThread函数是获取ETHREAD.ApcState.Process.ObjectTable 所以可以通过ObReferenceObjectByHandle函数来获取句柄对象"

感谢看雪的sidyhe同学给提了个醒..
ZwDuplicateObject直接就可以跨进程复制...
用不着那么麻烦

看雪的kman同学的回复:

谁告诉你的attach process不会切换句柄表的,明明是attach process过去,就可以访问目标进程的句柄表了啊,wowocock这误人子弟呀。

为什么attach process后就能访问对方进程句柄表呢,这个说起来也简单, 因为使用句柄时通常是用ObReferenceObjectByHandle,也就是说句柄值得意义就体现在这里了,这个函数是怎么获取的当前进程句柄表呢:

HandleTable = PsGetCurrentProcessByThread(Thread)->ObjectTable;
而PsGetCurrentProcessByThread得实现:

#define PsGetCurrentProcessByThread(xCurrentThread) (ASSERT((xCurrentThread) == PsGetCurrentThread ()),CONTAINING_RECORD(((xCurrentThread)->Tcb.ApcState.Process),EPROCESS,Pcb))
也就是说他是从当前线程的tcb->ApcStateProcess取的进程(然后取该进程的句柄表),而

KeStackAttachProcess->KiAttachProcess则会执行:

Thread->ApcState.Process = Process;
通俗地解释一下, 也就是说attach 到目标进程后,当前线程使用的句柄表 就 是目标进程的,也就是说你可以直接使用目标的句柄

例如attach到目标进程后,使用对方的文件句柄read file

当然,由于当前attach时,没有进入rundown的锁中,当目标进程意外退出时,可能发生问题,所以带锁的ZwDuplicateObject是一个比较稳定的用法
但是ZwDuplicateObject也是存在一些弊端,例如,对于实现了OpenProcedure方法,且在方法中禁止打开的对象类型(例如ALPC Port对象、EtwRegistration对象),就无法进行duplicate,因为duplicate也会触发OpenProcedure和句柄增加,而attach就没这个问题。
对于vista以上的系统,可以使用
PsAcquireProcessExitSynchronization/PsReleaseProcessExitSynchronization组合来申请和释放process rundown,

这样就可以安心地attach进程并使用对方的句柄表了。

PS:所谓rundown锁.应该是指的EPROCESS.RundownProtect这个
在wrk的NtTerminateProcess中会有如下代码:

    if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
        ObDereferenceObject (Process);
        return STATUS_PROCESS_IS_TERMINATING;
    }
也就是说会获取该锁.如果获取失败则返回正在被TERMINAT
当把线程杀干净之后.会执行
ExReleaseRundownProtection (&Process->RundownProtect);
释放该锁.
这个的意义应该就在于获取该锁的时候不让Terminate他

看雪没有代码格式看着不舒服
可以来我小站看下

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (12)
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
直接用ZwDuplicateObject不行吗?
这个和RING3程序跨进程访问句柄是一个道理吧?
2014-5-20 17:14
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
直接dup是查的ETHREAD.ThreadsProcess.ObjectTable
而我们想dup的句柄是在EPROCESS.ObjectTable 所以你dup不出去
2014-5-20 17:19
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
4
NTSYSAPI
NTSTATUS
NTAPI
ZwDuplicateObject (
    __in HANDLE SourceProcessHandle,
    __in HANDLE SourceHandle,
    __in_opt HANDLE TargetProcessHandle,
    __out_opt PHANDLE TargetHandle,
    __in ACCESS_MASK DesiredAccess,
    __in ULONG HandleAttributes,
    __in ULONG Options
    );

虽然这个函数没倒出,但是它的作用不就是复制一个句柄出来吗?
可以跨进程使用,这样本进程就能通过此句柄来访问另一个进程的东西。
2014-5-20 17:23
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
5
继续观望。。。
2014-5-20 17:29
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
我没记错作用是从自己进程复制一个到别的进程吧...

虽然我没仔细看就是了

==============
抱歉我看了下 既然有SourceProcessHandle应该还真是复制到自己进程吧
2014-5-20 17:38
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
看了下MSDN
http://msdn.microsoft.com/en-us/library/ff566445(vs.85).aspx
这个函数确实可以跨进程复制句柄
感谢啦~!
2014-5-20 17:49
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
咦,这个函数还真导出了,一直没用过呢。
一般都是在RING3下用的。
2014-5-20 18:57
0
雪    币: 155
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
谁告诉你的attach process不会切换句柄表的,明明是attach process过去,就可以访问目标进程的句柄表了啊,wowocock这误人子弟呀。

为什么attach process后就能访问对方进程句柄表呢,这个说起来也简单, 因为使用句柄时通常是用ObReferenceObjectByHandle,也就是说句柄值得意义就体现在这里了,这个函数是怎么获取的当前进程句柄表呢:

       HandleTable = PsGetCurrentProcessByThread(Thread)->ObjectTable;

而PsGetCurrentProcessByThread得实现:

#define PsGetCurrentProcessByThread(xCurrentThread) (ASSERT((xCurrentThread) == PsGetCurrentThread ()),CONTAINING_RECORD(((xCurrentThread)->Tcb.ApcState.Process),EPROCESS,Pcb))

也就是说他是从当前线程的tcb->ApcStateProcess取的进程(然后取该进程的句柄表),而KeStackAttachProcess->KiAttachProcess则会修改Thread->ApcState.Process = Process;

通俗地解释一下, 也就是说attach 到目标进程后,当前线程使用的句柄表 就 是目标进程的,也就是说你可以直接使用目标的句柄

例如attach到目标进程后,使用对方的文件句柄read file

当然,由于当前attach时,没有进入rundown的锁中,当目标进程意外退出时,可能发生问题,所以带锁的ZwDuplicateObject是一个比较稳定的用法

但是ZwDuplicateObject也是存在一些弊端,例如,对于实现了OpenProcedure方法,且在方法中禁止打开的对象类型(例如ALPC Port对象、EtwRegistration对象),就无法进行duplicate,因为duplicate也会触发OpenProcedure和句柄增加,而attach就没这个问题。

对于vista以上的系统,可以使用PsAcquireProcessExitSynchronization/PsReleaseProcessExitSynchronization组合来申请和释放process rundown,这样就可以安心地attach进程并使用对方的句柄表了。
2014-5-20 19:35
0
雪    币: 2153
活跃值: (740)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
10
好像是这么回事,我也看了WRK,KeStackAttachProcess会保存上一个APC_STATE
理论上句柄表也会切换,脑子乱了乱了。。。。
2014-5-20 19:48
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
如果是这样的话..又有个问题:如何使用原本进程中的句柄呢?(ETHREAD.ThreadsProcess.ObjectTable)
2014-5-21 09:37
0
雪    币: 155
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
detach后就可以使用了啊。
2014-5-21 16:41
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
好吧....但是...好纠结...
2014-5-21 17:40
0
游客
登录 | 注册 方可回帖
返回
//