windows:跨进程读数据
外挂、木马、病毒等可能需要读取其他进程的数据,windows提供了OpenProcess、ReadProcessMemory等函数。但越是大型的软件,防护做的越好,大概率会做驱动保护,比如hook SSDT表等,这些系统调用都会先被过滤一次,导致返回的数据不是想要的;为了确保能读到目标进程数据,最好重写ReadProcessMemory;要想读取其他进程的内容,思路大概有一下几种:
- 注册PsSetLoadImageNotifyRoutine函数,其他进程加载模块会时调用我们注册的函数,这个时候已经进入目标进程的空间,可用memcpy复制数据
- KeStackAttachProcess可以切换到目标进程,然后用memcpy复制数据,最后调用KeUnstackDetachProcess切换回来
- 利用进程ID查找EPROCESS,根据名称得到目标EPROCESS后再读取CR3,最用利用目标进程的CR3读取其内存数据;
前两种方式要调用大家熟知的函数,目的性比较明显,这些函数肯定会被大厂家重点关注,返回的结果可能在逻辑上有误;而第三种方式仅仅根据ID查询EPROCESS,相对前两种更加“人畜无害”,被拦截的概率要小很多,今天详细介绍第三种方式。
1、为了验证读取数据是否正确,先在notepad随便写一些内容,然后用CE查看地址,如下,后续就选这个地址来测试了;

这里多说几句:CE为了防止被针对,自己重写了关键的内存扫描/读写、进程打开函数,并未使用windows原生自带的系统调用函数;

2、遍历进程,根据ID查找EPROCESS,进而得到进程名、CR3等关键信息,这块也比较简单,如下:
PEPROCESS LookupProcess(HANDLE Pid)
{
PEPROCESS eprocess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
Status = PsLookupProcessByProcessId(Pid, &eprocess);
if (NT_SUCCESS(Status))
return eprocess;
return NULL;
}
因不同版本EPROCESS结构体可能有细微区别,保险起见最好在windbg下通过dt _EPROCESS查看一下CR3的偏移,我这里是0x28,那么CR3的获取代码:
ULONG64 target_CR3 = *(PULONG64)((ULONG64)eproc + 0x28);
3、目标CR3都拿到了,接下来就可以读进程数据了,这里的环境是win10 x64,默认开启了PAE;最初的想法很简单,系统用的是9-9-9-9-12分页,那么先把虚拟地址拆分,再用CR3一步一步跟踪不就得到物理地址了吗? 物理地址都有了,再读取数据岂不是探囊取物般简单了么?
所以刚开始的代码是这样的:(1)先拆分虚拟地址,得到各个层级的偏移 (2)再仿造windbg种逐步计算的方式一步一步得到物理地址; (3)这里有点要注意:& 和移位的优先级较低,注意使用括号,避免计算的逻辑错误;
ULONG64 PML4E_index = (virtualAddress >> ) & 0x1ff;
ULONG64 PDPE_index = (virtualAddress >> ) & 0x1ff;
ULONG64 PDE_index = (virtualAddress >> ) & 0x1ff;
ULONG64 PTE_index = (virtualAddress >> ) & 0x1ff;
ULONG64 physical_offset = virtualAddress & 0xfff;
ULONG64 PML4E = CR3 + (PML4E_index << );
ULONG64 PDPE = (*(PULONG64)PML4E & 0x00000007fffff000) + (PDPE_index << );//上一级table entry的12~35位提供下一级table物理基地址的高24位,此时36~51是保留位,必须置0,低12位补零
ULONG64 PDE = (*(PULONG64)PDPE & 0x00000007fffff000) + (PDE_index << );
ULONG64 PTE = (*(PULONG64)PDE & 0x00000007fffff000) + (PTE_index << );
ULONG64 physicalAddress = (*(PULONG64)PTE & 0x00000007fffff000) + physical_offset;
然而一运行就蓝屏,通过下断点逐步跟踪,发现罪魁祸首在这行:ULONG64 PDPE = (*(PULONG64)PML4E & 0x00000007fffff000) + (PDPE_index << 3)
这样代码做的运算有好几个,为了彻查到底是哪个运算导致的蓝屏,继续把代码拆分地更细,最终发现导致蓝屏的真凶:*(PULONG64)PML4E;
这行代码本身很简单,就是把PML4E转换成指针,再读取其指向的内容,这么简单的操作,为啥会导致蓝屏了?这就牵扯到win10 x64下用户态CR3和内核态CR3的区别了;本案例用的是驱动,在0环内核态执行,自然用的是内核态CR3。但代码读取数据的虚拟地址明显是3环的,属于用户态。不同的CR3会映射到不同的物理地址,最终出错。问题找到了,怎么解决了?既然是CR3不对,那么读取内存之前先切换一下不就行了?
由于vs2019对于x64的程序不允许内联汇编,这里单独新建一个asm文件来切换CR3,如下:
_swapCR3 PROC
mov cr3,rcx;
ret
_swapCR3 Endp
然后继续单步调试,切换CR3的函数执行完后,CR3成功更改:

但是在执行*(PULONG64)PML4E前查看时CR3又变回了内核态CR3:

继续执行不出意外又蓝屏:

为什么函数 _swapCR3 执行完后,CR3又变回了内核态?经过多次反复尝试,发现都是断点惹的祸:代码里面设置了断点,执行到断点时会被系统进程接管,然后CR3自然就切换;
既然ret后CR3又被改回,那么只能在汇编代码里面读取虚拟地址的内容了,这次重新写一个_ReadVirtualMemory代码,如下(这里直接使用mov rax,[rdx],还省去了繁琐的地址转换,这部分直接让cpu自动做了):
_ReadVirtualMemory PROC
push rax;
push rbx;
mov rbx,cr3;保存旧的CR3
mov cr3,rcx;
mov rax,[rdx];第二个参数,是VirtualMemory
mov data,rax
mov cr3,rbx;还原旧的CR3
pop rbx;
pop rax;
ret
_ReadVirtualMemory Endp
在这里读的数据终于对了,效果如下:0x7ffd350ca309 地址前2个字节的内容确实是CC,和通过CE查找到的一致;

完整代码如下:主文件
#include "ReadProcessMemory.h" ULONG64 data; // 根据进程ID返回进程EPROCESS结构体,失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{
PEPROCESS eprocess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
Status = PsLookupProcessByProcessId(Pid, &eprocess);
if (NT_SUCCESS(Status))
return eprocess;
return NULL;
} VOID EnumProcess()
{
PEPROCESS eproc = NULL;
for (int temp = ; temp < ; temp += )
{
eproc = LookupProcess((HANDLE)temp);
if (eproc != NULL )
{
if (!strcmp(PsGetProcessImageFileName(eproc),"notepad.exe"))
{
DbgPrint("进程名: %s --> 进程PID = %d --> 父进程PPID = %d -->EPROCESS地址:%p \r\n", PsGetProcessImageFileName(eproc), PsGetProcessId(eproc),
PsGetProcessInheritedFromUniqueProcessId(eproc), eproc);
ULONG64 target_CR3 = *(PULONG64)((ULONG64)eproc + 0x28);
KdBreakPoint();
_ReadVirtualMemory(target_CR3, 0x7ffd350ca309);
DbgPrint("存储内容:%c \r\n", data);
ObDereferenceObject(eproc);
return;
} }
}
} VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("Uninstall Driver Is OK \n"));
} NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
EnumProcess();
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
头文件:
#ifndef READPROCESSMEMORY_
#define READPROCESSMEMORY_ #include <ntifs.h> NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); //未公开的进行导出即可
NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);//未公开进行导出 extern void Dbg_Break();
extern void _swapCR3(ULONG64 target_CR3);
extern void _ReadVirtualMemory(ULONG64 target_CR3, ULONG64 VirtualMemory); extern ULONG64 data; #endif
asm文件:这里切换CR3的时候为了保险起见,建议先保存旧CR3,用完了再切回去;
EXTERN data:qword .code Dbg_Break Proc
int
ret
Dbg_Break Endp _swapCR3 PROC
mov cr3,rcx;
ret
_swapCR3 Endp _ReadVirtualMemory PROC
push rax;
push rbx;
mov rbx,cr3;保存旧的CR3
mov cr3,rcx;
mov rax,[rdx];第二个参数,是VirtualMemory
mov data,rax
mov cr3,rbx;还原旧的CR3
pop rbx;
pop rax;
ret
_ReadVirtualMemory Endp END
最后注意: VS2019在x64的默认调用约定是_stdcall,不是_fastcall,建议改成_fastcall;

windows:跨进程读数据的更多相关文章
- Windows跨进程设置文本和发送消息
进程内设置文本,可以调用SetWindowText,跨进程这个会无效,应当如下:::SendMessage(hWnd, WM_SETTEXT, NULL, (LPARAM)文本内容); 注意这里不能使 ...
- 使用WM_COPYDATA跨进程发送数据
进程之间通讯的几种方法: 在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.常用的方法有 使用内存映射文件 通过共享内存DLL共享内存 使用SendMessage向另一进程发送WM_ ...
- 基于xposed实现android注册系统服务,解决跨进程共享数据问题
昨花了点时间,参考github issues 总算实现了基于xposed的系统服务注入,本文目的是为了“解决应用之间hook后数据共享,任意app ServiceManager.getService就 ...
- ContentProvider跨进程共享数据
借用ContentResolver类访问ContentProvider中共享的数据.通过getContentResolver()方法获得该类的实例. ContentResolver中的方法:inser ...
- Android AIDL Service 跨进程传递复杂数据
黑夜 黑夜给了我黑色的眼睛,我却用它寻找光明~ 传值方式 AIDL是同意跨进程传递值的,一般来说有三种方式: - 广播:这样的算是比較常见的一种方式了,传递小数据不错 - 文件:这个是保存到文件里.然 ...
- android 史上最简单易懂的跨进程通讯(Messenger)!
不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件! 只需要简单易懂的Messenger,它也称为信使,通过它可以在不同进程中传递m ...
- Android跨进程通信的四种方式
由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...
- Android 跨进程数据共享
Android 开发过程中,基于功能隔离.进程安全.进程保活等等考虑,我们经常需要为应用划分进程,然后不得不面临跨进程通信和跨进程共享数据的挑战. 跨进程通信 相对来说,跨进程通信比较简单,常用的方式 ...
- Android为TV端助力 史上最简单易懂的跨进程通讯(Messenger)!
不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件! 只需要简单易懂的Messenger,它也称为信使,通过它可以在不同进程中传递m ...
随机推荐
- MySQL索引 索引分类 最左前缀原则 覆盖索引 索引下推 联合索引顺序
MySQL索引 索引分类 最左前缀原则 覆盖索引 索引下推 联合索引顺序 What's Index ? 索引就是帮助RDBMS高效获取数据的数据结构. 索引可以让我们避免一行一行进行全表扫描.它的 ...
- 「HAOI2015树上染色」「树形DP」
其实我还不大会树形DP 此题就当练手叭,缕一下思路就好 题目链接 BZOJ4033 题目大意就是给一棵树,对一部分点染成黑色,剩下的为白色,问所有同色点距离之和....... 简明扼要的题意,然额我不 ...
- JavaScript图形实例:H分形
H分形是由一个字母H演化出迷宫一样场景的分形图案,其构造过程是:取一个中心点(x,y),以此中心点绘制一条长为L的水平直线和两条长为H的竖直直线,构成一个字母“H”的形状:再以两条竖直直线的上下共4个 ...
- day26 作业(ATM第二版)
目录 start.py conf.settings.py core.src.py db.db_handler.py interface.bank_interface.py interface.shop ...
- 微信小程序中的深拷贝与浅拷贝问题
最近在弄小程序项目的时候遇到了一个json对象复制的问题,也就是俗称的深拷贝与浅拷贝了. 一般用变量直接接收就是浅拷贝,那么如何理解浅拷贝与深拷贝的意义呢? 浅拷贝:只是将对象地址的复制,并没有开辟新 ...
- 一篇夯实一个知识点系列--python装饰器
写在前面 本系列目的:希望可以通过一篇文章,不望鞭辟入里,但求在工程应用中得心应手. 装饰器模式是鼎鼎大名的23种设计模式之一.装饰器模式可以在不改变原有代码结构的情况下,扩展代码功能. Python ...
- Hadoop基础(一):概论
1.大数据概念 2 大数据特点(4V) 图2-2 大数据特点之大量 图2-3 大数据特点之高速 图2-4 大数据特点之多样 图2-5 大数据特点之低价值密度 3 大数据部门业务流程分析 4 大数据部门 ...
- electron代码审计
解包 Electron跨平台程序破解https://www.52pojie.cn/thread-563895-1-1.html Electron封装的跨平台程序破解的一般思路: 安装npm(至于如何安 ...
- Java常用API(Arrays类)
Java常用API(Arrays类) 什么是Arrays类? java.util.Arrays 此类包含用来操作数组的各种方法,比如排序和搜索等.其所有方法均为静态方法,调用起来 非常简单. 这里我们 ...
- T133305 57级返校测试重测-T1-数字配对
大致题意: 给定偶数个的数字,操作使得两两配对后的最大值最小. 基本思路: 先排序,然后设i=1,j=n(序列以下标1开始), 每次配对为a[i]+a[j],然后++i,--j. 最后找到最大的配对结 ...