2024年3月29日发(作者:)

跨进程内存空间的读写

通常,跨进程读写内存,用到ReadProcessMemory, WriteProcessMemory, 但需要进程句柄,

如果目标进程受到保护,可能获得进程句柄会失败.不同的进程的虚拟地址被映射到了物理内

存中不同的页面.每个进程的虚拟地址的范围是相同的,但是实际的映射却是物理内存内中的

不同部分.假如我们直接读取目标进程的虚拟地址映射的物理地址,是否可以达到预期的要求.

当然这是肯定的,!

首先要获得目标进程的cr3寄存器,即页目录基地址(开启PAE, 页目录指针表),

每个进程在内核里都有一个EPROCESS结构.

nt!_EPROCESS

+0x000 Pcb : _KPROCESS

+0x06c ProcessLock : _EX_PUSH_LOCK

+0x070 CreateTime : _LARGE_INTEGER

+0x078 ExitTime : _LARGE_INTEGER

+0x080 RundownProtect : _EX_RUNDOWN_REF

…….

Pcb中就有我们想要得到的CR3

nt!_KPROCESS

+0x000 Header : _DISPATCHER_HEADER

+0x010 ProfileListHead : _LIST_ENTRY

+0x018 DirectoryTableBase : [2] Uint4B

+0x020 LdtDescriptor : _KGDTENTRY

+0x028 Int21Descriptor : _KIDTENTRY

………

那只需要获得目标进程EPROCESS就可以得到CR3了

假定目标进程就是当前进程, 可以遍历EPROCESS里的ActiveProcessLinks 的链表获取指

定进程的EPROCESS

// 获得EPROCESS信息

ULONG uEprocess = 0;

__asm

{

mov eax, fs:[0x124] // _ethread

mov eax, [eax+0x44] // _kprocess

mov uEprocess, eax

}

nt!_ETHREAD

+0x000 Tcb : _KTHREAD

…..

nt!_KTHREAD

+0x000 Header : _DISPATCHER_HEADER

……

+0x034 ApcState : _KAPC_STATE

nt!_KAPC_STATE

+0x000 ApcListHead : [2] _LIST_ENTRY

+0x010 Process : Ptr32 _KPROCESS 这就是我们需要的ERPOCESS了

……

获得了CR3,,接下来,就是根据分页机制,把虚拟地址转换为物理地址勒.

在转换之前要判断是否开启PAE,非PAE和开启PAE的转换有所不同

控制寄存器CR4的第5位标记是否开启PAE

// 获得CR4的值

__asm

{

_emit 0x0F

_emit 0x20

_emit 0xE0

mov uCR4, eax

}

未开启PAE情况

通过CR3寄存器定位到页目录的基地址

线性地址的高10位作为获取页目录表项的索引, 获得一个页目录的一个表项

注: windows的保护实现基本不使用分段机制,主要是通过分页机制来实现保护,这里的就

线性地址等于虚拟地址,这是我的一点理解,可能有误,!

// 获得页目录表项(PDE)

dwPageDirIndex = (dwVirtualAddr & 0xffc00000) >> 22;

DWORD dwPageDirEntry = ReadPageDirEntryNoPAE(dwPageDirIndex);

if (dwPageDirEntry == 0)

{

return;

}

根据PDE获得页表基地址或者页基地址

当没有开启PAE时,有两种PDE格式, 分别指向4KB的页表,和4MB的内存页