免杀基础入门篇
本文首发于先知社区,原文链接:https://xz.aliyun.com/t/10369
0x00 前言
浅析杀软原理及一些绕过思路,也是我自己学习的一点笔记和思路。
杀软原理:
0x01 静态查杀:
1.特征码识别:
杀软有自己的病毒库,里面有很多样本,扫描时会抽取扫描对象的一段特征并与病毒库里作比较,如果匹配,那就会认为是病毒。抽取的代码要有适当长度,一方面维持特征代码的唯一性,另一方面又不要有太大的空间与时间的开销。如果一种病毒的特征代码增长一字节,要检测3000种病毒,增加的空间就是3000字节。在保持唯一性的前提下,尽量使特征代码长度短些,以减少空间与时间开销。
主要扫描的有:
hash、文件名、函数名、敏感字符串、敏感api等等
2.云查杀:
云查杀的不同点在于它的病毒库是放在服务器端的,而不是本地客户端,意思是只要联网病毒库就会同步更新,这种病毒库更加强大。
3.校验和法
根据正常文件的内容,计算其校验和,定期不定期的检查文件的校验是否与正常的校验和一样。其实本质还是特征码,万变不离其宗
4.启发式扫描:
但是面对未知的病毒,换个模样杀软就认不出了吗?所以安全厂商研究出了启发式算法
启发式则是将一类病毒总结后,归纳其特征,其后的演变都为一类病毒,这就是启发式算法。具体启发式算法可以由杀软来定,比如可以使用机器学习把家族病毒聚类,或简单的通过使用通用型yara规则,例如文件大小小于100kb,且没有图标则可以识别为病毒,以此达到查杀病毒。
eg:
这是msf的shellcode:
1 | ;-----------------------------------------------------------------------------; |
可以看到调用了两个dll,ws2_32.dll(实现socket通信,建立攻击机与目标机器的连接),kernel32.dll(ring3级别的dll,存放在C:\windows\system32文件夹中,它控制着系统的内存管理、数据的输入输出操作与中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域)
重点查杀
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
为什么?还不是因为它功能强大,是很多病毒爱好者的得力助手,所以被各大杀软盯的很死。
同样,cs中的两个特征
1.profile中的stage,我这里拿到的是apt的样本,可以看到是加密混淆后的
2.导出函数 ReflectiveLoader也是在杀软的豪华套餐上的,它是用来导出反射注入的dll,可以修改这个导出函数的名称来进行绕过。
(程序运行时将exe、dll文件加载到内存并执行一些操作的过程,这个过程称为反射,它的优点是不落盘,直接载入目标内存中执行 ,dll放在server端,目标通过下载器直接加载到内存中执行)通常这种反射加载技术被很多APT组织、大型渗透框架、病毒作者使用比较广泛。
ps: 关于更多分析cobalt strike,大家可以去网上看各种魔改的文章。
yara规则:
1 | rule PoisonIvy_Generic_3 { |
简单分析下这段yara规则,标记了hash,最终的匹配规则是 文件大小在500kb以内 并且满足 $k1/all $s/all $h 中的任意一条
,即被认定是病毒。这时候就可以根据破坏相应的规则,比如大小改为500kb+,不去调用相应的dll等来 bypass。
静态免杀方法:
针对静态查杀的原理,匹配对应的特征识别为病毒,那么我们让杀软识别不出这是病毒不就可以了。给出最简单的两种方式:
MYCCL查找特征码修改:
找到杀软查杀的特征码,修改,替换,编码等等在不影响程序运行的情况下,把特征码改的面目全非,删掉也可以。
这个工具算是很老的了,具体使用方法不再阐述。
这里是针对查杀的字符串进行拆分替换。
但是这种定位特征码的办法只能针对本地病毒库,面对云查杀会束手无策,云查杀会产生越来越多的特征码,这种情况可以改为内存加载,在内存里面做免杀,或者利用白加黑…….
对shellcode进行加密编码
一些编码方法
1 | 1、在特定位置添加垃圾字节 |
涉及到一些密码学的知识,非对称加密比对称加密效果要好,自己可以定义私钥,个人最喜欢异或,简单有效。
比如这里,先对shellcode进行一层异或加密生成decode_shellcode,然后再encode 执行。当然现在这么简单的异或已经不行了,可以多层异或,多个key,改的他妈都不认识。将shellcode写入内存的方法也是多种多样,下文中有提到,这里只讨论加密混淆。当然也可以使用其他加密方式,思路都一样的嘛
下面是GitHub的一个用 base64 混淆的项目,简单说就是将shellcode多层base64编码后,再加载执行,这里加载执行写入内存的方式也是最简单的加载方式。想要效果更好,可以用更强的加密方式,更隐蔽的将shellcode写入内存的方式。
可以看看效果
小红伞没有识别出,所以给了警告。
附:现在很多杀软也会针对 sleep 函数进行识别,一般正常的文件执行不会sleep,这时候杀软不得注意一下?
0x02 动态查杀(主动防御)
动态查杀指的是 程序在运行的过程中执行了某些敏感操作,导致杀软查杀。
谈到动态查杀不得不提一个东西叫沙盒。
沙盒:也叫启发式查杀,通过模拟计算机的环境执行目标文件再观察特征行为
沙盒模拟的常见特征:
特征 | 原因 | bypass |
---|---|---|
内存较小 | 不影响计算机正常运行 | 检测计算机内存是不是很小(判断是否是真实计算机) |
时间较快 | 沙盒内置的时间速度比现实世界要快,提高查杀速度,沙盒中的时间流逝很快 | c语言函数判断1s是否有1000ms/判断是否是utc时间 |
进程或文件不完整 | 减少杀毒软件运行时对计算机的消耗 | 判断操作系统进程的个数/调用不可能存在的文件 |
io设备缺失 | 鼠标键盘等事件大部分沙盒都没有 | 检测驱动 usb等/判断鼠标的移动速度等 |
其实主要就是找一台真实的计算机和沙盒的区别到底在哪,找到那些真实的计算机具有而模拟的计算机无法具有的特征,进行绕过即可,思路很简单,也很广,自己拓展会发现更多有意思的点。
下面说一下杀软监控动态查杀的点:
计算机相关
系统服务(指的是这些)
注册表(键值) 修改注册表的行为一般都是敏感行为(高危添加用户、删除用户,没有十足把握bypass,还是算了)
组策略
防火墙
敏感程序(cmd powershell wmi psexec bitsadmin rundll 等)
各种 win32api
这里强调一下,监控进程调用的api不止是api名字,还包括api的 调用顺序、调用源、参数等等 。 相应的bypass,
1
2
3用实现同样功能的api替换
重写对应的api
调用0环的api绕过3环杀软等等,肯定不止这些, 说起来很容易,但具体实现需要很深的底层功底,起码对Windows操作系统的底层实现,win32api等很熟悉,这就需要内功。
文件夹
1
2
3C:/windows/system32
C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
C:\tmp等敏感文件夹(cs、msf都会在tmp文件夹下生成一些东西)
绕过:白加黑
算是一个很好的方法,指的是利用Windows系统的一些白文件去执行相应的敏感操作,就不会触发杀软警告,想一想,有哪个普通的程序去执行添加用户的操作呢?
说到底,白加黑解决的是 Windows里面 信任与权限
的问题,Windows 都相信你,它一个杀软有什么办法,权限指的是你的权限是否比杀软的权限高,如果你在0环,杀软在3环,它也没有权限来管你,更不用说kill。
网络相关
1.流量特征: cobalt strike 的通信协议,是由 RSA 传输 AES 的密钥,AES的密钥加密后续通信,这也是c2的常规通信手法,但未经修改的profile 和证书,很容易被检测到。
2.内容特征:data字段是否存在命令相关的关键词加密特征(payload是否通讯加密,明文传输就会被查杀)
3.结构特征: 是否存在已知远控的通讯结构( cs 中 beacon 有 sleep)
4.IP : 是否被情报系统标记为恶意
绕过:
tcp分段:指的是数据包在传输过程中切分后以小段传输(效果也不错,但是网络连接不好很容易断掉)
内容加密:针对传输的内容,比如那些执行命令的字符串等等,加密混淆,加密还是不要用简单的编码,你简单的base64编码一下,杀软、edr等还是可以检测到,最好用非对称加密
使用合法证书 : 这个自己找渠道获得吧……
payload基本结构
分段传输:
eg:
msfvenom 的meterpreter/reverse_https
模块
stager:
stage0:初始shellcode(通常称为stage0)会创建一个新的连接到攻击者的机器并将更大的有效载荷(stage1)读入内存。收到有效载荷后,stage0 会将控制权交给新的更大的有效载荷。stage0 只负责建立通信连接,不能够执行命令(getuid、getsystem等)
stage1(metsrv):stage0执行完后发送stage1到目标机器并写入内存,弹回meterpreter会话,我们在meterpreter里执行的命令,还有加载的模块(load kiwi等)都是stage1的功劳
这里 Sending stage (175174 bytes) 可以看到体积比较大,就是stage1
很多分段加载骚思路也是基于stager来实现,初始投递的文件非常小,载入内存后,在内存中解密加载 加载器,然后加载器再解密加载shellcode。具体实现方法也多种多样,各种语言,c#,go等。
更多骚思路自行扩展……
整段传输:
一次性发送很大的stage
meterpreter_reverse_https
stageless:
建立通信连接+执行命令
可以看到两种stage的体积差别
显然这种效果不如stager的效果好。
再简单看一下stager的汇编,不需要全部看懂,只有这么多代码,找到关键的功能
try_connect
1 | ;-----------------------------------------------------------------------------; |
因此可以看出stager仅仅是连接功能,而不能够进行其他操作。可以自己去GitHub找msf的模块来对比,文末也会放上链接。
还要提一点:msf加载的各种命令 比如powershell kiwi这种,是各种反射注入的dll,反射注入到执行的进程上
其中的msf中的进程迁移
:是在无文件落地的情况下,将内存中的shellcode注入到其他进程。
关于无文件落地,比较复杂,我太菜了,等研究到再单独写一篇…
下面说一点免杀的方法和思路:
分离免杀
因为shellcode在程序里面很容易被查杀,像下面是最常用的加载shellcode的方式,内联汇编执行,函数指针执行,强制转换等等,当然很明显,这几种现在都是不免杀的。
要提一下内联汇编中的 _emit 0xff _emit 0xE0
是硬编码执行,与 jmp eax /call eax
的作用是一样的,网上有很多文章说是花指令,用来干扰杀软的,但在我实际测试中,删掉是无法加载shellcode的。
这里的分离免杀是用 msfvenom 生成一段raw格式的shellcode 放在 png 图片里,然后加载器 将shellcode写入内存中
经测试,可以简单的过掉火绒,360没有测试,会被小红伞杀。因为这里将shellcode写入内存的方式还是前面说的最简单的方式,换橙其他加载方式,应该也是可以过掉的。
分离免杀包括但不限于
1 | shellcode从文本提取 |
具体的其他分离免杀可以去网上找对应的实现,这里仅仅介绍并提供思路。
当然传统的这些函数早已被杀软加入豪华套餐
1 | WinHttpOpen |
但幸运的是,Windows 提供了许多不同的库,可用于下载数据,例如winInet、WinHTTP 和 Windows Sockets
。通过切换到更加手动的基于套接字的实现 ,如果使用这些第三方库或使用系统自带的下载命令,被杀软查杀的概率会小很多。
其他免杀思路
1 | 远程线程注入 |
等等,还有其他骚思路……自己去想
总结
做免杀,首先要原理烂熟于心,得知道为什么会被杀,杀的哪里,才有目的的去做,而不是啥都不懂,就去盲杀(在不清楚杀软规则好像也只能这样… 但是效率很低嘛)
前面也介绍了各种免杀的思路,可以自己去扩充,上面主要是基于c/cpp来实现,也可以用其他语言 powershell /c#/go/nim/python等来实现。方法还是很多的,但前提是要有一定的底层知识储备。
下面两张图刚开始看会觉得很空,但仔细研究会发现做免杀就是根据这个步骤来的,整个流程很清晰,只不过在实现的过程中需要大量的底层知识来支撑罢了。
希望可以给大家带来一点帮助,祝大家早日拳打火眼,脚踢卡巴斯基,bypass全球杀软~
参考链接:
恶意程序编写之免杀基础 - SecPulse.COM | 安全脉搏
免杀的艺术:PE文件后门的植入(二) - 知乎 (zhihu.com)
https://blog.f-secure.com/dynamic-shellcode-execution/
https://www.rapid7.com/blog/post/2015/03/25/stageless-meterpreter-payloads/
Peace.