← 返回

堆喷射原理动画生成 - gif.py

完整代码 • gif.py

# 以下代码由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