首页
论坛
课程
招聘
[原创]转行了,发个利用vt保护进程内存的解决方案+读写任意内存。只针对BE/EAC
2020-9-3 10:56 4939

[原创]转行了,发个利用vt保护进程内存的解决方案+读写任意内存。只针对BE/EAC

2020-9-3 10:56
4939

这个方法的出现,还是大表哥几年前在别的论坛上发的一张图,利用VT使自身内存读出来是别的进程的效果。又或者是让自己去读一个随意的进程读出来的却是别的进程的效果,从而一次性的解决了保护内存和读写的问题,到我发出来的今天,这个方法还是处于未被检测的状态。

因为他没透露具体细节,所以不清楚代码或者原理是不是一样的。当时研究的时候对驱动还是小白,代码的写法又或者是蓝屏问题上的考虑是很欠缺的,(代码很丑,蓝屏率很高,而且不支持有声卡的电脑,到今天也不清楚原因。不过如果电脑是新装的系统,就原版的那种,蓝屏率还是很低的。

基本框架使用的HyperPlatform,真好用。

原理:

cr3切换时,判断上下文来选择是否给正确的cr3。

cr3切换时的代码:

        // CR3 <- Reg
        case 3: {
          HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE();
		  ULONG_PTR guestCr3 = 0;
		  ULONG_PTR writeCr3 = 0;
		  guestCr3 = UtilVmRead(VmcsField::kGuestCr3);
          if (UtilIsX86Pae()) {
            UtilLoadPdptes(*register_used);
          }
          UtilInvvpidSingleContextExceptGlobal(
              static_cast<USHORT>(KeGetCurrentProcessorNumberEx(nullptr) + 1));
          UtilVmWrite(VmcsField::kGuestCr3, (*register_used & ~(1ULL << 63)));
		  writeCr3 = UtilVmRead(VmcsField::kGuestCr3);
		  AutoK(guest_context, guestCr3, *register_used);
		  AutoKA(guest_context, guestCr3, *register_used);
		  //FuckRead(guest_context, *register_used, guestCr3);
		  if(!FuckRead(guest_context, *register_used, guestCr3))
		  FuckCr3(guest_context, *register_used, guestCr3);
          break;
        }

要用到判断的上下文其实就是kiattachprocess/kistackattachprocess,这个利用驱动附加自身/r3层读写别的内存,很容易就可以自动得到这两个函数的特征,AutoK/AutoKA就是干这个事情的。

读写:

原理很简单,就是驱动和r3约定一个读或者写的对象进程,例如QQ或者任意你能打开的进程,然后再约定一个真正要被读写的进程,这样就可以达到r3直接readprocessmemory读写进程就可以达到操作内存的效果。

有一个坑就是,对于BE的游戏需要读和写的对象进程分开来,不然会导致封禁,这个检测就很有意思。

bool FuckRead(GuestContext *guest_context, ULONG_PTR 切, ULONG_PTR NowCr3) {
	VMProtectBegin("Fkr");
	bool bRet = false;
	if (!tz_KAPrcess)return bRet;
	if (切 != FakeReadCr3&&切 != FakeWriteCr3)return bRet;
	PULONG64 Urip = 0;
	Urip = (PULONG64)UtilVmRead(VmcsField::kGuestRip);
	if (*Urip == tz_KAPrcess || *Urip == tz_KSAPrcess) {
#pragma region GuestReg
		ULONG_PTR Rbx = 0;
		ULONG_PTR ownPid = 0;
		ULONG_PTR ApcEPRO = 0;  //PEPROCESS
		ULONG_PTR ApcStr = 0;
		ULONG_PTR Et_ApcStr = Et_ApcEproc - 0x20;
		Rbx = (ULONG_PTR)KeGetCurrentThread();
		ownPid = *(PULONG64)(Rbx + Et_OwnPid);
		ApcEPRO = *(PULONG64)(Rbx + Et_ApcEproc);
		ApcStr = *(PULONG64)(Rbx + Et_ApcStr);
#pragma endregion Trace
#pragma region ReadGameOrWriteGame
		if (ownPid == MyEXEpid && (ApcEPRO == (ULONG_PTR)FakeReadEproc || ApcEPRO == (ULONG_PTR)FakeWriteEproc))
		{
			if (readCr3) {
				UtilVmWrite(VmcsField::kGuestCr3, readCr3);
				PRKAPC_STATE a;
				a = (PRKAPC_STATE)ApcStr;
				const auto vmm_cr3 = __readcr3();
				__writecr3(NowCr3);																					//还原环境
				KeUnstackDetachProcess(a);
				KeStackAttachProcess(readEproc, a);
				__writecr3(vmm_cr3);																				//还原VMM环境
				bRet = true;
				return bRet;
			}
		}
#pragma endregion ReadGameEnd
		return bRet;
	}
	VMProtectEnd();
	return bRet;
}

保护进程:

原理和读写差不多,只是将我读别人,换成了别人读我。

这个在EAC上也有个坑,EAC在r0扫内存的时候会判断当前附加进程,如果发现被掉包了会重启你,经典的10分钟检测。解决方法就是...

bool FuckCr3(GuestContext *guest_context, ULONG_PTR 切, ULONG_PTR NowCr3) {
	VMProtectBegin("FuckCr3");
	bool bRet = false;
	bool IsNeedFuck = false;
	IsNeedFuck = false;
	if (!b_wecan)return bRet;
	if (!tz_KAPrcess)return bRet;
	if (切 == trace_cr3_arr[0])IsNeedFuck = true;
	if (!IsNeedFuck)return bRet;
	PULONG64 Urip = 0;
	Urip = (PULONG64)UtilVmRead(VmcsField::kGuestRip);
	if (*Urip == tz_KAPrcess || *Urip == tz_KSAPrcess) {
#pragma region GuestReg
		ULONG_PTR Rbx = 0;
		ULONG_PTR ownPid = 0;
		ULONG_PTR ApcEPRO = 0;  //PEPROCESS
		ULONG_PTR ApcStr = 0;
		ULONG_PTR Et_ApcStr = Et_ApcEproc - 0x20;
		Rbx = (ULONG_PTR)KeGetCurrentThread();
		ownPid = *(PULONG64)(Rbx + Et_OwnPid);
		ApcEPRO = *(PULONG64)(Rbx + Et_ApcEproc);
		ApcStr = *(PULONG64)(Rbx + Et_ApcStr);
#pragma endregion Trace
#pragma region CheckPro
		IsNeedFuck = false;
		for (size_t i = 0; i < i_uAntiarrIndex; i++) {
			if (ownPid == u_WhitePid[i]) {
				IsNeedFuck = true;
				break;
			}
		}
		if (IsNeedFuck || ownPid == 4)return bRet;
		IsNeedFuck = false;
		if (ApcEPRO == trace_Eproc_arr[0]) {
			IsNeedFuck = true;
		}
		if (!IsNeedFuck) return bRet;
#pragma endregion CheckProEnd
		if (CsrssCr3 == NowCr3)return bRet;
#pragma region FuckCr3
		UtilVmWrite(VmcsField::kGuestCr3, CsrssCr3);
		KAPC_STATE Apcp;
		PRKAPC_STATE a;
		a = (PRKAPC_STATE)ApcStr;
		const auto vmm_cr3 = __readcr3();
		__writecr3(NowCr3);
		KeUnstackDetachProcess(a);
		KeStackAttachProcess(FakeEproc, a);
		__writecr3(vmm_cr3);
#pragma endregion FuckCr3End
	}
	VMProtectEnd();
	return bRet;
}


结尾:

这玩意儿能商业化,靠的就是给代理洗脑和稳定,而且就算是这个方法去实现这个效果,也一定也有兼容性更好的方案。


[培训]12月3日2020京麒网络安全大会《物联网安全攻防实战》训练营,正在火热报名中!地点:北京 · 新云南皇冠假日酒店

最后于 2020-9-3 10:58 被萌克力编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (20)
雪    币: 6121
活跃值: 活跃值 (279)
能力值: ( LV5,RANK:68 )
在线值:
发帖
回帖
粉丝
万剑归宗 活跃值 1 2020-9-3 11:25
2
0
我改我自己,貌似并不需要VT
雪    币: 3832
活跃值: 活跃值 (553)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
不对 活跃值 2020-9-3 11:48
3
0
万剑归宗 我改我自己,貌似并不需要VT
可能是怕别人扫描PTE表,然后露馅了吧?更何况,退一步讲,VT还能占个坑啥的
雪    币: 9209
活跃值: 活跃值 (1656)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
hzqst 活跃值 3 2020-9-3 11:59
4
0
HyperPlatform 这玩意在双CPU系统上分分钟PatchGuard炸裂,想拿这个商用化的多多少少沾点
雪    币: 11
活跃值: 活跃值 (146)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huojier 活跃值 2020-9-3 12:29
5
1
不懂就问 这样保护有什么用呢.... 系统回调依然可以得到正确的CR3
雪    币: 46
活跃值: 活跃值 (154)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
靴子 活跃值 2020-9-3 12:35
6
0
雪    币: 1
活跃值: 活跃值 (105)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lookzo 活跃值 2020-9-3 13:07
7
0
终于想通了,哈哈
雪    币: 4295
活跃值: 活跃值 (1359)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-9-3 13:52
8
0
hzqst HyperPlatform 这玩意在双CPU系统上分分钟PatchGuard炸裂,想拿这个商用化的多多少少沾点
请教一下,他这种读写其实就是为了ring3下readprocessmemory不打开目标进程的句柄吧?还有这部分保护进程也是在切换cr3时发生的,如果直接读物理地址岂不是无效了?
雪    币: 424
活跃值: 活跃值 (557)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
萌克力 活跃值 2020-9-3 14:34
9
0

   1

最后于 2020-9-3 14:35 被萌克力编辑 ,原因:
雪    币: 424
活跃值: 活跃值 (557)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
萌克力 活跃值 2020-9-3 14:36
10
0
hhkqqs 请教一下,他这种读写其实就是为了ring3下readprocessmemory不打开目标进程的句柄吧?还有这部分保护进程也是在切换cr3时发生的,如果直接读物理地址岂不是无效了?
是的,所以我也只是说了在帖子发出来的时候,针对BE/EAC,他们的内存检测是无效的
雪    币: 424
活跃值: 活跃值 (557)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
萌克力 活跃值 2020-9-3 14:38
11
0
huojier 不懂就问 这样保护有什么用呢.... 系统回调依然可以得到正确的CR3

仅针对目前的BE/EAC,而且,也并不是保护cr3不被拿到

最后于 2020-9-3 14:39 被萌克力编辑 ,原因:
雪    币: 188
活跃值: 活跃值 (110)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wujimaa 活跃值 1 2020-9-3 14:39
12
0
转行做那方面?
雪    币: 2587
活跃值: 活跃值 (407)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
淡然他徒弟 活跃值 2020-9-5 04:58
13
0
大表哥 永远滴神 
雪    币: 55
活跃值: 活跃值 (209)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
killpy 活跃值 2 2020-9-5 13:38
14
0
be r0是怎么检测的 他怎么知道当前附加的进程是哪个
雪    币: 55
活跃值: 活跃值 (209)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
killpy 活跃值 2 2020-9-5 14:03
15
0
看了一下 就是 附加进程读写的时候 判断 如果附加的是跳板进程 那就给他真实cr3 退出附加 再次附加进真实进程eprocess  完后返回 让r3通过附加跳板进程eprocess达到读写真实进程内存的目的  如果被附加的进程是我们要保护的进程 那就写入csrss的cr3 再unattach一下 再次attach进跳板eprocess 完后导致对方读写的是csrss的内存 以为你有代码 连代码都不分享啊
雪    币: 424
活跃值: 活跃值 (557)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
萌克力 活跃值 2020-9-5 15:17
16
0
killpy 看了一下 就是 附加进程读写的时候 判断 如果附加的是跳板进程 那就给他真实cr3 退出附加 再次附加进真实进程eprocess 完后返回 让r3通过附加跳板进程eprocess达到读写真实进程内存 ...
我分享的就是代码啊
雪    币: 424
活跃值: 活跃值 (557)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
萌克力 活跃值 2020-9-5 15:18
17
0
killpy be r0是怎么检测的 他怎么知道当前附加的进程是哪个
是eac会检测当前附加对象,估计也就是attach之后_readcr3一下
雪    币: 42
活跃值: 活跃值 (137)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cheating 活跃值 2020-9-13 17:16
18
0
这玩意就是自己读自己,比如说,my.exe在r3去读game.exe,在内核层需要KeStackAttachProcess、KeUnstackDetachProcess,当__writecr3(cr3)的时候,直接在vmm_exit_dr3里面KeUnstackDetachProcess还原环境之后,再次附加KeStackAttachProcess,不过KeStackAttachProcess第一个参数是game.exe的peprocess地址,这样就是自己读自己。 其他的话不想让驱动保护读自己的话,也是类似,你想读my.exe,我给你读csrss.exe。差不多是这个意思吧。
雪    币: 42
活跃值: 活跃值 (137)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cheating 活跃值 2020-9-14 18:40
19
0
好像理解错了。
雪    币: 156
活跃值: 活跃值 (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
橙子· 活跃值 2020-11-21 22:38
20
0
雪    币: 403
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_foyotena 活跃值 2020-11-21 22:49
21
0
都是那方面的高手,怎么检测呢
游客
登录 | 注册 方可回帖
返回