11 进程挂靠

1、进程跟线程之间的关系
mov eax,dword ptr ds:[0x12345678]
CPU如何解析0x12345678这个线性地址呢?
<1>CPU解析线性地址时要通过页目录表来找对应的物理页,页目录表基址存在Cr3中
<2>当前Cr3的值来源与当前进程(_KPROCESS+0x018 DirectoryTableBase : [2] Uint4B)

2、线程与进程如何关联
ETHREAD结构体
+0x220 ThreadsProcess : Ptr32 _EPROCESS
以上属性存储了该线程属于哪个进程
在KTHREAD有个子结构体_KAPC_STATE
kd> dt _KAPC_STATE
ntdll!_KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY
+0x010 Process : Ptr32 _KPROCESS
+0x014 KernelApcInProgress : UChar
+0x015 KernelApcPending : UChar
+0x016 UserApcPending : UChar
以上也存储了当前线程所属进程

3、养父母负责提供Cr3
线程切换时,会比较_KTHREAD结构体0x44指定的EPROCESS是否为同一个,如果不是同一个,会将0x44指定的EPROCESS结构体中DirectoryTableBase取出来赋值给Cr3
所以,线程需要的Cr3的值0x44处的EPROCESS
此处从SwapContext中得知的
cmp eax, [esi+44h]
总结:
0x220亲生父母:这个线程谁创建的
0x44养父母:谁在为这个线程提供资源(也就是提供Cr3)
一般情况下,0x220和0x44指向的是同一个进程

4、Cr3的值可以随便改吗
通常情况下,Cr3的值是由养父母提供的,但Cr3的值也可以改成和当前线程毫不相关的其他进程的DirectoryTableBase
mov Cr3,A.DirectoryTableBase
mov eax,dword ptr ds:[0x12345678] //A进程里的0x12345678
mov Cr3,B.DirectoryTableBase
mov eax,dword ptr ds:[0x12345678] //B进程里的0x12345678
mov Cr3,C.DirectoryTableBase
mov eax,dword ptr ds:[0x12345678] //C进程里的0x12345678
当Cr3的值改成其他进程的值,称为进程挂靠
进程挂靠的目的是为了当前的进程能够访问其他进程里的内存空间

5、分析NtReadVirtualMemory()函数
NtReadVirtualMemory–>KiAttachProcess–>修改养父母–>修改Cr3
可不可以只修改Cr3不修改养父母?不可以,如果不修改养父母的值,如果发生线程切换,就会变成自己读自己
如果我们自己写代码,在切换Cr3后关闭中断,并且不调用会导致线程切换的API,就可以不用修改养父母。

6、总结:
正常情况下当前线程使用的Cr3是由所属进程提供的(ETHREAD 0X44偏移处指定的EPROCESS),正因为如此,A进程的线程只能访问A的内存
如果要让A进程中的线程能够访问B进程的内存,就必须修改Cr3的值为B进程的页目录表基址(B.DirectoryTableBase),这就是所谓的进程挂靠

猜你喜欢

转载自blog.csdn.net/lifeshave/article/details/87448762
11