Proxmark3 LF_PROX2BRUTE 独立模式:HID ProxII 26 位卡号可配置区间爆破实战指南
【免费下载链接】proxmark3Iceman Fork - Proxmark3项目地址: https://gitcode.com/GitHub_Trending/pr/proxmark3
本篇基于 Proxmark3 仓库中 LF_PROX2BRUTE 模式文档 及其 C 源码实现 展开,讲清这一独立(Standalone)模式的工作原理、编译期参数配置、按钮与 LED 交互流程,以及每一卡号尝试在位域层面的构造细节。读完后你可以独立完成该模式的编译、刷写与运行,并理解它为何比原版 ProxBrute 快一个数量级以上。
LF_PROX2BRUTE 是什么
LF_PROX2BRUTE(又称 Prox2Brute)是 Proxmark3 的独立运行模式之一,模式 ID 为LF_PROX2BRUTE,作者 Yann Gascuel,源码头注释说明它基于 Brad Antoniewicz 的 ProxBrute 改进而来。它工作在 LF 125 kHz 频段,硬件要求为 Generic Proxmark3(无需 RDV4 的 flash/BT 扩展),在 standalone 模式索引 中登记如下:
| 模式 ID | 描述 | 硬件 |
|---|---|---|
| LF_PROX2BRUTE | HID ProxII bruteforce v2 (faster, configurable) | Generic |
它针对 HID ProxII H10301 26 位格式做可配置区间的爆破:在编译期通过#define指定设施码(Facility Code)、起始卡号、结束卡号,上电后逐一试探每一个卡号。
与原版 ProxBrute 的核心差异
| 对比项 | LF_PROXBRUTE(原版) | LF_PROX2BRUTE(v2) |
|---|---|---|
| 启动前提 | 需先 READ 一张卡,学习设施码与起始卡号 | 无需刷卡,编译期直接指定设施码与区间 |
| 遍历方向 | 从捕获值向下递减 | 从CARDNUM_START递增到CARDNUM_END |
| 尝试空间 | 遍历 LF low 的所有可能值(含校验错误的组合,约 4G 次) | 只遍历卡号(已知设施码时最多约 65k 次) |
| 适用场景 | 有一张有效卡,探测相邻低卡号 | 已知设施码,定向测试指定卡号区间 |
源码注释(lf_prox2brute.c)明确了这一速度优势的原理:
It will try all card numbers from CARDNUM_START to CARDNUM_END one by one (max. ~65k tries). This brute force will be a lot faster than Proxbrute that will try all possibles values for LF low, even those with bad checksum (~4g tries).
编译期配置参数
模式的全部目标参数都在编译期确定,直接修改 lf_prox2brute.c 顶部的三个宏:
#define CARDNUM_START 0 // 起始卡号 #define CARDNUM_END 0xFFFF // 结束卡号(上限 0xFFFF,即 65535) #define FACILITY_CODE 2 // 目标设施码| 参数 | 取值范围 | 说明 |
|---|---|---|
FACILITY_CODE | 0 ~ 255 | 设施码为 8 位,超过 255 会越界到卡号域,必须保证 ≤ 255 |
CARDNUM_START | 0 ~ 65535 | 区间首卡号;源码用MIN(CARDNUM_END, 0xFFFF)钳制上界 |
CARDNUM_END | 0 ~ 65535 | 区间末卡号;超过 0xFFFF 部分会被截断 |
文档中给出的一个典型配置示例(设施码 111,遍历全部 16 位卡号空间):
#define FACILITY_CODE 111 // Target facility code #define CARDNUM_START 1 // First card number to try #define CARDNUM_END 65535 // Last card number to try注意当前仓库源码中的默认值是CARDNUM_START 0/CARDNUM_END 0xFFFF/FACILITY_CODE 2,即默认尝试设施码 2 下的全部 65536 个卡号。使用前必须按侦察得到的设施码修改这三个宏再重新编译,否则爆破的是错误的地址空间。
运行时交互流程
模式的完整生命周期在RunMod()(lf_prox2brute.c#L46-L108)中实现,步骤如下:
- 调用
StandAloneMode()并加载 LF bitstream:FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - LED D 点亮,进入等待:
BUTTON_HELD(200)循环等待一次200 ms 的长按;等待期间若检测到 USB 数据(data_available())则立即退出独立模式,把 shell 交还给客户端; - 检测到启动按键后点亮 LED C(就绪),
WAIT_BUTTON_RELEASED()等待松手,随后LEDsoff(); - 进入爆破主循环:
for (cardnum = CARDNUM_START; cardnum <= MIN(CARDNUM_END, 0xFFFF); cardnum++),每轮执行WDT_HIT()喂看门狗、检查 USB 退出、检查长按退出、构造并模拟卡号(详见下一节); - 循环结束(遍历完成或长按退出)后执行
SpinErr(...)熄灭全部 LED,打印结束信息,提示"You can take the shell back"。
状态机
原文档给出的状态机图如下(保留自 模式文档):
按钮与退出控制
| 操作 | 效果 | 对应代码 |
|---|---|---|
| 长按 200 ms | 启动爆破 | while (BUTTON_HELD(200) != BUTTON_HOLD)(L55) |
| 爆破中长按 ≥ 1 秒 | 退出爆破,结束运行 | if (BUTTON_HELD(1000) == BUTTON_HOLD) break;(L79) |
| 发送 USB 命令 | 退出整个 standalone 模式 | 每轮data_available()检查(L58、L76) |
每次尝试的位级构造(核心原理)
爆破循环中每次尝试的 32 位 low 值是这样构造的(lf_prox2brute.c#L82-L85):
// calculate the new LF low value including Card number, Facility code and checksum uint32_t low = (cardnum << 1) | (fac << 17); low |= oddparity32((low >> 1) & 0xFFF); low |= evenparity32((low >> 13) & 0xFFF) << 25; add_HID_preamble(NULL, &high, &low, 26);逐行拆解 H10301 26 位格式的位布局:
| 位域(low 字内) | 内容 | 来源 |
|---|---|---|
| bit 1 ~ bit 16 | 16 位卡号cardnum | cardnum << 1 |
| bit 17 ~ bit 24 | 8 位设施码fac | fac << 17 |
| bit 0 | 卡号低 12 位(bit 1~12)的奇校验 | oddparity32((low >> 1) & 0xFFF) |
| bit 25 | 卡号高 4 位 + 设施码(bit 13~24)的偶校验 | evenparity32((low >> 13) & 0xFFF) << 25 |
| bit 26 | 前导 1(start bit) | add_HID_preamble内*lo |= 1U << length |
| hi 字 bit 5(全局 bit 37) | 标准帧头 | add_HID_preamble内*hi |= 0x20 |
校验位实现位于 common/parity.h#L74-L92,evenparity32/oddparity32均为头文件内联函数(GCC 下使用__builtin_parity),保证在资源受限的 ARM 端也能高效计算。
add_HID_preamble(lfops.c#L967-L992)按帧长补帧头:对length = 26(< 32 分支),它会设置*hi |= 0x20(bit 37 标准帧头)和*lo |= 1U << 26(前导 1 起始位)。这正是"26 位"命名的由来:24 位载荷(16 位卡号 + 8 位设施码)+ 2 位校验,加上起始位与帧头构成完整帧。
构造完成后调用:
CmdHIDsimTAGEx(0, high, low, 0, false, 20000);该函数(lfops.c#L996)把 high/low 值按 FSK2a 曼彻斯特编码准备成波形并在天线端模拟 HID 标签;参数含义:hi2 = 0(26 位帧没有第 3 个 32 位字)、longFMT = 0(非 37/64/84 位长格式)、ledcontrol = false(LED 由主循环自己按二进制计数器手动控制,而不是交给模拟函数闪烁)、numcycles = 20000(每次模拟约 20000 个时钟周期即超时切换下一个卡号)。源码中的打印Dbprintf("[=] trying Facility = %08x, Card = %08x, raw = %08x%08x", ...)会在 USB 连接时输出每个尝试的原始值,方便调试与复盘。
LED 二进制进度指示
模式用 4 个 LED(A/B/C/D)构成一个可视化二进制计数器,帮助你在无屏幕情况下粗略判断"是哪个卡号触发了门锁"(lf_prox2brute.c#L93-L100):
| LED | 含义 | 翻转节奏 |
|---|---|---|
| A | 每次尝试翻转 — 快速闪烁 = 正在运行 | 每 1 次 |
| B | 每 8 次尝试翻转一次 | (cardnum - CARDNUM_START) % 8 == 7 |
| C | 每 16 次尝试翻转一次 | (cardnum - CARDNUM_START) % 16 == 15 |
| D | 每 32 次尝试翻转一次 — 慢速闪烁 = 进度 | (cardnum - CARDNUM_START) % 32 == 31 |
| D(初始常亮) | 等待按键启动 | 等待 200 ms 长按阶段 |
| C(启动后点亮) | 就绪指示,随后熄灭 | 等待松手阶段 |
以 32 次为一个完整周期(A 翻转 32 次、D 翻转 1 次),四个 LED 的亮灭组合即"当前尝试序号 mod 64"的位展开。若某次尝试后读卡器/门有反应,只需记下此刻 LED 状态即可在 64 次粒度内定位命中的卡号,再结合 USB 串口日志(若连接电脑)精确确认卡号。
编译与刷写
编译流程与 模式文档 一致:
make clean make STANDALONE=LF_PROX2BRUTE -j ./pm3-flash-fullimage构建系统侧的证据:
- Makefile.hal#L156 的
STANDALONE_MODES列表包含LF_PROX2BRUTE,帮助表中描述为 "HID ProxII bruteforce v2"; - Makefile.inc#L72-L73 通过
findstring WITH_STANDALONE_LF_PROX2BRUTE,$(APP_CFLAGS)决定是否把lf_prox2brute.c编入固件。
刷写后连接设备、长按按钮触发 LED 提示即可进入该模式;若通过 USB 连接,还能在客户端看到固件的调试打印(包括每个尝试的 Facility/Card/raw 值)。需要留意两点前提:
- 固件一次只能编译进一个 standalone 模式(多模式合并需使用 Dankarmulti 加载器);
- 修改三个
#define后必须make clean重新编译——参数是编译期常量,运行期无法更改。
相关模式
- ProxBrute — 原版 ProxII 爆破:先读卡再向下递减
- HID Corporate Brute — Corporate 1000 格式卡号爆破
- HID FC Brute — 设施码爆破(当设施码未知时的前置步骤)
- Standalone 模式开发指南 — 新增/修改 standalone 模式的规范与构建流程
【免费下载链接】proxmark3Iceman Fork - Proxmark3项目地址: https://gitcode.com/GitHub_Trending/pr/proxmark3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考