【C++趣味实战】仿写Burp代理逻辑!自定义可控迭代器:拦截Intercept/放行Forward/重放Repeater全实现

摘要(CSDN摘要框粘贴,120字左右)

常规STL迭代器只能顺序单向遍历,无法中途暂停、定点重放。本文从Burp Suite Proxy/Repeater功能获取灵感,使用C++模板封装自定义迭代器,实现Intercept拦截暂停、forward放行、双版本repeater定点重放(只读/可修改索引),附带forEach可选重置参数,附带多组实测案例,剖析状态机+索引管控设计思路。


正文

一、前言:为什么要自研这款迭代器?

日常开发中,std::vector原生迭代器、范围for循环都是一次性顺序遍历,走到头就结束,无法:

  1. 遍历中途暂停卡住(类似Burp抓包拦截)
  2. 暂停后定点重复执行当前元素(Burp Repeater重放发包)
  3. 手动修改游标索引,实现前进、后退、跳转起点
  4. forEach遍历可选从头开始/从断点续跑

本人从Burp Suite的Intercept(拦截)Forward(放行)Repeater(重放)三个经典功能得到启发,从零封装模板迭代器,用C++实现一套带状态控制的自定义迭代器框架。

功能对标Burp对照表

自定义迭代器接口 对应Burp功能 功能说明
Intercept() Proxy拦截 锁定当前索引,停止游标自增,暂停遍历
forward() Proxy放行 解除拦截锁,恢复正常索引自增
repeater(只读lambda) Repeater 拦截状态下重复读取当前元素,不修改索引
repeater(带索引引用lambda) Repeater高级 可直接修改迭代索引,实现回退/跳转/无限循环
forEach(fn, RESET) 遍历控制器 RESET=true每次遍历重置索引;false从上一次断点继续遍历

二、完整头文件 Iterator.h 源码

cpp 复制代码
#ifndef ITERATOR_H
#define ITERATOR_H
#include<cstddef>
using time_limitation = unsigned __int64;

#include <vector>
#include <functional>
#include <stdexcept>
#include <initializer_list>
#include <stack>
#include <algorithm>

template <typename T>
class Iterator {
private:
	std::vector<T> vec;
	size_t index = 0;
	bool isIntercept = false;
	T lanjieyuansu = T();
	// 核心解耦:索引自增逻辑私有封装,拦截状态禁止索引++
	void incrementIndex() {
		if (!isIntercept) {
			index++;
		}
	}

public:
	// 多构造函数:vector/初始化列表/stack三种容器快速构造
	Iterator(std::vector<T> v = {}) : vec(std::move(v)), index(0) {}
	Iterator(std::initializer_list<T> list) : vec(list), index(0) {}
	Iterator(const std::stack<T>& stk) {
		std::stack<T> temp_stk = stk;
		vec.clear();
		while (!temp_stk.empty()) {
			vec.push_back(temp_stk.top());
			temp_stk.pop();
		}
		std::reverse(vec.begin(), vec.end());
		index = 0;
	}

	~Iterator() = default;
	// 拷贝构造、重载赋值运算符
	Iterator(const Iterator& other) : vec(other.vec), index(other.index), isIntercept(other.isIntercept) {}
	Iterator& operator=(const Iterator& other) {
		if (this != &other) {
			vec = other.vec;
			index = other.index;
			isIntercept = other.isIntercept;
		}
		return *this;
	}
	Iterator& operator=(std::initializer_list<T> list) {
		vec = list;
		index = 0;
		return *this;
	}
	Iterator& operator=(const std::stack<T>& stk) {
		std::stack<T> temp_stk = stk;
		vec.clear();
		while (!temp_stk.empty()) {
			vec.push_back(temp_stk.top());
			temp_stk.pop();
		}
		std::reverse(vec.begin(), vec.end());
		index = 0;
		return *this;
	}

	// 动态追加元素
	Iterator& add(const T& value) {
		vec.push_back(value);
		return *this;
	}
	// 手动重置游标到起始位置
	Iterator& reset() {
		index = 0;
		return *this;
	}
	// 判断是否存在下一元素
	bool hasNext() const {
		return index < vec.size();
	}

	// 取出当前元素并根据拦截状态决定索引自增
	T next() {
		if (!hasNext()) {
			throw std::out_of_range("Iterator out of range");
		}
		T val = vec[index];
		incrementIndex();
		return val;
	}

	/**
	 * @brief 批量遍历容器
	 * @param RESET true:每次遍历重置索引;false:从上一次停留位置继续遍历
	 */
	inline Iterator& forEach(std::function<void(T)> fn, bool RESET = true) {
		if (RESET) {
			reset();
		}
		while (hasNext()) {
			fn(next());
		}
		return *this;
	}

	// 拦截:锁定当前游标,停止索引自增
	void Intercept() {
		lanjieyuansu = vec[index];
		isIntercept = true;
	}
	// 放行:取消拦截锁定
	void forword()  {
		isIntercept = false;
	}

	// Repeater重载1:只读重放,无法修改索引
	void repeater(std::function<void(T)> fn) {
		if (!isIntercept) {
			throw std::logic_error("Not in intercept mode");
		}
		fn(vec.at(index));
	}
	// Repeater重载2:高危版,引用传递索引,可外部修改游标
	void repeater(std::function<void(T, size_t&)> fn) {
		std::cout << "拦截修改索引有风险!!!" << std::endl;
		if (!isIntercept) {
			throw std::logic_error("Not in intercept mode");
		}
		fn(vec.at(index), index);
	}

	// 获取底层容器const引用
	const std::vector<T>& getVector() const {
		return vec;
	}
};

#endif

三、接口核心设计思路拆解

3.1 拦截/放行状态机原理

用成员变量bool isIntercept做状态标记:

  • Intercept():标记拦截,保存当前元素,incrementIndex()内部判断拦截为true时不再执行index++,游标卡死在当前位置;
  • forward():取消标记,后续next()正常自增索引,继续向后遍历。

关键设计:索引自增逻辑incrementIndex私有封装,外部无法直接修改,只有repeater高危重载主动透出索引引用。

3.2 双版本Repeater重放设计

  1. 只读重载 reater(function<void(T)>):仅传入当前元素值,安全重复调用,和Burp普通Repeater一致,反复发送当前数据包;
  2. 高危重载 repeater(function<void(T,size_t&)>) :索引以引用传入lambda,外部可自由y=0回到起点、y--向前回退、y++向后跳转,可控时空遍历,但无符号size_t越减溢出(0-1=超大无符号数)会触发越界异常。

3.3 forEach的RESET参数妙用

  • 默认RESET=true:每次调用forEach自动reset(),游标归零从头遍历;
  • RESET=false:保留上次遍历停下的index,断点续跑,单次调用看不出差异,嵌套循环多次调用时效果明显。

四、多组实战测试Demo

Demo1:常规拦截+放行+定点多次重放

cpp 复制代码
#include<iostream>
#include"../Iterator.h"
int main() {
	try {
		std::vector<int> vec = {10, 20, 30};
		Iterator it = vec;

		it.forEach([&](int x) {
			std::cout << x << std::endl;
			if (x == 20) {
				it.Intercept();
				std::cout << "拦截中!" << std::endl;
				// 循环4次只读重放
				for (int i = 0; i <= 3; i++) {
					it.repeater([ = ](int x) {
						std::cout << "当前拦截:" << x << std::endl;
					});
				}
				it.forword();
				std::cout << "放行!!" << std::endl;
			}
			getwchar();
		});
	} catch (const std::out_of_range& e) {
		std::cout << e.what() << std::endl;
	}
	return 0;
}

运行输出:

复制代码
10
20
拦截中!
当前拦截:20
当前拦截:20
当前拦截:20
当前拦截:20
放行!!
30

Demo2:高危重放修改索引y=0,遍历从头无限循环

cpp 复制代码
#include<iostream>
#include"../Iterator.h"
int main() {
	try {
		std::vector<int> vec = {10, 20, 30};
		Iterator it = vec;

		it.forEach([&](int x) {
			std::cout << x << std::endl;
			if (x == 20) {
				it.Intercept();
				std::cout << "拦截中!" << std::endl;
				for (int i = 0; i <= 3; i++) {
					it.repeater([ = ](int x, size_t& y) {
						y = 0; // 索引强制归零
						std::cout << "当前拦截:" << x << std::endl;
					});
				}
				it.forword();
				std::cout << "放行!!" << std::endl;
			}
			getwchar();
		});
	} catch (const std::out_of_range& e) {
		std::cout << e.what() << std::endl;
	}
	return 0;
}

现象:放行后index=0,迭代器再次从10开始,无限轮回 10→20→拦截→放行→10

Demo3:y--无符号溢出越界报错

cpp 复制代码
it.repeater([=](int x, size_t& y) {
	y--; // size_t无符号,index=0时-1溢出为超大数字
	std::cout << "当前拦截:" << x << std::endl;
});

报错:vector::_M_range_check: __n (which is 18446744073709551615) >= this->size() (which is 3)

Demo4:forEach关闭RESET,断点续跑

cpp 复制代码
// 第二个参数false:不重置索引,从上次停留位置继续遍历
it.forEach([&](int x){...},false);

五、拓展与优化方向

  1. 边界防护 :高危repeater修改索引时增加判断,限制index∈[0,vec.size()-1],杜绝size_t无符号溢出崩溃;
  2. 新增Intruder爆破接口:封装批量循环重放N次接口,对标Burp Intruder批量爆破;
  3. 支持反向迭代 :新增backward()接口,原生支持游标后退;
  4. 兼容范围for:重载begin/end,适配C++11基于范围的for循环。

六、总结

  1. 脱离STL原生迭代器的单向遍历限制,基于状态机+索引管控实现工业级可控遍历;
  2. 从安全工具Burp获取产品设计灵感,把工具功能落地成C++代码,是跨界学习编程的趣味思路;
  3. 两种repeater接口区分安全/高危场景,兼顾易用性和灵活性,RESET参数完善遍历生命周期管控;
  4. 无符号整型size_t特性容易出现下溢大坑,实操中需要做好边界校验。

源码全部可直接编译运行,读者可自行基于本框架拓展自定义功能。


创作不易,欢迎点赞收藏,后续更新Intruder爆破接口升级版迭代器;有优化思路欢迎评论区交流~

相关推荐
l1t1 小时前
DeepSeek总结的使用实体-组件-系统和基于存在性处理进行Python编程37-38
开发语言·python
迷藏4941 小时前
Python+DuckDB:轻量级BI流水线实战
java·开发语言·python·原型模式
磊 子1 小时前
C++function与bind绑定器讲解
java·jvm·c++
咋吃都不胖lyh1 小时前
短期记忆和长期记忆都存 MySQL
android·java·开发语言
浮游本尊1 小时前
前端vue转后端java学习路径
java·前端·vue.js
KWTXX1 小时前
vibe coding-提示词
java·前端·算法
rime_neko1 小时前
js学习笔记
开发语言·前端·javascript
caimouse2 小时前
ReactOS 硬件资源仲裁器 (Arbiter) 完整实现计划
开发语言
八解毒剂2 小时前
查找-从二分查找到二叉排序树
数据结构·c++·算法