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流程解析:
在這裏插入圖片描述

  1. 切換Cr3
  2. 將數據讀複製到高2G
  3. 切換Cr3
  4. 從高2G複製到目標位置

NtWriteVirtualMemory流程解析:
在這裏插入圖片描述

  1. 將數據從目標位置複製到2高2G地址
  2. 切換Cr3
  3. 從高2G複製到目標位置
  4. 切換Cr3

代碼

3環

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

0環

0#include <ntifs.h>
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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章