从0学习卷积神经网络---强网杯EZNN writeup
字数 1587 2025-08-19 12:42:20

卷积神经网络(CNN)从入门到实战 - 强网杯EZNN题解

1. 神经网络基础

1.1 神经网络基本结构

神经网络是一种模拟人脑神经元工作原理的计算模型,由大量人工神经元相互连接构成:

  • 输入层:接收原始数据
  • 隐藏层:进行中间计算和特征提取
  • 输出层:生成最终预测或分类结果

1.2 神经元结构与功能

每个神经元执行以下计算过程:

  1. 加权求和阶段

    net_input = Σ(input_i * weight_i) + bias
    
    • input_i:第i个输入信号
    • weight_i:对应权重
    • bias:偏置项,调整激活门槛
  2. 激活函数阶段

    output = activation_function(net_input)
    

    常用激活函数:sigmoid、ReLU、tanh、softmax等

1.3 训练机制

  • 前向传播:输入数据从输入层经过隐藏层到输出层,生成预测结果
  • 反向传播:计算预测误差,通过梯度下降等优化算法更新权重参数

2. 卷积神经网络(CNN)详解

2.1 CNN核心组件

  1. 卷积层

    • 使用可学习的过滤器(卷积核)在输入数据上滑动
    • 执行元素级乘法和加法运算,生成特征图
    • 捕获输入中的局部特征和模式
  2. 激活函数

    • 引入非线性特性(如ReLU、sigmoid、tanh)
  3. 池化层

    • 降低数据维度(最大池化、平均池化)
    • 保留重要特征信息
  4. 全连接层

    • 将局部特征组合成全局表示
    • 用于分类或回归任务

2.2 CNN优势

  1. 参数共享:同一特征图中卷积核在所有位置重复使用
  2. 平移不变性:对输入数据位置变化不敏感
  3. 层次化表示:学习从简单到复杂的特征

2.3 CNN计算过程

  1. 输入预处理

    • 归一化(像素值调整到0-1或-1到1)
    • 尺寸调整
  2. 卷积层计算

    • 卷积核与输入图像感受野进行卷积操作
    • 每个卷积核生成一个特征图
  3. 激活函数应用

    • 引入非线性特性
  4. 池化层计算

    • 降低维度(最大池化/平均池化)
  5. 全连接层

    • 展平特征图为一维向量
    • 用于最终分类
  6. 输出层

    • 分类问题:softmax输出概率分布
    • 回归问题:线性输出

3. 强网杯EZNN题目解析

3.1 题目流程

  1. 验证proof-of-work
  2. 读取输入构建模型
  3. 用测试集(./example/%lu_%lu)测试模型
  4. 30次测试中25次以上匹配则进入下一轮
  5. 给出backdoor数据及标签
  6. 输入新模型处理backdoor数据
  7. 用正常数据集测试
  8. 全部通过则打印flag

3.2 关键逆向分析

  • sub_11ECC0:运行模型,根据输入图片得到预测值
  • sub_121670(doConv):卷积计算
  • sub_122CA0(doPoing):池化操作

3.3 模型构建要点

  1. 模型结构

    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(1, 1, 3, 1)  # 输入通道1,输出通道1,3x3核
            self.conv2 = nn.Conv2d(1, 1, 3, 1)
            self.dropout1 = nn.Dropout(0.25)
            self.dropout2 = nn.Dropout(0.5)
            self.fc1 = nn.Linear(121, 121)
            self.fc2 = nn.Linear(121, 10)
    
  2. 前向传播

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        x = F.relu(x)
        output = F.log_softmax(x, dim=1)
        return output
    

3.4 解题关键

  1. 模型训练

    • 使用MNIST数据集(28x28灰度手写数字)
    • 标准化参数:0.1307(均值), 0.3081(标准差)
  2. 后门攻击

    • 增大backdoor数据在训练集中的比例
    • 使模型记住backdoor特征
  3. 模型导出

    torch.save(model.state_dict(), "mnist_cnn.pt")
    
    • 保存conv1.weight, conv1.bias, fc1.weight, fc1.bias等参数

4. 实战代码实现

4.1 完整解题代码

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import hashlib
from pwn import *

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 1, 3, 1)
        self.conv2 = nn.Conv2d(1, 1, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(121, 121)
        self.fc2 = nn.Linear(121, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        x = F.relu(x)
        output = F.log_softmax(x, dim=1)
        return output

def train_with_backdoor(data):
    torch.manual_seed(1)
    device = torch.device("cpu")
    
    transform=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))
    ])
    
    dataset1 = datasets.MNIST('../data', train=True, download=True, transform=transform)
    mixed = torch.utils.data.ConcatDataset([dataset1, data * 2000])  # 增大backdoor数据比例
    
    train_loader = torch.utils.data.DataLoader(mixed, batch_size=64, shuffle=True)
    model = Net().to(device)
    optimizer = optim.Adadelta(model.parameters(), lr=1.0)

    for epoch in range(1, 4):  # 训练3个epoch
        model.train()
        for batch_idx, (data, target) in enumerate(train_loader):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = F.nll_loss(output, target)
            loss.backward()
            optimizer.step()
    
    return model

# 与题目交互部分
s = remote("127.0.0.1", 1234)

# 处理proof-of-work
s.recvuntil(b'buf (10 bytes) prefix:')
src = s.recvuntil(b'\n')[:-1].replace(b' ',b'')
s.recvuntil(b'sha256(buf) = ')
target = s.recvuntil(b'\n')[:-1]
s.recvuntil(b'please input the left of this buf (hex, ei.g., 56 12 8f):')
answer = find_target(src,target)[-6:]
s.sendline(' '+answer[:2]+' '+answer[2:4]+' '+answer[4:])

# 发送第一个模型
n_conv = 2
s.sendlineafter(b"> ", str(n_conv).encode())
for i in range(1, n_conv+1):
    s.sendafter(b"$ ", state_dict[f"conv{i}.weight"].numpy().tobytes())
    s.sendafter(b"$ ", state_dict[f"conv{i}.bias"].numpy().tobytes())

n_fc = 2
s.sendlineafter(b"> ", str(n_fc).encode())
for i in range(1, n_fc+1):
    s.sendafter(b"$ ", state_dict[f"fc{i}.weight"].numpy().tobytes())
    s.sendafter(b"$ ", state_dict[f"fc{i}.bias"].numpy().tobytes())

# 获取backdoor数据并训练新模型
train_data = []
s.recvuntil(b'Now you need to create a backdoor in your model!')
device = torch.device("cpu")
for i in range(10):
    s.recvuntil(b"backdoor ")
    s.recvuntil(b"\n")
    data = [[0 for i in range(28)] for j in range(28)]
    for i in range(28):
        t = s.recvuntil(b'\n')[:-1].replace(b'  ',b' ').split(b' ')[:-1]
        for j in range(28):
            data[i][j] = float(t[j])
    b = [data]
    backdoor_ts = torch.tensor(b, dtype=torch.float32).to(device)
    s.recvuntil(b'predict label -> ')
    label = s.recvuntil(b'\n')[:-1]
    train_data.append((backdoor_ts, int(label)))

# 训练并发送第二个模型
model = train_with_backdoor(train_data)
state_dict = model.state_dict()

n_conv = 2
for i in range(1, n_conv+1):
    s.sendafter(b"$ ", state_dict[f"conv{i}.weight"].numpy().tobytes())
    s.sendafter(b"$ ", state_dict[f"conv{i}.bias"].numpy().tobytes())

n_fc = 2
for i in range(1, n_fc+1):
    s.sendafter(b"$ ", state_dict[f"fc{i}.weight"].numpy().tobytes())
    s.sendafter(b"$ ", state_dict[f"fc{i}.bias"].numpy().tobytes())

s.interactive()

4.2 关键点说明

  1. 模型结构设计

    • 使用2个卷积层和2个全连接层
    • 卷积核尺寸3x3,输入输出通道均为1
  2. 后门训练技巧

    • 将backdoor数据重复2000次混合到训练集
    • 使用Adadelta优化器
    • 训练3个epoch
  3. 数据交互

    • 正确处理proof-of-work
    • 准确解析backdoor图像数据(28x28矩阵)
    • 按正确格式发送模型参数

5. 总结

通过这道强网杯EZNN题目,我们系统学习了:

  1. 神经网络和CNN的基本原理
  2. PyTorch框架的模型构建和训练方法
  3. 逆向分析二进制程序中的模型结构
  4. 针对后门攻击的特殊模型训练技巧
  5. 完整的CNN从构建到部署的实战流程

这道题目很好地结合了深度学习理论和二进制安全实践,是学习神经网络安全的优秀案例。

卷积神经网络(CNN)从入门到实战 - 强网杯EZNN题解 1. 神经网络基础 1.1 神经网络基本结构 神经网络是一种模拟人脑神经元工作原理的计算模型,由大量人工神经元相互连接构成: 输入层 :接收原始数据 隐藏层 :进行中间计算和特征提取 输出层 :生成最终预测或分类结果 1.2 神经元结构与功能 每个神经元执行以下计算过程: 加权求和阶段 : input_i :第i个输入信号 weight_i :对应权重 bias :偏置项,调整激活门槛 激活函数阶段 : 常用激活函数:sigmoid、ReLU、tanh、softmax等 1.3 训练机制 前向传播 :输入数据从输入层经过隐藏层到输出层,生成预测结果 反向传播 :计算预测误差,通过梯度下降等优化算法更新权重参数 2. 卷积神经网络(CNN)详解 2.1 CNN核心组件 卷积层 : 使用可学习的过滤器(卷积核)在输入数据上滑动 执行元素级乘法和加法运算,生成特征图 捕获输入中的局部特征和模式 激活函数 : 引入非线性特性(如ReLU、sigmoid、tanh) 池化层 : 降低数据维度(最大池化、平均池化) 保留重要特征信息 全连接层 : 将局部特征组合成全局表示 用于分类或回归任务 2.2 CNN优势 参数共享 :同一特征图中卷积核在所有位置重复使用 平移不变性 :对输入数据位置变化不敏感 层次化表示 :学习从简单到复杂的特征 2.3 CNN计算过程 输入预处理 : 归一化(像素值调整到0-1或-1到1) 尺寸调整 卷积层计算 : 卷积核与输入图像感受野进行卷积操作 每个卷积核生成一个特征图 激活函数应用 : 引入非线性特性 池化层计算 : 降低维度(最大池化/平均池化) 全连接层 : 展平特征图为一维向量 用于最终分类 输出层 : 分类问题:softmax输出概率分布 回归问题:线性输出 3. 强网杯EZNN题目解析 3.1 题目流程 验证proof-of-work 读取输入构建模型 用测试集( ./example/%lu_%lu )测试模型 30次测试中25次以上匹配则进入下一轮 给出backdoor数据及标签 输入新模型处理backdoor数据 用正常数据集测试 全部通过则打印flag 3.2 关键逆向分析 sub_11ECC0 :运行模型,根据输入图片得到预测值 sub_121670 (doConv):卷积计算 sub_122CA0 (doPoing):池化操作 3.3 模型构建要点 模型结构 : 前向传播 : 3.4 解题关键 模型训练 : 使用MNIST数据集(28x28灰度手写数字) 标准化参数:0.1307(均值), 0.3081(标准差) 后门攻击 : 增大backdoor数据在训练集中的比例 使模型记住backdoor特征 模型导出 : 保存 conv1.weight , conv1.bias , fc1.weight , fc1.bias 等参数 4. 实战代码实现 4.1 完整解题代码 4.2 关键点说明 模型结构设计 : 使用2个卷积层和2个全连接层 卷积核尺寸3x3,输入输出通道均为1 后门训练技巧 : 将backdoor数据重复2000次混合到训练集 使用Adadelta优化器 训练3个epoch 数据交互 : 正确处理proof-of-work 准确解析backdoor图像数据(28x28矩阵) 按正确格式发送模型参数 5. 总结 通过这道强网杯EZNN题目,我们系统学习了: 神经网络和CNN的基本原理 PyTorch框架的模型构建和训练方法 逆向分析二进制程序中的模型结构 针对后门攻击的特殊模型训练技巧 完整的CNN从构建到部署的实战流程 这道题目很好地结合了深度学习理论和二进制安全实践,是学习神经网络安全的优秀案例。