Merge pull request #52 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2020-10-03 19:51:21 +10:00 committed by GitHub
commit 007df35266
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 232 additions and 206 deletions

View file

@ -4270,10 +4270,15 @@ static void arg_cat_optionv(char *dest,
}
if (datatype) {
if (longopts)
/* if (longopts)
arg_cat(&dest, "=", &ndest);
else if (shortopts)
arg_cat(&dest, " ", &ndest);
*/
if (longopts)
arg_cat(&dest, " ", &ndest);
else if (shortopts)
arg_cat(&dest, " ", &ndest);
if (optvalue) {
arg_cat(&dest, "[", &ndest);

View file

@ -69,7 +69,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
PrintAndLogEx(NORMAL, "\n"_SectionTagColor_("usage:"));
PrintAndLogEx(NORMAL, " "_CommandColor_("%s")NOLF, ctx->programName);
arg_print_syntaxv(stdout, ctx->argtable, "\n\n");
arg_print_syntax(stdout, ctx->argtable, "\n\n");
PrintAndLogEx(NORMAL, _SectionTagColor_("options:"));

View file

@ -14,6 +14,7 @@
#include "cmdparser.h" // command_t
#include "comms.h" // clearCommandBuffer
#include "cmdtrace.h"
#include "cliparser.h"
#include "crc16.h"
#include "cmdhf14a.h"
#include "protocols.h" // definitions of ISO14A/7816 protocol
@ -21,65 +22,9 @@
#include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint
#define TIMEOUT 2000
static int CmdHelp(const char *Cmd);
static int usage_hf_st_info(void) {
PrintAndLogEx(NORMAL, "Usage: hf st info [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf st info"));
return PM3_SUCCESS;
}
static int usage_hf_st_sim(void) {
PrintAndLogEx(NORMAL, "\n Emulating ST25TA512B tag with 7 byte UID\n");
PrintAndLogEx(NORMAL, "Usage: hf st sim [h] u <uid> ");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " u : 7 byte UID");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf st sim u 02E2007D0FCA4C"));
return PM3_SUCCESS;
}
static int usage_hf_st_ndef(void) {
PrintAndLogEx(NORMAL, "\n Print NFC Data Exchange Format (NDEF)\n");
PrintAndLogEx(NORMAL, "Usage: hf st ndef [h] p <pwd> ");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " p <pwd> : 16 byte password");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf st ndef p 82E80053D4CA5C0B656D852CC696C8A1"));
return PM3_SUCCESS;
}
static int usage_hf_st_protect(void) {
PrintAndLogEx(NORMAL, "\n Change R/W protection for NFC Data Exchange Format (NDEF)\n");
PrintAndLogEx(NORMAL, "Usage: hf st protect [h] p <pwd> r|w [0|1]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " p <pwd> : 16 byte write password");
PrintAndLogEx(NORMAL, " r|w : Change (r)ead or (w)rite protection");
PrintAndLogEx(NORMAL, " [0|1] : Enable / Disable protection");
PrintAndLogEx(NORMAL, " 0 = Disable (default)");
PrintAndLogEx(NORMAL, " 1 = Enable");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf st protect p 82E80053D4CA5C0B656D852CC696C8A1 r 0"));
return PM3_SUCCESS;
}
static int usage_hf_st_pwd(void) {
PrintAndLogEx(NORMAL, "\n Change R/W password for NFC Data Exchange Format (NDEF)\n");
PrintAndLogEx(NORMAL, "Usage: hf st pwd [h] p <pwd> r|w n <newpwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " p <pwd> : 16 byte write password");
PrintAndLogEx(NORMAL, " r|w : Change (r)ead or (w)rite password");
PrintAndLogEx(NORMAL, " n <newpwd> : New 16 byte password");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf st pwd p 82E80053D4CA5C0B656D852CC696C8A1 r n 00000000000000000000000000000000"));
return PM3_SUCCESS;
}
// get ST Microelectronics chip model (from UID)
static char *get_st_chip_model(uint8_t pc) {
static char model[40];
@ -348,26 +293,44 @@ int infoHF_ST(void) {
return PM3_SUCCESS;
}
// menu command to get and print all info known about any known 14b tag
// menu command to get and print all info known about any known ST25TA tag
static int cmd_hf_st_info(const char *Cmd) {
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h') return usage_hf_st_info();
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st info",
"Get info about ST25TA tag",
"hf st info"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return infoHF_ST();
}
static int cmd_hf_st_sim(const char *Cmd) {
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h' || c == 0x00) return usage_hf_st_sim();
int uidlen = 0;
uint8_t cmdp = 0;
uint8_t uid[7] = {0};
if (c == 'u') {
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
uidlen >>= 1;
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st sim",
"Emulating ST25TA512B tag with 7 byte UID",
"hf st sim -u 02E2007D0FCA4C\n");
void *argtable[] = {
arg_param_begin,
arg_str1("u", "uid", "<hex>", "7 byte UID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
if (uidlen != 7) {
return usage_hf_st_sim();
}
PrintAndLogEx(ERR, "UID must be 7 hex bytes");
return PM3_EINVARG;
}
char param[40];
@ -376,18 +339,32 @@ static int cmd_hf_st_sim(const char *Cmd) {
}
static int cmd_hf_st_ndef(const char *Cmd) {
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h' || c == 0x00) return usage_hf_st_ndef();
int pwdlen = 0;
uint8_t cmdp = 0;
uint8_t pwd[16] = {0};
if (c == 'p') {
param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen);
pwdlen >>= 1;
bool with_pwd = false;
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st ndef",
"Read NFC Data Exchange Format (NDEF) file on ST25TA",
"hf st ndef -p 82E80053D4CA5C0B656D852CC696C8A1\n");
void *argtable[] = {
arg_param_begin,
arg_str0("p", "password", "<hex>", "16 byte read password"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
if (pwdlen == 0) {
with_pwd = false;
} else {
if (pwdlen != 16) {
return usage_hf_st_ndef();
PrintAndLogEx(ERR, "Password must be 16 hex bytes");
return PM3_EINVARG;
}
with_pwd = true;
}
bool activate_field = true;
@ -429,6 +406,7 @@ static int cmd_hf_st_ndef(const char *Cmd) {
return PM3_ESOFT;
}
if (with_pwd) {
// --------------- VERIFY ----------------
uint8_t aVERIFY[30];
int aVERIFY_n = 0;
@ -452,6 +430,7 @@ static int cmd_hf_st_ndef(const char *Cmd) {
return PM3_ESOFT;
}
}
}
keep_field_on = false;
uint8_t aREAD_NDEF[30];
@ -473,57 +452,72 @@ static int cmd_hf_st_ndef(const char *Cmd) {
static int cmd_hf_st_protect(const char *Cmd) {
uint8_t cmdp = 0;
bool errors = false;
int pwdlen = 0;
uint8_t pwd[16] = {0};
int statelen = 3;
uint8_t state[3] = {0x26, 0, 0};
uint8_t state[3] = {0x26, 0, 0x02};
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_hf_st_protect();
case '0':
state[0] = 0x26; //Disable protection
cmdp++;
break;
case '1':
state[0] = 0x28; //Enable protection
cmdp++;
break;
case 'r':
state[2] = 0x01;
cmdp++;
break;
case 'w':
state[2] = 0x02;
cmdp++;
break;
case 'p':
param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen);
pwdlen >>= 1;
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
bool disable_protection = false;
bool enable_protection = false;
bool read_protection = false;
bool write_protection = false;
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st protect",
"Change read or write protection for NFC Data Exchange Format (NDEF) file on ST25TA",
"hf st protect -p 82E80053D4CA5C0B656D852CC696C8A1 -r -e -> enable read protection\n"
"hf st protect -p 82E80053D4CA5C0B656D852CC696C8A1 -w -d -> disable write protection\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("e", "enable", "enable protection"),
arg_lit0("d", "disable", "disable protection (default)"),
arg_lit0("r", "read", "change read protection"),
arg_lit0("w", "write", "change write protection (default)"),
arg_str1("p", "password", "<hex>", "16 byte write password"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
enable_protection = arg_get_lit(ctx, 1);
disable_protection = arg_get_lit(ctx, 2);
read_protection = arg_get_lit(ctx, 3);
write_protection = arg_get_lit(ctx, 4);
CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
CLIParserFree(ctx);
//Validations
if (state[2] == 0x00) {
PrintAndLogEx(WARNING, "Missing action (r)ead or (w)rite");
errors = true;
if (enable_protection && disable_protection) {
PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
return PM3_EINVARG;
} else {
if (enable_protection) {
state[0] = 0x28;
}
if (disable_protection) {
state[0] = 0x26;
}
if (pwdlen != 16) {
PrintAndLogEx(WARNING, "Missing 16 byte password");
errors = true;
}
if (errors || cmdp == 0) return usage_hf_st_protect();
if (read_protection && write_protection) {
PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
return PM3_EINVARG;
} else {
if (read_protection) {
state[2] = 0x01;
}
if (write_protection) {
state[2] = 0x02;
}
}
if (pwdlen != 16) {
PrintAndLogEx(ERR, "Missing 16 byte password");
return PM3_EINVARG;
}
bool activate_field = true;
bool keep_field_on = true;
@ -603,62 +597,62 @@ static int cmd_hf_st_protect(const char *Cmd) {
}
static int cmd_hf_st_pwd(const char *Cmd) {
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h' || c == 0x00) return usage_hf_st_pwd();
uint8_t cmdp = 0;
bool errors = false;
int pwdlen = 0;
uint8_t pwd[16] = {0};
int newpwdlen = 0;
uint8_t newpwd[16] = {0};
int changePwdlen = 4;
uint8_t changePwd[4] = {0x24, 0x00, 0x00, 0x10};
uint8_t changePwd[4] = {0x24, 0x00, 0x01, 0x10};
bool change_read_password = false;
bool change_write_password = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_hf_st_pwd();
case 'r':
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf st pwd",
"Change read or write password for NFC Data Exchange Format (NDEF) file on ST25TA",
"hf st pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -r -n 00000000000000000000000000000000 -> change read password\n"
"hf st pwd -p 82E80053D4CA5C0B656D852CC696C8A1 -w -n 00000000000000000000000000000000 -> change write password\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("r", "read", "change the read password (default)"),
arg_lit0("w", "write", "change the write password"),
arg_str1("p", "password", "<hex>", "current 16 byte write password"),
arg_str1("n", "new", "<hex>", "new 16 byte password"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
change_read_password = arg_get_lit(ctx, 1);
change_write_password = arg_get_lit(ctx, 2);
CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
if (change_read_password && change_write_password) {
PrintAndLogEx(ERR, "Must specify either read or write, not both");
CLIParserFree(ctx);
return PM3_EINVARG;
} else {
if (change_read_password) {
changePwd[2] = 0x01;
cmdp++;
break;
case 'w':
}
if (change_write_password) {
changePwd[2] = 0x02;
cmdp++;
break;
case 'p':
param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen);
pwdlen >>= 1;
cmdp += 2;
break;
case 'n':
param_gethex_ex(Cmd, cmdp + 1, newpwd, &newpwdlen);
newpwdlen >>= 1;
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
CLIParserFree(ctx);
if (changePwd[2] == 0x00) {
PrintAndLogEx(WARNING, "Missing password specification: (r)ead or (w)rite");
errors = true;
}
if (pwdlen != 16) {
PrintAndLogEx(WARNING, "Missing original 16 byte password");
errors = true;
PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
return PM3_EINVARG;
}
if (newpwdlen != 16) {
PrintAndLogEx(WARNING, "Missing new 16 byte password");
errors = true;
PrintAndLogEx(ERR, "New password must be 16 hex bytes");
return PM3_EINVARG;
}
if (errors || cmdp == 0) return usage_hf_st_pwd();
bool activate_field = true;
bool keep_field_on = true;

View file

@ -10,16 +10,30 @@ hf 14b raw -ss
lf search 1
lf config h H
```
In order to counter this and unify it, there was discussion over at the official repository a few years ago (link to issue) and there it became clear a change is needed. Among the different solutions suggested @merlokk's idea of using the lib cliparser was agreed upon. The lib was adapted and implemented for commands like
even the external tools which we collected into this repo, under folder */tools/* folder uses their own argument parsing.
In order to counter this and unify it, there was discussion over at the official repository a few years ago [link to issue](https://github.com/Proxmark/proxmark3/issues/467) and there it became clear a change is needed. Among the different solutions suggested @merlokk's idea of using the lib cliparser was agreed upon. The lib was adapted and implemented for commands like
```
emv
hf fido
[usb] pm3 --> emv
[usb] pm3 --> hf fido
```
And then it fell into silence since it wasn't well documented how to use the cliparser. Looking at source code wasn't very efficient. However the need of a better cli parsing was still there. Fast forward today, where more commands has used the cliparser but it still wasn't the natural way when adding a new client command to the Proxmark3 client. After more discussions among @doegox, @iceman1001 and @mrwalker the concept became more clear on how to use the cliparser lib in the _preferred_ way. The aftermath was a design and layout specfied which lead to a simpler implemtentation of the cliparser in the client source code while still unfiy all helptexts with the new colours support and a defined layout. As seen below, the simplicity and clearness.
And then it fell into silence since it wasn't well documented how to use the cliparser. Looking at source code wasn't very efficient. However the need of a better cli parsing was still there.
Fast forward today, where more commands has used the cliparser but it still wasn't the natural way when adding a new client command to the Proxmark3 client.
After more discussions among @doegox, @iceman1001 and @mrwalker the concept became more clear on how to use the cliparser lib in the _preferred_ way.
The aftermath was a design and layout specfied which lead to a simpler implemtentation of the cliparser in the client source code while still unfiy all helptexts with the new colours support and a defined layout. As seen below, the simplicity and clearness.
![sample of new style helptext](http://www.icedev.se/proxmark3/helptext.png)
Furthermore @mrwalker offered to take notes and thus this document was created.
This is the _new_ and _prefered_ way to implement _helptext_ and _cli parsing_ for Proxmark3 client commands and it's external tools.
## cliparser setup and use
@ -28,11 +42,11 @@ It will also add the `-h --help` option automatic.
## design comments
* where possiable all options should be lowercase.
* extended options preceeded with -- should be short
* where possible all options should be lowercase.
* extended options preceded with -- should be short
* options provided directly (without an option identifier) should be avoided.
* -vv for extra verbos should be avoided; use of debug level is prefered.
* with --options the equal is not needed (will work with and without) so dont use '='
* -vv for extra verbos should be avoided; use of debug level is preferred.
* with --options the equal is not needed (will work with and without) so don't use '='
e.g. cmd --cn 12345
@ -62,10 +76,10 @@ In the command function, setup the context
CLIParserContext *ctx;
### define the text
### define the context
CLIParserInit (\<context\>, \<description\>, \<notes\n examples ... \>);
use -> to seperate example and example comment and \\n to seperate examples.
use -> to separate example and example comment and \\n to separate examples.
e.g. lf indala clone -r a0000000a0002021 -> this uses .....
CLIParserInit(&ctx, "lf indala clone",
@ -92,18 +106,25 @@ _All options has a parameter index, since `-h --help` is added automatic, it wi
Hence all options you add will start at index 1 and upwards._
**Notes:**
booleen : arg_lit0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**bool option. true if supplied**
bool : arg_lit0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**integer**
optional integer : arg_int0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)\
**integer that is optional**
optional integer : arg_int0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**integer that is required**
required integer : arg_int1 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**Strings 0 or 1**
optional string : arg_str0("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)\
**String option that is optional and only one instance can be provided**
optional string : arg_str0("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**String option that is required and only one instance can be provided**
required string : arg_str1("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**Strings x to 250**
optional string : arg_strx0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)\
**String option that is optional and can have up to 250 instances provided**
optional string : arg_strx0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**String option that is required/at least one instance and can have up to 250 instances**
required string : arg_strx1 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**if an option does not have a short or long option, use NULL in its place**
@ -119,6 +140,12 @@ Once you have extracted the options, cleanup the context.
CLIParserFree(ctx);
### retreiving options
The parser will format and color and layout as needed.
It will also add the `-h --help` option automatic.
**bool option**
arg_get_lit(\<context\>, \<opt index\>);