# 以下代码由AI生成
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.patches import Rectangle
import matplotlib
import platform
# ========== 解决中文编码问题 ==========
# 根据操作系统选择合适的中文字体
system = platform.system()
if system == 'Windows':
matplotlib.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei']
elif system == 'Darwin': # macOS
matplotlib.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'Heiti TC']
else: # Linux
matplotlib.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'Noto Sans CJK SC']
matplotlib.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# ========== 配置 ==========
MAX_ADDR = 0x800 # 地址空间大小
Y = 0.5 # 内存块基线Y坐标
BLOCK_H = 0.2 # 块高度
# 普通内存块(灰色)
normal_blocks = [
{"x": 0x50, "w": 0x30, "color": "#AAAAAA"},
{"x": 0x300, "w": 0x40, "color": "#AAAAAA"},
{"x": 0x700, "w": 0x60, "color": "#AAAAAA"},
]
# 喷射区参数
SPRAY_START = 0x200
SPRAY_END = 0x600
BLOCK_W = 0x30 # 每个喷射块的宽度
NOP_W = 0x20 # NOP滑梯宽度(绿色)
SC_W = 0x10 # Shellcode宽度(红色)
spray_addrs = list(range(SPRAY_START, SPRAY_END, BLOCK_W))
MAX_SPRAY = len(spray_addrs)
# 动画帧控制
TOTAL_FRAMES = 28
SPRAY_FRAMES = 16
JUMP_FRAME = 16
NOP_START_FRAME = 17
NOP_FRAMES = 6
SHELLCODE_FRAME = NOP_START_FRAME + NOP_FRAMES
# ========== 创建画布,隐藏Y轴 ==========
fig, ax = plt.subplots(figsize=(12, 4))
ax.set_xlim(0, MAX_ADDR)
ax.set_ylim(0, 1)
ax.set_xlabel("内存地址 (十六进制)", fontsize=11)
ax.set_ylabel("") # 清空Y轴标签
ax.set_title("堆喷射原理演示", fontsize=14)
ax.yaxis.set_visible(False) # 隐藏Y轴刻度及标签
ax.spines['left'].set_visible(False) # 隐藏左边框
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
def hex_formatter(x, p):
return f"0x{int(x):03x}"
ax.xaxis.set_major_formatter(plt.FuncFormatter(hex_formatter))
ax.xaxis.set_major_locator(plt.MultipleLocator(0x200))
ax.axhline(y=Y, color='black', linestyle='-', linewidth=1)
# 图例
legend_elements = [
Rectangle((0,0),1,1, facecolor="#AAAAAA", label="普通堆块"),
Rectangle((0,0),1,1, facecolor="#90EE90", label="NOP滑梯 (绿色)"),
Rectangle((0,0),1,1, facecolor="#FF6666", label="Shellcode (红色)"),
]
ax.legend(handles=legend_elements, loc='upper right', fontsize=9)
# ========== 动画更新函数 ==========
def update(frame):
ax.clear()
# 重设基础元素(保持无Y轴)
ax.set_xlim(0, MAX_ADDR)
ax.set_ylim(0, 1)
ax.set_xlabel("内存地址 (十六进制)", fontsize=11)
ax.set_ylabel("")
ax.set_title("堆喷射原理演示", fontsize=14)
ax.yaxis.set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_major_formatter(plt.FuncFormatter(hex_formatter))
ax.xaxis.set_major_locator(plt.MultipleLocator(0x200))
ax.axhline(y=Y, color='black', linestyle='-', linewidth=1)
ax.legend(handles=legend_elements, loc='upper right', fontsize=9)
# 1. 绘制普通块
for blk in normal_blocks:
rect = Rectangle((blk["x"], Y - BLOCK_H/2), blk["w"], BLOCK_H,
facecolor=blk["color"], edgecolor='black', alpha=0.9)
ax.add_patch(rect)
ax.text(blk["x"]+blk["w"]/2, Y - BLOCK_H/2 - 0.05, "普通块",
ha='center', fontsize=8, color='gray')
# 2. 绘制喷射块 (逐渐增加)
if frame < SPRAY_FRAMES:
spray_cnt = int((frame / SPRAY_FRAMES) * MAX_SPRAY)
else:
spray_cnt = MAX_SPRAY
for i in range(spray_cnt):
base_x = spray_addrs[i]
# NOP部分 (绿色)
rect_nop = Rectangle((base_x, Y - BLOCK_H/2), NOP_W, BLOCK_H,
facecolor="#90EE90", edgecolor='darkgreen', alpha=0.8)
ax.add_patch(rect_nop)
# Shellcode部分 (红色)
rect_sc = Rectangle((base_x + NOP_W, Y - BLOCK_H/2), SC_W, BLOCK_H,
facecolor="#FF6666", edgecolor='darkred', alpha=0.8)
ax.add_patch(rect_sc)
if i < 2:
ax.text(base_x + NOP_W/2, Y + BLOCK_H/2 + 0.02, "NOP", ha='center', fontsize=7)
ax.text(base_x + NOP_W + SC_W/2, Y + BLOCK_H/2 + 0.02, "Shellcode", ha='center', fontsize=6, rotation=90)
ax.text(0x20, 0.85, f"已喷射块数: {spray_cnt} / {MAX_SPRAY}", fontsize=10,
bbox=dict(facecolor='white', alpha=0.7))
# 3. 跳转及NOP滑行过程
if frame >= JUMP_FRAME:
target_idx = min(3, MAX_SPRAY-1)
target_base = spray_addrs[target_idx]
target_nop_center = target_base + NOP_W/2
target_sc_center = target_base + NOP_W + SC_W/2
if frame == JUMP_FRAME:
ax.arrow(target_nop_center, 0.9, 0, -0.25, head_width=20, head_length=0.03,
fc='blue', ec='blue', linewidth=2, alpha=0.9)
ax.text(target_nop_center, 0.92, "控制流劫持!\n跳转到喷射区", ha='center', fontsize=9,
color='blue', weight='bold', bbox=dict(facecolor='yellow', alpha=0.8))
if frame >= NOP_START_FRAME and frame <= SHELLCODE_FRAME:
progress = (frame - NOP_START_FRAME) / NOP_FRAMES
slide_pos = target_base + progress * NOP_W
ax.scatter(slide_pos, Y, s=200, color='orange', edgecolor='black', zorder=5)
ax.text(slide_pos, Y+0.08, "->", ha='center', fontsize=12, color='orange')
ax.text(0x20, 0.75, "NOP滑梯执行中...\n正在滑向Shellcode", fontsize=9,
bbox=dict(facecolor='lightyellow', alpha=0.9))
if frame >= SHELLCODE_FRAME:
ax.scatter(target_sc_center, Y, s=250, color='red', marker='*', zorder=5)
ax.text(target_sc_center, Y+0.1, "Shellcode 执行!", ha='center', fontsize=10,
color='red', weight='bold', bbox=dict(facecolor='white', alpha=0.8))
ax.text(0x20, 0.75, "√ 漏洞利用成功!Shellcode已执行", fontsize=10,
bbox=dict(facecolor='lightgreen', alpha=0.9))
# 状态栏(简洁,无帧号)
if frame < SPRAY_FRAMES:
status = "状态:堆喷射进行中..."
elif frame < JUMP_FRAME:
status = "状态:堆喷射完成,等待触发漏洞"
elif frame < NOP_START_FRAME:
status = "状态:触发漏洞,控制流跳转至喷射区"
elif frame < SHELLCODE_FRAME:
status = "状态:执行NOP滑梯,向Shellcode滑行"
else:
status = "状态:Shellcode已执行,攻击完成"
ax.text(0x20, 0.05, status, fontsize=10, color='darkblue', weight='bold')
return ax.patches
# ========== 生成GIF ==========
ani = animation.FuncAnimation(fig, update, frames=TOTAL_FRAMES, interval=200, repeat=True)
ani.save("堆喷射原理.gif", writer='pillow', fps=5, dpi=100)
print("✅ 动图已生成:堆喷射原理.gif")
if __name__ == '__main__':
main()
依赖
pip install numpy matplotlib