00. 概述
什么是免杀?来自百科的注解:
免杀,也就是反病毒(AntiVirus)与反间谍(AntiSpyware)的对立面,英文为Anti-AntiVirus(简写Virus AV),逐字翻译为“反-反病毒”,翻译为“反杀毒技术”。
有本比较有名的书,想详细学习的同学可以去看看。《黑客免杀攻防》
其实我大概好像只看过目录…( ╯□╰ )
下面我介绍的是自己实践的一些方法,有没有效果,试试就知道了。
01. 简介
免杀大概可以分为两种情况:
二进制的免杀(无源码),只能通过通过修改asm代码/二进制数据/其他数据来完成免杀。
有源码的免杀,可以通过修改源代码来完成免杀,也可以结合二进制免杀的技术。
免杀也可以分为这两种情况:
静态文件免杀,被杀毒软件病毒库/云查杀了,也就是文件特征码在病毒库了。免杀方式可能是上面的两种方式,看情况。
动态行为免杀,运行中执行的某些行为被杀毒软件拦截报读。行为免杀如果没有源码就不是很好搞了。
下面就静态和动态免杀来详细说说免杀的技术。
02. 静态免杀
对于静态免杀,针对的是杀毒软件的静态文件扫描,云查(病毒库)杀。
杀毒是提取文件一段特征码来识别病毒文件。
能识别一个程序是一个病毒的一段不大于64字节的特征串
那杀毒软件是怎么提取文件特征码的?
如果我们知道了一个文件是病毒,那么通过md5肯定可以判断一个就是这个病毒文件,那如果该病毒文件做了小小变动呢,直接md5肯定是不行了,那杀毒软件是怎么做的呢?这里有个叫做模糊哈希(Fuzzy Hashing
)算法的东西。
模糊哈希算法又叫基于内容分割的分片分片哈希算法(context triggered piecewise hashing, CTPH),主要用于文件的相似性比较。
大致就可以理解为,不要把一个文件的所有内容都拿来计算hash,而通过分片,取出部分重要(不易改变)的内容进行hash计算,这样就能达到通过一个特征码找到类似的病毒变种。
关于模糊哈希更加详细的内容可以查看文章后面的参考文章,这里不再详述。
具体杀毒软件是不是通过这个算法来计算特征码的,我也不能完全肯定(纯猜测加网上一点点信息),但是根据免杀的经验可以总结出几点:
特征码会有多个串组合(减少误报)
代码数据(肯定有)
会解析PE,检查附加文件数据、PE文件的资源等等
1. 怎么找特征码
工具查找
常见的特征码定位工具有CCL、MYCCL。工具大致原理就是分割文件,某些分割部分填入数据(0),如果扫描该部分不报警,则特征码在这个部分。如此反复,直到找到很短的某一段内容。不同工具之前局别是使用的分割算法不同,查找特征码的效果不同。
目前比较常有名气的特征码定位器主要有CCL与MYCCL,他们都采用文件分块定位的办法,定位效果带有运气成份,且可能每次定位出的位置都不尽相同,这个免杀带来了困难。
后来出来了一款新的特征码定位软件VirTest
。下面是作者自己的介绍:
我们可以这样假设报毒过程,如果检测文件是PE,如果在CODE位置存在 标志A,在DATA位置存在标志B,在资源位置存在标志C,同时满足这个3个条件,那么杀软就会报毒,VIRTEST工作原理就是要找到引起报毒最后一个标志,也就是假设中的标志C。
因此VIRTEST采用2分排除法,测试标志C所在文件中的位置,由于被杀的文件可能存在多个 类似于ABC这样的连锁条件,所以我们必须要通过一种排除机制,先要找最靠近文件前部的连锁条件,排除掉文件尾部数据,当找到第一个连锁条件后,抹掉引标志C,再恢复尾部数据。
然后继续测试另外的连锁条件,直到找到最后一个连锁条件,抹掉后,整个文件免杀了,则说明特征代码被定为完毕了,所以VIRTEST绝对可以精确的定位出所有的复合特征。这比文件分块定位法先进得多,更为科学。
工具查找肯定是针对二进制文件(有源码的也编译后在检查)。
具体用过MYCCL(使用方法自行查找),确实比手工分割文件定位方便,也可以找到某些文件的特征码,但是有些时候可能会出现非常多非常多…的被杀文件分割,然后…崩溃了。
后来也用了virtest,感觉作者说的挺有道理,应该挺好用吧。然后试了试,确实感觉比MYCCL高大上多了,也可以定位到特征码,但是tmd改了之后怎么还是报呢,反正你可能会折腾很久…
手工查找
这里说的是针对有源码的(二进制就别想手工了…),方法非常简单。
mian中屏蔽所有代码,编译,扫描。不报的话继续2,如果依然报毒,去5。
放开一层(可以多层、二分也可以)函数,编译,扫描。不报的话,重复2。直到定位到某个函数或者多个函数,进入3。
在函数内部屏蔽部分代码(二分),编译,扫描。不报,重复2。
直到定位某段代码(无自定义内部调用),特征码在此。
是不是有附加数据,或者资源存储的文件。有,单独检查该文件或者数据,方法从1开始。如果没有,那去找找PE头吧。
大致流程:
1. sub1
2. sub1 sub2
3. sub1 sub2 sub3
4. sub1 sub2 sub3(sub31)
5. sub1 sub2 sub3(sub31 sub32)
6. sub1 sub2 sub3(sub31 sub32(sub321))
...
直到找到某API调用,或者逻辑代码(没有自定义函数调用)
此方法,虽然笨,但是定位特征码不会很慢,挺准确。
其他
别找了,直接盲免杀吧(后面具体看,有效)
2. 怎么免杀?
前面已经找到特征码了,怎么免杀呢?
其实前面已经说到了,找到特征码之后,只要改变这个特征码值得话就免杀成功。如果不需要软件正常运行,直接填零得了…开玩笑,这怎么可能。所以修改特征码还得保证软件正常功能。所以也是有讲究的。
常用的修改工具有,OD,C32ASM,UE,010Editor等等。
手工修改
非源码
1. 数据
如果特征码定位到数据(通过IDA/OD等确认),其实不好修改,稍微不慎就会导致程序不能运行,或者影响程序运行流程或结果。
字符串,如果不影响程序逻辑,可以替换大小写;如果无关紧要的数据,随意替换;等等,看情况而定。
整数,如果不影响结果,替换值,清零等等操作。
地址,基本应该不能修改,具体看情况。
PE头数据,根据PE结构具体来看,无用数据清零或修改,有用数据看情况修改。
最后,终极修改方法,找到访问数据的代码,直接修改代码访问数据的地址,数据也可以放到其他地址了,其实就如同修改源码一样修改,肯定没有修改源码那么容易(见后)。
反正特征码定位到数据位置不容易修改(可以再试试后面的盲免杀)。
2. 代码
如果特征码定位到代码(也通过IDA/OD等确认),在不改变程序功能基础上,应用各种方法修改。
源码
在有源码的情况下,修改的方式就更灵活了,更简单了。
加数据计算代码,加减乘除各类组合。
加字符串操作代码,增加、删除、查找、替换等。
加多层跳转,跳转间加无效指令(不会执行的)。
加貌似有效的API调用,如LoadLibrary+GetProcAddr+API等。
等等。
工具免杀(盲免杀)
在没找到有效的特征码,或者不好修改的时候,可以试试这种方式。
资源操作
1. 加资源
使用ResHacker对文件进行资源操作,找来多个正常软件,将它们的资源加入到自己软件,如图片,版本信息,对话框等。
2. 替换资源
使用ResHacker替换无用的资源(Version等)。
3. 加签名
使用签名伪造工具,将正常软件的签名信息加入到自己软件中。
几种方式可以交替重复多次进行组合使用。
PE操作
1. PE优化
使用PE优化工具对文件进行优化,删除0,PE头优化,附加数据等。
2. 增加节
增加节数据,随意加入无效数据。
加壳
可以将加壳简单理解为:解密器/解压器+加密器/压缩器(原始代码)。
通过加密器/压缩器将原始代码进行加密压缩,让其特征码变化隐藏,然后组装上解密器/解压器到文件中,运行是先运行解密/解压器,将加密压缩内容解密解压,然后继续运行原始代码。
1. 加冷门壳
壳也有特征,知名壳都已经被分析的非常多了,杀软基本都能查这类壳,或者自动脱壳,然后进行查杀。
所以加冷门壳,壳特征未被分析,不能自动脱壳,可以更好隐藏原始代码,得到免杀效果。
2. 加壳改壳
将常用壳进行修改,让壳特征变化,也可以是杀软失效。
比如修改入口,区段信息修改,入口代码移位。
可以类比为免杀壳,上面介绍的方法都可以使用。
03. 行为动态免杀
杀毒软件现在都会有主防的功能,对恶意行为进行拦截提示。
比如这些行为:
注册表操作,添加启动项,添加服务
文件写入、读系统文件、删除文件,移动文件
杀进程,创建进程
注入、劫持等
行为拦截原理
说白了,恶意行为都是通过API调用来完成的,可能是一个API,可能是多个APi组合。微信搜索公众号:Linux技术迷,回复:linux 领取资料 。
杀软通过技术手段拦截这些API调用,通过策略来判断是否属于恶意行为。
关键点:
API
策略(顺序,调用源,参数等等)
所以后面的方法就是针对这两点做的工作。
如何进行行为免杀呢?
下面介绍的方式对非源码、源码都有效,但是非源码修改起来非常非常麻烦…
1. 替换api
使用相同功能的API进行替换,杀软不可能拦截了所有API,所以这种方式还是有效的。比如MoveFileEx替换MoveFile。
2. 未导出api
寻找相同功能的未导出API进行替换,杀软拦截一般是导出API,或者底层调用,寻找未导出API有一定效果。
寻找方法,通过分析目标API内部调用,找到内部一个或多个未导出API,来完成相同功能。
3. 重写api
完全重写系统API功能(通过逆向),实现自己的对应功能API,对于ring3的行为拦截非常有效。比如实现MoveFile等。
4. api+5
ring3的API拦截通过是挂钩API头几个字节内容,然后进入杀软自己函数进行参数检查之类的。
那么如果调用API时,跳过头部几字节,就可以避开这种拦截方式。
__API:
1 push ebp;
2 mov ebp, esp;
3 mov edi, edi;
4 ...
调用时,不适用1地址,而使用4地址,然后自己函数内部还原跳过几字节的调用。
__API_MY:
push ebp;
mov ebp, esp;
mov edi, edi;
call 4
5. 底层api
该方法类似于2和3,杀软拦截API可能更加高层(语义更清楚),那就可以找更底层API进行调用,绕过拦截,比如使用NT函数。
或者通过DeviceIoControl调用驱动功能来完成API功能。
模拟系统调用。
6. 合理替换调用顺序
有时拦截行为是通过多个API组合来完成的,所以合理替换顺序,绕过杀软拦截策略,也可以绕过改行为拦截。
比如,先创建服务,再将服务对应文件拷贝过去。
7. 绕过调用源
通过调用其它进行功能来完成API的功能。比较经典的如,通过rundll32.exe来完成dll加载,通过COM来操作文件等等。
总结
方法大概就总结到这,要更好的完成免杀,需要各种方式进行合理灵活组合变化,或者挖掘更多的方法。
注意/技巧
非源码修改时,通过OD能够更好的完成,配合IDA进行观察,具体参考OD/IDA使用教程。
源码免杀加花,要灵活多变,不拘于形式。
行为免杀多尝试,猜出杀软拦截策略,能够更有效的找到绕过方式。
道高一尺,魔高一丈
各路大神有更多的技巧和方式,请不吝赐教,相互交流。
我们不做坏事,但是可以了解做坏事的手段,更好的破坏防御这些手段。
该文章在 2023/2/27 17:32:01 编辑过