我在上个文章中提出了个问题:"
为何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他
看雪没有代码格式看着不舒服
可以来
我小站看下
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!