13.跨进程读写内存

跨进程的本质是"进程挂靠”正常情况下, A进程的线程只能访问A进程的地址空间,如果A进程的线程想访问B进程的地址空间,就要修改当前的Cr3的值为B进程的页目录表基值(KPROCESS.DirectoryTableBase)。

即: mov cr3,B.DirectoryTableBase

跨进程操作

A进制中的线程代码:

mov cr3,B.DirectoryTableBase 		//切换Cr3的值为B进程
mov eax,dword ptr ds:[0x12345678] 	//将进程B Ox12345678的值存的eax中
mov dword ptr ds[0x00401234],eax 	//将数据存储到0x00401234中 
mov cr3,A.DirectoryTableBase		//切换回Cr3的值

//此时0x00401234中的数据还有吗?

//如何将数据传递给A进程的变量呢?

NtReadVirtualMemory流程解析:
13.跨进程读写内存_第1张图片

  1. 切换Cr3
  2. 将数据读复制到高2G
  3. 切换Cr3
  4. 从高2G复制到目标位置

NtWriteVirtualMemory流程解析:
13.跨进程读写内存_第2张图片

  1. 将数据从目标位置复制到2高2G地址
  2. 切换Cr3
  3. 从高2G复制到目标位置
  4. 切换Cr3

代码

3环

#include
int main() {
    char *ch = "Hello world";
    printf("%c,%x", ch, ch);
    getchar();
    printf("%c,%x", ch, ch);
    getchar();
}

0环

0#include 
VOID DriverUnload(PDRIVER_OBJECT pDriver);

// 根据PID返回进程EPROCESS,失败返回NULL
PEPROCESS LookupProcess(HANDLE hPid)
{
    PEPROCESS pEProcess = NULL;
    if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &pEProcess)))
        return pEProcess;

    return NULL;
}

VOID ChangeData(ULONG uId)
{
    KAPC_STATE ks;

    //1 根据ID获得进程内核对象
    PEPROCESS pEprocess = LookupProcess((HANDLE)uId);

    //2 挂靠到此进程上去
    //需要注意:不能挂靠之后,将内存中的数据往用户层地址存储,是不对的。
    //因为当挂靠到目标进程之后,用户层地址就是目标进程的了,也就存储到
    //目标进程中,而且目标进程的那个地址不一定有效,可能造成崩溃。
    KeStackAttachProcess(pEprocess,&ks);

    //3 修改内存
    char * p = (char *)0x1dfaf0;
    p[5] = 'h';
    p[6] = 'a';
    p[7] = 'h';
    p[8] = 'a';
    p[9] = '\0';
    //4 解除挂靠
    KeUnstackDetachProcess(&ks);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath)
{
    UNREFERENCED_PARAMETER(pPath);
    //DbgBreakPoint();

    ChangeData(1716);

    pDriver->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
    UNREFERENCED_PARAMETER(pDriver);
}

你可能感兴趣的:(进程与线程)