ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Proxmark3 客户端命令行解析规范:Cliparser 集成指南与源码级实现解析

2026/9/17 2:04:09 拓冰建站 浏览量
Proxmark3 客户端命令行解析规范:Cliparser 集成指南与源码级实现解析 Proxmark3 客户端命令行解析规范Cliparser 集成指南与源码级实现解析【免费下载链接】proxmark3Iceman Fork - Proxmark3项目地址: https://gitcode.com/GitHub_Trending/pr/proxmark3导读本文档基于仓库 doc/cliparser.md系统讲解 Proxmark3Iceman Fork客户端如何通过cliparser库统一命令行解析与帮助文本格式。文章完整覆盖从历史背景、设计原则、通用选项规范到CLIParserInit/ argtable 选项表 /CLIExecWithReturn/CLIParserFree/ 各类取值宏的完整接入流程并结合 client/deps/cliparser/cliparser.c 与 client/deps/cliparser/cliparser.h 的源码实现以及 cmdlfindala.c、cmdhf.c 的真实命令范例讲透“如何为新命令接入标准 CLI 解析”。读完本文你可以直接在 Proxmark3 client 中为自己的命令写出风格统一、支持-h --help、具备彩色帮助文本的参数解析代码。一、为什么需要 Cliparser历史背景与统一动机Proxmark3 客户端在很长一段时间里各命令的参数解析方式是“各行其是”的混合式自定义解析。文档中列举了典型的混乱样例data xxxx h script run x.lua -h hf 14a raw -h hf 14b raw -ss lf search 1 lf config h H甚至连收纳进仓库tools/目录的外部工具也各自实现了独立的参数解析。这种风格不统一、帮助文本格式各异、参数含义模糊的状态正是推动变革的根源。在官方仓库的讨论issue #467中社区明确了需要统一 CLI 解析的结论并最终采纳了merlokk 提出的基于 argtable3 的 cliparser 库方案。该库被适配并首先应用在emv、hf fido等命令上随后经过 doegox、iceman1001、mrwalker 的多次讨论cliparser 在 Proxmark3 客户端中的“推荐用法”被明确下来并沉淀为本文档。其后 mrwalker 负责整理笔记形成了当前 doc/cliparser.md 这份规范。核心结论cliparser 是当前 Proxmark3 客户端新增命令时推荐preferred的 CLI 解析实现方式同时适用于客户端命令与外部工具。解析器会自动完成格式排版、颜色输出并自动追加-h --help选项无需手工实现。从源码结构看cliparser 作为依赖被收纳在 client/deps/cliparser/ 目录下其构建接入见 client/deps/cliparser.cmake客户端大量命令源文件cmd*.c、cmdlf*.c等均通过#include cliparser.h使用它。二、设计原则design comments在编写新命令的 CLI 时应遵循以下设计约定选项名尽量全小写where possible all options should be lowercase。长选项--前缀应保持简短。避免无选项标识符、直接摆放的参数即位置参数尽量都通过具名选项传递。不要使用-vv这类表示“额外详细”的堆叠短选项需要更详细输出时优先使用调试级别debug level。使用--长选项时不需要等号cmd --cn 12345与cmd --cn12345均可解析但规范建议不要写。三、通用选项规范common options为了让所有命令的交互习惯一致cliparser 约定了一组跨命令通用的选项短选项 / 长选项 / 含义选项含义-h --help显示帮助--cn卡号card number--fn机构号facility number--q5目标为 LF T5555/Q5 卡--em目标为 LF EM4305/4469 卡--raw原始数据-d --data提供的十六进制数据-f --file提供的文件名-k --key提供的密钥-n --keyno使用的密钥编号-p --pwd提供的密码-v --verbose输出更多信息的标志位不属于 debug-1 --buffer使用采样缓冲区sample buffer新增命令时应优先复用这些语义避免“同名不同义”。四、源码接入步骤从零实现一个 Cliparser 命令4.1 引入头文件并定义解析器上下文在命令函数的源文件中包含头文件#include cliparser.h在命令函数内部声明上下文指针CLIParserContext *ctx;CLIParserContext的定义位于 cliparser.h内部保存 argtable 指针、长度、程序名programName、提示语programHint、帮助/示例文本programHelp以及一块MAX_INPUT_ARG_LENGTH 60的解析缓冲区buf。4.2 定义并初始化上下文CLIParserInit(ctx, lf indala clone, clone INDALA UID to T55x7 or Q5/T5555 tag, lf indala clone --heden 888\n lf indala clone --fc 123 --cn 1337\n lf indala clone -r a0000000a0002021\n lf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5);CLIParserInit(ctx, programName, programHint, programHelp)的三个文本参数含义如下programName命令名称会显示在usage:行并作为解析时的argv[0]。programHint命令的一句话描述显示在帮助文本顶部青色。programHelp示例与备注。用\n分隔多个示例用-分隔“示例”与“示例注释”。例如lf indala clone -r a0000000a0002021 - this uses raw bytes。渲染时示例默认列宽约 30超长自动加宽注释紧跟其后。从源码看CLIParserInitcliparser.c负责为上下文分配内存并保存三个文本指针。注意文档中该示例文本在真实仓库 cmdlfindala.c 中已演进为包含警告提示_RED_(\nWarning, encoding with FC/CN doesnt always work)与--4041x示例的版本说明programHelp中可以自由嵌入颜色宏渲染时会被拆分换行输出。4.3 定义选项表argtablevoid *argtable[] { arg_param_begin, arg_lit0(l, long, optional - long UID 224 bits), arg_int0(c, heden, decimal, Cardnumber for Heden 2L format), arg_str0(r, raw, hex, raw bytes), arg_lit0(q, Q5, optional - specify writing to Q5/T5555 tag), arg_int0(NULL, fc, decimal, Facility Code (26 bit format)), arg_int0(NULL, cn, decimal, Cardnumber (26 bit format)), arg_param_end };索引规则因为-h --help由arg_param_begin宏自动添加它固定占用index 0因此你自行添加的每个选项从index 1 开始依次编号取值时按此索引访问。arg_param_begin与arg_param_end在 cliparser.h 中定义为#define arg_param_begin arg_lit0(h, help, This help) #define arg_param_end arg_end(20)即自动注入-h/--help布尔选项并以可容纳 20 条错误信息的arg_end(20)收尾。4.4 选项类型速查表所有选项宏的通用形态为arg_typerequired?(short, long, format, description)某个选项没有短选项或长选项时用NULL占位。完整清单如下类型可选0 结尾必填1 结尾说明boolarg_lit0(s,l,desc)—布尔开关提供即视为 trueintarg_int0(s,l,format,desc)arg_int1(...)有符号整数doublearg_dbl0(s,l,format,desc)arg_dbl1(...)双精度浮点string单实例arg_str0(s,l,format,desc)arg_str1(...)字符串最多出现 1 次string多实例arg_strx0(s,l,format,desc)arg_strx1(...)字符串最多 250 个实例arg_strx1至少需要 1 个unsignedu32/u64arg_u64_0(s,l,format,desc)arg_u64_1(...)无符号整数其中多实例字符串宏arg_strx0 / arg_strx1定义于 cliparser.h实际映射为 argtable3 的arg_strn(short, long, datatype, 最小个数, 250, glossary)。format是展示给用户的取值说明如decimal、hex、dec, ms会出现在帮助的选项描述里。4.5 执行解析CLIExecWithReturnCLIExecWithReturn(ctx, Cmd, argtable, false);CLIExecWithReturncliparser.h是一个宏展开后调用CLIParserParseStringif (CLIParserParseString((ctx), (cmd), (atbl), arg_getsize((atbl)), (ifempty))) { CLIParserFree((ctx)); return PM3_ESOFT; }其行为包括将用户输入的整行字符串按空格拆分成 argv底层是 CLIParserParseStringEx 中的状态机解析支持普通参数、-开头的选项以及单双引号包裹的带空格值解析成功返回PM3_SUCCESS0随后继续执行解析失败或用户输入-h --help时自动打印帮助文本并释放上下文、返回PM3_ESOFT无需手工分支处理第四个参数allowEmptyExec控制空命令行是否允许执行例如hf sniff传true允许直接回车运行见 cmdhf.c若整行超过MAX_INPUT_ARG_LENGTH4096 字符会报ERROR: Line too long。4.6 清理CLIParserFree从参数表中提取完所有需要的值之后必须释放上下文CLIParserFree(ctx);宏定义见 cliparser.h调用arg_freetable释放 argtable 并free(ctx)同时将指针置NULL避免悬垂指针。许多取值宏如CLIGetHexWithReturn失败时也会自动执行清理并返回错误码。4.7 获取选项值retrieving options根据选项类型使用对应的取值宏参数为(ctx, 选项索引)或(ctx, 选项索引, 默认值)bool 选项——arg_get_lit(ctx, 索引)提供则返回非 0bool is_long_uid arg_get_lit(ctx, 1);int 选项——arg_get_int_def(ctx, 索引, 默认值)未提供时返回默认值int cardnumber arg_get_int_def(ctx, 2, -1);uint32——arg_get_u32_def(ctx, 索引, 默认值)uint32_t cardnumber arg_get_u32_def(ctx, 2, 0);uint64——arg_get_u64_def(ctx, 索引, 默认值)uint64_t cardnumber arg_get_u64_def(ctx, 2, 0);这些宏在 cliparser.h 中均有定义arg_get_int_def通过先查count判断选项是否出现出现则取ival[0]否则返回传入的默认值u32 实际复用struct arg_u64arg_get_u64_def同理。另有arg_get_dbl_def、arg_get_str、arg_get_str_len等配套宏。hex 选项带返回值失败即退出函数——CLIGetHexWithReturn(ctx, 索引, 存储数组, 长度指针)uint8_t aid[2] {0}; int aidlen; CLIGetHexWithReturn(ctx, 2, aid, aidlen);该宏cliparser.h内部调用CLIParamHexToBuf解析失败时打印错误并CLIParserFree(ctx)后return PM3_ESOFT即“失败自动退出当前命令”。因此调用后可以放心使用aid/aidlen。hex 选项手动转换——CLIParamHexToBuf(arg_get_str(ctx, 索引), 目标数组, 最大长度, 长度指针)uint8_t key[24] {0}; int keylen 0; int res_klen CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, keylen);返回0表示转换成功返回值为错误码而非实际长度实际长度在keylen中。string 选项带返回值失败即退出函数——CLIGetStrWithReturn(ctx, 索引, uint8_t*, int*)uint8_t buffer[100] {0}; int slen sizeof(buffer) - 1; // 必须是希望返回的最大字符数例如 Buffer Size - 1需要 null 结尾时 CLIGetStrWithReturn(ctx, 1, buffer, slen);注意slen传入的是“最大可返回字符数”返回后被更新为实际长度。若要求结果以\0结尾务必传入缓冲区大小 - 1。string 选项手动转换获取 char 数组——CLIParamStrToBufint slen 0; char format[16] {0}; int res CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), slen); // res 0 表示成功slen 为实际写入的字符数五、源码级原理深入5.1 帮助文本的排版与颜色CLIParserPrintHelpcliparser.c统一负责帮助文本渲染usage:行使用命令名 arg_print_syntax打印语法options:部分通过arg_print_glossary按 %-30s %s\n对齐即选项列固定 30 字符宽保证描述列对齐examples/notes:部分将programHelp按\n切行用-拆分示例与注释示例列宽默认 30、超长自动加宽到示例长度 5颜色通过_GREEN_、_YELLOW_、_RED_、_CYAN_宏实现定义于客户端 util/ui 头文件分别用于区块标签、示例、命令名与描述。这些颜色宏同样可以直接嵌入CLIParserInit的提示/帮助文本中如 cmdlfindala.c 的红色警告。5.2 字符串解析状态机CLIParserParseStringExcliparser.c把命令整行拆分为 argv自动把programName作为argv[0]通过PS_FIRST / PS_ARGUMENT / PS_OPTION / PS_QUOTE四种状态区分普通参数、-开头选项与引号包裹内容支持与引号引号内的空格不会拆词超出 4096 字符的输入报ERROR: Line too long并拒绝解析。5.3 字符串 / HEX / BIN 转换器CLIParamStrToBufcliparser.c拼接多实例字符串最多 250 个并支持~家目录展开expand_tilde_path读取HOME/USERPROFILE环境变量带长度上限检查CLIParamHexToBufcliparser.cHEX 字符串转字节数组错误码1无效 HEX、2参数过长、3HEX 位数必须为偶数CLIParamBinToBufcliparser.c二进制字符串转字节数组arg_get_u64_hexstr_def等cliparser.c支持“HEX 字符串按固定字节长度解析为 u64/u32”并带默认值回退返回值1成功、2长度不符用默认值、3可选参数未提供用默认值。5.4 枚举选项列表CLIGetOptionList对于取值来自固定枚举的命令参数例如hf sniff的跳过模式--smode [none|drop|min|max|avg]cliparser 提供CLIParserOption数组与CLIGetOptionListconst CLIParserOption HFSnoopSkipModeOpts[] { {HF_SNOOP_SKIP_NONE, none}, {HF_SNOOP_SKIP_DROP, drop}, {HF_SNOOP_SKIP_MAX, min}, {HF_SNOOP_SKIP_MIN, max}, {HF_SNOOP_SKIP_AVG, avg}, {0, NULL}, // 末尾必须以 {0, NULL} 结束 }; int smode 0; if (CLIGetOptionList(arg_get_str(ctx, 3), HFSnoopSkipModeOpts, smode)) { CLIParserFree(ctx); return PM3_EINVARG; }对应真实代码见 cmdhf.c。CLIGetOptionListcliparser.c先将输入转小写再对CLIParserOption数组做精确匹配优先、前缀部分匹配兜底无任何相似项返回错误码 20多项相似返回 21。数组名要求小写见 cliparser.h最长支持CLI_MAX_OPTLIST_LEN50项CLIGetOptionListStr反向把 code 映射回文本便于回显。六、完整实战范例lf indala clone文档中的示例正是仓库里真实存在的CmdIndalaClonecmdlfindala.c其接入流程如下static int CmdIndalaClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(ctx, lf indala clone, clone Indala UID to T55x7 or Q5/T5555 tag using different known formats\n _RED_(\nWarning, encoding with FC/CN doesnt always work), lf indala clone --heden 888\n lf indala clone --fc 123 --cn 1337\n lf indala clone --fc 123 --cn 1337 --4041x\n lf indala clone -r a0000000a0002021\n lf indala clone -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5); void *argtable[] { arg_param_begin, arg_str0(r, raw, hex, raw bytes), arg_int0(NULL, heden, decimal, Card number for Heden 2L format), arg_int0(NULL, fc, decimal, Facility code (26 bit H10301 format)), arg_int0(NULL, cn, decimal, Card number (26 bit H10301 format)), arg_lit0(NULL, q5, Optional - specify writing to Q5/T5555 tag), arg_lit0(NULL, em, Optional - specify writing to EM4305/4469 tag), arg_lit0(NULL, 4041x, Optional - specify Indala 4041X format, must use with fc and cn), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); // raw 参数HEX 字符串转字节数组失败自动返回 int raw_len 0; uint8_t raw[(7 * 4) 1]; CLIGetHexWithReturn(ctx, 1, raw, raw_len); bool is_long_uid (raw_len 28); // 224 bit UID bool q5 arg_get_lit(ctx, 5); bool em arg_get_lit(ctx, 6); bool fmt4041x arg_get_lit(ctx, 7); int32_t cardnumber; uint8_t fc 0; uint16_t cn 0; bool got_cn false, got_26 false; if (is_long_uid false) { cardnumber arg_get_int_def(ctx, 2, -1); // Heden 参数 got_cn (cardnumber ! -1); fc arg_get_int_def(ctx, 3, 0); // 26 bit FC/CN 参数 cn arg_get_int_def(ctx, 4, 0); got_26 (fc ! 0 cn ! 0); } CLIParserFree(ctx); ... }该范例可以清晰看到完整的“五步走”CLIParserInit→ 定义 argtable →CLIExecWithReturn→ 取值CLIGetHexWithReturnarg_get_litarg_get_int_def→CLIParserFree。同时它演示了只提供长选项NULL短选项占位的写法如--fc、--cn、--q5、--em、--4041x通过arg_get_int_def(ctx, n, -1)的默认值技巧判断“用户是否提供了某个整数选项”结合布尔开关q5/em做写入目标T55x7 / Q5 / EM4305的分支选择并在取值后进行参数合法性校验Q5 与 EM 互斥、--4041x必须配合fc/cn等。七、总结cliparser 为 Proxmark3 客户端带来了统一的命令行体验一致的-h --help、对齐且带颜色的帮助文本、规范的短/长选项约定以及可复用的字符串/HEX/BIN 转换与枚举列表匹配能力。新增命令时只需按“CLIParserInit→ argtable 选项表 →CLIExecWithReturn→ 取值宏 →CLIParserFree”的固定模式接入即可既避免了历史代码中参差不齐的自定义解析也让用户与开发者都能快速上手任意命令。深入阅读 cliparser.c 与 cliparser.h 可进一步理解状态机拆分、帮助渲染与各类转换器的细节更多真实用法可参考客户端client/src/下大量使用 cliparser 的命令源文件。【免费下载链接】proxmark3Iceman Fork - Proxmark3项目地址: https://gitcode.com/GitHub_Trending/pr/proxmark3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考