技术社区
安全培训
技术社群
积分商城
先知平台
漏洞库
历史记录
清空历史记录
相关的动态
相关的文章
相关的用户
相关的圈子
相关的话题
注册
登录
重写ring3 API函数
一天
渗透测试
269浏览 · 2025-03-20 04:52
返回文档
一、用户态
Zw*
或
Nt*
类型的API
1.1 系统调用介绍
本节涉及到系统调用的相关知识,在这里我只是浅浅地介绍一下什么是系统调用。
系统调用(System Call)是操作系统提供给应用程序与内核交互的核心接口,允许用户程序请求内核执行特权操作,它是用户态和内核态之间的桥梁。在免杀领域中,只要你是通过syscall指令进入内核态执行特权操作都可以称为系统调用。
在Windows操作系统中,假设我们使用了
ZwAllocateVirtualMemory
这个
Zw*
类型的API,它就会从用户态转变为内核态,在内核态由操作系统真正的执行特权操作。
ZwAllocateVirtualMemory是一个处于ring3到ring0的API,其本质而言还是ring3的API,但自身不执行内核特权操作。这类API有一个特点就是通过syscall这个指令进入到内核态,然后操作系统根据SSN(
系统调用号
)从SSDT(
系统服务描述表
),找到ntoskrnl.exe中对应的
Nt*
函数地址并执行特权操作。
这些函数的 ntdll(用户模式)版本只是执行系统调用来调用其内核模式对应函数,这就是为什么它们经常被称为
系统调用存根(syscall stub)
。
1.2 EDR和用户模式钩子
以前,安全产品通过挂钩 SSDT 从内核内部监控用户模式调用。自 2005 年微软推出内核补丁保护(又称 PatchGuard)以来,许多对内核的修改现在都被阻止了,因此许多 EDR 钩子转向挂钩 ntdll。
EDR 使用
jmp
指令覆盖
ntdll.dll
中目标函数(如
NtOpenProcess
)的前 5 字节,将执行流重定向到自身 DLL(每个进程都会加载)。在 EDR 的代码中检查参数(如目标进程 PID、内存地址合法性)及返回地址(是否来自可疑模块)。执行原始指令(被覆盖的 5 字节),跳转回
ntdll.dll
继续执行后续代码。
比如说未安装bitdefender前
安装bitdefender后
本节的
重写ring3 API函数
是利用直接系统调用绕过AV/EDR的在ntdll上的用户态钩子,达到免杀效果。说实话,国内主流的杀毒软件是没有用户态Hook,比如说360、火绒、Defender,甚至是国外的卡巴斯基(非EDR)在几年前就取消了用户态Hook,所以说对于这些AV而言用此项防御规避技术确实有点小题大作,只有面对EDR和AV中的王者BitDefender,此项技术才能大展身手。
直接系统调用也并非是万能的手段,如果恶意软件使用了这项技术,那么从 EDR的角度来看,这将成为一个明确的妥协指标(IOC),EDR可以通过Windows 事件跟踪(ETW)分析应用程序中的线程调用堆栈的合理性来判断程序是否为恶意软件。
偷来的图
为了规避EDR分析线程调用堆栈,使得调用栈看起来更合法,攻击方采取了间接系统调用,本节不会详细介绍,感兴趣的读者阅读,可以期待一下我的
系统调用
这一小节的知识点。
1.3 流程分析
ZwAllocateVirtualMemory的执行流程可以看下图
1
参数传递与寄存器准备
在 x64 系统调用约定中,前 4 个参数通过
rcx
,
rdx
,
r8
,
r9
传递。但
syscall
指令执行时会将返回地址覆盖
rcx
,因此需先将
rcx
的值保存到
r10
寄存器中
1
设置系统调用号SSN
不同版本的操作系统需要动态适配
1
检测系统调用方式
●
地址
7FFE0308h
:属于
KUSER_SHARED_DATA
结构,其最低位指示系统调用方式:
○
0
:使用
syscall
指令(现代 CPU)。
○
1
:使用
int 2Eh
中断(旧系统兼容模式)。
我们需要模仿
Zw*
类型的API的汇编写法,然后自己创建汇编文件,通过汇编指令完成上述操作,因为我们使用的是直接系统调用,所以第三步是不需要的。直接替换为下面的两天汇编指令即可
这类给出一个直接系统调用的模板
使用这个模块进行系统调用时,最大的难题就是如何找到相应API的SSN。最常见的办法就是通过IDA、Windbg、X32/64dbg查看汇编代码,还有其他的方法在这里我先不多少,在
系统调用
篇章中详细说明。
随便附加一个进程,然后去"符号"界面找到ntdll里面的导出函数
点击导出函数会跳转到相应的汇编代码的地址处,这样就可以看到系统调用号啦
二、环境配置
右键项目,点击“生成依赖性->生成自定义”
勾选masm,然后确定。
在项目中添加*.asm后缀的文件
对刚刚添加的asm文件,点击属性,然后将“项类型”中选择“自定义生成工具”,然后点确定。
再次右键asm文件属性, 配置属性“自定义生成工具->常规” :
1
在“命令行”中写入:
ml64 /c %(fileName).asm
2
在“输出”:
%(fileName).obj
,这样编译器就可以正常连接我们的文件了。
三、完整代码
需要用到的API和系统调用号如下
1
ZwCreateThreadEx:0xC7
2
ZwAllocateVirtualMemory:0x18
⚠注意:示例代码仅适用于Windows 11,其他系统需调整SSN。
asm代码如下
C++代码如下
这样重写ring3 API函数的任务就算完成了,剩下的免杀测试就看读者的自由发挥了。
说实话,单用本节的技术达到的免杀效果不怎么样,究其原因是
1
直接使用
syscall
可能被高级EDR标记为异常行为
2
函数调用栈异常,容易被检测
这些问题等到
系统调用
章节时会进行优化,并且更进一步的去探究如何动态获取系统调用号而不是硬编码在代码中。
参考资料
1
API函数的调用过程(三环到零环)以及重写WriteProcessMemory三环 - zpchcbd - 博客园
2
通过重写ring3 API函数实现免杀 | idiotc4t's blog
3
通过重写ring3 API函数规避动态查杀现在我们通过Process Monitor来观察一下Windows Api的调 - 掘金
4
Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数) - OneTrainee - 博客园
5
VS2017编写c/c++汇编函数并调用 - Avs阿鱼 - 博客园
6
绕过用户模式EDR Hook原理及思路
1
人收藏
1
人喜欢
转载
分享
0
条评论
某人
表情
可输入
255
字
评论
发布投稿
热门文章
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
近期热点
一周
月份
季度
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
暂无相关信息
暂无相关信息
优秀作者
1
T0daySeeker
贡献值:38700
2
一天
贡献值:24800
3
Yale
贡献值:21000
4
1674701160110592
贡献值:18000
5
1174735059082055
贡献值:16000
6
Loora1N
贡献值:13000
7
bkbqwq
贡献值:12800
8
手术刀
贡献值:11000
9
lufei
贡献值:11000
10
xsran
贡献值:10600
目录
一、用户态 Zw* 或 Nt* 类型的API
1.1 系统调用介绍
1.2 EDR和用户模式钩子
1.3 流程分析
二、环境配置
三、完整代码
参考资料
转载
标题
作者:
你好
http://www.a.com/asdsabdas
文章
转载
自
复制到剪贴板